1
2
3 __version__ = '$Revision: 4791 $'.split()[1]
4 __date__ = '$Date: 2007-01-18 $'.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 'kml'==format:
459 printKml(params,out)
460 elif 'kml-full'==format:
461 out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
462 out.write("<kml xmlns=\"http://earth.google.com/kml/2.1\">\n")
463 out.write("<Document>\n")
464 out.write(" <name>Position</name>\n")
465 printKml(params,out)
466 out.write("</Document>\n")
467 out.write("</kml>\n")
468 else:
469 print "ERROR: unknown format:",format
470 assert False
471
472 return
473
474 RepeatIndicatorEncodeLut = {
475 'default':'0',
476 'do not repeat any more':'3',
477 }
478
479 RepeatIndicatorDecodeLut = {
480 '0':'default',
481 '3':'do not repeat any more',
482 }
483
484 typeEncodeLut = {
485 'Default, Type of A to N not specified':'0',
486 'Reference point':'1',
487 'RACON':'2',
488 'Off Shore Structure':'3',
489 'Spare':'4',
490 'Light, without sectors':'5',
491 'Light, with sectors':'6',
492 'Leading Light Front':'7',
493 'Leading Light Rear':'8',
494 'Beacon, Cardinal N':'9',
495 'Beacon, Cardinal E':'10',
496 'Beacon, Cardinal S':'11',
497 'Beacon, Cardinal W':'12',
498 'Beacon, Port hand':'13',
499 'Beacon, Starbord hand':'14',
500 'Beacon, Preferred channel port hand':'15',
501 'Beacon, Preferred channel starboard hand':'16',
502 'Beacon, Isolated danger':'17',
503 'Beacon, Safe water':'18',
504 'Beacon, Special mark':'19',
505 'Cardinal Mark N':'20',
506 'Cardinal Mark E':'21',
507 'Cardinal Mark S':'22',
508 'Cardinal Mark W':'23',
509 'Port hand Mark':'24',
510 'Starbord hand Mark':'25',
511 'Preferred Channel Port hand':'26',
512 'Preferred Channel Starboard hand':'27',
513 'Isolated danger':'28',
514 'Safe water':'29',
515 'Special Mark':'30',
516 'Light Vessel/LANBY':'31',
517 }
518
519 typeDecodeLut = {
520 '0':'Default, Type of A to N not specified',
521 '1':'Reference point',
522 '2':'RACON',
523 '3':'Off Shore Structure',
524 '4':'Spare',
525 '5':'Light, without sectors',
526 '6':'Light, with sectors',
527 '7':'Leading Light Front',
528 '8':'Leading Light Rear',
529 '9':'Beacon, Cardinal N',
530 '10':'Beacon, Cardinal E',
531 '11':'Beacon, Cardinal S',
532 '12':'Beacon, Cardinal W',
533 '13':'Beacon, Port hand',
534 '14':'Beacon, Starbord hand',
535 '15':'Beacon, Preferred channel port hand',
536 '16':'Beacon, Preferred channel starboard hand',
537 '17':'Beacon, Isolated danger',
538 '18':'Beacon, Safe water',
539 '19':'Beacon, Special mark',
540 '20':'Cardinal Mark N',
541 '21':'Cardinal Mark E',
542 '22':'Cardinal Mark S',
543 '23':'Cardinal Mark W',
544 '24':'Port hand Mark',
545 '25':'Starbord hand Mark',
546 '26':'Preferred Channel Port hand',
547 '27':'Preferred Channel Starboard hand',
548 '28':'Isolated danger',
549 '29':'Safe water',
550 '30':'Special Mark',
551 '31':'Light Vessel/LANBY',
552 }
553
554 PositionAccuracyEncodeLut = {
555 'low (greater than 10 m)':'0',
556 'high (less than 10 m)':'1',
557 }
558
559 PositionAccuracyDecodeLut = {
560 '0':'low (greater than 10 m)',
561 '1':'high (less than 10 m)',
562 }
563
564 FixTypeEncodeLut = {
565 'Undefined (default)':'0',
566 'GPS':'1',
567 'GLONASS':'2',
568 'Combined GPS/GLONASS':'3',
569 'Loran-C':'4',
570 'Chayka':'5',
571 'Integrated Navigation System':'6',
572 'surveyed':'7',
573 'not used - 8':'8',
574 'not used - 9':'9',
575 'not used - 10':'10',
576 'not used - 11':'11',
577 'not used - 12':'12',
578 'not used - 13':'13',
579 'not used - 14':'14',
580 'not used - 15':'15',
581 }
582
583 FixTypeDecodeLut = {
584 '0':'Undefined (default)',
585 '1':'GPS',
586 '2':'GLONASS',
587 '3':'Combined GPS/GLONASS',
588 '4':'Loran-C',
589 '5':'Chayka',
590 '6':'Integrated Navigation System',
591 '7':'surveyed',
592 '8':'not used - 8',
593 '9':'not used - 9',
594 '10':'not used - 10',
595 '11':'not used - 11',
596 '12':'not used - 12',
597 '13':'not used - 13',
598 '14':'not used - 14',
599 '15':'not used - 15',
600 }
601
602 timestampEncodeLut = {
603 'Positioning system is in manual mode':'61',
604 'Electronic position fixing system operates in estimated mode':'62',
605 'Positioning system is inoperative':'63',
606 }
607
608 timestampDecodeLut = {
609 '61':'Positioning system is in manual mode',
610 '62':'Electronic position fixing system operates in estimated mode',
611 '63':'Positioning system is inoperative',
612 }
613
614 OffPositionEncodeLut = {
615 'On position':'False',
616 'Off position':'True',
617 }
618
619 OffPositionDecodeLut = {
620 'False':'On position',
621 'True':'Off position',
622 }
623
624 RAIMEncodeLut = {
625 'not in use':'False',
626 'in use':'True',
627 }
628
629 RAIMDecodeLut = {
630 'False':'not in use',
631 'True':'in use',
632 }
633
634
635
636
637
638
639 import unittest
641 '''Return a params file base on the testvalue tags.
642 @rtype: dict
643 @return: params based on testvalue tags
644 '''
645 params = {}
646 params['MessageID'] = 21
647 params['RepeatIndicator'] = 1
648 params['UserID'] = 1193046
649 params['type'] = 28
650 params['name'] = 'BUNCH OF ROCKS ATON@'
651 params['PositionAccuracy'] = 1
652 params['Position_longitude'] = Decimal('-122.16328055555556')
653 params['Position_latitude'] = Decimal('37.424458333333334')
654 params['dim'] = 0
655 params['FixType'] = 2
656 params['timestamp'] = 62
657 params['OffPosition'] = False
658 params['RegionalApp'] = 0
659 params['RAIM'] = False
660 params['Spare'] = 0
661
662 return params
663
665 '''Use testvalue tag text from each type to build test case the AidsToNavReport message'''
667
668 params = testParams()
669 bits = encode(params)
670 r = decode(bits)
671
672
673 self.failUnlessEqual(r['MessageID'],params['MessageID'])
674 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator'])
675 self.failUnlessEqual(r['UserID'],params['UserID'])
676 self.failUnlessEqual(r['type'],params['type'])
677 self.failUnlessEqual(r['name'],params['name'])
678 self.failUnlessEqual(r['PositionAccuracy'],params['PositionAccuracy'])
679 self.failUnlessAlmostEqual(r['Position_longitude'],params['Position_longitude'],5)
680 self.failUnlessAlmostEqual(r['Position_latitude'],params['Position_latitude'],5)
681 self.failUnlessEqual(r['dim'],params['dim'])
682 self.failUnlessEqual(r['FixType'],params['FixType'])
683 self.failUnlessEqual(r['timestamp'],params['timestamp'])
684 self.failUnlessEqual(r['OffPosition'],params['OffPosition'])
685 self.failUnlessEqual(r['RegionalApp'],params['RegionalApp'])
686 self.failUnlessEqual(r['RAIM'],params['RAIM'])
687 self.failUnlessEqual(r['Spare'],params['Spare'])
688
690 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true',
691 help='decode a "AidsToNavReport" AIS message')
692 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true',
693 help='encode a "AidsToNavReport" AIS message')
694 parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int'
695 ,help='Field parameter value [default: %default]')
696 parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int'
697 ,help='Field parameter value [default: %default]')
698 parser.add_option('--type-field', dest='typeField',default=0,metavar='uint',type='int'
699 ,help='Field parameter value [default: %default]')
700 parser.add_option('--name-field', dest='nameField',default='@@@@@@@@@@@@@@@@@@@@',metavar='aisstr6',type='string'
701 ,help='Field parameter value [default: %default]')
702 parser.add_option('--PositionAccuracy-field', dest='PositionAccuracyField',metavar='uint',type='int'
703 ,help='Field parameter value [default: %default]')
704 parser.add_option('--Position_longitude-field', dest='Position_longitudeField',default=Decimal('181'),metavar='decimal',type='string'
705 ,help='Field parameter value [default: %default]')
706 parser.add_option('--Position_latitude-field', dest='Position_latitudeField',default=Decimal('91'),metavar='decimal',type='string'
707 ,help='Field parameter value [default: %default]')
708 parser.add_option('--dim-field', dest='dimField',default=0,metavar='uint',type='int'
709 ,help='Field parameter value [default: %default]')
710 parser.add_option('--FixType-field', dest='FixTypeField',default=0,metavar='uint',type='int'
711 ,help='Field parameter value [default: %default]')
712 parser.add_option('--timestamp-field', dest='timestampField',metavar='uint',type='int'
713 ,help='Field parameter value [default: %default]')
714 parser.add_option('--OffPosition-field', dest='OffPositionField',metavar='bool',type='int'
715 ,help='Field parameter value [default: %default]')
716 parser.add_option('--RAIM-field', dest='RAIMField',metavar='bool',type='int'
717 ,help='Field parameter value [default: %default]')
718
719
720 if __name__=='__main__':
721
722 from optparse import OptionParser
723 parser = OptionParser(usage="%prog [options]",
724 version="%prog "+__version__)
725
726 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true',
727 help='run the documentation tests')
728 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true',
729 help='run the unit tests')
730 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true',
731 help='Make the test output verbose')
732
733
734
735 typeChoices = ('binary','nmeapayload','nmea')
736 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType'
737 ,default='nmeapayload'
738 ,help='What kind of string to expect ('+', '.join(typeChoices)+') [default: %default]')
739
740
741 outputChoices = ('std','html','csv' , 'kml','kml-full')
742 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType'
743 ,default='std'
744 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]')
745
746 parser.add_option('-o','--output',dest='outputFileName',default=None,
747 help='Name of the python file to write [default: stdout]')
748
749 parser.add_option('-f','--fields',dest='fieldList',default=None, action='append',
750 choices=fieldList,
751 help='Which fields to include in the output. Currently only for csv output [default: all]')
752
753 parser.add_option('-p','--print-csv-field-list',dest='printCsvfieldList',default=False,action='store_true',
754 help='Print the field name for csv')
755
756 addMsgOptions(parser)
757
758 (options,args) = parser.parse_args()
759 success=True
760
761 if options.doctest:
762 import os; print os.path.basename(sys.argv[0]), 'doctests ...',
763 sys.argv= [sys.argv[0]]
764 if options.verbose: sys.argv.append('-v')
765 import doctest
766 numfail,numtests=doctest.testmod()
767 if numfail==0: print 'ok'
768 else:
769 print 'FAILED'
770 success=False
771
772 if not success: sys.exit('Something Failed')
773 del success
774
775 if options.unittest:
776 sys.argv = [sys.argv[0]]
777 if options.verbose: sys.argv.append('-v')
778 unittest.main()
779
780 outfile = sys.stdout
781 if None!=options.outputFileName:
782 outfile = file(options.outputFileName,'w')
783
784
785 if options.doEncode:
786
787 if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField")
788 if None==options.UserIDField: parser.error("missing value for UserIDField")
789 if None==options.typeField: parser.error("missing value for typeField")
790 if None==options.nameField: parser.error("missing value for nameField")
791 if None==options.PositionAccuracyField: parser.error("missing value for PositionAccuracyField")
792 if None==options.Position_longitudeField: parser.error("missing value for Position_longitudeField")
793 if None==options.Position_latitudeField: parser.error("missing value for Position_latitudeField")
794 if None==options.dimField: parser.error("missing value for dimField")
795 if None==options.FixTypeField: parser.error("missing value for FixTypeField")
796 if None==options.timestampField: parser.error("missing value for timestampField")
797 if None==options.OffPositionField: parser.error("missing value for OffPositionField")
798 if None==options.RAIMField: parser.error("missing value for RAIMField")
799 msgDict={
800 'MessageID': '21',
801 'RepeatIndicator': options.RepeatIndicatorField,
802 'UserID': options.UserIDField,
803 'type': options.typeField,
804 'name': options.nameField,
805 'PositionAccuracy': options.PositionAccuracyField,
806 'Position_longitude': options.Position_longitudeField,
807 'Position_latitude': options.Position_latitudeField,
808 'dim': options.dimField,
809 'FixType': options.FixTypeField,
810 'timestamp': options.timestampField,
811 'OffPosition': options.OffPositionField,
812 'RegionalApp': '0',
813 'RAIM': options.RAIMField,
814 'Spare': '0',
815 }
816
817 bits = encode(msgDict)
818 if 'binary'==options.ioType: print str(bits)
819 elif 'nmeapayload'==options.ioType:
820
821 print "bitLen",len(bits)
822 bitLen=len(bits)
823 if bitLen%6!=0:
824 bits = bits + BitVector(size=(6 - (bitLen%6)))
825 print "result:",binary.bitvectoais6(bits)[0]
826
827
828
829 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability")
830 else: sys.exit('ERROR: unknown ioType. Help!')
831
832 if options.printCsvfieldList:
833
834 if None == options.fieldList: options.fieldList = fieldList
835 import StringIO
836 buf = StringIO.StringIO()
837 for field in options.fieldList:
838 buf.write(field+',')
839 result = buf.getvalue()
840 if result[-1] == ',': print result[:-1]
841 else: print result
842
843 if options.doDecode:
844 for msg in args:
845 bv = None
846 if 'binary' == options.ioType: bv = BitVector(bitstring=msg)
847 elif 'nmeapayload'== options.ioType: bv = binary.ais6tobitvec(msg)
848 elif 'nmea' == options.ioType: bv = binary.ais6tobitvec(msg.split(',')[5])
849 else: sys.exit('ERROR: unknown ioType. Help!')
850
851 printFields(decode(bv),out=outfile,format=options.outputType,fieldList=options.fieldList)
852