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

Source Code for Module ais.whalenotice

  1  #!/usr/bin/env python 
  2   
  3  __version__ = '$Revision: 4791 $'.split()[1] 
  4  __date__ = '$Date: 2007-02-26 $'.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          'dac', 
 51          'fid', 
 52          'efid', 
 53          'timetag_month', 
 54          'timetag_day', 
 55          'timetag_hour', 
 56          'timetag_min', 
 57          'timetag_sec', 
 58          'stationid', 
 59          'station_longitude', 
 60          'station_latitude', 
 61          'whale_longitude', 
 62          'whale_latitude', 
 63          'timetoexpire', 
 64          'radius', 
 65          'heading', 
 66          'numWhales', 
 67  ) 
 68   
 69  fieldListPostgres = ( 
 70          'dac', 
 71          'fid', 
 72          'efid', 
 73          'timetag_month', 
 74          'timetag_day', 
 75          'timetag_hour', 
 76          'timetag_min', 
 77          'timetag_sec', 
 78          'stationid', 
 79          'station_longitude', 
 80          'station_latitude', 
 81          'whale_longitude', 
 82          'whale_latitude', 
 83          'timetoexpire', 
 84          'radius', 
 85          'heading', 
 86          'numWhales', 
 87  ) 
 88   
 89  toPgFields = { 
 90  } 
 91  ''' 
 92  Go to the Postgis field names from the straight field name 
 93  ''' 
 94   
 95  fromPgFields = { 
 96  } 
 97  ''' 
 98  Go from the Postgis field names to the straight field name 
 99  ''' 
100   
101  pgTypes = { 
102  } 
103  ''' 
104  Lookup table for each postgis field name to get its type. 
105  ''' 
106   
107 -def encode(params, validate=False):
108 '''Create a whalenotice binary message payload to pack into an AIS Msg whalenotice. 109 110 Fields in params: 111 - dac(uint): Designated Area Code (field automatically set to "366") 112 - fid(uint): Functional Identifier (field automatically set to "1") 113 - efid(uint): extended functional identifier (dac+fid+id defines which message) (field automatically set to "2") 114 - timetag_month(uint): Time whale was last recorded month 1..12 115 - timetag_day(uint): Time whale was last recorded day of the month 1..31 116 - timetag_hour(uint): Time whale was last recorded UTC hours 0..23 117 - timetag_min(uint): Time whale was last recorded minutes 118 - timetag_sec(uint): Time whale was last recorded seconds 119 - stationid(aisstr6): Character identifier of the station. Usually a number. 120 - station_longitude(decimal): Location of the sensor taking the water level measurement or position of prediction East West location 121 - station_latitude(decimal): Location of the sensor taking the water level measurement or position of prediction North South location 122 - whale_longitude(decimal): Where was the whale East West location 123 - whale_latitude(decimal): Where was the whale North South location 124 - timetoexpire(uint): Seconds until this notice expires 125 - radius(uint): Distance of the required exclusion/slow zone 126 - heading(uint): Direction the whale is traveling 127 - numWhales(uint): Number of whales detected 128 @param params: Dictionary of field names/values. Throws a ValueError exception if required is missing 129 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 130 @rtype: BitVector 131 @return: encoded binary message (for binary messages, this needs to be wrapped in a msg 8 132 @note: The returned bits may not be 6 bit aligned. It is up to you to pad out the bits. 133 ''' 134 135 bvList = [] 136 bvList.append(binary.setBitVectorSize(BitVector(intVal=366),16)) 137 bvList.append(binary.setBitVectorSize(BitVector(intVal=1),4)) 138 bvList.append(binary.setBitVectorSize(BitVector(intVal=2),12)) 139 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['timetag_month']),4)) 140 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['timetag_day']),5)) 141 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['timetag_hour']),5)) 142 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['timetag_min']),6)) 143 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['timetag_sec']),6)) 144 if 'stationid' in params: 145 bvList.append(aisstring.encode(params['stationid'],42)) 146 else: 147 bvList.append(aisstring.encode('@@@@@@@',42)) 148 if 'station_longitude' in params: 149 bvList.append(binary.bvFromSignedInt(int(Decimal(params['station_longitude'])*Decimal('600000')),28)) 150 else: 151 bvList.append(binary.bvFromSignedInt(108600000,28)) 152 if 'station_latitude' in params: 153 bvList.append(binary.bvFromSignedInt(int(Decimal(params['station_latitude'])*Decimal('600000')),27)) 154 else: 155 bvList.append(binary.bvFromSignedInt(54600000,27)) 156 if 'whale_longitude' in params: 157 bvList.append(binary.bvFromSignedInt(int(Decimal(params['whale_longitude'])*Decimal('600000')),28)) 158 else: 159 bvList.append(binary.bvFromSignedInt(108600000,28)) 160 if 'whale_latitude' in params: 161 bvList.append(binary.bvFromSignedInt(int(Decimal(params['whale_latitude'])*Decimal('600000')),27)) 162 else: 163 bvList.append(binary.bvFromSignedInt(54600000,27)) 164 if 'timetoexpire' in params: 165 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['timetoexpire']),16)) 166 else: 167 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),16)) 168 if 'radius' in params: 169 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['radius']),16)) 170 else: 171 bvList.append(binary.setBitVectorSize(BitVector(intVal=65534),16)) 172 if 'heading' in params: 173 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['heading']),9)) 174 else: 175 bvList.append(binary.setBitVectorSize(BitVector(intVal=511),9)) 176 if 'numWhales' in params: 177 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['numWhales']),8)) 178 else: 179 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),8)) 180 181 return binary.joinBV(bvList)
182
183 -def decode(bv, validate=False):
184 '''Unpack a whalenotice message 185 186 Fields in params: 187 - dac(uint): Designated Area Code (field automatically set to "366") 188 - fid(uint): Functional Identifier (field automatically set to "1") 189 - efid(uint): extended functional identifier (dac+fid+id defines which message) (field automatically set to "2") 190 - timetag_month(uint): Time whale was last recorded month 1..12 191 - timetag_day(uint): Time whale was last recorded day of the month 1..31 192 - timetag_hour(uint): Time whale was last recorded UTC hours 0..23 193 - timetag_min(uint): Time whale was last recorded minutes 194 - timetag_sec(uint): Time whale was last recorded seconds 195 - stationid(aisstr6): Character identifier of the station. Usually a number. 196 - station_longitude(decimal): Location of the sensor taking the water level measurement or position of prediction East West location 197 - station_latitude(decimal): Location of the sensor taking the water level measurement or position of prediction North South location 198 - whale_longitude(decimal): Where was the whale East West location 199 - whale_latitude(decimal): Where was the whale North South location 200 - timetoexpire(uint): Seconds until this notice expires 201 - radius(uint): Distance of the required exclusion/slow zone 202 - heading(uint): Direction the whale is traveling 203 - numWhales(uint): Number of whales detected 204 @type bv: BitVector 205 @param bv: Bits defining a message 206 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 207 @rtype: dict 208 @return: params 209 ''' 210 211 #Would be nice to check the bit count here.. 212 #if validate: 213 # assert (len(bv)==FIX: SOME NUMBER) 214 r = {} 215 r['dac']=366 216 r['fid']=1 217 r['efid']=2 218 r['timetag_month']=int(bv[32:36]) 219 r['timetag_day']=int(bv[36:41]) 220 r['timetag_hour']=int(bv[41:46]) 221 r['timetag_min']=int(bv[46:52]) 222 r['timetag_sec']=int(bv[52:58]) 223 r['stationid']=aisstring.decode(bv[58:100]) 224 r['station_longitude']=Decimal(binary.signedIntFromBV(bv[100:128]))/Decimal('600000') 225 r['station_latitude']=Decimal(binary.signedIntFromBV(bv[128:155]))/Decimal('600000') 226 r['whale_longitude']=Decimal(binary.signedIntFromBV(bv[155:183]))/Decimal('600000') 227 r['whale_latitude']=Decimal(binary.signedIntFromBV(bv[183:210]))/Decimal('600000') 228 r['timetoexpire']=int(bv[210:226]) 229 r['radius']=int(bv[226:242]) 230 r['heading']=int(bv[242:251]) 231 r['numWhales']=int(bv[251:259]) 232 return r
233
234 -def decodedac(bv, validate=False):
235 return 366
236
237 -def decodefid(bv, validate=False):
238 return 1
239
240 -def decodeefid(bv, validate=False):
241 return 2
242
243 -def decodetimetag_month(bv, validate=False):
244 return int(bv[32:36])
245
246 -def decodetimetag_day(bv, validate=False):
247 return int(bv[36:41])
248
249 -def decodetimetag_hour(bv, validate=False):
250 return int(bv[41:46])
251
252 -def decodetimetag_min(bv, validate=False):
253 return int(bv[46:52])
254
255 -def decodetimetag_sec(bv, validate=False):
256 return int(bv[52:58])
257
258 -def decodestationid(bv, validate=False):
259 return aisstring.decode(bv[58:100])
260
261 -def decodestation_longitude(bv, validate=False):
262 return Decimal(binary.signedIntFromBV(bv[100:128]))/Decimal('600000')
263
264 -def decodestation_latitude(bv, validate=False):
265 return Decimal(binary.signedIntFromBV(bv[128:155]))/Decimal('600000')
266
267 -def decodewhale_longitude(bv, validate=False):
268 return Decimal(binary.signedIntFromBV(bv[155:183]))/Decimal('600000')
269
270 -def decodewhale_latitude(bv, validate=False):
271 return Decimal(binary.signedIntFromBV(bv[183:210]))/Decimal('600000')
272
273 -def decodetimetoexpire(bv, validate=False):
274 return int(bv[210:226])
275
276 -def decoderadius(bv, validate=False):
277 return int(bv[226:242])
278
279 -def decodeheading(bv, validate=False):
280 return int(bv[242:251])
281
282 -def decodenumWhales(bv, validate=False):
283 return int(bv[251:259])
284 285
286 -def printHtml(params, out=sys.stdout):
287 out.write("<h3>whalenotice<h3>\n") 288 out.write("<table border=\"1\">\n") 289 out.write("<tr bgcolor=\"orange\">\n") 290 out.write("<th align=\"left\">Field Name</th>\n") 291 out.write("<th align=\"left\">Type</th>\n") 292 out.write("<th align=\"left\">Value</th>\n") 293 out.write("<th align=\"left\">Value in Lookup Table</th>\n") 294 out.write("<th align=\"left\">Units</th>\n") 295 out.write("\n") 296 out.write("<tr>\n") 297 out.write("<td>dac</td>\n") 298 out.write("<td>uint</td>\n") 299 if 'dac' in params: 300 out.write(" <td>"+str(params['dac'])+"</td>\n") 301 out.write(" <td>"+str(params['dac'])+"</td>\n") 302 out.write("</tr>\n") 303 out.write("\n") 304 out.write("<tr>\n") 305 out.write("<td>fid</td>\n") 306 out.write("<td>uint</td>\n") 307 if 'fid' in params: 308 out.write(" <td>"+str(params['fid'])+"</td>\n") 309 out.write(" <td>"+str(params['fid'])+"</td>\n") 310 out.write("</tr>\n") 311 out.write("\n") 312 out.write("<tr>\n") 313 out.write("<td>efid</td>\n") 314 out.write("<td>uint</td>\n") 315 if 'efid' in params: 316 out.write(" <td>"+str(params['efid'])+"</td>\n") 317 out.write(" <td>"+str(params['efid'])+"</td>\n") 318 out.write("</tr>\n") 319 out.write("\n") 320 out.write("<tr>\n") 321 out.write("<td>timetag_month</td>\n") 322 out.write("<td>uint</td>\n") 323 if 'timetag_month' in params: 324 out.write(" <td>"+str(params['timetag_month'])+"</td>\n") 325 out.write(" <td>"+str(params['timetag_month'])+"</td>\n") 326 out.write("</tr>\n") 327 out.write("\n") 328 out.write("<tr>\n") 329 out.write("<td>timetag_day</td>\n") 330 out.write("<td>uint</td>\n") 331 if 'timetag_day' in params: 332 out.write(" <td>"+str(params['timetag_day'])+"</td>\n") 333 out.write(" <td>"+str(params['timetag_day'])+"</td>\n") 334 out.write("</tr>\n") 335 out.write("\n") 336 out.write("<tr>\n") 337 out.write("<td>timetag_hour</td>\n") 338 out.write("<td>uint</td>\n") 339 if 'timetag_hour' in params: 340 out.write(" <td>"+str(params['timetag_hour'])+"</td>\n") 341 out.write(" <td>"+str(params['timetag_hour'])+"</td>\n") 342 out.write("</tr>\n") 343 out.write("\n") 344 out.write("<tr>\n") 345 out.write("<td>timetag_min</td>\n") 346 out.write("<td>uint</td>\n") 347 if 'timetag_min' in params: 348 out.write(" <td>"+str(params['timetag_min'])+"</td>\n") 349 out.write(" <td>"+str(params['timetag_min'])+"</td>\n") 350 out.write("</tr>\n") 351 out.write("\n") 352 out.write("<tr>\n") 353 out.write("<td>timetag_sec</td>\n") 354 out.write("<td>uint</td>\n") 355 if 'timetag_sec' in params: 356 out.write(" <td>"+str(params['timetag_sec'])+"</td>\n") 357 out.write(" <td>"+str(params['timetag_sec'])+"</td>\n") 358 out.write("</tr>\n") 359 out.write("\n") 360 out.write("<tr>\n") 361 out.write("<td>stationid</td>\n") 362 out.write("<td>aisstr6</td>\n") 363 if 'stationid' in params: 364 out.write(" <td>"+str(params['stationid'])+"</td>\n") 365 out.write(" <td>"+str(params['stationid'])+"</td>\n") 366 out.write("</tr>\n") 367 out.write("\n") 368 out.write("<tr>\n") 369 out.write("<td>station_longitude</td>\n") 370 out.write("<td>decimal</td>\n") 371 if 'station_longitude' in params: 372 out.write(" <td>"+str(params['station_longitude'])+"</td>\n") 373 out.write(" <td>"+str(params['station_longitude'])+"</td>\n") 374 out.write("<td>degrees</td>\n") 375 out.write("</tr>\n") 376 out.write("\n") 377 out.write("<tr>\n") 378 out.write("<td>station_latitude</td>\n") 379 out.write("<td>decimal</td>\n") 380 if 'station_latitude' in params: 381 out.write(" <td>"+str(params['station_latitude'])+"</td>\n") 382 out.write(" <td>"+str(params['station_latitude'])+"</td>\n") 383 out.write("<td>degrees</td>\n") 384 out.write("</tr>\n") 385 out.write("\n") 386 out.write("<tr>\n") 387 out.write("<td>whale_longitude</td>\n") 388 out.write("<td>decimal</td>\n") 389 if 'whale_longitude' in params: 390 out.write(" <td>"+str(params['whale_longitude'])+"</td>\n") 391 out.write(" <td>"+str(params['whale_longitude'])+"</td>\n") 392 out.write("<td>degrees</td>\n") 393 out.write("</tr>\n") 394 out.write("\n") 395 out.write("<tr>\n") 396 out.write("<td>whale_latitude</td>\n") 397 out.write("<td>decimal</td>\n") 398 if 'whale_latitude' in params: 399 out.write(" <td>"+str(params['whale_latitude'])+"</td>\n") 400 out.write(" <td>"+str(params['whale_latitude'])+"</td>\n") 401 out.write("<td>degrees</td>\n") 402 out.write("</tr>\n") 403 out.write("\n") 404 out.write("<tr>\n") 405 out.write("<td>timetoexpire</td>\n") 406 out.write("<td>uint</td>\n") 407 if 'timetoexpire' in params: 408 out.write(" <td>"+str(params['timetoexpire'])+"</td>\n") 409 out.write(" <td>"+str(params['timetoexpire'])+"</td>\n") 410 out.write("<td>seconds</td>\n") 411 out.write("</tr>\n") 412 out.write("\n") 413 out.write("<tr>\n") 414 out.write("<td>radius</td>\n") 415 out.write("<td>uint</td>\n") 416 if 'radius' in params: 417 out.write(" <td>"+str(params['radius'])+"</td>\n") 418 out.write(" <td>"+str(params['radius'])+"</td>\n") 419 out.write("<td>m</td>\n") 420 out.write("</tr>\n") 421 out.write("\n") 422 out.write("<tr>\n") 423 out.write("<td>heading</td>\n") 424 out.write("<td>uint</td>\n") 425 if 'heading' in params: 426 out.write(" <td>"+str(params['heading'])+"</td>\n") 427 out.write(" <td>"+str(params['heading'])+"</td>\n") 428 out.write("<td>degrees true north</td>\n") 429 out.write("</tr>\n") 430 out.write("\n") 431 out.write("<tr>\n") 432 out.write("<td>numWhales</td>\n") 433 out.write("<td>uint</td>\n") 434 if 'numWhales' in params: 435 out.write(" <td>"+str(params['numWhales'])+"</td>\n") 436 out.write(" <td>"+str(params['numWhales'])+"</td>\n") 437 out.write("</tr>\n") 438 out.write("</table>\n")
439 440
441 -def printKml(params, out=sys.stdout):
442 '''KML (Keyhole Markup Language) for Google Earth, but without the header/footer''' 443 out.write("\ <Placemark>\n") 444 out.write("\t <name>"+str(params['stationsid'])+"</name>\n") 445 out.write("\t\t<description>\n") 446 import StringIO 447 buf = StringIO.StringIO() 448 printHtml(params,buf) 449 import cgi 450 out.write(cgi.escape(buf.getvalue())) 451 out.write("\t\t</description>\n") 452 out.write("\t\t<styleUrl>#m_ylw-pushpin_copy0</styleUrl>\n") 453 out.write("\t\t<Point>\n") 454 out.write("\t\t\t<coordinates>") 455 out.write(str(params['station_longitude'])) 456 out.write(',') 457 out.write(str(params['station_latitude'])) 458 out.write(",0</coordinates>\n") 459 out.write("\t\t</Point>\n") 460 out.write("\t</Placemark>\n")
461
462 -def printFields(params, out=sys.stdout, format='std', fieldList=None, dbType='postgres'):
463 '''Print a whalenotice message to stdout. 464 465 Fields in params: 466 - dac(uint): Designated Area Code (field automatically set to "366") 467 - fid(uint): Functional Identifier (field automatically set to "1") 468 - efid(uint): extended functional identifier (dac+fid+id defines which message) (field automatically set to "2") 469 - timetag_month(uint): Time whale was last recorded month 1..12 470 - timetag_day(uint): Time whale was last recorded day of the month 1..31 471 - timetag_hour(uint): Time whale was last recorded UTC hours 0..23 472 - timetag_min(uint): Time whale was last recorded minutes 473 - timetag_sec(uint): Time whale was last recorded seconds 474 - stationid(aisstr6): Character identifier of the station. Usually a number. 475 - station_longitude(decimal): Location of the sensor taking the water level measurement or position of prediction East West location 476 - station_latitude(decimal): Location of the sensor taking the water level measurement or position of prediction North South location 477 - whale_longitude(decimal): Where was the whale East West location 478 - whale_latitude(decimal): Where was the whale North South location 479 - timetoexpire(uint): Seconds until this notice expires 480 - radius(uint): Distance of the required exclusion/slow zone 481 - heading(uint): Direction the whale is traveling 482 - numWhales(uint): Number of whales detected 483 @param params: Dictionary of field names/values. 484 @param out: File like object to write to 485 @rtype: stdout 486 @return: text to out 487 ''' 488 489 if 'std'==format: 490 out.write("whalenotice:\n") 491 if 'dac' in params: out.write(" dac: "+str(params['dac'])+"\n") 492 if 'fid' in params: out.write(" fid: "+str(params['fid'])+"\n") 493 if 'efid' in params: out.write(" efid: "+str(params['efid'])+"\n") 494 if 'timetag_month' in params: out.write(" timetag_month: "+str(params['timetag_month'])+"\n") 495 if 'timetag_day' in params: out.write(" timetag_day: "+str(params['timetag_day'])+"\n") 496 if 'timetag_hour' in params: out.write(" timetag_hour: "+str(params['timetag_hour'])+"\n") 497 if 'timetag_min' in params: out.write(" timetag_min: "+str(params['timetag_min'])+"\n") 498 if 'timetag_sec' in params: out.write(" timetag_sec: "+str(params['timetag_sec'])+"\n") 499 if 'stationid' in params: out.write(" stationid: "+str(params['stationid'])+"\n") 500 if 'station_longitude' in params: out.write(" station_longitude: "+str(params['station_longitude'])+"\n") 501 if 'station_latitude' in params: out.write(" station_latitude: "+str(params['station_latitude'])+"\n") 502 if 'whale_longitude' in params: out.write(" whale_longitude: "+str(params['whale_longitude'])+"\n") 503 if 'whale_latitude' in params: out.write(" whale_latitude: "+str(params['whale_latitude'])+"\n") 504 if 'timetoexpire' in params: out.write(" timetoexpire: "+str(params['timetoexpire'])+"\n") 505 if 'radius' in params: out.write(" radius: "+str(params['radius'])+"\n") 506 if 'heading' in params: out.write(" heading: "+str(params['heading'])+"\n") 507 if 'numWhales' in params: out.write(" numWhales: "+str(params['numWhales'])+"\n") 508 elif 'csv'==format: 509 if None == options.fieldList: 510 options.fieldList = fieldList 511 needComma = False; 512 for field in fieldList: 513 if needComma: out.write(',') 514 needComma = True 515 if field in params: 516 out.write(str(params[field])) 517 # else: leave it empty 518 out.write("\n") 519 elif 'html'==format: 520 printHtml(params,out) 521 elif 'sql'==format: 522 sqlInsertStr(params,out,dbType=dbType) 523 elif 'kml'==format: 524 printKml(params,out) 525 elif 'kml-full'==format: 526 out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") 527 out.write("<kml xmlns=\"http://earth.google.com/kml/2.1\">\n") 528 out.write("<Document>\n") 529 out.write(" <name>whalenotice</name>\n") 530 printKml(params,out) 531 out.write("</Document>\n") 532 out.write("</kml>\n") 533 else: 534 print "ERROR: unknown format:",format 535 assert False 536 537 return # Nothing to return
538 539 ###################################################################### 540 # SQL SUPPORT 541 ###################################################################### 542
543 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None 544 ,addCoastGuardFields=True 545 ,dbType='postgres' 546 ):
547 ''' 548 Return the SQL CREATE command for this message type 549 @param outfile: file like object to print to. 550 @param fields: which fields to put in the create. Defaults to all. 551 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 552 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 553 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 554 @type addCoastGuardFields: bool 555 @return: sql create string 556 @rtype: str 557 558 @see: sqlCreate 559 ''' 560 outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType)))
561
562 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'):
563 ''' 564 Return the sqlhelp object to create the table. 565 566 @param fields: which fields to put in the create. Defaults to all. 567 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 568 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 569 @type addCoastGuardFields: bool 570 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 571 @return: An object that can be used to generate a return 572 @rtype: sqlhelp.create 573 ''' 574 if None == fields: fields = fieldList 575 import sqlhelp 576 c = sqlhelp.create('whalenotice',dbType=dbType) 577 c.addPrimaryKey() 578 if 'dac' in fields: c.addInt ('dac') 579 if 'fid' in fields: c.addInt ('fid') 580 if 'efid' in fields: c.addInt ('efid') 581 if 'timetag_month' in fields: c.addInt ('timetag_month') 582 if 'timetag_day' in fields: c.addInt ('timetag_day') 583 if 'timetag_hour' in fields: c.addInt ('timetag_hour') 584 if 'timetag_min' in fields: c.addInt ('timetag_min') 585 if 'timetag_sec' in fields: c.addInt ('timetag_sec') 586 if 'stationid' in fields: c.addVarChar('stationid',7) 587 if 'station_longitude' in fields: c.addDecimal('station_longitude',8,5) 588 if 'station_latitude' in fields: c.addDecimal('station_latitude',8,5) 589 if 'whale_longitude' in fields: c.addDecimal('whale_longitude',8,5) 590 if 'whale_latitude' in fields: c.addDecimal('whale_latitude',8,5) 591 if 'timetoexpire' in fields: c.addInt ('timetoexpire') 592 if 'radius' in fields: c.addInt ('radius') 593 if 'heading' in fields: c.addInt ('heading') 594 if 'numWhales' in fields: c.addInt ('numWhales') 595 596 if addCoastGuardFields: 597 # c.addInt('cg_rssi') # Relative signal strength indicator 598 # c.addInt('cg_d') # dBm receive strength 599 # c.addInt('cg_T') # Receive timestamp from the AIS equipment 600 # c.addInt('cg_S') # Slot received in 601 # c.addVarChar('cg_x',10) # Idonno 602 c.addVarChar('cg_r',15) # Receiver station ID - should usually be an MMSI, but sometimes is a string 603 c.addInt('cg_sec') # UTC seconds since the epoch 604 605 c.addTimestamp('cg_timestamp') # UTC decoded cg_sec - not actually in the data stream 606 607 return c
608
609 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'):
610 ''' 611 Return the SQL INSERT command for this message type 612 @param params: dictionary of values keyed by field name 613 @param outfile: file like object to print to. 614 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields 615 @return: sql create string 616 @rtype: str 617 618 @see: sqlCreate 619 ''' 620 outfile.write(str(sqlInsert(params,extraParams,dbType=dbType)))
621 622
623 -def sqlInsert(params,extraParams=None,dbType='postgres'):
624 ''' 625 Give the SQL INSERT statement 626 @param params: dict keyed by field name of values 627 @param extraParams: any extra fields that you have created beyond the normal ais message fields 628 @rtype: sqlhelp.insert 629 @return: insert class instance 630 @todo: allow optional type checking of params? 631 @warning: this will take invalid keys happily and do what??? 632 ''' 633 import sqlhelp 634 i = sqlhelp.insert('whalenotice',dbType=dbType) 635 636 if dbType=='postgres': 637 finished = [] 638 for key in params: 639 if key in finished: 640 continue 641 642 if key not in toPgFields and key not in fromPgFields: 643 if type(params[key])==Decimal: i.add(key,float(params[key])) 644 else: i.add(key,params[key]) 645 else: 646 if key in fromPgFields: 647 val = params[key] 648 # Had better be a WKT type like POINT(-88.1 30.321) 649 i.addPostGIS(key,val) 650 finished.append(key) 651 else: 652 # Need to construct the type. 653 pgName = toPgFields[key] 654 #valStr='GeomFromText(\''+pgTypes[pgName]+'(' 655 valStr=pgTypes[pgName]+'(' 656 vals = [] 657 for nonPgKey in fromPgFields[pgName]: 658 vals.append(str(params[nonPgKey])) 659 finished.append(nonPgKey) 660 valStr+=' '.join(vals)+')' 661 i.addPostGIS(pgName,valStr) 662 else: 663 for key in params: 664 if type(params[key])==Decimal: i.add(key,float(params[key])) 665 else: i.add(key,params[key]) 666 667 if None != extraParams: 668 for key in extraParams: 669 i.add(key,extraParams[key]) 670 671 return i
672 673 674 ###################################################################### 675 # UNIT TESTING 676 ###################################################################### 677 import unittest
678 -def testParams():
679 '''Return a params file base on the testvalue tags. 680 @rtype: dict 681 @return: params based on testvalue tags 682 ''' 683 params = {} 684 params['dac'] = 366 685 params['fid'] = 1 686 params['efid'] = 2 687 params['timetag_month'] = 2 688 params['timetag_day'] = 28 689 params['timetag_hour'] = 23 690 params['timetag_min'] = 45 691 params['timetag_sec'] = 58 692 params['stationid'] = 'A234567' 693 params['station_longitude'] = Decimal('-122.16328055555556') 694 params['station_latitude'] = Decimal('37.424458333333334') 695 params['whale_longitude'] = Decimal('-122.16328055555556') 696 params['whale_latitude'] = Decimal('37.424458333333334') 697 params['timetoexpire'] = 1 698 params['radius'] = 5000 699 params['heading'] = 35 700 params['numWhales'] = 2 701 702 return params
703
704 -class Testwhalenotice(unittest.TestCase):
705 '''Use testvalue tag text from each type to build test case the whalenotice message'''
706 - def testEncodeDecode(self):
707 708 params = testParams() 709 bits = encode(params) 710 r = decode(bits) 711 712 # Check that each parameter came through ok. 713 self.failUnlessEqual(r['dac'],params['dac']) 714 self.failUnlessEqual(r['fid'],params['fid']) 715 self.failUnlessEqual(r['efid'],params['efid']) 716 self.failUnlessEqual(r['timetag_month'],params['timetag_month']) 717 self.failUnlessEqual(r['timetag_day'],params['timetag_day']) 718 self.failUnlessEqual(r['timetag_hour'],params['timetag_hour']) 719 self.failUnlessEqual(r['timetag_min'],params['timetag_min']) 720 self.failUnlessEqual(r['timetag_sec'],params['timetag_sec']) 721 self.failUnlessEqual(r['stationid'],params['stationid']) 722 self.failUnlessAlmostEqual(r['station_longitude'],params['station_longitude'],5) 723 self.failUnlessAlmostEqual(r['station_latitude'],params['station_latitude'],5) 724 self.failUnlessAlmostEqual(r['whale_longitude'],params['whale_longitude'],5) 725 self.failUnlessAlmostEqual(r['whale_latitude'],params['whale_latitude'],5) 726 self.failUnlessEqual(r['timetoexpire'],params['timetoexpire']) 727 self.failUnlessEqual(r['radius'],params['radius']) 728 self.failUnlessEqual(r['heading'],params['heading']) 729 self.failUnlessEqual(r['numWhales'],params['numWhales'])
730
731 -def addMsgOptions(parser):
732 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true', 733 help='decode a "whalenotice" AIS message') 734 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true', 735 help='encode a "whalenotice" AIS message') 736 parser.add_option('--timetag_month-field', dest='timetag_monthField',metavar='uint',type='int' 737 ,help='Field parameter value [default: %default]') 738 parser.add_option('--timetag_day-field', dest='timetag_dayField',metavar='uint',type='int' 739 ,help='Field parameter value [default: %default]') 740 parser.add_option('--timetag_hour-field', dest='timetag_hourField',metavar='uint',type='int' 741 ,help='Field parameter value [default: %default]') 742 parser.add_option('--timetag_min-field', dest='timetag_minField',metavar='uint',type='int' 743 ,help='Field parameter value [default: %default]') 744 parser.add_option('--timetag_sec-field', dest='timetag_secField',metavar='uint',type='int' 745 ,help='Field parameter value [default: %default]') 746 parser.add_option('--stationid-field', dest='stationidField',default='@@@@@@@',metavar='aisstr6',type='string' 747 ,help='Field parameter value [default: %default]') 748 parser.add_option('--station_longitude-field', dest='station_longitudeField',default=Decimal('181'),metavar='decimal',type='string' 749 ,help='Field parameter value [default: %default]') 750 parser.add_option('--station_latitude-field', dest='station_latitudeField',default=Decimal('91'),metavar='decimal',type='string' 751 ,help='Field parameter value [default: %default]') 752 parser.add_option('--whale_longitude-field', dest='whale_longitudeField',default=Decimal('181'),metavar='decimal',type='string' 753 ,help='Field parameter value [default: %default]') 754 parser.add_option('--whale_latitude-field', dest='whale_latitudeField',default=Decimal('91'),metavar='decimal',type='string' 755 ,help='Field parameter value [default: %default]') 756 parser.add_option('--timetoexpire-field', dest='timetoexpireField',default=0,metavar='uint',type='int' 757 ,help='Field parameter value [default: %default]') 758 parser.add_option('--radius-field', dest='radiusField',default=65534,metavar='uint',type='int' 759 ,help='Field parameter value [default: %default]') 760 parser.add_option('--heading-field', dest='headingField',default=511,metavar='uint',type='int' 761 ,help='Field parameter value [default: %default]') 762 parser.add_option('--numWhales-field', dest='numWhalesField',default=0,metavar='uint',type='int' 763 ,help='Field parameter value [default: %default]')
764 765 ############################################################ 766 if __name__=='__main__': 767 768 from optparse import OptionParser 769 parser = OptionParser(usage="%prog [options]", 770 version="%prog "+__version__) 771 772 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true', 773 help='run the documentation tests') 774 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true', 775 help='run the unit tests') 776 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 777 help='Make the test output verbose') 778 779 # FIX: remove nmea from binary messages. No way to build the whole packet? 780 # FIX: or build the surrounding msg 8 for a broadcast? 781 typeChoices = ('binary','nmeapayload','nmea') # FIX: what about a USCG type message? 782 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType' 783 ,default='nmeapayload' 784 ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]') 785 786 787 outputChoices = ('std','html','csv','sql' , 'kml','kml-full') 788 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType' 789 ,default='std' 790 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]') 791 792 parser.add_option('-o','--output',dest='outputFileName',default=None, 793 help='Name of the python file to write [default: stdout]') 794 795 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append', 796 choices=fieldList, 797 help='Which fields to include in the output. Currently only for csv output [default: all]') 798 799 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true', 800 help='Print the field name for csv') 801 802 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true', 803 help='Print out an sql create command for the table.') 804 805 dbChoices = ('sqlite','postgres') 806 parser.add_option('-D','--db-type',dest='dbType',default='postgres' 807 ,choices=dbChoices,type='choice' 808 ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]') 809 810 addMsgOptions(parser) 811 812 (options,args) = parser.parse_args() 813 success=True 814 815 if options.doctest: 816 import os; print os.path.basename(sys.argv[0]), 'doctests ...', 817 sys.argv= [sys.argv[0]] 818 if options.verbose: sys.argv.append('-v') 819 import doctest 820 numfail,numtests=doctest.testmod() 821 if numfail==0: print 'ok' 822 else: 823 print 'FAILED' 824 success=False 825 826 if not success: sys.exit('Something Failed') 827 del success # Hide success from epydoc 828 829 if options.unittest: 830 sys.argv = [sys.argv[0]] 831 if options.verbose: sys.argv.append('-v') 832 unittest.main() 833 834 outfile = sys.stdout 835 if None!=options.outputFileName: 836 outfile = file(options.outputFileName,'w') 837 838 839 if options.doEncode: 840 # First make sure all non required options are specified 841 if None==options.timetag_monthField: parser.error("missing value for timetag_monthField") 842 if None==options.timetag_dayField: parser.error("missing value for timetag_dayField") 843 if None==options.timetag_hourField: parser.error("missing value for timetag_hourField") 844 if None==options.timetag_minField: parser.error("missing value for timetag_minField") 845 if None==options.timetag_secField: parser.error("missing value for timetag_secField") 846 if None==options.stationidField: parser.error("missing value for stationidField") 847 if None==options.station_longitudeField: parser.error("missing value for station_longitudeField") 848 if None==options.station_latitudeField: parser.error("missing value for station_latitudeField") 849 if None==options.whale_longitudeField: parser.error("missing value for whale_longitudeField") 850 if None==options.whale_latitudeField: parser.error("missing value for whale_latitudeField") 851 if None==options.timetoexpireField: parser.error("missing value for timetoexpireField") 852 if None==options.radiusField: parser.error("missing value for radiusField") 853 if None==options.headingField: parser.error("missing value for headingField") 854 if None==options.numWhalesField: parser.error("missing value for numWhalesField") 855 msgDict={ 856 'dac': '366', 857 'fid': '1', 858 'efid': '2', 859 'timetag_month': options.timetag_monthField, 860 'timetag_day': options.timetag_dayField, 861 'timetag_hour': options.timetag_hourField, 862 'timetag_min': options.timetag_minField, 863 'timetag_sec': options.timetag_secField, 864 'stationid': options.stationidField, 865 'station_longitude': options.station_longitudeField, 866 'station_latitude': options.station_latitudeField, 867 'whale_longitude': options.whale_longitudeField, 868 'whale_latitude': options.whale_latitudeField, 869 'timetoexpire': options.timetoexpireField, 870 'radius': options.radiusField, 871 'heading': options.headingField, 872 'numWhales': options.numWhalesField, 873 } 874 875 bits = encode(msgDict) 876 if 'binary'==options.ioType: print str(bits) 877 elif 'nmeapayload'==options.ioType: 878 # FIX: figure out if this might be necessary at compile time 879 print "bitLen",len(bits) 880 bitLen=len(bits) 881 if bitLen%6!=0: 882 bits = bits + BitVector(size=(6 - (bitLen%6))) # Pad out to multiple of 6 883 print "result:",binary.bitvectoais6(bits)[0] 884 885 886 # FIX: Do not emit this option for the binary message payloads. Does not make sense. 887 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability") 888 else: sys.exit('ERROR: unknown ioType. Help!') 889 890 891 if options.sqlCreate: 892 sqlCreateStr(outfile,options.fieldList,dbType=options.dbType) 893 894 if options.printCsvfieldList: 895 # Make a csv separated list of fields that will be displayed for csv 896 if None == options.fieldList: options.fieldList = fieldList 897 import StringIO 898 buf = StringIO.StringIO() 899 for field in options.fieldList: 900 buf.write(field+',') 901 result = buf.getvalue() 902 if result[-1] == ',': print result[:-1] 903 else: print result 904 905 if options.doDecode: 906 for msg in args: 907 bv = None 908 909 if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'): 910 # Found nmea 911 # FIX: do checksum 912 bv = binary.ais6tobitvec(msg.split(',')[5]) 913 else: # either binary or nmeapayload... expect mostly nmeapayloads 914 # assumes that an all 0 and 1 string can not be a nmeapayload 915 binaryMsg=True 916 for c in msg: 917 if c not in ('0','1'): 918 binaryMsg=False 919 break 920 if binaryMsg: 921 bv = BitVector(bitstring=msg) 922 else: # nmeapayload 923 bv = binary.ais6tobitvec(msg) 924 925 printFields(decode(bv) 926 ,out=outfile 927 ,format=options.outputType 928 ,fieldList=options.fieldList 929 ,dbType=options.dbType 930 ) 931