From 3999c3eb3c82abc20af618df81631a114504a7b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20Elio=20Petten=C3=B2?= Date: Sat, 6 Jan 2018 20:47:13 +0000 Subject: lifescan_binary_protocol: create a new module to support LifeScan drivers. Both the UltraEasy and Verio 2015 use a similar protocol, with the same base packet serialised to the device. Factor the packet definition out (and make it a bit more generic). Verio IQ (Issue #30) also shares the same base protocol. Also move the definition of VERIO_TIMESTAMP to this common module as it's also shared with the Verio IQ. --- glucometerutils/drivers/otultraeasy.py | 43 +++++------------- glucometerutils/drivers/otverio2015.py | 38 +++++----------- .../support/lifescan_binary_protocol.py | 52 ++++++++++++++++++++++ 3 files changed, 73 insertions(+), 60 deletions(-) create mode 100644 glucometerutils/support/lifescan_binary_protocol.py diff --git a/glucometerutils/drivers/otultraeasy.py b/glucometerutils/drivers/otultraeasy.py index 57c7ea2..0063ec1 100644 --- a/glucometerutils/drivers/otultraeasy.py +++ b/glucometerutils/drivers/otultraeasy.py @@ -15,7 +15,7 @@ Expected device path: /dev/ttyUSB0 or similar serial port device. __author__ = 'Diego Elio Pettenò' __email__ = 'flameeyes@flameeyes.eu' -__copyright__ = 'Copyright © 2014-2017, Diego Elio Pettenò' +__copyright__ = 'Copyright © 2014-2018, Diego Elio Pettenò' __license__ = 'MIT' import binascii @@ -27,36 +27,12 @@ import construct from glucometerutils import common from glucometerutils.support import construct_extras from glucometerutils.support import lifescan +from glucometerutils.support import lifescan_binary_protocol from glucometerutils.support import serial _INVALID_RECORD = 501 - -_PACKET = construct.Struct( - construct.RawCopy( - construct.Embedded( - construct.Struct( - construct.Const(b'\x02'), # stx - 'length' / construct.Rebuild( - construct.Byte, lambda ctx: len(ctx.message) + 6), - construct.EmbeddedBitStruct( - construct.Padding(3), - 'more' / construct.Default(construct.Flag, False), - 'disconnect' / construct.Flag, - 'acknowledge' / construct.Flag, - 'expect_receive' / construct.Flag, - 'sequence_number' / construct.Flag, - ), - 'message' / construct.Bytes(length=lambda ctx: ctx.length - 6), - construct.Const(b'\x03'), # etx - ), - ), - ), - 'checksum' / construct.Checksum( - construct.Int16ul, lifescan.crc_ccitt, construct.this.data), -) - _COMMAND_SUCCESS = construct.Const(b'\x05\x06') _VERSION_REQUEST = construct.Const(b'\x05\x0d\x02') @@ -130,7 +106,8 @@ class Device(serial.SerialDevice): self.sent_counter_ = False self.expect_receive_ = False - self.buffered_reader_ = construct.Rebuffered(_PACKET, tailcutoff=1024) + self.buffered_reader_ = construct.Rebuffered( + lifescan_binary_protocol.PACKET, tailcutoff=1024) def connect(self): try: @@ -143,13 +120,15 @@ class Device(serial.SerialDevice): self.connect() def _send_packet(self, message, acknowledge=False, disconnect=False): - pkt = _PACKET.build( + pkt = lifescan_binary_protocol.PACKET.build( {'value': { 'message': message, - 'sequence_number': self.sent_counter_, - 'expect_receive': self.expect_receive_, - 'acknowledge': acknowledge, - 'disconnect': disconnect, + 'link_control': { + 'sequence_number': self.sent_counter_, + 'expect_receive': self.expect_receive_, + 'acknowledge': acknowledge, + 'disconnect': disconnect, + }, }}) logging.debug('sending packet: %s', binascii.hexlify(pkt)) diff --git a/glucometerutils/drivers/otverio2015.py b/glucometerutils/drivers/otverio2015.py index 2c5b52f..d0b8a9c 100644 --- a/glucometerutils/drivers/otverio2015.py +++ b/glucometerutils/drivers/otverio2015.py @@ -22,7 +22,7 @@ https://flameeyes.github.io/glucometer-protocols/lifescan/onetouch-verio-2015 __author__ = 'Diego Elio Pettenò' __email__ = 'flameeyes@flameeyes.eu' -__copyright__ = 'Copyright © 2016-2017, Diego Elio Pettenò' +__copyright__ = 'Copyright © 2016-2018, Diego Elio Pettenò' __license__ = 'MIT' import binascii @@ -35,38 +35,17 @@ from pyscsi.pyscsi.scsi_device import SCSIDevice from glucometerutils import common from glucometerutils import exceptions -from glucometerutils.support import construct_extras from glucometerutils.support import lifescan +from glucometerutils.support import lifescan_binary_protocol # This device uses SCSI blocks as registers. _REGISTER_SIZE = 512 _PACKET = construct.Padded( - 512, construct.Struct( - construct.RawCopy( - construct.Embedded( - construct.Struct( - construct.Const(b'\x02'), # stx - 'length' / construct.Rebuild( - construct.Int16ul, lambda ctx: len(ctx.message) + 6), - 'message' / construct.Bytes( - length=lambda ctx: ctx.length - 6), - construct.Const(b'\x03'), # etx - ), - ), - ), - 'checksum' / construct.Checksum( - construct.Int16ul, lifescan.crc_ccitt, construct.this.data), - ), -) + _REGISTER_SIZE, construct.Embedded(lifescan_binary_protocol.PACKET)) _COMMAND_SUCCESS = construct.Const(b'\x04\x06') -# Device-specific timestamp. All timestamp reported by this device are seconds -# since this date. -_TIMESTAMP = construct_extras.Timestamp( - construct.Int32ul, epoch=946684800) # 2010-01-01 00:00 - _QUERY_REQUEST = construct.Struct( construct.Const(b'\x04\xe6\x02'), 'selector' / construct.Enum( @@ -101,12 +80,12 @@ _READ_RTC_REQUEST = construct.Const(b'\x04\x20\x02') _READ_RTC_RESPONSE = construct.Struct( _COMMAND_SUCCESS, - 'timestamp' / _TIMESTAMP, + 'timestamp' / lifescan_binary_protocol.VERIO_TIMESTAMP, ) _WRITE_RTC_REQUEST = construct.Struct( construct.Const(b'\x04\x20\x01'), - 'timestamp' / _TIMESTAMP, + 'timestamp' / lifescan_binary_protocol.VERIO_TIMESTAMP, ) _MEMORY_ERASE_REQUEST = construct.Const(b'\x04\x1a') @@ -135,7 +114,7 @@ _READ_RECORD_RESPONSE = construct.Struct( 'inverse_counter' / construct.Int16ul, construct.Padding(1), 'lifetime_counter' / construct.Int16ul, - 'timestamp' / _TIMESTAMP, + 'timestamp' / lifescan_binary_protocol.VERIO_TIMESTAMP, 'value' / construct.Int16ul, 'meal' / construct.SymmetricMapping( construct.Byte, _MEAL_FLAG), @@ -186,7 +165,10 @@ class Device(object): """ try: request = request_format.build(request_obj) - request_raw = _PACKET.build({'value': {'message': request}}) + request_raw = _PACKET.build({'value': { + 'message': request, + 'link_control': {}, # Verio does not use link_control. + }}) logging.debug( 'Request sent: %s', binascii.hexlify(request_raw)) self.scsi_.write10(lba, 1, request_raw) diff --git a/glucometerutils/support/lifescan_binary_protocol.py b/glucometerutils/support/lifescan_binary_protocol.py new file mode 100644 index 0000000..68b030d --- /dev/null +++ b/glucometerutils/support/lifescan_binary_protocol.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +"""Support module for the LifeScan binary protocol. + +A number of LifeScan devices use a semi-compatible binary protocol to talk host +and device, which is (vastly) compatible. + +This module implements an interface to send and receive these messages. +""" + +__author__ = 'Diego Elio Pettenò' +__email__ = 'flameeyes@flameeyes.eu' +__copyright__ = 'Copyright © 2014-2018, Diego Elio Pettenò' +__license__ = 'MIT' + +import construct + +from glucometerutils.support import construct_extras +from glucometerutils.support import lifescan + + +PACKET = construct.Struct( + construct.RawCopy( + construct.Embedded( + construct.Struct( + construct.Const(b'\x02'), # stx + 'length' / construct.Rebuild( + construct.Byte, lambda ctx: len(ctx.message) + 6), + # The following structure is only used by some of the devices. + 'link_control' / construct.BitStruct( + construct.Padding(3), + 'more' / construct.Default( + construct.Flag, False), + 'disconnect' / construct.Default( + construct.Flag, False), + 'acknowledge' / construct.Default( + construct.Flag, False), + 'expect_receive' / construct.Default( + construct.Flag, False), + 'sequence_number' / construct.Default( + construct.Flag, False), + ), + 'message' / construct.Bytes(length=lambda ctx: ctx.length - 6), + construct.Const(b'\x03'), # etx + ), + ), + ), + 'checksum' / construct.Checksum( + construct.Int16ul, lifescan.crc_ccitt, construct.this.data), +) + +VERIO_TIMESTAMP = construct_extras.Timestamp( + construct.Int32ul, epoch=946684800) # 2010-01-01 00:00 -- cgit v1.2.3