1   
   2   
   3  __version__ = '$Revision: 4791 $'.split()[1] 
   4  __date__ = '$Date: 2008-01-09 $'.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   
  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           
 256           
 257           
 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   
 284   
 287   
 290   
 292          return int(bv[38:40]) 
  293   
 295          return int(bv[40:70]) 
  296   
 299   
 302   
 304          return int(bv[232:240]) 
  305   
 307          return int(bv[240:249]) 
  308   
 310          return int(bv[249:258]) 
  311   
 313          return int(bv[258:264]) 
  314   
 316          return int(bv[264:270]) 
  317   
 319          return int(bv[270:274]) 
  320   
 322          return int(bv[274:280]) 
  323   
 325          return int(bv[280:285]) 
  326   
 328          return int(bv[285:290]) 
  329   
 331          return int(bv[290:294]) 
  332   
 334          return Decimal(int(bv[294:302]))/Decimal('10') 
  335   
 338   
 340          return int(bv[422:423]) 
  341   
 344   
 345   
 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                           
 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  
  625   
 626  RepeatIndicatorEncodeLut = { 
 627          'default':'0', 
 628          'do not repeat any more':'3', 
 629          }  
 630   
 631  RepeatIndicatorDecodeLut = { 
 632          '0':'default', 
 633          '3':'do not repeat any more', 
 634          }  
 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          }  
 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          }  
 801   
 802  dimCEncodeLut = { 
 803          '63 m or greater':'63', 
 804          }  
 805   
 806  dimCDecodeLut = { 
 807          '63':'63 m or greater', 
 808          }  
 809   
 810  dimDEncodeLut = { 
 811          '63 m or greater':'63', 
 812          }  
 813   
 814  dimDDecodeLut = { 
 815          '63':'63 m or greater', 
 816          }  
 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          }  
 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          }  
 839   
 840  draughtEncodeLut = { 
 841          '25.5 m or greater':'25.5', 
 842          }  
 843   
 844  draughtDecodeLut = { 
 845          '25.5':'25.5 m or greater', 
 846          }  
 847   
 848  dteEncodeLut = { 
 849          'available':'0', 
 850          'not available':'1', 
 851          }  
 852   
 853  dteDecodeLut = { 
 854          '0':'available', 
 855          '1':'not available', 
 856          }  
 857   
 858   
 859   
 860   
 861   
 862  dbTableName='shipdata' 
 863  'Database table name' 
 864   
 865 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None 
 866                  ,addCoastGuardFields=True 
 867                  ,dbType='postgres' 
 868                  ): 
  869          ''' 
 870          Return the SQL CREATE command for this message type 
 871          @param outfile: file like object to print to. 
 872          @param fields: which fields to put in the create.  Defaults to all. 
 873          @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 
 874          @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 
 875          @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 
 876          @type addCoastGuardFields: bool 
 877          @return: sql create string 
 878          @rtype: str 
 879   
 880          @see: sqlCreate 
 881          ''' 
 882           
 883          outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType))) 
  884   
 885 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'): 
  886          ''' 
 887          Return the sqlhelp object to create the table. 
 888   
 889          @param fields: which fields to put in the create.  Defaults to all. 
 890          @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 
 891          @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 
 892          @type addCoastGuardFields: bool 
 893          @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 
 894          @return: An object that can be used to generate a return 
 895          @rtype: sqlhelp.create 
 896          ''' 
 897          if None == fields: fields = fieldList 
 898          import sqlhelp 
 899          c = sqlhelp.create('shipdata',dbType=dbType) 
 900          c.addPrimaryKey() 
 901          if 'MessageID' in fields: c.addInt ('MessageID') 
 902          if 'RepeatIndicator' in fields: c.addInt ('RepeatIndicator') 
 903          if 'UserID' in fields: c.addInt ('UserID') 
 904          if 'AISversion' in fields: c.addInt ('AISversion') 
 905          if 'IMOnumber' in fields: c.addInt ('IMOnumber') 
 906          if 'callsign' in fields: c.addVarChar('callsign',7) 
 907          if 'name' in fields: c.addVarChar('name',20) 
 908          if 'shipandcargo' in fields: c.addInt ('shipandcargo') 
 909          if 'dimA' in fields: c.addInt ('dimA') 
 910          if 'dimB' in fields: c.addInt ('dimB') 
 911          if 'dimC' in fields: c.addInt ('dimC') 
 912          if 'dimD' in fields: c.addInt ('dimD') 
 913          if 'fixtype' in fields: c.addInt ('fixtype') 
 914          if 'ETAminute' in fields: c.addInt ('ETAminute') 
 915          if 'ETAhour' in fields: c.addInt ('ETAhour') 
 916          if 'ETAday' in fields: c.addInt ('ETAday') 
 917          if 'ETAmonth' in fields: c.addInt ('ETAmonth') 
 918          if 'draught' in fields: c.addDecimal('draught',3,1) 
 919          if 'destination' in fields: c.addVarChar('destination',20) 
 920          if 'dte' in fields: c.addInt ('dte') 
 921          if 'Spare' in fields: c.addInt ('Spare') 
 922   
 923          if addCoastGuardFields: 
 924                   
 925                   
 926                   
 927                   
 928                   
 929                  c.addVarChar('cg_r',15)    
 930                  c.addInt('cg_sec')         
 931   
 932                  c.addTimestamp('cg_timestamp')  
 933   
 934          return c 
  935   
 936 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'): 
  937          ''' 
 938          Return the SQL INSERT command for this message type 
 939          @param params: dictionary of values keyed by field name 
 940          @param outfile: file like object to print to. 
 941          @param extraParams: A sequence of tuples containing (name,sql type) for additional fields 
 942          @return: sql create string 
 943          @rtype: str 
 944   
 945          @see: sqlCreate 
 946          ''' 
 947          outfile.write(str(sqlInsert(params,extraParams,dbType=dbType))) 
  948   
 949   
 950 -def sqlInsert(params,extraParams=None,dbType='postgres'): 
  951          ''' 
 952          Give the SQL INSERT statement 
 953          @param params: dict keyed by field name of values 
 954          @param extraParams: any extra fields that you have created beyond the normal ais message fields 
 955          @rtype: sqlhelp.insert 
 956          @return: insert class instance 
 957          @todo: allow optional type checking of params? 
 958          @warning: this will take invalid keys happily and do what??? 
 959          ''' 
 960          import sqlhelp 
 961          i = sqlhelp.insert('shipdata',dbType=dbType) 
 962   
 963          if dbType=='postgres': 
 964                  finished = [] 
 965                  for key in params: 
 966                          if key in finished:  
 967                                  continue 
 968   
 969                          if key not in toPgFields and key not in fromPgFields: 
 970                                  if type(params[key])==Decimal: i.add(key,float(params[key])) 
 971                                  else: i.add(key,params[key]) 
 972                          else: 
 973                                  if key in fromPgFields: 
 974                                          val = params[key] 
 975                                           
 976                                          i.addPostGIS(key,val) 
 977                                          finished.append(key) 
 978                                  else: 
 979                                           
 980                                          pgName = toPgFields[key] 
 981                                           
 982                                          valStr=pgTypes[pgName]+'(' 
 983                                          vals = [] 
 984                                          for nonPgKey in fromPgFields[pgName]: 
 985                                                  vals.append(str(params[nonPgKey])) 
 986                                                  finished.append(nonPgKey) 
 987                                          valStr+=' '.join(vals)+')' 
 988                                          i.addPostGIS(pgName,valStr) 
 989          else: 
 990                  for key in params:  
 991                          if type(params[key])==Decimal: i.add(key,float(params[key])) 
 992                          else: i.add(key,params[key]) 
 993   
 994          if None != extraParams: 
 995                  for key in extraParams:  
 996                          i.add(key,extraParams[key]) 
 997   
 998          return i 
  999   
