1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
"""Utilities for working with NMEA strings."""
import re
import sys
import time
nmeaChecksumRegExStr = r"""\,[0-9]\*[0-9A-F][0-9A-F]"""
nmeaChecksumRE = re.compile(nmeaChecksumRegExStr)
def checksumStr(data):
"""Take a NMEA 0183 string and compute the checksum.
@param data: NMEA message. Leading ?/! and training checksum are optional
@type data: str
@return: hexidecimal value
@rtype: str
Checksum is calculated by xor'ing everything between ? or ! and the *
>>> checksumStr("!AIVDM,1,1,,B,35MsUdPOh8JwI:0HUwquiIFH21>i,0*09")
'09'
>>> checksumStr("AIVDM,1,1,,B,35MsUdPOh8JwI:0HUwquiIFH21>i,0")
'09'
"""
# FIX: strip off new line at the end too
if data[0]=='!' or data[0]=='?': data = data[1:]
if data[-1]=='*': data = data[:-1]
if data[-3]=='*': data = data[:-3]
# FIX: rename sum to not shadown builting function
checksum = 0
for c in data:
checksum = checksum ^ ord(c)
sum_hex = "%x" % checksum
if len(sum_hex) == 1:
sum_hex = '0' + sum_hex
return sum_hex.upper()
def isChecksumValid(nmeaStr, allowTailData=True):
"""Return True if the string checks out with the checksum.
@param allowTailData: Permit handing of Coast Guard format with data after the checksum
@param data: NMEA message. Leading ?/! are optional
@type data: str
@return: True if the checksum matches
@rtype: bool
>>> isChecksumValid("!AIVDM,1,1,,B,35MsUdPOh8JwI:0HUwquiIFH21>i,0*09")
True
Corrupted:
>>> isChecksumValid("!AIVDM,11,1,,B,35MsUdPOh8JwI:0HUwquiIFH21>i,0*09")
False
"""
if allowTailData:
match = nmeaChecksumRE.search(nmeaStr)
if not match:
return False
nmeaStr = nmeaStr[:match.end()]
if nmeaStr[-3]!='*':
return False # Bad string without proper checksum.
checksum=nmeaStr[-2:]
if checksum.upper() == checksumStr(nmeaStr).upper():
return True
return False
|