Package ais :: Module nmea
[hide private]
[frames] | no frames]

Source Code for Module ais.nmea

  1  #!/usr/bin/env python 
  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  # Python standard libraries 
 28  import time, sys 
 29   
 30  # Local Modules 
 31  import binary 
 32   
 33  import re 
 34   
 35   
36 -def checksumStr(data):
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 # FIX: strip off new line at the end too 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 # FIX: rename sum to not shadown builting function 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 # common variables 66 nmeaChecksumRegExStr = r"""\,[0-9]\*[0-9A-F][0-9A-F]""" 67 nmeaChecksumRE = re.compile(nmeaChecksumRegExStr) 68
69 -def isChecksumValid(nmeaStr, allowTailData=True):
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 #if checksum.upper()==checksumStr(nmeaStr[match.end() 92 93 94 if nmeaStr[-3]!='*': 95 print 'FIX: warning... bad nmea string' 96 return False # Bad string without proper checksum 97 checksum=nmeaStr[-2:] 98 if checksum.upper()==checksumStr(nmeaStr).upper(): return True 99 return False
100
101 -def buildNmea(aisBits,prefix='!',serviceType='AI',msgType='VDM',channelSeq=None,channel='A'):
102 ''' 103 Create one long oversized nmea string for the bits 104 @param aisBits: message payload 105 @type aisBits: BitVector 106 @param prefix: '!' or '$' what is the difference? 107 @param serviceType: 'can this be anything other than AI? 108 @param msgType: VDM. Should not be VDO (own ship) 109 @param channelSeq: 1-9 or None 110 @param channel: AIS channel A or B 111 @todo: sync names of prefix and serviceType to NMEA spec. 112 @see: reference the appropriate spec documents for all this stuff. 113 ''' 114 115 rList = [prefix,serviceType,msgType,',1,1,'] 116 if None != channelSeq: rList.append(str(channelSeq)) 117 rList.append(',') 118 rList.append(channel) 119 rList.append(',') 120 121 payloadStr,pad = binary.bitvectoais6(aisBits) #[0] 122 rList.append(payloadStr) 123 rList.append(','+str(pad)) 124 rStr = ''.join(rList) 125 rStr += '*'+checksumStr(rStr) 126 127 return rStr
128 129 ###################################################################### 130 if __name__=='__main__': 131 from optparse import OptionParser 132 myparser = OptionParser(usage="%prog [options]", 133 version="%prog "+__version__) 134 myparser.add_option('--test','--doc-test',dest='doctest',default=False,action='store_true', 135 help='run the documentation tests') 136 myparser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true', 137 help='run the tests run in verbose mode') 138 (options,args) = myparser.parse_args() 139 140 success=True 141 142 if options.doctest: 143 import os; print os.path.basename(sys.argv[0]), 'doctests ...', 144 argvOrig = sys.argv 145 sys.argv= [sys.argv[0]] 146 if options.verbose: sys.argv.append('-v') 147 import doctest 148 numfail,numtests=doctest.testmod() 149 if numfail==0: print 'ok' 150 else: 151 print 'FAILED' 152 success=False 153 sys.argv = argvOrig # Restore the original args 154 del argvOrig # hide from epydoc 155 156 if not success: 157 sys.exit('Something Failed') 158 159 del success # Hide success from epydoc 160