1000   
1001   
1002   
1003   
1006          ''' 
1007          Return the LaTeX definition table for this message type 
1008          @param outfile: file like object to print to. 
1009          @type outfile: file obj 
1010          @return: LaTeX table string via the outfile 
1011          @rtype: str 
1012   
1013          ''' 
1014          o = outfile 
1015   
1016          o.write(''' 
1017  \\begin{table}%[htb] 
1018  \\centering 
1019  \\begin{tabular}{|l|c|l|} 
1020  \\hline 
1021  Parameter & Number of bits & Description  
1022  \\\\  \\hline\\hline 
1023  MessageID & 6 & AIS message number.  Must be 5 \\\\ \hline  
1024  RepeatIndicator & 2 & Indicated how many times a message has been repeated \\\\ \hline  
1025  UserID & 30 & Unique ship identification number (MMSI) \\\\ \hline  
1026  AISversion & 2 & Compliant with what edition.  0 is the first edition. \\\\ \hline  
1027  IMOnumber & 30 & vessel identification number (different than mmsi) \\\\ \hline  
1028  callsign & 42 & Ship radio call sign \\\\ \hline  
1029  name & 120 & Vessel name \\\\ \hline  
1030  shipandcargo & 8 & Type of ship and cargo type \\\\ \hline  
1031  dimA & 9 & Distance from bow to reference position \\\\ \hline  
1032  dimB & 9 & Distance from reference position to stern \\\\ \hline  
1033  dimC & 6 & Distance from port side to reference position \\\\ \hline  
1034  dimD & 6 & Distance from reference position to starboard side \\\\ \hline  
1035  fixtype & 4 & Method used for positioning \\\\ \hline  
1036  ETAminute & 6 & Estimated time of arrival - minutes \\\\ \hline  
1037  ETAhour & 5 & Estimated time of arrival - hour \\\\ \hline  
1038  ETAday & 5 & Estimated time of arrival - day \\\\ \hline  
1039  ETAmonth & 4 & Estimated time of arrival - month \\\\ \hline  
1040  draught & 8 & Maximum present static draught \\\\ \hline  
1041  destination & 120 & Where is the vessel going \\\\ \hline  
1042  dte & 1 & Data terminal ready \\\\ \hline  
1043  Spare & 1 & Reserved for definition by a regional authority.\\\\ \\hline \\hline 
1044  Total bits & 424 & Appears to take 2 slots \\\\ \\hline 
1045  \\end{tabular} 
1046  \\caption{AIS message number 5: Class A vessel data report} 
1047  \\label{tab:shipdata} 
1048  \\end{table} 
1049  ''') 
 1050   
