Package ais :: Module ais_msg_5
[hide private]
[frames] | no frames]

Source Code for Module ais.ais_msg_5

   1  #!/usr/bin/env python 
   2   
   3  __version__ = '$Revision: 4791 $'.split()[1] 
   4  __date__ = '$Date: 2007-12-04 $'.split()[1] 
   5  __author__ = 'xmlbinmsg' 
   6   
   7  __doc__=''' 
   8   
   9  Autogenerated python functions to serialize/deserialize binary messages. 
  10   
  11  Generated by: ./aisxmlbinmsg2py.py 
  12   
  13  Need to then wrap these functions with the outer AIS packet and then 
  14  convert the whole binary blob to a NMEA string.  Those functions are 
  15  not currently provided in this file. 
  16   
  17  serialize: python to ais binary 
  18  deserialize: ais binary to python 
  19   
  20  The generated code uses translators.py, binary.py, and aisstring.py 
  21  which should be packaged with the resulting files. 
  22   
  23   
  24  @requires: U{epydoc<http://epydoc.sourceforge.net/>} > 3.0alpha3 
  25  @requires: U{BitVector<http://cheeseshop.python.org/pypi/BitVector>} 
  26   
  27  @author: '''+__author__+''' 
  28  @version: ''' + __version__ +''' 
  29  @var __date__: Date of last svn commit 
  30  @undocumented: __version__ __author__ __doc__ parser 
  31  @status: under development 
  32  @license: Generated code has no license 
  33  @todo: FIX: put in a description of the message here with fields and types. 
  34  ''' 
  35   
  36  import sys 
  37  from decimal import Decimal 
  38  from BitVector import BitVector 
  39   
  40  import binary, aisstring 
  41   
  42  # FIX: check to see if these will be needed 
  43  TrueBV  = BitVector(bitstring="1") 
  44  "Why always rebuild the True bit?  This should speed things up a bunch" 
  45  FalseBV = BitVector(bitstring="0") 
  46  "Why always rebuild the False bit?  This should speed things up a bunch" 
  47   
  48   
  49  fieldList = ( 
  50          'MessageID', 
  51          'RepeatIndicator', 
  52          'UserID', 
  53          'AISversion', 
  54          'IMOnumber', 
  55          'callsign', 
  56          'name', 
  57          'shipandcargo', 
  58          'dimA', 
  59          'dimB', 
  60          'dimC', 
  61          'dimD', 
  62          'fixtype', 
  63          'ETAminute', 
  64          'ETAhour', 
  65          'ETAday', 
  66          'ETAmonth', 
  67          'draught', 
  68          'destination', 
  69          'dte', 
  70          'Spare', 
  71  ) 
  72   
  73  fieldListPostgres = ( 
  74          'MessageID', 
  75          'RepeatIndicator', 
  76          'UserID', 
  77          'AISversion', 
  78          'IMOnumber', 
  79          'callsign', 
  80          'name', 
  81          'shipandcargo', 
  82          'dimA', 
  83          'dimB', 
  84          'dimC', 
  85          'dimD', 
  86          'fixtype', 
  87          'ETAminute', 
  88          'ETAhour', 
  89          'ETAday', 
  90          'ETAmonth', 
  91          'draught', 
  92          'destination', 
  93          'dte', 
  94          'Spare', 
  95  ) 
  96   
  97  toPgFields = { 
  98  } 
  99  ''' 
 100  Go to the Postgis field names from the straight field name 
 101  ''' 
 102   
 103  fromPgFields = { 
 104  } 
 105  ''' 
 106  Go from the Postgis field names to the straight field name 
 107  ''' 
 108   
 109  pgTypes = { 
 110  } 
 111  ''' 
 112  Lookup table for each postgis field name to get its type. 
 113  ''' 
 114   
