From f558f44907f65c2f0f418d3553ea929c86510eb9 Mon Sep 17 00:00:00 2001
From: "Jasper v. Blanckenburg" <j.blanckenburg@fasttube.de>
Date: Thu, 26 Jan 2023 16:52:58 +0100
Subject: [PATCH] Check timeouts

---
 load_controller/bms.py          | 30 ++++++++++++++++++++++++++----
 load_controller/temperatures.py |  7 ++++++-
 ui/main_window.qml              |  1 -
 3 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/load_controller/bms.py b/load_controller/bms.py
index 211105c..a5c5a60 100644
--- a/load_controller/bms.py
+++ b/load_controller/bms.py
@@ -21,6 +21,8 @@ THRESH_UV = 2.5
 THRESH_OV = 4.2
 THRESH_UT = 1
 THRESH_OT = 60
+THRESH_VOLTAGE_TIMEOUT = 1
+THRESH_TEMP_TIMEOUT = 1
 
 
 class BMSError(Enum):
@@ -29,6 +31,8 @@ class BMSError(Enum):
     OV = 2
     UT = 3
     OT = 4
+    TIMEOUT_V = 5
+    TIMEOUT_T = 6
 
     def __str__(self):
         if self == self.NONE:
@@ -41,6 +45,10 @@ class BMSError(Enum):
             return "Undertemperature"
         elif self == self.OT:
             return "Overtemperature"
+        elif self == self.TIMEOUT_V:
+            return "Timeout (voltages)"
+        elif self == self.TIMEOUT_T:
+            return "Timeout (temps)"
         else:
             return "Unknown error"
 
@@ -59,6 +67,8 @@ class BMS(QObject):
     _load: Load
     _num_cells: int
     _num_sensors: int
+    _last_voltage_time: float
+    _last_temp_time: float
 
     def __init__(self, load: Load, num_cells: int, num_sensors: int):
         super().__init__(None)
@@ -83,6 +93,11 @@ class BMS(QObject):
             if t < THRESH_UT:
                 error = BMSError.UT
                 break
+        now = time.time()
+        if now - self._last_voltage_time > THRESH_VOLTAGE_TIMEOUT:
+            error = BMSError.TIMEOUT_V
+        if now - self._last_temp_time > THRESH_TEMP_TIMEOUT:
+            error = BMSError.TIMEOUT_T
 
         if error != self._data.error:
             print(f"Error changed: {error}")
@@ -103,6 +118,8 @@ class BMSEvalBoard(BMS):
         self._dev = ModbusSerialClient(
             method="rtu", port=uart_path, baudrate=MODBUS_BAUDRATE
         )
+        self._last_voltage_time = time.time()
+        self._last_temp_time = time.time()
         temperaturesUpdated.connect(
             self._updateTemperatures, Qt.ConnectionType.DirectConnection
         )
@@ -113,15 +130,20 @@ class BMSEvalBoard(BMS):
             result = self._dev.read_holding_registers(
                 VOLTAGE_ADDRESS, NUM_CELLS, SLAVE_UNIT_ID
             )
-            self._data.voltages = list(
-                map(lambda v: v * VOLTAGE_QUANT, result.registers)
-            )
+            if result.isError():
+                print(f"ERROR READING VOLTAGES: {result}")
+            else:
+                self._data.voltages = list(
+                    map(lambda v: v * VOLTAGE_QUANT, result.registers)
+                )
+                self._last_voltage_time = time.time()
+                self.dataUpdated.emit(self._data)
             self._check_for_errors()
-            self.dataUpdated.emit(self._data)
 
     @Slot(list)
     def _updateTemperatures(self, temps: list[float]):
         assert len(temps) == N_SENSORS
         self._data.temperatures = temps
+        self._last_temp_time = time.time()
         self._check_for_errors()
         self.dataUpdated.emit(self._data)
diff --git a/load_controller/temperatures.py b/load_controller/temperatures.py
index a693344..ea4dab2 100644
--- a/load_controller/temperatures.py
+++ b/load_controller/temperatures.py
@@ -26,12 +26,17 @@ class Temperatures(QObject):
             self.dev.read_until(START_OF_TEMPS)
             data = self.dev.read(N_SENSORS * 2)
             temps = struct.unpack(f">{N_SENSORS}h", data)
+            err = False
             for i, t in enumerate(temps):
                 if (t & 0x0F) != 0:
                     print(
                         f"WARN: temperature had a non-zero least-significant nibble: {t:04x}",
                         file=sys.stderr,
                     )
+                    err = True
                 else:
                     self._temps[i] = (t >> 4) * TEMP_QUANT
-            self.temperaturesUpdated.emit(self._temps)
+            # Only emit the signal if there's no error, so we cause a timeout if
+            # there were errors.
+            if not err:
+                self.temperaturesUpdated.emit(self._temps)
diff --git a/ui/main_window.qml b/ui/main_window.qml
index 16bdc29..a10e1d1 100644
--- a/ui/main_window.qml
+++ b/ui/main_window.qml
@@ -47,7 +47,6 @@ ApplicationWindow {
     }
 
     onBmsErrorChanged: {
-        console.log(bmsError);
         bmsErrorVisible = bmsError != "";
     }