1051   
1052   
1053   
1054   
1055 -def textDefinitionTable(outfile=sys.stdout 
1056                  ,delim='\t' 
1057                  ): 
 1058          ''' 
1059          Return the text definition table for this message type 
1060          @param outfile: file like object to print to. 
1061          @type outfile: file obj 
1062          @return: text table string via the outfile 
1063          @rtype: str 
1064   
1065          ''' 
1066          o = outfile 
1067          o.write('''Parameter'''+delim+'Number of bits'''+delim+'''Description  
1068  MessageID'''+delim+'''6'''+delim+'''AIS message number.  Must be 5 
1069  RepeatIndicator'''+delim+'''2'''+delim+'''Indicated how many times a message has been repeated 
1070  UserID'''+delim+'''30'''+delim+'''Unique ship identification number (MMSI) 
1071  AISversion'''+delim+'''2'''+delim+'''Compliant with what edition.  0 is the first edition. 
1072  IMOnumber'''+delim+'''30'''+delim+'''vessel identification number (different than mmsi) 
1073  callsign'''+delim+'''42'''+delim+'''Ship radio call sign 
1074  name'''+delim+'''120'''+delim+'''Vessel name 
1075  shipandcargo'''+delim+'''8'''+delim+'''Type of ship and cargo type 
1076  dimA'''+delim+'''9'''+delim+'''Distance from bow to reference position 
1077  dimB'''+delim+'''9'''+delim+'''Distance from reference position to stern 
1078  dimC'''+delim+'''6'''+delim+'''Distance from port side to reference position 
1079  dimD'''+delim+'''6'''+delim+'''Distance from reference position to starboard side 
1080  fixtype'''+delim+'''4'''+delim+'''Method used for positioning 
1081  ETAminute'''+delim+'''6'''+delim+'''Estimated time of arrival - minutes 
1082  ETAhour'''+delim+'''5'''+delim+'''Estimated time of arrival - hour 
1083  ETAday'''+delim+'''5'''+delim+'''Estimated time of arrival - day 
1084  ETAmonth'''+delim+'''4'''+delim+'''Estimated time of arrival - month 
1085  draught'''+delim+'''8'''+delim+'''Maximum present static draught 
1086  destination'''+delim+'''120'''+delim+'''Where is the vessel going 
1087  dte'''+delim+'''1'''+delim+'''Data terminal ready 
1088  Spare'''+delim+'''1'''+delim+'''Reserved for definition by a regional authority. 
1089  Total bits'''+delim+'''424'''+delim+'''Appears to take 2 slots''') 
 1090   
