1
2
3 __version__ = '$Revision: 4791 $'.split()[1]
4 __date__ = '$Date: 2007-02-08 $'.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 '''
34
35 import sys
36 from decimal import Decimal
37 from BitVector import BitVector
38
39 import binary, aisstring
40
41
42 TrueBV = BitVector(bitstring="1")
43 "Why always rebuild the True bit? This should speed things up a bunch"
44 FalseBV = BitVector(bitstring="0")
45 "Why always rebuild the False bit? This should speed things up a bunch"
46
47
48 fieldList = [
49 'MessageID',
50 'RepeatIndicator',
51 'UserID',
52 'type',
53 'name',
54 'PositionAccuracy',
55 'Position_longitude',
56 'Position_latitude',
57 'dim',
58 'FixType',
59 'timestamp',
60 'OffPosition',
61 'RegionalApp',
62 'RAIM',
63 'Spare',
64 ]
65
66 -def encode(params, validate=False):
67 '''Create a AidsToNavReport binary message payload to pack into an AIS Msg AidsToNavReport.
68
69 Fields in params:
70 - MessageID(uint): AIS message number. Must be 21 aka 'F' (field automatically set to "21")
71 - RepeatIndicator(uint): Indicated how many times a message has been repeated
72 - UserID(uint): Unique ship identification number (MMSI)
73 - type(uint): IALA type of aid-to-navigation
74 - name(aisstr6): Name of the aid-to-navigation
75 - PositionAccuracy(uint): Accuracy of positioning fixes
76 - Position_longitude(decimal): Location of the vessel East West location
77 - Position_latitude(decimal): Location of the vessel North South location
78 - dim(uint): FIX: break this out.
79 - FixType(uint): Type of electronic position fixing device
80 - timestamp(uint): UTC second when report was generated
81 - OffPosition(bool): True when the AtoN is off station
82 - RegionalApp(uint): Should be set to zero (field automatically set to "0")
83 - RAIM(bool): Receiver autonomous integrity monitoring flag
84 - Spare(uint): Not Used (field automatically set to "0")
85 @param params: Dictionary of field names/values. Throws a ValueError exception if required is missing
86 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented.
87 @rtype: BitVector
88 @return: encoded binary message (for binary messages, this needs to be wrapped in a msg 8
89 @note: The returned bits may not be 6 bit aligned. It is up to you to pad out the bits.
90 '''
91
92 bvList = []
93 bvList.append(binary.setBitVectorSize(BitVector(intVal=21),6))
94 if 'RepeatIndicator' in params:
95 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['RepeatIndicator']),2))
96 else:
97 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2))
98 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['UserID']),30))
99 if 'type' in params:
100 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['type']),5))
101 else:
102 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),5))
103 if 'name' in params:
104 bvList.append(aisstring.encode(params['name'],120))
105 else:
106 bvList.append(aisstring.encode('@@@@@@@@@@@@@@@@@@@@',120))
107 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['PositionAccuracy']),1))
108 if 'Position_longitude' in params:
109 bvList.append(binary.bvFromSignedInt(int(Decimal(params['Position_longitude'])*Decimal('600000')),28))
110 else:
111 bvList.append(binary.bvFromSignedInt(108600000,28))
112 if 'Position_latitude' in params:
113 bvList.append(binary.bvFromSignedInt(int(Decimal(params['Position_latitude'])*Decimal('600000')),27))
114 else:
115 bvList.append(binary.bvFromSignedInt(54600000,27))
116 if 'dim' in params:
117 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['dim']),30))
118 else:
119 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),30))
120 if 'FixType' in params:
121 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['FixType']),4))
122 else:
123 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),4))
124 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['timestamp']),6))
125 if params["OffPosition"]: bvList.append(TrueBV)
126 else: bvList.append(FalseBV)
127 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),8))
128 if params["RAIM"]: bvList.append(TrueBV)
129 else: bvList.append(FalseBV)
130 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),3))
131
132 return binary.joinBV(bvList)
133
134 -def decode(bv, validate=False):
135 '''Unpack a AidsToNavReport message
136
137 Fields in params:
138 - MessageID(uint): AIS message number. Must be 21 aka 'F' (field automatically set to "21")
139 - RepeatIndicator(uint): Indicated how many times a message has been repeated
140 - UserID(uint): Unique ship identification number (MMSI)
141 - type(uint): IALA type of aid-to-navigation
142 - name(aisstr6): Name of the aid-to-navigation
143 - PositionAccuracy(uint): Accuracy of positioning fixes
144 - Position_longitude(decimal): Location of the vessel East West location
145 - Position_latitude(decimal): Location of the vessel North South location
146 - dim(uint): FIX: break this out.
147 - FixType(uint): Type of electronic position fixing device
148 - timestamp(uint): UTC second when report was generated
149 - OffPosition(bool): True when the AtoN is off station
150 - RegionalApp(uint): Should be set to zero (field automatically set to "0")
151 - RAIM(bool): Receiver autonomous integrity monitoring flag
152 - Spare(uint): Not Used (field automatically set to "0")
153 @type bv: BitVector
154 @param bv: Bits defining a message
155 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented.
156 @rtype: dict
157 @return: params
158 '''
159
160
161
162
163 r = {}
164 r['MessageID']=21
165 r['RepeatIndicator']=int(bv[6:8])
166 r['UserID']=int(bv[8:38])
167 r['type']=int(bv[38:43])
168 r['name']=aisstring.decode(bv[43:163])
169 r['PositionAccuracy']=int(bv[163:164])
170 r['Position_longitude']=Decimal(binary.signedIntFromBV(bv[164:192]))/Decimal('600000')
171 r['Position_latitude']=Decimal(binary.signedIntFromBV(bv[192:219]))/Decimal('600000')
172 r['dim']=int(bv[219:249])
173 r['FixType']=int(bv[249:253])
174 r['timestamp']=int(bv[253:259])
175 r['OffPosition']=bool(int(bv[259:260]))
176 r['RegionalApp']=0
177 r['RAIM']=bool(int(bv[268:269]))
178 r['Spare']=0
179 return r
180
182 return 21
183
186
189
191 return int(bv[38:43])
192
195
197 return int(bv[163:164])
198
201
204
206 return int(bv[219:249])
207
209 return int(bv[249:253])
210
212 return int(bv[253:259])
213
215 return bool(int(bv[259:260]))
216
218 return 0
219
221 return bool(int(bv[268:269]))
222
224 return 0
225
226
228 out.write("<h3>AidsToNavReport<h3>\n")
229 out.write("<table border=\"1\">\n")
230 out.write("<tr bgcolor=\"orange\">\n")
231 out.write("<th align=\"left\">Field Name</th>\n")
232 out.write("<th align=\"left\">Type</th>\n")
233 out.write("<th align=\"left\">Value</th>\n")
234 out.write("<th align=\"left\">Value in Lookup Table</th>\n")
235 out.write("<th align=\"left\">Units</th>\n")
236 out.write("\n")
237 out.write("<tr>\n")
238 out.write("<td>MessageID</td>\n")
239 out.write("<td>uint</td>\n")
240 if 'MessageID' in params:
241 out.write(" <td>"+str(params['MessageID'])+"</td>\n")
242 out.write(" <td>"+str(params['MessageID'])+"</td>\n")
243 out.write("</tr>\n")
244 out.write("\n")
245 out.write("<tr>\n")
246 out.write("<td>RepeatIndicator</td>\n")
247 out.write("<td>uint</td>\n")
248 if 'RepeatIndicator' in params:
249 out.write(" <td>"+str(params['RepeatIndicator'])+"</td>\n")
250 if str(params['RepeatIndicator']) in RepeatIndicatorDecodeLut:
251 out.write("<td>"+RepeatIndicatorDecodeLut[str(params['RepeatIndicator'])]+"</td>")
252 else:
253 out.write("<td><i>Missing LUT entry</i></td>")
254 out.write("</tr>\n")
255 out.write("\n")
256 out.write("<tr>\n")
257 out.write("<td>UserID</td>\n")
258 out.write("<td>uint</td>\n")
259 if 'UserID' in params:
260 out.write(" <td>"+str(params['UserID'])+"</td>\n")
261 out.write(" <td>"+str(params['UserID'])+"</td>\n")
262 out.write("</tr>\n")
263 out.write("\n")
264 out.write("<tr>\n")
265 out.write("<td>type</td>\n")
266 out.write("<td>uint</td>\n")
267 if 'type' in params:
268 out.write(" <td>"+str(params['type'])+"</td>\n")
269 if str(params['type']) in typeDecodeLut:
270 out.write("<td>"+typeDecodeLut[str(params['type'])]+"</td>")
271 else:
272 out.write("<td><i>Missing LUT entry</i></td>")
273 out.write("</tr>\n")
274 out.write("\n")
275 out.write("<tr>\n")
276 out.write("<td>name</td>\n")
277 out.write("<td>aisstr6</td>\n")
278 if 'name' in params:
279 out.write(" <td>"+str(params['name'])+"</td>\n")
280 out.write(" <td>"+str(params['name'])+"</td>\n")
281 out.write("</tr>\n")
282 out.write("\n")
283 out.write("<tr>\n")
284 out.write("<td>PositionAccuracy</td>\n")
285 out.write("<td>uint</td>\n")
286 if 'PositionAccuracy' in params:
287 out.write(" <td>"+str(params['PositionAccuracy'])+"</td>\n")
288 if str(params['PositionAccuracy']) in PositionAccuracyDecodeLut:
289 out.write("<td>"+PositionAccuracyDecodeLut[str(params['PositionAccuracy'])]+"</td>")
290 else:
291 out.write("<td><i>Missing LUT entry</i></td>")
292 out.write("</tr>\n")
293 out.write("\n")
294 out.write("<tr>\n")
295 out.write("<td>Position_longitude</td>\n")
296 out.write("<td>decimal</td>\n")
297 if 'Position_longitude' in params:
298 out.write(" <td>"+str(params['Position_longitude'])+"</td>\n")
299 out.write(" <td>"+str(params['Position_longitude'])+"</td>\n")
300 out.write("<td>degrees</td>\n")
301 out.write("</tr>\n")
302 out.write("\n")
303 out.write("<tr>\n")
304 out.write("<td>Position_latitude</td>\n")
305 out.write("<td>decimal</td>\n")
306 if 'Position_latitude' in params:
307 out.write(" <td>"+str(params['Position_latitude'])+"</td>\n")
308 out.write(" <td>"+str(params['Position_latitude'])+"</td>\n")
309 out.write("<td>degrees</td>\n")
310 out.write("</tr>\n")
311 out.write("\n")
312 out.write("<tr>\n")
313 out.write("<td>dim</td>\n")
314 out.write("<td>uint</td>\n")
315 if 'dim' in params:
316 out.write(" <td>"+str(params['dim'])+"</td>\n")
317 out.write(" <td>"+str(params['dim'])+"</td>\n")
318 out.write("</tr>\n")
319 out.write("\n")
320 out.write("<tr>\n")
321 out.write("<td>FixType</td>\n")
322 out.write("<td>uint</td>\n")
323 if 'FixType' in params:
324 out.write(" <td>"+str(params['FixType'])+"</td>\n")
325 if str(params['FixType']) in FixTypeDecodeLut:
326 out.write("<td>"+FixTypeDecodeLut[str(params['FixType'])]+"</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>timestamp</td>\n")
333 out.write("<td>uint</td>\n")
334 if 'timestamp' in params:
335 out.write(" <td>"+str(params['timestamp'])+"</td>\n")
336 if str(params['timestamp']) in timestampDecodeLut:
337 out.write("<td>"+timestampDecodeLut[str(params['timestamp'])]+"</td>")
338 else:
339 out.write("<td><i>Missing LUT entry</i></td>")
340 out.write("</tr>\n")
341 out.write("\n")
342 out.write("<tr>\n")
343 out.write("<td>OffPosition</td>\n")
344 out.write("<td>bool</td>\n")
345 if 'OffPosition' in params:
346 out.write(" <td>"+str(params['OffPosition'])+"</td>\n")
347 if str(params['OffPosition']) in OffPositionDecodeLut:
348 out.write("<td>"+OffPositionDecodeLut[str(params['OffPosition'])]+"</td>")
349 else:
350 out.write("<td><i>Missing LUT entry</i></td>")
351 out.write("</tr>\n")
352 out.write("\n")
353 out.write("<tr>\n")
354 out.write("<td>RegionalApp</td>\n")
355 out.write("<td>uint</td>\n")
356 if 'RegionalApp' in params:
357 out.write(" <td>"+str(params['RegionalApp'])+"</td>\n")
358 out.write(" <td>"+str(params['RegionalApp'])+"</td>\n")
359 out.write("</tr>\n")
360 out.write("\n")
361 out.write("<tr>\n")
362 out.write("<td>RAIM</td>\n")
363 out.write("<td>bool</td>\n")
364 if 'RAIM' in params:
365 out.write(" <td>"+str(params['RAIM'])+"</td>\n")
366 if str(params['RAIM']) in RAIMDecodeLut:
367 out.write("<td>"+RAIMDecodeLut[str(params['RAIM'])]+"</td>")
368 else:
369 out.write("<td><i>Missing LUT entry</i></td>")
370 out.write("</tr>\n")
371 out.write("\n")
372 out.write("<tr>\n")
373 out.write("<td>Spare</td>\n")
374 out.write("<td>uint</td>\n")
375 if 'Spare' in params:
376 out.write(" <td>"+str(params['Spare'])+"</td>\n")
377 out.write(" <td>"+str(params['Spare'])+"</td>\n")
378 out.write("</tr>\n")
379 out.write("</table>\n")
380
381
383 '''KML (Keyhole Markup Language) for Google Earth, but without the header/footer'''
384 out.write("\ <Placemark>\n")
385 out.write("\t <name>"+str(params['UserID'])+"</name>\n")
386 out.write("\t\t<description>\n")
387 import StringIO
388 buf = StringIO.StringIO()
389 printHtml(params,buf)
390 import cgi
391 out.write(cgi.escape(buf.getvalue()))
392 out.write("\t\t</description>\n")
393 out.write("\t\t<styleUrl>#m_ylw-pushpin_copy0</styleUrl>\n")
394 out.write("\t\t<Point>\n")
395 out.write("\t\t\t<coordinates>")
396 out.write(str(params['Position_longitude']))
397 out.write(',')
398 out.write(str(params['Position_latitude']))
399 out.write(",0</coordinates>\n")
400 out.write("\t\t</Point>\n")
401 out.write("\t</Placemark>\n")
402
403 -def printFields(params, out=sys.stdout, format='std', fieldList=None):
404 '''Print a Spare message to stdout.
405
406 Fields in params:
407 - MessageID(uint): AIS message number. Must be 21 aka 'F' (field automatically set to "21")
408 - RepeatIndicator(uint): Indicated how many times a message has been repeated
409 - UserID(uint): Unique ship identification number (MMSI)
410 - type(uint): IALA type of aid-to-navigation
411 - name(aisstr6): Name of the aid-to-navigation
412 - PositionAccuracy(uint): Accuracy of positioning fixes
413 - Position_longitude(decimal): Location of the vessel East West location
414 - Position_latitude(decimal): Location of the vessel North South location
415 - dim(uint): FIX: break this out.
416 - FixType(uint): Type of electronic position fixing device
417 - timestamp(uint): UTC second when report was generated
418 - OffPosition(bool): True when the AtoN is off station
419 - RegionalApp(uint): Should be set to zero (field automatically set to "0")
420 - RAIM(bool): Receiver autonomous integrity monitoring flag
421 - Spare(uint): Not Used (field automatically set to "0")
422 @param params: Dictionary of field names/values.
423 @param out: File like object to write to
424 @rtype: stdout
425 @return: text to out
426 '''
427
428 if 'std'==format:
429 out.write("Spare:\n")
430 if 'MessageID' in params: out.write(" MessageID: "+str(params['MessageID'])+"\n")
431 if 'RepeatIndicator' in params: out.write(" RepeatIndicator: "+str(params['RepeatIndicator'])+"\n")
432 if 'UserID' in params: out.write(" UserID: "+str(params['UserID'])+"\n")
433 if 'type' in params: out.write(" type: "+str(params['type'])+"\n")
434 if 'name' in params: out.write(" name: "+str(params['name'])+"\n")
435 if 'PositionAccuracy' in params: out.write(" PositionAccuracy: "+str(params['PositionAccuracy'])+"\n")
436 if 'Position_longitude' in params: out.write(" Position_longitude: "+str(params['Position_longitude'])+"\n")
437 if 'Position_latitude' in params: out.write(" Position_latitude: "+str(params['Position_latitude'])+"\n")
438 if 'dim' in params: out.write(" dim: "+str(params['dim'])+"\n")
439 if 'FixType' in params: out.write(" FixType: "+str(params['FixType'])+"\n")
440 if 'timestamp' in params: out.write(" timestamp: "+str(params['timestamp'])+"\n")
441 if 'OffPosition' in params: out.write(" OffPosition: "+str(params['OffPosition'])+"\n")
442 if 'RegionalApp' in params: out.write(" RegionalApp: "+str(params['RegionalApp'])+"\n")
443 if 'RAIM' in params: out.write(" RAIM: "+str(params['RAIM'])+"\n")
444 if 'Spare' in params: out.write(" Spare: "+str(params['Spare'])+"\n")
445 elif 'csv'==format:
446 if None == options.fieldList:
447 options.fieldList = fieldList
448 needComma = False;
449 for field in fieldList:
450 if needComma: out.write(',')
451 needComma = True
452 if field in params:
453 out.write(str(params[field]))
454
455 out.write("\n")
456 elif 'html'==format:
457 printHtml(params,out)
458 elif 'sql'==format:
459 sqlInsertStr(params,out)
460 elif 'kml'==format:
461 printKml(params,out)
462 elif 'kml-full'==format:
463 out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
464 out.write("<kml xmlns=\"http://earth.google.com/kml/2.1\">\n")
465 out.write("<Document>\n")
466 out.write(" <name>AidsToNavReport</name>\n")
467 printKml(params,out)
468 out.write("</Document>\n")
469 out.write("</kml>\n")
470 else:
471 print "ERROR: unknown format:",format
472 assert False
473
474 return
475
476 RepeatIndicatorEncodeLut = {
477 'default':'0',
478 'do not repeat any more':'3',
479 }
480
481 RepeatIndicatorDecodeLut = {
482 '0':'default',
483 '3':'do not repeat any more',
484 }
485
486 typeEncodeLut = {
487 'Default, Type of A to N not specified':'0',
488 'Reference point':'1',
489 'RACON':'2',
490 'Off Shore Structure':'3',
491 'Spare':'4',
492 'Light, without sectors':'5',
493 'Light, with sectors':'6',
494 'Leading Light Front':'7',
495 'Leading Light Rear':'8',
496 'Beacon, Cardinal N':'9',
497 'Beacon, Cardinal E':'10',
498 'Beacon, Cardinal S':'11',
499 'Beacon, Cardinal W':'12',
500 'Beacon, Port hand':'13',
501 'Beacon, Starbord hand':'14',
502 'Beacon, Preferred channel port hand':'15',
503 'Beacon, Preferred channel starboard hand':'16',
504 'Beacon, Isolated danger':'17',
505 'Beacon, Safe water':'18',
506 'Beacon, Special mark':'19',
507 'Cardinal Mark N':'20',
508 'Cardinal Mark E':'21',
509 'Cardinal Mark S':'22',
510 'Cardinal Mark W':'23',
511 'Port hand Mark':'24',
512 'Starbord hand Mark':'25',
513 'Preferred Channel Port hand':'26',
514 'Preferred Channel Starboard hand':'27',
515 'Isolated danger':'28',
516 'Safe water':'29',
517 'Special Mark':'30',
518 'Light Vessel/LANBY':'31',
519 }
520
521 typeDecodeLut = {
522 '0':'Default, Type of A to N not specified',
523 '1':'Reference point',
524 '2':'RACON',
525 '3':'Off Shore Structure',
526 '4':'Spare',
527 '5':'Light, without sectors',
528 '6':'Light, with sectors',
529 '7':'Leading Light Front',
530 '8':'Leading Light Rear',
531 '9':'Beacon, Cardinal N',
532 '10':'Beacon, Cardinal E',
533 '11':'Beacon, Cardinal S',
534 '12':'Beacon, Cardinal W',
535 '13':'Beacon, Port hand',
536 '14':'Beacon, Starbord hand',
537 '15':'Beacon, Preferred channel port hand',
538 '16':'Beacon, Preferred channel starboard hand',
539 '17':'Beacon, Isolated danger',
540 '18':'Beacon, Safe water',
541 '19':'Beacon, Special mark',
542 '20':'Cardinal Mark N',
543 '21':'Cardinal Mark E',
544 '22':'Cardinal Mark S',
545 '23':'Cardinal Mark W',
546 '24':'Port hand Mark',
547 '25':'Starbord hand Mark',
548 '26':'Preferred Channel Port hand',
549 '27':'Preferred Channel Starboard hand',
550 '28':'Isolated danger',
551 '29':'Safe water',
552 '30':'Special Mark',
553 '31':'Light Vessel/LANBY',
554 }
555
556 PositionAccuracyEncodeLut = {
557 'low (greater than 10 m)':'0',
558 'high (less than 10 m)':'1',
559 }
560
561 PositionAccuracyDecodeLut = {
562 '0':'low (greater than 10 m)',
563 '1':'high (less than 10 m)',
564 }
565
566 FixTypeEncodeLut = {
567 'Undefined (default)':'0',
568 'GPS':'1',
569 'GLONASS':'2',
570 'Combined GPS/GLONASS':'3',
571 'Loran-C':'4',
572 'Chayka':'5',
573 'Integrated Navigation System':'6',
574 'surveyed':'7',
575 'not used - 8':'8',
576 'not used - 9':'9',
577 'not used - 10':'10',
578 'not used - 11':'11',
579 'not used - 12':'12',
580 'not used - 13':'13',
581 'not used - 14':'14',
582 'not used - 15':'15',
583 }
584
585 FixTypeDecodeLut = {
586 '0':'Undefined (default)',
587 '1':'GPS',
588 '2':'GLONASS',
589 '3':'Combined GPS/GLONASS',
590 '4':'Loran-C',
591 '5':'Chayka',
592 '6':'Integrated Navigation System',
593 '7':'surveyed',
594 '8':'not used - 8',
595 '9':'not used - 9',
596 '10':'not used - 10',
597 '11':'not used - 11',
598 '12':'not used - 12',
599 '13':'not used - 13',
600 '14':'not used - 14',
601 '15':'not used - 15',
602 }
603
604 timestampEncodeLut = {
605 'Positioning system is in manual mode':'61',
606 'Electronic position fixing system operates in estimated mode':'62',
607 'Positioning system is inoperative':'63',
608 }
609
610 timestampDecodeLut = {
611 '61':'Positioning system is in manual mode',
612 '62':'Electronic position fixing system operates in estimated mode',
613 '63':'Positioning system is inoperative',
614 }
615
616 OffPositionEncodeLut = {
617 'On position':'False',
618 'Off position':'True',
619 }
620
621 OffPositionDecodeLut = {
622 'False':'On position',
623 'True':'Off position',
624 }
625
626 RAIMEncodeLut = {
627 'not in use':'False',
628 'in use':'True',
629 }
630
631 RAIMDecodeLut = {
632 'False':'not in use',
633 'True':'in use',
634 }
635
636
637
638
639
640 -def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None, addCoastGuardFields=True):
641 '''
642 Return the SQL CREATE command for this message type
643 @param outfile: file like object to print to.
644 @param fields: which fields to put in the create. Defaults to all.
645 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields
646 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format
647 @type addCoastGuardFields: bool
648 @return: sql create string
649 @rtype: str
650
651 @see: sqlCreate
652 '''
653 outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields)))
654
655 -def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True):
656 '''
657 Return the sqlhelp object to create the table.
658
659 @param fields: which fields to put in the create. Defaults to all.
660 @param extraFields: A sequence of tuples containing (name,sql type) for additional fields
661 @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format
662 @type addCoastGuardFields: bool
663 @return: An object that can be used to generate a return
664 @rtype: sqlhelp.create
665 '''
666 if None == fields: fields = fieldList
667 import sqlhelp
668 c = sqlhelp.create('AidsToNavReport')
669 if 'MessageID' in fields: c.addInt ('MessageID')
670 if 'RepeatIndicator' in fields: c.addInt ('RepeatIndicator')
671 if 'UserID' in fields: c.addInt ('UserID')
672 if 'type' in fields: c.addInt ('type')
673 if 'name' in fields: c.addVarChar('name',20)
674 if 'PositionAccuracy' in fields: c.addInt ('PositionAccuracy')
675 if 'Position_longitude' in fields: c.addDecimal('Position_longitude',8,5)
676 if 'Position_latitude' in fields: c.addDecimal('Position_latitude',8,5)
677 if 'dim' in fields: c.addInt ('dim')
678 if 'FixType' in fields: c.addInt ('FixType')
679 if 'timestamp' in fields: c.addInt ('timestamp')
680 if 'OffPosition' in fields: c.addBool('OffPosition')
681 if 'RegionalApp' in fields: c.addInt ('RegionalApp')
682 if 'RAIM' in fields: c.addBool('RAIM')
683 if 'Spare' in fields: c.addInt ('Spare')
684
685 if addCoastGuardFields:
686
687
688
689
690
691 c.addVarChar('cg_r',15)
692 c.addInt('cg_timestamp')
693
694
695 return c
696
697 -def sqlInsertStr(params, outfile=sys.stdout, extraParams=None):
698 '''
699 Return the SQL CREATE command for this message type
700 @param params: dictionary of values keyed by field name
701 @param outfile: file like object to print to.
702 @param extraParams: A sequence of tuples containing (name,sql type) for additional fields
703 @return: sql create string
704 @rtype: str
705
706 @see: sqlCreate
707 '''
708 outfile.write(str(sqlInsert(params,extraParams)))
709
710
712 '''
713 Give the SQL insert statement
714 @param params: dict keyed by field name of values
715 @param extraParams: any extra fields that you have created beyond the normal ais message fields
716 @rtype: sqlhelp.insert
717 @return: insert class instance
718 @todo: allow optional type checking of params?
719 @warning: this will take invalid keys happily and do what???
720 '''
721 import sqlhelp
722 i = sqlhelp.insert('AidsToNavReport')
723 for key in params:
724
725 if type(params[key])==Decimal: i.add(key,float(params[key]))
726 else: i.add(key,params[key])
727 if None != extraParams:
728 for key in extraParams:
729 i.add(key,extraParams[key])
730
731 return i
732
733
734
735
736
737 import unittest
739 '''Return a params file base on the testvalue tags.
740 @rtype: dict
741 @return: params based on testvalue tags
742 '''
743 params = {}
744 params['MessageID'] = 21
745 params['RepeatIndicator'] = 1
746 params['UserID'] = 1193046
747 params['type'] = 28
748 params['name'] = 'BUNCH OF ROCKS ATON@'
749 params['PositionAccuracy'] = 1
750 params['Position_longitude'] = Decimal('-122.16328055555556')
751 params['Position_latitude'] = Decimal('37.424458333333334')
752 params['dim'] = 0
753 params['FixType'] = 2
754 params['timestamp'] = 62
755 params['OffPosition'] = False
756 params['RegionalApp'] = 0
757 params['RAIM'] = False
758 params['Spare'] = 0
759
760 return params
761
763 '''Use testvalue tag text from each type to build test case the AidsToNavReport message'''
765
766 params = testParams()
767 bits = encode(params)
768 r = decode(bits)
769
770
771 self.failUnlessEqual(r['MessageID'],params['MessageID'])
772 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator'])
773 self.failUnlessEqual(r['UserID'],params['UserID'])
774 self.failUnlessEqual(r['type'],params['type'])
775 self.failUnlessEqual(r['name'],params['name'])
776 self.failUnlessEqual(r['PositionAccuracy'],params['PositionAccuracy'])
777 self.failUnlessAlmostEqual(r['Position_longitude'],params['Position_longitude'],5)
778 self.failUnlessAlmostEqual(r['Position_latitude'],params['Position_latitude'],5)
779 self.failUnlessEqual(r['dim'],params['dim'])
780 self.failUnlessEqual(r['FixType'],params['FixType'])
781 self.failUnlessEqual(r['timestamp'],params['timestamp'])
782 self.failUnlessEqual(r['OffPosition'],params['OffPosition'])
783 self.failUnlessEqual(r['RegionalApp'],params['RegionalApp'])
784 self.failUnlessEqual(r['RAIM'],params['RAIM'])
785 self.failUnlessEqual(r['Spare'],params['Spare'])
786
788 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true',
789 help='decode a "AidsToNavReport" AIS message')
790 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true',
791 help='encode a "AidsToNavReport" AIS message')
792 parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int'
793 ,help='Field parameter value [default: %default]')
794 parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int'
795 ,help='Field parameter value [default: %default]')
796 parser.add_option('--type-field', dest='typeField',default=0,metavar='uint',type='int'
797 ,help='Field parameter value [default: %default]')
798 parser.add_option('--name-field', dest='nameField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string'
799 ,help='Field parameter value [default: %default]')
800 parser.add_option('--PositionAccuracy-field', dest='PositionAccuracyField',metavar='uint',type='int'
801 ,help='Field parameter value [default: %default]')
802 parser.add_option('--Position_longitude-field', dest='Position_longitudeField',default=Decimal('181'),metavar='decimal',type='string'
803 ,help='Field parameter value [default: %default]')
804 parser.add_option('--Position_latitude-field', dest='Position_latitudeField',default=Decimal('91'),metavar='decimal',type='string'
805 ,help='Field parameter value [default: %default]')
806 parser.add_option('--dim-field', dest='dimField',default=0,metavar='uint',type='int'
807 ,help='Field parameter value [default: %default]')
808 parser.add_option('--FixType-field', dest='FixTypeField',default=0,metavar='uint',type='int'
809 ,help='Field parameter value [default: %default]')
810 parser.add_option('--timestamp-field', dest='timestampField',metavar='uint',type='int'
811 ,help='Field parameter value [default: %default]')
812 parser.add_option('--OffPosition-field', dest='OffPositionField',metavar='bool',type='int'
813 ,help='Field parameter value [default: %default]')
814 parser.add_option('--RAIM-field', dest='RAIMField',metavar='bool',type='int'
815 ,help='Field parameter value [default: %default]')
816
817
818 if __name__=='__main__':
819
820 from optparse import OptionParser
821 parser = OptionParser(usage="%prog [options]",
822 version="%prog "+__version__)
823
824 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true',
825 help='run the documentation tests')
826 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true',
827 help='run the unit tests')
828 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true',
829 help='Make the test output verbose')
830
831
832
833 typeChoices = ('binary','nmeapayload','nmea')
834 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType'
835 ,default='nmeapayload'
836 ,help='What kind of string to expect ('+', '.join(typeChoices)+') [default: %default]')
837
838
839 outputChoices = ('std','html','csv','sql' , 'kml','kml-full')
840 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType'
841 ,default='std'
842 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]')
843
844 parser.add_option('-o','--output',dest='outputFileName',default=None,
845 help='Name of the python file to write [default: stdout]')
846
847 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append',
848 choices=fieldList,
849 help='Which fields to include in the output. Currently only for csv output [default: all]')
850
851 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true',
852 help='Print the field name for csv')
853
854 parser.add_option('-c','--sql-create',dest='sqlCreate',default=False,action='store_true',
855 help='Print out an sql create command for the table.')
856
857 addMsgOptions(parser)
858
859 (options,args) = parser.parse_args()
860 success=True
861
862 if options.doctest:
863 import os; print os.path.basename(sys.argv[0]), 'doctests ...',
864 sys.argv= [sys.argv[0]]
865 if options.verbose: sys.argv.append('-v')
866 import doctest
867 numfail,numtests=doctest.testmod()
868 if numfail==0: print 'ok'
869 else:
870 print 'FAILED'
871 success=False
872
873 if not success: sys.exit('Something Failed')
874 del success
875
876 if options.unittest:
877 sys.argv = [sys.argv[0]]
878 if options.verbose: sys.argv.append('-v')
879 unittest.main()
880
881 outfile = sys.stdout
882 if None!=options.outputFileName:
883 outfile = file(options.outputFileName,'w')
884
885
886 if options.doEncode:
887
888 if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField")
889 if None==options.UserIDField: parser.error("missing value for UserIDField")
890 if None==options.typeField: parser.error("missing value for typeField")
891 if None==options.nameField: parser.error("missing value for nameField")
892 if None==options.PositionAccuracyField: parser.error("missing value for PositionAccuracyField")
893 if None==options.Position_longitudeField: parser.error("missing value for Position_longitudeField")
894 if None==options.Position_latitudeField: parser.error("missing value for Position_latitudeField")
895 if None==options.dimField: parser.error("missing value for dimField")
896 if None==options.FixTypeField: parser.error("missing value for FixTypeField")
897 if None==options.timestampField: parser.error("missing value for timestampField")
898 if None==options.OffPositionField: parser.error("missing value for OffPositionField")
899 if None==options.RAIMField: parser.error("missing value for RAIMField")
900 msgDict={
901 'MessageID': '21',
902 'RepeatIndicator': options.RepeatIndicatorField,
903 'UserID': options.UserIDField,
904 'type': options.typeField,
905 'name': options.nameField,
906 'PositionAccuracy': options.PositionAccuracyField,
907 'Position_longitude': options.Position_longitudeField,
908 'Position_latitude': options.Position_latitudeField,
909 'dim': options.dimField,
910 'FixType': options.FixTypeField,
911 'timestamp': options.timestampField,
912 'OffPosition': options.OffPositionField,
913 'RegionalApp': '0',
914 'RAIM': options.RAIMField,
915 'Spare': '0',
916 }
917
918 bits = encode(msgDict)
919 if 'binary'==options.ioType: print str(bits)
920 elif 'nmeapayload'==options.ioType:
921
922 print "bitLen",len(bits)
923 bitLen=len(bits)
924 if bitLen%6!=0:
925 bits = bits + BitVector(size=(6 - (bitLen%6)))
926 print "result:",binary.bitvectoais6(bits)[0]
927
928
929
930 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability")
931 else: sys.exit('ERROR: unknown ioType. Help!')
932
933
934 if options.sqlCreate:
935 sqlCreateStr(outfile,options.fieldList)
936
937 if options.printCsvfieldList:
938
939 if None == options.fieldList: options.fieldList = fieldList
940 import StringIO
941 buf = StringIO.StringIO()
942 for field in options.fieldList:
943 buf.write(field+',')
944 result = buf.getvalue()
945 if result[-1] == ',': print result[:-1]
946 else: print result
947
948 if options.doDecode:
949 for msg in args:
950 bv = None
951 if 'binary' == options.ioType: bv = BitVector(bitstring=msg)
952 elif 'nmeapayload'== options.ioType: bv = binary.ais6tobitvec(msg)
953 elif 'nmea' == options.ioType: bv = binary.ais6tobitvec(msg.split(',')[5])
954 else: sys.exit('ERROR: unknown ioType. Help!')
955
956 printFields(decode(bv),out=outfile,format=options.outputType,fieldList=options.fieldList)
957