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

Source Code for Module ais.ais_msg_21

  1  #!/usr/bin/env python 
  2   
  3  __version__ = '$Revision: 4791 $'.split()[1] 
  4  __date__ = '$Date: 2007-01-23 $'.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  ''' 
 34   
 35  import sys 
 36  from decimal import Decimal 
 37  from BitVector import BitVector 
 38   
 39  import binary, aisstring 
 40   
 41  # FIX: check to see if these will be needed 
 42  TrueBV  = BitVector(bitstring="1") 
 43  "Why always rebuild the True bit?  This should speed things up a bunch" 
 44  FalseBV = BitVector(bitstring="0") 
 45  "Why always rebuild the False bit?  This should speed things up a bunch" 
 46   
 47   
 48  fieldList = [ 
 49          'MessageID', 
 50          'RepeatIndicator', 
 51          'UserID', 
 52          'type', 
 53          'name', 
 54          'PositionAccuracy', 
 55          'Position_longitude', 
 56          'Position_latitude', 
 57          'dim', 
 58          'FixType', 
 59          'timestamp', 
 60          'OffPosition', 
 61          'RegionalApp', 
 62          'RAIM', 
 63          'Spare', 
 64  ] 
 65   
66 -def encode(params, validate=False):
67 '''Create a AidsToNavReport binary message payload to pack into an AIS Msg AidsToNavReport. 68 69 Fields in params: 70 - MessageID(uint): AIS message number. Must be 21 aka 'F' (field automatically set to "21") 71 - RepeatIndicator(uint): Indicated how many times a message has been repeated 72 - UserID(uint): Unique ship identification number (MMSI) 73 - type(uint): IALA type of aid-to-navigation 74 - name(aisstr6): Name of the aid-to-navigation 75 - PositionAccuracy(uint): Accuracy of positioning fixes 76 - Position_longitude(decimal): Location of the vessel East West location 77 - Position_latitude(decimal): Location of the vessel North South location 78 - dim(uint): FIX: break this out. 79 - FixType(uint): Type of electronic position fixing device 80 - timestamp(uint): UTC second when report was generated 81 - OffPosition(bool): True when the AtoN is off station 82 - RegionalApp(uint): Should be set to zero (field automatically set to "0") 83 - RAIM(bool): Receiver autonomous integrity monitoring flag 84 - Spare(uint): Not Used (field automatically set to "0") 85 @param params: Dictionary of field names/values. Throws a ValueError exception if required is missing 86 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 87 @rtype: BitVector 88 @return: encoded binary message (for binary messages, this needs to be wrapped in a msg 8 89 @note: The returned bits may not be 6 bit aligned. It is up to you to pad out the bits. 90 ''' 91 92 bvList = [] 93 bvList.append(binary.setBitVectorSize(BitVector(intVal=21),6)) 94 if 'RepeatIndicator' in params: 95 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['RepeatIndicator']),2)) 96 else: 97 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2)) 98 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['UserID']),30)) 99 if 'type' in params: 100 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['type']),5)) 101 else: 102 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),5)) 103 if 'name' in params: 104 bvList.append(aisstring.encode(params['name'],120)) 105 else: 106 bvList.append(aisstring.encode('@@@@@@@@@@@@@@@@@@@@',120)) 107 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['PositionAccuracy']),1)) 108 if 'Position_longitude' in params: 109 bvList.append(binary.bvFromSignedInt(int(Decimal(params['Position_longitude'])*Decimal('600000')),28)) 110 else: 111 bvList.append(binary.bvFromSignedInt(108600000,28)) 112 if 'Position_latitude' in params: 113 bvList.append(binary.bvFromSignedInt(int(Decimal(params['Position_latitude'])*Decimal('600000')),27)) 114 else: 115 bvList.append(binary.bvFromSignedInt(54600000,27)) 116 if 'dim' in params: 117 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['dim']),30)) 118 else: 119 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),30)) 120 if 'FixType' in params: 121 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['FixType']),4)) 122 else: 123 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),4)) 124 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['timestamp']),6)) 125 if params["OffPosition"]: bvList.append(TrueBV) 126 else: bvList.append(FalseBV) 127 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),8)) 128 if params["RAIM"]: bvList.append(TrueBV) 129 else: bvList.append(FalseBV) 130 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),3)) 131 132 return binary.joinBV(bvList)
133
134 -def decode(bv, validate=False):
135 '''Unpack a AidsToNavReport message 136 137 Fields in params: 138 - MessageID(uint): AIS message number. Must be 21 aka 'F' (field automatically set to "21") 139 - RepeatIndicator(uint): Indicated how many times a message has been repeated 140 - UserID(uint): Unique ship identification number (MMSI) 141 - type(uint): IALA type of aid-to-navigation 142 - name(aisstr6): Name of the aid-to-navigation 143 - PositionAccuracy(uint): Accuracy of positioning fixes 144 - Position_longitude(decimal): Location of the vessel East West location 145 - Position_latitude(decimal): Location of the vessel North South location 146 - dim(uint): FIX: break this out. 147 - FixType(uint): Type of electronic position fixing device 148 - timestamp(uint): UTC second when report was generated 149 - OffPosition(bool): True when the AtoN is off station 150 - RegionalApp(uint): Should be set to zero (field automatically set to "0") 151 - RAIM(bool): Receiver autonomous integrity monitoring flag 152 - Spare(uint): Not Used (field automatically set to "0") 153 @type bv: BitVector 154 @param bv: Bits defining a message 155 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 156 @rtype: dict 157 @return: params 158 ''' 159 160 #Would be nice to check the bit count here.. 161 #if validate: 162 # assert (len(bv)==FIX: SOME NUMBER) 163 r = {} 164 r['MessageID']=21 165 r['RepeatIndicator']=int(bv[6:8]) 166 r['UserID']=int(bv[8:38]) 167 r['type']=int(bv[38:43]) 168 r['name']=aisstring.decode(bv[43:163]) 169 r['PositionAccuracy']=int(bv[163:164]) 170 r['Position_longitude']=Decimal(binary.signedIntFromBV(bv[164:192]))/Decimal('600000') 171 r['Position_latitude']=Decimal(binary.signedIntFromBV(bv[192:219]))/Decimal('600000') 172 r['dim']=int(bv[219:249]) 173 r['FixType']=int(bv[249:253]) 174 r['timestamp']=int(bv[253:259]) 175 r['OffPosition']=bool(int(bv[259:260])) 176 r['RegionalApp']=0 177 r['RAIM']=bool(int(bv[268:269])) 178 r['Spare']=0 179 return r
180
181 -def decodeMessageID(bv, validate=False):
182 return 21
183
184 -def decodeRepeatIndicator(bv, validate=False):
185 return int(bv[6:8])
186
187 -def decodeUserID(bv, validate=False):
188 return int(bv[8:38])
189
190 -def decodetype(bv, validate=False):
191 return int(bv[38:43])
192
193 -def decodename(bv, validate=False):
194 return aisstring.decode(bv[43:163])
195
196 -def decodePositionAccuracy(bv, validate=False):
197 return int(bv[163:164])
198
199 -def decodePosition_longitude(bv, validate=False):
200 return Decimal(binary.signedIntFromBV(bv[164:192]))/Decimal('600000')
201
202 -def decodePosition_latitude(bv, validate=False):
203 return Decimal(binary.signedIntFromBV(bv[192:219]))/Decimal('600000')
204
205 -def decodedim(bv, validate=False):
206 return int(bv[219:249])
207
208 -def decodeFixType(bv, validate=False):
209 return int(bv[249:253])
210
211 -def decodetimestamp(bv, validate=False):
212 return int(bv[253:259])
213
214 -def decodeOffPosition(bv, validate=False):
215 return bool(int(bv[259:260]))
216
217 -def decodeRegionalApp(bv, validate=False):
218 return 0
219
220 -def decodeRAIM(bv, validate=False):
221 return bool(int(bv[268:269]))
222
223 -def decodeSpare(bv, validate=False):
224 return 0
225 226
227 -def printHtml(params, out=sys.stdout):
228 out.write("<h3>AidsToNavReport<h3>\n") 229 out.write("<table border=\"1\">\n") 230 out.write("<tr bgcolor=\"orange\">\n") 231 out.write("<th align=\"left\">Field Name</th>\n") 232 out.write("<th align=\"left\">Type</th>\n") 233 out.write("<th align=\"left\">Value</th>\n") 234 out.write("<th align=\"left\">Value in Lookup Table</th>\n") 235 out.write("<th align=\"left\">Units</th>\n") 236 out.write("\n") 237 out.write("<tr>\n") 238 out.write("<td>MessageID</td>\n") 239 out.write("<td>uint</td>\n") 240 if 'MessageID' in params: 241 out.write(" <td>"+str(params['MessageID'])+"</td>\n") 242 out.write(" <td>"+str(params['MessageID'])+"</td>\n") 243 out.write("</tr>\n") 244 out.write("\n") 245 out.write("<tr>\n") 246 out.write("<td>RepeatIndicator</td>\n") 247 out.write("<td>uint</td>\n") 248 if 'RepeatIndicator' in params: 249 out.write(" <td>"+str(params['RepeatIndicator'])+"</td>\n") 250 if str(params['RepeatIndicator']) in RepeatIndicatorDecodeLut: 251 out.write("<td>"+RepeatIndicatorDecodeLut[str(params['RepeatIndicator'])]+"</td>") 252 else: 253 out.write("<td><i>Missing LUT entry</i></td>") 254 out.write("</tr>\n") 255 out.write("\n") 256 out.write("<tr>\n") 257 out.write("<td>UserID</td>\n") 258 out.write("<td>uint</td>\n") 259 if 'UserID' in params: 260 out.write(" <td>"+str(params['UserID'])+"</td>\n") 261 out.write(" <td>"+str(params['UserID'])+"</td>\n") 262 out.write("</tr>\n") 263 out.write("\n") 264 out.write("<tr>\n") 265 out.write("<td>type</td>\n") 266 out.write("<td>uint</td>\n") 267 if 'type' in params: 268 out.write(" <td>"+str(params['type'])+"</td>\n") 269 if str(params['type']) in typeDecodeLut: 270 out.write("<td>"+typeDecodeLut[str(params['type'])]+"</td>") 271 else: 272 out.write("<td><i>Missing LUT entry</i></td>") 273 out.write("</tr>\n") 274 out.write("\n") 275 out.write("<tr>\n") 276 out.write("<td>name</td>\n") 277 out.write("<td>aisstr6</td>\n") 278 if 'name' in params: 279 out.write(" <td>"+str(params['name'])+"</td>\n") 280 out.write(" <td>"+str(params['name'])+"</td>\n") 281 out.write("</tr>\n") 282 out.write("\n") 283 out.write("<tr>\n") 284 out.write("<td>PositionAccuracy</td>\n") 285 out.write("<td>uint</td>\n") 286 if 'PositionAccuracy' in params: 287 out.write(" <td>"+str(params['PositionAccuracy'])+"</td>\n") 288 if str(params['PositionAccuracy']) in PositionAccuracyDecodeLut: 289 out.write("<td>"+PositionAccuracyDecodeLut[str(params['PositionAccuracy'])]+"</td>") 290 else: 291 out.write("<td><i>Missing LUT entry</i></td>") 292 out.write("</tr>\n") 293 out.write("\n") 294 out.write("<tr>\n") 295 out.write("<td>Position_longitude</td>\n") 296 out.write("<td>decimal</td>\n") 297 if 'Position_longitude' in params: 298 out.write(" <td>"+str(params['Position_longitude'])+"</td>\n") 299 out.write(" <td>"+str(params['Position_longitude'])+"</td>\n") 300 out.write("<td>degrees</td>\n") 301 out.write("</tr>\n") 302 out.write("\n") 303 out.write("<tr>\n") 304 out.write("<td>Position_latitude</td>\n") 305 out.write("<td>decimal</td>\n") 306 if 'Position_latitude' in params: 307 out.write(" <td>"+str(params['Position_latitude'])+"</td>\n") 308 out.write(" <td>"+str(params['Position_latitude'])+"</td>\n") 309 out.write("<td>degrees</td>\n") 310 out.write("</tr>\n") 311 out.write("\n") 312 out.write("<tr>\n") 313 out.write("<td>dim</td>\n") 314 out.write("<td>uint</td>\n") 315 if 'dim' in params: 316 out.write(" <td>"+str(params['dim'])+"</td>\n") 317 out.write(" <td>"+str(params['dim'])+"</td>\n") 318 out.write("</tr>\n") 319 out.write("\n") 320 out.write("<tr>\n") 321 out.write("<td>FixType</td>\n") 322 out.write("<td>uint</td>\n") 323 if 'FixType' in params: 324 out.write(" <td>"+str(params['FixType'])+"</td>\n") 325 if str(params['FixType']) in FixTypeDecodeLut: 326 out.write("<td>"+FixTypeDecodeLut[str(params['FixType'])]+"</td>") 327 else: 328 out.write("<td><i>Missing LUT entry</i></td>") 329 out.write("</tr>\n") 330 out.write("\n") 331 out.write("<tr>\n") 332 out.write("<td>timestamp</td>\n") 333 out.write("<td>uint</td>\n") 334 if 'timestamp' in params: 335 out.write(" <td>"+str(params['timestamp'])+"</td>\n") 336 if str(params['timestamp']) in timestampDecodeLut: 337 out.write("<td>"+timestampDecodeLut[str(params['timestamp'])]+"</td>") 338 else: 339 out.write("<td><i>Missing LUT entry</i></td>") 340 out.write("</tr>\n") 341 out.write("\n") 342 out.write("<tr>\n") 343 out.write("<td>OffPosition</td>\n") 344 out.write("<td>bool</td>\n") 345 if 'OffPosition' in params: 346 out.write(" <td>"+str(params['OffPosition'])+"</td>\n") 347 if str(params['OffPosition']) in OffPositionDecodeLut: 348 out.write("<td>"+OffPositionDecodeLut[str(params['OffPosition'])]+"</td>") 349 else: 350 out.write("<td><i>Missing LUT entry</i></td>") 351 out.write("</tr>\n") 352 out.write("\n") 353 out.write("<tr>\n") 354 out.write("<td>RegionalApp</td>\n") 355 out.write("<td>uint</td>\n") 356 if 'RegionalApp' in params: 357 out.write(" <td>"+str(params['RegionalApp'])+"</td>\n") 358 out.write(" <td>"+str(params['RegionalApp'])+"</td>\n") 359 out.write("</tr>\n") 360 out.write("\n") 361 out.write("<tr>\n") 362 out.write("<td>RAIM</td>\n") 363 out.write("<td>bool</td>\n") 364 if 'RAIM' in params: 365 out.write(" <td>"+str(params['RAIM'])+"</td>\n") 366 if str(params['RAIM']) in RAIMDecodeLut: 367 out.write("<td>"+RAIMDecodeLut[str(params['RAIM'])]+"</td>") 368 else: 369 out.write("<td><i>Missing LUT entry</i></td>") 370 out.write("</tr>\n") 371 out.write("\n") 372 out.write("<tr>\n") 373 out.write("<td>Spare</td>\n") 374 out.write("<td>uint</td>\n") 375 if 'Spare' in params: 376 out.write(" <td>"+str(params['Spare'])+"</td>\n") 377 out.write(" <td>"+str(params['Spare'])+"</td>\n") 378 out.write("</tr>\n") 379 out.write("</table>\n")
380 381
382 -def printKml(params, out=sys.stdout):
383 '''KML (Keyhole Markup Language) for Google Earth, but without the header/footer''' 384 out.write("\ <Placemark>\n") 385 out.write("\t <name>"+str(params['UserID'])+"</name>\n") 386 out.write("\t\t<description>\n") 387 import StringIO 388 buf = StringIO.StringIO() 389 printHtml(params,buf) 390 import cgi 391 out.write(cgi.escape(buf.getvalue())) 392 out.write("\t\t</description>\n") 393 out.write("\t\t<styleUrl>#m_ylw-pushpin_copy0</styleUrl>\n") 394 out.write("\t\t<Point>\n") 395 out.write("\t\t\t<coordinates>") 396 out.write(str(params['Position_longitude'])) 397 out.write(',') 398 out.write(str(params['Position_latitude'])) 399 out.write(",0</coordinates>\n") 400 out.write("\t\t</Point>\n") 401 out.write("\t</Placemark>\n")
402
403 -def printFields(params, out=sys.stdout, format='std', fieldList=None):
404 '''Print a Spare message to stdout. 405 406 Fields in params: 407 - MessageID(uint): AIS message number. Must be 21 aka 'F' (field automatically set to "21") 408 - RepeatIndicator(uint): Indicated how many times a message has been repeated 409 - UserID(uint): Unique ship identification number (MMSI) 410 - type(uint): IALA type of aid-to-navigation 411 - name(aisstr6): Name of the aid-to-navigation 412 - PositionAccuracy(uint): Accuracy of positioning fixes 413 - Position_longitude(decimal): Location of the vessel East West location 414 - Position_latitude(decimal): Location of the vessel North South location 415 - dim(uint): FIX: break this out. 416 - FixType(uint): Type of electronic position fixing device 417 - timestamp(uint): UTC second when report was generated 418 - OffPosition(bool): True when the AtoN is off station 419 - RegionalApp(uint): Should be set to zero (field automatically set to "0") 420 - RAIM(bool): Receiver autonomous integrity monitoring flag 421 - Spare(uint): Not Used (field automatically set to "0") 422 @param params: Dictionary of field names/values. 423 @param out: File like object to write to 424 @rtype: stdout 425 @return: text to out 426 ''' 427 428 if 'std'==format: 429 out.write("Spare:\n") 430 if 'MessageID' in params: out.write(" MessageID: "+str(params['MessageID'])+"\n") 431 if 'RepeatIndicator' in params: out.write(" RepeatIndicator: "+str(params['RepeatIndicator'])+"\n") 432 if 'UserID' in params: out.write(" UserID: "+str(params['UserID'])+"\n") 433 if 'type' in params: out.write(" type: "+str(params['type'])+"\n") 434 if 'name' in params: out.write(" name: "+str(params['name'])+"\n") 435 if 'PositionAccuracy' in params: out.write(" PositionAccuracy: "+str(params['PositionAccuracy'])+"\n") 436 if 'Position_longitude' in params: out.write(" Position_longitude: "+str(params['Position_longitude'])+"\n") 437 if 'Position_latitude' in params: out.write(" Position_latitude: "+str(params['Position_latitude'])+"\n") 438 if 'dim' in params: out.write(" dim: "+str(params['dim'])+"\n") 439 if 'FixType' in params: out.write(" FixType: "+str(params['FixType'])+"\n") 440 if 'timestamp' in params: out.write(" timestamp: "+str(params['timestamp'])+"\n") 441 if 'OffPosition' in params: out.write(" OffPosition: "+str(params['OffPosition'])+"\n") 442 if 'RegionalApp' in params: out.write(" RegionalApp: "+str(params['RegionalApp'])+"\n") 443 if 'RAIM' in params: out.write(" RAIM: "+str(params['RAIM'])+"\n") 444 if 'Spare' in params: out.write(" Spare: "+str(params['Spare'])+"\n") 445 elif 'csv'==format: 446 if None == options.fieldList: 447 options.fieldList = fieldList 448 needComma = False; 449 for field in fieldList: 450 if needComma: out.write(',') 451 needComma = True 452 if field in params: 453 out.write(str(params[field])) 454 # else: leave it empty 455 out.write("\n") 456 elif 'html'==format: 457 printHtml(params,out) 458 elif 'sql'==format: 459 sqlInsertStr(params,out) 460 elif 'kml'==format: 461 printKml(params,out) 462 elif 'kml-full'==format: 463 out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") 464 out.write("<kml xmlns=\"http://earth.google.com/kml/2.1\">\n") 465 out.write("<Document>\n") 466 out.write(" <name>AidsToNavReport</name>\n") 467 printKml(params,out) 468 out.write("</Document>\n") 469 out.write("</kml>\n") 470 else: 471 print "ERROR: unknown format:",format 472 assert False 473 474 return # Nothing to return
475 476 RepeatIndicatorEncodeLut = { 477 'default':'0', 478 'do not repeat any more':'3', 479 } #RepeatIndicatorEncodeLut 480 481 RepeatIndicatorDecodeLut = { 482 '0':'default', 483 '3':'do not repeat any more', 484 } # RepeatIndicatorEncodeLut 485 486 typeEncodeLut = { 487 'Default, Type of A to N not specified':'0', 488 'Reference point':'1', 489 'RACON':'2', 490 'Off Shore Structure':'3', 491 'Spare':'4', 492 'Light, without sectors':'5', 493 'Light, with sectors':'6', 494 'Leading Light Front':'7', 495 'Leading Light Rear':'8', 496 'Beacon, Cardinal N':'9', 497 'Beacon, Cardinal E':'10', 498 'Beacon, Cardinal S':'11', 499 'Beacon, Cardinal W':'12', 500 'Beacon, Port hand':'13', 501 'Beacon, Starbord hand':'14', 502 'Beacon, Preferred channel port hand':'15', 503 'Beacon, Preferred channel starboard hand':'16', 504 'Beacon, Isolated danger':'17', 505 'Beacon, Safe water':'18', 506 'Beacon, Special mark':'19', 507 'Cardinal Mark N':'20', 508 'Cardinal Mark E':'21', 509 'Cardinal Mark S':'22', 510 'Cardinal Mark W':'23', 511 'Port hand Mark':'24', 512 'Starbord hand Mark':'25', 513 'Preferred Channel Port hand':'26', 514 'Preferred Channel Starboard hand':'27', 515 'Isolated danger':'28', 516 'Safe water':'29', 517 'Special Mark':'30', 518 'Light Vessel/LANBY':'31', 519 } #typeEncodeLut 520 521 typeDecodeLut = { 522 '0':'Default, Type of A to N not specified', 523 '1':'Reference point', 524 '2':'RACON', 525 '3':'Off Shore Structure', 526 '4':'Spare', 527 '5':'Light, without sectors', 528 '6':'Light, with sectors', 529 '7':'Leading Light Front', 530 '8':'Leading Light Rear', 531 '9':'Beacon, Cardinal N', 532 '10':'Beacon, Cardinal E', 533 '11':'Beacon, Cardinal S', 534 '12':'Beacon, Cardinal W', 535 '13':'Beacon, Port hand', 536 '14':'Beacon, Starbord hand', 537 '15':'Beacon, Preferred channel port hand', 538 '16':'Beacon, Preferred channel starboard hand', 539 '17':'Beacon, Isolated danger', 540 '18':'Beacon, Safe water', 541 '19':'Beacon, Special mark', 542 '20':'Cardinal Mark N', 543 '21':'Cardinal Mark E', 544 '22':'Cardinal Mark S', 545 '23':'Cardinal Mark W', 546 '24':'Port hand Mark', 547 '25':'Starbord hand Mark', 548 '26':'Preferred Channel Port hand', 549 '27':'Preferred Channel Starboard hand', 550 '28':'Isolated danger', 551 '29':'Safe water', 552 '30':'Special Mark', 553 '31':'Light Vessel/LANBY', 554 } # typeEncodeLut 555 556 PositionAccuracyEncodeLut = { 557 'low (greater than 10 m)':'0', 558 'high (less than 10 m)':'1', 559 } #PositionAccuracyEncodeLut 560 561 PositionAccuracyDecodeLut = { 562 '0':'low (greater than 10 m)', 563 '1':'high (less than 10 m)', 564 } # PositionAccuracyEncodeLut 565 566 FixTypeEncodeLut = { 567 'Undefined (default)':'0', 568 'GPS':'1', 569 'GLONASS':'2', 570 'Combined GPS/GLONASS':'3', 571 'Loran-C':'4', 572 'Chayka':'5', 573 'Integrated Navigation System':'6', 574 'surveyed':'7', 575 'not used - 8':'8', 576 'not used - 9':'9', 577 'not used - 10':'10', 578 'not used - 11':'11', 579 'not used - 12':'12', 580 'not used - 13':'13', 581 'not used - 14':'14', 582 'not used - 15':'15', 583 } #FixTypeEncodeLut 584 585 FixTypeDecodeLut = { 586 '0':'Undefined (default)', 587 '1':'GPS', 588 '2':'GLONASS', 589 '3':'Combined GPS/GLONASS', 590 '4':'Loran-C', 591 '5':'Chayka', 592 '6':'Integrated Navigation System', 593 '7':'surveyed', 594 '8':'not used - 8', 595 '9':'not used - 9', 596 '10':'not used - 10', 597 '11':'not used - 11', 598 '12':'not used - 12', 599 '13':'not used - 13', 600 '14':'not used - 14', 601 '15':'not used - 15', 602 } # FixTypeEncodeLut 603 604 timestampEncodeLut = { 605 'Positioning system is in manual mode':'61', 606 'Electronic position fixing system operates in estimated mode':'62', 607 'Positioning system is inoperative':'63', 608 } #timestampEncodeLut 609 610 timestampDecodeLut = { 611 '61':'Positioning system is in manual mode', 612 '62':'Electronic position fixing system operates in estimated mode', 613 '63':'Positioning system is inoperative', 614 } # timestampEncodeLut 615 616 OffPositionEncodeLut = { 617 'On position':'False', 618 'Off position':'True', 619 } #OffPositionEncodeLut 620 621 OffPositionDecodeLut = { 622 'False':'On position', 623 'True':'Off position', 624 } # OffPositionEncodeLut 625 626 RAIMEncodeLut = { 627 'not in use':'False', 628 'in use':'True', 629 } #RAIMEncodeLut 630 631 RAIMDecodeLut = { 632 'False':'not in use', 633 'True':'in use', 634 } # RAIMEncodeLut 635 636 ###################################################################### 637 # SQL SUPPORT 638 ###################################################################### 639
640 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None):
641 ''' 642 Return the SQL CREATE command for this message type 643 @param outfile: file like object to print to. 644 @param fields: which fields to put in the create. Defaults to all. 645 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 646 @return: sql create string 647 @rtype: str 648 649 @see: sqlCreate 650 ''' 651 outfile.write(str(sqlCreate(fields,extraFields)))
652
653 -def sqlCreate(fields=None, extraFields=None):
654 ''' 655 Return the sqlhelp object to create the table. 656 657 @param fields: which fields to put in the create. Defaults to all. 658 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 659 @return: An object that can be used to generate a return 660 @rtype: sqlhelp.create 661 ''' 662 if None == fields: fields = fieldList 663 import sqlhelp 664 c = sqlhelp.create('AidsToNavReport') 665 if 'MessageID' in fields: c.addInt ('MessageID') 666 if 'RepeatIndicator' in fields: c.addInt ('RepeatIndicator') 667 if 'UserID' in fields: c.addInt ('UserID') 668 if 'type' in fields: c.addInt ('type') 669 if 'name' in fields: c.addVarChar(name,20) 670 if 'PositionAccuracy' in fields: c.addInt ('PositionAccuracy') 671 if 'Position_longitude' in fields: c.addDecimal('Position_longitude',8,5) 672 if 'Position_latitude' in fields: c.addDecimal('Position_latitude',8,5) 673 if 'dim' in fields: c.addInt ('dim') 674 if 'FixType' in fields: c.addInt ('FixType') 675 if 'timestamp' in fields: c.addInt ('timestamp') 676 if 'OffPosition' in fields: c.addBool('OffPosition') 677 if 'RegionalApp' in fields: c.addInt ('RegionalApp') 678 if 'RAIM' in fields: c.addBool('RAIM') 679 if 'Spare' in fields: c.addInt ('Spare') 680 681 return c
682
683 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None):
684 ''' 685 Return the SQL CREATE command for this message type 686 @param params: dictionary of values keyed by field name 687 @param outfile: file like object to print to. 688 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields 689 @return: sql create string 690 @rtype: str 691 692 @see: sqlCreate 693 ''' 694 outfile.write(str(sqlInsert(params,extraParams)))
695 696
697 -def sqlInsert(params,extraParams=None):
698 ''' 699 Give the SQL insert statement 700 @param params: dict keyed by field name of values 701 @param extraParams: any extra fields that you have created beyond the normal ais message fields 702 @rtype: sqlhelp.insert 703 @return: insert class instance 704 @todo: allow optional type checking of params? 705 @warning: this will take invalid keys happily and do what??? 706 ''' 707 import sqlhelp 708 i = sqlhelp.insert('AidsToNavReport') 709 for key in params: i.add(key,params[key]) 710 if None != extraParams: 711 for key in extraParams: 712 i.add(key,extraParams[key]) 713 714 return i
715 716 717 ###################################################################### 718 # UNIT TESTING 719 ###################################################################### 720 import unittest
721 -def testParams():
722 '''Return a params file base on the testvalue tags. 723 @rtype: dict 724 @return: params based on testvalue tags 725 ''' 726 params = {} 727 params['MessageID'] = 21 728 params['RepeatIndicator'] = 1 729 params['UserID'] = 1193046 730 params['type'] = 28 731 params['name'] = 'BUNCH OF ROCKS ATON@' 732 params['PositionAccuracy'] = 1 733 params['Position_longitude'] = Decimal('-122.16328055555556') 734 params['Position_latitude'] = Decimal('37.424458333333334') 735 params['dim'] = 0 736 params['FixType'] = 2 737 params['timestamp'] = 62 738 params['OffPosition'] = False 739 params['RegionalApp'] = 0 740 params['RAIM'] = False 741 params['Spare'] = 0 742 743 return params
744
745 -class TestAidsToNavReport(unittest.TestCase):
746 '''Use testvalue tag text from each type to build test case the AidsToNavReport message'''
747 - def testEncodeDecode(self):
748 749 params = testParams() 750 bits = encode(params) 751 r = decode(bits) 752 753 # Check that each parameter came through ok. 754 self.failUnlessEqual(r['MessageID'],params['MessageID']) 755 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator']) 756 self.failUnlessEqual(r['UserID'],params['UserID']) 757 self.failUnlessEqual(r['type'],params['type']) 758 self.failUnlessEqual(r['name'],params['name']) 759 self.failUnlessEqual(r['PositionAccuracy'],params['PositionAccuracy']) 760 self.failUnlessAlmostEqual(r['Position_longitude'],params['Position_longitude'],5) 761 self.failUnlessAlmostEqual(r['Position_latitude'],params['Position_latitude'],5) 762 self.failUnlessEqual(r['dim'],params['dim']) 763 self.failUnlessEqual(r['FixType'],params['FixType']) 764 self.failUnlessEqual(r['timestamp'],params['timestamp']) 765 self.failUnlessEqual(r['OffPosition'],params['OffPosition']) 766 self.failUnlessEqual(r['RegionalApp'],params['RegionalApp']) 767 self.failUnlessEqual(r['RAIM'],params['RAIM']) 768 self.failUnlessEqual(r['Spare'],params['Spare'])
769
770 -def addMsgOptions(parser):
771 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true', 772 help='decode a "AidsToNavReport" AIS message') 773 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true', 774 help='encode a "AidsToNavReport" AIS message') 775 parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int' 776 ,help='Field parameter value [default: %default]') 777 parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int' 778 ,help='Field parameter value [default: %default]') 779 parser.add_option('--type-field', dest='typeField',default=0,metavar='uint',type='int' 780 ,help='Field parameter value [default: %default]') 781 parser.add_option('--name-field', dest='nameField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string' 782 ,help='Field parameter value [default: %default]') 783 parser.add_option('--PositionAccuracy-field', dest='PositionAccuracyField',metavar='uint',type='int' 784 ,help='Field parameter value [default: %default]') 785 parser.add_option('--Position_longitude-field', dest='Position_longitudeField',default=Decimal('181'),metavar='decimal',type='string' 786 ,help='Field parameter value [default: %default]') 787 parser.add_option('--Position_latitude-field', dest='Position_latitudeField',default=Decimal('91'),metavar='decimal',type='string' 788 ,help='Field parameter value [default: %default]') 789 parser.add_option('--dim-field', dest='dimField',default=0,metavar='uint',type='int' 790 ,help='Field parameter value [default: %default]') 791 parser.add_option('--FixType-field', dest='FixTypeField',default=0,metavar='uint',type='int' 792 ,help='Field parameter value [default: %default]') 793 parser.add_option('--timestamp-field', dest='timestampField',metavar='uint',type='int' 794 ,help='Field parameter value [default: %default]') 795 parser.add_option('--OffPosition-field', dest='OffPositionField',metavar='bool',type='int' 796 ,help='Field parameter value [default: %default]') 797 parser.add_option('--RAIM-field', dest='RAIMField',metavar='bool',type='int' 798 ,help='Field parameter value [default: %default]')
799 800 ############################################################ 801 if __name__=='__main__': 802 803 from optparse import OptionParser 804 parser = OptionParser(usage="%prog [options]", 805 version="%prog "+__version__) 806 807 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true', 808 help='run the documentation tests') 809 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true', 810 help='run the unit tests') 811 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 812 help='Make the test output verbose') 813 814 # FIX: remove nmea from binary messages. No way to build the whole packet? 815 # FIX: or build the surrounding msg 8 for a broadcast? 816 typeChoices = ('binary','nmeapayload','nmea') # FIX: what about a USCG type message? 817 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType' 818 ,default='nmeapayload' 819 ,help='What kind of string to expect ('+', '.join(typeChoices)+') [default: %default]') 820 821 822 outputChoices = ('std','html','csv','sql' , 'kml','kml-full') 823 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType' 824 ,default='std' 825 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]') 826 827 parser.add_option('-o','--output',dest='outputFileName',default=None, 828 help='Name of the python file to write [default: stdout]') 829 830 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append', 831 choices=fieldList, 832 help='Which fields to include in the output. Currently only for csv output [default: all]') 833 834 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true', 835 help='Print the field name for csv') 836 837 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true', 838 help='Print out an sql create command for the table.') 839 840 addMsgOptions(parser) 841 842 (options,args) = parser.parse_args() 843 success=True 844 845 if options.doctest: 846 import os; print os.path.basename(sys.argv[0]), 'doctests ...', 847 sys.argv= [sys.argv[0]] 848 if options.verbose: sys.argv.append('-v') 849 import doctest 850 numfail,numtests=doctest.testmod() 851 if numfail==0: print 'ok' 852 else: 853 print 'FAILED' 854 success=False 855 856 if not success: sys.exit('Something Failed') 857 del success # Hide success from epydoc 858 859 if options.unittest: 860 sys.argv = [sys.argv[0]] 861 if options.verbose: sys.argv.append('-v') 862 unittest.main() 863 864 outfile = sys.stdout 865 if None!=options.outputFileName: 866 outfile = file(options.outputFileName,'w') 867 868 869 if options.doEncode: 870 # First make sure all non required options are specified 871 if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField") 872 if None==options.UserIDField: parser.error("missing value for UserIDField") 873 if None==options.typeField: parser.error("missing value for typeField") 874 if None==options.nameField: parser.error("missing value for nameField") 875 if None==options.PositionAccuracyField: parser.error("missing value for PositionAccuracyField") 876 if None==options.Position_longitudeField: parser.error("missing value for Position_longitudeField") 877 if None==options.Position_latitudeField: parser.error("missing value for Position_latitudeField") 878 if None==options.dimField: parser.error("missing value for dimField") 879 if None==options.FixTypeField: parser.error("missing value for FixTypeField") 880 if None==options.timestampField: parser.error("missing value for timestampField") 881 if None==options.OffPositionField: parser.error("missing value for OffPositionField") 882 if None==options.RAIMField: parser.error("missing value for RAIMField") 883 msgDict={ 884 'MessageID': '21', 885 'RepeatIndicator': options.RepeatIndicatorField, 886 'UserID': options.UserIDField, 887 'type': options.typeField, 888 'name': options.nameField, 889 'PositionAccuracy': options.PositionAccuracyField, 890 'Position_longitude': options.Position_longitudeField, 891 'Position_latitude': options.Position_latitudeField, 892 'dim': options.dimField, 893 'FixType': options.FixTypeField, 894 'timestamp': options.timestampField, 895 'OffPosition': options.OffPositionField, 896 'RegionalApp': '0', 897 'RAIM': options.RAIMField, 898 'Spare': '0', 899 } 900 901 bits = encode(msgDict) 902 if 'binary'==options.ioType: print str(bits) 903 elif 'nmeapayload'==options.ioType: 904 # FIX: figure out if this might be necessary at compile time 905 print "bitLen",len(bits) 906 bitLen=len(bits) 907 if bitLen%6!=0: 908 bits = bits + BitVector(size=(6 - (bitLen%6))) # Pad out to multiple of 6 909 print "result:",binary.bitvectoais6(bits)[0] 910 911 912 # FIX: Do not emit this option for the binary message payloads. Does not make sense. 913 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability") 914 else: sys.exit('ERROR: unknown ioType. Help!') 915 916 917 if options.sqlCreate: 918 sqlCreateStr(outfile,options.fieldList) 919 920 if options.printCsvfieldList: 921 # Make a csv separated list of fields that will be displayed for csv 922 if None == options.fieldList: options.fieldList = fieldList 923 import StringIO 924 buf = StringIO.StringIO() 925 for field in options.fieldList: 926 buf.write(field+',') 927 result = buf.getvalue() 928 if result[-1] == ',': print result[:-1] 929 else: print result 930 931 if options.doDecode: 932 for msg in args: 933 bv = None 934 if 'binary' == options.ioType: bv = BitVector(bitstring=msg) 935 elif 'nmeapayload'== options.ioType: bv = binary.ais6tobitvec(msg) 936 elif 'nmea' == options.ioType: bv = binary.ais6tobitvec(msg.split(',')[5]) 937 else: sys.exit('ERROR: unknown ioType. Help!') 938 939 printFields(decode(bv),out=outfile,format=options.outputType,fieldList=options.fieldList) 940