1091   
1092   
1093   
1094   
1095  import unittest 
1097          '''Return a params file base on the testvalue tags. 
1098          @rtype: dict 
1099          @return: params based on testvalue tags 
1100          ''' 
1101          params = {} 
1102          params['MessageID'] = 5 
1103          params['RepeatIndicator'] = 1 
1104          params['UserID'] = 1193046 
1105          params['AISversion'] = 0 
1106          params['IMOnumber'] = 3210 
1107          params['callsign'] = 'PIRATE1' 
1108          params['name'] = 'BLACK PEARL@@@@@@@@@' 
1109          params['shipandcargo'] = 55 
1110          params['dimA'] = 10 
1111          params['dimB'] = 11 
1112          params['dimC'] = 12 
1113          params['dimD'] = 13 
1114          params['fixtype'] = 1 
1115          params['ETAminute'] = 54 
1116          params['ETAhour'] = 9 
1117          params['ETAday'] = 28 
1118          params['ETAmonth'] = 2 
1119          params['draught'] = Decimal('21.1') 
1120          params['destination'] = 'NOWHERE@@@@@@@@@@@@@' 
1121          params['dte'] = 0 
1122          params['Spare'] = 0 
1123   
1124          return params 
 1125   
1127          '''Use testvalue tag text from each type to build test case the shipdata message''' 
1129   
1130                  params = testParams() 
1131                  bits   = encode(params) 
1132                  r      = decode(bits) 
1133   
1134                   
1135                  self.failUnlessEqual(r['MessageID'],params['MessageID']) 
1136                  self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator']) 
1137                  self.failUnlessEqual(r['UserID'],params['UserID']) 
1138                  self.failUnlessEqual(r['AISversion'],params['AISversion']) 
1139                  self.failUnlessEqual(r['IMOnumber'],params['IMOnumber']) 
1140                  self.failUnlessEqual(r['callsign'],params['callsign']) 
1141                  self.failUnlessEqual(r['name'],params['name']) 
1142                  self.failUnlessEqual(r['shipandcargo'],params['shipandcargo']) 
1143                  self.failUnlessEqual(r['dimA'],params['dimA']) 
1144                  self.failUnlessEqual(r['dimB'],params['dimB']) 
1145                  self.failUnlessEqual(r['dimC'],params['dimC']) 
1146                  self.failUnlessEqual(r['dimD'],params['dimD']) 
1147                  self.failUnlessEqual(r['fixtype'],params['fixtype']) 
1148                  self.failUnlessEqual(r['ETAminute'],params['ETAminute']) 
1149                  self.failUnlessEqual(r['ETAhour'],params['ETAhour']) 
1150                  self.failUnlessEqual(r['ETAday'],params['ETAday']) 
1151                  self.failUnlessEqual(r['ETAmonth'],params['ETAmonth']) 
1152                  self.failUnlessAlmostEqual(r['draught'],params['draught'],1) 
1153                  self.failUnlessEqual(r['destination'],params['destination']) 
1154                  self.failUnlessEqual(r['dte'],params['dte']) 
1155                  self.failUnlessEqual(r['Spare'],params['Spare']) 
  1156   
