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