207 lines
7.5 KiB
Python
207 lines
7.5 KiB
Python
|
#!/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 <http://www.gnu.org/licenses/>.
|
||
|
'''
|
||
|
|
||
|
|
||
|
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)
|