1158          parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true', 
1159                  help='decode a "shipdata" AIS message') 
1160          parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true', 
1161                  help='encode a "shipdata" AIS message') 
1162          parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int' 
1163                  ,help='Field parameter value [default: %default]') 
1164          parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int' 
1165                  ,help='Field parameter value [default: %default]') 
1166          parser.add_option('--AISversion-field', dest='AISversionField',default=0,metavar='uint',type='int' 
1167                  ,help='Field parameter value [default: %default]') 
1168          parser.add_option('--IMOnumber-field', dest='IMOnumberField',default=0,metavar='uint',type='int' 
1169                  ,help='Field parameter value [default: %default]') 
1170          parser.add_option('--callsign-field', dest='callsignField',default='@@@@@@@',metavar='aisstr6',type='string' 
1171                  ,help='Field parameter value [default: %default]') 
1172          parser.add_option('--name-field', dest='nameField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string' 
1173                  ,help='Field parameter value [default: %default]') 
1174          parser.add_option('--shipandcargo-field', dest='shipandcargoField',default=0,metavar='uint',type='int' 
1175                  ,help='Field parameter value [default: %default]') 
1176          parser.add_option('--dimA-field', dest='dimAField',default=0,metavar='uint',type='int' 
1177                  ,help='Field parameter value [default: %default]') 
1178          parser.add_option('--dimB-field', dest='dimBField',default=0,metavar='uint',type='int' 
1179                  ,help='Field parameter value [default: %default]') 
1180          parser.add_option('--dimC-field', dest='dimCField',default=0,metavar='uint',type='int' 
1181                  ,help='Field parameter value [default: %default]') 
1182          parser.add_option('--dimD-field', dest='dimDField',default=0,metavar='uint',type='int' 
1183                  ,help='Field parameter value [default: %default]') 
1184          parser.add_option('--fixtype-field', dest='fixtypeField',default=0,metavar='uint',type='int' 
1185                  ,help='Field parameter value [default: %default]') 
1186          parser.add_option('--ETAminute-field', dest='ETAminuteField',default=60,metavar='uint',type='int' 
1187                  ,help='Field parameter value [default: %default]') 
1188          parser.add_option('--ETAhour-field', dest='ETAhourField',default=24,metavar='uint',type='int' 
1189                  ,help='Field parameter value [default: %default]') 
1190          parser.add_option('--ETAday-field', dest='ETAdayField',default=0,metavar='uint',type='int' 
1191                  ,help='Field parameter value [default: %default]') 
1192          parser.add_option('--ETAmonth-field', dest='ETAmonthField',default=0,metavar='uint',type='int' 
1193                  ,help='Field parameter value [default: %default]') 
1194          parser.add_option('--draught-field', dest='draughtField',default=Decimal('0'),metavar='udecimal',type='string' 
1195                  ,help='Field parameter value [default: %default]') 
1196          parser.add_option('--destination-field', dest='destinationField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string' 
1197                  ,help='Field parameter value [default: %default]') 
1198          parser.add_option('--dte-field', dest='dteField',metavar='uint',type='int' 
1199                  ,help='Field parameter value [default: %default]') 
 1200   
