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