Package ais :: Package sls :: Module waterflow
[hide private]
[frames] | no frames]

Source Code for Module ais.sls.waterflow

  1  #!/usr/bin/env python 
  2   
  3  __version__ = '$Revision: 4791 $'.split()[1] 
  4  __date__ = '$Date: 2007-11-07 $'.split()[1] 
  5  __author__ = 'xmlbinmsg' 
  6   
  7  __doc__=''' 
  8   
  9  Autogenerated python functions to serialize/deserialize binary messages. 
 10   
 11  Generated by: ../aisxmlbinmsg2py.py 
 12   
 13  Need to then wrap these functions with the outer AIS packet and then 
 14  convert the whole binary blob to a NMEA string.  Those functions are 
 15  not currently provided in this file. 
 16   
 17  serialize: python to ais binary 
 18  deserialize: ais binary to python 
 19   
 20  The generated code uses translators.py, binary.py, and aisstring.py 
 21  which should be packaged with the resulting files. 
 22   
 23   
 24  @requires: U{epydoc<http://epydoc.sourceforge.net/>} > 3.0alpha3 
 25  @requires: U{BitVector<http://cheeseshop.python.org/pypi/BitVector>} 
 26   
 27  @author: '''+__author__+''' 
 28  @version: ''' + __version__ +''' 
 29  @var __date__: Date of last svn commit 
 30  @undocumented: __version__ __author__ __doc__ parser 
 31  @status: under development 
 32  @license: Generated code has no license 
 33  @todo: FIX: put in a description of the message here with fields and types. 
 34  ''' 
 35   
 36  import sys 
 37  from decimal import Decimal 
 38  from BitVector import BitVector 
 39   
 40  import binary, aisstring 
 41   
 42  # FIX: check to see if these will be needed 
 43  TrueBV  = BitVector(bitstring="1") 
 44  "Why always rebuild the True bit?  This should speed things up a bunch" 
 45  FalseBV = BitVector(bitstring="0") 
 46  "Why always rebuild the False bit?  This should speed things up a bunch" 
 47   
 48   
 49  fieldList = ( 
 50          'time_month', 
 51          'time_day', 
 52          'time_hour', 
 53          'time_min', 
 54          'stationid', 
 55          'pos_longitude', 
 56          'pos_latitude', 
 57          'flow', 
 58          'reserved', 
 59  ) 
 60   
 61  fieldListPostgres = ( 
 62          'time_month', 
 63          'time_day', 
 64          'time_hour', 
 65          'time_min', 
 66          'stationid', 
 67          'pos',  # PostGIS data type 
 68          'flow', 
 69          'reserved', 
 70  ) 
 71   
 72  toPgFields = { 
 73          'pos_longitude':'pos', 
 74          'pos_latitude':'pos', 
 75  } 
 76  ''' 
 77  Go to the Postgis field names from the straight field name 
 78  ''' 
 79   
 80  fromPgFields = { 
 81          'pos':('pos_longitude','pos_latitude',), 
 82  } 
 83  ''' 
 84  Go from the Postgis field names to the straight field name 
 85  ''' 
 86   
 87  pgTypes = { 
 88          'pos':'POINT', 
 89  } 
 90  ''' 
 91  Lookup table for each postgis field name to get its type. 
 92  ''' 
 93   