1201   
1202  if __name__=='__main__': 
1203   
1204          from optparse import OptionParser 
1205          parser = OptionParser(usage="%prog [options]", 
1206                  version="%prog "+__version__) 
1207   
1208          parser.add_option('--doc-test',dest='doctest',default=False,action='store_true', 
1209                  help='run the documentation tests') 
1210          parser.add_option('--unit-test',dest='unittest',default=False,action='store_true', 
1211                  help='run the unit tests') 
1212          parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 
1213                  help='Make the test output verbose') 
1214   
1215           
1216           
1217          typeChoices = ('binary','nmeapayload','nmea')  
1218          parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType' 
1219                  ,default='nmeapayload' 
1220                  ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]') 
1221   
1222   
1223          outputChoices = ('std','html','csv','sql' ) 
1224          parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType' 
1225                  ,default='std' 
1226                  ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]') 
1227   
1228          parser.add_option('-o','--output',dest='outputFileName',default=None, 
1229                            help='Name of the python file to write [default: stdout]') 
1230   
1231          parser.add_option('-f','--fields',dest='fieldList',default=None, action='append', 
1232                            choices=fieldList, 
1233                            help='Which fields to include in the output.  Currently only for csv output [default: all]') 
1234   
1235          parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true', 
1236                            help='Print the field name for csv') 
1237   
1238          parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true', 
1239                            help='Print out an sql create command for the table.') 
1240   
1241          parser.add_option('--latex-table',dest='latexDefinitionTable',default=False,action='store_true', 
1242                            help='Print a LaTeX table of the type') 
1243   
1244          parser.add_option('--text-table',dest='textDefinitionTable',default=False,action='store_true', 
1245                            help='Print delimited table of the type (for Word table importing)') 
1246          parser.add_option('--delimt-text-table',dest='delimTextDefinitionTable',default='\t' 
1247                            ,help='Delimiter for text table [default: \'%default\'](for Word table importing)') 
1248   
1249   
1250          dbChoices = ('sqlite','postgres') 
1251          parser.add_option('-D','--db-type',dest='dbType',default='postgres' 
1252                            ,choices=dbChoices,type='choice' 
1253                            ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]') 
1254   
1255          addMsgOptions(parser) 
1256   
1257          (options,args) = parser.parse_args() 
1258          success=True 
1259   
1260          if options.doctest: 
1261                  import os; print os.path.basename(sys.argv[0]), 'doctests ...', 
1262                  sys.argv= [sys.argv[0]] 
1263                  if options.verbose: sys.argv.append('-v') 
1264                  import doctest 
1265                  numfail,numtests=doctest.testmod() 
1266                  if numfail==0: print 'ok' 
1267                  else:  
1268                          print 'FAILED' 
1269                          success=False 
1270   
1271          if not success: sys.exit('Something Failed') 
1272          del success  
1273   
1274          if options.unittest: 
1275                  sys.argv = [sys.argv[0]] 
1276                  if options.verbose: sys.argv.append('-v') 
1277                  unittest.main() 
1278   
1279          outfile = sys.stdout 
1280          if None!=options.outputFileName: 
1281                  outfile = file(options.outputFileName,'w') 
1282   
1283   
1284          if options.doEncode: 
1285                   
1286                  if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField") 
1287                  if None==options.UserIDField: parser.error("missing value for UserIDField") 
1288                  if None==options.AISversionField: parser.error("missing value for AISversionField") 
1289                  if None==options.IMOnumberField: parser.error("missing value for IMOnumberField") 
1290                  if None==options.callsignField: parser.error("missing value for callsignField") 
1291                  if None==options.nameField: parser.error("missing value for nameField") 
1292                  if None==options.shipandcargoField: parser.error("missing value for shipandcargoField") 
1293                  if None==options.dimAField: parser.error("missing value for dimAField") 
1294                  if None==options.dimBField: parser.error("missing value for dimBField") 
1295                  if None==options.dimCField: parser.error("missing value for dimCField") 
1296                  if None==options.dimDField: parser.error("missing value for dimDField") 
1297                  if None==options.fixtypeField: parser.error("missing value for fixtypeField") 
1298                  if None==options.ETAminuteField: parser.error("missing value for ETAminuteField") 
1299                  if None==options.ETAhourField: parser.error("missing value for ETAhourField") 
1300                  if None==options.ETAdayField: parser.error("missing value for ETAdayField") 
1301                  if None==options.ETAmonthField: parser.error("missing value for ETAmonthField") 
1302                  if None==options.draughtField: parser.error("missing value for draughtField") 
1303                  if None==options.destinationField: parser.error("missing value for destinationField") 
1304                  if None==options.dteField: parser.error("missing value for dteField") 
1305                  msgDict={ 
1306                          'MessageID': '5', 
1307                          'RepeatIndicator': options.RepeatIndicatorField, 
1308                          'UserID': options.UserIDField, 
1309                          'AISversion': options.AISversionField, 
1310                          'IMOnumber': options.IMOnumberField, 
1311                          'callsign': options.callsignField, 
1312                          'name': options.nameField, 
1313                          'shipandcargo': options.shipandcargoField, 
1314                          'dimA': options.dimAField, 
1315                          'dimB': options.dimBField, 
1316                          'dimC': options.dimCField, 
1317                          'dimD': options.dimDField, 
1318                          'fixtype': options.fixtypeField, 
1319                          'ETAminute': options.ETAminuteField, 
1320                          'ETAhour': options.ETAhourField, 
1321                          'ETAday': options.ETAdayField, 
1322                          'ETAmonth': options.ETAmonthField, 
1323                          'draught': options.draughtField, 
1324                          'destination': options.destinationField, 
1325                          'dte': options.dteField, 
1326                          'Spare': '0', 
1327                  } 
1328   
1329                  bits = encode(msgDict) 
1330                  if 'binary'==options.ioType: print str(bits) 
1331                  elif 'nmeapayload'==options.ioType: 
1332                           
1333                          print "bitLen",len(bits) 
1334                          bitLen=len(bits) 
1335                          if bitLen%6!=0: 
1336                              bits = bits + BitVector(size=(6 - (bitLen%6)))   
1337                          print "result:",binary.bitvectoais6(bits)[0] 
1338   
1339   
1340                   
1341                  elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability") 
1342                  else: sys.exit('ERROR: unknown ioType.  Help!') 
1343   
1344   
1345          if options.sqlCreate: 
1346                  sqlCreateStr(outfile,options.fieldList,dbType=options.dbType) 
1347   
1348          if options.latexDefinitionTable: 
1349                  latexDefinitionTable(outfile) 
1350   
1351           
1352          if options.textDefinitionTable: 
1353                  textDefinitionTable(outfile,options.delimTextDefinitionTable) 
1354   
1355          if options.printCsvfieldList: 
1356                   
1357                  if None == options.fieldList: options.fieldList = fieldList 
1358                  import StringIO 
1359                  buf = StringIO.StringIO() 
1360                  for field in options.fieldList: 
1361                          buf.write(field+',') 
1362                  result = buf.getvalue() 
1363                  if result[-1] == ',': print result[:-1] 
1364                  else: print result 
1365   
1366          if options.doDecode: 
1367                  if len(args)==0: args = sys.stdin 
1368                  for msg in args: 
1369                          bv = None 
1370   
1371                          if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'): 
1372                                   
1373                                   
1374                                  bv = binary.ais6tobitvec(msg.split(',')[5]) 
1375                          else:  
1376                                   
1377                                  binaryMsg=True 
1378                                  for c in msg: 
1379                                          if c not in ('0','1'): 
1380                                                  binaryMsg=False 
1381                                                  break 
1382                                  if binaryMsg: 
1383                                          bv = BitVector(bitstring=msg) 
1384                                  else:  
1385                                          bv = binary.ais6tobitvec(msg) 
1386   
1387                          printFields(decode(bv) 
1388                                      ,out=outfile 
1389                                      ,format=options.outputType 
1390                                      ,fieldList=options.fieldList 
1391                                      ,dbType=options.dbType 
1392                                      ) 
1393