#!/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)