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

Source Code for Module ais.backup

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