94 -def encode(params, validate=False):
95 '''Create a sls_wind binary message payload to pack into an AIS Msg sls_wind. 96 97 Fields in params: 98 - time_month(uint): Time tag of measurement month 1..12 99 - time_day(uint): Time tag of measurement day of the month 1..31 100 - time_hour(uint): Time tag of measurement UTC hours 0..23 101 - time_min(uint): Time tag of measurement minutes 102 - stationid(aisstr6): Character identifier of the station 103 - pos_longitude(decimal): Location of measurement East West location 104 - pos_latitude(decimal): Location of measurement North South location 105 - flow(uint): Water flow 106 - reserved(uint): Reserved bits for future use (field automatically set to "0") 107 @param params: Dictionary of field names/values. Throws a ValueError exception if required is missing 108 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 109 @rtype: BitVector 110 @return: encoded binary message (for binary messages, this needs to be wrapped in a msg 8 111 @note: The returned bits may not be 6 bit aligned. It is up to you to pad out the bits. 112 ''' 113 114 bvList = [] 115 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time_month']),4)) 116 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time_day']),5)) 117 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time_hour']),5)) 118 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time_min']),6)) 119 if 'stationid' in params: 120 bvList.append(aisstring.encode(params['stationid'],42)) 121 else: 122 bvList.append(aisstring.encode('@@@@@@@',42)) 123 if 'pos_longitude' in params: 124 bvList.append(binary.bvFromSignedInt(int(Decimal(params['pos_longitude'])*Decimal('60000')),25)) 125 else: 126 bvList.append(binary.bvFromSignedInt(10860000,25)) 127 if 'pos_latitude' in params: 128 bvList.append(binary.bvFromSignedInt(int(Decimal(params['pos_latitude'])*Decimal('60000')),24)) 129 else: 130 bvList.append(binary.bvFromSignedInt(5460000,24)) 131 if 'flow' in params: 132 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['flow']),10)) 133 else: 134 bvList.append(binary.setBitVectorSize(BitVector(intVal=16383),10)) 135 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),19)) 136 137 return binary.joinBV(bvList)
138
139 -def decode(bv, validate=False):
140 '''Unpack a sls_wind message 141 142 Fields in params: 143 - time_month(uint): Time tag of measurement month 1..12 144 - time_day(uint): Time tag of measurement day of the month 1..31 145 - time_hour(uint): Time tag of measurement UTC hours 0..23 146 - time_min(uint): Time tag of measurement minutes 147 - stationid(aisstr6): Character identifier of the station 148 - pos_longitude(decimal): Location of measurement East West location 149 - pos_latitude(decimal): Location of measurement North South location 150 - flow(uint): Water flow 151 - reserved(uint): Reserved bits for future use (field automatically set to "0") 152 @type bv: BitVector 153 @param bv: Bits defining a message 154 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented. 155 @rtype: dict 156 @return: params 157 ''' 158 159 #Would be nice to check the bit count here.. 160 #if validate: 161 # assert (len(bv)==FIX: SOME NUMBER) 162 r = {} 163 r['time_month']=int(bv[0:4]) 164 r['time_day']=int(bv[4:9]) 165 r['time_hour']=int(bv[9:14]) 166 r['time_min']=int(bv[14:20]) 167 r['stationid']=aisstring.decode(bv[20:62]) 168 r['pos_longitude']=Decimal(binary.signedIntFromBV(bv[62:87]))/Decimal('60000') 169 r['pos_latitude']=Decimal(binary.signedIntFromBV(bv[87:111]))/Decimal('60000') 170 r['flow']=int(bv[111:121]) 171 r['reserved']=0 172 return r
173
174 -def decodetime_month(bv, validate=False):
175 return int(bv[0:4])
176
177 -def decodetime_day(bv, validate=False):
178 return int(bv[4:9])
179
180 -def decodetime_hour(bv, validate=False):
181 return int(bv[9:14])
182
183 -def decodetime_min(bv, validate=False):
184 return int(bv[14:20])
185
186 -def decodestationid(bv, validate=False):
187 return aisstring.decode(bv[20:62])
188
189 -def decodepos_longitude(bv, validate=False):
190 return Decimal(binary.signedIntFromBV(bv[62:87]))/Decimal('60000')
191
192 -def decodepos_latitude(bv, validate=False):
193 return Decimal(binary.signedIntFromBV(bv[87:111]))/Decimal('60000')
194
195 -def decodeflow(bv, validate=False):
196 return int(bv[111:121])
197
198 -def decodereserved(bv, validate=False):
199 return 0
200 201
202 -def printHtml(params, out=sys.stdout):
203 out.write("<h3>sls_wind</h3>\n") 204 out.write("<table border=\"1\">\n") 205 out.write("<tr bgcolor=\"orange\">\n") 206 out.write("<th align=\"left\">Field Name</th>\n") 207 out.write("<th align=\"left\">Type</th>\n") 208 out.write("<th align=\"left\">Value</th>\n") 209 out.write("<th align=\"left\">Value in Lookup Table</th>\n") 210 out.write("<th align=\"left\">Units</th>\n") 211 out.write("\n") 212 out.write("<tr>\n") 213 out.write("<td>time_month</td>\n") 214 out.write("<td>uint</td>\n") 215 if 'time_month' in params: 216 out.write(" <td>"+str(params['time_month'])+"</td>\n") 217 out.write(" <td>"+str(params['time_month'])+"</td>\n") 218 out.write("</tr>\n") 219 out.write("\n") 220 out.write("<tr>\n") 221 out.write("<td>time_day</td>\n") 222 out.write("<td>uint</td>\n") 223 if 'time_day' in params: 224 out.write(" <td>"+str(params['time_day'])+"</td>\n") 225 out.write(" <td>"+str(params['time_day'])+"</td>\n") 226 out.write("</tr>\n") 227 out.write("\n") 228 out.write("<tr>\n") 229 out.write("<td>time_hour</td>\n") 230 out.write("<td>uint</td>\n") 231 if 'time_hour' in params: 232 out.write(" <td>"+str(params['time_hour'])+"</td>\n") 233 out.write(" <td>"+str(params['time_hour'])+"</td>\n") 234 out.write("</tr>\n") 235 out.write("\n") 236 out.write("<tr>\n") 237 out.write("<td>time_min</td>\n") 238 out.write("<td>uint</td>\n") 239 if 'time_min' in params: 240 out.write(" <td>"+str(params['time_min'])+"</td>\n") 241 out.write(" <td>"+str(params['time_min'])+"</td>\n") 242 out.write("</tr>\n") 243 out.write("\n") 244 out.write("<tr>\n") 245 out.write("<td>stationid</td>\n") 246 out.write("<td>aisstr6</td>\n") 247 if 'stationid' in params: 248 out.write(" <td>"+str(params['stationid'])+"</td>\n") 249 out.write(" <td>"+str(params['stationid'])+"</td>\n") 250 out.write("</tr>\n") 251 out.write("\n") 252 out.write("<tr>\n") 253 out.write("<td>pos_longitude</td>\n") 254 out.write("<td>decimal</td>\n") 255 if 'pos_longitude' in params: 256 out.write(" <td>"+str(params['pos_longitude'])+"</td>\n") 257 out.write(" <td>"+str(params['pos_longitude'])+"</td>\n") 258 out.write("<td>degrees</td>\n") 259 out.write("</tr>\n") 260 out.write("\n") 261 out.write("<tr>\n") 262 out.write("<td>pos_latitude</td>\n") 263 out.write("<td>decimal</td>\n") 264 if 'pos_latitude' in params: 265 out.write(" <td>"+str(params['pos_latitude'])+"</td>\n") 266 out.write(" <td>"+str(params['pos_latitude'])+"</td>\n") 267 out.write("<td>degrees</td>\n") 268 out.write("</tr>\n") 269 out.write("\n") 270 out.write("<tr>\n") 271 out.write("<td>flow</td>\n") 272 out.write("<td>uint</td>\n") 273 if 'flow' in params: 274 out.write(" <td>"+str(params['flow'])+"</td>\n") 275 out.write(" <td>"+str(params['flow'])+"</td>\n") 276 out.write("<td>m^3/s</td>\n") 277 out.write("</tr>\n") 278 out.write("\n") 279 out.write("<tr>\n") 280 out.write("<td>reserved</td>\n") 281 out.write("<td>uint</td>\n") 282 if 'reserved' in params: 283 out.write(" <td>"+str(params['reserved'])+"</td>\n") 284 out.write(" <td>"+str(params['reserved'])+"</td>\n") 285 out.write("</tr>\n") 286 out.write("</table>\n")
287 288
289 -def printKml(params, out=sys.stdout):
290 '''KML (Keyhole Markup Language) for Google Earth, but without the header/footer''' 291 out.write("\ <Placemark>\n") 292 out.write("\t <name>"+str(params['stationid'])+"</name>\n") 293 out.write("\t\t<description>\n") 294 import StringIO 295 buf = StringIO.StringIO() 296 printHtml(params,buf) 297 import cgi 298 out.write(cgi.escape(buf.getvalue())) 299 out.write("\t\t</description>\n") 300 out.write("\t\t<styleUrl>#m_ylw-pushpin_copy0</styleUrl>\n") 301 out.write("\t\t<Point>\n") 302 out.write("\t\t\t<coordinates>") 303 out.write(str(params['pos_longitude'])) 304 out.write(',') 305 out.write(str(params['pos_latitude'])) 306 out.write(",0</coordinates>\n") 307 out.write("\t\t</Point>\n") 308 out.write("\t</Placemark>\n")
309
310 -def printFields(params, out=sys.stdout, format='std', fieldList=None, dbType='postgres'):
311 '''Print a sls_wind message to stdout. 312 313 Fields in params: 314 - time_month(uint): Time tag of measurement month 1..12 315 - time_day(uint): Time tag of measurement day of the month 1..31 316 - time_hour(uint): Time tag of measurement UTC hours 0..23 317 - time_min(uint): Time tag of measurement minutes 318 - stationid(aisstr6): Character identifier of the station 319 - pos_longitude(decimal): Location of measurement East West location 320 - pos_latitude(decimal): Location of measurement North South location 321 - flow(uint): Water flow 322 - reserved(uint): Reserved bits for future use (field automatically set to "0") 323 @param params: Dictionary of field names/values. 324 @param out: File like object to write to 325 @rtype: stdout 326 @return: text to out 327 ''' 328 329 if 'std'==format: 330 out.write("sls_wind:\n") 331 if 'time_month' in params: out.write(" time_month: "+str(params['time_month'])+"\n") 332 if 'time_day' in params: out.write(" time_day: "+str(params['time_day'])+"\n") 333 if 'time_hour' in params: out.write(" time_hour: "+str(params['time_hour'])+"\n") 334 if 'time_min' in params: out.write(" time_min: "+str(params['time_min'])+"\n") 335 if 'stationid' in params: out.write(" stationid: "+str(params['stationid'])+"\n") 336 if 'pos_longitude' in params: out.write(" pos_longitude: "+str(params['pos_longitude'])+"\n") 337 if 'pos_latitude' in params: out.write(" pos_latitude: "+str(params['pos_latitude'])+"\n") 338 if 'flow' in params: out.write(" flow: "+str(params['flow'])+"\n") 339 if 'reserved' in params: out.write(" reserved: "+str(params['reserved'])+"\n") 340 elif 'csv'==format: 341 if None == options.fieldList: 342 options.fieldList = fieldList 343 needComma = False; 344 for field in fieldList: 345 if needComma: out.write(',') 346 needComma = True 347 if field in params: 348 out.write(str(params[field])) 349 # else: leave it empty 350 out.write("\n") 351 elif 'html'==format: 352 printHtml(params,out) 353 elif 'sql'==format: 354 sqlInsertStr(params,out,dbType=dbType) 355 elif 'kml'==format: 356 printKml(params,out) 357 elif 'kml-full'==format: 358 out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") 359 out.write("<kml xmlns=\"http://earth.google.com/kml/2.1\">\n") 360 out.write("<Document>\n") 361 out.write(" <name>sls_wind</name>\n") 362 printKml(params,out) 363 out.write("</Document>\n") 364 out.write("</kml>\n") 365 else: 366 print "ERROR: unknown format:",format 367 assert False 368 369 return # Nothing to return
370 371 ###################################################################### 372 # SQL SUPPORT 373 ###################################################################### 374
375 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None 376 ,addCoastGuardFields=True 377 ,dbType='postgres' 378 ):
379 ''' 380 Return the SQL CREATE command for this message type 381 @param outfile: file like object to print to. 382 @param fields: which fields to put in the create. Defaults to all. 383 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 384 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 385 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 386 @type addCoastGuardFields: bool 387 @return: sql create string 388 @rtype: str 389 390 @see: sqlCreate 391 ''' 392 # FIX: should this sqlCreate be the same as in LaTeX (createFuncName) rather than hard coded? 393 outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType)))
394
395 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'):
396 ''' 397 Return the sqlhelp object to create the table. 398 399 @param fields: which fields to put in the create. Defaults to all. 400 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 401 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 402 @type addCoastGuardFields: bool 403 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 404 @return: An object that can be used to generate a return 405 @rtype: sqlhelp.create 406 ''' 407 if None == fields: fields = fieldList 408 import sqlhelp 409 c = sqlhelp.create('sls_wind',dbType=dbType) 410 c.addPrimaryKey() 411 if 'time_month' in fields: c.addInt ('time_month') 412 if 'time_day' in fields: c.addInt ('time_day') 413 if 'time_hour' in fields: c.addInt ('time_hour') 414 if 'time_min' in fields: c.addInt ('time_min') 415 if 'stationid' in fields: c.addVarChar('stationid',7) 416 if dbType != 'postgres': 417 if 'pos_longitude' in fields: c.addDecimal('pos_longitude',7,4) 418 if dbType != 'postgres': 419 if 'pos_latitude' in fields: c.addDecimal('pos_latitude',7,4) 420 if 'flow' in fields: c.addInt ('flow') 421 if 'reserved' in fields: c.addInt ('reserved') 422 423 if addCoastGuardFields: 424 # c.addInt('cg_rssi') # Relative signal strength indicator 425 # c.addInt('cg_d') # dBm receive strength 426 # c.addInt('cg_T') # Receive timestamp from the AIS equipment 427 # c.addInt('cg_S') # Slot received in 428 # c.addVarChar('cg_x',10) # Idonno 429 c.addVarChar('cg_r',15) # Receiver station ID - should usually be an MMSI, but sometimes is a string 430 c.addInt('cg_sec') # UTC seconds since the epoch 431 432 c.addTimestamp('cg_timestamp') # UTC decoded cg_sec - not actually in the data stream 433 434 if dbType == 'postgres': 435 #--- EPSG 4326 : WGS 84 436 #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 '); 437 c.addPostGIS('pos','POINT',2,SRID=4326); 438 439 return c
440
441 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'):
442 ''' 443 Return the SQL INSERT command for this message type 444 @param params: dictionary of values keyed by field name 445 @param outfile: file like object to print to. 446 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields 447 @return: sql create string 448 @rtype: str 449 450 @see: sqlCreate 451 ''' 452 outfile.write(str(sqlInsert(params,extraParams,dbType=dbType)))
453 454
455 -def sqlInsert(params,extraParams=None,dbType='postgres'):
456 ''' 457 Give the SQL INSERT statement 458 @param params: dict keyed by field name of values 459 @param extraParams: any extra fields that you have created beyond the normal ais message fields 460 @rtype: sqlhelp.insert 461 @return: insert class instance 462 @todo: allow optional type checking of params? 463 @warning: this will take invalid keys happily and do what??? 464 ''' 465 import sqlhelp 466 i = sqlhelp.insert('sls_wind',dbType=dbType) 467 468 if dbType=='postgres': 469 finished = [] 470 for key in params: 471 if key in finished: 472 continue 473 474 if key not in toPgFields and key not in fromPgFields: 475 if type(params[key])==Decimal: i.add(key,float(params[key])) 476 else: i.add(key,params[key]) 477 else: 478 if key in fromPgFields: 479 val = params[key] 480 # Had better be a WKT type like POINT(-88.1 30.321) 481 i.addPostGIS(key,val) 482 finished.append(key) 483 else: 484 # Need to construct the type. 485 pgName = toPgFields[key] 486 #valStr='GeomFromText(\''+pgTypes[pgName]+'(' 487 valStr=pgTypes[pgName]+'(' 488 vals = [] 489 for nonPgKey in fromPgFields[pgName]: 490 vals.append(str(params[nonPgKey])) 491 finished.append(nonPgKey) 492 valStr+=' '.join(vals)+')' 493 i.addPostGIS(pgName,valStr) 494 else: 495 for key in params: 496 if type(params[key])==Decimal: i.add(key,float(params[key])) 497 else: i.add(key,params[key]) 498 499 if None != extraParams: 500 for key in extraParams: 501 i.add(key,extraParams[key]) 502 503 return i
504 505 ###################################################################### 506 # LATEX SUPPORT 507 ###################################################################### 508
509 -def latexDefinitionTable(outfile=sys.stdout 510 ):
511 ''' 512 Return the LaTeX definition table for this message type 513 @param outfile: file like object to print to. 514 @type outfile: file obj 515 @return: LaTeX table string via the outfile 516 @rtype: str 517 518 ''' 519 o = outfile 520 521 o.write(''' 522 \\begin{table}%[htb] 523 \\centering 524 \\begin{tabular}{|l|c|l|} 525 \\hline 526 Parameter & Number of bits & Description 527 \\\\ \\hline\\hline 528 time\_month & 4 & Time tag of measurement month 1..12 \\\\ \hline 529 time\_day & 5 & Time tag of measurement day of the month 1..31 \\\\ \hline 530 time\_hour & 5 & Time tag of measurement UTC hours 0..23 \\\\ \hline 531 time\_min & 6 & Time tag of measurement minutes \\\\ \hline 532 stationid & 42 & Character identifier of the station \\\\ \hline 533 pos\_longitude & 25 & Location of measurement East West location \\\\ \hline 534 pos\_latitude & 24 & Location of measurement North South location \\\\ \hline 535 flow & 10 & Water flow \\\\ \hline 536 reserved & 19 & Reserved bits for future use\\\\ \\hline \\hline 537 Total bits & 140 & Appears to take 1 slot with 28 pad bits to fill the last slot \\\\ \\hline 538 \\end{tabular} 539 \\caption{AIS message number 8: St Lawrance Seaway wind information} 540 \\label{tab:sls_wind} 541 \\end{table} 542 ''')
543 544 ###################################################################### 545 # Text Definition 546 ###################################################################### 547
548 -def textDefinitionTable(outfile=sys.stdout 549 ,delim='\t' 550 ):
551 ''' 552 Return the text definition table for this message type 553 @param outfile: file like object to print to. 554 @type outfile: file obj 555 @return: text table string via the outfile 556 @rtype: str 557 558 ''' 559 o = outfile 560 o.write('''Parameter'''+delim+'Number of bits'''+delim+'''Description 561 time_month'''+delim+'''4'''+delim+'''Time tag of measurement month 1..12 562 time_day'''+delim+'''5'''+delim+'''Time tag of measurement day of the month 1..31 563 time_hour'''+delim+'''5'''+delim+'''Time tag of measurement UTC hours 0..23 564 time_min'''+delim+'''6'''+delim+'''Time tag of measurement minutes 565 stationid'''+delim+'''42'''+delim+'''Character identifier of the station 566 pos_longitude'''+delim+'''25'''+delim+'''Location of measurement East West location 567 pos_latitude'''+delim+'''24'''+delim+'''Location of measurement North South location 568 flow'''+delim+'''10'''+delim+'''Water flow 569 reserved'''+delim+'''19'''+delim+'''Reserved bits for future use 570 Total bits'''+delim+'''140'''+delim+'''Appears to take 1 slot with 28 pad bits to fill the last slot''')
571 572 573 ###################################################################### 574 # UNIT TESTING 575 ###################################################################### 576 import unittest
577 -def testParams():
578 '''Return a params file base on the testvalue tags. 579 @rtype: dict 580 @return: params based on testvalue tags 581 ''' 582 params = {} 583 params['time_month'] = 2 584 params['time_day'] = 28 585 params['time_hour'] = 23 586 params['time_min'] = 45 587 params['stationid'] = 'A345678' 588 params['pos_longitude'] = Decimal('-122.16328') 589 params['pos_latitude'] = Decimal('37.42446') 590 params['flow'] = 43 591 params['reserved'] = 0 592 593 return params
594
595 -class Testsls_wind(unittest.TestCase):
596 '''Use testvalue tag text from each type to build test case the sls_wind message'''
597 - def testEncodeDecode(self):
598 599 params = testParams() 600 bits = encode(params) 601 r = decode(bits) 602 603 # Check that each parameter came through ok. 604 self.failUnlessEqual(r['time_month'],params['time_month']) 605 self.failUnlessEqual(r['time_day'],params['time_day']) 606 self.failUnlessEqual(r['time_hour'],params['time_hour']) 607 self.failUnlessEqual(r['time_min'],params['time_min']) 608 self.failUnlessEqual(r['stationid'],params['stationid']) 609 self.failUnlessAlmostEqual(r['pos_longitude'],params['pos_longitude'],4) 610 self.failUnlessAlmostEqual(r['pos_latitude'],params['pos_latitude'],4) 611 self.failUnlessEqual(r['flow'],params['flow']) 612 self.failUnlessEqual(r['reserved'],params['reserved'])
613
614 -def addMsgOptions(parser):
615 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true', 616 help='decode a "sls_wind" AIS message') 617 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true', 618 help='encode a "sls_wind" AIS message') 619 parser.add_option('--time_month-field', dest='time_monthField',metavar='uint',type='int' 620 ,help='Field parameter value [default: %default]') 621 parser.add_option('--time_day-field', dest='time_dayField',metavar='uint',type='int' 622 ,help='Field parameter value [default: %default]') 623 parser.add_option('--time_hour-field', dest='time_hourField',metavar='uint',type='int' 624 ,help='Field parameter value [default: %default]') 625 parser.add_option('--time_min-field', dest='time_minField',metavar='uint',type='int' 626 ,help='Field parameter value [default: %default]') 627 parser.add_option('--stationid-field', dest='stationidField',default='@@@@@@@',metavar='aisstr6',type='string' 628 ,help='Field parameter value [default: %default]') 629 parser.add_option('--pos_longitude-field', dest='pos_longitudeField',default=Decimal('181'),metavar='decimal',type='string' 630 ,help='Field parameter value [default: %default]') 631 parser.add_option('--pos_latitude-field', dest='pos_latitudeField',default=Decimal('91'),metavar='decimal',type='string' 632 ,help='Field parameter value [default: %default]') 633 parser.add_option('--flow-field', dest='flowField',default=16383,metavar='uint',type='int' 634 ,help='Field parameter value [default: %default]')
635 636 ############################################################ 637 if __name__=='__main__': 638 639 from optparse import OptionParser 640 parser = OptionParser(usage="%prog [options]", 641 version="%prog "+__version__) 642 643 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true', 644 help='run the documentation tests') 645 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true', 646 help='run the unit tests') 647 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 648 help='Make the test output verbose') 649 650 # FIX: remove nmea from binary messages. No way to build the whole packet? 651 # FIX: or build the surrounding msg 8 for a broadcast? 652 typeChoices = ('binary','nmeapayload','nmea') # FIX: what about a USCG type message? 653 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType' 654 ,default='nmeapayload' 655 ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]') 656 657 658 outputChoices = ('std','html','csv','sql' , 'kml','kml-full') 659 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType' 660 ,default='std' 661 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]') 662 663 parser.add_option('-o','--output',dest='outputFileName',default=None, 664 help='Name of the python file to write [default: stdout]') 665 666 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append', 667 choices=fieldList, 668 help='Which fields to include in the output. Currently only for csv output [default: all]') 669 670 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true', 671 help='Print the field name for csv') 672 673 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true', 674 help='Print out an sql create command for the table.') 675 676 parser.add_option('--latex-table',dest='latexDefinitionTable',default=False,action='store_true', 677 help='Print a LaTeX table of the type') 678 679 parser.add_option('--text-table',dest='textDefinitionTable',default=False,action='store_true', 680 help='Print delimited table of the type (for Word table importing)') 681 parser.add_option('--delimt-text-table',dest='delimTextDefinitionTable',default='\t' 682 ,help='Delimiter for text table [default: \'%default\'](for Word table importing)') 683 684 685 dbChoices = ('sqlite','postgres') 686 parser.add_option('-D','--db-type',dest='dbType',default='postgres' 687 ,choices=dbChoices,type='choice' 688 ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]') 689 690 addMsgOptions(parser) 691 692 (options,args) = parser.parse_args() 693 success=True 694 695 if options.doctest: 696 import os; print os.path.basename(sys.argv[0]), 'doctests ...', 697 sys.argv= [sys.argv[0]] 698 if options.verbose: sys.argv.append('-v') 699 import doctest 700 numfail,numtests=doctest.testmod() 701 if numfail==0: print 'ok' 702 else: 703 print 'FAILED' 704 success=False 705 706 if not success: sys.exit('Something Failed') 707 del success # Hide success from epydoc 708 709 if options.unittest: 710 sys.argv = [sys.argv[0]] 711 if options.verbose: sys.argv.append('-v') 712 unittest.main() 713 714 outfile = sys.stdout 715 if None!=options.outputFileName: 716 outfile = file(options.outputFileName,'w') 717 718 719 if options.doEncode: 720 # First make sure all non required options are specified 721 if None==options.time_monthField: parser.error("missing value for time_monthField") 722 if None==options.time_dayField: parser.error("missing value for time_dayField") 723 if None==options.time_hourField: parser.error("missing value for time_hourField") 724 if None==options.time_minField: parser.error("missing value for time_minField") 725 if None==options.stationidField: parser.error("missing value for stationidField") 726 if None==options.pos_longitudeField: parser.error("missing value for pos_longitudeField") 727 if None==options.pos_latitudeField: parser.error("missing value for pos_latitudeField") 728 if None==options.flowField: parser.error("missing value for flowField") 729 msgDict={ 730 'time_month': options.time_monthField, 731 'time_day': options.time_dayField, 732 'time_hour': options.time_hourField, 733 'time_min': options.time_minField, 734 'stationid': options.stationidField, 735 'pos_longitude': options.pos_longitudeField, 736 'pos_latitude': options.pos_latitudeField, 737 'flow': options.flowField, 738 'reserved': '0', 739 } 740 741 bits = encode(msgDict) 742 if 'binary'==options.ioType: print str(bits) 743 elif 'nmeapayload'==options.ioType: 744 # FIX: figure out if this might be necessary at compile time 745 print "bitLen",len(bits) 746 bitLen=len(bits) 747 if bitLen%6!=0: 748 bits = bits + BitVector(size=(6 - (bitLen%6))) # Pad out to multiple of 6 749 print "result:",binary.bitvectoais6(bits)[0] 750 751 752 # FIX: Do not emit this option for the binary message payloads. Does not make sense. 753 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability") 754 else: sys.exit('ERROR: unknown ioType. Help!') 755 756 757 if options.sqlCreate: 758 sqlCreateStr(outfile,options.fieldList,dbType=options.dbType) 759 760 if options.latexDefinitionTable: 761 latexDefinitionTable(outfile) 762 763 # For conversion to word tables 764 if options.textDefinitionTable: 765 textDefinitionTable(outfile,options.delimTextDefinitionTable) 766 767 if options.printCsvfieldList: 768 # Make a csv separated list of fields that will be displayed for csv 769 if None == options.fieldList: options.fieldList = fieldList 770 import StringIO 771 buf = StringIO.StringIO() 772 for field in options.fieldList: 773 buf.write(field+',') 774 result = buf.getvalue() 775 if result[-1] == ',': print result[:-1] 776 else: print result 777 778 if options.doDecode: 779 if len(args)==0: args = sys.stdin 780 for msg in args: 781 bv = None 782 783 if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'): 784 # Found nmea 785 # FIX: do checksum 786 bv = binary.ais6tobitvec(msg.split(',')[5]) 787 else: # either binary or nmeapayload... expect mostly nmeapayloads 788 # assumes that an all 0 and 1 string can not be a nmeapayload 789 binaryMsg=True 790 for c in msg: 791 if c not in ('0','1'): 792 binaryMsg=False 793 break 794 if binaryMsg: 795 bv = BitVector(bitstring=msg) 796 else: # nmeapayload 797 bv = binary.ais6tobitvec(msg) 798 799 printFields(decode(bv) 800 ,out=outfile 801 ,format=options.outputType 802 ,fieldList=options.fieldList 803 ,dbType=options.dbType 804 ) 805