diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/epc.py b/epc.py new file mode 100644 index 0000000..069435f --- /dev/null +++ b/epc.py @@ -0,0 +1,206 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +''' + Copyright (C) 2016 Entr'ouvert + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +''' + + +import sys +import re + + +class InvalidEPC(Exception): + + def __init__(self, value): + self.value = value + + def __str__(self): + return repr(self.value) + + +def word_flag(word): + ''' + Test first bit of a 2 bytes words. + ''' + return word & 32768 + + +class VeadistaEPC: + def __init__(self, epc, + trcal=85e-6, # V + can_precision=13e-3, # V + sensor_sensibility=70e-3, # V/°C + sensor_center=34): # °C at 011111(b) = 31(d) + + if len(epc) != 24 or not re.match(r'[0-9a-fA-F]{24}', epc): + raise InvalidEPC(epc) + + self.epc = epc + self.words = [int(self.epc[i*4: i*4+4], 16) for i in range(6)] + self.trcal = trcal + self.can_precision = can_precision + self.sensor_sensibility = sensor_sensibility + self.sensor_center = sensor_center + self.can_step = can_precision / sensor_sensibility + self.sensor_start = sensor_center - 31 * self.can_step + + (self.temperature_int, + self.temperature_degree, + self.temperature_volt) = self.get_temperature() + + (self.tension_int, + self.tension_volt) = self.get_tension() + + (self.cpt_trcal, + self.period_osc, + ((self.hr1_int, + self.hr1_second, + self.hr1_bpm), + (self.hr2_int, + self.hr2_second, + self.hr2_bpm), + (self.hr3_int, + self.hr3_second, + self.hr3_bpm))) = self.get_hr() + + def t_celsius(self, value): + return self.sensor_start + value * self.can_step + + def t_voltage(self, value): + return value * self.can_precision + + def get_temperature(self): + w = self.words[1] + value = w & 63 # 6 lsb + + if word_flag(w): + return value, self.t_celsius(value), self.t_voltage(value) + + return None, None, None + + def get_tension(self): + w = self.words[2] + value = w & 63 # 6 lsb + + if word_flag(w): + return value, self.t_voltage(value) + + return None, None + + def get_hr(self): + w = self.words[3] + raw_trcal_count = w & 32512 + + if raw_trcal_count: + cpt_trcal = raw_trcal_count >> 8 + period_osc = self.trcal / (4 * (cpt_trcal + 1)) + + def process_hr(w): + if word_flag(w): + count = w & 255 + if count > 2: + period = (count + 1) * 4 * 4096 * period_osc + return count, period, 60 / period + return None, None, None + + return (cpt_trcal, + period_osc, + [process_hr(self.words[3+i]) for i in range(3)]) + + return None, None, None + + def __str__(self): + string = "----------------------------------------------------------------------" + + string += "\nEPC:\t{}\n".format(' '.join([self.epc[i*4:i*4+4] for i in range(6)])) + + w = self.words[1] + string += "\nWord 3:\t\t\thex : {}\tint : {}\tbin : {:b}\n".format(self.epc[4:8], w, w) + value = w & 63 + if word_flag(w): + string += "CAN precision :\t\t{}V\n".format(self.can_precision) + string += "Sensor sensibility :\t{}V/°C\n".format(self.sensor_sensibility) + string += "Sensor centered at :\t{}°C\n".format(self.sensor_center) + string += "Sensor range :" + string += "\t\t{}°C to {}°C\n".format(self.sensor_start, + self.sensor_start + 63 * self.can_step) + string += "Temperature :\t\tint : {0}/63\tbin : {0:b}\n".format(self.temperature_int) + string += "Temperature :\t\t{} V\n".format(self.temperature_volt) + string += "Temperature :\t\t{} °C\n".format(self.temperature_degree) + else: + string += "Temperature :\t\tflag is null.\n" + + w = self.words[2] + string += "\nWord 4:\t\t\thex : {}\tint : {}\tbin : {:b}\n".format(self.epc[8:12], w, w) + value = w & 63 + if word_flag(w): + string += "CAN precision :\t\t{}mV\n".format(self.can_precision) + string += "External voltage :\tint : {0}/63\tbin : {0:b}\n".format(self.tension_int) + string += "External voltage :\t{} V\n".format(self.tension_volt) + else: + string += "External voltage :\tflag is null.\n" + + w = self.words[3] + string += "\nWord 5:\t\t\thex : {}\tint : {}\tbin : {:b}\n".format(self.epc[12:16], w, w) + raw_trcal_count = w & 32512 + if not raw_trcal_count: + string += "No TRCAL count\n" + else: + count = raw_trcal_count >> 8 + string += "TRCAL reader set : \t{}s\n".format(self.trcal) + string += "TRCAL count : \t\tint : {0}/127\tbin : {0:b}\n".format(self.cpt_trcal) + string += "Osc period (s) : \t{}\n".format(self.period_osc) + string += "Osc frequency (Hz) : \t{}\n".format(1/self.period_osc) + + def process_hr(number, word, value, second, bpm): + string = "" + if word_flag(word): + if not value: + string += "Interval {} :\t\tno value\n".format(number) + elif value <= 2: + string += "Interval {} :\t\tthe sensor".format(number) + string += "seems to be pressed continuously." + string += "\traw int: {0}/255\traw bin : {0:b}\n".format(value) + else: + string += "Interval {0} :\t\tint: {1}/255".format(number, value) + string += "\traw bin : {:b}\n".format(value) + string += "Interval {} :\t\t{} s\n".format(number, second) + string += "Interval {} :\t\t{} bpm\n".format(number, bpm) + else: + string += "Interval {} :\t\tflag is null.\n".format(number) + return string + + string += process_hr(1, w, self.hr1_int, self.hr1_second, self.hr1_bpm) + w = self.words[4] + string += "\nWord 6:\t\t\thex : {}".format(self.epc[16:20]) + string += "\tint : {0}\tbin : {0:b}\n".format(w) + string += process_hr(2, w, self.hr2_int, self.hr2_second, self.hr2_bpm) + w = self.words[5] + string += "\nWord 7:\t\t\thex : {}".format(self.epc[20:24]) + string += "\tint : {0}\tbin : {0:b}\n".format(w) + string += process_hr(3, w, self.hr3_int, self.hr3_second, self.hr3_bpm) + + string += "----------------------------------------------------------------------\n" + + return string + + +if __name__ == "__main__": + epc = "FFFF800D8009A17C807C0000" + if len(sys.argv) > 1: + epc = sys.argv[1] + epc = VeadistaEPC(epc) + print(epc)