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: 2008-01-09 $'.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 dbTableName='imo_fairway_closed' 581 'Database table name' 582
583 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None 584 ,addCoastGuardFields=True 585 ,dbType='postgres' 586 ):
587 ''' 588 Return the SQL CREATE command for this message type 589 @param outfile: file like object to print to. 590 @param fields: which fields to put in the create. Defaults to all. 591 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 592 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 593 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 594 @type addCoastGuardFields: bool 595 @return: sql create string 596 @rtype: str 597 598 @see: sqlCreate 599 ''' 600 # FIX: should this sqlCreate be the same as in LaTeX (createFuncName) rather than hard coded? 601 outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType)))
602
603 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'):
604 ''' 605 Return the sqlhelp object to create the table. 606 607 @param fields: which fields to put in the create. Defaults to all. 608 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 609 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 610 @type addCoastGuardFields: bool 611 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 612 @return: An object that can be used to generate a return 613 @rtype: sqlhelp.create 614 ''' 615 if None == fields: fields = fieldList 616 import sqlhelp 617 c = sqlhelp.create('imo_fairway_closed',dbType=dbType) 618 c.addPrimaryKey() 619 if 'MessageID' in fields: c.addInt ('MessageID') 620 if 'RepeatIndicator' in fields: c.addInt ('RepeatIndicator') 621 if 'UserID' in fields: c.addInt ('UserID') 622 if 'Spare' in fields: c.addInt ('Spare') 623 if 'dac' in fields: c.addInt ('dac') 624 if 'fid' in fields: c.addInt ('fid') 625 if 'reason' in fields: c.addVarChar('reason',20) 626 if 'from' in fields: c.addVarChar('from',20) 627 if 'to' in fields: c.addVarChar('to',20) 628 if 'radius' in fields: c.addInt ('radius') 629 if 'unit' in fields: c.addInt ('unit') 630 if 'closingday' in fields: c.addInt ('closingday') 631 if 'closingmonth' in fields: c.addInt ('closingmonth') 632 if 'fromhour' in fields: c.addInt ('fromhour') 633 if 'frommin' in fields: c.addInt ('frommin') 634 if 'today' in fields: c.addInt ('today') 635 if 'tomonth' in fields: c.addInt ('tomonth') 636 if 'tohour' in fields: c.addInt ('tohour') 637 if 'tomin' in fields: c.addInt ('tomin') 638 if 'spare2' in fields: c.addInt ('spare2') 639 640 if addCoastGuardFields: 641 # c.addInt('cg_rssi') # Relative signal strength indicator 642 # c.addInt('cg_d') # dBm receive strength 643 # c.addInt('cg_T') # Receive timestamp from the AIS equipment 644 # c.addInt('cg_S') # Slot received in 645 # c.addVarChar('cg_x',10) # Idonno 646 c.addVarChar('cg_r',15) # Receiver station ID - should usually be an MMSI, but sometimes is a string 647 c.addInt('cg_sec') # UTC seconds since the epoch 648 649 c.addTimestamp('cg_timestamp') # UTC decoded cg_sec - not actually in the data stream 650 651 return c
652
653 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'):
654 ''' 655 Return the SQL INSERT command for this message type 656 @param params: dictionary of values keyed by field name 657 @param outfile: file like object to print to. 658 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields 659 @return: sql create string 660 @rtype: str 661 662 @see: sqlCreate 663 ''' 664 outfile.write(str(sqlInsert(params,extraParams,dbType=dbType)))
665 666
667 -def sqlInsert(params,extraParams=None,dbType='postgres'):
668 ''' 669 Give the SQL INSERT statement 670 @param params: dict keyed by field name of values 671 @param extraParams: any extra fields that you have created beyond the normal ais message fields 672 @rtype: sqlhelp.insert 673 @return: insert class instance 674 @todo: allow optional type checking of params? 675 @warning: this will take invalid keys happily and do what??? 676 ''' 677 import sqlhelp 678 i = sqlhelp.insert('imo_fairway_closed',dbType=dbType) 679 680 if dbType=='postgres': 681 finished = [] 682 for key in params: 683 if key in finished: 684 continue 685 686 if key not in toPgFields and key not in fromPgFields: 687 if type(params[key])==Decimal: i.add(key,float(params[key])) 688 else: i.add(key,params[key]) 689 else: 690 if key in fromPgFields: 691 val = params[key] 692 # Had better be a WKT type like POINT(-88.1 30.321) 693 i.addPostGIS(key,val) 694 finished.append(key) 695 else: 696 # Need to construct the type. 697 pgName = toPgFields[key] 698 #valStr='GeomFromText(\''+pgTypes[pgName]+'(' 699 valStr=pgTypes[pgName]+'(' 700 vals = [] 701 for nonPgKey in fromPgFields[pgName]: 702 vals.append(str(params[nonPgKey])) 703 finished.append(nonPgKey) 704 valStr+=' '.join(vals)+')' 705 i.addPostGIS(pgName,valStr) 706 else: 707 for key in params: 708 if type(params[key])==Decimal: i.add(key,float(params[key])) 709 else: i.add(key,params[key]) 710 711 if None != extraParams: 712 for key in extraParams: 713 i.add(key,extraParams[key]) 714 715 return i
716 717 ###################################################################### 718 # LATEX SUPPORT 719 ###################################################################### 720
721 -def latexDefinitionTable(outfile=sys.stdout 722 ):
723 ''' 724 Return the LaTeX definition table for this message type 725 @param outfile: file like object to print to. 726 @type outfile: file obj 727 @return: LaTeX table string via the outfile 728 @rtype: str 729 730 ''' 731 o = outfile 732 733 o.write(''' 734 \\begin{table}%[htb] 735 \\centering 736 \\begin{tabular}{|l|c|l|} 737 \\hline 738 Parameter & Number of bits & Description 739 \\\\ \\hline\\hline 740 MessageID & 6 & AIS message number. Must be 8 \\\\ \hline 741 RepeatIndicator & 2 & Indicated how many times a message has been repeated \\\\ \hline 742 UserID & 30 & MMSI number of transmitter broadcasting the message \\\\ \hline 743 Spare & 2 & Reserved for definition by a regional authority. \\\\ \hline 744 dac & 10 & Designated Area Code - part 1 of the IAI \\\\ \hline 745 fid & 6 & Functional Identifier - part 2 of the IAI \\\\ \hline 746 reason & 120 & Reason for closing \\\\ \hline 747 from & 120 & Location of closing from \\\\ \hline 748 to & 120 & Location of closing To \\\\ \hline 749 radius & 10 & Extention of closed area \\\\ \hline 750 unit & 2 & Unit of extension value for range field \\\\ \hline 751 closingday & 5 & Closing from day \\\\ \hline 752 closingmonth & 4 & Closing from month \\\\ \hline 753 fromhour & 5 & From LT hour (appr) \\\\ \hline 754 frommin & 6 & From LT minute (appr) \\\\ \hline 755 today & 5 & To day \\\\ \hline 756 tomonth & 4 & To month \\\\ \hline 757 tohour & 5 & To LT hour (appr) \\\\ \hline 758 tomin & 6 & To LT minute (appr) \\\\ \hline 759 spare2 & 4 & Padding out the slot\\\\ \\hline \\hline 760 Total bits & 472 & Appears to take 3 slots with 208 pad bits to fill the last slot \\\\ \\hline 761 \\end{tabular} 762 \\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. } 763 \\label{tab:imo_fairway_closed} 764 \\end{table} 765 ''')
766 767 ###################################################################### 768 # Text Definition 769 ###################################################################### 770
771 -def textDefinitionTable(outfile=sys.stdout 772 ,delim='\t' 773 ):
774 ''' 775 Return the text definition table for this message type 776 @param outfile: file like object to print to. 777 @type outfile: file obj 778 @return: text table string via the outfile 779 @rtype: str 780 781 ''' 782 o = outfile 783 o.write('''Parameter'''+delim+'Number of bits'''+delim+'''Description 784 MessageID'''+delim+'''6'''+delim+'''AIS message number. Must be 8 785 RepeatIndicator'''+delim+'''2'''+delim+'''Indicated how many times a message has been repeated 786 UserID'''+delim+'''30'''+delim+'''MMSI number of transmitter broadcasting the message 787 Spare'''+delim+'''2'''+delim+'''Reserved for definition by a regional authority. 788 dac'''+delim+'''10'''+delim+'''Designated Area Code - part 1 of the IAI 789 fid'''+delim+'''6'''+delim+'''Functional Identifier - part 2 of the IAI 790 reason'''+delim+'''120'''+delim+'''Reason for closing 791 from'''+delim+'''120'''+delim+'''Location of closing from 792 to'''+delim+'''120'''+delim+'''Location of closing To 793 radius'''+delim+'''10'''+delim+'''Extention of closed area 794 unit'''+delim+'''2'''+delim+'''Unit of extension value for range field 795 closingday'''+delim+'''5'''+delim+'''Closing from day 796 closingmonth'''+delim+'''4'''+delim+'''Closing from month 797 fromhour'''+delim+'''5'''+delim+'''From LT hour (appr) 798 frommin'''+delim+'''6'''+delim+'''From LT minute (appr) 799 today'''+delim+'''5'''+delim+'''To day 800 tomonth'''+delim+'''4'''+delim+'''To month 801 tohour'''+delim+'''5'''+delim+'''To LT hour (appr) 802 tomin'''+delim+'''6'''+delim+'''To LT minute (appr) 803 spare2'''+delim+'''4'''+delim+'''Padding out the slot 804 Total bits'''+delim+'''472'''+delim+'''Appears to take 3 slots with 208 pad bits to fill the last slot''')
805 806 807 ###################################################################### 808 # UNIT TESTING 809 ###################################################################### 810 import unittest
811 -def testParams():
812 '''Return a params file base on the testvalue tags. 813 @rtype: dict 814 @return: params based on testvalue tags 815 ''' 816 params = {} 817 params['MessageID'] = 8 818 params['RepeatIndicator'] = 1 819 params['UserID'] = 1193046 820 params['Spare'] = 0 821 params['dac'] = 1 822 params['fid'] = 11 823 params['reason'] = 'FIX GIVE SAMPLE ' 824 params['from'] = 'FIX GIVE SAMPLE ' 825 params['to'] = 'FIX GIVE SAMPLE ' 826 params['radius'] = 321 827 params['unit'] = 0 828 params['closingday'] = 31 829 params['closingmonth'] = 12 830 params['fromhour'] = 20 831 params['frommin'] = 23 832 params['today'] = 27 833 params['tomonth'] = 2 834 params['tohour'] = 22 835 params['tomin'] = 35 836 params['spare2'] = 0 837 838 return params
839
840 -class Testimo_fairway_closed(unittest.TestCase):
841 '''Use testvalue tag text from each type to build test case the imo_fairway_closed message'''
842 - def testEncodeDecode(self):
843 844 params = testParams() 845 bits = encode(params) 846 r = decode(bits) 847 848 # Check that each parameter came through ok. 849 self.failUnlessEqual(r['MessageID'],params['MessageID']) 850 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator']) 851 self.failUnlessEqual(r['UserID'],params['UserID']) 852 self.failUnlessEqual(r['Spare'],params['Spare']) 853 self.failUnlessEqual(r['dac'],params['dac']) 854 self.failUnlessEqual(r['fid'],params['fid']) 855 self.failUnlessEqual(r['reason'],params['reason']) 856 self.failUnlessEqual(r['from'],params['from']) 857 self.failUnlessEqual(r['to'],params['to']) 858 self.failUnlessEqual(r['radius'],params['radius']) 859 self.failUnlessEqual(r['unit'],params['unit']) 860 self.failUnlessEqual(r['closingday'],params['closingday']) 861 self.failUnlessEqual(r['closingmonth'],params['closingmonth']) 862 self.failUnlessEqual(r['fromhour'],params['fromhour']) 863 self.failUnlessEqual(r['frommin'],params['frommin']) 864 self.failUnlessEqual(r['today'],params['today']) 865 self.failUnlessEqual(r['tomonth'],params['tomonth']) 866 self.failUnlessEqual(r['tohour'],params['tohour']) 867 self.failUnlessEqual(r['tomin'],params['tomin']) 868 self.failUnlessEqual(r['spare2'],params['spare2'])
869
870 -def addMsgOptions(parser):
871 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true', 872 help='decode a "imo_fairway_closed" AIS message') 873 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true', 874 help='encode a "imo_fairway_closed" AIS message') 875 parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int' 876 ,help='Field parameter value [default: %default]') 877 parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int' 878 ,help='Field parameter value [default: %default]') 879 parser.add_option('--reason-field', dest='reasonField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string' 880 ,help='Field parameter value [default: %default]') 881 parser.add_option('--from-field', dest='fromField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string' 882 ,help='Field parameter value [default: %default]') 883 parser.add_option('--to-field', dest='toField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string' 884 ,help='Field parameter value [default: %default]') 885 parser.add_option('--radius-field', dest='radiusField',default=1001,metavar='uint',type='int' 886 ,help='Field parameter value [default: %default]') 887 parser.add_option('--unit-field', dest='unitField',metavar='uint',type='int' 888 ,help='Field parameter value [default: %default]') 889 parser.add_option('--closingday-field', dest='closingdayField',metavar='uint',type='int' 890 ,help='Field parameter value [default: %default]') 891 parser.add_option('--closingmonth-field', dest='closingmonthField',metavar='uint',type='int' 892 ,help='Field parameter value [default: %default]') 893 parser.add_option('--fromhour-field', dest='fromhourField',metavar='uint',type='int' 894 ,help='Field parameter value [default: %default]') 895 parser.add_option('--frommin-field', dest='fromminField',metavar='uint',type='int' 896 ,help='Field parameter value [default: %default]') 897 parser.add_option('--today-field', dest='todayField',metavar='uint',type='int' 898 ,help='Field parameter value [default: %default]') 899 parser.add_option('--tomonth-field', dest='tomonthField',metavar='uint',type='int' 900 ,help='Field parameter value [default: %default]') 901 parser.add_option('--tohour-field', dest='tohourField',metavar='uint',type='int' 902 ,help='Field parameter value [default: %default]') 903 parser.add_option('--tomin-field', dest='tominField',metavar='uint',type='int' 904 ,help='Field parameter value [default: %default]')
905 906 ############################################################ 907 if __name__=='__main__': 908 909 from optparse import OptionParser 910 parser = OptionParser(usage="%prog [options]", 911 version="%prog "+__version__) 912 913 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true', 914 help='run the documentation tests') 915 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true', 916 help='run the unit tests') 917 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 918 help='Make the test output verbose') 919 920 # FIX: remove nmea from binary messages. No way to build the whole packet? 921 # FIX: or build the surrounding msg 8 for a broadcast? 922 typeChoices = ('binary','nmeapayload','nmea') # FIX: what about a USCG type message? 923 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType' 924 ,default='nmeapayload' 925 ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]') 926 927 928 outputChoices = ('std','html','csv','sql' ) 929 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType' 930 ,default='std' 931 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]') 932 933 parser.add_option('-o','--output',dest='outputFileName',default=None, 934 help='Name of the python file to write [default: stdout]') 935 936 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append', 937 choices=fieldList, 938 help='Which fields to include in the output. Currently only for csv output [default: all]') 939 940 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true', 941 help='Print the field name for csv') 942 943 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true', 944 help='Print out an sql create command for the table.') 945 946 parser.add_option('--latex-table',dest='latexDefinitionTable',default=False,action='store_true', 947 help='Print a LaTeX table of the type') 948 949 parser.add_option('--text-table',dest='textDefinitionTable',default=False,action='store_true', 950 help='Print delimited table of the type (for Word table importing)') 951 parser.add_option('--delimt-text-table',dest='delimTextDefinitionTable',default='\t' 952 ,help='Delimiter for text table [default: \'%default\'](for Word table importing)') 953 954 955 dbChoices = ('sqlite','postgres') 956 parser.add_option('-D','--db-type',dest='dbType',default='postgres' 957 ,choices=dbChoices,type='choice' 958 ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]') 959 960 addMsgOptions(parser) 961 962 (options,args) = parser.parse_args() 963 success=True 964 965 if options.doctest: 966 import os; print os.path.basename(sys.argv[0]), 'doctests ...', 967 sys.argv= [sys.argv[0]] 968 if options.verbose: sys.argv.append('-v') 969 import doctest 970 numfail,numtests=doctest.testmod() 971 if numfail==0: print 'ok' 972 else: 973 print 'FAILED' 974 success=False 975 976 if not success: sys.exit('Something Failed') 977 del success # Hide success from epydoc 978 979 if options.unittest: 980 sys.argv = [sys.argv[0]] 981 if options.verbose: sys.argv.append('-v') 982 unittest.main() 983 984 outfile = sys.stdout 985 if None!=options.outputFileName: 986 outfile = file(options.outputFileName,'w') 987 988 989 if options.doEncode: 990 # First make sure all non required options are specified 991 if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField") 992 if None==options.UserIDField: parser.error("missing value for UserIDField") 993 if None==options.reasonField: parser.error("missing value for reasonField") 994 if None==options.fromField: parser.error("missing value for fromField") 995 if None==options.toField: parser.error("missing value for toField") 996 if None==options.radiusField: parser.error("missing value for radiusField") 997 if None==options.unitField: parser.error("missing value for unitField") 998 if None==options.closingdayField: parser.error("missing value for closingdayField") 999 if None==options.closingmonthField: parser.error("missing value for closingmonthField") 1000 if None==options.fromhourField: parser.error("missing value for fromhourField") 1001 if None==options.fromminField: parser.error("missing value for fromminField") 1002 if None==options.todayField: parser.error("missing value for todayField") 1003 if None==options.tomonthField: parser.error("missing value for tomonthField") 1004 if None==options.tohourField: parser.error("missing value for tohourField") 1005 if None==options.tominField: parser.error("missing value for tominField") 1006 msgDict={ 1007 'MessageID': '8', 1008 'RepeatIndicator': options.RepeatIndicatorField, 1009 'UserID': options.UserIDField, 1010 'Spare': '0', 1011 'dac': '1', 1012 'fid': '11', 1013 'reason': options.reasonField, 1014 'from': options.fromField, 1015 'to': options.toField, 1016 'radius': options.radiusField, 1017 'unit': options.unitField, 1018 'closingday': options.closingdayField, 1019 'closingmonth': options.closingmonthField, 1020 'fromhour': options.fromhourField, 1021 'frommin': options.fromminField, 1022 'today': options.todayField, 1023 'tomonth': options.tomonthField, 1024 'tohour': options.tohourField, 1025 'tomin': options.tominField, 1026 'spare2': '0', 1027 } 1028 1029 bits = encode(msgDict) 1030 if 'binary'==options.ioType: print str(bits) 1031 elif 'nmeapayload'==options.ioType: 1032 # FIX: figure out if this might be necessary at compile time 1033 print "bitLen",len(bits) 1034 bitLen=len(bits) 1035 if bitLen%6!=0: 1036 bits = bits + BitVector(size=(6 - (bitLen%6))) # Pad out to multiple of 6 1037 print "result:",binary.bitvectoais6(bits)[0] 1038 1039 1040 # FIX: Do not emit this option for the binary message payloads. Does not make sense. 1041 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability") 1042 else: sys.exit('ERROR: unknown ioType. Help!') 1043 1044 1045 if options.sqlCreate: 1046 sqlCreateStr(outfile,options.fieldList,dbType=options.dbType) 1047 1048 if options.latexDefinitionTable: 1049 latexDefinitionTable(outfile) 1050 1051 # For conversion to word tables 1052 if options.textDefinitionTable: 1053 textDefinitionTable(outfile,options.delimTextDefinitionTable) 1054 1055 if options.printCsvfieldList: 1056 # Make a csv separated list of fields that will be displayed for csv 1057 if None == options.fieldList: options.fieldList = fieldList 1058 import StringIO 1059 buf = StringIO.StringIO() 1060 for field in options.fieldList: 1061 buf.write(field+',') 1062 result = buf.getvalue() 1063 if result[-1] == ',': print result[:-1] 1064 else: print result 1065 1066 if options.doDecode: 1067 if len(args)==0: args = sys.stdin 1068 for msg in args: 1069 bv = None 1070 1071 if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'): 1072 # Found nmea 1073 # FIX: do checksum 1074 bv = binary.ais6tobitvec(msg.split(',')[5]) 1075 else: # either binary or nmeapayload... expect mostly nmeapayloads 1076 # assumes that an all 0 and 1 string can not be a nmeapayload 1077 binaryMsg=True 1078 for c in msg: 1079 if c not in ('0','1'): 1080 binaryMsg=False 1081 break 1082 if binaryMsg: 1083 bv = BitVector(bitstring=msg) 1084 else: # nmeapayload 1085 bv = binary.ais6tobitvec(msg) 1086 1087 printFields(decode(bv) 1088 ,out=outfile 1089 ,format=options.outputType 1090 ,fieldList=options.fieldList 1091 ,dbType=options.dbType 1092 ) 1093