def __init__(self, stream): raw = bytearray(stream.read(1024)) data, crc = raw[0:1022], raw[1022:] computed = lib.CRC16CCITT.compute(bytearray(data)) if lib.BangInt(crc) != computed: assert lib.BangInt(crc) == computed, "CRC does not match page data" data.reverse() self.data = self.eat_nulls(data) self.stream = io.BufferedReader(io.BytesIO(self.data))
def readStatus(self): result = self.link.sendComLink2Command(3) commStatus = result[0] # 0 indicates success if commStatus != 0: log.error("readStatus: non-zero status: %02x" % commStatus) raise BadDeviceCommError("readStatus: non-zero status: %02x" % commStatus) status = result[2] lb, hb = result[3], result[4] bytesAvailable = lib.BangInt((lb, hb)) self.status = status log.info('status byte: %02x' % status) if (status & 0x2) > 0: log.info('STATUS: receive in progress!') if (status & 0x4) > 0: log.info('STATUS: transmit in progress!') if (status & 0x8) > 0: log.info('STATUS: interface error!') if (status & 0x10) > 0: log.info('STATUS: recieve overflow!') if (status & 0x20) > 0: log.info('STATUS: transmit overflow!') assert commStatus == 0 if (status & 0x1) > 0: return bytesAvailable return 0
def decode(self): self.parse_time( ) dose = { 'amount': self.head[2]/10.0, 'programmed': self.head[1]/10.0, 'duration': self.head[3] * 30, 'type': self.head[3] > 0 and 'square' or 'normal' } if self.larger: duration = self.head[7] * 30 dose = { 'amount': lib.BangInt(self.head[3:5])/40.0, 'programmed': lib.BangInt(self.head[1:3])/40.0, 'unabsorbed': lib.BangInt(self.head[5:7])/40.0, 'duration': duration, 'type': duration > 0 and 'square' or 'normal', } return dose
def decode(self): self.parse_time( ) bg = lib.BangInt([ self.body[1] & 0x0f, self.head[1] ]) carb_input = int(self.body[0]) # XXX: I have no idea if this is correct; it seems to produce correct results. correction = ( twos_comp( self.body[7], 8 ) + twos_comp( self.body[5] & 0x0f, 8 ) ) / 10.0 wizard = { 'bg': bg, 'carb_input': carb_input, 'carb_ratio': int(self.body[2]), 'sensitivity': int(self.body[3]), 'bg_target_low': int(self.body[4]), 'bg_target_high': int(self.body[12]), 'bolus_estimate': int(self.body[11])/10.0, 'food_estimate': int(self.body[6])/10.0, 'unabsorbed_insulin_total': int(self.body[9])/10.0, 'unabsorbed_insulin_count': '??', 'correction_estimate': correction, '_byte[5]': self.body[5], '_byte[7]': int(self.body[7]), # 'unknown_byte[8]': self.body[8], 'unknown_byte[10]': self.body[10], # '??': '??', # 'unabsorbed_insulin_total': int(self.body[9])/10.0, # 'food_estimate': int(self.body[0]), } if self.larger: # correction = ( twos_comp( self.body[6], (self.body[9] & 0x38) << 5 ) ) / 40.0 bg = ((self.body[1] & 0x03) << 8) + self.head[1] carb_input = ((self.body[1] & 0x0c) << 6) + self.body[0] carb_ratio = (((self.body[2] & 0x07) << 8) + self.body[3]) / 10.0 # xxx: not sure about this # https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/log_entries/bolus_wizard.rb#L102 sensitivity = int(self.body[4]) wizard = { 'bg': bg, 'carb_input': carb_input, 'carb_ratio': carb_ratio, 'sensitivity': sensitivity, 'bg_target_low': int(self.body[5]), 'bg_target_high': int(self.body[14]), # 'bolus_estimate': int(self.body[13])/40.0, 'correction_estimate': (((self.body[9] & 0x38) << 5) + self.body[6]) / 40.0, # 'correction_maybe_estimate': correction, 'food_estimate': insulin_decode(self.body[7], self.body[8]), 'unabsorbed_insulin_total': insulin_decode(self.body[10], self.body[11]), 'bolus_estimate': insulin_decode(self.body[12], self.body[13]), # 'unknown_bytes': map(int, list(self.body)), } if self.MMOL_DEFAULT: for key in [ 'bg', 'bg_target_high', 'bg_target_low', 'sensitivity' ]: wizard[key] = wizard[key] / 10.0 return wizard
def __init__(self, stream, larger=False): raw = bytearray(stream.read(1024)) data, crc = raw[0:1022], raw[1022:] computed = lib.CRC16CCITT.compute(bytearray(data)) self.larger = larger if lib.BangInt(crc) != computed: raise DataTransferCorruptionError("CRC does not match page data") data.reverse() self.data = self.eat_nulls(data) self.stream = io.BufferedReader(io.BytesIO(self.data))
def readDeviceDataIO(self): results = self.readData() lb, hb = results[5] & 0x7F, results[6] self.eod = (results[5] & 0x80) > 0 resLength = lib.BangInt((lb, hb)) log.info('XXX resLength: %s' % resLength) #assert resLength < 64, ("cmd low byte count:\n%s" % lib.hexdump(results)) data = results[13:13 + resLength] assert len(data) == resLength crc = results[-1] # crc check log.info('readDeviceDataIO:msgCRC:%r:expectedCRC:%r:data:%s' % (crc, CRC8(data), lib.hexdump(data))) assert crc == CRC8(data) return data
def decode(self): self.parse_time() bg = lib.BangInt([self.body[1] & 0x0f, self.head[1]]) carb_input = int(self.body[0]) # XXX: I have no idea if this is correct; it seems to produce correct results. correction = (twos_comp(self.body[7], 8) + twos_comp(self.body[5] & 0x0f, 8)) / 10.0 wizard = { 'bg': bg, 'carb_input': carb_input, 'carb_ratio': int(self.body[2]), 'sensitivity': int(self.body[3]), 'bg_target_low': int(self.body[4]), 'bg_target_high': int(self.body[12]), 'bolus_estimate': int(self.body[11]) / 10.0, 'food_estimate': int(self.body[6]) / 10.0, 'unabsorbed_insulin_total': int(self.body[9]) / 10.0, 'unabsorbed_insulin_count': '??', 'correction_estimate': correction, '_byte[5]': self.body[5], '_byte[7]': int(self.body[7]), # 'unknown_byte[8]': self.body[8], 'unknown_byte[10]': self.body[10], # '??': '??', # 'unabsorbed_insulin_total': int(self.body[9])/10.0, # 'food_estimate': int(self.body[0]), } if self.larger: correction = (twos_comp(self.body[6], 8)) / 40.0 wizard = { 'bg': bg, 'carb_input': carb_input, 'carb_ratio': int(self.body[14]) / 10.0, 'sensitivity': int(self.body[4]), 'bg_target_low': int(self.body[5]), 'bg_target_high': int(self.body[3]), 'bolus_estimate': int(self.body[13]) / 40.0, # 'correction_estimate': int(self.body[6])/40.0, 'correction_estimate': correction, 'food_estimate': int(self.body[8]) / 40.0, 'unabsorbed_insulin_total': int(self.body[11]) / 40.0, # 'unknown_bytes': map(int, list(self.body)), } return wizard
def decode (self): """ XXX: buggy code * fails to acknowledge gaps in time * fails to acknowledge SensorSync """ records = [ ] prefix_records = [] for B in iter(lambda: self.stream.read(1), ""): B = bytearray(B) record = self.suggest(B[0]) record['_tell'] = self.stream.tell( ) # read packet if needed if not record is None and record['packet_size'] > 0: raw_packet = bytearray(self.stream.read(record['packet_size'])) if record['name'] == 'DataEnd': prefix_records.append(record) continue elif record['name'] == 'GlucoseSensorData' or record['name'] == 'SensorWeakSignal' \ or record['name'] == 'SensorCal' or record['name'] == '19-Something': # add to prefixed records to add to the next sensor minute timestamped record if record['name'] == 'SensorCal': record.update(raw=self.byte_to_str(raw_packet)) if int(raw_packet[0]) == 1: record.update(waiting='waiting') else: record.update(waiting='meter_bg_now') prefix_records.append(record) elif record['name'] == 'SensorTimestamp' or record['name'] == 'SensorCalFactor' or record['name'] in ['10-Something' ]: # TODO: maybe this is like a ResetGlucose base command # these are sensor minute timestamped records thus create the record # and map prefixed elements based on the timedelta record.update(raw=self.byte_to_str(raw_packet)) date, body = raw_packet[:4], raw_packet[4:] date.reverse() date = parse_date(date) if date: record.update(date=date.isoformat()) else: print "@@@", self.stream.tell( ) pprint(dict(raw=hexlify(raw_packet))) pprint(dict(date=hexlify(date or bytearray( )))) pprint(dict(body=hexlify(body))) break prefix_records.reverse() mapped_glucose_records = self.map_glucose(prefix_records, start=date, delta=self.delta_ago(reverse=True)) mapped_glucose_records.reverse() # And this ResetGlucose has a payload indicating calibration factor # Update sensor cal factor if record['name'] == 'SensorCalFactor': factor = lib.BangInt([ body[0], body[1] ]) / 1000.0 record.update(factor=factor) records.extend(mapped_glucose_records) records.append(record) prefix_records = [] elif record['name'] in ['SensorStatus', 'DateTimeChange', 'SensorSync', '10-Something', 'CalBGForGH', 'BatteryChange' ]: # independent record => parse and add to records list record.update(raw=self.byte_to_str(raw_packet)) if record['name'] in ['SensorStatus', 'SensorSync', 'CalBGForGH', 'BatteryChange', 'DateTimeChange']: date, body = raw_packet[:4], raw_packet[4:] date.reverse() date = parse_date(date) if date is not None: record.update(date=date.isoformat()) else: record.update(_date=str(raw_packet[:4]).encode('hex')) record.update(body=self.byte_to_str(body)) # Update cal amount if record['name'] == 'DateTimeChange': """ changed = body[1:5] changed.reverse( ) changed = parse_date(changed) record.update(change=changed.isoformat( ), body=self.byte_to_str(body[5:])) """ if record['name'] == 'CalBGForGH': amount = lib.BangInt([ (raw_packet[2] & 0b00100000) >> 5, body[0] ]) record.update(body=self.byte_to_str(body)) record.update(amount=amount) records.append(record) else: # could not decode records.append(record) # End For records.reverse() self.records = records return self.records
def decode(self): self.parse_time() year_bits = extra_year_bits(self.date[4]) return {'amount': int(lib.BangInt([year_bits[0], self.head[1]]))} pass
def decode(self): """ XXX: buggy code * fails to acknowledge gaps in time * fails to acknowledge SensorSync """ records = [] prefix_records = [] for B in iter(lambda: self.stream.read(1), ""): B = bytearray(B) record = self.suggest(B[0]) # read packet if needed if not record is None and record['packet_size'] > 0: raw_packet = bytearray(self.stream.read(record['packet_size'])) if record['name'] == 'DataEnd': prefix_records.append(record) continue elif record['name'] == 'GlucoseSensorData' or record['name'] == 'SensorWeakSignal' \ or record['name'] == 'SensorCal' or record['name'] == '19-Something': # add to prefixed records to add to the next sensor minute timestamped record if record['name'] == 'SensorCal': record.update(raw=self.byte_to_str(raw_packet)) if int(raw_packet[0]) == 1: record.update(waiting='waiting') else: record.update(waiting='meter_bg_now') prefix_records.append(record) elif record['name'] == 'SensorTimestamp' or record[ 'name'] == 'SensorCalFactor': # TODO: maybe this is like a ResetGlucose base command # these are sensor minute timestamped records thus create the record # and map prefixed elements based on the timedelta record.update(raw=self.byte_to_str(raw_packet)) date, body = raw_packet[:4], raw_packet[4:] date.reverse() date = parse_date(date) record.update(date=date.isoformat()) prefix_records.reverse() mapped_glucose_records = self.map_glucose( prefix_records, start=date, delta=self.delta_ago(reverse=True)) # mapped_glucose_records.reverse() # And this ResetGlucose has a payload indicating calibration factor # Update sensor cal factor if record['name'] == 'SensorCalFactor': factor = lib.BangInt([body[0], body[1]]) / 1000.0 record.update(factor=factor) records.append(mapped_glucose_records) records.append(record) prefix_records = [] elif record['name'] == 'SensorStatus' or record['name'] == 'DateTimeChange' \ or record['name'] == 'SensorSync' or record['name'] == '10-Something' \ or record['name'] == 'CalBGForGH' : # independent record => parse and add to records list record.update(raw=self.byte_to_str(raw_packet)) if record['name'] == 'SensorStatus' or record['name'] == 'SensorSync'\ or record['name'] == 'CalBGForGH' : date, body = raw_packet[:4], raw_packet[4:] date.reverse() date = parse_date(date) record.update(date=date.isoformat()) record.update(body=self.byte_to_str(body)) # Update cal amount if record['name'] == 'CalBGForGH': amount = int(body[0]) if amount < 32: amount = 0x100 + amount record.update(body=self.byte_to_str(body)) record.update(amount=amount) records.append(record) else: # could not decode records.append(record) # End For records.reverse() self.records = records return self.records