1   
  2   
  3  __version__ = '$Revision: 4791 $'.split()[1] 
  4  __date__ = '$Date: 2008-01-11 $'.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   
 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          'lockid', 
 55          'pos_longitude', 
 56          'pos_latitude', 
 57          'reserved', 
 58          'lockschedules', 
 59  ) 
 60   
 61  fieldListPostgres = ( 
 62          'time_month', 
 63          'time_day', 
 64          'time_hour', 
 65          'time_min', 
 66          'lockid', 
 67          'pos',   
 68          'reserved', 
 69          'lockschedules', 
 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_lockorder binary message payload to pack into an AIS Msg sls_lockorder. 
 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            - lockid(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            - reserved(uint): Reserved bits for future use (field automatically set to "0") 
106            - lockschedules(binary): up to 6 lock schedule reports 
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 'lockid' in params: 
120                  bvList.append(aisstring.encode(params['lockid'],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          bvList.append(binary.setBitVectorSize(BitVector(intVal=0),19)) 
132          bvList.append(params['lockschedules']) 
133   
134          return binary.joinBV(bvList) 
 135   
136 -def decode(bv, validate=False): 
 137          '''Unpack a sls_lockorder message  
138   
139          Fields in params: 
140            - time_month(uint): Time tag of measurement  month 1..12 
141            - time_day(uint): Time tag of measurement  day of the month 1..31 
142            - time_hour(uint): Time tag of measurement  UTC hours 0..23 
143            - time_min(uint): Time tag of measurement  minutes 
144            - lockid(aisstr6): Character identifier of the station 
145            - pos_longitude(decimal): Location of measurement  East West location 
146            - pos_latitude(decimal): Location of measurement  North South location 
147            - reserved(uint): Reserved bits for future use (field automatically set to "0") 
148            - lockschedules(binary): up to 6 lock schedule reports 
149          @type bv: BitVector 
150          @param bv: Bits defining a message 
151          @param validate: Set to true to cause checking to occur.  Runs slower.  FIX: not implemented. 
152          @rtype: dict 
153          @return: params 
154          ''' 
155   
156           
157           
158           
159          r = {} 
160          r['time_month']=int(bv[0:4]) 
161          r['time_day']=int(bv[4:9]) 
162          r['time_hour']=int(bv[9:14]) 
163          r['time_min']=int(bv[14:20]) 
164          r['lockid']=aisstring.decode(bv[20:62]) 
165          r['pos_longitude']=Decimal(binary.signedIntFromBV(bv[62:87]))/Decimal('60000') 
166          r['pos_latitude']=Decimal(binary.signedIntFromBV(bv[87:111]))/Decimal('60000') 
167          r['reserved']=0 
168          r['lockschedules']=bv[130:] 
169          return r 
 170   
173   
176   
179   
181          return int(bv[14:20]) 
 182   
185   
188   
191   
194   
197   
198   
200                  out.write("<h3>sls_lockorder</h3>\n") 
201                  out.write("<table border=\"1\">\n") 
202                  out.write("<tr bgcolor=\"orange\">\n") 
203                  out.write("<th align=\"left\">Field Name</th>\n") 
204                  out.write("<th align=\"left\">Type</th>\n") 
205                  out.write("<th align=\"left\">Value</th>\n") 
206                  out.write("<th align=\"left\">Value in Lookup Table</th>\n") 
207                  out.write("<th align=\"left\">Units</th>\n") 
208                  out.write("\n") 
209                  out.write("<tr>\n") 
210                  out.write("<td>time_month</td>\n") 
211                  out.write("<td>uint</td>\n") 
212                  if 'time_month' in params: 
213                          out.write("     <td>"+str(params['time_month'])+"</td>\n") 
214                          out.write("     <td>"+str(params['time_month'])+"</td>\n") 
215                  out.write("</tr>\n") 
216                  out.write("\n") 
217                  out.write("<tr>\n") 
218                  out.write("<td>time_day</td>\n") 
219                  out.write("<td>uint</td>\n") 
220                  if 'time_day' in params: 
221                          out.write("     <td>"+str(params['time_day'])+"</td>\n") 
222                          out.write("     <td>"+str(params['time_day'])+"</td>\n") 
223                  out.write("</tr>\n") 
224                  out.write("\n") 
225                  out.write("<tr>\n") 
226                  out.write("<td>time_hour</td>\n") 
227                  out.write("<td>uint</td>\n") 
228                  if 'time_hour' in params: 
229                          out.write("     <td>"+str(params['time_hour'])+"</td>\n") 
230                          out.write("     <td>"+str(params['time_hour'])+"</td>\n") 
231                  out.write("</tr>\n") 
232                  out.write("\n") 
233                  out.write("<tr>\n") 
234                  out.write("<td>time_min</td>\n") 
235                  out.write("<td>uint</td>\n") 
236                  if 'time_min' in params: 
237                          out.write("     <td>"+str(params['time_min'])+"</td>\n") 
238                          out.write("     <td>"+str(params['time_min'])+"</td>\n") 
239                  out.write("</tr>\n") 
240                  out.write("\n") 
241                  out.write("<tr>\n") 
242                  out.write("<td>lockid</td>\n") 
243                  out.write("<td>aisstr6</td>\n") 
244                  if 'lockid' in params: 
245                          out.write("     <td>"+str(params['lockid'])+"</td>\n") 
246                          out.write("     <td>"+str(params['lockid'])+"</td>\n") 
247                  out.write("</tr>\n") 
248                  out.write("\n") 
249                  out.write("<tr>\n") 
250                  out.write("<td>pos_longitude</td>\n") 
251                  out.write("<td>decimal</td>\n") 
252                  if 'pos_longitude' in params: 
253                          out.write("     <td>"+str(params['pos_longitude'])+"</td>\n") 
254                          out.write("     <td>"+str(params['pos_longitude'])+"</td>\n") 
255                  out.write("<td>degrees</td>\n") 
256                  out.write("</tr>\n") 
257                  out.write("\n") 
258                  out.write("<tr>\n") 
259                  out.write("<td>pos_latitude</td>\n") 
260                  out.write("<td>decimal</td>\n") 
261                  if 'pos_latitude' in params: 
262                          out.write("     <td>"+str(params['pos_latitude'])+"</td>\n") 
263                          out.write("     <td>"+str(params['pos_latitude'])+"</td>\n") 
264                  out.write("<td>degrees</td>\n") 
265                  out.write("</tr>\n") 
266                  out.write("\n") 
267                  out.write("<tr>\n") 
268                  out.write("<td>reserved</td>\n") 
269                  out.write("<td>uint</td>\n") 
270                  if 'reserved' in params: 
271                          out.write("     <td>"+str(params['reserved'])+"</td>\n") 
272                          out.write("     <td>"+str(params['reserved'])+"</td>\n") 
273                  out.write("</tr>\n") 
274                  out.write("\n") 
275                  out.write("<tr>\n") 
276                  out.write("<td>lockschedules</td>\n") 
277                  out.write("<td>binary</td>\n") 
278                  if 'lockschedules' in params: 
279                          out.write("     <td>"+str(params['lockschedules'])+"</td>\n") 
280                          out.write("     <td>"+str(params['lockschedules'])+"</td>\n") 
281                  out.write("</tr>\n") 
282                  out.write("</table>\n") 
 283   
284   
286          '''KML (Keyhole Markup Language) for Google Earth, but without the header/footer''' 
287          out.write("\    <Placemark>\n") 
288          out.write("\t   <name>"+str(params['lockid'])+"</name>\n") 
289          out.write("\t\t<description>\n") 
290          import StringIO 
291          buf = StringIO.StringIO() 
292          printHtml(params,buf) 
293          import cgi 
294          out.write(cgi.escape(buf.getvalue())) 
295          out.write("\t\t</description>\n") 
296          out.write("\t\t<styleUrl>#m_ylw-pushpin_copy0</styleUrl>\n") 
297          out.write("\t\t<Point>\n") 
298          out.write("\t\t\t<coordinates>") 
299          out.write(str(params['pos_longitude'])) 
300          out.write(',') 
301          out.write(str(params['pos_latitude'])) 
302          out.write(",0</coordinates>\n") 
303          out.write("\t\t</Point>\n") 
304          out.write("\t</Placemark>\n") 
 305   
306 -def printFields(params, out=sys.stdout, format='std', fieldList=None, dbType='postgres'): 
 307          '''Print a sls_lockorder message to stdout. 
308   
309          Fields in params: 
310            - time_month(uint): Time tag of measurement  month 1..12 
311            - time_day(uint): Time tag of measurement  day of the month 1..31 
312            - time_hour(uint): Time tag of measurement  UTC hours 0..23 
313            - time_min(uint): Time tag of measurement  minutes 
314            - lockid(aisstr6): Character identifier of the station 
315            - pos_longitude(decimal): Location of measurement  East West location 
316            - pos_latitude(decimal): Location of measurement  North South location 
317            - reserved(uint): Reserved bits for future use (field automatically set to "0") 
318            - lockschedules(binary): up to 6 lock schedule reports 
319          @param params: Dictionary of field names/values.   
320          @param out: File like object to write to 
321          @rtype: stdout 
322          @return: text to out 
323          ''' 
324   
325          if 'std'==format: 
326                  out.write("sls_lockorder:\n") 
327                  if 'time_month' in params: out.write("  time_month:     "+str(params['time_month'])+"\n") 
328                  if 'time_day' in params: out.write("    time_day:       "+str(params['time_day'])+"\n") 
329                  if 'time_hour' in params: out.write("   time_hour:      "+str(params['time_hour'])+"\n") 
330                  if 'time_min' in params: out.write("    time_min:       "+str(params['time_min'])+"\n") 
331                  if 'lockid' in params: out.write("      lockid:         "+str(params['lockid'])+"\n") 
332                  if 'pos_longitude' in params: out.write("       pos_longitude:  "+str(params['pos_longitude'])+"\n") 
333                  if 'pos_latitude' in params: out.write("        pos_latitude:   "+str(params['pos_latitude'])+"\n") 
334                  if 'reserved' in params: out.write("    reserved:       "+str(params['reserved'])+"\n") 
335                  if 'lockschedules' in params: out.write("       lockschedules:  "+str(params['lockschedules'])+"\n") 
336          elif 'csv'==format: 
337                  if None == options.fieldList: 
338                          options.fieldList = fieldList 
339                  needComma = False; 
340                  for field in fieldList: 
341                          if needComma: out.write(',') 
342                          needComma = True 
343                          if field in params: 
344                                  out.write(str(params[field])) 
345                           
346                  out.write("\n") 
347          elif 'html'==format: 
348                  printHtml(params,out) 
349          elif 'sql'==format: 
350                  sqlInsertStr(params,out,dbType=dbType) 
351          elif 'kml'==format: 
352                  printKml(params,out) 
353          elif 'kml-full'==format: 
354                  out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") 
355                  out.write("<kml xmlns=\"http://earth.google.com/kml/2.1\">\n") 
356                  out.write("<Document>\n") 
357                  out.write("     <name>sls_lockorder</name>\n") 
358                  printKml(params,out) 
359                  out.write("</Document>\n") 
360                  out.write("</kml>\n") 
361          else:  
362                  print "ERROR: unknown format:",format 
363                  assert False 
364   
365          return  
 366   
367   
368   
369   
370   
371  dbTableName='sls_lockorder' 
372  'Database table name' 
373   
374 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None 
375                  ,addCoastGuardFields=True 
376                  ,dbType='postgres' 
377                  ): 
 378          ''' 
379          Return the SQL CREATE command for this message type 
380          @param outfile: file like object to print to. 
381          @param fields: which fields to put in the create.  Defaults to all. 
382          @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 
383          @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 
384          @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 
385          @type addCoastGuardFields: bool 
386          @return: sql create string 
387          @rtype: str 
388   
389          @see: sqlCreate 
390          ''' 
391           
392          outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType))) 
 393   
394 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'): 
 395          ''' 
396          Return the sqlhelp object to create the table. 
397   
398          @param fields: which fields to put in the create.  Defaults to all. 
399          @param extraFields: A sequence of tuples containing (name,sql type) for additional fields 
400          @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format 
401          @type addCoastGuardFields: bool 
402          @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres') 
403          @return: An object that can be used to generate a return 
404          @rtype: sqlhelp.create 
405          ''' 
406          if None == fields: fields = fieldList 
407          import sqlhelp 
408          c = sqlhelp.create('sls_lockorder',dbType=dbType) 
409          c.addPrimaryKey() 
410          if 'time_month' in fields: c.addInt ('time_month') 
411          if 'time_day' in fields: c.addInt ('time_day') 
412          if 'time_hour' in fields: c.addInt ('time_hour') 
413          if 'time_min' in fields: c.addInt ('time_min') 
414          if 'lockid' in fields: c.addVarChar('lockid',7) 
415          if dbType != 'postgres': 
416                  if 'pos_longitude' in fields: c.addDecimal('pos_longitude',7,4) 
417          if dbType != 'postgres': 
418                  if 'pos_latitude' in fields: c.addDecimal('pos_latitude',7,4) 
419          if 'reserved' in fields: c.addInt ('reserved') 
420          if 'lockschedules' in fields: c.addBitVarying('lockschedules',1024) 
421   
422          if addCoastGuardFields: 
423                   
424                   
425                   
426                   
427                   
428                  c.addVarChar('cg_r',15)    
429                  c.addInt('cg_sec')         
430   
431                  c.addTimestamp('cg_timestamp')  
432   
433          if dbType == 'postgres': 
434                   
435                   
436                  c.addPostGIS('pos','POINT',2,SRID=4326); 
437   
438          return c 
 439   
