Script 1_py
[hide private]
[frames] | no frames]

Source Code for Script script-1_py

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