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

Source Code for Module ais.imo_001_13

   1  #!/usr/bin/env python 
   2   
   3  __version__ = '$Revision: 4791 $'.split()[1] 
   4  __date__ = '$Date: 2007-11-07 $'.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          'Spare', 
  54          'dac', 
  55          'fid', 
  56          'reason', 
  57          'from', 
  58          'to', 
  59          'radius', 
  60          'unit', 
  61          'closingday', 
  62          'closingmonth', 
  63          'fromhour', 
  64          'frommin', 
  65          'today', 
  66          'tomonth', 
  67          'tohour', 
  68          'tomin', 
  69          'spare2', 
  70  ) 
  71   
  72  fieldListPostgres = ( 
  73          'MessageID', 
  74          'RepeatIndicator', 
  75          'UserID', 
  76          'Spare', 
  77          'dac', 
  78          'fid', 
  79          'reason', 
  80          'from', 
  81          'to', 
  82          'radius', 
  83          'unit', 
  84          'closingday', 
  85          'closingmonth', 
  86          'fromhour', 
  87          'frommin', 
  88          'today', 
  89          'tomonth', 
  90          'tohour', 
  91          'tomin', 
  92          'spare2', 
  93  ) 
  94   
  95  toPgFields = { 
  96  } 
  97  ''' 
  98  Go to the Postgis field names from the straight field name 
  99  ''' 
 100   
 101  fromPgFields = { 
 102  } 
 103  ''' 
 104  Go from the Postgis field names to the straight field name 
 105  ''' 
 106   
 107  pgTypes = { 
 108  } 
 109  ''' 
 110  Lookup table for each postgis field name to get its type. 
 111  ''' 
 112   