440 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'): 
 441          ''' 
442          Return the SQL INSERT command for this message type 
443          @param params: dictionary of values keyed by field name 
444          @param outfile: file like object to print to. 
445          @param extraParams: A sequence of tuples containing (name,sql type) for additional fields 
446          @return: sql create string 
447          @rtype: str 
448   
449          @see: sqlCreate 
450          ''' 
451          outfile.write(str(sqlInsert(params,extraParams,dbType=dbType))) 
 452   
453   
454 -def sqlInsert(params,extraParams=None,dbType='postgres'): 
 455          ''' 
456          Give the SQL INSERT statement 
457          @param params: dict keyed by field name of values 
458          @param extraParams: any extra fields that you have created beyond the normal ais message fields 
459          @rtype: sqlhelp.insert 
460          @return: insert class instance 
461          @todo: allow optional type checking of params? 
462          @warning: this will take invalid keys happily and do what??? 
463          ''' 
464          import sqlhelp 
465          i = sqlhelp.insert('sls_lockorder',dbType=dbType) 
466   
467          if dbType=='postgres': 
468                  finished = [] 
469                  for key in params: 
470                          if key in finished:  
471                                  continue 
472   
473                          if key not in toPgFields and key not in fromPgFields: 
474                                  if type(params[key])==Decimal: i.add(key,float(params[key])) 
475                                  else: i.add(key,params[key]) 
476                          else: 
477                                  if key in fromPgFields: 
478                                          val = params[key] 
479                                           
480                                          i.addPostGIS(key,val) 
481                                          finished.append(key) 
482                                  else: 
483                                           
484                                          pgName = toPgFields[key] 
485                                           
486                                          valStr=pgTypes[pgName]+'(' 
487                                          vals = [] 
488                                          for nonPgKey in fromPgFields[pgName]: 
489                                                  vals.append(str(params[nonPgKey])) 
490                                                  finished.append(nonPgKey) 
491                                          valStr+=' '.join(vals)+')' 
492                                          i.addPostGIS(pgName,valStr) 
493          else: 
494                  for key in params:  
495                          if type(params[key])==Decimal: i.add(key,float(params[key])) 
496                          else: i.add(key,params[key]) 
497   
498          if None != extraParams: 
499                  for key in extraParams:  
500                          i.add(key,extraParams[key]) 
501   
502          return i 
 503   
504   
505   
506   
507   
510          ''' 
511          Return the LaTeX definition table for this message type 
512          @param outfile: file like object to print to. 
513          @type outfile: file obj 
514          @return: LaTeX table string via the outfile 
515          @rtype: str 
516   
517          ''' 
518          o = outfile 
519   
520          o.write(''' 
521  \\begin{table}%[htb] 
522  \\centering 
523  \\begin{tabular}{|l|c|l|} 
524  \\hline 
525  Parameter & Number of bits & Description  
526  \\\\  \\hline\\hline 
527  time\_month & 4 & Time tag of measurement  month 1..12 \\\\ \hline  
528  time\_day & 5 & Time tag of measurement  day of the month 1..31 \\\\ \hline  
529  time\_hour & 5 & Time tag of measurement  UTC hours 0..23 \\\\ \hline  
530  time\_min & 6 & Time tag of measurement  minutes \\\\ \hline  
531  lockid & 42 & Character identifier of the station \\\\ \hline  
532  pos\_longitude & 25 & Location of measurement  East West location \\\\ \hline  
533  pos\_latitude & 24 & Location of measurement  North South location \\\\ \hline  
534  reserved & 19 & Reserved bits for future use \\\\ \hline  
535  lockschedules & -1 & up to 6 lock schedule reports\\\\ \\hline \\hline 
536  Total bits & 129 & Appears to take 1 slot with 39 pad bits to fill the last slot \\\\ \\hline 
537  \\end{tabular} 
538  \\caption{AIS message number 8: St Lawrance Seaway wind information} 
539  \\label{tab:sls_lockorder} 
540  \\end{table} 
541  ''') 
 542   
543   
544   
545   
546   
547 -def textDefinitionTable(outfile=sys.stdout 
548                  ,delim='\t' 
549                  ): 
 550          ''' 
551          Return the text definition table for this message type 
552          @param outfile: file like object to print to. 
553          @type outfile: file obj 
554          @return: text table string via the outfile 
555          @rtype: str 
556   
557          ''' 
558          o = outfile 
559          o.write('''Parameter'''+delim+'Number of bits'''+delim+'''Description  
560  time_month'''+delim+'''4'''+delim+'''Time tag of measurement  month 1..12 
561  time_day'''+delim+'''5'''+delim+'''Time tag of measurement  day of the month 1..31 
562  time_hour'''+delim+'''5'''+delim+'''Time tag of measurement  UTC hours 0..23 
563  time_min'''+delim+'''6'''+delim+'''Time tag of measurement  minutes 
564  lockid'''+delim+'''42'''+delim+'''Character identifier of the station 
565  pos_longitude'''+delim+'''25'''+delim+'''Location of measurement  East West location 
566  pos_latitude'''+delim+'''24'''+delim+'''Location of measurement  North South location 
567  reserved'''+delim+'''19'''+delim+'''Reserved bits for future use 
568  lockschedules'''+delim+'''-1'''+delim+'''up to 6 lock schedule reports 
569  Total bits'''+delim+'''129'''+delim+'''Appears to take 1 slot with 39 pad bits to fill the last slot''') 
 570   
571   
572   
573   
574   
575  import unittest 
577          '''Return a params file base on the testvalue tags. 
578          @rtype: dict 
579          @return: params based on testvalue tags 
580          ''' 
581          params = {} 
582          params['time_month'] = 2 
583          params['time_day'] = 28 
584          params['time_hour'] = 23 
585          params['time_min'] = 45 
586          params['lockid'] = 'A345678' 
587          params['pos_longitude'] = Decimal('-122.16328') 
588          params['pos_latitude'] = Decimal('37.42446') 
589          params['reserved'] = 0 
590          params['lockschedules'] = BitVector(bitstring='0001010101010000') 
591   
592          return params 
 593   
595          '''Use testvalue tag text from each type to build test case the sls_lockorder message''' 
597   
598                  params = testParams() 
599                  bits   = encode(params) 
600                  r      = decode(bits) 
601   
602                   
603                  self.failUnlessEqual(r['time_month'],params['time_month']) 
604                  self.failUnlessEqual(r['time_day'],params['time_day']) 
605                  self.failUnlessEqual(r['time_hour'],params['time_hour']) 
606                  self.failUnlessEqual(r['time_min'],params['time_min']) 
607                  self.failUnlessEqual(r['lockid'],params['lockid']) 
608                  self.failUnlessAlmostEqual(r['pos_longitude'],params['pos_longitude'],4) 
609                  self.failUnlessAlmostEqual(r['pos_latitude'],params['pos_latitude'],4) 
610                  self.failUnlessEqual(r['reserved'],params['reserved']) 
611                  self.failUnlessEqual(r['lockschedules'],params['lockschedules']) 
  612   
614          parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true', 
615                  help='decode a "sls_lockorder" AIS message') 
616          parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true', 
617                  help='encode a "sls_lockorder" AIS message') 
618          parser.add_option('--time_month-field', dest='time_monthField',metavar='uint',type='int' 
619                  ,help='Field parameter value [default: %default]') 
620          parser.add_option('--time_day-field', dest='time_dayField',metavar='uint',type='int' 
621                  ,help='Field parameter value [default: %default]') 
622          parser.add_option('--time_hour-field', dest='time_hourField',metavar='uint',type='int' 
623                  ,help='Field parameter value [default: %default]') 
624          parser.add_option('--time_min-field', dest='time_minField',metavar='uint',type='int' 
625                  ,help='Field parameter value [default: %default]') 
626          parser.add_option('--lockid-field', dest='lockidField',default='@@@@@@@',metavar='aisstr6',type='string' 
627                  ,help='Field parameter value [default: %default]') 
628          parser.add_option('--pos_longitude-field', dest='pos_longitudeField',default=Decimal('181'),metavar='decimal',type='string' 
629                  ,help='Field parameter value [default: %default]') 
630          parser.add_option('--pos_latitude-field', dest='pos_latitudeField',default=Decimal('91'),metavar='decimal',type='string' 
631                  ,help='Field parameter value [default: %default]') 
632          parser.add_option('--lockschedules-field', dest='lockschedulesField',metavar='binary',type='string' 
633                  ,help='Field parameter value [default: %default]') 
 634   
