1
2
3 __version__ = '$Revision: 4791 $'.split()[1]
4 __date__ = '$Date: 2006-12-20 $'.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__ myparser
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
228 '''Print a position message to stdout.
229
230 Fields in params:
231 - MessageID(uint): AIS message number. Must be 1 (field automatically set to "1")
232 - RepeatIndicator(uint): Indicated how many times a message has been repeated
233 - UserID(uint): Unique ship identification number (MMSI)
234 - NavigationStatus(uint): What is the vessel doing
235 - ROT(int): RateOfTurn
236 - SOG(udecimal): Speed over ground
237 - PositionAccuracy(uint): Accuracy of positioning fixes
238 - Position_longitude(decimal): Location of the vessel East West location
239 - Position_latitude(decimal): Location of the vessel North South location
240 - COG(udecimal): Course over ground
241 - TrueHeading(uint): True heading (relative to true North)
242 - TimeStamp(uint): UTC second when the report was generated
243 - RegionalReserved(uint): Reserved for definition by a regional authority. (field automatically set to "0")
244 - Spare(uint): Reserved for definition by a regional authority. (field automatically set to "0")
245 - RAIM(bool): Receiver autonomous integrity monitoring flag
246 - syncstate(uint): Sycronization state
247 - slotoffset(uint): In what slot will the next transmission occur. BROKEN
248 @param params: Dictionary of field names/values.
249 @param out: File like object to write to
250 @rtype: stdout
251 @return: text to out
252 '''
253
254 if 'std'==format:
255 out.write("position:\n")
256 out.write(" MessageID: "+str(params['MessageID'])+"\n")
257 out.write(" RepeatIndicator: "+str(params['RepeatIndicator'])+"\n")
258 out.write(" UserID: "+str(params['UserID'])+"\n")
259 out.write(" NavigationStatus: "+str(params['NavigationStatus'])+"\n")
260 out.write(" ROT: "+str(params['ROT'])+"\n")
261 out.write(" SOG: "+str(params['SOG'])+"\n")
262 out.write(" PositionAccuracy: "+str(params['PositionAccuracy'])+"\n")
263 out.write(" Position_longitude: "+str(params['Position_longitude'])+"\n")
264 out.write(" Position_latitude: "+str(params['Position_latitude'])+"\n")
265 out.write(" COG: "+str(params['COG'])+"\n")
266 out.write(" TrueHeading: "+str(params['TrueHeading'])+"\n")
267 out.write(" TimeStamp: "+str(params['TimeStamp'])+"\n")
268 out.write(" RegionalReserved: "+str(params['RegionalReserved'])+"\n")
269 out.write(" Spare: "+str(params['Spare'])+"\n")
270 out.write(" RAIM: "+str(params['RAIM'])+"\n")
271 out.write(" syncstate: "+str(params['syncstate'])+"\n")
272 out.write(" slotoffset: "+str(params['slotoffset'])+"\n")
273
274 return
275
276
277
278
279
280
281 import unittest
283 '''Return a params file base on the testvalue tags.
284 @rtype: dict
285 @return: params based on testvalue tags
286 '''
287 params = {}
288 params['MessageID'] = 1
289 params['RepeatIndicator'] = 1
290 params['UserID'] = 1193046
291 params['NavigationStatus'] = 3
292 params['ROT'] = -2
293 params['SOG'] = Decimal('101.9')
294 params['PositionAccuracy'] = 1
295 params['Position_longitude'] = Decimal('-122.16328055555556')
296 params['Position_latitude'] = Decimal('37.424458333333334')
297 params['COG'] = Decimal('34.5')
298 params['TrueHeading'] = 41
299 params['TimeStamp'] = 35
300 params['RegionalReserved'] = 0
301 params['Spare'] = 0
302 params['RAIM'] = False
303 params['syncstate'] = 2
304 params['slotoffset'] = 1221
305
306 return params
307
309 '''Use testvalue tag text from each type to build test case the position message'''
311
312 params = testParams()
313 bits = encode(params)
314 r = decode(bits)
315
316
317 self.failUnlessEqual(r['MessageID'],params['MessageID'])
318 self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator'])
319 self.failUnlessEqual(r['UserID'],params['UserID'])
320 self.failUnlessEqual(r['NavigationStatus'],params['NavigationStatus'])
321 self.failUnlessEqual(r['ROT'],params['ROT'])
322 self.failUnlessAlmostEqual(r['SOG'],params['SOG'],1)
323 self.failUnlessEqual(r['PositionAccuracy'],params['PositionAccuracy'])
324 self.failUnlessAlmostEqual(r['Position_longitude'],params['Position_longitude'],5)
325 self.failUnlessAlmostEqual(r['Position_latitude'],params['Position_latitude'],5)
326 self.failUnlessAlmostEqual(r['COG'],params['COG'],7)
327 self.failUnlessEqual(r['TrueHeading'],params['TrueHeading'])
328 self.failUnlessEqual(r['TimeStamp'],params['TimeStamp'])
329 self.failUnlessEqual(r['RegionalReserved'],params['RegionalReserved'])
330 self.failUnlessEqual(r['Spare'],params['Spare'])
331 self.failUnlessEqual(r['RAIM'],params['RAIM'])
332 self.failUnlessEqual(r['syncstate'],params['syncstate'])
333 self.failUnlessEqual(r['slotoffset'],params['slotoffset'])
334
335
336 if __name__=='__main__':
337
338 from optparse import OptionParser
339 myparser = OptionParser(usage="%prog [options]",
340 version="%prog "+__version__)
341
342
343 myparser.add_option('--doc-test',dest='doctest',default=False,action='store_true',
344 help='run the documentation tests')
345 myparser.add_option('--unit-test',dest='unittest',default=False,action='store_true',
346 help='run the unit tests')
347 myparser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true',
348 help='Make the test output verbose')
349
350
351 myparser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true',
352 help='decode a "position" AIS message')
353 myparser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true',
354 help='encode a "position" AIS message')
355
356
357
358
359 typeChoices = ('binary','nmeapayload','nmea')
360 myparser.add_option('-t','--type',choices=typeChoices,type='choice',dest='ioType'
361 ,default='nmeapayload'
362 ,help='What kind of string to expect ('+', '.join(typeChoices)+') [default: %default]')
363
364 myparser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0
365 ,help='Field parameter value [default: %default]'
366 ,metavar='uint'
367 ,type='int'
368 )
369 myparser.add_option('--UserID-field', dest='UserIDField'
370 ,help='Field parameter value [default: %default]'
371 ,metavar='uint'
372 ,type='int'
373 )
374 myparser.add_option('--NavigationStatus-field', dest='NavigationStatusField',default=15
375 ,help='Field parameter value [default: %default]'
376 ,metavar='uint'
377 ,type='int'
378 )
379 myparser.add_option('--ROT-field', dest='ROTField',default=-128
380 ,help='Field parameter value [default: %default]'
381 ,metavar='int'
382 ,type='int'
383 )
384 myparser.add_option('--SOG-field', dest='SOGField',default=Decimal('102.3')
385 ,help='Field parameter value [default: %default]'
386 ,metavar='udecimal'
387 ,type='string'
388 )
389 myparser.add_option('--PositionAccuracy-field', dest='PositionAccuracyField'
390 ,help='Field parameter value [default: %default]'
391 ,metavar='uint'
392 ,type='int'
393 )
394 myparser.add_option('--Position_longitude-field', dest='Position_longitudeField',default=Decimal('181')
395 ,help='Field parameter value [default: %default]'
396 ,metavar='decimal'
397 ,type='string'
398 )
399 myparser.add_option('--Position_latitude-field', dest='Position_latitudeField',default=Decimal('91')
400 ,help='Field parameter value [default: %default]'
401 ,metavar='decimal'
402 ,type='string'
403 )
404 myparser.add_option('--COG-field', dest='COGField',default=Decimal('360')
405 ,help='Field parameter value [default: %default]'
406 ,metavar='udecimal'
407 ,type='string'
408 )
409 myparser.add_option('--TrueHeading-field', dest='TrueHeadingField',default=511
410 ,help='Field parameter value [default: %default]'
411 ,metavar='uint'
412 ,type='int'
413 )
414 myparser.add_option('--TimeStamp-field', dest='TimeStampField',default=60
415 ,help='Field parameter value [default: %default]'
416 ,metavar='uint'
417 ,type='int'
418 )
419 myparser.add_option('--RAIM-field', dest='RAIMField'
420 ,help='Field parameter value [default: %default]'
421 ,metavar='bool'
422 ,type='int'
423 )
424 myparser.add_option('--syncstate-field', dest='syncstateField'
425 ,help='Field parameter value [default: %default]'
426 ,metavar='uint'
427 ,type='int'
428 )
429 myparser.add_option('--slotoffset-field', dest='slotoffsetField'
430 ,help='Field parameter value [default: %default]'
431 ,metavar='uint'
432 ,type='int'
433 )
434
435 (options,args) = myparser.parse_args()
436 success=True
437
438 if options.doctest:
439 import os; print os.path.basename(sys.argv[0]), 'doctests ...',
440 sys.argv= [sys.argv[0]]
441 if options.verbose: sys.argv.append('-v')
442 import doctest
443 numfail,numtests=doctest.testmod()
444 if numfail==0: print 'ok'
445 else:
446 print 'FAILED'
447 success=False
448
449 if not success:
450 sys.exit('Something Failed')
451
452 del success
453
454 if options.unittest:
455 sys.argv = [sys.argv[0]]
456 if options.verbose: sys.argv.append('-v')
457 unittest.main()
458
459 if options.doEncode:
460
461 if None==options.RepeatIndicatorField: myparser.error("missing value for RepeatIndicatorField")
462 if None==options.UserIDField: myparser.error("missing value for UserIDField")
463 if None==options.NavigationStatusField: myparser.error("missing value for NavigationStatusField")
464 if None==options.ROTField: myparser.error("missing value for ROTField")
465 if None==options.SOGField: myparser.error("missing value for SOGField")
466 if None==options.PositionAccuracyField: myparser.error("missing value for PositionAccuracyField")
467 if None==options.Position_longitudeField: myparser.error("missing value for Position_longitudeField")
468 if None==options.Position_latitudeField: myparser.error("missing value for Position_latitudeField")
469 if None==options.COGField: myparser.error("missing value for COGField")
470 if None==options.TrueHeadingField: myparser.error("missing value for TrueHeadingField")
471 if None==options.TimeStampField: myparser.error("missing value for TimeStampField")
472 if None==options.RAIMField: myparser.error("missing value for RAIMField")
473 if None==options.syncstateField: myparser.error("missing value for syncstateField")
474 if None==options.slotoffsetField: myparser.error("missing value for slotoffsetField")
475 msgDict={
476 'MessageID': '1',
477 'RepeatIndicator': options.RepeatIndicatorField,
478 'UserID': options.UserIDField,
479 'NavigationStatus': options.NavigationStatusField,
480 'ROT': options.ROTField,
481 'SOG': options.SOGField,
482 'PositionAccuracy': options.PositionAccuracyField,
483 'Position_longitude': options.Position_longitudeField,
484 'Position_latitude': options.Position_latitudeField,
485 'COG': options.COGField,
486 'TrueHeading': options.TrueHeadingField,
487 'TimeStamp': options.TimeStampField,
488 'RegionalReserved': '0',
489 'Spare': '0',
490 'RAIM': options.RAIMField,
491 'syncstate': options.syncstateField,
492 'slotoffset': options.slotoffsetField,
493 }
494 bits = encode(msgDict)
495 if 'binary'==options.ioType: print str(bits)
496 elif 'nmeapayload'==options.ioType:
497 print "bitLen",len(bits)
498 bitLen=len(bits)
499 if bitLen%6!=0:
500 bits = bits + BitVector(size=(6 - (bitLen%6)))
501 print "result:",binary.bitvectoais6(bits)[0]
502 elif 'nmea'==options.ioType: sys.exit("FIX: need to implement this capability")
503 else: sys.exit('ERROR: unknown ioType. Help!')
504
505 if options.doDecode:
506 for msg in args:
507 if 'binary'==options.ioType:
508 bv = BitVector(bitstring=msg)
509 printFields(decode(bv))
510 elif 'nmeapayload'==options.ioType:
511 bv = binary.ais6tobitvec(msg)
512 printFields(decode(bv))
513 elif 'nmea'==options.ioType:
514 bv = binary.ais6tobitvec(msg.split(',')[5])
515 printFields(decode(bv))
516 else: sys.exit('ERROR: unknown ioType. Help!')
517