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

Source Code for Module ais.waterlevel

   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          'efid', 
  57          'month', 
  58          'day', 
  59          'hour', 
  60          'min', 
  61          'sec', 
  62          'stationid', 
  63          'longitude', 
  64          'latitude', 
  65          'waterlevel', 
  66          'datum', 
  67          'sigma', 
  68          'o', 
  69          'levelinferred', 
  70          'flat_tolerance_exceeded', 
  71          'rate_tolerance_exceeded', 
  72          'temp_tolerance_exceeded', 
  73          'expected_height_exceeded', 
  74          'link_down', 
  75          'timeLastMeasured', 
  76  ) 
  77   
  78  fieldListPostgres = ( 
  79          'MessageID', 
  80          'RepeatIndicator', 
  81          'UserID', 
  82          'Spare', 
  83          'dac', 
  84          'fid', 
  85          'efid', 
  86          'month', 
  87          'day', 
  88          'hour', 
  89          'min', 
  90          'sec', 
  91          'stationid', 
  92          'stationloc',   # PostGIS data type 
  93          'waterlevel', 
  94          'datum', 
  95          'sigma', 
  96          'o', 
  97          'levelinferred', 
  98          'flat_tolerance_exceeded', 
  99          'rate_tolerance_exceeded', 
 100          'temp_tolerance_exceeded', 
 101          'expected_height_exceeded', 
 102          'link_down', 
 103          'timeLastMeasured', 
 104  ) 
 105   
 106  toPgFields = { 
 107          'longitude':'stationloc', 
 108          'latitude':'stationloc', 
 109  } 
 110  ''' 
 111  Go to the Postgis field names from the straight field name 
 112  ''' 
 113   
 114  fromPgFields = { 
 115          'stationloc':('longitude','latitude',), 
 116  } 
 117  ''' 
 118  Go from the Postgis field names to the straight field name 
 119  ''' 
 120   
 121  pgTypes = { 
 122          'stationloc':'POINT', 
 123  } 
 124  ''' 
 125  Lookup table for each postgis field name to get its type. 
 126  ''' 
 127   
