summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--glucometerutils/drivers/freestyle_optium.py28
1 files changed, 26 insertions, 2 deletions
diff --git a/glucometerutils/drivers/freestyle_optium.py b/glucometerutils/drivers/freestyle_optium.py
index 0be4995..d40a9a1 100644
--- a/glucometerutils/drivers/freestyle_optium.py
+++ b/glucometerutils/drivers/freestyle_optium.py
@@ -15,6 +15,14 @@ import serial
from glucometerutils import common
from glucometerutils import exceptions
+
+class InvalidChecksum(exceptions.InvalidResponse):
+ def __init__(self, expected, gotten):
+ self.message = (
+ 'Response checksum not matching: %04x expected, %04x gotten' %
+ (expected, gotten))
+
+
_CLOCK_RE = re.compile(
r'^Clock:\t(?P<month>[A-Z][a-z]{2}) (?P<day>[0-9]{2}) (?P<year>[0-9]{4})\t'
r'(?P<time>[0-9]{2}:[0-9]{2}:[0-9]{2})$')
@@ -28,7 +36,10 @@ _CLOCK_RE = re.compile(
# I don't have β-ketone strips to test.
_READING_RE = re.compile(
r'^(?P<reading>HI |[0-9]{3}) (?P<month>[A-Z][a-z]{2})[ ey] (?P<day>[0-9]{2}) '
- r'(?P<year>[0-9]{4}) (?P<time>[0-9]{2}:[0-9]{2}) G 0x00')
+ r'(?P<year>[0-9]{4}) (?P<time>[0-9]{2}:[0-9]{2}) G 0x00$')
+
+_CHECKSUM_RE = re.compile(
+ r'^(?P<checksum>0x[0-9A-F]{4}) END$')
# There are two date format used by the device. One uses three-letters month
# names, and that's easy enough. The other uses three-letters month names,
@@ -68,7 +79,7 @@ def _parse_clock(datestr):
hour, minute, second = (int(part) for part in match.group('time').split(':'))
return datetime.datetime(year, month, day, hour, minute, second)
-
+
class Device(object):
def __init__(self, device):
@@ -226,6 +237,19 @@ class Device(object):
if count != (len(data) - 6):
raise exceptions.InvalidResponse('\n'.join(data))
+ # Extract the checksum from the last line.
+ checksum_match = _CHECKSUM_RE.match(data[-1])
+ if not checksum_match:
+ raise exceptions.InvalidResponse('\n'.join(data))
+
+ expected_checksum = int(checksum_match.group('checksum'), 16)
+ # exclude the last line in the checksum calculation, as that's the checksum
+ # itself. The final \r\n is added separately.
+ calculated_checksum = sum(ord(c) for c in '\r\n'.join(data[:-1])) + 0xd + 0xa
+
+ if expected_checksum != calculated_checksum:
+ raise InvalidChecksum(expected_checksum, calculated_checksum)
+
for line in data[5:-1]:
match = _READING_RE.match(line)
if not match: