From 8524c9386e754fba0f7144b7d4d828e4a89afcc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20Elio=20Petten=C3=B2?= Date: Fri, 27 Mar 2020 13:37:57 +0000 Subject: Fix typing for contourusb support module. This replaces the definition of modes with an Enum class, which is more appropriate, and adds typing throughout the module. Text is also replaced with str since we don't support Python 2 anyway. --- glucometerutils/support/contourusb.py | 65 ++++++++++++++++++----------------- 1 file 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 , send 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 , 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, 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: -- cgit v1.2.3