summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--glucometerutils/support/contourusb.py65
1 files changed, 33 insertions, 32 deletions
diff --git a/glucometerutils/support/contourusb.py b/glucometerutils/support/contourusb.py
index 876c534..91491e2 100644
--- a/glucometerutils/support/contourusb.py
+++ b/glucometerutils/support/contourusb.py
@@ -12,8 +12,9 @@ http://protocols.ascensia.com/Programming-Guide.aspx
"""
import datetime
+import enum
import re
-from typing import Dict, List, Optional, Text, Tuple
+from typing import Dict, Generator, List, Optional, Tuple
from glucometerutils.support import driver_base, hiddevice
@@ -58,21 +59,27 @@ class FrameError(Exception):
pass
+@enum.unique
+class Mode(enum.Enum):
+ """Operation modes."""
+
+ ESTABLISH = enum.auto()
+ DATA = enum.auto()
+ PRECOMMAND = enum.auto()
+ COMMAND = enum.auto()
+
+
class ContourHidDevice(driver_base.GlucometerDriver):
"""Base class implementing the ContourUSB HID common protocol.
"""
blocksize = 64
- # Operation modes
- mode_establish = object
- mode_data = object()
- mode_precommand = object()
- mode_command = object()
- state = None
+ state: Optional[Mode] = None
+
+ currecno: Optional[int] = None
- def __init__(self, usb_ids, device_path):
- # type: (Tuple[int, int], Optional[Text]) -> None
+ def __init__(self, usb_ids: Tuple[int, int], device_path: Optional[str]) -> None:
super().__init__(device_path)
self._hid_session = hiddevice.HidSession(usb_ids, device_path)
@@ -96,8 +103,8 @@ class ContourHidDevice(driver_base.GlucometerDriver):
self._hid_session.write(data)
- USB_VENDOR_ID = 0x1A79 # type: int # Bayer Health Care LLC Contour
- USB_PRODUCT_ID = 0x6002 # type: int
+ USB_VENDOR_ID: int = 0x1A79 # Bayer Health Care LLC Contour
+ USB_PRODUCT_ID: int = 0x6002
def parse_header_record(self, text):
header = _HEADER_RECORD_RE.search(text)
@@ -162,7 +169,7 @@ class ContourHidDevice(driver_base.GlucometerDriver):
checksum = hex(sum(ord(c) for c in text) % 256).upper().split("X")[1]
return ("00" + checksum)[-2:]
- def checkframe(self, frame):
+ def checkframe(self, frame) -> Optional[str]:
"""
Implemented by Anders Hammarquist for glucodump project
More info: https://bitbucket.org/iko/glucodump/src/default/
@@ -202,7 +209,7 @@ class ContourHidDevice(driver_base.GlucometerDriver):
def _get_info_record(self):
self.currecno = None
- self.state = self.mode_establish
+ self.state = Mode.ESTABLISH
try:
while True:
self.write("\x04")
@@ -233,23 +240,19 @@ class ContourHidDevice(driver_base.GlucometerDriver):
# Some of the commands are also shared across devices that use this HID
# protocol, but not many. Only provide here those that do seep to change
# between them.
- def _get_version(self):
- # type: () -> Text
+ def _get_version(self) -> str:
"""Return the software version of the device."""
return self.dig_ver + " - " + self.anlg_ver + " - " + self.agp_ver
- def _get_serial_number(self):
- # type: () -> Text
+ def _get_serial_number(self) -> str:
"""Returns the serial number of the device."""
return self.serial_num
- def _get_glucose_unit(self):
- # type: () -> Text
+ def _get_glucose_unit(self) -> str:
"""Return 0 for mg/dL, 1 for mmol/L"""
return self.unit
- def get_datetime(self):
- # type: () -> datetime.datetime
+ def get_datetime(self) -> datetime.datetime:
datetime_str = self.datetime
return datetime.datetime(
int(datetime_str[0:4]), # year
@@ -260,26 +263,26 @@ class ContourHidDevice(driver_base.GlucometerDriver):
0,
)
- def sync(self):
+ def sync(self) -> Generator[str, None, None]:
"""
Sync with meter and yield received data frames
FSM implemented by Anders Hammarquist's for glucodump
More info: https://bitbucket.org/iko/glucodump/src/default/
"""
- self.state = self.mode_establish
+ self.state = Mode.ESTABLISH
try:
tometer = "\x04"
result = None
foo = 0
while True:
self.write(tometer)
- if result is not None and self.state == self.mode_data:
+ if result is not None and self.state == Mode.DATA:
yield result
result = None
data_bytes = self.read()
data = data_bytes.decode()
- if self.state == self.mode_establish:
+ if self.state == Mode.ESTABLISH:
if data_bytes[-1] == 15:
# got a <NAK>, send <EOT>
tometer = chr(foo)
@@ -291,10 +294,10 @@ class ContourHidDevice(driver_base.GlucometerDriver):
tometer = "\x06"
self.currecno = None
continue
- if self.state == self.mode_data:
+ if self.state == Mode.DATA:
if data_bytes[-1] == 4:
# got an <EOT>, done
- self.state = self.mode_precommand
+ self.state = Mode.PRECOMMAND
break
stx = data.find("\x02")
if stx != -1:
@@ -302,7 +305,7 @@ class ContourHidDevice(driver_base.GlucometerDriver):
try:
result = self.checkframe(data[stx:])
tometer = "\x06"
- self.state = self.mode_data
+ self.state = Mode.DATA
except FrameError:
tometer = "\x15" # Couldn't parse, <NAK>
else:
@@ -311,15 +314,13 @@ class ContourHidDevice(driver_base.GlucometerDriver):
except Exception as e:
raise e
- def parse_result_record(self, text):
- # type: (Text) -> Dict[Text, Text]
+ def parse_result_record(self, text: str) -> Dict[str, str]:
result = _RESULT_RECORD_RE.search(text)
assert result is not None
rec_text = result.groupdict()
return rec_text
- def _get_multirecord(self):
- # type: () -> List[Dict[Text, Text]]
+ def _get_multirecord(self) -> List[Dict[str, str]]:
"""Queries for, and returns, "multirecords" results.
Returns: