1
2
3 __version__ = '$Revision: 4791 $'.split()[1]
4 __date__ = '$Date: 2007-04-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
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 'speed',
58 'gust',
59 'direction',
60 'atmpressure',
61 'airtemp',
62 'dewpoint',
63 'visibility',
64 'watertemp',
65 'reserved',
66 )
67
68 fieldListPostgres = (
69 'time_month',
70 'time_day',
71 'time_hour',
72 'time_min',
73 'stationid',
74 'pos',
75 'speed',
76 'gust',
77 'direction',
78 'atmpressure',
79 'airtemp',
80 'dewpoint',
81 'visibility',
82 'watertemp',
83 'reserved',
84 )
85
86 toPgFields = {
87 'pos_longitude':'pos',
88 'pos_latitude':'pos',
89 }
90 '''
91 Go to the Postgis field names from the straight field name
92 '''
93
94 fromPgFields = {
95 'pos':('pos_longitude','pos_latitude',),
96 }
97 '''
98 Go from the Postgis field names to the straight field name
99 '''
100
101 pgTypes = {
102 'pos':'POINT',
103 }
104 '''
105 Lookup table for each postgis field name to get its type.
106 '''
107
108 -def encode(params, validate=False):
109 '''Create a sls_weatherreport binary message payload to pack into an AIS Msg sls_weatherreport.
110
111 Fields in params:
112 - time_month(uint): Time tag of measurement month 1..12
113 - time_day(uint): Time tag of measurement day of the month 1..31
114 - time_hour(uint): Time tag of measurement UTC hours 0..23
115 - time_min(uint): Time tag of measurement minutes
116 - stationid(aisstr6): Character identifier of the station
117 - pos_longitude(decimal): Location of measurement East West location
118 - pos_latitude(decimal): Location of measurement North South location
119 - speed(udecimal): Average wind speed
120 - gust(udecimal): Wind gust
121 - direction(uint): Wind direction
122 - atmpressure(udecimal): Atmospheric pressure
123 - airtemp(decimal): Air temperature
124 - dewpoint(decimal): Dew Point
125 - visibility(udecimal): Visibility
126 - watertemp(decimal): Water Temperature
127 - reserved(uint): Reserved bits for future use (field automatically set to "0")
128 @param params: Dictionary of field names/values. Throws a ValueError exception if required is missing
129 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented.
130 @rtype: BitVector
131 @return: encoded binary message (for binary messages, this needs to be wrapped in a msg 8
132 @note: The returned bits may not be 6 bit aligned. It is up to you to pad out the bits.
133 '''
134
135 bvList = []
136 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time_month']),4))
137 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time_day']),5))
138 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time_hour']),5))
139 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['time_min']),6))
140 if 'stationid' in params:
141 bvList.append(aisstring.encode(params['stationid'],42))
142 else:
143 bvList.append(aisstring.encode('@@@@@@@',42))
144 if 'pos_longitude' in params:
145 bvList.append(binary.bvFromSignedInt(int(Decimal(params['pos_longitude'])*Decimal('60000')),25))
146 else:
147 bvList.append(binary.bvFromSignedInt(10860000,25))
148 if 'pos_latitude' in params:
149 bvList.append(binary.bvFromSignedInt(int(Decimal(params['pos_latitude'])*Decimal('60000')),24))
150 else:
151 bvList.append(binary.bvFromSignedInt(5460000,24))
152 if 'speed' in params:
153 bvList.append(binary.setBitVectorSize(BitVector(intVal=int((Decimal(params['speed'])*Decimal('10')))),10))
154 else:
155 bvList.append(binary.setBitVectorSize(BitVector(intVal=int(1023)),10))
156 if 'gust' in params:
157 bvList.append(binary.setBitVectorSize(BitVector(intVal=int((Decimal(params['gust'])*Decimal('10')))),10))
158 else:
159 bvList.append(binary.setBitVectorSize(BitVector(intVal=int(1023)),10))
160 if 'direction' in params:
161 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['direction']),9))
162 else:
163 bvList.append(binary.setBitVectorSize(BitVector(intVal=511),9))
164 if 'atmpressure' in params:
165 bvList.append(binary.setBitVectorSize(BitVector(intVal=int((Decimal(params['atmpressure'])*Decimal('10')))),14))
166 else:
167 bvList.append(binary.setBitVectorSize(BitVector(intVal=int(163830)),14))
168 if 'airtemp' in params:
169 bvList.append(binary.bvFromSignedInt(int(Decimal(params['airtemp'])*Decimal('10')),10))
170 else:
171 bvList.append(binary.bvFromSignedInt(-512,10))
172 if 'dewpoint' in params:
173 bvList.append(binary.bvFromSignedInt(int(Decimal(params['dewpoint'])*Decimal('10')),10))
174 else:
175 bvList.append(binary.bvFromSignedInt(-512,10))
176 if 'visibility' in params:
177 bvList.append(binary.setBitVectorSize(BitVector(intVal=int((Decimal(params['visibility'])*Decimal('10')))),8))
178 else:
179 bvList.append(binary.setBitVectorSize(BitVector(intVal=int(255)),8))
180 if 'watertemp' in params:
181 bvList.append(binary.bvFromSignedInt(int(Decimal(params['watertemp'])*Decimal('10')),10))
182 else:
183 bvList.append(binary.bvFromSignedInt(-512,10))
184 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),4))
185
186 return binary.joinBV(bvList)
187
188 -def decode(bv, validate=False):
189 '''Unpack a sls_weatherreport message
190
191 Fields in params:
192 - time_month(uint): Time tag of measurement month 1..12
193 - time_day(uint): Time tag of measurement day of the month 1..31
194 - time_hour(uint): Time tag of measurement UTC hours 0..23
195 - time_min(uint): Time tag of measurement minutes
196 - stationid(aisstr6): Character identifier of the station
197 - pos_longitude(decimal): Location of measurement East West location
198 - pos_latitude(decimal): Location of measurement North South location
199 - speed(udecimal): Average wind speed
200 - gust(udecimal): Wind gust
201 - direction(uint): Wind direction
202 - atmpressure(udecimal): Atmospheric pressure
203 - airtemp(decimal): Air temperature
204 - dewpoint(decimal): Dew Point
205 - visibility(udecimal): Visibility
206 - watertemp(decimal): Water Temperature
207 - reserved(uint): Reserved bits for future use (field automatically set to "0")
208 @type bv: BitVector
209 @param bv: Bits defining a message
210 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented.
211 @rtype: dict
212 @return: params
213 '''
214
215
216
217
218 r = {}
219 r['time_month']=int(bv[0:4])
220 r['time_day']=int(bv[4:9])
221 r['time_hour']=int(bv[9:14])
222 r['time_min']=int(bv[14:20])
223 r['stationid']=aisstring.decode(bv[20:62])
224 r['pos_longitude']=Decimal(binary.signedIntFromBV(bv[62:87]))/Decimal('60000')
225 r['pos_latitude']=Decimal(binary.signedIntFromBV(bv[87:111]))/Decimal('60000')
226 r['speed']=Decimal(int(bv[111:121]))/Decimal('10')
227 r['gust']=Decimal(int(bv[121:131]))/Decimal('10')
228 r['direction']=int(bv[131:140])
229 r['atmpressure']=Decimal(int(bv[140:154]))/Decimal('10')
230 r['airtemp']=Decimal(binary.signedIntFromBV(bv[154:164]))/Decimal('10')
231 r['dewpoint']=Decimal(binary.signedIntFromBV(bv[164:174]))/Decimal('10')
232 r['visibility']=Decimal(int(bv[174:182]))/Decimal('10')
233 r['watertemp']=Decimal(binary.signedIntFromBV(bv[182:192]))/Decimal('10')
234 r['reserved']=0
235 return r
236
239
242
245
247 return int(bv[14:20])
248
251
254
257
259 return Decimal(int(bv[111:121]))/Decimal('10')
260
262 return Decimal(int(bv[121:131]))/Decimal('10')
263
265 return int(bv[131:140])
266
268 return Decimal(int(bv[140:154]))/Decimal('10')
269
272
275
277 return Decimal(int(bv[174:182]))/Decimal('10')
278
281
284
285
287 out.write("<h3>sls_weatherreport<h3>\n")
288 out.write("<table border=\"1\">\n")
289 out.write("<tr bgcolor=\"orange\">\n")
290 out.write("<th align=\"left\">Field Name</th>\n")
291 out.write("<th align=\"left\">Type</th>\n")
292 out.write("<th align=\"left\">Value</th>\n")
293 out.write("<th align=\"left\">Value in Lookup Table</th>\n")
294 out.write("<th align=\"left\">Units</th>\n")
295 out.write("\n")
296 out.write("<tr>\n")
297 out.write("<td>time_month</td>\n")
298 out.write("<td>uint</td>\n")
299 if 'time_month' in params:
300 out.write(" <td>"+str(params['time_month'])+"</td>\n")
301 out.write(" <td>"+str(params['time_month'])+"</td>\n")
302 out.write("</tr>\n")
303 out.write("\n")
304 out.write("<tr>\n")
305 out.write("<td>time_day</td>\n")
306 out.write("<td>uint</td>\n")
307 if 'time_day' in params:
308 out.write(" <td>"+str(params['time_day'])+"</td>\n")
309 out.write(" <td>"+str(params['time_day'])+"</td>\n")
310 out.write("</tr>\n")
311 out.write("\n")
312 out.write("<tr>\n")
313 out.write("<td>time_hour</td>\n")
314 out.write("<td>uint</td>\n")
315 if 'time_hour' in params:
316 out.write(" <td>"+str(params['time_hour'])+"</td>\n")
317 out.write(" <td>"+str(params['time_hour'])+"</td>\n")
318 out.write("</tr>\n")
319 out.write("\n")
320 out.write("<tr>\n")
321 out.write("<td>time_min</td>\n")
322 out.write("<td>uint</td>\n")
323 if 'time_min' in params:
324 out.write(" <td>"+str(params['time_min'])+"</td>\n")
325 out.write(" <td>"+str(params['time_min'])+"</td>\n")
326 out.write("</tr>\n")
327 out.write("\n")
328 out.write("<tr>\n")
329 out.write("<td>stationid</td>\n")
330 out.write("<td>aisstr6</td>\n")
331 if 'stationid' in params:
332 out.write(" <td>"+str(params['stationid'])+"</td>\n")
333 out.write(" <td>"+str(params['stationid'])+"</td>\n")
334 out.write("</tr>\n")
335 out.write("\n")
336 out.write("<tr>\n")
337 out.write("<td>pos_longitude</td>\n")
338 out.write("<td>decimal</td>\n")
339 if 'pos_longitude' in params:
340 out.write(" <td>"+str(params['pos_longitude'])+"</td>\n")
341 out.write(" <td>"+str(params['pos_longitude'])+"</td>\n")
342 out.write("<td>degrees</td>\n")
343 out.write("</tr>\n")
344 out.write("\n")
345 out.write("<tr>\n")
346 out.write("<td>pos_latitude</td>\n")
347 out.write("<td>decimal</td>\n")
348 if 'pos_latitude' in params:
349 out.write(" <td>"+str(params['pos_latitude'])+"</td>\n")
350 out.write(" <td>"+str(params['pos_latitude'])+"</td>\n")
351 out.write("<td>degrees</td>\n")
352 out.write("</tr>\n")
353 out.write("\n")
354 out.write("<tr>\n")
355 out.write("<td>speed</td>\n")
356 out.write("<td>udecimal</td>\n")
357 if 'speed' in params:
358 out.write(" <td>"+str(params['speed'])+"</td>\n")
359 if str(params['speed']) in speedDecodeLut:
360 out.write("<td>"+speedDecodeLut[str(params['speed'])]+"</td>")
361 else:
362 out.write("<td><i>Missing LUT entry</i></td>")
363 out.write("<td>kts</td>\n")
364 out.write("</tr>\n")
365 out.write("\n")
366 out.write("<tr>\n")
367 out.write("<td>gust</td>\n")
368 out.write("<td>udecimal</td>\n")
369 if 'gust' in params:
370 out.write(" <td>"+str(params['gust'])+"</td>\n")
371 if str(params['gust']) in gustDecodeLut:
372 out.write("<td>"+gustDecodeLut[str(params['gust'])]+"</td>")
373 else:
374 out.write("<td><i>Missing LUT entry</i></td>")
375 out.write("<td>kts</td>\n")
376 out.write("</tr>\n")
377 out.write("\n")
378 out.write("<tr>\n")
379 out.write("<td>direction</td>\n")
380 out.write("<td>uint</td>\n")
381 if 'direction' in params:
382 out.write(" <td>"+str(params['direction'])+"</td>\n")
383 out.write(" <td>"+str(params['direction'])+"</td>\n")
384 out.write("<td>degrees</td>\n")
385 out.write("</tr>\n")
386 out.write("\n")
387 out.write("<tr>\n")
388 out.write("<td>atmpressure</td>\n")
389 out.write("<td>udecimal</td>\n")
390 if 'atmpressure' in params:
391 out.write(" <td>"+str(params['atmpressure'])+"</td>\n")
392 out.write(" <td>"+str(params['atmpressure'])+"</td>\n")
393 out.write("<td>millibars</td>\n")
394 out.write("</tr>\n")
395 out.write("\n")
396 out.write("<tr>\n")
397 out.write("<td>airtemp</td>\n")
398 out.write("<td>decimal</td>\n")
399 if 'airtemp' in params:
400 out.write(" <td>"+str(params['airtemp'])+"</td>\n")
401 if str(params['airtemp']) in airtempDecodeLut:
402 out.write("<td>"+airtempDecodeLut[str(params['airtemp'])]+"</td>")
403 else:
404 out.write("<td><i>Missing LUT entry</i></td>")
405 out.write("<td>Celsius</td>\n")
406 out.write("</tr>\n")
407 out.write("\n")
408 out.write("<tr>\n")
409 out.write("<td>dewpoint</td>\n")
410 out.write("<td>decimal</td>\n")
411 if 'dewpoint' in params:
412 out.write(" <td>"+str(params['dewpoint'])+"</td>\n")
413 if str(params['dewpoint']) in dewpointDecodeLut:
414 out.write("<td>"+dewpointDecodeLut[str(params['dewpoint'])]+"</td>")
415 else:
416 out.write("<td><i>Missing LUT entry</i></td>")
417 out.write("<td>Celsius</td>\n")
418 out.write("</tr>\n")
419 out.write("\n")
420 out.write("<tr>\n")
421 out.write("<td>visibility</td>\n")
422 out.write("<td>udecimal</td>\n")
423 if 'visibility' in params:
424 out.write(" <td>"+str(params['visibility'])+"</td>\n")
425 if str(params['visibility']) in visibilityDecodeLut:
426 out.write("<td>"+visibilityDecodeLut[str(params['visibility'])]+"</td>")
427 else:
428 out.write("<td><i>Missing LUT entry</i></td>")
429 out.write("<td>km</td>\n")
430 out.write("</tr>\n")
431 out.write("\n")
432 out.write("<tr>\n")
433 out.write("<td>watertemp</td>\n")
434 out.write("<td>decimal</td>\n")
435 if 'watertemp' in params:
436 out.write(" <td>"+str(params['watertemp'])+"</td>\n")
437 if str(params['watertemp']) in watertempDecodeLut:
438 out.write("<td>"+watertempDecodeLut[str(params['watertemp'])]+"</td>")
439 else:
440 out.write("<td><i>Missing LUT entry</i></td>")
441 out.write("<td>Celsius</td>\n")
442 out.write("</tr>\n")
443 out.write("\n")
444 out.write("<tr>\n")
445 out.write("<td>reserved</td>\n")
446 out.write("<td>uint</td>\n")
447 if 'reserved' in params:
448 out.write(" <td>"+str(params['reserved'])+"</td>\n")
449 out.write(" <td>"+str(params['reserved'])+"</td>\n")
450 out.write("</tr>\n")
451 out.write("</table>\n")
452
453
455 '''KML (Keyhole Markup Language) for Google Earth, but without the header/footer'''
456 out.write("\ <Placemark>\n")
457 out.write("\t <name>"+str(params['stationid'])+"</name>\n")
458 out.write("\t\t<description>\n")
459 import StringIO
460 buf = StringIO.StringIO()
461 printHtml(params,buf)
462 import cgi
463 out.write(cgi.escape(buf.getvalue()))
464 out.write("\t\t</description>\n")
465 out.write("\t\t<styleUrl>#m_ylw-pushpin_copy0</styleUrl>\n")
466 out.write("\t\t<Point>\n")
467 out.write("\t\t\t<coordinates>")
468 out.write(str(params['pos_longitude']))
469 out.write(',')
470 out.write(str(params['pos_latitude']))
471 out.write(",0</coordinates>\n")
472 out.write("\t\t</Point>\n")
473 out.write("\t</Placemark>\n")
474
475 -def printFields(params, out=sys.stdout, format='std', fieldList=None, dbType='postgres'):
476 '''Print a sls_weatherreport message to stdout.
477
478 Fields in params:
479 - time_month(uint): Time tag of measurement month 1..12
480 - time_day(uint): Time tag of measurement day of the month 1..31
481 - time_hour(uint): Time tag of measurement UTC hours 0..23
482 - time_min(uint): Time tag of measurement minutes
483 - stationid(aisstr6): Character identifier of the station
484 - pos_longitude(decimal): Location of measurement East West location
485 - pos_latitude(decimal): Location of measurement North South location
486 - speed(udecimal): Average wind speed
487 - gust(udecimal): Wind gust
488 - direction(uint): Wind direction
489 - atmpressure(udecimal): Atmospheric pressure
490 - airtemp(decimal): Air temperature
491 - dewpoint(decimal): Dew Point
492 - visibility(udecimal): Visibility
493 - watertemp(decimal): Water Temperature
494 - reserved(uint): Reserved bits for future use (field automatically set to "0")
495 @param params: Dictionary of field names/values.
496 @param out: File like object to write to
497 @rtype: stdout
498 @return: text to out
499 '''
500
501 if 'std'==format:
502 out.write("sls_weatherreport:\n")
503 if 'time_month' in params: out.write(" time_month: "+str(params['time_month'])+"\n")
504 if 'time_day' in params: out.write(" time_day: "+str(params['time_day'])+"\n")
505 if 'time_hour' in params: out.write(" time_hour: "+str(params['time_hour'])+"\n")
506 if 'time_min' in params: out.write(" time_min: "+str(params['time_min'])+"\n")
507 if 'stationid' in params: out.write(" stationid: "+str(params['stationid'])+"\n")
508 if 'pos_longitude' in params: out.write(" pos_longitude: "+str(params['pos_longitude'])+"\n")
509 if 'pos_latitude' in params: out.write(" pos_latitude: "+str(params['pos_latitude'])+"\n")
510 if 'speed' in params: out.write(" speed: "+str(params['speed'])+"\n")
511 if 'gust' in params: out.write(" gust: "+str(params['gust'])+"\n")
512 if 'direction' in params: out.write(" direction: "+str(params['direction'])+"\n")
513 if 'atmpressure' in params: out.write(" atmpressure: "+str(params['atmpressure'])+"\n")
514 if 'airtemp' in params: out.write(" airtemp: "+str(params['airtemp'])+"\n")
515 if 'dewpoint' in params: out.write(" dewpoint: "+str(params['dewpoint'])+"\n")
516 if 'visibility' in params: out.write(" visibility: "+str(params['visibility'])+"\n")
517 if 'watertemp' in params: out.write(" watertemp: "+str(params['watertemp'])+"\n")
518 if 'reserved' in params: out.write(" reserved: "+str(params['reserved'])+"\n")
519 elif 'csv'==format:
520 if None == options.fieldList:
521 options.fieldList = fieldList
522 needComma = False;
523 for field in fieldList:
524 if needComma: out.write(',')
525 needComma = True
526 if field in params:
527 out.write(str(params[field]))
528
529 out.write("\n")
530 elif 'html'==format:
531 printHtml(params,out)
532 elif 'sql'==format:
533 sqlInsertStr(params,out,dbType=dbType)
534 elif 'kml'==format:
535 printKml(params,out)
536 elif 'kml-full'==format:
537 out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
538 out.write("<kml xmlns=\"http://earth.google.com/kml/2.1\">\n")
539 out.write("<Document>\n")
540 out.write(" <name>sls_weatherreport</name>\n")
541 printKml(params,out)
542 out.write("</Document>\n")
543 out.write("</kml>\n")
544 else:
545 print "ERROR: unknown format:",format
546 assert False
547
548 return
549
550 speedEncodeLut = {
551 '102.2 kts or greater':'102.2',
552 }
553
554 speedDecodeLut = {
555 '102.2':'102.2 kts or greater',
556 }
557
558 gustEncodeLut = {
559 '102.2 kts or greater':'102.2',
560 }
561
562 gustDecodeLut = {
563 '102.2':'102.2 kts or greater',
564 }
565
566 airtempEncodeLut = {
567 '-51.1 degrees C or lower':'-51.1',
568 '51.1 degrees C or greater':'51.1',
569 }
570
571 airtempDecodeLut = {
572 '-51.1':'-51.1 degrees C or lower',
573 '51.1':'51.1 degrees C or greater',
574 }
575
576 dewpointEncodeLut = {
577 '-51.1 degrees C or lower':'-51.1',
578 '51.1 degrees C or greater':'51.1',
579 }
580
581 dewpointDecodeLut = {
582 '-51.1':'-51.1 degrees C or lower',
583 '51.1':'51.1 degrees C or greater',
584 }
585
586 visibilityEncodeLut = {
587 '25.4 km or greater':'25.4',
588 }
589
590 visibilityDecodeLut = {
591 '25.4':'25.4 km or greater',
592 }
593
594 watertempEncodeLut = {
595 '-51.1 degrees C or lower':'-51.1',
596 '51.1 degrees C or greater':'51.1',
597 }
598
599 watertempDecodeLut = {
600 '-51.1':'-51.1 degrees C or lower',
601 '51.1':'51.1 degrees C or greater',
602 }
603
604
605
606
607
608 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None
609 ,addCoastGuardFields=True
610 ,dbType='postgres'
611 ):
612 '''
613 Return the SQL CREATE command for this message type
614 @param outfile: file like object to print to.
615 @param fields: which fields to put in the create. Defaults to all.
616 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields
617 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format
618 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres')
619 @type addCoastGuardFields: bool
620 @return: sql create string
621 @rtype: str
622
623 @see: sqlCreate
624 '''
625
626 outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType)))
627
628 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'):
629 '''
630 Return the sqlhelp object to create the table.
631
632 @param fields: which fields to put in the create. Defaults to all.
633 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields
634 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format
635 @type addCoastGuardFields: bool
636 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres')
637 @return: An object that can be used to generate a return
638 @rtype: sqlhelp.create
639 '''
640 if None == fields: fields = fieldList
641 import sqlhelp
642 c = sqlhelp.create('sls_weatherreport',dbType=dbType)
643 c.addPrimaryKey()
644 if 'time_month' in fields: c.addInt ('time_month')
645 if 'time_day' in fields: c.addInt ('time_day')
646 if 'time_hour' in fields: c.addInt ('time_hour')
647 if 'time_min' in fields: c.addInt ('time_min')
648 if 'stationid' in fields: c.addVarChar('stationid',7)
649 if dbType != 'postgres':
650 if 'pos_longitude' in fields: c.addDecimal('pos_longitude',7,4)
651 if dbType != 'postgres':
652 if 'pos_latitude' in fields: c.addDecimal('pos_latitude',7,4)
653 if 'speed' in fields: c.addDecimal('speed',4,1)
654 if 'gust' in fields: c.addDecimal('gust',4,1)
655 if 'direction' in fields: c.addInt ('direction')
656 if 'atmpressure' in fields: c.addDecimal('atmpressure',5,1)
657 if 'airtemp' in fields: c.addDecimal('airtemp',4,1)
658 if 'dewpoint' in fields: c.addDecimal('dewpoint',4,1)
659 if 'visibility' in fields: c.addDecimal('visibility',3,1)
660 if 'watertemp' in fields: c.addDecimal('watertemp',4,1)
661 if 'reserved' in fields: c.addInt ('reserved')
662
663 if addCoastGuardFields:
664
665
666
667
668
669 c.addVarChar('cg_r',15)
670 c.addInt('cg_sec')
671
672 c.addTimestamp('cg_timestamp')
673
674 if dbType == 'postgres':
675 c.addPostGIS('pos','POINT',2);
676
677 return c
678
679 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'):
680 '''
681 Return the SQL INSERT command for this message type
682 @param params: dictionary of values keyed by field name
683 @param outfile: file like object to print to.
684 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields
685 @return: sql create string
686 @rtype: str
687
688 @see: sqlCreate
689 '''
690 outfile.write(str(sqlInsert(params,extraParams,dbType=dbType)))
691
692
693 -def sqlInsert(params,extraParams=None,dbType='postgres'):
694 '''
695 Give the SQL INSERT statement
696 @param params: dict keyed by field name of values
697 @param extraParams: any extra fields that you have created beyond the normal ais message fields
698 @rtype: sqlhelp.insert
699 @return: insert class instance
700 @todo: allow optional type checking of params?
701 @warning: this will take invalid keys happily and do what???
702 '''
703 import sqlhelp
704 i = sqlhelp.insert('sls_weatherreport',dbType=dbType)
705
706 if dbType=='postgres':
707 finished = []
708 for key in params:
709 if key in finished:
710 continue
711
712 if key not in toPgFields and key not in fromPgFields:
713 if type(params[key])==Decimal: i.add(key,float(params[key]))
714 else: i.add(key,params[key])
715 else:
716 if key in fromPgFields:
717 val = params[key]
718
719 i.addPostGIS(key,val)
720 finished.append(key)
721 else:
722
723 pgName = toPgFields[key]
724
725 valStr=pgTypes[pgName]+'('
726 vals = []
727 for nonPgKey in fromPgFields[pgName]:
728 vals.append(str(params[nonPgKey]))
729 finished.append(nonPgKey)
730 valStr+=' '.join(vals)+')'
731 i.addPostGIS(pgName,valStr)
732 else:
733 for key in params:
734 if type(params[key])==Decimal: i.add(key,float(params[key]))
735 else: i.add(key,params[key])
736
737 if None != extraParams:
738 for key in extraParams:
739 i.add(key,extraParams[key])
740
741 return i
742
743
744
745
746
749 '''
750 Return the LaTeX definition table for this message type
751 @param outfile: file like object to print to.
752 @type outfile: file obj
753 @return: LaTeX table string via the outfile
754 @rtype: str
755
756 '''
757 o = outfile
758
759 o.write('''
760 \\begin{table}%[htb]
761 \\centering
762 \\begin{tabular}{|l|c|l|}
763 \\hline
764 Parameter & Number of bits & Description
765 \\\\ \\hline\\hline
766 time\_month & 4 & Time tag of measurement month 1..12 \\\\ \hline
767 time\_day & 5 & Time tag of measurement day of the month 1..31 \\\\ \hline
768 time\_hour & 5 & Time tag of measurement UTC hours 0..23 \\\\ \hline
769 time\_min & 6 & Time tag of measurement minutes \\\\ \hline
770 stationid & 42 & Character identifier of the station \\\\ \hline
771 pos\_longitude & 25 & Location of measurement East West location \\\\ \hline
772 pos\_latitude & 24 & Location of measurement North South location \\\\ \hline
773 speed & 10 & Average wind speed \\\\ \hline
774 gust & 10 & Wind gust \\\\ \hline
775 direction & 9 & Wind direction \\\\ \hline
776 atmpressure & 14 & Atmospheric pressure \\\\ \hline
777 airtemp & 10 & Air temperature \\\\ \hline
778 dewpoint & 10 & Dew Point \\\\ \hline
779 visibility & 8 & Visibility \\\\ \hline
780 watertemp & 10 & Water Temperature \\\\ \hline
781 reserved & 4 & Reserved bits for future use\\\\ \\hline \\hline
782 Total bits & 196 & Appears to take 2 slots with 228 pad bits to fill the last slot \\\\ \\hline
783 \\end{tabular}
784 \\caption{AIS message number 8: St Lawrance Seaway wind information}
785 \\label{tab:sls_weatherreport}
786 \\end{table}
787 ''')
788
789
790
791
792
793 -def textDefinitionTable(outfile=sys.stdout
794 ,delim='\t'
795 ):
796 '''
797 Return the text definition table for this message type
798 @param outfile: file like object to print to.
799 @type outfile: file obj
800 @return: text table string via the outfile
801 @rtype: str
802
803 '''
804 o = outfile
805 o.write('''Parameter'''+delim+'Number of bits'''+delim+'''Description
806 time_month'''+delim+'''4'''+delim+'''Time tag of measurement month 1..12
807 time_day'''+delim+'''5'''+delim+'''Time tag of measurement day of the month 1..31
808 time_hour'''+delim+'''5'''+delim+'''Time tag of measurement UTC hours 0..23
809 time_min'''+delim+'''6'''+delim+'''Time tag of measurement minutes
810 stationid'''+delim+'''42'''+delim+'''Character identifier of the station
811 pos_longitude'''+delim+'''25'''+delim+'''Location of measurement East West location
812 pos_latitude'''+delim+'''24'''+delim+'''Location of measurement North South location
813 speed'''+delim+'''10'''+delim+'''Average wind speed
814 gust'''+delim+'''10'''+delim+'''Wind gust
815 direction'''+delim+'''9'''+delim+'''Wind direction
816 atmpressure'''+delim+'''14'''+delim+'''Atmospheric pressure
817 airtemp'''+delim+'''10'''+delim+'''Air temperature
818 dewpoint'''+delim+'''10'''+delim+'''Dew Point
819 visibility'''+delim+'''8'''+delim+'''Visibility
820 watertemp'''+delim+'''10'''+delim+'''Water Temperature
821 reserved'''+delim+'''4'''+delim+'''Reserved bits for future use
822 Total bits'''+delim+'''196'''+delim+'''Appears to take 2 slots with 228 pad bits to fill the last slot''')
823
824
825
826
827
828 import unittest
830 '''Return a params file base on the testvalue tags.
831 @rtype: dict
832 @return: params based on testvalue tags
833 '''
834 params = {}
835 params['time_month'] = 2
836 params['time_day'] = 28
837 params['time_hour'] = 23
838 params['time_min'] = 45
839 params['stationid'] = 'A345678'
840 params['pos_longitude'] = Decimal('-122.16328')
841 params['pos_latitude'] = Decimal('37.42446')
842 params['speed'] = Decimal('0.7')
843 params['gust'] = Decimal('0.7')
844 params['direction'] = 41
845 params['atmpressure'] = Decimal('0.7')
846 params['airtemp'] = Decimal('-8')
847 params['dewpoint'] = Decimal('-7')
848 params['visibility'] = Decimal('12.3')
849 params['watertemp'] = Decimal('-0.2')
850 params['reserved'] = 0
851
852 return params
853
855 '''Use testvalue tag text from each type to build test case the sls_weatherreport message'''
857
858 params = testParams()
859 bits = encode(params)
860 r = decode(bits)
861
862
863 self.failUnlessEqual(r['time_month'],params['time_month'])
864 self.failUnlessEqual(r['time_day'],params['time_day'])
865 self.failUnlessEqual(r['time_hour'],params['time_hour'])
866 self.failUnlessEqual(r['time_min'],params['time_min'])
867 self.failUnlessEqual(r['stationid'],params['stationid'])
868 self.failUnlessAlmostEqual(r['pos_longitude'],params['pos_longitude'],4)
869 self.failUnlessAlmostEqual(r['pos_latitude'],params['pos_latitude'],4)
870 self.failUnlessAlmostEqual(r['speed'],params['speed'],1)
871 self.failUnlessAlmostEqual(r['gust'],params['gust'],1)
872 self.failUnlessEqual(r['direction'],params['direction'])
873 self.failUnlessAlmostEqual(r['atmpressure'],params['atmpressure'],1)
874 self.failUnlessAlmostEqual(r['airtemp'],params['airtemp'],1)
875 self.failUnlessAlmostEqual(r['dewpoint'],params['dewpoint'],1)
876 self.failUnlessAlmostEqual(r['visibility'],params['visibility'],1)
877 self.failUnlessAlmostEqual(r['watertemp'],params['watertemp'],1)
878 self.failUnlessEqual(r['reserved'],params['reserved'])
879
881 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true',
882 help='decode a "sls_weatherreport" AIS message')
883 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true',
884 help='encode a "sls_weatherreport" AIS message')
885 parser.add_option('--time_month-field', dest='time_monthField',metavar='uint',type='int'
886 ,help='Field parameter value [default: %default]')
887 parser.add_option('--time_day-field', dest='time_dayField',metavar='uint',type='int'
888 ,help='Field parameter value [default: %default]')
889 parser.add_option('--time_hour-field', dest='time_hourField',metavar='uint',type='int'
890 ,help='Field parameter value [default: %default]')
891 parser.add_option('--time_min-field', dest='time_minField',metavar='uint',type='int'
892 ,help='Field parameter value [default: %default]')
893 parser.add_option('--stationid-field', dest='stationidField',default='@@@@@@@',metavar='aisstr6',type='string'
894 ,help='Field parameter value [default: %default]')
895 parser.add_option('--pos_longitude-field', dest='pos_longitudeField',default=Decimal('181'),metavar='decimal',type='string'
896 ,help='Field parameter value [default: %default]')
897 parser.add_option('--pos_latitude-field', dest='pos_latitudeField',default=Decimal('91'),metavar='decimal',type='string'
898 ,help='Field parameter value [default: %default]')
899 parser.add_option('--speed-field', dest='speedField',default=Decimal('102.3'),metavar='udecimal',type='string'
900 ,help='Field parameter value [default: %default]')
901 parser.add_option('--gust-field', dest='gustField',default=Decimal('102.3'),metavar='udecimal',type='string'
902 ,help='Field parameter value [default: %default]')
903 parser.add_option('--direction-field', dest='directionField',default=511,metavar='uint',type='int'
904 ,help='Field parameter value [default: %default]')
905 parser.add_option('--atmpressure-field', dest='atmpressureField',default=Decimal('16383'),metavar='udecimal',type='string'
906 ,help='Field parameter value [default: %default]')
907 parser.add_option('--airtemp-field', dest='airtempField',default=Decimal('-51.2'),metavar='decimal',type='string'
908 ,help='Field parameter value [default: %default]')
909 parser.add_option('--dewpoint-field', dest='dewpointField',default=Decimal('-51.2'),metavar='decimal',type='string'
910 ,help='Field parameter value [default: %default]')
911 parser.add_option('--visibility-field', dest='visibilityField',default=Decimal('25.5'),metavar='udecimal',type='string'
912 ,help='Field parameter value [default: %default]')
913 parser.add_option('--watertemp-field', dest='watertempField',default=Decimal('-51.2'),metavar='decimal',type='string'
914 ,help='Field parameter value [default: %default]')
915
916
917 if __name__=='__main__':
918
919 from optparse import OptionParser
920 parser = OptionParser(usage="%prog [options]",
921 version="%prog "+__version__)
922
923 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true',
924 help='run the documentation tests')
925 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true',
926 help='run the unit tests')
927 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true',
928 help='Make the test output verbose')
929
930
931
932 typeChoices = ('binary','nmeapayload','nmea')
933 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType'
934 ,default='nmeapayload'
935 ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]')
936
937
938 outputChoices = ('std','html','csv','sql' , 'kml','kml-full')
939 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType'
940 ,default='std'
941 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]')
942
943 parser.add_option('-o','--output',dest='outputFileName',default=None,
944 help='Name of the python file to write [default: stdout]')
945
946 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append',
947 choices=fieldList,
948 help='Which fields to include in the output. Currently only for csv output [default: all]')
949
950 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true',
951 help='Print the field name for csv')
952
953 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true',
954 help='Print out an sql create command for the table.')
955
956 parser.add_option('--latex-table',dest='latexDefinitionTable',default=False,action='store_true',
957 help='Print a LaTeX table of the type')
958
959 parser.add_option('--text-table',dest='textDefinitionTable',default=False,action='store_true',
960 help='Print delimited table of the type (for Word table importing)')
961 parser.add_option('--delimt-text-table',dest='delimTextDefinitionTable',default='\t'
962 ,help='Delimiter for text table [default: \'%default\'](for Word table importing)')
963
964
965 dbChoices = ('sqlite','postgres')
966 parser.add_option('-D','--db-type',dest='dbType',default='postgres'
967 ,choices=dbChoices,type='choice'
968 ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]')
969
970 addMsgOptions(parser)
971
972 (options,args) = parser.parse_args()
973 success=True
974
975 if options.doctest:
976 import os; print os.path.basename(sys.argv[0]), 'doctests ...',
977 sys.argv= [sys.argv[0]]
978 if options.verbose: sys.argv.append('-v')
979 import doctest
980 numfail,numtests=doctest.testmod()
981 if numfail==0: print 'ok'
982 else:
983 print 'FAILED'
984 success=False
985
986 if not success: sys.exit('Something Failed')
987 del success
988
989 if options.unittest:
990 sys.argv = [sys.argv[0]]
991 if options.verbose: sys.argv.append('-v')
992 unittest.main()
993
994 outfile = sys.stdout
995 if None!=options.outputFileName:
996 outfile = file(options.outputFileName,'w')
997
998
999 if options.doEncode:
1000
1001 if None==options.time_monthField: parser.error("missing value for time_monthField")
1002 if None==options.time_dayField: parser.error("missing value for time_dayField")
1003 if None==options.time_hourField: parser.error("missing value for time_hourField")
1004 if None==options.time_minField: parser.error("missing value for time_minField")
1005 if None==options.stationidField: parser.error("missing value for stationidField")
1006 if None==options.pos_longitudeField: parser.error("missing value for pos_longitudeField")
1007 if None==options.pos_latitudeField: parser.error("missing value for pos_latitudeField")
1008 if None==options.speedField: parser.error("missing value for speedField")
1009 if None==options.gustField: parser.error("missing value for gustField")
1010 if None==options.directionField: parser.error("missing value for directionField")
1011 if None==options.atmpressureField: parser.error("missing value for atmpressureField")
1012 if None==options.airtempField: parser.error("missing value for airtempField")
1013 if None==options.dewpointField: parser.error("missing value for dewpointField")
1014 if None==options.visibilityField: parser.error("missing value for visibilityField")
1015 if None==options.watertempField: parser.error("missing value for watertempField")
1016 msgDict={
1017 'time_month': options.time_monthField,
1018 'time_day': options.time_dayField,
1019 'time_hour': options.time_hourField,
1020 'time_min': options.time_minField,
1021 'stationid': options.stationidField,
1022 'pos_longitude': options.pos_longitudeField,
1023 'pos_latitude': options.pos_latitudeField,
1024 'speed': options.speedField,
1025 'gust': options.gustField,
1026 'direction': options.directionField,
1027 'atmpressure': options.atmpressureField,
1028 'airtemp': options.airtempField,
1029 'dewpoint': options.dewpointField,
1030 'visibility': options.visibilityField,
1031 'watertemp': options.watertempField,
1032 'reserved': '0',
1033 }
1034
1035 bits = encode(msgDict)
1036 if 'binary'==options.ioType: print str(bits)
1037 elif 'nmeapayload'==options.ioType:
1038
1039 print "bitLen",len(bits)
1040 bitLen=len(bits)
1041 if bitLen%6!=0:
1042 bits = bits + BitVector(size=(6 - (bitLen%6)))
1043 print "result:",binary.bitvectoais6(bits)[0]
1044
1045
1046
1047 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability")
1048 else: sys.exit('ERROR: unknown ioType. Help!')
1049
1050
1051 if options.sqlCreate:
1052 sqlCreateStr(outfile,options.fieldList,dbType=options.dbType)
1053
1054 if options.latexDefinitionTable:
1055 latexDefinitionTable(outfile)
1056
1057
1058 if options.textDefinitionTable:
1059 textDefinitionTable(outfile,options.delimTextDefinitionTable)
1060
1061 if options.printCsvfieldList:
1062
1063 if None == options.fieldList: options.fieldList = fieldList
1064 import StringIO
1065 buf = StringIO.StringIO()
1066 for field in options.fieldList:
1067 buf.write(field+',')
1068 result = buf.getvalue()
1069 if result[-1] == ',': print result[:-1]
1070 else: print result
1071
1072 if options.doDecode:
1073 for msg in args:
1074 bv = None
1075
1076 if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'):
1077
1078
1079 bv = binary.ais6tobitvec(msg.split(',')[5])
1080 else:
1081
1082 binaryMsg=True
1083 for c in msg:
1084 if c not in ('0','1'):
1085 binaryMsg=False
1086 break
1087 if binaryMsg:
1088 bv = BitVector(bitstring=msg)
1089 else:
1090 bv = binary.ais6tobitvec(msg)
1091
1092 printFields(decode(bv)
1093 ,out=outfile
1094 ,format=options.outputType
1095 ,fieldList=options.fieldList
1096 ,dbType=options.dbType
1097 )
1098