635   
636  if __name__=='__main__': 
637   
638          from optparse import OptionParser 
639          parser = OptionParser(usage="%prog [options]", 
640                  version="%prog "+__version__) 
641   
642          parser.add_option('--doc-test',dest='doctest',default=False,action='store_true', 
643                  help='run the documentation tests') 
644          parser.add_option('--unit-test',dest='unittest',default=False,action='store_true', 
645                  help='run the unit tests') 
646          parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 
647                  help='Make the test output verbose') 
648   
649           
650           
651          typeChoices = ('binary','nmeapayload','nmea')  
652          parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType' 
653                  ,default='nmeapayload' 
654                  ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]') 
655   
656   
657          outputChoices = ('std','html','csv','sql' , 'kml','kml-full') 
658          parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType' 
659                  ,default='std' 
660                  ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]') 
661   
662          parser.add_option('-o','--output',dest='outputFileName',default=None, 
663                            help='Name of the python file to write [default: stdout]') 
664   
665          parser.add_option('-f','--fields',dest='fieldList',default=None, action='append', 
666                            choices=fieldList, 
667                            help='Which fields to include in the output.  Currently only for csv output [default: all]') 
668   
669          parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true', 
670                            help='Print the field name for csv') 
671   
672          parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true', 
673                            help='Print out an sql create command for the table.') 
674   
675          parser.add_option('--latex-table',dest='latexDefinitionTable',default=False,action='store_true', 
676                            help='Print a LaTeX table of the type') 
677   
678          parser.add_option('--text-table',dest='textDefinitionTable',default=False,action='store_true', 
679                            help='Print delimited table of the type (for Word table importing)') 
680          parser.add_option('--delimt-text-table',dest='delimTextDefinitionTable',default='\t' 
681                            ,help='Delimiter for text table [default: \'%default\'](for Word table importing)') 
682   
683   
684          dbChoices = ('sqlite','postgres') 
685          parser.add_option('-D','--db-type',dest='dbType',default='postgres' 
686                            ,choices=dbChoices,type='choice' 
687                            ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]') 
688   
689          addMsgOptions(parser) 
690   
691          (options,args) = parser.parse_args() 
692          success=True 
693   
694          if options.doctest: 
695                  import os; print os.path.basename(sys.argv[0]), 'doctests ...', 
696                  sys.argv= [sys.argv[0]] 
697                  if options.verbose: sys.argv.append('-v') 
698                  import doctest 
699                  numfail,numtests=doctest.testmod() 
700                  if numfail==0: print 'ok' 
701                  else:  
702                          print 'FAILED' 
703                          success=False 
704   
705          if not success: sys.exit('Something Failed') 
706          del success  
707   
708          if options.unittest: 
709                  sys.argv = [sys.argv[0]] 
710                  if options.verbose: sys.argv.append('-v') 
711                  unittest.main() 
712   
713          outfile = sys.stdout 
714          if None!=options.outputFileName: 
715                  outfile = file(options.outputFileName,'w') 
716   
717   
718          if options.doEncode: 
719                   
720                  if None==options.time_monthField: parser.error("missing value for time_monthField") 
721                  if None==options.time_dayField: parser.error("missing value for time_dayField") 
722                  if None==options.time_hourField: parser.error("missing value for time_hourField") 
723                  if None==options.time_minField: parser.error("missing value for time_minField") 
724                  if None==options.lockidField: parser.error("missing value for lockidField") 
725                  if None==options.pos_longitudeField: parser.error("missing value for pos_longitudeField") 
726                  if None==options.pos_latitudeField: parser.error("missing value for pos_latitudeField") 
727                  if None==options.lockschedulesField: parser.error("missing value for lockschedulesField") 
728                  msgDict={ 
729                          'time_month': options.time_monthField, 
730                          'time_day': options.time_dayField, 
731                          'time_hour': options.time_hourField, 
732                          'time_min': options.time_minField, 
733                          'lockid': options.lockidField, 
734                          'pos_longitude': options.pos_longitudeField, 
735                          'pos_latitude': options.pos_latitudeField, 
736                          'reserved': '0', 
737                          'lockschedules': options.lockschedulesField, 
738                  } 
739   
740                  bits = encode(msgDict) 
741                  if 'binary'==options.ioType: print str(bits) 
742                  elif 'nmeapayload'==options.ioType: 
743                           
744                          print "bitLen",len(bits) 
745                          bitLen=len(bits) 
746                          if bitLen%6!=0: 
747                              bits = bits + BitVector(size=(6 - (bitLen%6)))   
748                          print "result:",binary.bitvectoais6(bits)[0] 
749   
750   
751                   
752                  elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability") 
753                  else: sys.exit('ERROR: unknown ioType.  Help!') 
754   
755   
756          if options.sqlCreate: 
757                  sqlCreateStr(outfile,options.fieldList,dbType=options.dbType) 
758   
759          if options.latexDefinitionTable: 
760                  latexDefinitionTable(outfile) 
761   
762           
763          if options.textDefinitionTable: 
764                  textDefinitionTable(outfile,options.delimTextDefinitionTable) 
765   
766          if options.printCsvfieldList: 
767                   
768                  if None == options.fieldList: options.fieldList = fieldList 
769                  import StringIO 
770                  buf = StringIO.StringIO() 
771                  for field in options.fieldList: 
772                          buf.write(field+',') 
773                  result = buf.getvalue() 
774                  if result[-1] == ',': print result[:-1] 
775                  else: print result 
776   
777          if options.doDecode: 
778                  if len(args)==0: args = sys.stdin 
779                  for msg in args: 
780                          bv = None 
781   
782                          if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'): 
783                                   
784                                   
785                                  bv = binary.ais6tobitvec(msg.split(',')[5]) 
786                          else:  
787                                   
788                                  binaryMsg=True 
789                                  for c in msg: 
790                                          if c not in ('0','1'): 
791                                                  binaryMsg=False 
792                                                  break 
793                                  if binaryMsg: 
794                                          bv = BitVector(bitstring=msg) 
795                                  else:  
796                                          bv = binary.ais6tobitvec(msg) 
797   
798                          printFields(decode(bv) 
799                                      ,out=outfile 
800                                      ,format=options.outputType 
801                                      ,fieldList=options.fieldList 
802                                      ,dbType=options.dbType 
803                                      ) 
804