From dea8ec030eda9d9d2c4f22d1491cae5d2b94c79a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20Elio=20Petten=C3=B2?= Date: Sat, 3 Jun 2017 15:46:35 +0100 Subject: Abbott devices: add support for using hidapi library. This allows these drivers to be used on operating systems other than Linux, as hidapi abstracts away the access. The interface is similar enough to using hidraw that the actual code only needed minimal changes. Maintain the ability to access the devices with the hidraw path too, without forcing the dependency. --- README | 10 +++++---- gdef | 2 +- glucometerutils/drivers/fsinsulinx.py | 7 +++++-- glucometerutils/drivers/fslibre.py | 6 +++++- glucometerutils/drivers/fsprecisionneo.py | 5 ++++- glucometerutils/support/freestyle.py | 35 +++++++++++++++++++++++++------ 6 files changed, 50 insertions(+), 15 deletions(-) diff --git a/README b/README index 3620439..329aa69 100644 --- a/README +++ b/README @@ -26,18 +26,20 @@ information on each of the devices. | LifeScan | OneTouch Ultra Mini | `otultraeasy` | [pyserial] | | LifeScan | OneTouch Verio (USB) | `otverio2015` | [python-scsi] | | LifeScan | OneTouch Select Plus | `otverio2015` | [python-scsi] | -| Abbott | FreeStyle InsuLinx† | `fsinsulinx` | | -| Abbott | FreeStyle Libre | `fslibre` | | +| Abbott | FreeStyle InsuLinx† | `fsinsulinx` | [hidapi]‡ | +| Abbott | FreeStyle Libre | `fslibre` | [hidapi]‡ | | Abbott | FreeStyle Optium | `fsoptium` | [pyserial] | -| Abbott | FreeStyle Precision Neo | `fsprecisionneo` | | -| Abbott | FreeStyle Optium Neo† | `fsprecisionneo` | | +| Abbott | FreeStyle Precision Neo | `fsprecisionneo` | [hidapi]‡ | +| Abbott | FreeStyle Optium Neo† | `fsprecisionneo` | [hidapi]‡ | | Roche | Accu-Chek Mobile | `accuchek_reports` | | | SD Biosensor | SD CodeFree | `sdcodefree` | [pyserial] | † Untested. +‡ Optional dependency on Linux; required on other operating systems. [pyserial]: https://pythonhosted.org/pyserial/ [python-scsi]: https://github.com/rosjat/python-scsi +[hidapi]: https://pypi.python.org/pypi/hidapi ## Dump format diff --git a/gdef b/gdef index 835b4df..0a3359b 160000 --- a/gdef +++ b/gdef @@ -1 +1 @@ -Subproject commit 835b4df9b0fe6bb1071d8f3b3e1e33a926b97db6 +Subproject commit 0a3359b0863f7b69d9c301e12e3d3fc55a4b8310 diff --git a/glucometerutils/drivers/fsinsulinx.py b/glucometerutils/drivers/fsinsulinx.py index f0986ee..2d3cf2c 100644 --- a/glucometerutils/drivers/fsinsulinx.py +++ b/glucometerutils/drivers/fsinsulinx.py @@ -6,7 +6,8 @@ Supported features: - get and set date and time; - get serial number and software version. -Expected device path: /dev/hidraw9 or similar HID device. +Expected device path: /dev/hidraw9 or similar HID device. Optional when using +HIDAPI. WARNING: currently untested! Based off reverse engineering notes provided by Xavier Claessens. @@ -41,7 +42,9 @@ _InsulinxReading = collections.namedtuple('_InsulinxReading', ( class Device(freestyle.FreeStyleHidDevice): - """Glucometer driver for FreeStyle Precision Neo devices.""" + """Glucometer driver for FreeStyle InsuLinux devices.""" + + USB_PRODUCT_ID = 0x3460 def get_meter_info(self): """Return the device information in structured form.""" diff --git a/glucometerutils/drivers/fslibre.py b/glucometerutils/drivers/fslibre.py index b364cc2..4dda376 100644 --- a/glucometerutils/drivers/fslibre.py +++ b/glucometerutils/drivers/fslibre.py @@ -6,11 +6,13 @@ Supported features: - get and set date and time; - get serial number and software version. -Expected device path: /dev/hidraw9 or similar HID device. +Expected device path: /dev/hidraw9 or similar HID device. Optional when using +HIDAPI. Further information on the device protocol can be found at https://flameeyes.github.io/glucometer-protocols/abbott/freestyle-libre + """ __author__ = 'Diego Elio Pettenò' @@ -164,6 +166,8 @@ def _parse_arresult(record): class Device(freestyle.FreeStyleHidDevice): """Glucometer driver for FreeStyle Libre devices.""" + USB_PRODUCT_ID = 0x3650 + def get_meter_info(self): """Return the device information in structured form.""" return common.MeterInfo( diff --git a/glucometerutils/drivers/fsprecisionneo.py b/glucometerutils/drivers/fsprecisionneo.py index b77617c..42e652d 100644 --- a/glucometerutils/drivers/fsprecisionneo.py +++ b/glucometerutils/drivers/fsprecisionneo.py @@ -9,7 +9,8 @@ Supported features: - get and set date and time; - get serial number and software version. -Expected device path: /dev/hidraw9 or similar HID device. +Expected device path: /dev/hidraw9 or similar HID device. Optional when using +HIDAPI. Further information on the device protocol can be found at @@ -47,6 +48,8 @@ _NeoReading = collections.namedtuple('_NeoReading', ( class Device(freestyle.FreeStyleHidDevice): """Glucometer driver for FreeStyle Precision Neo devices.""" + USB_PRODUCT_ID = 0x3850 + def get_meter_info(self): """Return the device information in structured form.""" return common.MeterInfo( diff --git a/glucometerutils/support/freestyle.py b/glucometerutils/support/freestyle.py index bb891fd..737eda1 100644 --- a/glucometerutils/support/freestyle.py +++ b/glucometerutils/support/freestyle.py @@ -69,16 +69,39 @@ class FreeStyleHidDevice(object): TEXT_CMD = 0x60 TEXT_REPLY_CMD = 0x60 + USB_VENDOR_ID = 0x1a61 # Abbott Diabetes Care + USB_PRODUCT_ID = None + def __init__(self, device): - if not device: + # If we do not know for sure the device ID, rely on the user providing a + # device path. + if self.USB_PRODUCT_ID is None and not device: raise exceptions.CommandLineError( '--device parameter is required, should point to /dev/hidraw ' 'for the meter') - if not os.path.exists(device): + # If the user passed a device path that does not exist, raise an error. + if device and not os.path.exists(device): raise exceptions.ConnectionFailed( message='Path %s does not exist.' % device) - self.handle_ = open(device, 'w+b') + + # If the user passed a device, try opening it. Note that I have had no + # success on actually opening the /dev/hidraw path but that's a + # different problem. + try: + if device: + self.handle_ = open(device, 'w+b') + else: + try: + import hid + except ImportError: + raise exceptions.ConnectionFailed( + message='Missing requied "hidapi" module.') + self.handle_ = hid.device() + self.handle_.open(self.USB_VENDOR_ID, self.USB_PRODUCT_ID) + except OSError: + raise exceptions.ConnectionFailed( + message='Unable to connect to meter.') def connect(self): """Open connection to the device, starting the knocking sequence.""" @@ -103,8 +126,7 @@ class FreeStyleHidDevice(object): cmdlen = len(command) assert cmdlen <= 62 - # First byte in the written buffer is the report number, on Linux HID - # interface. + # First byte in the written buffer is the report number. usb_packet = b'\x00' + _STRUCT_PREAMBLE.pack( message_type, cmdlen) + command + bytes(62 - cmdlen) @@ -126,7 +148,8 @@ class FreeStyleHidDevice(object): if message_type == 0x22 and message_length == 1: return self._read_response() - return (message_type, message_content) + # hidapi module returns a list of bytes rather than a bytes object. + return (message_type, bytes(message_content)) def _send_text_command(self, command): """Send a command to the device that expects a text reply.""" -- cgit v1.2.3