1
2
3 __version__ = '$Revision: 4791 $'.split()[1]
4 __date__ = '$Date: 2007-01-05 $'.split()[1]
5 __author__ = 'xmlbinmsg'
6
7 __doc__='''
8
9 Autogenerated python functions to serialize/deserialize binary messages.
10
11 Generated by: ./aisxmlbinmsg2py.py
12
13 Need to then wrap these functions with the outer AIS packet and then
14 convert the whole binary blob to a NMEA string. Those functions are
15 not currently provided in this file.
16
17 serialize: python to ais binary
18 deserialize: ais binary to python
19
20 The generated code uses translators.py, binary.py, and aisstring.py
21 which should be packaged with the resulting files.
22
23
24 @requires: U{epydoc<http://epydoc.sourceforge.net/>} > 3.0alpha3
25 @requires: U{BitVector<http://cheeseshop.python.org/pypi/BitVector>}
26
27 @author: '''+__author__+'''
28 @version: ''' + __version__ +'''
29 @var __date__: Date of last svn commit
30 @undocumented: __version__ __author__ __doc__ parser
31 @status: under development
32 @license: Generated code has no license
33 '''
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 -def encode(params, validate=False):
49 '''Create a position binary message payload to pack into an AIS Msg position.
50
51 Fields in params:
52 - MessageID(uint): AIS message number. Must be 1 (field automatically set to "1")
53 - RepeatIndicator(uint): Indicated how many times a message has been repeated
54 - UserID(uint): Unique ship identification number (MMSI)
55 - NavigationStatus(uint): What is the vessel doing
56 - ROT(int): RateOfTurn
57 - SOG(udecimal): Speed over ground
58 - PositionAccuracy(uint): Accuracy of positioning fixes
59 - Position_longitude(decimal): Location of the vessel East West location
60 - Position_latitude(decimal): Location of the vessel North South location
61 - COG(udecimal): Course over ground
62 - TrueHeading(uint): True heading (relative to true North)
63 - TimeStamp(uint): UTC second when the report was generated
64 - RegionalReserved(uint): Reserved for definition by a regional authority. (field automatically set to "0")
65 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0")
66 - RAIM(bool): Receiver autonomous integrity monitoring flag
67 - syncstate(uint): Sycronization state
68 - slotoffset(uint): In what slot will the next transmission occur. BROKEN
69 @param params: Dictionary of field names/values. Throws a ValueError exception if required is missing
70 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented.
71 @rtype: BitVector
72 @return: encoded binary message (for binary messages, this needs to be wrapped in a msg 8
73 @note: The returned bits may not be 6 bit aligned. It is up to you to pad out the bits.
74 '''
75
76 bvList = []
77 bvList.append(binary.setBitVectorSize(BitVector(intVal=1),6))
78 if 'RepeatIndicator' in params:
79 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['RepeatIndicator']),2))
80 else:
81 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2))
82 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['UserID']),30))
83 if 'NavigationStatus' in params:
84 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['NavigationStatus']),4))
85 else:
86 bvList.append(binary.setBitVectorSize(BitVector(intVal=15),4))
87 if 'ROT' in params:
88 bvList.append(binary.bvFromSignedInt(params['ROT'],8))
89 else:
90 bvList.append(binary.bvFromSignedInt(-128,8))
91 if 'SOG' in params:
92 bvList.append(binary.setBitVectorSize(BitVector(intVal=int((Decimal(params['SOG'])*Decimal('10')))),10))
93 else:
94 bvList.append(binary.setBitVectorSize(BitVector(intVal=int(1023)),10))
95 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['PositionAccuracy']),1))
96 if 'Position_longitude' in params:
97 bvList.append(binary.bvFromSignedInt(int(Decimal(params['Position_longitude'])*Decimal('600000')),28))
98 else:
99 bvList.append(binary.bvFromSignedInt(108600000,28))
100 if 'Position_latitude' in params:
101 bvList.append(binary.bvFromSignedInt(int(Decimal(params['Position_latitude'])*Decimal('600000')),27))
102 else:
103 bvList.append(binary.bvFromSignedInt(54600000,27))
104 if 'COG' in params:
105 bvList.append(binary.setBitVectorSize(BitVector(intVal=int((Decimal(params['COG'])*Decimal('10')))),12))
106 else:
107 bvList.append(binary.setBitVectorSize(BitVector(intVal=int(3600)),12))
108 if 'TrueHeading' in params:
109 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['TrueHeading']),9))
110 else:
111 bvList.append(binary.setBitVectorSize(BitVector(intVal=511),9))
112 if 'TimeStamp' in params:
113 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['TimeStamp']),6))
114 else:
115 bvList.append(binary.setBitVectorSize(BitVector(intVal=60),6))
116 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),4))
117 bvList.append(binary.setBitVectorSize(BitVector(intVal=0),1))
118 if params["RAIM"]: bvList.append(TrueBV)
119 else: bvList.append(FalseBV)
120 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['syncstate']),2))
121 bvList.append(binary.setBitVectorSize(BitVector(intVal=params['slotoffset']),14))
122
123 return binary.joinBV(bvList)
124
125 -def decode(bv, validate=False):
126 '''Unpack a position message
127
128 Fields in params:
129 - MessageID(uint): AIS message number. Must be 1 (field automatically set to "1")
130 - RepeatIndicator(uint): Indicated how many times a message has been repeated
131 - UserID(uint): Unique ship identification number (MMSI)
132 - NavigationStatus(uint): What is the vessel doing
133 - ROT(int): RateOfTurn
134 - SOG(udecimal): Speed over ground
135 - PositionAccuracy(uint): Accuracy of positioning fixes
136 - Position_longitude(decimal): Location of the vessel East West location
137 - Position_latitude(decimal): Location of the vessel North South location
138 - COG(udecimal): Course over ground
139 - TrueHeading(uint): True heading (relative to true North)
140 - TimeStamp(uint): UTC second when the report was generated
141 - RegionalReserved(uint): Reserved for definition by a regional authority. (field automatically set to "0")
142 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0")
143 - RAIM(bool): Receiver autonomous integrity monitoring flag
144 - syncstate(uint): Sycronization state
145 - slotoffset(uint): In what slot will the next transmission occur. BROKEN
146 @type bv: BitVector
147 @param bv: Bits defining a message
148 @param validate: Set to true to cause checking to occur. Runs slower. FIX: not implemented.
149 @rtype: dict
150 @return: params
151 '''
152
153
154
155
156 r = {}
157 r['MessageID']=1
158 r['RepeatIndicator']=int(bv[6:8])
159 r['UserID']=int(bv[8:38])
160 r['NavigationStatus']=int(bv[38:42])
161 r['ROT']=binary.signedIntFromBV(bv[42:50])
162 r['SOG']=Decimal(int(bv[50:60]))/Decimal('10')
163 r['PositionAccuracy']=int(bv[60:61])
164 r['Position_longitude']=Decimal(binary.signedIntFromBV(bv[61:89]))/Decimal('600000')
165 r['Position_latitude']=Decimal(binary.signedIntFromBV(bv[89:116]))/Decimal('600000')
166 r['COG']=Decimal(int(bv[116:128]))/Decimal('10')
167 r['TrueHeading']=int(bv[128:137])
168 r['TimeStamp']=int(bv[137:143])
169 r['RegionalReserved']=0
170 r['Spare']=0
171 r['RAIM']=bool(int(bv[148:149]))
172 r['syncstate']=int(bv[149:151])
173 r['slotoffset']=int(bv[151:165])
174 return r
175
177 return 1
178
181
184
186 return int(bv[38:42])
187
190
192 return Decimal(int(bv[50:60]))/Decimal('10')
193
195 return int(bv[60:61])
196
199
202
204 return Decimal(int(bv[116:128]))/Decimal('10')
205
207 return int(bv[128:137])
208
210 return int(bv[137:143])
211
213 return 0
214
216 return 0
217
219 return bool(int(bv[148:149]))
220
222 return int(bv[149:151])
223
225 return int(bv[151:165])
226
227
229 out.write("<h3>position<h3>\n")
230 out.write("<table border=\"1\">\n")
231 out.write("<tr bgcolor=\"orange\">\n")
232 out.write("<th align=\"left\">Field Name</th>\n")
233 out.write("<th align=\"left\">Type</th>\n")
234 out.write("<th align=\"left\">Value</th>\n")
235 out.write("<th align=\"left\">Value in Lookup Table</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>NavigationStatus</td>\n")
266 out.write("<td>uint</td>\n")
267 if 'NavigationStatus' in params:
268 out.write(" <td>"+str(params['NavigationStatus'])+"</td>\n")
269 if str(params['NavigationStatus']) in NavigationStatusDecodeLut:
270 out.write("<td>"+NavigationStatusDecodeLut[str(params['NavigationStatus'])]+"</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>ROT</td>\n")
277 out.write("<td>int</td>\n")
278 if 'ROT' in params:
279 out.write(" <td>"+str(params['ROT'])+"</td>\n")
280 out.write(" <td>"+str(params['ROT'])+"</td>\n")
281 out.write("</tr>\n")
282 out.write("\n")
283 out.write("<tr>\n")
284 out.write("<td>SOG</td>\n")
285 out.write("<td>udecimal</td>\n")
286 if 'SOG' in params:
287 out.write(" <td>"+str(params['SOG'])+"</td>\n")
288 if str(params['SOG']) in SOGDecodeLut:
289 out.write("<td>"+SOGDecodeLut[str(params['SOG'])]+"</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>PositionAccuracy</td>\n")
296 out.write("<td>uint</td>\n")
297 if 'PositionAccuracy' in params:
298 out.write(" <td>"+str(params['PositionAccuracy'])+"</td>\n")
299 if str(params['PositionAccuracy']) in PositionAccuracyDecodeLut:
300 out.write("<td>"+PositionAccuracyDecodeLut[str(params['PositionAccuracy'])]+"</td>")
301 else:
302 out.write("<td><i>Missing LUT entry</i></td>")
303 out.write("</tr>\n")
304 out.write("\n")
305 out.write("<tr>\n")
306 out.write("<td>Position_longitude</td>\n")
307 out.write("<td>decimal</td>\n")
308 if 'Position_longitude' in params:
309 out.write(" <td>"+str(params['Position_longitude'])+"</td>\n")
310 out.write(" <td>"+str(params['Position_longitude'])+"</td>\n")
311 out.write("</tr>\n")
312 out.write("\n")
313 out.write("<tr>\n")
314 out.write("<td>Position_latitude</td>\n")
315 out.write("<td>decimal</td>\n")
316 if 'Position_latitude' in params:
317 out.write(" <td>"+str(params['Position_latitude'])+"</td>\n")
318 out.write(" <td>"+str(params['Position_latitude'])+"</td>\n")
319 out.write("</tr>\n")
320 out.write("\n")
321 out.write("<tr>\n")
322 out.write("<td>COG</td>\n")
323 out.write("<td>udecimal</td>\n")
324 if 'COG' in params:
325 out.write(" <td>"+str(params['COG'])+"</td>\n")
326 out.write(" <td>"+str(params['COG'])+"</td>\n")
327 out.write("</tr>\n")
328 out.write("\n")
329 out.write("<tr>\n")
330 out.write("<td>TrueHeading</td>\n")
331 out.write("<td>uint</td>\n")
332 if 'TrueHeading' in params:
333 out.write(" <td>"+str(params['TrueHeading'])+"</td>\n")
334 out.write(" <td>"+str(params['TrueHeading'])+"</td>\n")
335 out.write("</tr>\n")
336 out.write("\n")
337 out.write("<tr>\n")
338 out.write("<td>TimeStamp</td>\n")
339 out.write("<td>uint</td>\n")
340 if 'TimeStamp' in params:
341 out.write(" <td>"+str(params['TimeStamp'])+"</td>\n")
342 if str(params['TimeStamp']) in TimeStampDecodeLut:
343 out.write("<td>"+TimeStampDecodeLut[str(params['TimeStamp'])]+"</td>")
344 else:
345 out.write("<td><i>Missing LUT entry</i></td>")
346 out.write("</tr>\n")
347 out.write("\n")
348 out.write("<tr>\n")
349 out.write("<td>RegionalReserved</td>\n")
350 out.write("<td>uint</td>\n")
351 if 'RegionalReserved' in params:
352 out.write(" <td>"+str(params['RegionalReserved'])+"</td>\n")
353 out.write(" <td>"+str(params['RegionalReserved'])+"</td>\n")
354 out.write("</tr>\n")
355 out.write("\n")
356 out.write("<tr>\n")
357 out.write("<td>Spare</td>\n")
358 out.write("<td>uint</td>\n")
359 if 'Spare' in params:
360 out.write(" <td>"+str(params['Spare'])+"</td>\n")
361 out.write(" <td>"+str(params['Spare'])+"</td>\n")
362 out.write("</tr>\n")
363 out.write("\n")
364 out.write("<tr>\n")
365 out.write("<td>RAIM</td>\n")
366 out.write("<td>bool</td>\n")
367 if 'RAIM' in params:
368 out.write(" <td>"+str(params['RAIM'])+"</td>\n")
369 if str(params['RAIM']) in RAIMDecodeLut:
370 out.write("<td>"+RAIMDecodeLut[str(params['RAIM'])]+"</td>")
371 else:
372 out.write("<td><i>Missing LUT entry</i></td>")
373 out.write("</tr>\n")
374 out.write("\n")
375 out.write("<tr>\n")
376 out.write("<td>syncstate</td>\n")
377 out.write("<td>uint</td>\n")
378 if 'syncstate' in params:
379 out.write(" <td>"+str(params['syncstate'])+"</td>\n")
380 if str(params['syncstate']) in syncstateDecodeLut:
381 out.write("<td>"+syncstateDecodeLut[str(params['syncstate'])]+"</td>")
382 else:
383 out.write("<td><i>Missing LUT entry</i></td>")
384 out.write("</tr>\n")
385 out.write("\n")
386 out.write("<tr>\n")
387 out.write("<td>slotoffset</td>\n")
388 out.write("<td>uint</td>\n")
389 if 'slotoffset' in params:
390 out.write(" <td>"+str(params['slotoffset'])+"</td>\n")
391 out.write(" <td>"+str(params['slotoffset'])+"</td>\n")
392 out.write("</tr>\n")
393 out.write("</table>\n")
394
396 '''KML (Keyhole Markup Language) for Google Earth, but without the header/footer'''
397 out.write("\ <Placemark>\n")
398 out.write("\t <name>"+str(params['UserID'])+"</name>\n")
399 out.write("\t\t<description>\n")
400 import StringIO
401 buf = StringIO.StringIO()
402 printHtml(params,buf)
403 import cgi
404 out.write(cgi.escape(buf.getvalue()))
405 out.write("\t\t</description>\n")
406 out.write("\t\t<styleUrl>#m_ylw-pushpin_copy0</styleUrl>\n")
407 out.write("\t\t<Point>\n")
408 out.write("\t\t\t<coordinates>")
409 out.write(str(params['Position_longitude']))
410 out.write(',')
411 out.write(str(params['Position_latitude']))
412 out.write(",0</coordinates>\n")
413 out.write("\t\t</Point>\n")
414 out.write("\t</Placemark>\n")
415
417 '''Print a slotoffset message to stdout.
418
419 Fields in params:
420 - MessageID(uint): AIS message number. Must be 1 (field automatically set to "1")
421 - RepeatIndicator(uint): Indicated how many times a message has been repeated
422 - UserID(uint): Unique ship identification number (MMSI)
423 - NavigationStatus(uint): What is the vessel doing
424 - ROT(int): RateOfTurn
425 - SOG(udecimal): Speed over ground
426 - PositionAccuracy(uint): Accuracy of positioning fixes
427 - Position_longitude(decimal): Location of the vessel East West location
428 - Position_latitude(decimal): Location of the vessel North South location
429 - COG(udecimal): Course over ground
430 - TrueHeading(uint): True heading (relative to true North)
431 - TimeStamp(uint): UTC second when the report was generated
432 - RegionalReserved(uint): Reserved for definition by a regional authority. (field automatically set to "0")
433 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0")
434 - RAIM(bool): Receiver autonomous integrity monitoring flag
435 - syncstate(uint): Sycronization state
436 - slotoffset(uint): In what slot will the next transmission occur. BROKEN
437 @param params: Dictionary of field names/values.
438 @param out: File like object to write to
439 @rtype: stdout
440 @return: text to out
441 '''
442
443 if 'std'==format:
444 out.write("slotoffset:\n")
445 if 'MessageID' in params: out.write(" MessageID: "+str(params['MessageID'])+"\n")
446 if 'RepeatIndicator' in params: out.write(" RepeatIndicator: "+str(params['RepeatIndicator'])+"\n")
447 if 'UserID' in params: out.write(" UserID: "+str(params['UserID'])+"\n")
448 if 'NavigationStatus' in params: out.write(" NavigationStatus: "+str(params['NavigationStatus'])+"\n")
449 if 'ROT' in params: out.write(" ROT: "+str(params['ROT'])+"\n")
450 if 'SOG' in params: out.write(" SOG: "+str(params['SOG'])+"\n")
451 if 'PositionAccuracy' in params: out.write(" PositionAccuracy: "+str(params['PositionAccuracy'])+"\n")
452 if 'Position_longitude' in params: out.write(" Position_longitude: "+str(params['Position_longitude'])+"\n")
453 if 'Position_latitude' in params: out.write(" Position_latitude: "+str(params['Position_latitude'])+"\n")
454 if 'COG' in params: out.write(" COG: "+str(params['COG'])+"\n")
455 if 'TrueHeading' in params: out.write(" TrueHeading: "+str(params['TrueHeading'])+"\n")
456 if 'TimeStamp' in params: out.write(" TimeStamp: "+str(params['TimeStamp'])+"\n")
457 if 'RegionalReserved' in params: out.write(" RegionalReserved: "+str(params['RegionalReserved'])+"\n")
458 if 'Spare' in params: out.write(" Spare: "+str(params['Spare'])+"\n")
459 if 'RAIM' in params: out.write(" RAIM: "+str(params['RAIM'])+"\n")
460 if 'syncstate' in params: out.write(" syncstate: "+str(params['syncstate'])+"\n")
461 if 'slotoffset' in params: out.write(" slotoffset: "+str(params['slotoffset'])+"\n")
462 elif 'html'==format:
463 printHtml(params,out)
464 elif 'kml'==format:
465 printKml(params,out)
466 elif 'kml-full'==format:
467 out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
468 out.write("<kml xmlns=\"http://earth.google.com/kml/2.1\">\n")
469 out.write("<Document>\n")
470 out.write(" <name>Position</name>\n")
471 printKml(params,out)
472 out.write("</Document>\n")
473 out.write("</kml>\n")
474 else:
475 print "ERROR: unknown format:",format
476 assert False
477
478 return
479
480 RepeatIndicatorEncodeLut = {
481 'default':'0',
482 'do not repeat any more':'3',
483 }
484
485 RepeatIndicatorDecodeLut = {
486 '0':'default',
487 '3':'do not repeat any more',
488 }
489
490 NavigationStatusEncodeLut = {
491 'under way using engine':'0',
492 'at anchor':'1',
493 'not under command':'2',
494 'restricted maneuverability':'3',
495 'constrained by her draught':'4',
496 'moored':'5',
497 'aground':'6',
498 'engaged in fishing':'7',
499 'under way sailing':'8',
500 'reserved for future use (hazmat)':'9',
501 'reserved for future use':'10',
502 'reserved for future use':'11',
503 'reserved for future use':'12',
504 'reserved for future use':'13',
505 'reserved for future use':'14',
506 'not defined = default':'15',
507 }
508
509 NavigationStatusDecodeLut = {
510 '0':'under way using engine',
511 '1':'at anchor',
512 '2':'not under command',
513 '3':'restricted maneuverability',
514 '4':'constrained by her draught',
515 '5':'moored',
516 '6':'aground',
517 '7':'engaged in fishing',
518 '8':'under way sailing',
519 '9':'reserved for future use (hazmat)',
520 '10':'reserved for future use',
521 '11':'reserved for future use',
522 '12':'reserved for future use',
523 '13':'reserved for future use',
524 '14':'reserved for future use',
525 '15':'not defined = default',
526 }
527
528 SOGEncodeLut = {
529 '102.2 knots or higher':'102.2',
530 }
531
532 SOGDecodeLut = {
533 '102.2':'102.2 knots or higher',
534 }
535
536 PositionAccuracyEncodeLut = {
537 'low (greater than 10 m)':'0',
538 'high (greater than 10 m)':'1',
539 }
540
541 PositionAccuracyDecodeLut = {
542 '0':'low (greater than 10 m)',
543 '1':'high (greater than 10 m)',
544 }
545
546 TimeStampEncodeLut = {
547 'not available/default':'60',
548 'manual input':'61',
549 'dead reckoning':'62',
550 'inoperative':'63',
551 }
552
553 TimeStampDecodeLut = {
554 '60':'not available/default',
555 '61':'manual input',
556 '62':'dead reckoning',
557 '63':'inoperative',
558 }
559
560 RAIMEncodeLut = {
561 'not in use':'False',
562 'in use':'True',
563 }
564
565 RAIMDecodeLut = {
566 'False':'not in use',
567 'True':'in use',
568 }
569
570 syncstateEncodeLut = {
571 'UTC direct':'0',
572 'UTC indirect':'1',
573 'synchronized to a base station':'2',
574 'synchronized to another station':'3',
575 }
576
577 syncstateDecodeLut = {
578 '0':'UTC direct',
579 '1':'UTC indirect',
580 '2':'synchronized to a base station',
581 '3':'synchronized to another station',
582 }
583
584
585
586
587
588
589 import unittest
591 '''Return a params file base on the testvalue tags.
592 @rtype: dict
593 @return: params based on testvalue tags
594 '''
595 params = {}
596 params['MessageID'] = 1
597 params['RepeatIndicator'] = 1
598 params['UserID'] = 1193046
599 params['NavigationStatus'] = 3
600 params['ROT'] = -2
601 params['SOG'] = Decimal('101.9')
602 params['PositionAccuracy'] = 1
603 params['Position_longitude'] = Decimal('-122.16328055555556')
604 params['Position_latitude'] = Decimal('37.424458333333334')
605 params['COG'] = Decimal('34.5')
606 params['TrueHeading'] = 41
607 params['TimeStamp'] = 35
608 params['RegionalReserved'] = 0
609 params['Spare'] = 0
610 params['RAIM'] = False
611 params['syncstate'] = 2
612 params['slotoffset'] = 1221
613
614 return params
615
617 '''Use testvalue tag text from each type to build test case the position message'''
619
620 params = testParams()
621 bits = encode(params)
622 r = decode(bits)
623
624
625 self.failUnlessEqual(r['MessageID'],params['MessageID'])
626 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator'])
627 self.failUnlessEqual(r['UserID'],params['UserID'])
628 self.failUnlessEqual(r['NavigationStatus'],params['NavigationStatus'])
629 self.failUnlessEqual(r['ROT'],params['ROT'])
630 self.failUnlessAlmostEqual(r['SOG'],params['SOG'],1)
631 self.failUnlessEqual(r['PositionAccuracy'],params['PositionAccuracy'])
632 self.failUnlessAlmostEqual(r['Position_longitude'],params['Position_longitude'],5)
633 self.failUnlessAlmostEqual(r['Position_latitude'],params['Position_latitude'],5)
634 self.failUnlessAlmostEqual(r['COG'],params['COG'],3)
635 self.failUnlessEqual(r['TrueHeading'],params['TrueHeading'])
636 self.failUnlessEqual(r['TimeStamp'],params['TimeStamp'])
637 self.failUnlessEqual(r['RegionalReserved'],params['RegionalReserved'])
638 self.failUnlessEqual(r['Spare'],params['Spare'])
639 self.failUnlessEqual(r['RAIM'],params['RAIM'])
640 self.failUnlessEqual(r['syncstate'],params['syncstate'])
641 self.failUnlessEqual(r['slotoffset'],params['slotoffset'])
642
644 parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true',
645 help='decode a "position" AIS message')
646 parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true',
647 help='encode a "position" AIS message')
648 parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int'
649 ,help='Field parameter value [default: %default]')
650 parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int'
651 ,help='Field parameter value [default: %default]')
652 parser.add_option('--NavigationStatus-field', dest='NavigationStatusField',default=15,metavar='uint',type='int'
653 ,help='Field parameter value [default: %default]')
654 parser.add_option('--ROT-field', dest='ROTField',default=-128,metavar='int',type='int'
655 ,help='Field parameter value [default: %default]')
656 parser.add_option('--SOG-field', dest='SOGField',default=Decimal('102.3'),metavar='udecimal',type='string'
657 ,help='Field parameter value [default: %default]')
658 parser.add_option('--PositionAccuracy-field', dest='PositionAccuracyField',metavar='uint',type='int'
659 ,help='Field parameter value [default: %default]')
660 parser.add_option('--Position_longitude-field', dest='Position_longitudeField',default=Decimal('181'),metavar='decimal',type='string'
661 ,help='Field parameter value [default: %default]')
662 parser.add_option('--Position_latitude-field', dest='Position_latitudeField',default=Decimal('91'),metavar='decimal',type='string'
663 ,help='Field parameter value [default: %default]')
664 parser.add_option('--COG-field', dest='COGField',default=Decimal('360'),metavar='udecimal',type='string'
665 ,help='Field parameter value [default: %default]')
666 parser.add_option('--TrueHeading-field', dest='TrueHeadingField',default=511,metavar='uint',type='int'
667 ,help='Field parameter value [default: %default]')
668 parser.add_option('--TimeStamp-field', dest='TimeStampField',default=60,metavar='uint',type='int'
669 ,help='Field parameter value [default: %default]')
670 parser.add_option('--RAIM-field', dest='RAIMField',metavar='bool',type='int'
671 ,help='Field parameter value [default: %default]')
672 parser.add_option('--syncstate-field', dest='syncstateField',metavar='uint',type='int'
673 ,help='Field parameter value [default: %default]')
674 parser.add_option('--slotoffset-field', dest='slotoffsetField',metavar='uint',type='int'
675 ,help='Field parameter value [default: %default]')
676
677
678 if __name__=='__main__':
679
680 from optparse import OptionParser
681 parser = OptionParser(usage="%prog [options]",
682 version="%prog "+__version__)
683
684 parser.add_option('--doc-test',dest='doctest',default=False,action='store_true',
685 help='run the documentation tests')
686 parser.add_option('--unit-test',dest='unittest',default=False,action='store_true',
687 help='run the unit tests')
688 parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true',
689 help='Make the test output verbose')
690
691
692
693 typeChoices = ('binary','nmeapayload','nmea')
694 parser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType'
695 ,default='nmeapayload'
696 ,help='What kind of string to expect ('+', '.join(typeChoices)+') [default: %default]')
697
698
699 outputChoices = ('std','html','xml' , 'kml','kml-full')
700 parser.add_option('-T','--output-type',choices=outputChoices,type='choice',dest='outputType'
701 ,default='std'
702 ,help='What kind of string to output ('+', '.join(outputChoices)+') [default: %default]')
703
704 parser.add_option('-o','--output',dest='outputFileName',default=None,
705 help='Name of the python file to write [default: stdout]')
706
707 addMsgOptions(parser)
708
709 (options,args) = parser.parse_args()
710 success=True
711
712 if options.doctest:
713 import os; print os.path.basename(sys.argv[0]), 'doctests ...',
714 sys.argv= [sys.argv[0]]
715 if options.verbose: sys.argv.append('-v')
716 import doctest
717 numfail,numtests=doctest.testmod()
718 if numfail==0: print 'ok'
719 else:
720 print 'FAILED'
721 success=False
722
723 if not success: sys.exit('Something Failed')
724 del success
725
726 if options.unittest:
727 sys.argv = [sys.argv[0]]
728 if options.verbose: sys.argv.append('-v')
729 unittest.main()
730
731 outfile = sys.stdout
732 if None!=options.outputFileName:
733 outfile = file(options.outputFileName,'w')
734
735
736 if options.doEncode:
737
738 if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField")
739 if None==options.UserIDField: parser.error("missing value for UserIDField")
740 if None==options.NavigationStatusField: parser.error("missing value for NavigationStatusField")
741 if None==options.ROTField: parser.error("missing value for ROTField")
742 if None==options.SOGField: parser.error("missing value for SOGField")
743 if None==options.PositionAccuracyField: parser.error("missing value for PositionAccuracyField")
744 if None==options.Position_longitudeField: parser.error("missing value for Position_longitudeField")
745 if None==options.Position_latitudeField: parser.error("missing value for Position_latitudeField")
746 if None==options.COGField: parser.error("missing value for COGField")
747 if None==options.TrueHeadingField: parser.error("missing value for TrueHeadingField")
748 if None==options.TimeStampField: parser.error("missing value for TimeStampField")
749 if None==options.RAIMField: parser.error("missing value for RAIMField")
750 if None==options.syncstateField: parser.error("missing value for syncstateField")
751 if None==options.slotoffsetField: parser.error("missing value for slotoffsetField")
752 msgDict={
753 'MessageID': '1',
754 'RepeatIndicator': options.RepeatIndicatorField,
755 'UserID': options.UserIDField,
756 'NavigationStatus': options.NavigationStatusField,
757 'ROT': options.ROTField,
758 'SOG': options.SOGField,
759 'PositionAccuracy': options.PositionAccuracyField,
760 'Position_longitude': options.Position_longitudeField,
761 'Position_latitude': options.Position_latitudeField,
762 'COG': options.COGField,
763 'TrueHeading': options.TrueHeadingField,
764 'TimeStamp': options.TimeStampField,
765 'RegionalReserved': '0',
766 'Spare': '0',
767 'RAIM': options.RAIMField,
768 'syncstate': options.syncstateField,
769 'slotoffset': options.slotoffsetField,
770 }
771
772 bits = encode(msgDict)
773 if 'binary'==options.ioType: print str(bits)
774 elif 'nmeapayload'==options.ioType:
775
776 print "bitLen",len(bits)
777 bitLen=len(bits)
778 if bitLen%6!=0:
779 bits = bits + BitVector(size=(6 - (bitLen%6)))
780 print "result:",binary.bitvectoais6(bits)[0]
781
782
783
784 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability")
785 else: sys.exit('ERROR: unknown ioType. Help!')
786
787 if options.doDecode:
788 for msg in args:
789 bv = None
790 if 'binary' == options.ioType: bv = BitVector(bitstring=msg)
791 elif 'nmeapayload'== options.ioType: bv = binary.ais6tobitvec(msg)
792 elif 'nmea' == options.ioType: bv = binary.ais6tobitvec(msg.split(',')[5])
793 else: sys.exit('ERROR: unknown ioType. Help!')
794
795 printFields(decode(bv),out=outfile,format=options.outputType)
796