113 -def encode(params, validate=False):
114 '''Create a imo_fairway_closed binary message payload to pack into an AIS Msg imo_fairway_closed. 115 116 Fields in params: 117 - MessageID(uint): AIS message number. Must be 8 (field automatically set to "8") 118 - RepeatIndicator(uint): Indicated how many times a message has been repeated 119 - UserID(uint): MMSI number of transmitter broadcasting the message 120 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0") 121 - dac(uint): Designated Area Code - part 1 of the IAI (field automatically set to "1") 122 - fid(uint): Functional Identifier - part 2 of the IAI (field automatically set to "11") 123 - reason(aisstr6): Reason for closing 124 - from(aisstr6): Location of closing from 125 - to(aisstr6): Location of closing To 126 - radius(uint): Extention of closed area 127 - unit(uint): Unit of extension value for range field 128 - closingday(uint): Closing from day 129 - closingmonth(uint): Closing from month 130 - fromhour(uint): From LT hour (appr) 131 - frommin(uint): From LT minute (appr) 132 - today(uint): To day 133 - tomonth(uint): To month 134 - tohour(uint): To LT hour (appr) 135 - tomin(uint): To LT minute (appr) 136 - spare2(uint): Padding out the slot (field automatically set to "0") 137 @param params: Dictionary of field names/values. Throws a ValueError exception if required is missing 138 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 139 @rtype: BitVector 140 @return: encoded binary message (for binary messages, this needs to be wrapped in a msg 8 141 @note: The returned bits may not be 6 bit aligned. It is up to you to pad out the bits. 142 ''' 143 144 bvList = [] 145 bvList.append(binary.setBitVectorSize(BitVector(intVal=8),6)) 146 if 'RepeatIndicator' in params: 147 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['RepeatIndicator']),2)) 148 else: 149 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2)) 150 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['UserID']),30)) 151 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2)) 152 bvList.append(binary.setBitVectorSize(BitVector(intVal=1),10)) 153 bvList.append(binary.setBitVectorSize(BitVector(intVal=11),6)) 154 if 'reason' in params: 155 bvList.append(aisstring.encode(params['reason'],120)) 156 else: 157 bvList.append(aisstring.encode('@@@@@@@@@@@@@@@@@@@@',120)) 158 if 'from' in params: 159 bvList.append(aisstring.encode(params['from'],120)) 160 else: 161 bvList.append(aisstring.encode('@@@@@@@@@@@@@@@@@@@@',120)) 162 if 'to' in params: 163 bvList.append(aisstring.encode(params['to'],120)) 164 else: 165 bvList.append(aisstring.encode('@@@@@@@@@@@@@@@@@@@@',120)) 166 if 'radius' in params: 167 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['radius']),10)) 168 else: 169 bvList.append(binary.setBitVectorSize(BitVector(intVal=1001),10)) 170 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['unit']),2)) 171 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['closingday']),5)) 172 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['closingmonth']),4)) 173 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['fromhour']),5)) 174 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['frommin']),6)) 175 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['today']),5)) 176 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['tomonth']),4)) 177 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['tohour']),5)) 178 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['tomin']),6)) 179 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),4)) 180 181 return binary.joinBV(bvList)
182
183 -def decode(bv, validate=False):
184 '''Unpack a imo_fairway_closed message 185 186 Fields in params: 187 - MessageID(uint): AIS message number. Must be 8 (field automatically set to "8") 188 - RepeatIndicator(uint): Indicated how many times a message has been repeated 189 - UserID(uint): MMSI number of transmitter broadcasting the message 190 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0") 191 - dac(uint): Designated Area Code - part 1 of the IAI (field automatically set to "1") 192 - fid(uint): Functional Identifier - part 2 of the IAI (field automatically set to "11") 193 - reason(aisstr6): Reason for closing 194 - from(aisstr6): Location of closing from 195 - to(aisstr6): Location of closing To 196 - radius(uint): Extention of closed area 197 - unit(uint): Unit of extension value for range field 198 - closingday(uint): Closing from day 199 - closingmonth(uint): Closing from month 200 - fromhour(uint): From LT hour (appr) 201 - frommin(uint): From LT minute (appr) 202 - today(uint): To day 203 - tomonth(uint): To month 204 - tohour(uint): To LT hour (appr) 205 - tomin(uint): To LT minute (appr) 206 - spare2(uint): Padding out the slot (field automatically set to "0") 207 @type bv: BitVector 208 @param bv: Bits defining a message 209 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 210 @rtype: dict 211 @return: params 212 ''' 213 214 #Would be nice to check the bit count here.. 215 #if validate: 216 # assert (len(bv)==FIX: SOME NUMBER) 217 r = {} 218 r['MessageID']=8 219 r['RepeatIndicator']=int(bv[6:8]) 220 r['UserID']=int(bv[8:38]) 221 r['Spare']=0 222 r['dac']=1 223 r['fid']=11 224 r['reason']=aisstring.decode(bv[56:176]) 225 r['from']=aisstring.decode(bv[176:296]) 226 r['to']=aisstring.decode(bv[296:416]) 227 r['radius']=int(bv[416:426]) 228 r['unit']=int(bv[426:428]) 229 r['closingday']=int(bv[428:433]) 230 r['closingmonth']=int(bv[433:437]) 231 r['fromhour']=int(bv[437:442]) 232 r['frommin']=int(bv[442:448]) 233 r['today']=int(bv[448:453]) 234 r['tomonth']=int(bv[453:457]) 235 r['tohour']=int(bv[457:462]) 236 r['tomin']=int(bv[462:468]) 237 r['spare2']=0 238 return r
239
240 -def decodeMessageID(bv, validate=False):
241 return 8
242
243 -def decodeRepeatIndicator(bv, validate=False):
244 return int(bv[6:8])
245
246 -def decodeUserID(bv, validate=False):
247 return int(bv[8:38])
248
249 -def decodeSpare(bv, validate=False):
250 return 0
251
252 -def decodedac(bv, validate=False):
253 return 1
254
255 -def decodefid(bv, validate=False):
256 return 11
257
258 -def decodereason(bv, validate=False):
259 return aisstring.decode(bv[56:176])
260
261 -def decodefrom(bv, validate=False):
262 return aisstring.decode(bv[176:296])
263
264 -def decodeto(bv, validate=False):
265 return aisstring.decode(bv[296:416])
266
267 -def decoderadius(bv, validate=False):
268 return int(bv[416:426])
269
270 -def decodeunit(bv, validate=False):
271 return int(bv[426:428])
272
273 -def decodeclosingday(bv, validate=False):
274 return int(bv[428:433])
275
276 -def decodeclosingmonth(bv, validate=False):
277 return int(bv[433:437])
278
279 -def decodefromhour(bv, validate=False):
280 return int(bv[437:442])
281
282 -def decodefrommin(bv, validate=False):
283 return int(bv[442:448])
284
285 -def decodetoday(bv, validate=False):
286 return int(bv[448:453])
287
288 -def decodetomonth(bv, validate=False):
289 return int(bv[453:457])
290
291 -def decodetohour(bv, validate=False):
292 return int(bv[457:462])
293
294 -def decodetomin(bv, validate=False):
295 return int(bv[462:468])
296
297 -def decodespare2(bv, validate=False):
298 return 0
299 300
301 -def printHtml(params, out=sys.stdout):
302 out.write("<h3>imo_fairway_closed</h3>\n") 303 out.write("<table border=\"1\">\n") 304 out.write("<tr bgcolor=\"orange\">\n") 305 out.write("<th align=\"left\">Field Name</th>\n") 306 out.write("<th align=\"left\">Type</th>\n") 307 out.write("<th align=\"left\">Value</th>\n") 308 out.write("<th align=\"left\">Value in Lookup Table</th>\n") 309 out.write("<th align=\"left\">Units</th>\n") 310 out.write("\n") 311 out.write("<tr>\n") 312 out.write("<td>MessageID</td>\n") 313 out.write("<td>uint</td>\n") 314 if 'MessageID' in params: 315 out.write(" <td>"+str(params['MessageID'])+"</td>\n") 316 out.write(" <td>"+str(params['MessageID'])+"</td>\n") 317 out.write("</tr>\n") 318 out.write("\n") 319 out.write("<tr>\n") 320 out.write("<td>RepeatIndicator</td>\n") 321 out.write("<td>uint</td>\n") 322 if 'RepeatIndicator' in params: 323 out.write(" <td>"+str(params['RepeatIndicator'])+"</td>\n") 324 if str(params['RepeatIndicator']) in RepeatIndicatorDecodeLut: 325 out.write("<td>"+RepeatIndicatorDecodeLut[str(params['RepeatIndicator'])]+"</td>") 326 else: 327 out.write("<td><i>Missing LUT entry</i></td>") 328 out.write("</tr>\n") 329 out.write("\n") 330 out.write("<tr>\n") 331 out.write("<td>UserID</td>\n") 332 out.write("<td>uint</td>\n") 333 if 'UserID' in params: 334 out.write(" <td>"+str(params['UserID'])+"</td>\n") 335 out.write(" <td>"+str(params['UserID'])+"</td>\n") 336 out.write("</tr>\n") 337 out.write("\n") 338 out.write("<tr>\n") 339 out.write("<td>Spare</td>\n") 340 out.write("<td>uint</td>\n") 341 if 'Spare' in params: 342 out.write(" <td>"+str(params['Spare'])+"</td>\n") 343 out.write(" <td>"+str(params['Spare'])+"</td>\n") 344 out.write("</tr>\n") 345 out.write("\n") 346 out.write("<tr>\n") 347 out.write("<td>dac</td>\n") 348 out.write("<td>uint</td>\n") 349 if 'dac' in params: 350 out.write(" <td>"+str(params['dac'])+"</td>\n") 351 out.write(" <td>"+str(params['dac'])+"</td>\n") 352 out.write("</tr>\n") 353 out.write("\n") 354 out.write("<tr>\n") 355 out.write("<td>fid</td>\n") 356 out.write("<td>uint</td>\n") 357 if 'fid' in params: 358 out.write(" <td>"+str(params['fid'])+"</td>\n") 359 out.write(" <td>"+str(params['fid'])+"</td>\n") 360 out.write("</tr>\n") 361 out.write("\n") 362 out.write("<tr>\n") 363 out.write("<td>reason</td>\n") 364 out.write("<td>aisstr6</td>\n") 365 if 'reason' in params: 366 out.write(" <td>"+str(params['reason'])+"</td>\n") 367 out.write(" <td>"+str(params['reason'])+"</td>\n") 368 out.write("</tr>\n") 369 out.write("\n") 370 out.write("<tr>\n") 371 out.write("<td>from</td>\n") 372 out.write("<td>aisstr6</td>\n") 373 if 'from' in params: 374 out.write(" <td>"+str(params['from'])+"</td>\n") 375 out.write(" <td>"+str(params['from'])+"</td>\n") 376 out.write("</tr>\n") 377 out.write("\n") 378 out.write("<tr>\n") 379 out.write("<td>to</td>\n") 380 out.write("<td>aisstr6</td>\n") 381 if 'to' in params: 382 out.write(" <td>"+str(params['to'])+"</td>\n") 383 out.write(" <td>"+str(params['to'])+"</td>\n") 384 out.write("</tr>\n") 385 out.write("\n") 386 out.write("<tr>\n") 387 out.write("<td>radius</td>\n") 388 out.write("<td>uint</td>\n") 389 if 'radius' in params: 390 out.write(" <td>"+str(params['radius'])+"</td>\n") 391 out.write(" <td>"+str(params['radius'])+"</td>\n") 392 out.write("<td>See unit field</td>\n") 393 out.write("</tr>\n") 394 out.write("\n") 395 out.write("<tr>\n") 396 out.write("<td>unit</td>\n") 397 out.write("<td>uint</td>\n") 398 if 'unit' in params: 399 out.write(" <td>"+str(params['unit'])+"</td>\n") 400 if str(params['unit']) in unitDecodeLut: 401 out.write("<td>"+unitDecodeLut[str(params['unit'])]+"</td>") 402 else: 403 out.write("<td><i>Missing LUT entry</i></td>") 404 out.write("</tr>\n") 405 out.write("\n") 406 out.write("<tr>\n") 407 out.write("<td>closingday</td>\n") 408 out.write("<td>uint</td>\n") 409 if 'closingday' in params: 410 out.write(" <td>"+str(params['closingday'])+"</td>\n") 411 out.write(" <td>"+str(params['closingday'])+"</td>\n") 412 out.write("</tr>\n") 413 out.write("\n") 414 out.write("<tr>\n") 415 out.write("<td>closingmonth</td>\n") 416 out.write("<td>uint</td>\n") 417 if 'closingmonth' in params: 418 out.write(" <td>"+str(params['closingmonth'])+"</td>\n") 419 out.write(" <td>"+str(params['closingmonth'])+"</td>\n") 420 out.write("</tr>\n") 421 out.write("\n") 422 out.write("<tr>\n") 423 out.write("<td>fromhour</td>\n") 424 out.write("<td>uint</td>\n") 425 if 'fromhour' in params: 426 out.write(" <td>"+str(params['fromhour'])+"</td>\n") 427 out.write(" <td>"+str(params['fromhour'])+"</td>\n") 428 out.write("</tr>\n") 429 out.write("\n") 430 out.write("<tr>\n") 431 out.write("<td>frommin</td>\n") 432 out.write("<td>uint</td>\n") 433 if 'frommin' in params: 434 out.write(" <td>"+str(params['frommin'])+"</td>\n") 435 out.write(" <td>"+str(params['frommin'])+"</td>\n") 436 out.write("</tr>\n") 437 out.write("\n") 438 out.write("<tr>\n") 439 out.write("<td>today</td>\n") 440 out.write("<td>uint</td>\n") 441 if 'today' in params: 442 out.write(" <td>"+str(params['today'])+"</td>\n") 443 out.write(" <td>"+str(params['today'])+"</td>\n") 444 out.write("</tr>\n") 445 out.write("\n") 446 out.write("<tr>\n") 447 out.write("<td>tomonth</td>\n") 448 out.write("<td>uint</td>\n") 449 if 'tomonth' in params: 450 out.write(" <td>"+str(params['tomonth'])+"</td>\n") 451 out.write(" <td>"+str(params['tomonth'])+"</td>\n") 452 out.write("</tr>\n") 453 out.write("\n") 454 out.write("<tr>\n") 455 out.write("<td>tohour</td>\n") 456 out.write("<td>uint</td>\n") 457 if 'tohour' in params: 458 out.write(" <td>"+str(params['tohour'])+"</td>\n") 459 out.write(" <td>"+str(params['tohour'])+"</td>\n") 460 out.write("</tr>\n") 461 out.write("\n") 462 out.write("<tr>\n") 463 out.write("<td>tomin</td>\n") 464 out.write("<td>uint</td>\n") 465 if 'tomin' in params: 466 out.write(" <td>"+str(params['tomin'])+"</td>\n") 467 out.write(" <td>"+str(params['tomin'])+"</td>\n") 468 out.write("</tr>\n") 469 out.write("\n") 470 out.write("<tr>\n") 471 out.write("<td>spare2</td>\n") 472 out.write("<td>uint</td>\n") 473 if 'spare2' in params: 474 out.write(" <td>"+str(params['spare2'])+"</td>\n") 475 out.write(" <td>"+str(params['spare2'])+"</td>\n") 476 out.write("</tr>\n") 477 out.write("</table>\n")
478
479 -def printFields(params, out=sys.stdout, format='std', fieldList=None, dbType='postgres'):
480 '''Print a imo_fairway_closed message to stdout. 481 482 Fields in params: 483 - MessageID(uint): AIS message number. Must be 8 (field automatically set to "8") 484 - RepeatIndicator(uint): Indicated how many times a message has been repeated 485 - UserID(uint): MMSI number of transmitter broadcasting the message 486 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0") 487 - dac(uint): Designated Area Code - part 1 of the IAI (field automatically set to "1") 488 - fid(uint): Functional Identifier - part 2 of the IAI (field automatically set to "11") 489 - reason(aisstr6): Reason for closing 490 - from(aisstr6): Location of closing from 491 - to(aisstr6): Location of closing To 492 - radius(uint): Extention of closed area 493 - unit(uint): Unit of extension value for range field 494 - closingday(uint): Closing from day 495 - closingmonth(uint): Closing from month 496 - fromhour(uint): From LT hour (appr) 497 - frommin(uint): From LT minute (appr) 498 - today(uint): To day 499 - tomonth(uint): To month 500 - tohour(uint): To LT hour (appr) 501 - tomin(uint): To LT minute (appr) 502 - spare2(uint): Padding out the slot (field automatically set to "0") 503 @param params: Dictionary of field names/values. 504 @param out: File like object to write to 505 @rtype: stdout 506 @return: text to out 507 ''' 508 509 if 'std'==format: 510 out.write("imo_fairway_closed:\n") 511 if 'MessageID' in params: out.write(" MessageID: "+str(params['MessageID'])+"\n") 512 if 'RepeatIndicator' in params: out.write(" RepeatIndicator: "+str(params['RepeatIndicator'])+"\n") 513 if 'UserID' in params: out.write(" UserID: "+str(params['UserID'])+"\n") 514 if 'Spare' in params: out.write(" Spare: "+str(params['Spare'])+"\n") 515 if 'dac' in params: out.write(" dac: "+str(params['dac'])+"\n") 516 if 'fid' in params: out.write(" fid: "+str(params['fid'])+"\n") 517 if 'reason' in params: out.write(" reason: "+str(params['reason'])+"\n") 518 if 'from' in params: out.write(" from: "+str(params['from'])+"\n") 519 if 'to' in params: out.write(" to: "+str(params['to'])+"\n") 520 if 'radius' in params: out.write(" radius: "+str(params['radius'])+"\n") 521 if 'unit' in params: out.write(" unit: "+str(params['unit'])+"\n") 522 if 'closingday' in params: out.write(" closingday: "+str(params['closingday'])+"\n") 523 if 'closingmonth' in params: out.write(" closingmonth: "+str(params['closingmonth'])+"\n") 524 if 'fromhour' in params: out.write(" fromhour: "+str(params['fromhour'])+"\n") 525 if 'frommin' in params: out.write(" frommin: "+str(params['frommin'])+"\n") 526 if 'today' in params: out.write(" today: "+str(params['today'])+"\n") 527 if 'tomonth' in params: out.write(" tomonth: "+str(params['tomonth'])+"\n") 528 if 'tohour' in params: out.write(" tohour: "+str(params['tohour'])+"\n") 529 if 'tomin' in params: out.write(" tomin: "+str(params['tomin'])+"\n") 530 if 'spare2' in params: out.write(" spare2: "+str(params['spare2'])+"\n") 531 elif 'csv'==format: 532 if None == options.fieldList: 533 options.fieldList = fieldList 534 needComma = False; 535 for field in fieldList: 536 if needComma: out.write(',') 537 needComma = True 538 if field in params: 539 out.write(str(params[field])) 540 # else: leave it empty 541 out.write("\n") 542 elif 'html'==format: 543 printHtml(params,out) 544 elif 'sql'==format: 545 sqlInsertStr(params,out,dbType=dbType) 546 else: 547 print "ERROR: unknown format:",format 548 assert False 549 550 return # Nothing to return
551 552 RepeatIndicatorEncodeLut = { 553 'default':'0', 554 'do not repeat any more':'3', 555 } #RepeatIndicatorEncodeLut 556 557 RepeatIndicatorDecodeLut = { 558 '0':'default', 559 '3':'do not repeat any more', 560 } # RepeatIndicatorEncodeLut 561 562 unitEncodeLut = { 563 'm':'0', 564 'km':'1', 565 'nm':'2', 566 'cbl':'3', 567 } #unitEncodeLut 568 569 unitDecodeLut = { 570 '0':'m', 571 '1':'km', 572 '2':'nm', 573 '3':'cbl', 574 } # unitEncodeLut 575 576 ###################################################################### 577 # SQL SUPPORT 578 ###################################################################### 579
580 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None 581 ,addCoastGuardFields=True 582 ,dbType='postgres' 583 ):
584 ''' 585 Return the SQL CREATE command for this message type 586 @param outfile: file like object to print to. 587 @param fields: which fields to put in the create. Defaults to all. 588 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 589 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 590 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 591 @type addCoastGuardFields: bool 592 @return: sql create string 593 @rtype: str 594 595 @see: sqlCreate 596 ''' 597 # FIX: should this sqlCreate be the same as in LaTeX (createFuncName) rather than hard coded? 598 outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType)))
599
600 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'):
601 ''' 602 Return the sqlhelp object to create the table. 603 604 @param fields: which fields to put in the create. Defaults to all. 605 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 606 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 607 @type addCoastGuardFields: bool 608 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 609 @return: An object that can be used to generate a return 610 @rtype: sqlhelp.create 611 ''' 612 if None == fields: fields = fieldList 613 import sqlhelp 614 c = sqlhelp.create('imo_fairway_closed',dbType=dbType) 615 c.addPrimaryKey() 616 if 'MessageID' in fields: c.addInt ('MessageID') 617 if 'RepeatIndicator' in fields: c.addInt ('RepeatIndicator') 618 if 'UserID' in fields: c.addInt ('UserID') 619 if 'Spare' in fields: c.addInt ('Spare') 620 if 'dac' in fields: c.addInt ('dac') 621 if 'fid' in fields: c.addInt ('fid') 622 if 'reason' in fields: c.addVarChar('reason',20) 623 if 'from' in fields: c.addVarChar('from',20) 624 if 'to' in fields: c.addVarChar('to',20) 625 if 'radius' in fields: c.addInt ('radius') 626 if 'unit' in fields: c.addInt ('unit') 627 if 'closingday' in fields: c.addInt ('closingday') 628 if 'closingmonth' in fields: c.addInt ('closingmonth') 629 if 'fromhour' in fields: c.addInt ('fromhour') 630 if 'frommin' in fields: c.addInt ('frommin') 631 if 'today' in fields: c.addInt ('today') 632 if 'tomonth' in fields: c.addInt ('tomonth') 633 if 'tohour' in fields: c.addInt ('tohour') 634 if 'tomin' in fields: c.addInt ('tomin') 635 if 'spare2' in fields: c.addInt ('spare2') 636 637 if addCoastGuardFields: 638 # c.addInt('cg_rssi') # Relative signal strength indicator 639 # c.addInt('cg_d') # dBm receive strength 640 # c.addInt('cg_T') # Receive timestamp from the AIS equipment 641 # c.addInt('cg_S') # Slot received in 642 # c.addVarChar('cg_x',10) # Idonno 643 c.addVarChar('cg_r',15) # Receiver station ID - should usually be an MMSI, but sometimes is a string 644 c.addInt('cg_sec') # UTC seconds since the epoch 645 646 c.addTimestamp('cg_timestamp') # UTC decoded cg_sec - not actually in the data stream 647 648 return c
649
650 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'):
651 ''' 652 Return the SQL INSERT command for this message type 653 @param params: dictionary of values keyed by field name 654 @param outfile: file like object to print to. 655 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields 656 @return: sql create string 657 @rtype: str 658 659 @see: sqlCreate 660 ''' 661 outfile.write(str(sqlInsert(params,extraParams,dbType=dbType)))
662 663
664 -def sqlInsert(params,extraParams=None,dbType='postgres'):
665 ''' 666 Give the SQL INSERT statement 667 @param params: dict keyed by field name of values 668 @param extraParams: any extra fields that you have created beyond the normal ais message fields 669 @rtype: sqlhelp.insert 670 @return: insert class instance 671 @todo: allow optional type checking of params? 672 @warning: this will take invalid keys happily and do what??? 673 ''' 674 import sqlhelp 675 i = sqlhelp.insert('imo_fairway_closed',dbType=dbType) 676 677 if dbType=='postgres': 678 finished = [] 679 for key in params: 680 if key in finished: 681 continue 682 683 if key not in toPgFields and key not in fromPgFields: 684 if type(params[key])==Decimal: i.add(key,float(params[key])) 685 else: i.add(key,params[key]) 686 else: 687 if key in fromPgFields: 688 val = params[key] 689 # Had better be a WKT type like POINT(-88.1 30.321) 690 i.addPostGIS(key,val) 691 finished.append(key) 692 else: 693 # Need to construct the type. 694 pgName = toPgFields[key] 695 #valStr='GeomFromText(\''+pgTypes[pgName]+'(' 696 valStr=pgTypes[pgName]+'(' 697 vals = [] 698 for nonPgKey in fromPgFields[pgName]: 699 vals.append(str(params[nonPgKey])) 700 finished.append(nonPgKey) 701 valStr+=' '.join(vals)+')' 702 i.addPostGIS(pgName,valStr) 703 else: 704 for key in params: 705 if type(params[key])==Decimal: i.add(key,float(params[key])) 706 else: i.add(key,params[key]) 707 708 if None != extraParams: 709 for key in extraParams: 710 i.add(key,extraParams[key]) 711 712 return i
713 714 ###################################################################### 715 # LATEX SUPPORT 716 ###################################################################### 717
718 -def latexDefinitionTable(outfile=sys.stdout 719 ):
720 ''' 721 Return the LaTeX definition table for this message type 722 @param outfile: file like object to print to. 723 @type outfile: file obj 724 @return: LaTeX table string via the outfile 725 @rtype: str 726 727 ''' 728 o = outfile 729 730 o.write(''' 731 \\begin{table}%[htb] 732 \\centering 733 \\begin{tabular}{|l|c|l|} 734 \\hline 735 Parameter & Number of bits & Description 736 \\\\ \\hline\\hline 737 MessageID & 6 & AIS message number. Must be 8 \\\\ \hline 738 RepeatIndicator & 2 & Indicated how many times a message has been repeated \\\\ \hline 739 UserID & 30 & MMSI number of transmitter broadcasting the message \\\\ \hline 740 Spare & 2 & Reserved for definition by a regional authority. \\\\ \hline 741 dac & 10 & Designated Area Code - part 1 of the IAI \\\\ \hline 742 fid & 6 & Functional Identifier - part 2 of the IAI \\\\ \hline 743 reason & 120 & Reason for closing \\\\ \hline 744 from & 120 & Location of closing from \\\\ \hline 745 to & 120 & Location of closing To \\\\ \hline 746 radius & 10 & Extention of closed area \\\\ \hline 747 unit & 2 & Unit of extension value for range field \\\\ \hline 748 closingday & 5 & Closing from day \\\\ \hline 749 closingmonth & 4 & Closing from month \\\\ \hline 750 fromhour & 5 & From LT hour (appr) \\\\ \hline 751 frommin & 6 & From LT minute (appr) \\\\ \hline 752 today & 5 & To day \\\\ \hline 753 tomonth & 4 & To month \\\\ \hline 754 tohour & 5 & To LT hour (appr) \\\\ \hline 755 tomin & 6 & To LT minute (appr) \\\\ \hline 756 spare2 & 4 & Padding out the slot\\\\ \\hline \\hline 757 Total bits & 472 & Appears to take 3 slots with 208 pad bits to fill the last slot \\\\ \\hline 758 \\end{tabular} 759 \\caption{AIS message number 8: IMO fairway closed. Specified in SN\\Circ.236 Annex 2, page 4, Application 3. Also defined in IALA Guidelines on AIS, Vol 1, Part 1, Ed. 1.3. Guildeline No 1028. This message should be used to inform ships, in particular to give guidance to large vessels about temporary closed fairways or sections in ports. Attributes: broadcast, shore station transmitting, no acknowledgement. } 760 \\label{tab:imo_fairway_closed} 761 \\end{table} 762 ''')
763 764 ###################################################################### 765 # Text Definition 766 ###################################################################### 767
768 -def textDefinitionTable(outfile=sys.stdout 769 ,delim='\t' 770 ):
771 ''' 772 Return the text definition table for this message type 773 @param outfile: file like object to print to. 774 @type outfile: file obj 775 @return: text table string via the outfile 776 @rtype: str 777 778 ''' 779 o = outfile 780 o.write('''Parameter'''+delim+'Number of bits'''+delim+'''Description 781 MessageID'''+delim+'''6'''+delim+'''AIS message number. Must be 8 782 RepeatIndicator'''+delim+'''2'''+delim+'''Indicated how many times a message has been repeated 783 UserID'''+delim+'''30'''+delim+'''MMSI number of transmitter broadcasting the message 784 Spare'''+delim+'''2'''+delim+'''Reserved for definition by a regional authority. 785 dac'''+delim+'''10'''+delim+'''Designated Area Code - part 1 of the IAI 786 fid'''+delim+'''6'''+delim+'''Functional Identifier - part 2 of the IAI 787 reason'''+delim+'''120'''+delim+'''Reason for closing 788 from'''+delim+'''120'''+delim+'''Location of closing from 789 to'''+delim+'''120'''+delim+'''Location of closing To 790 radius'''+delim+'''10'''+delim+'''Extention of closed area 791 unit'''+delim+'''2'''+delim+'''Unit of extension value for range field 792 closingday'''+delim+'''5'''+delim+'''Closing from day 793 closingmonth'''+delim+'''4'''+delim+'''Closing from month 794 fromhour'''+delim+'''5'''+delim+'''From LT hour (appr) 795 frommin'''+delim+'''6'''+delim+'''From LT minute (appr) 796 today'''+delim+'''5'''+delim+'''To day 797 tomonth'''+delim+'''4'''+delim+'''To month 798 tohour'''+delim+'''5'''+delim+'''To LT hour (appr) 799 tomin'''+delim+'''6'''+delim+'''To LT minute (appr) 800 spare2'''+delim+'''4'''+delim+'''Padding out the slot 801 Total bits'''+delim+'''472'''+delim+'''Appears to take 3 slots with 208 pad bits to fill the last slot''')
802 803 804 ###################################################################### 805 # UNIT TESTING 806 ###################################################################### 807 import unittest
808 -def testParams():
809 '''Return a params file base on the testvalue tags. 810 @rtype: dict 811 @return: params based on testvalue tags 812 ''' 813 params = {} 814 params['MessageID'] = 8 815 params['RepeatIndicator'] = 1 816 params['UserID'] = 1193046 817 params['Spare'] = 0 818 params['dac'] = 1 819 params['fid'] = 11 820 params['reason'] = 'FIX GIVE SAMPLE ' 821 params['from'] = 'FIX GIVE SAMPLE ' 822 params['to'] = 'FIX GIVE SAMPLE ' 823 params['radius'] = 321 824 params['unit'] = 0 825 params['closingday'] = 31 826 params['closingmonth'] = 12 827 params['fromhour'] = 20 828 params['frommin'] = 23 829 params['today'] = 27 830 params['tomonth'] = 2 831 params['tohour'] = 22 832 params['tomin'] = 35 833 params['spare2'] = 0 834 835 return params
836
837 -class Testimo_fairway_closed(unittest.TestCase):
838 '''Use testvalue tag text from each type to build test case the imo_fairway_closed message'''
839 - def testEncodeDecode(self):
840 841 params = testParams() 842 bits = encode(params) 843 r = decode(bits) 844 845 # Check that each parameter came through ok. 846 self.failUnlessEqual(r['MessageID'],params['MessageID']) 847 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator']) 848 self.failUnlessEqual(r['UserID'],params['UserID']) 849 self.failUnlessEqual(r['Spare'],params['Spare']) 850 self.failUnlessEqual(r['dac'],params['dac']) 851 self.failUnlessEqual(r['fid'],params['fid']) 852 self.failUnlessEqual(r['reason'],params['reason']) 853 self.failUnlessEqual(r['from'],params['from']) 854 self.failUnlessEqual(r['to'],params['to']) 855 self.failUnlessEqual(r['radius'],params['radius']) 856 self.failUnlessEqual(r['unit'],params['unit']) 857 self.failUnlessEqual(r['closingday'],params['closingday']) 858 self.failUnlessEqual(r['closingmonth'],params['closingmonth']) 859 self.failUnlessEqual(r['fromhour'],params['fromhour']) 860 self.failUnlessEqual(r['frommin'],params['frommin']) 861 self.failUnlessEqual(r['today'],params['today']) 862 self.failUnlessEqual(r['tomonth'],params['tomonth']) 863 self.failUnlessEqual(r['tohour'],params['tohour']) 864 self.failUnlessEqual(r['tomin'],params['tomin']) 865 self.failUnlessEqual(r['spare2'],params['spare2'])
866
867 -def addMsgOptions(parser):
868 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true', 869 help='decode a "imo_fairway_closed" AIS message') 870 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true', 871 help='encode a "imo_fairway_closed" AIS message') 872 parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int' 873 ,help='Field parameter value [default: %default]') 874 parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int' 875 ,help='Field parameter value [default: %default]') 876 parser.add_option('--reason-field', dest='reasonField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string' 877 ,help='Field parameter value [default: %default]') 878 parser.add_option('--from-field', dest='fromField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string' 879 ,help='Field parameter value [default: %default]') 880 parser.add_option('--to-field', dest='toField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string' 881 ,help='Field parameter value [default: %default]') 882 parser.add_option('--radius-field', dest='radiusField',default=1001,metavar='uint',type='int' 883 ,help='Field parameter value [default: %default]') 884 parser.add_option('--unit-field', dest='unitField',metavar='uint',type='int' 885 ,help='Field parameter value [default: %default]') 886 parser.add_option('--closingday-field', dest='closingdayField',metavar='uint',type='int' 887 ,help='Field parameter value [default: %default]') 888 parser.add_option('--closingmonth-field', dest='closingmonthField',metavar='uint',type='int' 889 ,help='Field parameter value [default: %default]') 890 parser.add_option('--fromhour-field', dest='fromhourField',metavar='uint',type='int' 891 ,help='Field parameter value [default: %default]') 892 parser.add_option('--frommin-field', dest='fromminField',metavar='uint',type='int' 893 ,help='Field parameter value [default: %default]') 894 parser.add_option('--today-field', dest='todayField',metavar='uint',type='int' 895 ,help='Field parameter value [default: %default]') 896 parser.add_option('--tomonth-field', dest='tomonthField',metavar='uint',type='int' 897 ,help='Field parameter value [default: %default]') 898 parser.add_option('--tohour-field', dest='tohourField',metavar='uint',type='int' 899 ,help='Field parameter value [default: %default]') 900 parser.add_option('--tomin-field', dest='tominField',metavar='uint',type='int' 901 ,help='Field parameter value [default: %default]')
902 903 ############################################################ 904 if __name__=='__main__': 905 906 from optparse import OptionParser 907 parser = OptionParser(usage="%prog [options]", 908 version="%prog "+__version__) 909 910 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true', 911 help='run the documentation tests') 912 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true', 913 help='run the unit tests') 914 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 915 help='Make the test output verbose') 916 917 # FIX: remove nmea from binary messages. No way to build the whole packet? 918 # FIX: or build the surrounding msg 8 for a broadcast? 919 typeChoices = ('binary','nmeapayload','nmea') # FIX: what about a USCG type message? 920 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType' 921 ,default='nmeapayload' 922 ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]') 923 924 925 outputChoices = ('std','html','csv','sql' ) 926 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType' 927 ,default='std' 928 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]') 929 930 parser.add_option('-o','--output',dest='outputFileName',default=None, 931 help='Name of the python file to write [default: stdout]') 932 933 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append', 934 choices=fieldList, 935 help='Which fields to include in the output. Currently only for csv output [default: all]') 936 937 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true', 938 help='Print the field name for csv') 939 940 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true', 941 help='Print out an sql create command for the table.') 942 943 parser.add_option('--latex-table',dest='latexDefinitionTable',default=False,action='store_true', 944 help='Print a LaTeX table of the type') 945 946 parser.add_option('--text-table',dest='textDefinitionTable',default=False,action='store_true', 947 help='Print delimited table of the type (for Word table importing)') 948 parser.add_option('--delimt-text-table',dest='delimTextDefinitionTable',default='\t' 949 ,help='Delimiter for text table [default: \'%default\'](for Word table importing)') 950 951 952 dbChoices = ('sqlite','postgres') 953 parser.add_option('-D','--db-type',dest='dbType',default='postgres' 954 ,choices=dbChoices,type='choice' 955 ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]') 956 957 addMsgOptions(parser) 958 959 (options,args) = parser.parse_args() 960 success=True 961 962 if options.doctest: 963 import os; print os.path.basename(sys.argv[0]), 'doctests ...', 964 sys.argv= [sys.argv[0]] 965 if options.verbose: sys.argv.append('-v') 966 import doctest 967 numfail,numtests=doctest.testmod() 968 if numfail==0: print 'ok' 969 else: 970 print 'FAILED' 971 success=False 972 973 if not success: sys.exit('Something Failed') 974 del success # Hide success from epydoc 975 976 if options.unittest: 977 sys.argv = [sys.argv[0]] 978 if options.verbose: sys.argv.append('-v') 979 unittest.main() 980 981 outfile = sys.stdout 982 if None!=options.outputFileName: 983 outfile = file(options.outputFileName,'w') 984 985 986 if options.doEncode: 987 # First make sure all non required options are specified 988 if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField") 989 if None==options.UserIDField: parser.error("missing value for UserIDField") 990 if None==options.reasonField: parser.error("missing value for reasonField") 991 if None==options.fromField: parser.error("missing value for fromField") 992 if None==options.toField: parser.error("missing value for toField") 993 if None==options.radiusField: parser.error("missing value for radiusField") 994 if None==options.unitField: parser.error("missing value for unitField") 995 if None==options.closingdayField: parser.error("missing value for closingdayField") 996 if None==options.closingmonthField: parser.error("missing value for closingmonthField") 997 if None==options.fromhourField: parser.error("missing value for fromhourField") 998 if None==options.fromminField: parser.error("missing value for fromminField") 999 if None==options.todayField: parser.error("missing value for todayField") 1000 if None==options.tomonthField: parser.error("missing value for tomonthField") 1001 if None==options.tohourField: parser.error("missing value for tohourField") 1002 if None==options.tominField: parser.error("missing value for tominField") 1003 msgDict={ 1004 'MessageID': '8', 1005 'RepeatIndicator': options.RepeatIndicatorField, 1006 'UserID': options.UserIDField, 1007 'Spare': '0', 1008 'dac': '1', 1009 'fid': '11', 1010 'reason': options.reasonField, 1011 'from': options.fromField, 1012 'to': options.toField, 1013 'radius': options.radiusField, 1014 'unit': options.unitField, 1015 'closingday': options.closingdayField, 1016 'closingmonth': options.closingmonthField, 1017 'fromhour': options.fromhourField, 1018 'frommin': options.fromminField, 1019 'today': options.todayField, 1020 'tomonth': options.tomonthField, 1021 'tohour': options.tohourField, 1022 'tomin': options.tominField, 1023 'spare2': '0', 1024 } 1025 1026 bits = encode(msgDict) 1027 if 'binary'==options.ioType: print str(bits) 1028 elif 'nmeapayload'==options.ioType: 1029 # FIX: figure out if this might be necessary at compile time 1030 print "bitLen",len(bits) 1031 bitLen=len(bits) 1032 if bitLen%6!=0: 1033 bits = bits + BitVector(size=(6 - (bitLen%6))) # Pad out to multiple of 6 1034 print "result:",binary.bitvectoais6(bits)[0] 1035 1036 1037 # FIX: Do not emit this option for the binary message payloads. Does not make sense. 1038 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability") 1039 else: sys.exit('ERROR: unknown ioType. Help!') 1040 1041 1042 if options.sqlCreate: 1043 sqlCreateStr(outfile,options.fieldList,dbType=options.dbType) 1044 1045 if options.latexDefinitionTable: 1046 latexDefinitionTable(outfile) 1047 1048 # For conversion to word tables 1049 if options.textDefinitionTable: 1050 textDefinitionTable(outfile,options.delimTextDefinitionTable) 1051 1052 if options.printCsvfieldList: 1053 # Make a csv separated list of fields that will be displayed for csv 1054 if None == options.fieldList: options.fieldList = fieldList 1055 import StringIO 1056 buf = StringIO.StringIO() 1057 for field in options.fieldList: 1058 buf.write(field+',') 1059 result = buf.getvalue() 1060 if result[-1] == ',': print result[:-1] 1061 else: print result 1062 1063 if options.doDecode: 1064 if len(args)==0: args = sys.stdin 1065 for msg in args: 1066 bv = None 1067 1068 if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'): 1069 # Found nmea 1070 # FIX: do checksum 1071 bv = binary.ais6tobitvec(msg.split(',')[5]) 1072 else: # either binary or nmeapayload... expect mostly nmeapayloads 1073 # assumes that an all 0 and 1 string can not be a nmeapayload 1074 binaryMsg=True 1075 for c in msg: 1076 if c not in ('0','1'): 1077 binaryMsg=False 1078 break 1079 if binaryMsg: 1080 bv = BitVector(bitstring=msg) 1081 else: # nmeapayload 1082 bv = binary.ais6tobitvec(msg) 1083 1084 printFields(decode(bv) 1085 ,out=outfile 1086 ,format=options.outputType 1087 ,fieldList=options.fieldList 1088 ,dbType=options.dbType 1089 ) 1090