1
2
3 __version__ = '$Revision: 4799 $'.split()[1]
4 __date__ = '$Date: 2006-09-25 11:09:02 -0400 (Mon, 25 Sep 2006) $'.split()[1]
5 __author__ = 'John Doe FIX: put in the authors name'
6
7 __doc__='''
8 Handle creation and extraction of NMEA strings. Maybe need a separate VDM class like ais-py?
9
10 @requires: U{lxml<http://codespeak.net/lxml/>} - For libxml2 ElementTree interface. Not actually required for the template, but this is just a demo or requirements.
11 @requires: U{Python<http://python.org/>} >= 2.4
12 @requires: U{epydoc<http://epydoc.sourceforge.net/>} >= 3.0alpha3
13 @requires: BitVector
14
15 @author: U{'''+__author__+'''<http://schwehr.org/>}
16 @version: ''' + __version__ +'''
17 @copyright: 2006
18 @var __date__: Date of last svn commit
19 @undocumented: __version__ __author__ __doc__ myparser
20 @since: 2006-Sep-26 FIX: replace with the file creation date
21 @status: under development
22 @organization: U{CCOM<http://ccom.unh.edu/>} - FIX: if not CCOM change the name and link
23
24 @license: GPL v2
25 '''
26
27
28 import time, sys
29
30
31 import binary
32
33 import re
34
35
37 """
38 Take a NMEA 0183 string and compute the checksum.
39 @param data: NMEA message. Leading ?/! and training checksum are optional
40 @type data: str
41 @return: hexidecimal value
42 @rtype: str
43
44 Checksum is calculated by xor'ing everything between ? or ! and the *
45
46 >>> checksumStr("!AIVDM,1,1,,B,35MsUdPOh8JwI:0HUwquiIFH21>i,0*09")
47 '09'
48 >>> checksumStr("AIVDM,1,1,,B,35MsUdPOh8JwI:0HUwquiIFH21>i,0")
49 '09'
50 """
51
52
53 if data[0]=='!' or data[0]=='?': data = data[1:]
54 if data[-1]=='*': data = data[:-1]
55 if data[-3]=='*': data = data[:-3]
56
57 sum=0
58 for c in data: sum = sum ^ ord(c)
59 sumHex = "%x" % sum
60 if len(sumHex)==1: sumHex = '0'+sumHex
61 return sumHex.upper()
62
63
64
65
66 nmeaChecksumRegExStr = r"""\,[0-9]\*[0-9A-F][0-9A-F]"""
67 nmeaChecksumRE = re.compile(nmeaChecksumRegExStr)
68
70 """Return True if the string checks out with the checksum
71
72 @param allowTailData: Permit handing of Coast Guard format with data after the checksum
73 @param data: NMEA message. Leading ?/! are optional
74 @type data: str
75 @return: True if the checksum matches
76 @rtype: bool
77
78 >>> isChecksumValid("!AIVDM,1,1,,B,35MsUdPOh8JwI:0HUwquiIFH21>i,0*09")
79 True
80
81 Corrupted:
82
83 >>> isChecksumValid("!AIVDM,11,1,,B,35MsUdPOh8JwI:0HUwquiIFH21>i,0*09")
84 False
85 """
86
87 if allowTailData:
88 match = nmeaChecksumRE.search(nmeaStr)
89 if not match: return False
90 nmeaStr = nmeaStr[:match.end()]
91
92
93
94 if nmeaStr[-3]!='*':
95 print 'FIX: warning... bad nmea string'
96 return False
97 checksum=nmeaStr[-2:]
98 if checksum.upper()==checksumStr(nmeaStr).upper(): return True
99 return False
100
101
102 if __name__=='__main__':
103 from optparse import OptionParser
104 myparser = OptionParser(usage="%prog [options]",
105 version="%prog "+__version__)
106 myparser.add_option('--test','--doc-test',dest='doctest',default=False,action='store_true',
107 help='run the documentation tests')
108 myparser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true',
109 help='run the tests run in verbose mode')
110 (options,args) = myparser.parse_args()
111
112 success=True
113
114 if options.doctest:
115 import os; print os.path.basename(sys.argv[0]), 'doctests ...',
116 argvOrig = sys.argv
117 sys.argv= [sys.argv[0]]
118 if options.verbose: sys.argv.append('-v')
119 import doctest
120 numfail,numtests=doctest.testmod()
121 if numfail==0: print 'ok'
122 else:
123 print 'FAILED'
124 success=False
125 sys.argv = argvOrig
126 del argvOrig
127
128 if not success:
129 sys.exit('Something Failed')
130
131 del success
132