128 -def encode(params, validate=False):
129 '''Create a waterlevel binary message payload to pack into an AIS Msg waterlevel. 130 131 Fields in params: 132 - MessageID(uint): AIS message number. Must be 8 (field automatically set to "8") 133 - RepeatIndicator(uint): Indicated how many times a message has been repeated 134 - UserID(uint): Unique ship identification number (MMSI) 135 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0") 136 - dac(uint): Designated Area Code (field automatically set to "366") 137 - fid(uint): Functional Identifier (field automatically set to "63") 138 - efid(uint): extended functional identifier (field automatically set to "2") 139 - month(uint): Time the measurement represents month 1..12 140 - day(uint): Time the measurement represents day of the month 1..31 141 - hour(uint): Time the measurement represents UTC hours 0..23 142 - min(uint): Time the measurement represents minutes 143 - sec(uint): Time the measurement represents seconds 144 - stationid(aisstr6): Character identifier of the station. Usually a number. 145 - longitude(decimal): Location of the sensor taking the water level measurement or position of prediction. East West location 146 - latitude(decimal): Location of the sensor taking the water level measurement or position of prediction. North South location 147 - waterlevel(int): Water level in centimeters 148 - datum(uint): What reference datum applies to the value 149 - sigma(float): Standard deviation of 1 second samples used to compute the water level height 150 - o(uint): Count of number of samples that fall outside a 3-sigma band about the mean 151 - levelinferred(bool): indicates that the water level value has been inferred 152 - flat_tolerance_exceeded(bool): flat tolerance limit was exceeded. Need better descr 153 - rate_tolerance_exceeded(bool): rate of change tolerance limit was exceeded 154 - temp_tolerance_exceeded(bool): temperature difference tolerance limit was exceeded 155 - expected_height_exceeded(bool): either the maximum or minimum expected water level height limit was exceeded 156 - link_down(bool): Unable to communicate with the tide system. All data invalid 157 - timeLastMeasured(udecimal): Time relative since the timetag that the station actually measured a value. 158 @param params: Dictionary of field names/values. Throws a ValueError exception if required is missing 159 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 160 @rtype: BitVector 161 @return: encoded binary message (for binary messages, this needs to be wrapped in a msg 8 162 @note: The returned bits may not be 6 bit aligned. It is up to you to pad out the bits. 163 ''' 164 165 bvList = [] 166 bvList.append(binary.setBitVectorSize(BitVector(intVal=8),6)) 167 if 'RepeatIndicator' in params: 168 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['RepeatIndicator']),2)) 169 else: 170 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2)) 171 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['UserID']),30)) 172 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2)) 173 bvList.append(binary.setBitVectorSize(BitVector(intVal=366),10)) 174 bvList.append(binary.setBitVectorSize(BitVector(intVal=63),6)) 175 bvList.append(binary.setBitVectorSize(BitVector(intVal=2),12)) 176 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['month']),4)) 177 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['day']),5)) 178 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['hour']),5)) 179 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['min']),6)) 180 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['sec']),6)) 181 if 'stationid' in params: 182 bvList.append(aisstring.encode(params['stationid'],42)) 183 else: 184 bvList.append(aisstring.encode('@@@@@@@',42)) 185 if 'longitude' in params: 186 bvList.append(binary.bvFromSignedInt(int(Decimal(params['longitude'])*Decimal('600000')),28)) 187 else: 188 bvList.append(binary.bvFromSignedInt(108600000,28)) 189 if 'latitude' in params: 190 bvList.append(binary.bvFromSignedInt(int(Decimal(params['latitude'])*Decimal('600000')),27)) 191 else: 192 bvList.append(binary.bvFromSignedInt(54600000,27)) 193 if 'waterlevel' in params: 194 bvList.append(binary.bvFromSignedInt(params['waterlevel'],16)) 195 else: 196 bvList.append(binary.bvFromSignedInt(-32768,16)) 197 if 'datum' in params: 198 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['datum']),5)) 199 else: 200 bvList.append(binary.setBitVectorSize(BitVector(intVal=31),5)) 201 bvList.append(binary.float2bitvec(params['sigma'])) 202 if 'o' in params: 203 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['o']),8)) 204 else: 205 bvList.append(binary.setBitVectorSize(BitVector(intVal=255),8)) 206 if params["levelinferred"]: bvList.append(TrueBV) 207 else: bvList.append(FalseBV) 208 if params["flat_tolerance_exceeded"]: bvList.append(TrueBV) 209 else: bvList.append(FalseBV) 210 if params["rate_tolerance_exceeded"]: bvList.append(TrueBV) 211 else: bvList.append(FalseBV) 212 if params["temp_tolerance_exceeded"]: bvList.append(TrueBV) 213 else: bvList.append(FalseBV) 214 if params["expected_height_exceeded"]: bvList.append(TrueBV) 215 else: bvList.append(FalseBV) 216 if params["link_down"]: bvList.append(TrueBV) 217 else: bvList.append(FalseBV) 218 if 'timeLastMeasured' in params: 219 bvList.append(binary.setBitVectorSize(BitVector(intVal=int((Decimal(params['timeLastMeasured'])*Decimal('10')))),12)) 220 else: 221 bvList.append(binary.setBitVectorSize(BitVector(intVal=int(4096)),12)) 222 223 return binary.joinBV(bvList)
224
225 -def decode(bv, validate=False):
226 '''Unpack a waterlevel message 227 228 Fields in params: 229 - MessageID(uint): AIS message number. Must be 8 (field automatically set to "8") 230 - RepeatIndicator(uint): Indicated how many times a message has been repeated 231 - UserID(uint): Unique ship identification number (MMSI) 232 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0") 233 - dac(uint): Designated Area Code (field automatically set to "366") 234 - fid(uint): Functional Identifier (field automatically set to "63") 235 - efid(uint): extended functional identifier (field automatically set to "2") 236 - month(uint): Time the measurement represents month 1..12 237 - day(uint): Time the measurement represents day of the month 1..31 238 - hour(uint): Time the measurement represents UTC hours 0..23 239 - min(uint): Time the measurement represents minutes 240 - sec(uint): Time the measurement represents seconds 241 - stationid(aisstr6): Character identifier of the station. Usually a number. 242 - longitude(decimal): Location of the sensor taking the water level measurement or position of prediction. East West location 243 - latitude(decimal): Location of the sensor taking the water level measurement or position of prediction. North South location 244 - waterlevel(int): Water level in centimeters 245 - datum(uint): What reference datum applies to the value 246 - sigma(float): Standard deviation of 1 second samples used to compute the water level height 247 - o(uint): Count of number of samples that fall outside a 3-sigma band about the mean 248 - levelinferred(bool): indicates that the water level value has been inferred 249 - flat_tolerance_exceeded(bool): flat tolerance limit was exceeded. Need better descr 250 - rate_tolerance_exceeded(bool): rate of change tolerance limit was exceeded 251 - temp_tolerance_exceeded(bool): temperature difference tolerance limit was exceeded 252 - expected_height_exceeded(bool): either the maximum or minimum expected water level height limit was exceeded 253 - link_down(bool): Unable to communicate with the tide system. All data invalid 254 - timeLastMeasured(udecimal): Time relative since the timetag that the station actually measured a value. 255 @type bv: BitVector 256 @param bv: Bits defining a message 257 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 258 @rtype: dict 259 @return: params 260 ''' 261 262 #Would be nice to check the bit count here.. 263 #if validate: 264 # assert (len(bv)==FIX: SOME NUMBER) 265 r = {} 266 r['MessageID']=8 267 r['RepeatIndicator']=int(bv[6:8]) 268 r['UserID']=int(bv[8:38]) 269 r['Spare']=0 270 r['dac']=366 271 r['fid']=63 272 r['efid']=2 273 r['month']=int(bv[68:72]) 274 r['day']=int(bv[72:77]) 275 r['hour']=int(bv[77:82]) 276 r['min']=int(bv[82:88]) 277 r['sec']=int(bv[88:94]) 278 r['stationid']=aisstring.decode(bv[94:136]) 279 r['longitude']=Decimal(binary.signedIntFromBV(bv[136:164]))/Decimal('600000') 280 r['latitude']=Decimal(binary.signedIntFromBV(bv[164:191]))/Decimal('600000') 281 r['waterlevel']=binary.signedIntFromBV(bv[191:207]) 282 r['datum']=int(bv[207:212]) 283 r['sigma']=binary.bitvec2float(bv[212:244]) 284 r['o']=int(bv[244:252]) 285 r['levelinferred']=bool(int(bv[252:253])) 286 r['flat_tolerance_exceeded']=bool(int(bv[253:254])) 287 r['rate_tolerance_exceeded']=bool(int(bv[254:255])) 288 r['temp_tolerance_exceeded']=bool(int(bv[255:256])) 289 r['expected_height_exceeded']=bool(int(bv[256:257])) 290 r['link_down']=bool(int(bv[257:258])) 291 r['timeLastMeasured']=Decimal(int(bv[258:270]))/Decimal('10') 292 return r
293
294 -def decodeMessageID(bv, validate=False):
295 return 8
296
297 -def decodeRepeatIndicator(bv, validate=False):
298 return int(bv[6:8])
299
300 -def decodeUserID(bv, validate=False):
301 return int(bv[8:38])
302
303 -def decodeSpare(bv, validate=False):
304 return 0
305
306 -def decodedac(bv, validate=False):
307 return 366
308
309 -def decodefid(bv, validate=False):
310 return 63
311
312 -def decodeefid(bv, validate=False):
313 return 2
314
315 -def decodemonth(bv, validate=False):
316 return int(bv[68:72])
317
318 -def decodeday(bv, validate=False):
319 return int(bv[72:77])
320
321 -def decodehour(bv, validate=False):
322 return int(bv[77:82])
323
324 -def decodemin(bv, validate=False):
325 return int(bv[82:88])
326
327 -def decodesec(bv, validate=False):
328 return int(bv[88:94])
329
330 -def decodestationid(bv, validate=False):
331 return aisstring.decode(bv[94:136])
332
333 -def decodelongitude(bv, validate=False):
334 return Decimal(binary.signedIntFromBV(bv[136:164]))/Decimal('600000')
335
336 -def decodelatitude(bv, validate=False):
337 return Decimal(binary.signedIntFromBV(bv[164:191]))/Decimal('600000')
338
339 -def decodewaterlevel(bv, validate=False):
340 return binary.signedIntFromBV(bv[191:207])
341
342 -def decodedatum(bv, validate=False):
343 return int(bv[207:212])
344
345 -def decodesigma(bv, validate=False):
346 return binary.bitvec2float(bv[212:244])
347
348 -def decodeo(bv, validate=False):
349 return int(bv[244:252])
350
351 -def decodelevelinferred(bv, validate=False):
352 return bool(int(bv[252:253]))
353
354 -def decodeflat_tolerance_exceeded(bv, validate=False):
355 return bool(int(bv[253:254]))
356
357 -def decoderate_tolerance_exceeded(bv, validate=False):
358 return bool(int(bv[254:255]))
359
360 -def decodetemp_tolerance_exceeded(bv, validate=False):
361 return bool(int(bv[255:256]))
362
363 -def decodeexpected_height_exceeded(bv, validate=False):
364 return bool(int(bv[256:257]))
365 368
369 -def decodetimeLastMeasured(bv, validate=False):
370 return Decimal(int(bv[258:270]))/Decimal('10')
371 372
373 -def printHtml(params, out=sys.stdout):
374 out.write("<h3>waterlevel</h3>\n") 375 out.write("<table border=\"1\">\n") 376 out.write("<tr bgcolor=\"orange\">\n") 377 out.write("<th align=\"left\">Field Name</th>\n") 378 out.write("<th align=\"left\">Type</th>\n") 379 out.write("<th align=\"left\">Value</th>\n") 380 out.write("<th align=\"left\">Value in Lookup Table</th>\n") 381 out.write("<th align=\"left\">Units</th>\n") 382 out.write("\n") 383 out.write("<tr>\n") 384 out.write("<td>MessageID</td>\n") 385 out.write("<td>uint</td>\n") 386 if 'MessageID' in params: 387 out.write(" <td>"+str(params['MessageID'])+"</td>\n") 388 out.write(" <td>"+str(params['MessageID'])+"</td>\n") 389 out.write("</tr>\n") 390 out.write("\n") 391 out.write("<tr>\n") 392 out.write("<td>RepeatIndicator</td>\n") 393 out.write("<td>uint</td>\n") 394 if 'RepeatIndicator' in params: 395 out.write(" <td>"+str(params['RepeatIndicator'])+"</td>\n") 396 if str(params['RepeatIndicator']) in RepeatIndicatorDecodeLut: 397 out.write("<td>"+RepeatIndicatorDecodeLut[str(params['RepeatIndicator'])]+"</td>") 398 else: 399 out.write("<td><i>Missing LUT entry</i></td>") 400 out.write("</tr>\n") 401 out.write("\n") 402 out.write("<tr>\n") 403 out.write("<td>UserID</td>\n") 404 out.write("<td>uint</td>\n") 405 if 'UserID' in params: 406 out.write(" <td>"+str(params['UserID'])+"</td>\n") 407 out.write(" <td>"+str(params['UserID'])+"</td>\n") 408 out.write("</tr>\n") 409 out.write("\n") 410 out.write("<tr>\n") 411 out.write("<td>Spare</td>\n") 412 out.write("<td>uint</td>\n") 413 if 'Spare' in params: 414 out.write(" <td>"+str(params['Spare'])+"</td>\n") 415 out.write(" <td>"+str(params['Spare'])+"</td>\n") 416 out.write("</tr>\n") 417 out.write("\n") 418 out.write("<tr>\n") 419 out.write("<td>dac</td>\n") 420 out.write("<td>uint</td>\n") 421 if 'dac' in params: 422 out.write(" <td>"+str(params['dac'])+"</td>\n") 423 out.write(" <td>"+str(params['dac'])+"</td>\n") 424 out.write("</tr>\n") 425 out.write("\n") 426 out.write("<tr>\n") 427 out.write("<td>fid</td>\n") 428 out.write("<td>uint</td>\n") 429 if 'fid' in params: 430 out.write(" <td>"+str(params['fid'])+"</td>\n") 431 out.write(" <td>"+str(params['fid'])+"</td>\n") 432 out.write("</tr>\n") 433 out.write("\n") 434 out.write("<tr>\n") 435 out.write("<td>efid</td>\n") 436 out.write("<td>uint</td>\n") 437 if 'efid' in params: 438 out.write(" <td>"+str(params['efid'])+"</td>\n") 439 out.write(" <td>"+str(params['efid'])+"</td>\n") 440 out.write("</tr>\n") 441 out.write("\n") 442 out.write("<tr>\n") 443 out.write("<td>month</td>\n") 444 out.write("<td>uint</td>\n") 445 if 'month' in params: 446 out.write(" <td>"+str(params['month'])+"</td>\n") 447 out.write(" <td>"+str(params['month'])+"</td>\n") 448 out.write("</tr>\n") 449 out.write("\n") 450 out.write("<tr>\n") 451 out.write("<td>day</td>\n") 452 out.write("<td>uint</td>\n") 453 if 'day' in params: 454 out.write(" <td>"+str(params['day'])+"</td>\n") 455 out.write(" <td>"+str(params['day'])+"</td>\n") 456 out.write("</tr>\n") 457 out.write("\n") 458 out.write("<tr>\n") 459 out.write("<td>hour</td>\n") 460 out.write("<td>uint</td>\n") 461 if 'hour' in params: 462 out.write(" <td>"+str(params['hour'])+"</td>\n") 463 out.write(" <td>"+str(params['hour'])+"</td>\n") 464 out.write("</tr>\n") 465 out.write("\n") 466 out.write("<tr>\n") 467 out.write("<td>min</td>\n") 468 out.write("<td>uint</td>\n") 469 if 'min' in params: 470 out.write(" <td>"+str(params['min'])+"</td>\n") 471 out.write(" <td>"+str(params['min'])+"</td>\n") 472 out.write("</tr>\n") 473 out.write("\n") 474 out.write("<tr>\n") 475 out.write("<td>sec</td>\n") 476 out.write("<td>uint</td>\n") 477 if 'sec' in params: 478 out.write(" <td>"+str(params['sec'])+"</td>\n") 479 out.write(" <td>"+str(params['sec'])+"</td>\n") 480 out.write("</tr>\n") 481 out.write("\n") 482 out.write("<tr>\n") 483 out.write("<td>stationid</td>\n") 484 out.write("<td>aisstr6</td>\n") 485 if 'stationid' in params: 486 out.write(" <td>"+str(params['stationid'])+"</td>\n") 487 out.write(" <td>"+str(params['stationid'])+"</td>\n") 488 out.write("</tr>\n") 489 out.write("\n") 490 out.write("<tr>\n") 491 out.write("<td>longitude</td>\n") 492 out.write("<td>decimal</td>\n") 493 if 'longitude' in params: 494 out.write(" <td>"+str(params['longitude'])+"</td>\n") 495 out.write(" <td>"+str(params['longitude'])+"</td>\n") 496 out.write("<td>degrees</td>\n") 497 out.write("</tr>\n") 498 out.write("\n") 499 out.write("<tr>\n") 500 out.write("<td>latitude</td>\n") 501 out.write("<td>decimal</td>\n") 502 if 'latitude' in params: 503 out.write(" <td>"+str(params['latitude'])+"</td>\n") 504 out.write(" <td>"+str(params['latitude'])+"</td>\n") 505 out.write("<td>degrees</td>\n") 506 out.write("</tr>\n") 507 out.write("\n") 508 out.write("<tr>\n") 509 out.write("<td>waterlevel</td>\n") 510 out.write("<td>int</td>\n") 511 if 'waterlevel' in params: 512 out.write(" <td>"+str(params['waterlevel'])+"</td>\n") 513 out.write(" <td>"+str(params['waterlevel'])+"</td>\n") 514 out.write("<td>cm</td>\n") 515 out.write("</tr>\n") 516 out.write("\n") 517 out.write("<tr>\n") 518 out.write("<td>datum</td>\n") 519 out.write("<td>uint</td>\n") 520 if 'datum' in params: 521 out.write(" <td>"+str(params['datum'])+"</td>\n") 522 if str(params['datum']) in datumDecodeLut: 523 out.write("<td>"+datumDecodeLut[str(params['datum'])]+"</td>") 524 else: 525 out.write("<td><i>Missing LUT entry</i></td>") 526 out.write("</tr>\n") 527 out.write("\n") 528 out.write("<tr>\n") 529 out.write("<td>sigma</td>\n") 530 out.write("<td>float</td>\n") 531 if 'sigma' in params: 532 out.write(" <td>"+str(params['sigma'])+"</td>\n") 533 out.write(" <td>"+str(params['sigma'])+"</td>\n") 534 out.write("<td>m</td>\n") 535 out.write("</tr>\n") 536 out.write("\n") 537 out.write("<tr>\n") 538 out.write("<td>o</td>\n") 539 out.write("<td>uint</td>\n") 540 if 'o' in params: 541 out.write(" <td>"+str(params['o'])+"</td>\n") 542 out.write(" <td>"+str(params['o'])+"</td>\n") 543 out.write("</tr>\n") 544 out.write("\n") 545 out.write("<tr>\n") 546 out.write("<td>levelinferred</td>\n") 547 out.write("<td>bool</td>\n") 548 if 'levelinferred' in params: 549 out.write(" <td>"+str(params['levelinferred'])+"</td>\n") 550 out.write(" <td>"+str(params['levelinferred'])+"</td>\n") 551 out.write("</tr>\n") 552 out.write("\n") 553 out.write("<tr>\n") 554 out.write("<td>flat_tolerance_exceeded</td>\n") 555 out.write("<td>bool</td>\n") 556 if 'flat_tolerance_exceeded' in params: 557 out.write(" <td>"+str(params['flat_tolerance_exceeded'])+"</td>\n") 558 out.write(" <td>"+str(params['flat_tolerance_exceeded'])+"</td>\n") 559 out.write("</tr>\n") 560 out.write("\n") 561 out.write("<tr>\n") 562 out.write("<td>rate_tolerance_exceeded</td>\n") 563 out.write("<td>bool</td>\n") 564 if 'rate_tolerance_exceeded' in params: 565 out.write(" <td>"+str(params['rate_tolerance_exceeded'])+"</td>\n") 566 out.write(" <td>"+str(params['rate_tolerance_exceeded'])+"</td>\n") 567 out.write("</tr>\n") 568 out.write("\n") 569 out.write("<tr>\n") 570 out.write("<td>temp_tolerance_exceeded</td>\n") 571 out.write("<td>bool</td>\n") 572 if 'temp_tolerance_exceeded' in params: 573 out.write(" <td>"+str(params['temp_tolerance_exceeded'])+"</td>\n") 574 out.write(" <td>"+str(params['temp_tolerance_exceeded'])+"</td>\n") 575 out.write("</tr>\n") 576 out.write("\n") 577 out.write("<tr>\n") 578 out.write("<td>expected_height_exceeded</td>\n") 579 out.write("<td>bool</td>\n") 580 if 'expected_height_exceeded' in params: 581 out.write(" <td>"+str(params['expected_height_exceeded'])+"</td>\n") 582 out.write(" <td>"+str(params['expected_height_exceeded'])+"</td>\n") 583 out.write("</tr>\n") 584 out.write("\n") 585 out.write("<tr>\n") 586 out.write("<td>link_down</td>\n") 587 out.write("<td>bool</td>\n") 588 if 'link_down' in params: 589 out.write(" <td>"+str(params['link_down'])+"</td>\n") 590 out.write(" <td>"+str(params['link_down'])+"</td>\n") 591 out.write("</tr>\n") 592 out.write("\n") 593 out.write("<tr>\n") 594 out.write("<td>timeLastMeasured</td>\n") 595 out.write("<td>udecimal</td>\n") 596 if 'timeLastMeasured' in params: 597 out.write(" <td>"+str(params['timeLastMeasured'])+"</td>\n") 598 out.write(" <td>"+str(params['timeLastMeasured'])+"</td>\n") 599 out.write("<td>hours</td>\n") 600 out.write("</tr>\n") 601 out.write("</table>\n")
602 603
604 -def printKml(params, out=sys.stdout):
605 '''KML (Keyhole Markup Language) for Google Earth, but without the header/footer''' 606 out.write("\ <Placemark>\n") 607 out.write("\t <name>"+str(params['stationid'])+"</name>\n") 608 out.write("\t\t<description>\n") 609 import StringIO 610 buf = StringIO.StringIO() 611 printHtml(params,buf) 612 import cgi 613 out.write(cgi.escape(buf.getvalue())) 614 out.write("\t\t</description>\n") 615 out.write("\t\t<styleUrl>#m_ylw-pushpin_copy0</styleUrl>\n") 616 out.write("\t\t<Point>\n") 617 out.write("\t\t\t<coordinates>") 618 out.write(str(params['longitude'])) 619 out.write(',') 620 out.write(str(params['latitude'])) 621 out.write(",0</coordinates>\n") 622 out.write("\t\t</Point>\n") 623 out.write("\t</Placemark>\n")
624
625 -def printFields(params, out=sys.stdout, format='std', fieldList=None, dbType='postgres'):
626 '''Print a waterlevel message to stdout. 627 628 Fields in params: 629 - MessageID(uint): AIS message number. Must be 8 (field automatically set to "8") 630 - RepeatIndicator(uint): Indicated how many times a message has been repeated 631 - UserID(uint): Unique ship identification number (MMSI) 632 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0") 633 - dac(uint): Designated Area Code (field automatically set to "366") 634 - fid(uint): Functional Identifier (field automatically set to "63") 635 - efid(uint): extended functional identifier (field automatically set to "2") 636 - month(uint): Time the measurement represents month 1..12 637 - day(uint): Time the measurement represents day of the month 1..31 638 - hour(uint): Time the measurement represents UTC hours 0..23 639 - min(uint): Time the measurement represents minutes 640 - sec(uint): Time the measurement represents seconds 641 - stationid(aisstr6): Character identifier of the station. Usually a number. 642 - longitude(decimal): Location of the sensor taking the water level measurement or position of prediction. East West location 643 - latitude(decimal): Location of the sensor taking the water level measurement or position of prediction. North South location 644 - waterlevel(int): Water level in centimeters 645 - datum(uint): What reference datum applies to the value 646 - sigma(float): Standard deviation of 1 second samples used to compute the water level height 647 - o(uint): Count of number of samples that fall outside a 3-sigma band about the mean 648 - levelinferred(bool): indicates that the water level value has been inferred 649 - flat_tolerance_exceeded(bool): flat tolerance limit was exceeded. Need better descr 650 - rate_tolerance_exceeded(bool): rate of change tolerance limit was exceeded 651 - temp_tolerance_exceeded(bool): temperature difference tolerance limit was exceeded 652 - expected_height_exceeded(bool): either the maximum or minimum expected water level height limit was exceeded 653 - link_down(bool): Unable to communicate with the tide system. All data invalid 654 - timeLastMeasured(udecimal): Time relative since the timetag that the station actually measured a value. 655 @param params: Dictionary of field names/values. 656 @param out: File like object to write to 657 @rtype: stdout 658 @return: text to out 659 ''' 660 661 if 'std'==format: 662 out.write("waterlevel:\n") 663 if 'MessageID' in params: out.write(" MessageID: "+str(params['MessageID'])+"\n") 664 if 'RepeatIndicator' in params: out.write(" RepeatIndicator: "+str(params['RepeatIndicator'])+"\n") 665 if 'UserID' in params: out.write(" UserID: "+str(params['UserID'])+"\n") 666 if 'Spare' in params: out.write(" Spare: "+str(params['Spare'])+"\n") 667 if 'dac' in params: out.write(" dac: "+str(params['dac'])+"\n") 668 if 'fid' in params: out.write(" fid: "+str(params['fid'])+"\n") 669 if 'efid' in params: out.write(" efid: "+str(params['efid'])+"\n") 670 if 'month' in params: out.write(" month: "+str(params['month'])+"\n") 671 if 'day' in params: out.write(" day: "+str(params['day'])+"\n") 672 if 'hour' in params: out.write(" hour: "+str(params['hour'])+"\n") 673 if 'min' in params: out.write(" min: "+str(params['min'])+"\n") 674 if 'sec' in params: out.write(" sec: "+str(params['sec'])+"\n") 675 if 'stationid' in params: out.write(" stationid: "+str(params['stationid'])+"\n") 676 if 'longitude' in params: out.write(" longitude: "+str(params['longitude'])+"\n") 677 if 'latitude' in params: out.write(" latitude: "+str(params['latitude'])+"\n") 678 if 'waterlevel' in params: out.write(" waterlevel: "+str(params['waterlevel'])+"\n") 679 if 'datum' in params: out.write(" datum: "+str(params['datum'])+"\n") 680 if 'sigma' in params: out.write(" sigma: "+str(params['sigma'])+"\n") 681 if 'o' in params: out.write(" o: "+str(params['o'])+"\n") 682 if 'levelinferred' in params: out.write(" levelinferred: "+str(params['levelinferred'])+"\n") 683 if 'flat_tolerance_exceeded' in params: out.write(" flat_tolerance_exceeded: "+str(params['flat_tolerance_exceeded'])+"\n") 684 if 'rate_tolerance_exceeded' in params: out.write(" rate_tolerance_exceeded: "+str(params['rate_tolerance_exceeded'])+"\n") 685 if 'temp_tolerance_exceeded' in params: out.write(" temp_tolerance_exceeded: "+str(params['temp_tolerance_exceeded'])+"\n") 686 if 'expected_height_exceeded' in params: out.write(" expected_height_exceeded: "+str(params['expected_height_exceeded'])+"\n") 687 if 'link_down' in params: out.write(" link_down: "+str(params['link_down'])+"\n") 688 if 'timeLastMeasured' in params: out.write(" timeLastMeasured: "+str(params['timeLastMeasured'])+"\n") 689 elif 'csv'==format: 690 if None == options.fieldList: 691 options.fieldList = fieldList 692 needComma = False; 693 for field in fieldList: 694 if needComma: out.write(',') 695 needComma = True 696 if field in params: 697 out.write(str(params[field])) 698 # else: leave it empty 699 out.write("\n") 700 elif 'html'==format: 701 printHtml(params,out) 702 elif 'sql'==format: 703 sqlInsertStr(params,out,dbType=dbType) 704 elif 'kml'==format: 705 printKml(params,out) 706 elif 'kml-full'==format: 707 out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") 708 out.write("<kml xmlns=\"http://earth.google.com/kml/2.1\">\n") 709 out.write("<Document>\n") 710 out.write(" <name>waterlevel</name>\n") 711 printKml(params,out) 712 out.write("</Document>\n") 713 out.write("</kml>\n") 714 else: 715 print "ERROR: unknown format:",format 716 assert False 717 718 return # Nothing to return
719 720 RepeatIndicatorEncodeLut = { 721 'default':'0', 722 'do not repeat any more':'3', 723 } #RepeatIndicatorEncodeLut 724 725 RepeatIndicatorDecodeLut = { 726 '0':'default', 727 '3':'do not repeat any more', 728 } # RepeatIndicatorEncodeLut 729 730 datumEncodeLut = { 731 'MLLW':'0', 732 'IGLD-85':'1', 733 'WaterDepth':'2', 734 'STND':'3', 735 'MHW':'4', 736 'MSL':'5', 737 'NGVD':'6', 738 'NAVD':'7', 739 'WGS-84':'8', 740 'LAT':'9', 741 } #datumEncodeLut 742 743 datumDecodeLut = { 744 '0':'MLLW', 745 '1':'IGLD-85', 746 '2':'WaterDepth', 747 '3':'STND', 748 '4':'MHW', 749 '5':'MSL', 750 '6':'NGVD', 751 '7':'NAVD', 752 '8':'WGS-84', 753 '9':'LAT', 754 } # datumEncodeLut 755 756 ###################################################################### 757 # SQL SUPPORT 758 ###################################################################### 759 760 dbTableName='waterlevel' 761 'Database table name' 762
763 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None 764 ,addCoastGuardFields=True 765 ,dbType='postgres' 766 ):
767 ''' 768 Return the SQL CREATE command for this message type 769 @param outfile: file like object to print to. 770 @param fields: which fields to put in the create. Defaults to all. 771 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 772 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 773 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 774 @type addCoastGuardFields: bool 775 @return: sql create string 776 @rtype: str 777 778 @see: sqlCreate 779 ''' 780 # FIX: should this sqlCreate be the same as in LaTeX (createFuncName) rather than hard coded? 781 outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType)))
782
783 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'):
784 ''' 785 Return the sqlhelp object to create the table. 786 787 @param fields: which fields to put in the create. Defaults to all. 788 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 789 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 790 @type addCoastGuardFields: bool 791 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 792 @return: An object that can be used to generate a return 793 @rtype: sqlhelp.create 794 ''' 795 if None == fields: fields = fieldList 796 import sqlhelp 797 c = sqlhelp.create('waterlevel',dbType=dbType) 798 c.addPrimaryKey() 799 if 'MessageID' in fields: c.addInt ('MessageID') 800 if 'RepeatIndicator' in fields: c.addInt ('RepeatIndicator') 801 if 'UserID' in fields: c.addInt ('UserID') 802 if 'Spare' in fields: c.addInt ('Spare') 803 if 'dac' in fields: c.addInt ('dac') 804 if 'fid' in fields: c.addInt ('fid') 805 if 'efid' in fields: c.addInt ('efid') 806 if 'month' in fields: c.addInt ('month') 807 if 'day' in fields: c.addInt ('day') 808 if 'hour' in fields: c.addInt ('hour') 809 if 'min' in fields: c.addInt ('min') 810 if 'sec' in fields: c.addInt ('sec') 811 if 'stationid' in fields: c.addVarChar('stationid',7) 812 if dbType != 'postgres': 813 if 'longitude' in fields: c.addDecimal('longitude',8,5) 814 if dbType != 'postgres': 815 if 'latitude' in fields: c.addDecimal('latitude',8,5) 816 if 'waterlevel' in fields: c.addInt ('waterlevel') 817 if 'datum' in fields: c.addInt ('datum') 818 if 'sigma' in fields: c.addReal('sigma') 819 if 'o' in fields: c.addInt ('o') 820 if 'levelinferred' in fields: c.addBool('levelinferred') 821 if 'flat_tolerance_exceeded' in fields: c.addBool('flat_tolerance_exceeded') 822 if 'rate_tolerance_exceeded' in fields: c.addBool('rate_tolerance_exceeded') 823 if 'temp_tolerance_exceeded' in fields: c.addBool('temp_tolerance_exceeded') 824 if 'expected_height_exceeded' in fields: c.addBool('expected_height_exceeded') 825 if 'link_down' in fields: c.addBool('link_down') 826 if 'timeLastMeasured' in fields: c.addDecimal('timeLastMeasured',4,1) 827 828 if addCoastGuardFields: 829 # c.addInt('cg_rssi') # Relative signal strength indicator 830 # c.addInt('cg_d') # dBm receive strength 831 # c.addInt('cg_T') # Receive timestamp from the AIS equipment 832 # c.addInt('cg_S') # Slot received in 833 # c.addVarChar('cg_x',10) # Idonno 834 c.addVarChar('cg_r',15) # Receiver station ID - should usually be an MMSI, but sometimes is a string 835 c.addInt('cg_sec') # UTC seconds since the epoch 836 837 c.addTimestamp('cg_timestamp') # UTC decoded cg_sec - not actually in the data stream 838 839 if dbType == 'postgres': 840 #--- EPSG 4326 : WGS 84 841 #INSERT INTO "spatial_ref_sys" ("srid","auth_name","auth_srid","srtext","proj4text") VALUES (4326,'EPSG',4326,'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs '); 842 c.addPostGIS('stationloc','POINT',2,SRID=4326); 843 844 return c
845
846 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'):
847 ''' 848 Return the SQL INSERT command for this message type 849 @param params: dictionary of values keyed by field name 850 @param outfile: file like object to print to. 851 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields 852 @return: sql create string 853 @rtype: str 854 855 @see: sqlCreate 856 ''' 857 outfile.write(str(sqlInsert(params,extraParams,dbType=dbType)))
858 859
860 -def sqlInsert(params,extraParams=None,dbType='postgres'):
861 ''' 862 Give the SQL INSERT statement 863 @param params: dict keyed by field name of values 864 @param extraParams: any extra fields that you have created beyond the normal ais message fields 865 @rtype: sqlhelp.insert 866 @return: insert class instance 867 @todo: allow optional type checking of params? 868 @warning: this will take invalid keys happily and do what??? 869 ''' 870 import sqlhelp 871 i = sqlhelp.insert('waterlevel',dbType=dbType) 872 873 if dbType=='postgres': 874 finished = [] 875 for key in params: 876 if key in finished: 877 continue 878 879 if key not in toPgFields and key not in fromPgFields: 880 if type(params[key])==Decimal: i.add(key,float(params[key])) 881 else: i.add(key,params[key]) 882 else: 883 if key in fromPgFields: 884 val = params[key] 885 # Had better be a WKT type like POINT(-88.1 30.321) 886 i.addPostGIS(key,val) 887 finished.append(key) 888 else: 889 # Need to construct the type. 890 pgName = toPgFields[key] 891 #valStr='GeomFromText(\''+pgTypes[pgName]+'(' 892 valStr=pgTypes[pgName]+'(' 893 vals = [] 894 for nonPgKey in fromPgFields[pgName]: 895 vals.append(str(params[nonPgKey])) 896 finished.append(nonPgKey) 897 valStr+=' '.join(vals)+')' 898 i.addPostGIS(pgName,valStr) 899 else: 900 for key in params: 901 if type(params[key])==Decimal: i.add(key,float(params[key])) 902 else: i.add(key,params[key]) 903 904 if None != extraParams: 905 for key in extraParams: 906 i.add(key,extraParams[key]) 907 908 return i
909 910 ###################################################################### 911 # LATEX SUPPORT 912 ###################################################################### 913
914 -def latexDefinitionTable(outfile=sys.stdout 915 ):
916 ''' 917 Return the LaTeX definition table for this message type 918 @param outfile: file like object to print to. 919 @type outfile: file obj 920 @return: LaTeX table string via the outfile 921 @rtype: str 922 923 ''' 924 o = outfile 925 926 o.write(''' 927 \\begin{table}%[htb] 928 \\centering 929 \\begin{tabular}{|l|c|l|} 930 \\hline 931 Parameter & Number of bits & Description 932 \\\\ \\hline\\hline 933 MessageID & 6 & AIS message number. Must be 8 \\\\ \hline 934 RepeatIndicator & 2 & Indicated how many times a message has been repeated \\\\ \hline 935 UserID & 30 & Unique ship identification number (MMSI) \\\\ \hline 936 Spare & 2 & Reserved for definition by a regional authority. \\\\ \hline 937 dac & 10 & Designated Area Code \\\\ \hline 938 fid & 6 & Functional Identifier \\\\ \hline 939 efid & 12 & extended functional identifier \\\\ \hline 940 month & 4 & Time the measurement represents month 1..12 \\\\ \hline 941 day & 5 & Time the measurement represents day of the month 1..31 \\\\ \hline 942 hour & 5 & Time the measurement represents UTC hours 0..23 \\\\ \hline 943 min & 6 & Time the measurement represents minutes \\\\ \hline 944 sec & 6 & Time the measurement represents seconds \\\\ \hline 945 stationid & 42 & Character identifier of the station. Usually a number. \\\\ \hline 946 longitude & 28 & Location of the sensor taking the water level measurement or position of prediction. East West location \\\\ \hline 947 latitude & 27 & Location of the sensor taking the water level measurement or position of prediction. North South location \\\\ \hline 948 waterlevel & 16 & Water level in centimeters \\\\ \hline 949 datum & 5 & What reference datum applies to the value \\\\ \hline 950 sigma & 32 & Standard deviation of 1 second samples used to compute the water level height \\\\ \hline 951 o & 8 & Count of number of samples that fall outside a 3-sigma band about the mean \\\\ \hline 952 levelinferred & 1 & indicates that the water level value has been inferred \\\\ \hline 953 flat\_tolerance\_exceeded & 1 & flat tolerance limit was exceeded. Need better descr \\\\ \hline 954 rate\_tolerance\_exceeded & 1 & rate of change tolerance limit was exceeded \\\\ \hline 955 temp\_tolerance\_exceeded & 1 & temperature difference tolerance limit was exceeded \\\\ \hline 956 expected\_height\_exceeded & 1 & either the maximum or minimum expected water level height limit was exceeded \\\\ \hline 957 link\_down & 1 & Unable to communicate with the tide system. All data invalid \\\\ \hline 958 timeLastMeasured & 12 & Time relative since the timetag that the station actually measured a value.\\\\ \\hline \\hline 959 Total bits & 270 & Appears to take 2 slots with 154 pad bits to fill the last slot \\\\ \\hline 960 \\end{tabular} 961 \\caption{AIS message number 8: Water level report. In this case from the NOAA Co-Ops 6 minute raw data. This is } 962 \\label{tab:waterlevel} 963 \\end{table} 964 ''')
965 966 ###################################################################### 967 # Text Definition 968 ###################################################################### 969
970 -def textDefinitionTable(outfile=sys.stdout 971 ,delim='\t' 972 ):
973 ''' 974 Return the text definition table for this message type 975 @param outfile: file like object to print to. 976 @type outfile: file obj 977 @return: text table string via the outfile 978 @rtype: str 979 980 ''' 981 o = outfile 982 o.write('''Parameter'''+delim+'Number of bits'''+delim+'''Description 983 MessageID'''+delim+'''6'''+delim+'''AIS message number. Must be 8 984 RepeatIndicator'''+delim+'''2'''+delim+'''Indicated how many times a message has been repeated 985 UserID'''+delim+'''30'''+delim+'''Unique ship identification number (MMSI) 986 Spare'''+delim+'''2'''+delim+'''Reserved for definition by a regional authority. 987 dac'''+delim+'''10'''+delim+'''Designated Area Code 988 fid'''+delim+'''6'''+delim+'''Functional Identifier 989 efid'''+delim+'''12'''+delim+'''extended functional identifier 990 month'''+delim+'''4'''+delim+'''Time the measurement represents month 1..12 991 day'''+delim+'''5'''+delim+'''Time the measurement represents day of the month 1..31 992 hour'''+delim+'''5'''+delim+'''Time the measurement represents UTC hours 0..23 993 min'''+delim+'''6'''+delim+'''Time the measurement represents minutes 994 sec'''+delim+'''6'''+delim+'''Time the measurement represents seconds 995 stationid'''+delim+'''42'''+delim+'''Character identifier of the station. Usually a number. 996 longitude'''+delim+'''28'''+delim+'''Location of the sensor taking the water level measurement or position of prediction. East West location 997 latitude'''+delim+'''27'''+delim+'''Location of the sensor taking the water level measurement or position of prediction. North South location 998 waterlevel'''+delim+'''16'''+delim+'''Water level in centimeters 999 datum'''+delim+'''5'''+delim+'''What reference datum applies to the value 1000 sigma'''+delim+'''32'''+delim+'''Standard deviation of 1 second samples used to compute the water level height 1001 o'''+delim+'''8'''+delim+'''Count of number of samples that fall outside a 3-sigma band about the mean 1002 levelinferred'''+delim+'''1'''+delim+'''indicates that the water level value has been inferred 1003 flat_tolerance_exceeded'''+delim+'''1'''+delim+'''flat tolerance limit was exceeded. Need better descr 1004 rate_tolerance_exceeded'''+delim+'''1'''+delim+'''rate of change tolerance limit was exceeded 1005 temp_tolerance_exceeded'''+delim+'''1'''+delim+'''temperature difference tolerance limit was exceeded 1006 expected_height_exceeded'''+delim+'''1'''+delim+'''either the maximum or minimum expected water level height limit was exceeded 1007 link_down'''+delim+'''1'''+delim+'''Unable to communicate with the tide system. All data invalid 1008 timeLastMeasured'''+delim+'''12'''+delim+'''Time relative since the timetag that the station actually measured a value. 1009 Total bits'''+delim+'''270'''+delim+'''Appears to take 2 slots with 154 pad bits to fill the last slot''')
1010 1011 1012 ###################################################################### 1013 # UNIT TESTING 1014 ###################################################################### 1015 import unittest
1016 -def testParams():
1017 '''Return a params file base on the testvalue tags. 1018 @rtype: dict 1019 @return: params based on testvalue tags 1020 ''' 1021 params = {} 1022 params['MessageID'] = 8 1023 params['RepeatIndicator'] = 1 1024 params['UserID'] = 1193046 1025 params['Spare'] = 0 1026 params['dac'] = 366 1027 params['fid'] = 63 1028 params['efid'] = 2 1029 params['month'] = 2 1030 params['day'] = 28 1031 params['hour'] = 23 1032 params['min'] = 45 1033 params['sec'] = 58 1034 params['stationid'] = 'A234567' 1035 params['longitude'] = Decimal('-122.16328055555556') 1036 params['latitude'] = Decimal('37.424458333333334') 1037 params['waterlevel'] = -97 1038 params['datum'] = 0 1039 params['sigma'] = -1.234 1040 params['o'] = 240 1041 params['levelinferred'] = False 1042 params['flat_tolerance_exceeded'] = True 1043 params['rate_tolerance_exceeded'] = False 1044 params['temp_tolerance_exceeded'] = False 1045 params['expected_height_exceeded'] = True 1046 params['link_down'] = False 1047 params['timeLastMeasured'] = Decimal('0') 1048 1049 return params
1050
1051 -class Testwaterlevel(unittest.TestCase):
1052 '''Use testvalue tag text from each type to build test case the waterlevel message'''
1053 - def testEncodeDecode(self):
1054 1055 params = testParams() 1056 bits = encode(params) 1057 r = decode(bits) 1058 1059 # Check that each parameter came through ok. 1060 self.failUnlessEqual(r['MessageID'],params['MessageID']) 1061 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator']) 1062 self.failUnlessEqual(r['UserID'],params['UserID']) 1063 self.failUnlessEqual(r['Spare'],params['Spare']) 1064 self.failUnlessEqual(r['dac'],params['dac']) 1065 self.failUnlessEqual(r['fid'],params['fid']) 1066 self.failUnlessEqual(r['efid'],params['efid']) 1067 self.failUnlessEqual(r['month'],params['month']) 1068 self.failUnlessEqual(r['day'],params['day']) 1069 self.failUnlessEqual(r['hour'],params['hour']) 1070 self.failUnlessEqual(r['min'],params['min']) 1071 self.failUnlessEqual(r['sec'],params['sec']) 1072 self.failUnlessEqual(r['stationid'],params['stationid']) 1073 self.failUnlessAlmostEqual(r['longitude'],params['longitude'],5) 1074 self.failUnlessAlmostEqual(r['latitude'],params['latitude'],5) 1075 self.failUnlessEqual(r['waterlevel'],params['waterlevel']) 1076 self.failUnlessEqual(r['datum'],params['datum']) 1077 self.failUnlessAlmostEqual(r['sigma'],params['sigma'],3) 1078 self.failUnlessEqual(r['o'],params['o']) 1079 self.failUnlessEqual(r['levelinferred'],params['levelinferred']) 1080 self.failUnlessEqual(r['flat_tolerance_exceeded'],params['flat_tolerance_exceeded']) 1081 self.failUnlessEqual(r['rate_tolerance_exceeded'],params['rate_tolerance_exceeded']) 1082 self.failUnlessEqual(r['temp_tolerance_exceeded'],params['temp_tolerance_exceeded']) 1083 self.failUnlessEqual(r['expected_height_exceeded'],params['expected_height_exceeded']) 1084 self.failUnlessEqual(r['link_down'],params['link_down']) 1085 self.failUnlessAlmostEqual(r['timeLastMeasured'],params['timeLastMeasured'],1)
1086
1087 -def addMsgOptions(parser):
1088 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true', 1089 help='decode a "waterlevel" AIS message') 1090 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true', 1091 help='encode a "waterlevel" AIS message') 1092 parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int' 1093 ,help='Field parameter value [default: %default]') 1094 parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int' 1095 ,help='Field parameter value [default: %default]') 1096 parser.add_option('--month-field', dest='monthField',metavar='uint',type='int' 1097 ,help='Field parameter value [default: %default]') 1098 parser.add_option('--day-field', dest='dayField',metavar='uint',type='int' 1099 ,help='Field parameter value [default: %default]') 1100 parser.add_option('--hour-field', dest='hourField',metavar='uint',type='int' 1101 ,help='Field parameter value [default: %default]') 1102 parser.add_option('--min-field', dest='minField',metavar='uint',type='int' 1103 ,help='Field parameter value [default: %default]') 1104 parser.add_option('--sec-field', dest='secField',metavar='uint',type='int' 1105 ,help='Field parameter value [default: %default]') 1106 parser.add_option('--stationid-field', dest='stationidField',default='@@@@@@@',metavar='aisstr6',type='string' 1107 ,help='Field parameter value [default: %default]') 1108 parser.add_option('--longitude-field', dest='longitudeField',default=Decimal('181'),metavar='decimal',type='string' 1109 ,help='Field parameter value [default: %default]') 1110 parser.add_option('--latitude-field', dest='latitudeField',default=Decimal('91'),metavar='decimal',type='string' 1111 ,help='Field parameter value [default: %default]') 1112 parser.add_option('--waterlevel-field', dest='waterlevelField',default=-32768,metavar='int',type='int' 1113 ,help='Field parameter value [default: %default]') 1114 parser.add_option('--datum-field', dest='datumField',default=31,metavar='uint',type='int' 1115 ,help='Field parameter value [default: %default]') 1116 parser.add_option('--sigma-field', dest='sigmaField',metavar='float',type='float' 1117 ,help='Field parameter value [default: %default]') 1118 parser.add_option('--o-field', dest='oField',default=255,metavar='uint',type='int' 1119 ,help='Field parameter value [default: %default]') 1120 parser.add_option('--levelinferred-field', dest='levelinferredField',metavar='bool',type='int' 1121 ,help='Field parameter value [default: %default]') 1122 parser.add_option('--flat_tolerance_exceeded-field', dest='flat_tolerance_exceededField',metavar='bool',type='int' 1123 ,help='Field parameter value [default: %default]') 1124 parser.add_option('--rate_tolerance_exceeded-field', dest='rate_tolerance_exceededField',metavar='bool',type='int' 1125 ,help='Field parameter value [default: %default]') 1126 parser.add_option('--temp_tolerance_exceeded-field', dest='temp_tolerance_exceededField',metavar='bool',type='int' 1127 ,help='Field parameter value [default: %default]') 1128 parser.add_option('--expected_height_exceeded-field', dest='expected_height_exceededField',metavar='bool',type='int' 1129 ,help='Field parameter value [default: %default]') 1130 parser.add_option('--link_down-field', dest='link_downField',metavar='bool',type='int' 1131 ,help='Field parameter value [default: %default]') 1132 parser.add_option('--timeLastMeasured-field', dest='timeLastMeasuredField',default=Decimal('409.6'),metavar='udecimal',type='string' 1133 ,help='Field parameter value [default: %default]')
1134 1135 ############################################################ 1136 if __name__=='__main__': 1137 1138 from optparse import OptionParser 1139 parser = OptionParser(usage="%prog [options]", 1140 version="%prog "+__version__) 1141 1142 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true', 1143 help='run the documentation tests') 1144 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true', 1145 help='run the unit tests') 1146 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 1147 help='Make the test output verbose') 1148 1149 # FIX: remove nmea from binary messages. No way to build the whole packet? 1150 # FIX: or build the surrounding msg 8 for a broadcast? 1151 typeChoices = ('binary','nmeapayload','nmea') # FIX: what about a USCG type message? 1152 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType' 1153 ,default='nmeapayload' 1154 ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]') 1155 1156 1157 outputChoices = ('std','html','csv','sql' , 'kml','kml-full') 1158 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType' 1159 ,default='std' 1160 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]') 1161 1162 parser.add_option('-o','--output',dest='outputFileName',default=None, 1163 help='Name of the python file to write [default: stdout]') 1164 1165 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append', 1166 choices=fieldList, 1167 help='Which fields to include in the output. Currently only for csv output [default: all]') 1168 1169 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true', 1170 help='Print the field name for csv') 1171 1172 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true', 1173 help='Print out an sql create command for the table.') 1174 1175 parser.add_option('--latex-table',dest='latexDefinitionTable',default=False,action='store_true', 1176 help='Print a LaTeX table of the type') 1177 1178 parser.add_option('--text-table',dest='textDefinitionTable',default=False,action='store_true', 1179 help='Print delimited table of the type (for Word table importing)') 1180 parser.add_option('--delimt-text-table',dest='delimTextDefinitionTable',default='\t' 1181 ,help='Delimiter for text table [default: \'%default\'](for Word table importing)') 1182 1183 1184 dbChoices = ('sqlite','postgres') 1185 parser.add_option('-D','--db-type',dest='dbType',default='postgres' 1186 ,choices=dbChoices,type='choice' 1187 ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]') 1188 1189 addMsgOptions(parser) 1190 1191 (options,args) = parser.parse_args() 1192 success=True 1193 1194 if options.doctest: 1195 import os; print os.path.basename(sys.argv[0]), 'doctests ...', 1196 sys.argv= [sys.argv[0]] 1197 if options.verbose: sys.argv.append('-v') 1198 import doctest 1199 numfail,numtests=doctest.testmod() 1200 if numfail==0: print 'ok' 1201 else: 1202 print 'FAILED' 1203 success=False 1204 1205 if not success: sys.exit('Something Failed') 1206 del success # Hide success from epydoc 1207 1208 if options.unittest: 1209 sys.argv = [sys.argv[0]] 1210 if options.verbose: sys.argv.append('-v') 1211 unittest.main() 1212 1213 outfile = sys.stdout 1214 if None!=options.outputFileName: 1215 outfile = file(options.outputFileName,'w') 1216 1217 1218 if options.doEncode: 1219 # First make sure all non required options are specified 1220 if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField") 1221 if None==options.UserIDField: parser.error("missing value for UserIDField") 1222 if None==options.monthField: parser.error("missing value for monthField") 1223 if None==options.dayField: parser.error("missing value for dayField") 1224 if None==options.hourField: parser.error("missing value for hourField") 1225 if None==options.minField: parser.error("missing value for minField") 1226 if None==options.secField: parser.error("missing value for secField") 1227 if None==options.stationidField: parser.error("missing value for stationidField") 1228 if None==options.longitudeField: parser.error("missing value for longitudeField") 1229 if None==options.latitudeField: parser.error("missing value for latitudeField") 1230 if None==options.waterlevelField: parser.error("missing value for waterlevelField") 1231 if None==options.datumField: parser.error("missing value for datumField") 1232 if None==options.sigmaField: parser.error("missing value for sigmaField") 1233 if None==options.oField: parser.error("missing value for oField") 1234 if None==options.levelinferredField: parser.error("missing value for levelinferredField") 1235 if None==options.flat_tolerance_exceededField: parser.error("missing value for flat_tolerance_exceededField") 1236 if None==options.rate_tolerance_exceededField: parser.error("missing value for rate_tolerance_exceededField") 1237 if None==options.temp_tolerance_exceededField: parser.error("missing value for temp_tolerance_exceededField") 1238 if None==options.expected_height_exceededField: parser.error("missing value for expected_height_exceededField") 1239 if None==options.link_downField: parser.error("missing value for link_downField") 1240 if None==options.timeLastMeasuredField: parser.error("missing value for timeLastMeasuredField") 1241 msgDict={ 1242 'MessageID': '8', 1243 'RepeatIndicator': options.RepeatIndicatorField, 1244 'UserID': options.UserIDField, 1245 'Spare': '0', 1246 'dac': '366', 1247 'fid': '63', 1248 'efid': '2', 1249 'month': options.monthField, 1250 'day': options.dayField, 1251 'hour': options.hourField, 1252 'min': options.minField, 1253 'sec': options.secField, 1254 'stationid': options.stationidField, 1255 'longitude': options.longitudeField, 1256 'latitude': options.latitudeField, 1257 'waterlevel': options.waterlevelField, 1258 'datum': options.datumField, 1259 'sigma': options.sigmaField, 1260 'o': options.oField, 1261 'levelinferred': options.levelinferredField, 1262 'flat_tolerance_exceeded': options.flat_tolerance_exceededField, 1263 'rate_tolerance_exceeded': options.rate_tolerance_exceededField, 1264 'temp_tolerance_exceeded': options.temp_tolerance_exceededField, 1265 'expected_height_exceeded': options.expected_height_exceededField, 1266 'link_down': options.link_downField, 1267 'timeLastMeasured': options.timeLastMeasuredField, 1268 } 1269 1270 bits = encode(msgDict) 1271 if 'binary'==options.ioType: print str(bits) 1272 elif 'nmeapayload'==options.ioType: 1273 # FIX: figure out if this might be necessary at compile time 1274 print "bitLen",len(bits) 1275 bitLen=len(bits) 1276 if bitLen%6!=0: 1277 bits = bits + BitVector(size=(6 - (bitLen%6))) # Pad out to multiple of 6 1278 print "result:",binary.bitvectoais6(bits)[0] 1279 1280 1281 # FIX: Do not emit this option for the binary message payloads. Does not make sense. 1282 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability") 1283 else: sys.exit('ERROR: unknown ioType. Help!') 1284 1285 1286 if options.sqlCreate: 1287 sqlCreateStr(outfile,options.fieldList,dbType=options.dbType) 1288 1289 if options.latexDefinitionTable: 1290 latexDefinitionTable(outfile) 1291 1292 # For conversion to word tables 1293 if options.textDefinitionTable: 1294 textDefinitionTable(outfile,options.delimTextDefinitionTable) 1295 1296 if options.printCsvfieldList: 1297 # Make a csv separated list of fields that will be displayed for csv 1298 if None == options.fieldList: options.fieldList = fieldList 1299 import StringIO 1300 buf = StringIO.StringIO() 1301 for field in options.fieldList: 1302 buf.write(field+',') 1303 result = buf.getvalue() 1304 if result[-1] == ',': print result[:-1] 1305 else: print result 1306 1307 if options.doDecode: 1308 if len(args)==0: args = sys.stdin 1309 for msg in args: 1310 bv = None 1311 1312 if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'): 1313 # Found nmea 1314 # FIX: do checksum 1315 bv = binary.ais6tobitvec(msg.split(',')[5]) 1316 else: # either binary or nmeapayload... expect mostly nmeapayloads 1317 # assumes that an all 0 and 1 string can not be a nmeapayload 1318 binaryMsg=True 1319 for c in msg: 1320 if c not in ('0','1'): 1321 binaryMsg=False 1322 break 1323 if binaryMsg: 1324 bv = BitVector(bitstring=msg) 1325 else: # nmeapayload 1326 bv = binary.ais6tobitvec(msg) 1327 1328 printFields(decode(bv) 1329 ,out=outfile 1330 ,format=options.outputType 1331 ,fieldList=options.fieldList 1332 ,dbType=options.dbType 1333 ) 1334