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

Source Code for Module ais.ais_msg_10

  1  #!/usr/bin/env python 
  2   
  3  __version__ = '$Revision: 4791 $'.split()[1] 
  4  __date__ = '$Date: 2007-03-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  @todo: FIX: put in a description of the message here with fields and types. 
 34  ''' 
 35   
 36  import sys 
 37  from decimal import Decimal 
 38  from BitVector import BitVector 
 39   
 40  import binary, aisstring 
 41   
 42  # FIX: check to see if these will be needed 
 43  TrueBV  = BitVector(bitstring="1") 
 44  "Why always rebuild the True bit?  This should speed things up a bunch" 
 45  FalseBV = BitVector(bitstring="0") 
 46  "Why always rebuild the False bit?  This should speed things up a bunch" 
 47   
 48   
 49  fieldList = ( 
 50          'MessageID', 
 51          'RepeatIndicator', 
 52          'UserID', 
 53          'Spare1', 
 54          'DestID', 
 55          'Spare2', 
 56  ) 
 57   
 58  fieldListPostgres = ( 
 59          'MessageID', 
 60          'RepeatIndicator', 
 61          'UserID', 
 62          'Spare1', 
 63          'DestID', 
 64          'Spare2', 
 65  ) 
 66   
 67  toPgFields = { 
 68  } 
 69  ''' 
 70  Go to the Postgis field names from the straight field name 
 71  ''' 
 72   
 73  fromPgFields = { 
 74  } 
 75  ''' 
 76  Go from the Postgis field names to the straight field name 
 77  ''' 
 78   
 79  pgTypes = { 
 80  } 
 81  ''' 
 82  Lookup table for each postgis field name to get its type. 
 83  ''' 
 84   
85 -def encode(params, validate=False):
86 '''Create a utcquery binary message payload to pack into an AIS Msg utcquery. 87 88 Fields in params: 89 - MessageID(uint): AIS message number. Must be 10 (field automatically set to "10") 90 - RepeatIndicator(uint): Indicated how many times a message has been repeated 91 - UserID(uint): Unique ship identification number (MMSI) 92 - Spare1(uint): Not used. Should be set to zero. (field automatically set to "0") 93 - DestID(uint): Unique ship identification number (MMSI) 94 - Spare2(uint): Not used. Should be set to zero. (field automatically set to "0") 95 @param params: Dictionary of field names/values. Throws a ValueError exception if required is missing 96 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 97 @rtype: BitVector 98 @return: encoded binary message (for binary messages, this needs to be wrapped in a msg 8 99 @note: The returned bits may not be 6 bit aligned. It is up to you to pad out the bits. 100 ''' 101 102 bvList = [] 103 bvList.append(binary.setBitVectorSize(BitVector(intVal=10),6)) 104 if 'RepeatIndicator' in params: 105 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['RepeatIndicator']),2)) 106 else: 107 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2)) 108 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['UserID']),30)) 109 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2)) 110 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['DestID']),30)) 111 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2)) 112 113 return binary.joinBV(bvList)
114
115 -def decode(bv, validate=False):
116 '''Unpack a utcquery message 117 118 Fields in params: 119 - MessageID(uint): AIS message number. Must be 10 (field automatically set to "10") 120 - RepeatIndicator(uint): Indicated how many times a message has been repeated 121 - UserID(uint): Unique ship identification number (MMSI) 122 - Spare1(uint): Not used. Should be set to zero. (field automatically set to "0") 123 - DestID(uint): Unique ship identification number (MMSI) 124 - Spare2(uint): Not used. Should be set to zero. (field automatically set to "0") 125 @type bv: BitVector 126 @param bv: Bits defining a message 127 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 128 @rtype: dict 129 @return: params 130 ''' 131 132 #Would be nice to check the bit count here.. 133 #if validate: 134 # assert (len(bv)==FIX: SOME NUMBER) 135 r = {} 136 r['MessageID']=10 137 r['RepeatIndicator']=int(bv[6:8]) 138 r['UserID']=int(bv[8:38]) 139 r['Spare1']=0 140 r['DestID']=int(bv[40:70]) 141 r['Spare2']=0 142 return r
143
144 -def decodeMessageID(bv, validate=False):
145 return 10
146
147 -def decodeRepeatIndicator(bv, validate=False):
148 return int(bv[6:8])
149
150 -def decodeUserID(bv, validate=False):
151 return int(bv[8:38])
152
153 -def decodeSpare1(bv, validate=False):
154 return 0
155
156 -def decodeDestID(bv, validate=False):
157 return int(bv[40:70])
158
159 -def decodeSpare2(bv, validate=False):
160 return 0
161 162
163 -def printHtml(params, out=sys.stdout):
164 out.write("<h3>utcquery<h3>\n") 165 out.write("<table border=\"1\">\n") 166 out.write("<tr bgcolor=\"orange\">\n") 167 out.write("<th align=\"left\">Field Name</th>\n") 168 out.write("<th align=\"left\">Type</th>\n") 169 out.write("<th align=\"left\">Value</th>\n") 170 out.write("<th align=\"left\">Value in Lookup Table</th>\n") 171 out.write("<th align=\"left\">Units</th>\n") 172 out.write("\n") 173 out.write("<tr>\n") 174 out.write("<td>MessageID</td>\n") 175 out.write("<td>uint</td>\n") 176 if 'MessageID' in params: 177 out.write(" <td>"+str(params['MessageID'])+"</td>\n") 178 out.write(" <td>"+str(params['MessageID'])+"</td>\n") 179 out.write("</tr>\n") 180 out.write("\n") 181 out.write("<tr>\n") 182 out.write("<td>RepeatIndicator</td>\n") 183 out.write("<td>uint</td>\n") 184 if 'RepeatIndicator' in params: 185 out.write(" <td>"+str(params['RepeatIndicator'])+"</td>\n") 186 if str(params['RepeatIndicator']) in RepeatIndicatorDecodeLut: 187 out.write("<td>"+RepeatIndicatorDecodeLut[str(params['RepeatIndicator'])]+"</td>") 188 else: 189 out.write("<td><i>Missing LUT entry</i></td>") 190 out.write("</tr>\n") 191 out.write("\n") 192 out.write("<tr>\n") 193 out.write("<td>UserID</td>\n") 194 out.write("<td>uint</td>\n") 195 if 'UserID' in params: 196 out.write(" <td>"+str(params['UserID'])+"</td>\n") 197 out.write(" <td>"+str(params['UserID'])+"</td>\n") 198 out.write("</tr>\n") 199 out.write("\n") 200 out.write("<tr>\n") 201 out.write("<td>Spare1</td>\n") 202 out.write("<td>uint</td>\n") 203 if 'Spare1' in params: 204 out.write(" <td>"+str(params['Spare1'])+"</td>\n") 205 out.write(" <td>"+str(params['Spare1'])+"</td>\n") 206 out.write("</tr>\n") 207 out.write("\n") 208 out.write("<tr>\n") 209 out.write("<td>DestID</td>\n") 210 out.write("<td>uint</td>\n") 211 if 'DestID' in params: 212 out.write(" <td>"+str(params['DestID'])+"</td>\n") 213 out.write(" <td>"+str(params['DestID'])+"</td>\n") 214 out.write("</tr>\n") 215 out.write("\n") 216 out.write("<tr>\n") 217 out.write("<td>Spare2</td>\n") 218 out.write("<td>uint</td>\n") 219 if 'Spare2' in params: 220 out.write(" <td>"+str(params['Spare2'])+"</td>\n") 221 out.write(" <td>"+str(params['Spare2'])+"</td>\n") 222 out.write("</tr>\n") 223 out.write("</table>\n")
224
225 -def printFields(params, out=sys.stdout, format='std', fieldList=None, dbType='postgres'):
226 '''Print a utcquery message to stdout. 227 228 Fields in params: 229 - MessageID(uint): AIS message number. Must be 10 (field automatically set to "10") 230 - RepeatIndicator(uint): Indicated how many times a message has been repeated 231 - UserID(uint): Unique ship identification number (MMSI) 232 - Spare1(uint): Not used. Should be set to zero. (field automatically set to "0") 233 - DestID(uint): Unique ship identification number (MMSI) 234 - Spare2(uint): Not used. Should be set to zero. (field automatically set to "0") 235 @param params: Dictionary of field names/values. 236 @param out: File like object to write to 237 @rtype: stdout 238 @return: text to out 239 ''' 240 241 if 'std'==format: 242 out.write("utcquery:\n") 243 if 'MessageID' in params: out.write(" MessageID: "+str(params['MessageID'])+"\n") 244 if 'RepeatIndicator' in params: out.write(" RepeatIndicator: "+str(params['RepeatIndicator'])+"\n") 245 if 'UserID' in params: out.write(" UserID: "+str(params['UserID'])+"\n") 246 if 'Spare1' in params: out.write(" Spare1: "+str(params['Spare1'])+"\n") 247 if 'DestID' in params: out.write(" DestID: "+str(params['DestID'])+"\n") 248 if 'Spare2' in params: out.write(" Spare2: "+str(params['Spare2'])+"\n") 249 elif 'csv'==format: 250 if None == options.fieldList: 251 options.fieldList = fieldList 252 needComma = False; 253 for field in fieldList: 254 if needComma: out.write(',') 255 needComma = True 256 if field in params: 257 out.write(str(params[field])) 258 # else: leave it empty 259 out.write("\n") 260 elif 'html'==format: 261 printHtml(params,out) 262 elif 'sql'==format: 263 sqlInsertStr(params,out,dbType=dbType) 264 else: 265 print "ERROR: unknown format:",format 266 assert False 267 268 return # Nothing to return
269 270 RepeatIndicatorEncodeLut = { 271 'default':'0', 272 'do not repeat any more':'3', 273 } #RepeatIndicatorEncodeLut 274 275 RepeatIndicatorDecodeLut = { 276 '0':'default', 277 '3':'do not repeat any more', 278 } # RepeatIndicatorEncodeLut 279 280 ###################################################################### 281 # SQL SUPPORT 282 ###################################################################### 283
284 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None 285 ,addCoastGuardFields=True 286 ,dbType='postgres' 287 ):
288 ''' 289 Return the SQL CREATE command for this message type 290 @param outfile: file like object to print to. 291 @param fields: which fields to put in the create. Defaults to all. 292 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 293 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 294 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 295 @type addCoastGuardFields: bool 296 @return: sql create string 297 @rtype: str 298 299 @see: sqlCreate 300 ''' 301 outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType)))
302
303 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'):
304 ''' 305 Return the sqlhelp object to create the table. 306 307 @param fields: which fields to put in the create. Defaults to all. 308 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 309 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 310 @type addCoastGuardFields: bool 311 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 312 @return: An object that can be used to generate a return 313 @rtype: sqlhelp.create 314 ''' 315 if None == fields: fields = fieldList 316 import sqlhelp 317 c = sqlhelp.create('utcquery',dbType=dbType) 318 c.addPrimaryKey() 319 if 'MessageID' in fields: c.addInt ('MessageID') 320 if 'RepeatIndicator' in fields: c.addInt ('RepeatIndicator') 321 if 'UserID' in fields: c.addInt ('UserID') 322 if 'Spare1' in fields: c.addInt ('Spare1') 323 if 'DestID' in fields: c.addInt ('DestID') 324 if 'Spare2' in fields: c.addInt ('Spare2') 325 326 if addCoastGuardFields: 327 # c.addInt('cg_rssi') # Relative signal strength indicator 328 # c.addInt('cg_d') # dBm receive strength 329 # c.addInt('cg_T') # Receive timestamp from the AIS equipment 330 # c.addInt('cg_S') # Slot received in 331 # c.addVarChar('cg_x',10) # Idonno 332 c.addVarChar('cg_r',15) # Receiver station ID - should usually be an MMSI, but sometimes is a string 333 c.addInt('cg_sec') # UTC seconds since the epoch 334 335 c.addTimestamp('cg_timestamp') # UTC decoded cg_sec - not actually in the data stream 336 337 return c
338
339 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'):
340 ''' 341 Return the SQL INSERT command for this message type 342 @param params: dictionary of values keyed by field name 343 @param outfile: file like object to print to. 344 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields 345 @return: sql create string 346 @rtype: str 347 348 @see: sqlCreate 349 ''' 350 outfile.write(str(sqlInsert(params,extraParams,dbType=dbType)))
351 352
353 -def sqlInsert(params,extraParams=None,dbType='postgres'):
354 ''' 355 Give the SQL INSERT statement 356 @param params: dict keyed by field name of values 357 @param extraParams: any extra fields that you have created beyond the normal ais message fields 358 @rtype: sqlhelp.insert 359 @return: insert class instance 360 @todo: allow optional type checking of params? 361 @warning: this will take invalid keys happily and do what??? 362 ''' 363 import sqlhelp 364 i = sqlhelp.insert('utcquery',dbType=dbType) 365 366 if dbType=='postgres': 367 finished = [] 368 for key in params: 369 if key in finished: 370 continue 371 372 if key not in toPgFields and key not in fromPgFields: 373 if type(params[key])==Decimal: i.add(key,float(params[key])) 374 else: i.add(key,params[key]) 375 else: 376 if key in fromPgFields: 377 val = params[key] 378 # Had better be a WKT type like POINT(-88.1 30.321) 379 i.addPostGIS(key,val) 380 finished.append(key) 381 else: 382 # Need to construct the type. 383 pgName = toPgFields[key] 384 #valStr='GeomFromText(\''+pgTypes[pgName]+'(' 385 valStr=pgTypes[pgName]+'(' 386 vals = [] 387 for nonPgKey in fromPgFields[pgName]: 388 vals.append(str(params[nonPgKey])) 389 finished.append(nonPgKey) 390 valStr+=' '.join(vals)+')' 391 i.addPostGIS(pgName,valStr) 392 else: 393 for key in params: 394 if type(params[key])==Decimal: i.add(key,float(params[key])) 395 else: i.add(key,params[key]) 396 397 if None != extraParams: 398 for key in extraParams: 399 i.add(key,extraParams[key]) 400 401 return i
402 403 404 ###################################################################### 405 # UNIT TESTING 406 ###################################################################### 407 import unittest
408 -def testParams():
409 '''Return a params file base on the testvalue tags. 410 @rtype: dict 411 @return: params based on testvalue tags 412 ''' 413 params = {} 414 params['MessageID'] = 10 415 params['RepeatIndicator'] = 1 416 params['UserID'] = 1193046 417 params['Spare1'] = 0 418 params['DestID'] = 1193046 419 params['Spare2'] = 0 420 421 return params
422
423 -class Testutcquery(unittest.TestCase):
424 '''Use testvalue tag text from each type to build test case the utcquery message'''
425 - def testEncodeDecode(self):
426 427 params = testParams() 428 bits = encode(params) 429 r = decode(bits) 430 431 # Check that each parameter came through ok. 432 self.failUnlessEqual(r['MessageID'],params['MessageID']) 433 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator']) 434 self.failUnlessEqual(r['UserID'],params['UserID']) 435 self.failUnlessEqual(r['Spare1'],params['Spare1']) 436 self.failUnlessEqual(r['DestID'],params['DestID']) 437 self.failUnlessEqual(r['Spare2'],params['Spare2'])
438
439 -def addMsgOptions(parser):
440 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true', 441 help='decode a "utcquery" AIS message') 442 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true', 443 help='encode a "utcquery" AIS message') 444 parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int' 445 ,help='Field parameter value [default: %default]') 446 parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int' 447 ,help='Field parameter value [default: %default]') 448 parser.add_option('--DestID-field', dest='DestIDField',metavar='uint',type='int' 449 ,help='Field parameter value [default: %default]')
450 451 ############################################################ 452 if __name__=='__main__': 453 454 from optparse import OptionParser 455 parser = OptionParser(usage="%prog [options]", 456 version="%prog "+__version__) 457 458 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true', 459 help='run the documentation tests') 460 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true', 461 help='run the unit tests') 462 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 463 help='Make the test output verbose') 464 465 # FIX: remove nmea from binary messages. No way to build the whole packet? 466 # FIX: or build the surrounding msg 8 for a broadcast? 467 typeChoices = ('binary','nmeapayload','nmea') # FIX: what about a USCG type message? 468 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType' 469 ,default='nmeapayload' 470 ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]') 471 472 473 outputChoices = ('std','html','csv','sql' ) 474 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType' 475 ,default='std' 476 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]') 477 478 parser.add_option('-o','--output',dest='outputFileName',default=None, 479 help='Name of the python file to write [default: stdout]') 480 481 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append', 482 choices=fieldList, 483 help='Which fields to include in the output. Currently only for csv output [default: all]') 484 485 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true', 486 help='Print the field name for csv') 487 488 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true', 489 help='Print out an sql create command for the table.') 490 491 dbChoices = ('sqlite','postgres') 492 parser.add_option('-D','--db-type',dest='dbType',default='postgres' 493 ,choices=dbChoices,type='choice' 494 ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]') 495 496 addMsgOptions(parser) 497 498 (options,args) = parser.parse_args() 499 success=True 500 501 if options.doctest: 502 import os; print os.path.basename(sys.argv[0]), 'doctests ...', 503 sys.argv= [sys.argv[0]] 504 if options.verbose: sys.argv.append('-v') 505 import doctest 506 numfail,numtests=doctest.testmod() 507 if numfail==0: print 'ok' 508 else: 509 print 'FAILED' 510 success=False 511 512 if not success: sys.exit('Something Failed') 513 del success # Hide success from epydoc 514 515 if options.unittest: 516 sys.argv = [sys.argv[0]] 517 if options.verbose: sys.argv.append('-v') 518 unittest.main() 519 520 outfile = sys.stdout 521 if None!=options.outputFileName: 522 outfile = file(options.outputFileName,'w') 523 524 525 if options.doEncode: 526 # First make sure all non required options are specified 527 if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField") 528 if None==options.UserIDField: parser.error("missing value for UserIDField") 529 if None==options.DestIDField: parser.error("missing value for DestIDField") 530 msgDict={ 531 'MessageID': '10', 532 'RepeatIndicator': options.RepeatIndicatorField, 533 'UserID': options.UserIDField, 534 'Spare1': '0', 535 'DestID': options.DestIDField, 536 'Spare2': '0', 537 } 538 539 bits = encode(msgDict) 540 if 'binary'==options.ioType: print str(bits) 541 elif 'nmeapayload'==options.ioType: 542 # FIX: figure out if this might be necessary at compile time 543 print "bitLen",len(bits) 544 bitLen=len(bits) 545 if bitLen%6!=0: 546 bits = bits + BitVector(size=(6 - (bitLen%6))) # Pad out to multiple of 6 547 print "result:",binary.bitvectoais6(bits)[0] 548 549 550 # FIX: Do not emit this option for the binary message payloads. Does not make sense. 551 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability") 552 else: sys.exit('ERROR: unknown ioType. Help!') 553 554 555 if options.sqlCreate: 556 sqlCreateStr(outfile,options.fieldList,dbType=options.dbType) 557 558 if options.printCsvfieldList: 559 # Make a csv separated list of fields that will be displayed for csv 560 if None == options.fieldList: options.fieldList = fieldList 561 import StringIO 562 buf = StringIO.StringIO() 563 for field in options.fieldList: 564 buf.write(field+',') 565 result = buf.getvalue() 566 if result[-1] == ',': print result[:-1] 567 else: print result 568 569 if options.doDecode: 570 for msg in args: 571 bv = None 572 573 if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'): 574 # Found nmea 575 # FIX: do checksum 576 bv = binary.ais6tobitvec(msg.split(',')[5]) 577 else: # either binary or nmeapayload... expect mostly nmeapayloads 578 # assumes that an all 0 and 1 string can not be a nmeapayload 579 binaryMsg=True 580 for c in msg: 581 if c not in ('0','1'): 582 binaryMsg=False 583 break 584 if binaryMsg: 585 bv = BitVector(bitstring=msg) 586 else: # nmeapayload 587 bv = binary.ais6tobitvec(msg) 588 589 printFields(decode(bv) 590 ,out=outfile 591 ,format=options.outputType 592 ,fieldList=options.fieldList 593 ,dbType=options.dbType 594 ) 595