def isEmpty(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ISEMPTY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Check if database is empty. """ # Link to database range command command = self.commands["ReadDatabaseRange"] # Tell command which database to read from command.database = self.code # Read range command.execute() # Decode it self.pageRange = [ lib.unpack(command.response["Payload"][0:4], "<"), lib.unpack(command.response["Payload"][4:8], "<") ] # Return whether it is empty or not return self.pageRange == EMPTY_PAGE_RANGE
def read(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ READ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Get current time self.t = datetime.datetime.now() # Execute command self.commands["ReadLevel"].execute() # Assign response self.level = lib.unpack( self.commands["ReadLevel"].response["Payload"], "<") # Give user info Logger.info("Battery level: " + str(self.level)) # Execute command self.commands["ReadState"].execute() # Assign response self.state = self.states[lib.unpack( self.commands["ReadState"].response["Payload"], "<")] # Give user info Logger.info("Battery state: " + self.state) # Store battery level self.store()
def decode(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Decode the record's bytes. [0-3]: SYSTEM TIME [4-7]: DISPLAY TIME [8:9]: CALIBRATION BG VALUE [10]: ??? [11-14]: ENTERED TIME [15-18]: ??? [19-20]: CRC """ # Initialize decoding super(CalibrationRecord, self).decode() # Entered time self.enteredTime = ( cgm.EPOCH_TIME + datetime.timedelta(seconds=lib.unpack(self.bytes[11:15], "<"))) # Decode BG self.value = round(lib.unpack(self.bytes[8:10], "<") / 18.0, 1)
def read(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ READ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Execute command self.commands["ReadSystemTime"].execute() # Compute time delta since epoch delta = datetime.timedelta(seconds = lib.unpack( self.commands["ReadSystemTime"].response["Payload"], "<")) # Assign response self.systemTime = self.epoch + delta # Give user info Logger.info("System time: " + lib.formatTime(self.systemTime)) # Execute command self.commands["ReadMode"].execute() # Assign response self.mode = self.modes[lib.unpack( self.commands["ReadMode"].response["Payload"], "<")] # Give user info Logger.info("Clock mode: " + self.mode) # Store clock mode self.store()
def decode(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Decode the record's bytes. [0-3]: SYSTEM TIME [4-7]: DISPLAY TIME [8]: EVENT TYPE [9]: EVENT SUB-TYPE [10-13]: ENTERED TIME [14-17]: VALUE [18-19]: CRC """ # Initialize decoding super(EventRecord, self).decode() # Entered time self.enteredTime = ( cgm.EPOCH_TIME + datetime.timedelta(seconds=lib.unpack(self.bytes[10:14], "<"))) # Decode event type self.type = self.types[self.bytes[8]] # Decode event sub-type # No sub-type if self.bytes[9] == 0: self.subType = None # Otherwise else: self.subType = self.subTypes[self.type][self.bytes[9]] # No value entered for health events if self.type == "Health": self.value = None # Otherwise else: self.value = lib.unpack(self.bytes[14:18], "<") # Insulin needs post-treatment if self.type == "Insulin": self.value /= 100.0
def execute(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXECUTE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Command response packet format: [0-3]: HEAD [4-531]: PAYLOAD [532-533]: CRC """ # Reset response self.response = {"Head": None, "Payload": None, "CRC": None} # Prepare packet self.packet.build(self.code, self.database, self.page) # Send packet self.cgm.write(self.packet.bytes) # Get response data data = self.cgm.read() # Check packet status status = data[0] # Packet OK if packets.STATUSES["ACK"] == status: # Compute size of packet to receive size = lib.unpack(data[1:3], "<") # Until whole data collected while len(data) != size: # Read more data data.extend(self.cgm.read()) # Head self.response["Head"] = data[0:4] # Payload self.response["Payload"] = data[4:(size - 2)] # CRC self.response["CRC"] = data[-2:] # Verify response self.verifyCRC() # Otherwise else: raise IOError("Packet does not have an ACK status.")
def decode(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Decode the record's time-related bytes. [0-3] SYSTEM TIME [4-7] DISPLAY TIME [...] """ # Decode system time self.systemTime = ( cgm.EPOCH_TIME + datetime.timedelta(seconds=lib.unpack(self.bytes[0:4], "<"))) # Decode display time self.displayTime = ( cgm.EPOCH_TIME + datetime.timedelta(seconds=lib.unpack(self.bytes[4:8], "<")))
def decode(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Decode local time t = (self.cgm.clock.epoch + datetime.timedelta(seconds=lib.unpack(self.bytes[-1][4:8], "<"))) # Store it self.t.append(t)
def measure(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MEASURE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Reset database range self.range = [] # Link to database range command command = self.commands["ReadDatabaseRange"] # Tell command which database to read from command.database = self.code # Read range command.execute() # Decode it self.range.append(lib.unpack(command.response["Payload"][0:4], "<")) self.range.append(lib.unpack(command.response["Payload"][4:8], "<")) # Deal with empty database if self.range == self.emptyRange: # Give user info Logger.warning("Database empty.") # Exit return False else: # Give user info Logger.debug("Database range: " + str(self.range)) # Exit return True
def decode(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Decode local time t = (self.cgm.clock.epoch + datetime.timedelta(seconds = lib.unpack(self.bytes[-1][4:8], "<"))) # Store it self.t.append(t)
def verifyCRC(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VERIFY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Compute and check CRC value of last record. """ # Decode and compute CRCs expectedCRC = lib.unpack(self.bytes[-2:], "<") computedCRC = crc.compute(self.bytes[:-2]) # Exit if CRCs mismatch if computedCRC != expectedCRC: raise ValueError("Bad record CRC. Expected: " + str(expectedCRC) + ". Computed: " + str(computedCRC) + ".")
def verifyCRC(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VERIFYCRC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Get and compute response CRCs expectedCRC = lib.unpack(self.response["CRC"], "<") computedCRC = crc.compute(self.response["Head"] + self.response["Payload"]) # Exit if CRCs mismatch if computedCRC != expectedCRC: raise ValueError("Bad packet CRC. Expected: " + str(expectedCRC) + ". Computed: " + str(computedCRC) + ".")
def verify(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VERIFY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Get and compute header CRCs expectedCRC = lib.unpack(self.page["Header"][-2:], "<") computedCRC = lib.computeCRC16(self.page["Header"][:-2]) # Exit if CRCs mismatch if computedCRC != expectedCRC: # Error raise errors.BadCGMCRC(expectedCRC, computedCRC)
def verify(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VERIFY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Decode and compute CRCs expectedCRC = lib.unpack(self.bytes[-1][-2:], "<") computedCRC = lib.computeCRC16(self.bytes[-1][:-2]) # Exit if CRCs mismatch if computedCRC != expectedCRC: # Raise error raise errors.BadCGMRecordCRC(expectedCRC, computedCRC)
def verify(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VERIFY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Decode and compute CRCs expectedCRC = lib.unpack(self.bytes[-1][-2:], "<") computedCRC = lib.computeCRC16(self.bytes[-1][:-2]) # Exit if CRCs mismatch if computedCRC != expectedCRC: # Raise error raise errors.BadCGMRecordCRC(expectedCRC, computedCRC)
def verifyCRC(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VERIFYCRC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Verify database page head CRC. """ # Get and compute header CRCs expectedCRC = lib.unpack(self.currentPage["Head"][-2:], "<") computedCRC = crc.compute(self.currentPage["Head"][:-2]) # CRCs mismatch if computedCRC != expectedCRC: raise ValueError("Bad database page head CRC. Expected: " + str(expectedCRC) + ". Computed: " + str(computedCRC) + ".")
def execute(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EXECUTE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Reset response self.response = {"Head": None, "Payload": None, "CRC": None} # Prepare packet self.packet.build(self.code, self.database, self.page) # Send packet self.cgm.write(self.packet.bytes) # Get data data = self.cgm.read() # Compute size of packet to receive size = lib.unpack(data[1:3], "<") # Until whole data collected while len(data) != size: # Read more data data.extend(self.cgm.read()) # Head self.response["Head"] = data[0:4] # Payload self.response["Payload"] = data[4:(size - 2)] # CRC self.response["CRC"] = data[-2:] # Try and find XML structure in response Logger.debug("XML: " + str(lib.XMLify(self.response["Payload"]))) # Verify response self.verify()
def verify(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VERIFY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Get and compute response CRCs expectedCRC = lib.unpack(self.response["CRC"], "<") computedCRC = lib.computeCRC16(self.response["Head"] + self.response["Payload"]) # Exit if CRCs mismatch if computedCRC != expectedCRC: # Error raise errors.BadCGMCRC(expectedCRC, computedCRC)
def decode(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Initialize decoding super(self.__class__, self).decode() # Decode BG BG = round(lib.unpack(self.bytes[-1][8:10], "<") / 18.0, 1) # Store it self.values.append(BG) # Give user info Logger.info("BG: " + str(BG) + " " + self.cgm.units.value + " " + "(" + lib.formatTime(self.t[-1]) + ")")
def decode(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Initialize decoding super(self.__class__, self).decode() # Decode BG BG = round(lib.unpack(self.bytes[-1][8:10], "<") / 18.0, 1) # Store it self.values.append(BG) # Give user info Logger.info("BG: " + str(BG) + " " + self.cgm.units.value + " " + "(" + lib.formatTime(self.t[-1]) + ")")
def read(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ READ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Execute command self.command.execute() # Assign response self.value = self.values[lib.unpack( self.command.response["Payload"], "<")] # Give user info Logger.info("Units: " + self.value) # Store it self.store()
def decode(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Initialize decoding super(self.__class__, self).decode() # Decode BG BG = lib.unpack(self.bytes[-1][8:10], "<") & 1023 # Decode trend trend = self.trends[self.bytes[-1][10] & 15] # Deal with special values if BG in self.special: # Decode special BG BG = self.special[BG] # Give user info Logger.info("Special value: " + BG) # Deal with normal values else: # Convert BG units if desired if self.convert: # Convert them BG = round(BG / 18.0, 1) # Give user info Logger.info("BG: " + str(BG) + " " + str(trend) + " " + "(" + lib.formatTime(self.t[-1]) + ")") # Store them self.values.append({"BG": BG, "Trend": trend})
def decode(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Initialize decoding super(self.__class__, self).decode() # Decode BG BG = lib.unpack(self.bytes[-1][8:10], "<") & 1023 # Decode trend trend = self.trends[self.bytes[-1][10] & 15] # Deal with special values if BG in self.special: # Decode special BG BG = self.special[BG] # Give user info Logger.info("Special value: " + BG) # Deal with normal values else: # Convert BG units if desired if self.convert: # Convert them BG = round(BG / 18.0, 1) # Give user info Logger.info("BG: " + str(BG) + " " + str(trend) + " " + "(" + lib.formatTime(self.t[-1]) + ")") # Store them self.values.append({"BG": BG, "Trend": trend})
def decode(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Decode the record's bytes. [0-3]: SYSTEM TIME [4-7]: DISPLAY TIME [8-9]: BG [10-13]: MEASUREMENT TIME (?) [14-18]: ??? [19]: TREND [20-22]: ??? [23-24]: CRC """ # Initialize decoding super(BGRecord, self).decode() # Decode BG value self.value = lib.unpack(self.bytes[8:10], "<") & BG_VALUE_MASK # Decode trend self.trend = self.trends[self.bytes[19] & BG_TREND_MASK] # G6 #self.trend = self.trends[self.bytes[10] & BG_TREND_MASK] # G4 # Normal values if self.value not in self.special: # Convert BG units by default from mg/dL to mmol/L self.value = round(self.value / 18.0, 1) # Special values else: # Decode special BG self.value = self.special[self.value]
def decode(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Decode record time super(self.__class__, self).decode() # Decode TB rate and units if self.body[0] >= 0 and self.body[0] < 8: # Decode rate rate = round((lib.unpack([self.head[1], self.body[0]], "<") * self.pump.basal.stroke), 2) # Decode units units = "U/h" elif self.body[0] == 8: # Decode rate rate = self.head[1] # Decode units units = "%" # Decode TB duration duration = self.body[2] * self.pump.basal.time # Build TB vector TB = [rate, units, duration] # Store TB self.values.append(TB)
def decode(self): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECODE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Decode record time super(TBRecord, self).decode() # Decode TB rate and units if self.body[0] >= 0 and self.body[0] < 8: # Decode rate rate = round((lib.unpack([self.head[1], self.body[0]], "<") * self.pump.basal.stroke), 2) # Decode units units = "U/h" elif self.body[0] == 8: # Decode rate rate = self.head[1] # Decode units units = "%" # Decode TB duration duration = self.body[2] * self.pump.basal.time # Build TB vector TB = [rate, units, duration] # Store TB self.values.append(TB)
def __init__(self, cgm): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INIT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ # Initialize database code self.code = None # Initialize database record self.record = None # Initialize database range self.range = None # Initialize database page self.page = None # Initialize database data self.data = None # Define response head size self.headSize = 28 # Define empty range response self.emptyRange = [lib.unpack([255] * 4, "<")] * 2 # Define command(s) self.commands = { "ReadDatabaseRange": commands.ReadDatabaseRange(cgm), "ReadDatabase": commands.ReadDatabase(cgm) } # Link with CGM self.cgm = cgm
""" # USER LIBRARIES import lib import logger import reporter import crc import commands import records # Instanciate logger Logger = logger.Logger("CGM.databases") # Constants DATABASE_HEAD_SIZE = 28 EMPTY_PAGE_RANGE = [lib.unpack([255] * 4, "<")] * 2 class Database(object): # Database parameters code = None recordType = records.Record def __init__(self, cgm): """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INIT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """