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-16 $'.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 numWhales 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("numWhales:\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 #print 'already did key',key 641 continue 642 643 if key not in toPgFields and key not in fromPgFields: 644 if type(params[key])==Decimal: i.add(key,float(params[key])) 645 else: i.add(key,params[key]) 646 else: 647 if key in fromPgFields: 648 val = params[key] 649 # Had better be a WKT type like POINT(-88.1 30.321) 650 i.addPostGIS(key,val) 651 finished.append(key) 652 else: 653 # Need to construct the type. 654 pgName = toPgFields[key] 655 #valStr='GeomFromText(\''+pgTypes[pgName]+'(' 656 valStr=pgTypes[pgName]+'(' 657 vals = [] 658 for nonPgKey in fromPgFields[pgName]: 659 vals.append(str(params[nonPgKey])) 660 finished.append(nonPgKey) 661 valStr+=' '.join(vals)+')' 662 i.addPostGIS(pgName,valStr) 663 else: 664 for key in params: 665 if type(params[key])==Decimal: i.add(key,float(params[key])) 666 else: i.add(key,params[key]) 667 668 if None != extraParams: 669 for key in extraParams: 670 i.add(key,extraParams[key]) 671 672 return i
673 674 675 ###################################################################### 676 # UNIT TESTING 677 ###################################################################### 678 import unittest
679 -def testParams():
680 '''Return a params file base on the testvalue tags. 681 @rtype: dict 682 @return: params based on testvalue tags 683 ''' 684 params = {} 685 params['dac'] = 366 686 params['fid'] = 1 687 params['efid'] = 2 688 params['timetag_month'] = 2 689 params['timetag_day'] = 28 690 params['timetag_hour'] = 23 691 params['timetag_min'] = 45 692 params['timetag_sec'] = 58 693 params['stationid'] = 'A234567' 694 params['station_longitude'] = Decimal('-122.16328055555556') 695 params['station_latitude'] = Decimal('37.424458333333334') 696 params['whale_longitude'] = Decimal('-122.16328055555556') 697 params['whale_latitude'] = Decimal('37.424458333333334') 698 params['timetoexpire'] = 1 699 params['radius'] = 5000 700 params['heading'] = 35 701 params['numWhales'] = 2 702 703 return params
704
705 -class Testwhalenotice(unittest.TestCase):
706 '''Use testvalue tag text from each type to build test case the whalenotice message'''
707 - def testEncodeDecode(self):
708 709 params = testParams() 710 bits = encode(params) 711 r = decode(bits) 712 713 # Check that each parameter came through ok. 714 self.failUnlessEqual(r['dac'],params['dac']) 715 self.failUnlessEqual(r['fid'],params['fid']) 716 self.failUnlessEqual(r['efid'],params['efid']) 717 self.failUnlessEqual(r['timetag_month'],params['timetag_month']) 718 self.failUnlessEqual(r['timetag_day'],params['timetag_day']) 719 self.failUnlessEqual(r['timetag_hour'],params['timetag_hour']) 720 self.failUnlessEqual(r['timetag_min'],params['timetag_min']) 721 self.failUnlessEqual(r['timetag_sec'],params['timetag_sec']) 722 self.failUnlessEqual(r['stationid'],params['stationid']) 723 self.failUnlessAlmostEqual(r['station_longitude'],params['station_longitude'],5) 724 self.failUnlessAlmostEqual(r['station_latitude'],params['station_latitude'],5) 725 self.failUnlessAlmostEqual(r['whale_longitude'],params['whale_longitude'],5) 726 self.failUnlessAlmostEqual(r['whale_latitude'],params['whale_latitude'],5) 727 self.failUnlessEqual(r['timetoexpire'],params['timetoexpire']) 728 self.failUnlessEqual(r['radius'],params['radius']) 729 self.failUnlessEqual(r['heading'],params['heading']) 730 self.failUnlessEqual(r['numWhales'],params['numWhales'])
731
732 -def addMsgOptions(parser):
733 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true', 734 help='decode a "whalenotice" AIS message') 735 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true', 736 help='encode a "whalenotice" AIS message') 737 parser.add_option('--timetag_month-field', dest='timetag_monthField',metavar='uint',type='int' 738 ,help='Field parameter value [default: %default]') 739 parser.add_option('--timetag_day-field', dest='timetag_dayField',metavar='uint',type='int' 740 ,help='Field parameter value [default: %default]') 741 parser.add_option('--timetag_hour-field', dest='timetag_hourField',metavar='uint',type='int' 742 ,help='Field parameter value [default: %default]') 743 parser.add_option('--timetag_min-field', dest='timetag_minField',metavar='uint',type='int' 744 ,help='Field parameter value [default: %default]') 745 parser.add_option('--timetag_sec-field', dest='timetag_secField',metavar='uint',type='int' 746 ,help='Field parameter value [default: %default]') 747 parser.add_option('--stationid-field', dest='stationidField',default='@@@@@@@',metavar='aisstr6',type='string' 748 ,help='Field parameter value [default: %default]') 749 parser.add_option('--station_longitude-field', dest='station_longitudeField',default=Decimal('181'),metavar='decimal',type='string' 750 ,help='Field parameter value [default: %default]') 751 parser.add_option('--station_latitude-field', dest='station_latitudeField',default=Decimal('91'),metavar='decimal',type='string' 752 ,help='Field parameter value [default: %default]') 753 parser.add_option('--whale_longitude-field', dest='whale_longitudeField',default=Decimal('181'),metavar='decimal',type='string' 754 ,help='Field parameter value [default: %default]') 755 parser.add_option('--whale_latitude-field', dest='whale_latitudeField',default=Decimal('91'),metavar='decimal',type='string' 756 ,help='Field parameter value [default: %default]') 757 parser.add_option('--timetoexpire-field', dest='timetoexpireField',default=0,metavar='uint',type='int' 758 ,help='Field parameter value [default: %default]') 759 parser.add_option('--radius-field', dest='radiusField',default=65534,metavar='uint',type='int' 760 ,help='Field parameter value [default: %default]') 761 parser.add_option('--heading-field', dest='headingField',default=511,metavar='uint',type='int' 762 ,help='Field parameter value [default: %default]') 763 parser.add_option('--numWhales-field', dest='numWhalesField',default=0,metavar='uint',type='int' 764 ,help='Field parameter value [default: %default]')
765 766 ############################################################ 767 if __name__=='__main__': 768 769 from optparse import OptionParser 770 parser = OptionParser(usage="%prog [options]", 771 version="%prog "+__version__) 772 773 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true', 774 help='run the documentation tests') 775 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true', 776 help='run the unit tests') 777 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 778 help='Make the test output verbose') 779 780 # FIX: remove nmea from binary messages. No way to build the whole packet? 781 # FIX: or build the surrounding msg 8 for a broadcast? 782 typeChoices = ('binary','nmeapayload','nmea') # FIX: what about a USCG type message? 783 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType' 784 ,default='nmeapayload' 785 ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]') 786 787 788 outputChoices = ('std','html','csv','sql' , 'kml','kml-full') 789 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType' 790 ,default='std' 791 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]') 792 793 parser.add_option('-o','--output',dest='outputFileName',default=None, 794 help='Name of the python file to write [default: stdout]') 795 796 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append', 797 choices=fieldList, 798 help='Which fields to include in the output. Currently only for csv output [default: all]') 799 800 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true', 801 help='Print the field name for csv') 802 803 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true', 804 help='Print out an sql create command for the table.') 805 806 dbChoices = ('sqlite','postgres') 807 parser.add_option('-D','--db-type',dest='dbType',default='postgres' 808 ,choices=dbChoices,type='choice' 809 ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]') 810 811 addMsgOptions(parser) 812 813 (options,args) = parser.parse_args() 814 success=True 815 816 if options.doctest: 817 import os; print os.path.basename(sys.argv[0]), 'doctests ...', 818 sys.argv= [sys.argv[0]] 819 if options.verbose: sys.argv.append('-v') 820 import doctest 821 numfail,numtests=doctest.testmod() 822 if numfail==0: print 'ok' 823 else: 824 print 'FAILED' 825 success=False 826 827 if not success: sys.exit('Something Failed') 828 del success # Hide success from epydoc 829 830 if options.unittest: 831 sys.argv = [sys.argv[0]] 832 if options.verbose: sys.argv.append('-v') 833 unittest.main() 834 835 outfile = sys.stdout 836 if None!=options.outputFileName: 837 outfile = file(options.outputFileName,'w') 838 839 840 if options.doEncode: 841 # First make sure all non required options are specified 842 if None==options.timetag_monthField: parser.error("missing value for timetag_monthField") 843 if None==options.timetag_dayField: parser.error("missing value for timetag_dayField") 844 if None==options.timetag_hourField: parser.error("missing value for timetag_hourField") 845 if None==options.timetag_minField: parser.error("missing value for timetag_minField") 846 if None==options.timetag_secField: parser.error("missing value for timetag_secField") 847 if None==options.stationidField: parser.error("missing value for stationidField") 848 if None==options.station_longitudeField: parser.error("missing value for station_longitudeField") 849 if None==options.station_latitudeField: parser.error("missing value for station_latitudeField") 850 if None==options.whale_longitudeField: parser.error("missing value for whale_longitudeField") 851 if None==options.whale_latitudeField: parser.error("missing value for whale_latitudeField") 852 if None==options.timetoexpireField: parser.error("missing value for timetoexpireField") 853 if None==options.radiusField: parser.error("missing value for radiusField") 854 if None==options.headingField: parser.error("missing value for headingField") 855 if None==options.numWhalesField: parser.error("missing value for numWhalesField") 856 msgDict={ 857 'dac': '366', 858 'fid': '1', 859 'efid': '2', 860 'timetag_month': options.timetag_monthField, 861 'timetag_day': options.timetag_dayField, 862 'timetag_hour': options.timetag_hourField, 863 'timetag_min': options.timetag_minField, 864 'timetag_sec': options.timetag_secField, 865 'stationid': options.stationidField, 866 'station_longitude': options.station_longitudeField, 867 'station_latitude': options.station_latitudeField, 868 'whale_longitude': options.whale_longitudeField, 869 'whale_latitude': options.whale_latitudeField, 870 'timetoexpire': options.timetoexpireField, 871 'radius': options.radiusField, 872 'heading': options.headingField, 873 'numWhales': options.numWhalesField, 874 } 875 876 bits = encode(msgDict) 877 if 'binary'==options.ioType: print str(bits) 878 elif 'nmeapayload'==options.ioType: 879 # FIX: figure out if this might be necessary at compile time 880 print "bitLen",len(bits) 881 bitLen=len(bits) 882 if bitLen%6!=0: 883 bits = bits + BitVector(size=(6 - (bitLen%6))) # Pad out to multiple of 6 884 print "result:",binary.bitvectoais6(bits)[0] 885 886 887 # FIX: Do not emit this option for the binary message payloads. Does not make sense. 888 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability") 889 else: sys.exit('ERROR: unknown ioType. Help!') 890 891 892 if options.sqlCreate: 893 sqlCreateStr(outfile,options.fieldList,dbType=options.dbType) 894 895 if options.printCsvfieldList: 896 # Make a csv separated list of fields that will be displayed for csv 897 if None == options.fieldList: options.fieldList = fieldList 898 import StringIO 899 buf = StringIO.StringIO() 900 for field in options.fieldList: 901 buf.write(field+',') 902 result = buf.getvalue() 903 if result[-1] == ',': print result[:-1] 904 else: print result 905 906 if options.doDecode: 907 for msg in args: 908 bv = None 909 910 if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'): 911 # Found nmea 912 # FIX: do checksum 913 bv = binary.ais6tobitvec(msg.split(',')[5]) 914 else: # either binary or nmeapayload... expect mostly nmeapayloads 915 # assumes that an all 0 and 1 string can not be a nmeapayload 916 binaryMsg=True 917 for c in msg: 918 if c not in ('0','1'): 919 binaryMsg=False 920 break 921 if binaryMsg: 922 bv = BitVector(bitstring=msg) 923 else: # nmeapayload 924 bv = binary.ais6tobitvec(msg) 925 926 printFields(decode(bv) 927 ,out=outfile 928 ,format=options.outputType 929 ,fieldList=options.fieldList 930 ,dbType=options.dbType 931 ) 932