2024-05-28 09:20:02 +00:00
|
|
|
from collections import Iterable
|
|
|
|
from decimal import *
|
|
|
|
|
|
|
|
import config as cfg
|
|
|
|
from data import LedState, BatteryStatus
|
|
|
|
|
|
|
|
# trick the pycharm type-checker into thinking Callable is in scope, not used at runtime
|
|
|
|
# noinspection PyUnreachableCode
|
|
|
|
if False:
|
|
|
|
from typing import Callable
|
|
|
|
|
|
|
|
|
|
|
|
def read_bool(register, bit):
|
|
|
|
# type: (int, int) -> Callable[[BatteryStatus], bool]
|
|
|
|
|
|
|
|
def get_value(status):
|
|
|
|
# type: (BatteryStatus) -> bool
|
|
|
|
value = status.modbus_data[register - cfg.BASE_ADDRESS]
|
|
|
|
return value & (1 << bit) > 0
|
|
|
|
|
|
|
|
return get_value
|
|
|
|
|
|
|
|
|
|
|
|
def read_float(register, scale_factor=1.0, offset=0.0, places=2):
|
|
|
|
# type: (int, float, float) -> Callable[[BatteryStatus], float]
|
|
|
|
|
|
|
|
def get_value(status):
|
|
|
|
# type: (BatteryStatus) -> float
|
|
|
|
value = status.modbus_data[register - cfg.BASE_ADDRESS]
|
|
|
|
|
|
|
|
if value >= 0x8000: # convert to signed int16
|
|
|
|
value -= 0x10000 # fiamm stores their integers signed AND with sign-offset @#%^&!
|
|
|
|
|
|
|
|
result = (value+offset)*scale_factor
|
|
|
|
return round(result,places)
|
|
|
|
|
|
|
|
return get_value
|
|
|
|
|
|
|
|
|
|
|
|
def read_hex_string(register, count):
|
|
|
|
# type: (int, int) -> Callable[[BatteryStatus], str]
|
|
|
|
"""
|
|
|
|
reads count consecutive modbus registers from start_address,
|
|
|
|
and returns a hex representation of it:
|
|
|
|
e.g. for count=4: DEAD BEEF DEAD BEEF.
|
|
|
|
"""
|
|
|
|
start = register - cfg.BASE_ADDRESS
|
|
|
|
end = start + count
|
|
|
|
|
|
|
|
def get_value(status):
|
|
|
|
# type: (BatteryStatus) -> str
|
|
|
|
return ' '.join(['{0:0>4X}'.format(x) for x in status.modbus_data[start:end]])
|
|
|
|
|
|
|
|
return get_value
|
|
|
|
|
|
|
|
|
|
|
|
def read_led_state(register, led):
|
|
|
|
# type: (int, int) -> Callable[[BatteryStatus], int]
|
|
|
|
|
|
|
|
read_lo = read_bool(register, led * 2)
|
|
|
|
read_hi = read_bool(register, led * 2 + 1)
|
|
|
|
|
|
|
|
def get_value(status):
|
|
|
|
# type: (BatteryStatus) -> int
|
|
|
|
|
|
|
|
lo = read_lo(status)
|
|
|
|
hi = read_hi(status)
|
|
|
|
|
|
|
|
if hi:
|
|
|
|
if lo:
|
|
|
|
return LedState.blinking_fast
|
|
|
|
else:
|
|
|
|
return LedState.blinking_slow
|
|
|
|
else:
|
|
|
|
if lo:
|
|
|
|
return LedState.on
|
|
|
|
else:
|
|
|
|
return LedState.off
|
|
|
|
|
|
|
|
return get_value
|
|
|
|
|
|
|
|
|
|
|
|
def read_bitmap(register):
|
|
|
|
# type: (int) -> Callable[[BatteryStatus], bitmap]
|
|
|
|
|
|
|
|
def get_value(status):
|
|
|
|
# type: (BatteryStatus) -> bitmap
|
|
|
|
value = status.modbus_data[register - cfg.BASE_ADDRESS]
|
|
|
|
return value
|
|
|
|
|
|
|
|
return get_value
|
|
|
|
|
2024-06-18 11:16:35 +00:00
|
|
|
def read_limb_string(register):
|
|
|
|
# type: (int) -> Callable[[BatteryStatus], bitmap]
|
|
|
|
|
|
|
|
def get_value(status):
|
|
|
|
# type: (BatteryStatus) -> bitmap
|
|
|
|
value = status.modbus_data[register - cfg.BASE_ADDRESS]
|
|
|
|
|
|
|
|
string1_disabled = int((value & 0b00001) != 0)
|
|
|
|
string2_disabled = int((value & 0b00010) != 0)
|
|
|
|
string3_disabled = int((value & 0b00100) != 0)
|
|
|
|
string4_disabled = int((value & 0b01000) != 0)
|
|
|
|
string5_disabled = int((value & 0b10000) != 0)
|
|
|
|
n_limb_strings = string1_disabled+string2_disabled+string3_disabled+string4_disabled+string5_disabled
|
|
|
|
if n_limb_strings>=2:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
|
|
|
|
return False
|
|
|
|
return get_value
|
2024-05-28 09:20:02 +00:00
|
|
|
|
|
|
|
def append_unit(unit):
|
|
|
|
# type: (unicode) -> Callable[[unicode], unicode]
|
|
|
|
|
|
|
|
def get_text(v):
|
|
|
|
# type: (unicode) -> unicode
|
|
|
|
return "{0}{1}".format(str(v), unit)
|
|
|
|
|
|
|
|
return get_text
|
|
|
|
|
|
|
|
|
|
|
|
def mean(numbers):
|
|
|
|
# type: (Iterable[float] | Iterable[int]) -> float
|
|
|
|
return float("{:.2f}".format(float(sum(numbers)) / len(numbers)))
|
|
|
|
|
|
|
|
def ssum(numbers):
|
|
|
|
# type: (Iterable[float] | Iterable[int]) -> float
|
|
|
|
return float("{:.2f}".format(float(sum(numbers))))
|
|
|
|
|
|
|
|
|
|
|
|
def first(ts):
|
|
|
|
return next(t for t in ts)
|
|
|
|
|
|
|
|
def return_in_list(ts):
|
|
|
|
return ts
|
|
|
|
|
|
|
|
|