1
2
3 __version__ = '$Revision: 4791 $'.split()[1]
4 __date__ = '$Date: 2007-03-31 $'.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
689 outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType)))
690
691 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'):
692 '''
693 Return the sqlhelp object to create the table.
694
695 @param fields: which fields to put in the create. Defaults to all.
696 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields
697 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format
698 @type addCoastGuardFields: bool
699 @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres')
700 @return: An object that can be used to generate a return
701 @rtype: sqlhelp.create
702 '''
703 if None == fields: fields = fieldList
704 import sqlhelp
705 c = sqlhelp.create('bsreport',dbType=dbType)
706 c.addPrimaryKey()
707 if 'MessageID' in fields: c.addInt ('MessageID')
708 if 'RepeatIndicator' in fields: c.addInt ('RepeatIndicator')
709 if 'UserID' in fields: c.addInt ('UserID')
710 if 'Time_year' in fields: c.addInt ('Time_year')
711 if 'Time_month' in fields: c.addInt ('Time_month')
712 if 'Time_day' in fields: c.addInt ('Time_day')
713 if 'Time_hour' in fields: c.addInt ('Time_hour')
714 if 'Time_min' in fields: c.addInt ('Time_min')
715 if 'Time_sec' in fields: c.addInt ('Time_sec')
716 if 'PositionAccuracy' in fields: c.addInt ('PositionAccuracy')
717 if dbType != 'postgres':
718 if 'Position_longitude' in fields: c.addDecimal('Position_longitude',8,5)
719 if dbType != 'postgres':
720 if 'Position_latitude' in fields: c.addDecimal('Position_latitude',8,5)
721 if 'fixtype' in fields: c.addInt ('fixtype')
722 if 'Spare' in fields: c.addInt ('Spare')
723 if 'RAIM' in fields: c.addBool('RAIM')
724 if 'state_syncstate' in fields: c.addInt ('state_syncstate')
725 if 'state_slottimeout' in fields: c.addInt ('state_slottimeout')
726 if 'state_slotoffset' in fields: c.addInt ('state_slotoffset')
727
728 if addCoastGuardFields:
729
730
731
732
733
734 c.addVarChar('cg_r',15)
735 c.addInt('cg_sec')
736
737 c.addTimestamp('cg_timestamp')
738
739 if dbType == 'postgres':
740 c.addPostGIS('Position','POINT',2);
741
742 return c
743
744 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'):
745 '''
746 Return the SQL INSERT command for this message type
747 @param params: dictionary of values keyed by field name
748 @param outfile: file like object to print to.
749 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields
750 @return: sql create string
751 @rtype: str
752
753 @see: sqlCreate
754 '''
755 outfile.write(str(sqlInsert(params,extraParams,dbType=dbType)))
756
757
758 -def sqlInsert(params,extraParams=None,dbType='postgres'):
759 '''
760 Give the SQL INSERT statement
761 @param params: dict keyed by field name of values
762 @param extraParams: any extra fields that you have created beyond the normal ais message fields
763 @rtype: sqlhelp.insert
764 @return: insert class instance
765 @todo: allow optional type checking of params?
766 @warning: this will take invalid keys happily and do what???
767 '''
768 import sqlhelp
769 i = sqlhelp.insert('bsreport',dbType=dbType)
770
771 if dbType=='postgres':
772 finished = []
773 for key in params:
774 if key in finished:
775 continue
776
777 if key not in toPgFields and key not in fromPgFields:
778 if type(params[key])==Decimal: i.add(key,float(params[key]))
779 else: i.add(key,params[key])
780 else:
781 if key in fromPgFields:
782 val = params[key]
783
784 i.addPostGIS(key,val)
785 finished.append(key)
786 else:
787
788 pgName = toPgFields[key]
789
790 valStr=pgTypes[pgName]+'('
791 vals = []
792 for nonPgKey in fromPgFields[pgName]:
793 vals.append(str(params[nonPgKey]))
794 finished.append(nonPgKey)
795 valStr+=' '.join(vals)+')'
796 i.addPostGIS(pgName,valStr)
797 else:
798 for key in params:
799 if type(params[key])==Decimal: i.add(key,float(params[key]))
800 else: i.add(key,params[key])
801
802 if None != extraParams:
803 for key in extraParams:
804 i.add(key,extraParams[key])
805
806 return i
807
808
809
810
811
814 '''
815 Return the LaTeX definition table for this message type
816 @param outfile: file like object to print to.
817 @type outfile: file obj
818 @return: LaTeX table string via the outfile
819 @rtype: str
820
821 '''
822 o = outfile
823
824 o.write('''
825 \\begin{table}%[htb]
826 \\centering
827 \\begin{tabular}{|l|c|l|}
828 \\hline
829 Parameter & Number of bits & Description
830 \\\\ \\hline\\hline
831 MessageID & 6 & AIS message number. Must be 4 \\\\ \hline
832 RepeatIndicator & 2 & Indicated how many times a message has been repeated \\\\ \hline
833 UserID & 30 & Unique ship identification number (MMSI) \\\\ \hline
834 Time\_year & 14 & Current time stamp year 1-9999 \\\\ \hline
835 Time\_month & 4 & Current time stamp month 1..12 \\\\ \hline
836 Time\_day & 5 & Current time stamp day of the month 1..31 \\\\ \hline
837 Time\_hour & 5 & Current time stamp UTC hours 0..23 \\\\ \hline
838 Time\_min & 6 & Current time stamp minutes \\\\ \hline
839 Time\_sec & 6 & Current time stamp seconds \\\\ \hline
840 PositionAccuracy & 1 & Accuracy of positioning fixes \\\\ \hline
841 Position\_longitude & 28 & Location of base station East West location \\\\ \hline
842 Position\_latitude & 27 & Location of base station North South location \\\\ \hline
843 fixtype & 4 & Method used for positioning \\\\ \hline
844 Spare & 10 & Not used. Should be set to zero. \\\\ \hline
845 RAIM & 1 & Receiver autonomous integrity monitoring flag \\\\ \hline
846 state\_syncstate & 2 & Communications State - SOTDMA Sycronization state \\\\ \hline
847 state\_slottimeout & 3 & Communications State - SOTDMA Frames remaining until a new slot is selected \\\\ \hline
848 state\_slotoffset & 14 & Communications State - SOTDMA In what slot will the next transmission occur. BROKEN\\\\ \\hline \\hline
849 Total bits & 168 & Appears to take 1 slot \\\\ \\hline
850 \\end{tabular}
851 \\caption{AIS message number 4: Base station report}
852 \\label{tab:bsreport}
853 \\end{table}
854 ''')
855
856
857
858
859
860 import unittest
862 '''Return a params file base on the testvalue tags.
863 @rtype: dict
864 @return: params based on testvalue tags
865 '''
866 params = {}
867 params['MessageID'] = 4
868 params['RepeatIndicator'] = 1
869 params['UserID'] = 1193046
870 params['Time_year'] = 2
871 params['Time_month'] = 2
872 params['Time_day'] = 28
873 params['Time_hour'] = 23
874 params['Time_min'] = 45
875 params['Time_sec'] = 54
876 params['PositionAccuracy'] = 1
877 params['Position_longitude'] = Decimal('-122.16328055555556')
878 params['Position_latitude'] = Decimal('37.424458333333334')
879 params['fixtype'] = 1
880 params['Spare'] = 0
881 params['RAIM'] = False
882 params['state_syncstate'] = 2
883 params['state_slottimeout'] = 0
884 params['state_slotoffset'] = 1221
885
886 return params
887
889 '''Use testvalue tag text from each type to build test case the bsreport message'''
891
892 params = testParams()
893 bits = encode(params)
894 r = decode(bits)
895
896
897 self.failUnlessEqual(r['MessageID'],params['MessageID'])
898 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator'])
899 self.failUnlessEqual(r['UserID'],params['UserID'])
900 self.failUnlessEqual(r['Time_year'],params['Time_year'])
901 self.failUnlessEqual(r['Time_month'],params['Time_month'])
902 self.failUnlessEqual(r['Time_day'],params['Time_day'])
903 self.failUnlessEqual(r['Time_hour'],params['Time_hour'])
904 self.failUnlessEqual(r['Time_min'],params['Time_min'])
905 self.failUnlessEqual(r['Time_sec'],params['Time_sec'])
906 self.failUnlessEqual(r['PositionAccuracy'],params['PositionAccuracy'])
907 self.failUnlessAlmostEqual(r['Position_longitude'],params['Position_longitude'],5)
908 self.failUnlessAlmostEqual(r['Position_latitude'],params['Position_latitude'],5)
909 self.failUnlessEqual(r['fixtype'],params['fixtype'])
910 self.failUnlessEqual(r['Spare'],params['Spare'])
911 self.failUnlessEqual(r['RAIM'],params['RAIM'])
912 self.failUnlessEqual(r['state_syncstate'],params['state_syncstate'])
913 self.failUnlessEqual(r['state_slottimeout'],params['state_slottimeout'])
914 self.failUnlessEqual(r['state_slotoffset'],params['state_slotoffset'])
915
917 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true',
918 help='decode a "bsreport" AIS message')
919 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true',
920 help='encode a "bsreport" AIS message')
921 parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int'
922 ,help='Field parameter value [default: %default]')
923 parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int'
924 ,help='Field parameter value [default: %default]')
925 parser.add_option('--Time_year-field', dest='Time_yearField',default=0,metavar='uint',type='int'
926 ,help='Field parameter value [default: %default]')
927 parser.add_option('--Time_month-field', dest='Time_monthField',default=0,metavar='uint',type='int'
928 ,help='Field parameter value [default: %default]')
929 parser.add_option('--Time_day-field', dest='Time_dayField',default=0,metavar='uint',type='int'
930 ,help='Field parameter value [default: %default]')
931 parser.add_option('--Time_hour-field', dest='Time_hourField',default=24,metavar='uint',type='int'
932 ,help='Field parameter value [default: %default]')
933 parser.add_option('--Time_min-field', dest='Time_minField',default=60,metavar='uint',type='int'
934 ,help='Field parameter value [default: %default]')
935 parser.add_option('--Time_sec-field', dest='Time_secField',default=60,metavar='uint',type='int'
936 ,help='Field parameter value [default: %default]')
937 parser.add_option('--PositionAccuracy-field', dest='PositionAccuracyField',metavar='uint',type='int'
938 ,help='Field parameter value [default: %default]')
939 parser.add_option('--Position_longitude-field', dest='Position_longitudeField',default=Decimal('181'),metavar='decimal',type='string'
940 ,help='Field parameter value [default: %default]')
941 parser.add_option('--Position_latitude-field', dest='Position_latitudeField',default=Decimal('91'),metavar='decimal',type='string'
942 ,help='Field parameter value [default: %default]')
943 parser.add_option('--fixtype-field', dest='fixtypeField',default=0,metavar='uint',type='int'
944 ,help='Field parameter value [default: %default]')
945 parser.add_option('--RAIM-field', dest='RAIMField',metavar='bool',type='int'
946 ,help='Field parameter value [default: %default]')
947 parser.add_option('--state_syncstate-field', dest='state_syncstateField',metavar='uint',type='int'
948 ,help='Field parameter value [default: %default]')
949 parser.add_option('--state_slottimeout-field', dest='state_slottimeoutField',metavar='uint',type='int'
950 ,help='Field parameter value [default: %default]')
951 parser.add_option('--state_slotoffset-field', dest='state_slotoffsetField',metavar='uint',type='int'
952 ,help='Field parameter value [default: %default]')
953
954
955 if __name__=='__main__':
956
957 from optparse import OptionParser
958 parser = OptionParser(usage="%prog [options]",
959 version="%prog "+__version__)
960
961 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true',
962 help='run the documentation tests')
963 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true',
964 help='run the unit tests')
965 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true',
966 help='Make the test output verbose')
967
968
969
970 typeChoices = ('binary','nmeapayload','nmea')
971 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType'
972 ,default='nmeapayload'
973 ,help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]')
974
975
976 outputChoices = ('std','html','csv','sql' , 'kml','kml-full')
977 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType'
978 ,default='std'
979 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]')
980
981 parser.add_option('-o','--output',dest='outputFileName',default=None,
982 help='Name of the python file to write [default: stdout]')
983
984 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append',
985 choices=fieldList,
986 help='Which fields to include in the output. Currently only for csv output [default: all]')
987
988 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true',
989 help='Print the field name for csv')
990
991 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true',
992 help='Print out an sql create command for the table.')
993
994 parser.add_option('--latex-table',dest='latexDefinitionTable',default=False,action='store_true',
995 help='Print a LaTeX table of the type')
996
997 dbChoices = ('sqlite','postgres')
998 parser.add_option('-D','--db-type',dest='dbType',default='postgres'
999 ,choices=dbChoices,type='choice'
1000 ,help='What kind of database ('+', '.join(dbChoices)+') [default: %default]')
1001
1002 addMsgOptions(parser)
1003
1004 (options,args) = parser.parse_args()
1005 success=True
1006
1007 if options.doctest:
1008 import os; print os.path.basename(sys.argv[0]), 'doctests ...',
1009 sys.argv= [sys.argv[0]]
1010 if options.verbose: sys.argv.append('-v')
1011 import doctest
1012 numfail,numtests=doctest.testmod()
1013 if numfail==0: print 'ok'
1014 else:
1015 print 'FAILED'
1016 success=False
1017
1018 if not success: sys.exit('Something Failed')
1019 del success
1020
1021 if options.unittest:
1022 sys.argv = [sys.argv[0]]
1023 if options.verbose: sys.argv.append('-v')
1024 unittest.main()
1025
1026 outfile = sys.stdout
1027 if None!=options.outputFileName:
1028 outfile = file(options.outputFileName,'w')
1029
1030
1031 if options.doEncode:
1032
1033 if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField")
1034 if None==options.UserIDField: parser.error("missing value for UserIDField")
1035 if None==options.Time_yearField: parser.error("missing value for Time_yearField")
1036 if None==options.Time_monthField: parser.error("missing value for Time_monthField")
1037 if None==options.Time_dayField: parser.error("missing value for Time_dayField")
1038 if None==options.Time_hourField: parser.error("missing value for Time_hourField")
1039 if None==options.Time_minField: parser.error("missing value for Time_minField")
1040 if None==options.Time_secField: parser.error("missing value for Time_secField")
1041 if None==options.PositionAccuracyField: parser.error("missing value for PositionAccuracyField")
1042 if None==options.Position_longitudeField: parser.error("missing value for Position_longitudeField")
1043 if None==options.Position_latitudeField: parser.error("missing value for Position_latitudeField")
1044 if None==options.fixtypeField: parser.error("missing value for fixtypeField")
1045 if None==options.RAIMField: parser.error("missing value for RAIMField")
1046 if None==options.state_syncstateField: parser.error("missing value for state_syncstateField")
1047 if None==options.state_slottimeoutField: parser.error("missing value for state_slottimeoutField")
1048 if None==options.state_slotoffsetField: parser.error("missing value for state_slotoffsetField")
1049 msgDict={
1050 'MessageID': '4',
1051 'RepeatIndicator': options.RepeatIndicatorField,
1052 'UserID': options.UserIDField,
1053 'Time_year': options.Time_yearField,
1054 'Time_month': options.Time_monthField,
1055 'Time_day': options.Time_dayField,
1056 'Time_hour': options.Time_hourField,
1057 'Time_min': options.Time_minField,
1058 'Time_sec': options.Time_secField,
1059 'PositionAccuracy': options.PositionAccuracyField,
1060 'Position_longitude': options.Position_longitudeField,
1061 'Position_latitude': options.Position_latitudeField,
1062 'fixtype': options.fixtypeField,
1063 'Spare': '0',
1064 'RAIM': options.RAIMField,
1065 'state_syncstate': options.state_syncstateField,
1066 'state_slottimeout': options.state_slottimeoutField,
1067 'state_slotoffset': options.state_slotoffsetField,
1068 }
1069
1070 bits = encode(msgDict)
1071 if 'binary'==options.ioType: print str(bits)
1072 elif 'nmeapayload'==options.ioType:
1073
1074 print "bitLen",len(bits)
1075 bitLen=len(bits)
1076 if bitLen%6!=0:
1077 bits = bits + BitVector(size=(6 - (bitLen%6)))
1078 print "result:",binary.bitvectoais6(bits)[0]
1079
1080
1081
1082 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability")
1083 else: sys.exit('ERROR: unknown ioType. Help!')
1084
1085
1086 if options.sqlCreate:
1087 sqlCreateStr(outfile,options.fieldList,dbType=options.dbType)
1088
1089 if options.latexDefinitionTable:
1090 latexDefinitionTable(outfile)
1091
1092 if options.printCsvfieldList:
1093
1094 if None == options.fieldList: options.fieldList = fieldList
1095 import StringIO
1096 buf = StringIO.StringIO()
1097 for field in options.fieldList:
1098 buf.write(field+',')
1099 result = buf.getvalue()
1100 if result[-1] == ',': print result[:-1]
1101 else: print result
1102
1103 if options.doDecode:
1104 for msg in args:
1105 bv = None
1106
1107 if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'):
1108
1109
1110 bv = binary.ais6tobitvec(msg.split(',')[5])
1111 else:
1112
1113 binaryMsg=True
1114 for c in msg:
1115 if c not in ('0','1'):
1116 binaryMsg=False
1117 break
1118 if binaryMsg:
1119 bv = BitVector(bitstring=msg)
1120 else:
1121 bv = binary.ais6tobitvec(msg)
1122
1123 printFields(decode(bv)
1124 ,out=outfile
1125 ,format=options.outputType
1126 ,fieldList=options.fieldList
1127 ,dbType=options.dbType
1128 )
1129