115 -def encode(params, validate=False):
116 '''Create a shipdata binary message payload to pack into an AIS Msg shipdata. 117 118 Fields in params: 119 - MessageID(uint): AIS message number. Must be 5 (field automatically set to "5") 120 - RepeatIndicator(uint): Indicated how many times a message has been repeated 121 - UserID(uint): Unique ship identification number (MMSI) 122 - AISversion(uint): Compliant with what edition. 0 is the first edition. 123 - IMOnumber(uint): vessel identification number (different than mmsi) 124 - callsign(aisstr6): Ship radio call sign 125 - name(aisstr6): Vessel name 126 - shipandcargo(uint): what 127 - dimA(uint): Distance from bow to reference position 128 - dimB(uint): Distance from reference position to stern 129 - dimC(uint): Distance from port side to reference position 130 - dimD(uint): Distance from reference position to starboard side 131 - fixtype(uint): Method used for positioning 132 - ETAminute(uint): Estimated time of arrival - minutes 133 - ETAhour(uint): Estimated time of arrival - hour 134 - ETAday(uint): Estimated time of arrival - day 135 - ETAmonth(uint): Estimated time of arrival - month 136 - draught(udecimal): Maximum present static draught 137 - destination(aisstr6): Where is the vessel going 138 - dte(uint): Data terminal ready 139 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0") 140 @param params: Dictionary of field names/values. Throws a ValueError exception if required is missing 141 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 142 @rtype: BitVector 143 @return: encoded binary message (for binary messages, this needs to be wrapped in a msg 8 144 @note: The returned bits may not be 6 bit aligned. It is up to you to pad out the bits. 145 ''' 146 147 bvList = [] 148 bvList.append(binary.setBitVectorSize(BitVector(intVal=5),6)) 149 if 'RepeatIndicator' in params: 150 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['RepeatIndicator']),2)) 151 else: 152 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2)) 153 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['UserID']),30)) 154 if 'AISversion' in params: 155 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['AISversion']),2)) 156 else: 157 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2)) 158 if 'IMOnumber' in params: 159 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['IMOnumber']),30)) 160 else: 161 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),30)) 162 if 'callsign' in params: 163 bvList.append(aisstring.encode(params['callsign'],42)) 164 else: 165 bvList.append(aisstring.encode('@@@@@@@',42)) 166 if 'name' in params: 167 bvList.append(aisstring.encode(params['name'],120)) 168 else: 169 bvList.append(aisstring.encode('@@@@@@@@@@@@@@@@@@@@',120)) 170 if 'shipandcargo' in params: 171 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['shipandcargo']),8)) 172 else: 173 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),8)) 174 if 'dimA' in params: 175 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['dimA']),9)) 176 else: 177 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),9)) 178 if 'dimB' in params: 179 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['dimB']),9)) 180 else: 181 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),9)) 182 if 'dimC' in params: 183 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['dimC']),6)) 184 else: 185 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),6)) 186 if 'dimD' in params: 187 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['dimD']),6)) 188 else: 189 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),6)) 190 if 'fixtype' in params: 191 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['fixtype']),4)) 192 else: 193 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),4)) 194 if 'ETAminute' in params: 195 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['ETAminute']),6)) 196 else: 197 bvList.append(binary.setBitVectorSize(BitVector(intVal=60),6)) 198 if 'ETAhour' in params: 199 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['ETAhour']),5)) 200 else: 201 bvList.append(binary.setBitVectorSize(BitVector(intVal=24),5)) 202 if 'ETAday' in params: 203 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['ETAday']),5)) 204 else: 205 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),5)) 206 if 'ETAmonth' in params: 207 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['ETAmonth']),4)) 208 else: 209 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),4)) 210 if 'draught' in params: 211 bvList.append(binary.setBitVectorSize(BitVector(intVal=int((Decimal(params['draught'])*Decimal('10')))),8)) 212 else: 213 bvList.append(binary.setBitVectorSize(BitVector(intVal=int(0)),8)) 214 if 'destination' in params: 215 bvList.append(aisstring.encode(params['destination'],120)) 216 else: 217 bvList.append(aisstring.encode('@@@@@@@@@@@@@@@@@@@@',120)) 218 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['dte']),1)) 219 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),1)) 220 221 return binary.joinBV(bvList)
222
223 -def decode(bv, validate=False):
224 '''Unpack a shipdata message 225 226 Fields in params: 227 - MessageID(uint): AIS message number. Must be 5 (field automatically set to "5") 228 - RepeatIndicator(uint): Indicated how many times a message has been repeated 229 - UserID(uint): Unique ship identification number (MMSI) 230 - AISversion(uint): Compliant with what edition. 0 is the first edition. 231 - IMOnumber(uint): vessel identification number (different than mmsi) 232 - callsign(aisstr6): Ship radio call sign 233 - name(aisstr6): Vessel name 234 - shipandcargo(uint): what 235 - dimA(uint): Distance from bow to reference position 236 - dimB(uint): Distance from reference position to stern 237 - dimC(uint): Distance from port side to reference position 238 - dimD(uint): Distance from reference position to starboard side 239 - fixtype(uint): Method used for positioning 240 - ETAminute(uint): Estimated time of arrival - minutes 241 - ETAhour(uint): Estimated time of arrival - hour 242 - ETAday(uint): Estimated time of arrival - day 243 - ETAmonth(uint): Estimated time of arrival - month 244 - draught(udecimal): Maximum present static draught 245 - destination(aisstr6): Where is the vessel going 246 - dte(uint): Data terminal ready 247 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0") 248 @type bv: BitVector 249 @param bv: Bits defining a message 250 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 251 @rtype: dict 252 @return: params 253 ''' 254 255 #Would be nice to check the bit count here.. 256 #if validate: 257 # assert (len(bv)==FIX: SOME NUMBER) 258 r = {} 259 r['MessageID']=5 260 r['RepeatIndicator']=int(bv[6:8]) 261 r['UserID']=int(bv[8:38]) 262 r['AISversion']=int(bv[38:40]) 263 r['IMOnumber']=int(bv[40:70]) 264 r['callsign']=aisstring.decode(bv[70:112]) 265 r['name']=aisstring.decode(bv[112:232]) 266 r['shipandcargo']=int(bv[232:240]) 267 r['dimA']=int(bv[240:249]) 268 r['dimB']=int(bv[249:258]) 269 r['dimC']=int(bv[258:264]) 270 r['dimD']=int(bv[264:270]) 271 r['fixtype']=int(bv[270:274]) 272 r['ETAminute']=int(bv[274:280]) 273 r['ETAhour']=int(bv[280:285]) 274 r['ETAday']=int(bv[285:290]) 275 r['ETAmonth']=int(bv[290:294]) 276 r['draught']=Decimal(int(bv[294:302]))/Decimal('10') 277 r['destination']=aisstring.decode(bv[302:422]) 278 r['dte']=int(bv[422:423]) 279 r['Spare']=0 280 return r
281
282 -def decodeMessageID(bv, validate=False):
283 return 5
284
285 -def decodeRepeatIndicator(bv, validate=False):
286 return int(bv[6:8])
287
288 -def decodeUserID(bv, validate=False):
289 return int(bv[8:38])
290
291 -def decodeAISversion(bv, validate=False):
292 return int(bv[38:40])
293
294 -def decodeIMOnumber(bv, validate=False):
295 return int(bv[40:70])
296
297 -def decodecallsign(bv, validate=False):
298 return aisstring.decode(bv[70:112])
299
300 -def decodename(bv, validate=False):
301 return aisstring.decode(bv[112:232])
302
303 -def decodeshipandcargo(bv, validate=False):
304 return int(bv[232:240])
305
306 -def decodedimA(bv, validate=False):
307 return int(bv[240:249])
308
309 -def decodedimB(bv, validate=False):
310 return int(bv[249:258])
311
312 -def decodedimC(bv, validate=False):
313 return int(bv[258:264])
314
315 -def decodedimD(bv, validate=False):
316 return int(bv[264:270])
317
318 -def decodefixtype(bv, validate=False):
319 return int(bv[270:274])
320
321 -def decodeETAminute(bv, validate=False):
322 return int(bv[274:280])
323
324 -def decodeETAhour(bv, validate=False):
325 return int(bv[280:285])
326
327 -def decodeETAday(bv, validate=False):
328 return int(bv[285:290])
329
330 -def decodeETAmonth(bv, validate=False):
331 return int(bv[290:294])
332
333 -def decodedraught(bv, validate=False):
334 return Decimal(int(bv[294:302]))/Decimal('10')
335
336 -def decodedestination(bv, validate=False):
337 return aisstring.decode(bv[302:422])
338
339 -def decodedte(bv, validate=False):
340 return int(bv[422:423])
341
342 -def decodeSpare(bv, validate=False):
343 return 0
344 345
346 -def printHtml(params, out=sys.stdout):
347 out.write("<h3>shipdata</h3>\n") 348 out.write("<table border=\"1\">\n") 349 out.write("<tr bgcolor=\"orange\">\n") 350 out.write("<th align=\"left\">Field Name</th>\n") 351 out.write("<th align=\"left\">Type</th>\n") 352 out.write("<th align=\"left\">Value</th>\n") 353 out.write("<th align=\"left\">Value in Lookup Table</th>\n") 354 out.write("<th align=\"left\">Units</th>\n") 355 out.write("\n") 356 out.write("<tr>\n") 357 out.write("<td>MessageID</td>\n") 358 out.write("<td>uint</td>\n") 359 if 'MessageID' in params: 360 out.write(" <td>"+str(params['MessageID'])+"</td>\n") 361 out.write(" <td>"+str(params['MessageID'])+"</td>\n") 362 out.write("</tr>\n") 363 out.write("\n") 364 out.write("<tr>\n") 365 out.write("<td>RepeatIndicator</td>\n") 366 out.write("<td>uint</td>\n") 367 if 'RepeatIndicator' in params: 368 out.write(" <td>"+str(params['RepeatIndicator'])+"</td>\n") 369 if str(params['RepeatIndicator']) in RepeatIndicatorDecodeLut: 370 out.write("<td>"+RepeatIndicatorDecodeLut[str(params['RepeatIndicator'])]+"</td>") 371 else: 372 out.write("<td><i>Missing LUT entry</i></td>") 373 out.write("</tr>\n") 374 out.write("\n") 375 out.write("<tr>\n") 376 out.write("<td>UserID</td>\n") 377 out.write("<td>uint</td>\n") 378 if 'UserID' in params: 379 out.write(" <td>"+str(params['UserID'])+"</td>\n") 380 out.write(" <td>"+str(params['UserID'])+"</td>\n") 381 out.write("</tr>\n") 382 out.write("\n") 383 out.write("<tr>\n") 384 out.write("<td>AISversion</td>\n") 385 out.write("<td>uint</td>\n") 386 if 'AISversion' in params: 387 out.write(" <td>"+str(params['AISversion'])+"</td>\n") 388 out.write(" <td>"+str(params['AISversion'])+"</td>\n") 389 out.write("</tr>\n") 390 out.write("\n") 391 out.write("<tr>\n") 392 out.write("<td>IMOnumber</td>\n") 393 out.write("<td>uint</td>\n") 394 if 'IMOnumber' in params: 395 out.write(" <td>"+str(params['IMOnumber'])+"</td>\n") 396 out.write(" <td>"+str(params['IMOnumber'])+"</td>\n") 397 out.write("</tr>\n") 398 out.write("\n") 399 out.write("<tr>\n") 400 out.write("<td>callsign</td>\n") 401 out.write("<td>aisstr6</td>\n") 402 if 'callsign' in params: 403 out.write(" <td>"+str(params['callsign'])+"</td>\n") 404 out.write(" <td>"+str(params['callsign'])+"</td>\n") 405 out.write("</tr>\n") 406 out.write("\n") 407 out.write("<tr>\n") 408 out.write("<td>name</td>\n") 409 out.write("<td>aisstr6</td>\n") 410 if 'name' in params: 411 out.write(" <td>"+str(params['name'])+"</td>\n") 412 out.write(" <td>"+str(params['name'])+"</td>\n") 413 out.write("</tr>\n") 414 out.write("\n") 415 out.write("<tr>\n") 416 out.write("<td>shipandcargo</td>\n") 417 out.write("<td>uint</td>\n") 418 if 'shipandcargo' in params: 419 out.write(" <td>"+str(params['shipandcargo'])+"</td>\n") 420 if str(params['shipandcargo']) in shipandcargoDecodeLut: 421 out.write("<td>"+shipandcargoDecodeLut[str(params['shipandcargo'])]+"</td>") 422 else: 423 out.write("<td><i>Missing LUT entry</i></td>") 424 out.write("</tr>\n") 425 out.write("\n") 426 out.write("<tr>\n") 427 out.write("<td>dimA</td>\n") 428 out.write("<td>uint</td>\n") 429 if 'dimA' in params: 430 out.write(" <td>"+str(params['dimA'])+"</td>\n") 431 out.write(" <td>"+str(params['dimA'])+"</td>\n") 432 out.write("<td>m</td>\n") 433 out.write("</tr>\n") 434 out.write("\n") 435 out.write("<tr>\n") 436 out.write("<td>dimB</td>\n") 437 out.write("<td>uint</td>\n") 438 if 'dimB' in params: 439 out.write(" <td>"+str(params['dimB'])+"</td>\n") 440 out.write(" <td>"+str(params['dimB'])+"</td>\n") 441 out.write("<td>m</td>\n") 442 out.write("</tr>\n") 443 out.write("\n") 444 out.write("<tr>\n") 445 out.write("<td>dimC</td>\n") 446 out.write("<td>uint</td>\n") 447 if 'dimC' in params: 448 out.write(" <td>"+str(params['dimC'])+"</td>\n") 449 if str(params['dimC']) in dimCDecodeLut: 450 out.write("<td>"+dimCDecodeLut[str(params['dimC'])]+"</td>") 451 else: 452 out.write("<td><i>Missing LUT entry</i></td>") 453 out.write("<td>m</td>\n") 454 out.write("</tr>\n") 455 out.write("\n") 456 out.write("<tr>\n") 457 out.write("<td>dimD</td>\n") 458 out.write("<td>uint</td>\n") 459 if 'dimD' in params: 460 out.write(" <td>"+str(params['dimD'])+"</td>\n") 461 if str(params['dimD']) in dimDDecodeLut: 462 out.write("<td>"+dimDDecodeLut[str(params['dimD'])]+"</td>") 463 else: 464 out.write("<td><i>Missing LUT entry</i></td>") 465 out.write("<td>m</td>\n") 466 out.write("</tr>\n") 467 out.write("\n") 468 out.write("<tr>\n") 469 out.write("<td>fixtype</td>\n") 470 out.write("<td>uint</td>\n") 471 if 'fixtype' in params: 472 out.write(" <td>"+str(params['fixtype'])+"</td>\n") 473 if str(params['fixtype']) in fixtypeDecodeLut: 474 out.write("<td>"+fixtypeDecodeLut[str(params['fixtype'])]+"</td>") 475 else: 476 out.write("<td><i>Missing LUT entry</i></td>") 477 out.write("</tr>\n") 478 out.write("\n") 479 out.write("<tr>\n") 480 out.write("<td>ETAminute</td>\n") 481 out.write("<td>uint</td>\n") 482 if 'ETAminute' in params: 483 out.write(" <td>"+str(params['ETAminute'])+"</td>\n") 484 out.write(" <td>"+str(params['ETAminute'])+"</td>\n") 485 out.write("</tr>\n") 486 out.write("\n") 487 out.write("<tr>\n") 488 out.write("<td>ETAhour</td>\n") 489 out.write("<td>uint</td>\n") 490 if 'ETAhour' in params: 491 out.write(" <td>"+str(params['ETAhour'])+"</td>\n") 492 out.write(" <td>"+str(params['ETAhour'])+"</td>\n") 493 out.write("</tr>\n") 494 out.write("\n") 495 out.write("<tr>\n") 496 out.write("<td>ETAday</td>\n") 497 out.write("<td>uint</td>\n") 498 if 'ETAday' in params: 499 out.write(" <td>"+str(params['ETAday'])+"</td>\n") 500 out.write(" <td>"+str(params['ETAday'])+"</td>\n") 501 out.write("</tr>\n") 502 out.write("\n") 503 out.write("<tr>\n") 504 out.write("<td>ETAmonth</td>\n") 505 out.write("<td>uint</td>\n") 506 if 'ETAmonth' in params: 507 out.write(" <td>"+str(params['ETAmonth'])+"</td>\n") 508 out.write(" <td>"+str(params['ETAmonth'])+"</td>\n") 509 out.write("</tr>\n") 510 out.write("\n") 511 out.write("<tr>\n") 512 out.write("<td>draught</td>\n") 513 out.write("<td>udecimal</td>\n") 514 if 'draught' in params: 515 out.write(" <td>"+str(params['draught'])+"</td>\n") 516 if str(params['draught']) in draughtDecodeLut: 517 out.write("<td>"+draughtDecodeLut[str(params['draught'])]+"</td>") 518 else: 519 out.write("<td><i>Missing LUT entry</i></td>") 520 out.write("<td>m</td>\n") 521 out.write("</tr>\n") 522 out.write("\n") 523 out.write("<tr>\n") 524 out.write("<td>destination</td>\n") 525 out.write("<td>aisstr6</td>\n") 526 if 'destination' in params: 527 out.write(" <td>"+str(params['destination'])+"</td>\n") 528 out.write(" <td>"+str(params['destination'])+"</td>\n") 529 out.write("</tr>\n") 530 out.write("\n") 531 out.write("<tr>\n") 532 out.write("<td>dte</td>\n") 533 out.write("<td>uint</td>\n") 534 if 'dte' in params: 535 out.write(" <td>"+str(params['dte'])+"</td>\n") 536 if str(params['dte']) in dteDecodeLut: 537 out.write("<td>"+dteDecodeLut[str(params['dte'])]+"</td>") 538 else: 539 out.write("<td><i>Missing LUT entry</i></td>") 540 out.write("</tr>\n") 541 out.write("\n") 542 out.write("<tr>\n") 543 out.write("<td>Spare</td>\n") 544 out.write("<td>uint</td>\n") 545 if 'Spare' in params: 546 out.write(" <td>"+str(params['Spare'])+"</td>\n") 547 out.write(" <td>"+str(params['Spare'])+"</td>\n") 548 out.write("</tr>\n") 549 out.write("</table>\n")
550
551 -def printFields(params, out=sys.stdout, format='std', fieldList=None, dbType='postgres'):
552 '''Print a shipdata message to stdout. 553 554 Fields in params: 555 - MessageID(uint): AIS message number. Must be 5 (field automatically set to "5") 556 - RepeatIndicator(uint): Indicated how many times a message has been repeated 557 - UserID(uint): Unique ship identification number (MMSI) 558 - AISversion(uint): Compliant with what edition. 0 is the first edition. 559 - IMOnumber(uint): vessel identification number (different than mmsi) 560 - callsign(aisstr6): Ship radio call sign 561 - name(aisstr6): Vessel name 562 - shipandcargo(uint): what 563 - dimA(uint): Distance from bow to reference position 564 - dimB(uint): Distance from reference position to stern 565 - dimC(uint): Distance from port side to reference position 566 - dimD(uint): Distance from reference position to starboard side 567 - fixtype(uint): Method used for positioning 568 - ETAminute(uint): Estimated time of arrival - minutes 569 - ETAhour(uint): Estimated time of arrival - hour 570 - ETAday(uint): Estimated time of arrival - day 571 - ETAmonth(uint): Estimated time of arrival - month 572 - draught(udecimal): Maximum present static draught 573 - destination(aisstr6): Where is the vessel going 574 - dte(uint): Data terminal ready 575 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0") 576 @param params: Dictionary of field names/values. 577 @param out: File like object to write to 578 @rtype: stdout 579 @return: text to out 580 ''' 581 582 if 'std'==format: 583 out.write("shipdata:\n") 584 if 'MessageID' in params: out.write(" MessageID: "+str(params['MessageID'])+"\n") 585 if 'RepeatIndicator' in params: out.write(" RepeatIndicator: "+str(params['RepeatIndicator'])+"\n") 586 if 'UserID' in params: out.write(" UserID: "+str(params['UserID'])+"\n") 587 if 'AISversion' in params: out.write(" AISversion: "+str(params['AISversion'])+"\n") 588 if 'IMOnumber' in params: out.write(" IMOnumber: "+str(params['IMOnumber'])+"\n") 589 if 'callsign' in params: out.write(" callsign: "+str(params['callsign'])+"\n") 590 if 'name' in params: out.write(" name: "+str(params['name'])+"\n") 591 if 'shipandcargo' in params: out.write(" shipandcargo: "+str(params['shipandcargo'])+"\n") 592 if 'dimA' in params: out.write(" dimA: "+str(params['dimA'])+"\n") 593 if 'dimB' in params: out.write(" dimB: "+str(params['dimB'])+"\n") 594 if 'dimC' in params: out.write(" dimC: "+str(params['dimC'])+"\n") 595 if 'dimD' in params: out.write(" dimD: "+str(params['dimD'])+"\n") 596 if 'fixtype' in params: out.write(" fixtype: "+str(params['fixtype'])+"\n") 597 if 'ETAminute' in params: out.write(" ETAminute: "+str(params['ETAminute'])+"\n") 598 if 'ETAhour' in params: out.write(" ETAhour: "+str(params['ETAhour'])+"\n") 599 if 'ETAday' in params: out.write(" ETAday: "+str(params['ETAday'])+"\n") 600 if 'ETAmonth' in params: out.write(" ETAmonth: "+str(params['ETAmonth'])+"\n") 601 if 'draught' in params: out.write(" draught: "+str(params['draught'])+"\n") 602 if 'destination' in params: out.write(" destination: "+str(params['destination'])+"\n") 603 if 'dte' in params: out.write(" dte: "+str(params['dte'])+"\n") 604 if 'Spare' in params: out.write(" Spare: "+str(params['Spare'])+"\n") 605 elif 'csv'==format: 606 if None == options.fieldList: 607 options.fieldList = fieldList 608 needComma = False; 609 for field in fieldList: 610 if needComma: out.write(',') 611 needComma = True 612 if field in params: 613 out.write(str(params[field])) 614 # else: leave it empty 615 out.write("\n") 616 elif 'html'==format: 617 printHtml(params,out) 618 elif 'sql'==format: 619 sqlInsertStr(params,out,dbType=dbType) 620 else: 621 print "ERROR: unknown format:",format 622 assert False 623 624 return # Nothing to return
625 626 RepeatIndicatorEncodeLut = { 627 'default':'0', 628 'do not repeat any more':'3', 629 } #RepeatIndicatorEncodeLut 630 631 RepeatIndicatorDecodeLut = { 632 '0':'default', 633 '3':'do not repeat any more', 634 } # RepeatIndicatorEncodeLut 635 636 shipandcargoEncodeLut = { 637 'Wing in ground (WIG), all ships of this type':'20', 638 'Wing in ground (WIG), Hazardous catagory A':'21', 639 'Wing in ground (WIG), Hazardous catagory B':'22', 640 'Wing in ground (WIG), Hazardous catagory C':'23', 641 'Wing in ground (WIG), Hazardous catagory D':'24', 642 'Wing in ground (WIG), Reserved for future use':'25', 643 'Wing in ground (WIG), Reserved for future use':'26', 644 'Wing in ground (WIG), Reserved for future use':'27', 645 'Wing in ground (WIG), Reserved for future use':'28', 646 'Wing in ground (WIG), No additional information':'29', 647 'fishing':'30', 648 'towing':'31', 649 'towing length exceeds 200m or breadth exceeds 25m':'32', 650 'dredging or underwater ops':'33', 651 'diving ops':'34', 652 'military ops':'35', 653 'sailing':'36', 654 'pleasure craft':'37', 655 'reserved':'38', 656 'reserved':'39', 657 'High speed craft (HSC), all ships of this type':'40', 658 'High speed craft (HSC), Hazardous catagory A':'41', 659 'High speed craft (HSC), Hazardous catagory B':'42', 660 'High speed craft (HSC), Hazardous catagory C':'43', 661 'High speed craft (HSC), Hazardous catagory D':'44', 662 'High speed craft (HSC), Reserved for future use':'45', 663 'High speed craft (HSC), Reserved for future use':'46', 664 'High speed craft (HSC), Reserved for future use':'47', 665 'High speed craft (HSC), Reserved for future use':'48', 666 'High speed craft (HSC), No additional information':'49', 667 'pilot vessel':'50', 668 'search and rescue vessel':'51', 669 'tug':'52', 670 'port tender':'53', 671 'anti-polution equipment':'54', 672 'law enforcement':'55', 673 'spare - local vessel':'56', 674 'spare - local vessel':'57', 675 'medical transport':'58', 676 'ship according to RR Resolution No. 18':'59', 677 'passenger, all ships of this type':'60', 678 'passenger, Hazardous catagory A':'61', 679 'passenger, Hazardous catagory B':'62', 680 'passenger, Hazardous catagory C':'63', 681 'passenger, Hazardous catagory D':'64', 682 'passenger, Reserved for future use':'65', 683 'passenger, Reserved for future use':'66', 684 'passenger, Reserved for future use':'67', 685 'passenger, Reserved for future use':'68', 686 'passenger, No additional information':'69', 687 'cargo, all ships of this type':'70', 688 'cargo, Hazardous catagory A':'71', 689 'cargo, Hazardous catagory B':'72', 690 'cargo, Hazardous catagory C':'73', 691 'cargo, Hazardous catagory D':'74', 692 'cargo, Reserved for future use':'75', 693 'cargo, Reserved for future use':'76', 694 'cargo, Reserved for future use':'77', 695 'cargo, Reserved for future use':'78', 696 'cargo, No additional information':'79', 697 'tanker, all ships of this type':'80', 698 'tanker, Hazardous catagory A':'81', 699 'tanker, Hazardous catagory B':'82', 700 'tanker, Hazardous catagory C':'83', 701 'tanker, Hazardous catagory D':'84', 702 'tanker, Reserved for future use':'85', 703 'tanker, Reserved for future use':'86', 704 'tanker, Reserved for future use':'87', 705 'tanker, Reserved for future use':'88', 706 'tanker, No additional information':'89', 707 'other type, all ships of this type':'90', 708 'other type, Hazardous catagory A':'91', 709 'other type, Hazardous catagory B':'92', 710 'other type, Hazardous catagory C':'93', 711 'other type, Hazardous catagory D':'94', 712 'other type, Reserved for future use':'95', 713 'other type, Reserved for future use':'96', 714 'other type, Reserved for future use':'97', 715 'other type, Reserved for future use':'98', 716 'other type, No additional information':'99', 717 } #shipandcargoEncodeLut 718 719 shipandcargoDecodeLut = { 720 '20':'Wing in ground (WIG), all ships of this type', 721 '21':'Wing in ground (WIG), Hazardous catagory A', 722 '22':'Wing in ground (WIG), Hazardous catagory B', 723 '23':'Wing in ground (WIG), Hazardous catagory C', 724 '24':'Wing in ground (WIG), Hazardous catagory D', 725 '25':'Wing in ground (WIG), Reserved for future use', 726 '26':'Wing in ground (WIG), Reserved for future use', 727 '27':'Wing in ground (WIG), Reserved for future use', 728 '28':'Wing in ground (WIG), Reserved for future use', 729 '29':'Wing in ground (WIG), No additional information', 730 '30':'fishing', 731 '31':'towing', 732 '32':'towing length exceeds 200m or breadth exceeds 25m', 733 '33':'dredging or underwater ops', 734 '34':'diving ops', 735 '35':'military ops', 736 '36':'sailing', 737 '37':'pleasure craft', 738 '38':'reserved', 739 '39':'reserved', 740 '40':'High speed craft (HSC), all ships of this type', 741 '41':'High speed craft (HSC), Hazardous catagory A', 742 '42':'High speed craft (HSC), Hazardous catagory B', 743 '43':'High speed craft (HSC), Hazardous catagory C', 744 '44':'High speed craft (HSC), Hazardous catagory D', 745 '45':'High speed craft (HSC), Reserved for future use', 746 '46':'High speed craft (HSC), Reserved for future use', 747 '47':'High speed craft (HSC), Reserved for future use', 748 '48':'High speed craft (HSC), Reserved for future use', 749 '49':'High speed craft (HSC), No additional information', 750 '50':'pilot vessel', 751 '51':'search and rescue vessel', 752 '52':'tug', 753 '53':'port tender', 754 '54':'anti-polution equipment', 755 '55':'law enforcement', 756 '56':'spare - local vessel', 757 '57':'spare - local vessel', 758 '58':'medical transport', 759 '59':'ship according to RR Resolution No. 18', 760 '60':'passenger, all ships of this type', 761 '61':'passenger, Hazardous catagory A', 762 '62':'passenger, Hazardous catagory B', 763 '63':'passenger, Hazardous catagory C', 764 '64':'passenger, Hazardous catagory D', 765 '65':'passenger, Reserved for future use', 766 '66':'passenger, Reserved for future use', 767 '67':'passenger, Reserved for future use', 768 '68':'passenger, Reserved for future use', 769 '69':'passenger, No additional information', 770 '70':'cargo, all ships of this type', 771 '71':'cargo, Hazardous catagory A', 772 '72':'cargo, Hazardous catagory B', 773 '73':'cargo, Hazardous catagory C', 774 '74':'cargo, Hazardous catagory D', 775 '75':'cargo, Reserved for future use', 776 '76':'cargo, Reserved for future use', 777 '77':'cargo, Reserved for future use', 778 '78':'cargo, Reserved for future use', 779 '79':'cargo, No additional information', 780 '80':'tanker, all ships of this type', 781 '81':'tanker, Hazardous catagory A', 782 '82':'tanker, Hazardous catagory B', 783 '83':'tanker, Hazardous catagory C', 784 '84':'tanker, Hazardous catagory D', 785 '85':'tanker, Reserved for future use', 786 '86':'tanker, Reserved for future use', 787 '87':'tanker, Reserved for future use', 788 '88':'tanker, Reserved for future use', 789 '89':'tanker, No additional information', 790 '90':'other type, all ships of this type', 791 '91':'other type, Hazardous catagory A', 792 '92':'other type, Hazardous catagory B', 793 '93':'other type, Hazardous catagory C', 794 '94':'other type, Hazardous catagory D', 795 '95':'other type, Reserved for future use', 796 '96':'other type, Reserved for future use', 797 '97':'other type, Reserved for future use', 798 '98':'other type, Reserved for future use', 799 '99':'other type, No additional information', 800 } # shipandcargoEncodeLut 801 802 dimCEncodeLut = { 803 '63 m or greater':'63', 804 } #dimCEncodeLut 805 806 dimCDecodeLut = { 807 '63':'63 m or greater', 808 } # dimCEncodeLut 809 810 dimDEncodeLut = { 811 '63 m or greater':'63', 812 } #dimDEncodeLut 813 814 dimDDecodeLut = { 815 '63':'63 m or greater', 816 } # dimDEncodeLut 817 818 fixtypeEncodeLut = { 819 'undefined':'0', 820 'GPS':'1', 821 'GLONASS':'2', 822 'combined GPS/GLONASS':'3', 823 'Loran-C':'4', 824 'Chayka':'5', 825 'integrated navigation system':'6', 826 'surveyed':'7', 827 } #fixtypeEncodeLut 828 829 fixtypeDecodeLut = { 830 '0':'undefined', 831 '1':'GPS', 832 '2':'GLONASS', 833 '3':'combined GPS/GLONASS', 834 '4':'Loran-C', 835 '5':'Chayka', 836 '6':'integrated navigation system', 837 '7':'surveyed', 838 } # fixtypeEncodeLut 839 840 draughtEncodeLut = { 841 '25.5 m or greater':'25.5', 842 } #draughtEncodeLut 843 844 draughtDecodeLut = { 845 '25.5':'25.5 m or greater', 846 } # draughtEncodeLut 847 848 dteEncodeLut = { 849 'available':'0', 850 'not available':'1', 851 } #dteEncodeLut 852 853 dteDecodeLut = { 854 '0':'available', 855 '1':'not available', 856 } # dteEncodeLut 857 858 ###################################################################### 859 # SQL SUPPORT 860 ###################################################################### 861
862 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None 863 ,addCoastGuardFields=True 864 ,dbType='postgres' 865 ):
866 ''' 867 Return the SQL CREATE command for this message type 868 @param outfile: file like object to print to. 869 @param fields: which fields to put in the create. Defaults to all. 870 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 871 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 872 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 873 @type addCoastGuardFields: bool 874 @return: sql create string 875 @rtype: str 876 877 @see: sqlCreate 878 ''' 879 # FIX: should this sqlCreate be the same as in LaTeX (createFuncName) rather than hard coded? 880 outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType)))
881
882 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'):
883 ''' 884 Return the sqlhelp object to create the table. 885 886 @param fields: which fields to put in the create. Defaults to all. 887 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 888 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 889 @type addCoastGuardFields: bool 890 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 891 @return: An object that can be used to generate a return 892 @rtype: sqlhelp.create 893 ''' 894 if None == fields: fields = fieldList 895 import sqlhelp 896 c = sqlhelp.create('shipdata',dbType=dbType) 897 c.addPrimaryKey() 898 if 'MessageID' in fields: c.addInt ('MessageID') 899 if 'RepeatIndicator' in fields: c.addInt ('RepeatIndicator') 900 if 'UserID' in fields: c.addInt ('UserID') 901 if 'AISversion' in fields: c.addInt ('AISversion') 902 if 'IMOnumber' in fields: c.addInt ('IMOnumber') 903 if 'callsign' in fields: c.addVarChar('callsign',7) 904 if 'name' in fields: c.addVarChar('name',20) 905 if 'shipandcargo' in fields: c.addInt ('shipandcargo') 906 if 'dimA' in fields: c.addInt ('dimA') 907 if 'dimB' in fields: c.addInt ('dimB') 908 if 'dimC' in fields: c.addInt ('dimC') 909 if 'dimD' in fields: c.addInt ('dimD') 910 if 'fixtype' in fields: c.addInt ('fixtype') 911 if 'ETAminute' in fields: c.addInt ('ETAminute') 912 if 'ETAhour' in fields: c.addInt ('ETAhour') 913 if 'ETAday' in fields: c.addInt ('ETAday') 914 if 'ETAmonth' in fields: c.addInt ('ETAmonth') 915 if 'draught' in fields: c.addDecimal('draught',3,1) 916 if 'destination' in fields: c.addVarChar('destination',20) 917 if 'dte' in fields: c.addInt ('dte') 918 if 'Spare' in fields: c.addInt ('Spare') 919 920 if addCoastGuardFields: 921 # c.addInt('cg_rssi') # Relative signal strength indicator 922 # c.addInt('cg_d') # dBm receive strength 923 # c.addInt('cg_T') # Receive timestamp from the AIS equipment 924 # c.addInt('cg_S') # Slot received in 925 # c.addVarChar('cg_x',10) # Idonno 926 c.addVarChar('cg_r',15) # Receiver station ID - should usually be an MMSI, but sometimes is a string 927 c.addInt('cg_sec') # UTC seconds since the epoch 928 929 c.addTimestamp('cg_timestamp') # UTC decoded cg_sec - not actually in the data stream 930 931 return c
932
933 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'):
934 ''' 935 Return the SQL INSERT command for this message type 936 @param params: dictionary of values keyed by field name 937 @param outfile: file like object to print to. 938 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields 939 @return: sql create string 940 @rtype: str 941 942 @see: sqlCreate 943 ''' 944 outfile.write(str(sqlInsert(params,extraParams,dbType=dbType)))
945 946
947 -def sqlInsert(params,extraParams=None,dbType='postgres'):
948 ''' 949 Give the SQL INSERT statement 950 @param params: dict keyed by field name of values 951 @param extraParams: any extra fields that you have created beyond the normal ais message fields 952 @rtype: sqlhelp.insert 953 @return: insert class instance 954 @todo: allow optional type checking of params? 955 @warning: this will take invalid keys happily and do what??? 956 ''' 957 import sqlhelp 958 i = sqlhelp.insert('shipdata',dbType=dbType) 959 960 if dbType=='postgres': 961 finished = [] 962 for key in params: 963 if key in finished: 964 continue 965 966 if key not in toPgFields and key not in fromPgFields: 967 if type(params[key])==Decimal: i.add(key,float(params[key])) 968 else: i.add(key,params[key]) 969 else: 970 if key in fromPgFields: 971 val = params[key] 972 # Had better be a WKT type like POINT(-88.1 30.321) 973 i.addPostGIS(key,val) 974 finished.append(key) 975 else: 976 # Need to construct the type. 977 pgName = toPgFields[key] 978 #valStr='GeomFromText(\''+pgTypes[pgName]+'(' 979 valStr=pgTypes[pgName]+'(' 980 vals = [] 981 for nonPgKey in fromPgFields[pgName]: 982 vals.append(str(params[nonPgKey])) 983 finished.append(nonPgKey) 984 valStr+=' '.join(vals)+')' 985 i.addPostGIS(pgName,valStr) 986 else: 987 for key in params: 988 if type(params[key])==Decimal: i.add(key,float(params[key])) 989 else: i.add(key,params[key]) 990 991 if None != extraParams: 992 for key in extraParams: 993 i.add(key,extraParams[key]) 994 995 return i
996 997 ###################################################################### 998 # LATEX SUPPORT 999 ###################################################################### 1000
1001 -def latexDefinitionTable(outfile=sys.stdout 1002 ):
1003 ''' 1004 Return the LaTeX definition table for this message type 1005 @param outfile: file like object to print to. 1006 @type outfile: file obj 1007 @return: LaTeX table string via the outfile 1008 @rtype: str 1009 1010 ''' 1011 o = outfile 1012 1013 o.write(''' 1014 \\begin{table}%[htb] 1015 \\centering 1016 \\begin{tabular}{|l|c|l|} 1017 \\hline 1018 Parameter & Number of bits & Description 1019 \\\\ \\hline\\hline 1020 MessageID & 6 & AIS message number. Must be 5 \\\\ \hline 1021 RepeatIndicator & 2 & Indicated how many times a message has been repeated \\\\ \hline 1022 UserID & 30 & Unique ship identification number (MMSI) \\\\ \hline 1023 AISversion & 2 & Compliant with what edition. 0 is the first edition. \\\\ \hline 1024 IMOnumber & 30 & vessel identification number (different than mmsi) \\\\ \hline 1025 callsign & 42 & Ship radio call sign \\\\ \hline 1026 name & 120 & Vessel name \\\\ \hline 1027 shipandcargo & 8 & Type of ship and cargo type \\\\ \hline 1028 dimA & 9 & Distance from bow to reference position \\\\ \hline 1029 dimB & 9 & Distance from reference position to stern \\\\ \hline 1030 dimC & 6 & Distance from port side to reference position \\\\ \hline 1031 dimD & 6 & Distance from reference position to starboard side \\\\ \hline 1032 fixtype & 4 & Method used for positioning \\\\ \hline 1033 ETAminute & 6 & Estimated time of arrival - minutes \\\\ \hline 1034 ETAhour & 5 & Estimated time of arrival - hour \\\\ \hline 1035 ETAday & 5 & Estimated time of arrival - day \\\\ \hline 1036 ETAmonth & 4 & Estimated time of arrival - month \\\\ \hline 1037 draught & 8 & Maximum present static draught \\\\ \hline 1038 destination & 120 & Where is the vessel going \\\\ \hline 1039 dte & 1 & Data terminal ready \\\\ \hline 1040 Spare & 1 & Reserved for definition by a regional authority.\\\\ \\hline \\hline 1041 Total bits & 424 & Appears to take 2 slots \\\\ \\hline 1042 \\end{tabular} 1043 \\caption{AIS message number 5: Class A vessel data report} 1044 \\label{tab:shipdata} 1045 \\end{table} 1046 ''')
1047 1048 ###################################################################### 1049 # Text Definition 1050 ###################################################################### 1051
1052 -def textDefinitionTable(outfile=sys.stdout 1053 ,delim='\t' 1054 ):
1055 ''' 1056 Return the text definition table for this message type 1057 @param outfile: file like object to print to. 1058 @type outfile: file obj 1059 @return: text table string via the outfile 1060 @rtype: str 1061 1062 ''' 1063 o = outfile 1064 o.write('''Parameter'''+delim+'Number of bits'''+delim+'''Description 1065 MessageID'''+delim+'''6'''+delim+'''AIS message number. Must be 5 1066 RepeatIndicator'''+delim+'''2'''+delim+'''Indicated how many times a message has been repeated 1067 UserID'''+delim+'''30'''+delim+'''Unique ship identification number (MMSI) 1068 AISversion'''+delim+'''2'''+delim+'''Compliant with what edition. 0 is the first edition. 1069 IMOnumber'''+delim+'''30'''+delim+'''vessel identification number (different than mmsi) 1070 callsign'''+delim+'''42'''+delim+'''Ship radio call sign 1071 name'''+delim+'''120'''+delim+'''Vessel name 1072 shipandcargo'''+delim+'''8'''+delim+'''Type of ship and cargo type 1073 dimA'''+delim+'''9'''+delim+'''Distance from bow to reference position 1074 dimB'''+delim+'''9'''+delim+'''Distance from reference position to stern 1075 dimC'''+delim+'''6'''+delim+'''Distance from port side to reference position 1076 dimD'''+delim+'''6'''+delim+'''Distance from reference position to starboard side 1077 fixtype'''+delim+'''4'''+delim+'''Method used for positioning 1078 ETAminute'''+delim+'''6'''+delim+'''Estimated time of arrival - minutes 1079 ETAhour'''+delim+'''5'''+delim+'''Estimated time of arrival - hour 1080 ETAday'''+delim+'''5'''+delim+'''Estimated time of arrival - day 1081 ETAmonth'''+delim+'''4'''+delim+'''Estimated time of arrival - month 1082 draught'''+delim+'''8'''+delim+'''Maximum present static draught 1083 destination'''+delim+'''120'''+delim+'''Where is the vessel going 1084 dte'''+delim+'''1'''+delim+'''Data terminal ready 1085 Spare'''+delim+'''1'''+delim+'''Reserved for definition by a regional authority. 1086 Total bits'''+delim+'''424'''+delim+'''Appears to take 2 slots''')
1087 1088 1089 ###################################################################### 1090 # UNIT TESTING 1091 ###################################################################### 1092 import unittest
1093 -def testParams():
1094 '''Return a params file base on the testvalue tags. 1095 @rtype: dict 1096 @return: params based on testvalue tags 1097 ''' 1098 params = {} 1099 params['MessageID'] = 5 1100 params['RepeatIndicator'] = 1 1101 params['UserID'] = 1193046 1102 params['AISversion'] = 0 1103 params['IMOnumber'] = 3210 1104 params['callsign'] = 'PIRATE1' 1105 params['name'] = 'BLACK PEARL@@@@@@@@@' 1106 params['shipandcargo'] = 55 1107 params['dimA'] = 10 1108 params['dimB'] = 11 1109 params['dimC'] = 12 1110 params['dimD'] = 13 1111 params['fixtype'] = 1 1112 params['ETAminute'] = 54 1113 params['ETAhour'] = 9 1114 params['ETAday'] = 28 1115 params['ETAmonth'] = 2 1116 params['draught'] = Decimal('21.1') 1117 params['destination'] = 'NOWHERE@@@@@@@@@@@@@' 1118 params['dte'] = 0 1119 params['Spare'] = 0 1120 1121 return params
1122
1123 -class Testshipdata(unittest.TestCase):
1124 '''Use testvalue tag text from each type to build test case the shipdata message'''
1125 - def testEncodeDecode(self):
1126 1127 params = testParams() 1128 bits = encode(params) 1129 r = decode(bits) 1130 1131 # Check that each parameter came through ok. 1132 self.failUnlessEqual(r['MessageID'],params['MessageID']) 1133 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator']) 1134 self.failUnlessEqual(r['UserID'],params['UserID']) 1135 self.failUnlessEqual(r['AISversion'],params['AISversion']) 1136 self.failUnlessEqual(r['IMOnumber'],params['IMOnumber']) 1137 self.failUnlessEqual(r['callsign'],params['callsign']) 1138 self.failUnlessEqual(r['name'],params['name']) 1139 self.failUnlessEqual(r['shipandcargo'],params['shipandcargo']) 1140 self.failUnlessEqual(r['dimA'],params['dimA']) 1141 self.failUnlessEqual(r['dimB'],params['dimB']) 1142 self.failUnlessEqual(r['dimC'],params['dimC']) 1143 self.failUnlessEqual(r['dimD'],params['dimD']) 1144 self.failUnlessEqual(r['fixtype'],params['fixtype']) 1145 self.failUnlessEqual(r['ETAminute'],params['ETAminute']) 1146 self.failUnlessEqual(r['ETAhour'],params['ETAhour']) 1147 self.failUnlessEqual(r['ETAday'],params['ETAday']) 1148 self.failUnlessEqual(r['ETAmonth'],params['ETAmonth']) 1149 self.failUnlessAlmostEqual(r['draught'],params['draught'],1) 1150 self.failUnlessEqual(r['destination'],params['destination']) 1151 self.failUnlessEqual(r['dte'],params['dte']) 1152 self.failUnlessEqual(r['Spare'],params['Spare'])
1153
1154 -def addMsgOptions(parser):
1155 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true', 1156 help='decode a "shipdata" AIS message') 1157 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true', 1158 help='encode a "shipdata" AIS message') 1159 parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int' 1160 ,help='Field parameter value [default: %default]') 1161 parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int' 1162 ,help='Field parameter value [default: %default]') 1163 parser.add_option('--AISversion-field', dest='AISversionField',default=0,metavar='uint',type='int' 1164 ,help='Field parameter value [default: %default]') 1165 parser.add_option('--IMOnumber-field', dest='IMOnumberField',default=0,metavar='uint',type='int' 1166 ,help='Field parameter value [default: %default]') 1167 parser.add_option('--callsign-field', dest='callsignField',default='@@@@@@@',metavar='aisstr6',type='string' 1168 ,help='Field parameter value [default: %default]') 1169 parser.add_option('--name-field', dest='nameField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string' 1170 ,help='Field parameter value [default: %default]') 1171 parser.add_option('--shipandcargo-field', dest='shipandcargoField',default=0,metavar='uint',type='int' 1172 ,help='Field parameter value [default: %default]') 1173 parser.add_option('--dimA-field', dest='dimAField',default=0,metavar='uint',type='int' 1174 ,help='Field parameter value [default: %default]') 1175 parser.add_option('--dimB-field', dest='dimBField',default=0,metavar='uint',type='int' 1176 ,help='Field parameter value [default: %default]') 1177 parser.add_option('--dimC-field', dest='dimCField',default=0,metavar='uint',type='int' 1178 ,help='Field parameter value [default: %default]') 1179 parser.add_option('--dimD-field', dest='dimDField',default=0,metavar='uint',type='int' 1180 ,help='Field parameter value [default: %default]') 1181 parser.add_option('--fixtype-field', dest='fixtypeField',default=0,metavar='uint',type='int' 1182 ,help='Field parameter value [default: %default]') 1183 parser.add_option('--ETAminute-field', dest='ETAminuteField',default=60,metavar='uint',type='int' 1184 ,help='Field parameter value [default: %default]') 1185 parser.add_option('--ETAhour-field', dest='ETAhourField',default=24,metavar='uint',type='int' 1186 ,help='Field parameter value [default: %default]') 1187 parser.add_option('--ETAday-field', dest='ETAdayField',default=0,metavar='uint',type='int' 1188 ,help='Field parameter value [default: %default]') 1189 parser.add_option('--ETAmonth-field', dest='ETAmonthField',default=0,metavar='uint',type='int' 1190 ,help='Field parameter value [default: %default]') 1191 parser.add_option('--draught-field', dest='draughtField',default=Decimal('0'),metavar='udecimal',type='string' 1192 ,help='Field parameter value [default: %default]') 1193 parser.add_option('--destination-field', dest='destinationField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string' 1194 ,help='Field parameter value [default: %default]') 1195 parser.add_option('--dte-field', dest='dteField',metavar='uint',type='int' 1196 ,help='Field parameter value [default: %default]')
1197 1198 ############################################################ 1199 if __name__=='__main__': 1200 1201 from optparse import OptionParser 1202 parser = OptionParser(usage="%prog [options]", 1203 version="%prog "+__version__) 1204 1205 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true', 1206 help='run the documentation tests') 1207 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true', 1208 help='run the unit tests') 1209 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 1210 help='Make the test output verbose') 1211 1212 # FIX: remove nmea from binary messages. No way to build the whole packet? 1213 # FIX: or build the surrounding msg 8 for a broadcast? 1214 typeChoices = ('binary','nmeapayload','nmea') # FIX: what about a USCG type message? 1215 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType' 1216 ,default='nmeapayload' 1217 ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]') 1218 1219 1220 outputChoices = ('std','html','csv','sql' ) 1221 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType' 1222 ,default='std' 1223 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]') 1224 1225 parser.add_option('-o','--output',dest='outputFileName',default=None, 1226 help='Name of the python file to write [default: stdout]') 1227 1228 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append', 1229 choices=fieldList, 1230 help='Which fields to include in the output. Currently only for csv output [default: all]') 1231 1232 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true', 1233 help='Print the field name for csv') 1234 1235 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true', 1236 help='Print out an sql create command for the table.') 1237 1238 parser.add_option('--latex-table',dest='latexDefinitionTable',default=False,action='store_true', 1239 help='Print a LaTeX table of the type') 1240 1241 parser.add_option('--text-table',dest='textDefinitionTable',default=False,action='store_true', 1242 help='Print delimited table of the type (for Word table importing)') 1243 parser.add_option('--delimt-text-table',dest='delimTextDefinitionTable',default='\t' 1244 ,help='Delimiter for text table [default: \'%default\'](for Word table importing)') 1245 1246 1247 dbChoices = ('sqlite','postgres') 1248 parser.add_option('-D','--db-type',dest='dbType',default='postgres' 1249 ,choices=dbChoices,type='choice' 1250 ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]') 1251 1252 addMsgOptions(parser) 1253 1254 (options,args) = parser.parse_args() 1255 success=True 1256 1257 if options.doctest: 1258 import os; print os.path.basename(sys.argv[0]), 'doctests ...', 1259 sys.argv= [sys.argv[0]] 1260 if options.verbose: sys.argv.append('-v') 1261 import doctest 1262 numfail,numtests=doctest.testmod() 1263 if numfail==0: print 'ok' 1264 else: 1265 print 'FAILED' 1266 success=False 1267 1268 if not success: sys.exit('Something Failed') 1269 del success # Hide success from epydoc 1270 1271 if options.unittest: 1272 sys.argv = [sys.argv[0]] 1273 if options.verbose: sys.argv.append('-v') 1274 unittest.main() 1275 1276 outfile = sys.stdout 1277 if None!=options.outputFileName: 1278 outfile = file(options.outputFileName,'w') 1279 1280 1281 if options.doEncode: 1282 # First make sure all non required options are specified 1283 if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField") 1284 if None==options.UserIDField: parser.error("missing value for UserIDField") 1285 if None==options.AISversionField: parser.error("missing value for AISversionField") 1286 if None==options.IMOnumberField: parser.error("missing value for IMOnumberField") 1287 if None==options.callsignField: parser.error("missing value for callsignField") 1288 if None==options.nameField: parser.error("missing value for nameField") 1289 if None==options.shipandcargoField: parser.error("missing value for shipandcargoField") 1290 if None==options.dimAField: parser.error("missing value for dimAField") 1291 if None==options.dimBField: parser.error("missing value for dimBField") 1292 if None==options.dimCField: parser.error("missing value for dimCField") 1293 if None==options.dimDField: parser.error("missing value for dimDField") 1294 if None==options.fixtypeField: parser.error("missing value for fixtypeField") 1295 if None==options.ETAminuteField: parser.error("missing value for ETAminuteField") 1296 if None==options.ETAhourField: parser.error("missing value for ETAhourField") 1297 if None==options.ETAdayField: parser.error("missing value for ETAdayField") 1298 if None==options.ETAmonthField: parser.error("missing value for ETAmonthField") 1299 if None==options.draughtField: parser.error("missing value for draughtField") 1300 if None==options.destinationField: parser.error("missing value for destinationField") 1301 if None==options.dteField: parser.error("missing value for dteField") 1302 msgDict={ 1303 'MessageID': '5', 1304 'RepeatIndicator': options.RepeatIndicatorField, 1305 'UserID': options.UserIDField, 1306 'AISversion': options.AISversionField, 1307 'IMOnumber': options.IMOnumberField, 1308 'callsign': options.callsignField, 1309 'name': options.nameField, 1310 'shipandcargo': options.shipandcargoField, 1311 'dimA': options.dimAField, 1312 'dimB': options.dimBField, 1313 'dimC': options.dimCField, 1314 'dimD': options.dimDField, 1315 'fixtype': options.fixtypeField, 1316 'ETAminute': options.ETAminuteField, 1317 'ETAhour': options.ETAhourField, 1318 'ETAday': options.ETAdayField, 1319 'ETAmonth': options.ETAmonthField, 1320 'draught': options.draughtField, 1321 'destination': options.destinationField, 1322 'dte': options.dteField, 1323 'Spare': '0', 1324 } 1325 1326 bits = encode(msgDict) 1327 if 'binary'==options.ioType: print str(bits) 1328 elif 'nmeapayload'==options.ioType: 1329 # FIX: figure out if this might be necessary at compile time 1330 print "bitLen",len(bits) 1331 bitLen=len(bits) 1332 if bitLen%6!=0: 1333 bits = bits + BitVector(size=(6 - (bitLen%6))) # Pad out to multiple of 6 1334 print "result:",binary.bitvectoais6(bits)[0] 1335 1336 1337 # FIX: Do not emit this option for the binary message payloads. Does not make sense. 1338 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability") 1339 else: sys.exit('ERROR: unknown ioType. Help!') 1340 1341 1342 if options.sqlCreate: 1343 sqlCreateStr(outfile,options.fieldList,dbType=options.dbType) 1344 1345 if options.latexDefinitionTable: 1346 latexDefinitionTable(outfile) 1347 1348 # For conversion to word tables 1349 if options.textDefinitionTable: 1350 textDefinitionTable(outfile,options.delimTextDefinitionTable) 1351 1352 if options.printCsvfieldList: 1353 # Make a csv separated list of fields that will be displayed for csv 1354 if None == options.fieldList: options.fieldList = fieldList 1355 import StringIO 1356 buf = StringIO.StringIO() 1357 for field in options.fieldList: 1358 buf.write(field+',') 1359 result = buf.getvalue() 1360 if result[-1] == ',': print result[:-1] 1361 else: print result 1362 1363 if options.doDecode: 1364 if len(args)==0: args = sys.stdin 1365 for msg in args: 1366 bv = None 1367 1368 if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'): 1369 # Found nmea 1370 # FIX: do checksum 1371 bv = binary.ais6tobitvec(msg.split(',')[5]) 1372 else: # either binary or nmeapayload... expect mostly nmeapayloads 1373 # assumes that an all 0 and 1 string can not be a nmeapayload 1374 binaryMsg=True 1375 for c in msg: 1376 if c not in ('0','1'): 1377 binaryMsg=False 1378 break 1379 if binaryMsg: 1380 bv = BitVector(bitstring=msg) 1381 else: # nmeapayload 1382 bv = binary.ais6tobitvec(msg) 1383 1384 printFields(decode(bv) 1385 ,out=outfile 1386 ,format=options.outputType 1387 ,fieldList=options.fieldList 1388 ,dbType=options.dbType 1389 ) 1390