Skip to content

Commit 9c75790

Browse files
committed
Add alert management for disconnected components and sensor re-evaluation
- Introduced functions to clear alerts for disconnected BMS and ESC components. - Added logic to trigger sensor re-evaluation upon reconnection of BMS or ESC. - Updated altimeter to calculate a 5-second rolling average for vertical speed. - Enhanced monitor interface with a reset state function for reconnection scenarios. - Adjusted UI elements for better alignment and visibility of alerts.
1 parent 889b2f9 commit 9c75790

File tree

8 files changed

+250
-53
lines changed

8 files changed

+250
-53
lines changed

inc/sp140/alert_display.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ void updateAlertCounterDisplay(const AlertCounts& counts);
6060
// Helper for monitors/UI logger to push alert events
6161
void sendAlertEvent(SensorID id, AlertLevel level);
6262

63+
// Function to clear alerts for disconnected components
64+
void clearDisconnectedComponentAlerts();
65+
66+
// Function to trigger sensor re-evaluation for reconnected components
67+
void triggerSensorReevaluation(bool bms, bool esc);
68+
6369
// ILogger sink that pushes events to the alert queue (for UI)
6470
struct AlertUILogger : ILogger {
6571
void log(SensorID id, AlertLevel lvl, float v) override {

inc/sp140/altimeter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include "sp140/shared-config.h"
88

99
// Constants
10-
#define VARIO_BUFFER_SIZE 10 // Number of samples to average for vertical speed
10+
#define VARIO_BUFFER_SIZE 50 // Number of samples to average for vertical speed (5 seconds at 10Hz)
1111
#define MAX_VERTICAL_SPEED 250.0f // Maximum vertical speed to display (m/s)
1212

1313
// Set up the barometer

inc/sp140/simple_monitor.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ extern MultiLogger multiLogger; // Global fan-out logger
107107
struct IMonitor {
108108
virtual ~IMonitor() = default;
109109
virtual void check() = 0;
110+
virtual void resetState() = 0; // Reset internal state for reconnection scenarios
110111
};
111112

112113
// Sensor monitor for analog values
@@ -135,6 +136,10 @@ struct SensorMonitor : public IMonitor {
135136
last = now;
136137
}
137138
}
139+
140+
void resetState() override {
141+
last = AlertLevel::OK; // Reset to force state change detection
142+
}
138143
};
139144

140145
// New monitor for boolean conditions
@@ -161,6 +166,10 @@ struct BooleanMonitor : public IMonitor {
161166
lastState = currentState;
162167
}
163168
}
169+
170+
void resetState() override {
171+
lastState = !alertOnTrue; // Reset to force state change detection
172+
}
164173
};
165174

166175
// Global monitor registry
@@ -181,4 +190,7 @@ void addAltimeterMonitors();
181190
void addInternalMonitors();
182191
void enableMonitoring();
183192

193+
// Function to reset monitor states (for reconnection scenarios)
194+
void resetMonitorStates(bool bms, bool esc);
195+
184196
#endif // INC_SP140_SIMPLE_MONITOR_H_

src/sp140/alert_display.cpp

Lines changed: 177 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <algorithm>
66
#include "../../inc/sp140/lvgl/lvgl_display.h"
77
#include "../../inc/sp140/vibration_pwm.h" // For alert vibrations
8+
#include "../../inc/sp140/globals.h" // For connection status
9+
#include "../../inc/sp140/simple_monitor.h" // For checkAllSensors()
810

911
// ------------ Globals -------------
1012
QueueHandle_t alertEventQueue = NULL;
@@ -30,6 +32,72 @@ static void alertAggregationTask(void* parameter);
3032
static void recalcCountsAndPublish();
3133
static void handleAlertVibration(const AlertCounts& newCounts, const AlertCounts& previousCounts);
3234

35+
// Helper function to check if a sensor belongs to a connected component
36+
static bool isSensorFromConnectedComponent(SensorID sensorId) {
37+
bool isConnected = false;
38+
39+
switch (sensorId) {
40+
// BMS sensors - only alert if BMS is connected
41+
case SensorID::BMS_MOS_Temp:
42+
case SensorID::BMS_Balance_Temp:
43+
case SensorID::BMS_T1_Temp:
44+
case SensorID::BMS_T2_Temp:
45+
case SensorID::BMS_T3_Temp:
46+
case SensorID::BMS_T4_Temp:
47+
case SensorID::BMS_High_Cell_Voltage:
48+
case SensorID::BMS_Low_Cell_Voltage:
49+
case SensorID::BMS_SOC:
50+
case SensorID::BMS_Total_Voltage:
51+
case SensorID::BMS_Voltage_Differential:
52+
case SensorID::BMS_Charge_MOS:
53+
case SensorID::BMS_Discharge_MOS:
54+
isConnected = (bmsTelemetryData.bmsState == TelemetryState::CONNECTED);
55+
if (!isConnected) {
56+
USBSerial.printf("[AlertDisplay] Filtering BMS alert for %s - BMS not connected\n", sensorIDToString(sensorId));
57+
}
58+
return isConnected;
59+
60+
// ESC sensors - only alert if ESC is connected
61+
case SensorID::ESC_MOS_Temp:
62+
case SensorID::ESC_MCU_Temp:
63+
case SensorID::ESC_CAP_Temp:
64+
case SensorID::Motor_Temp:
65+
case SensorID::ESC_OverCurrent_Error:
66+
case SensorID::ESC_LockedRotor_Error:
67+
case SensorID::ESC_OverTemp_Error:
68+
case SensorID::ESC_OverVolt_Error:
69+
case SensorID::ESC_VoltageDrop_Error:
70+
case SensorID::ESC_ThrottleSat_Warning:
71+
case SensorID::ESC_MotorCurrentOut_Error:
72+
case SensorID::ESC_TotalCurrentOut_Error:
73+
case SensorID::ESC_MotorVoltageOut_Error:
74+
case SensorID::ESC_CapNTC_Error:
75+
case SensorID::ESC_MosNTC_Error:
76+
case SensorID::ESC_BusVoltRange_Error:
77+
case SensorID::ESC_BusVoltSample_Error:
78+
case SensorID::ESC_MotorZLow_Error:
79+
case SensorID::ESC_MotorZHigh_Error:
80+
case SensorID::ESC_MotorVDet1_Error:
81+
case SensorID::ESC_MotorVDet2_Error:
82+
case SensorID::ESC_MotorIDet2_Error:
83+
case SensorID::ESC_SwHwIncompat_Error:
84+
case SensorID::ESC_BootloaderBad_Error:
85+
isConnected = (escTelemetryData.escState == TelemetryState::CONNECTED);
86+
if (!isConnected) {
87+
USBSerial.printf("[AlertDisplay] Filtering ESC alert for %s - ESC not connected\n", sensorIDToString(sensorId));
88+
}
89+
return isConnected;
90+
91+
// Internal sensors - always alert (no connection dependency)
92+
case SensorID::Baro_Temp:
93+
case SensorID::CPU_Temp:
94+
return true;
95+
96+
default:
97+
return true; // Default to allowing alerts for unknown sensors
98+
}
99+
}
100+
33101
// ------------ Public helpers -------------
34102
void initAlertDisplay() {
35103
// Create queues – small, non-blocking
@@ -54,6 +122,98 @@ void sendAlertEvent(SensorID id, AlertLevel level) {
54122
xQueueSend(alertEventQueue, &ev, 0); // best-effort, drop if full
55123
}
56124

125+
// Track previous connection states to detect reconnections
126+
static bool bmsWasConnected = false;
127+
static bool escWasConnected = false;
128+
129+
// Function to clear alerts for disconnected components and trigger re-evaluation on reconnection
130+
void clearDisconnectedComponentAlerts() {
131+
if (!alertEventQueue) return;
132+
133+
bool bmsCurrentlyConnected = (bmsTelemetryData.bmsState == TelemetryState::CONNECTED);
134+
bool escCurrentlyConnected = (escTelemetryData.escState == TelemetryState::CONNECTED);
135+
136+
// Check for BMS alerts to clear if BMS is disconnected
137+
if (!bmsCurrentlyConnected) {
138+
// Clear all BMS-related alerts
139+
SensorID bmsSensors[] = {
140+
SensorID::BMS_MOS_Temp, SensorID::BMS_Balance_Temp,
141+
SensorID::BMS_T1_Temp, SensorID::BMS_T2_Temp,
142+
SensorID::BMS_T3_Temp, SensorID::BMS_T4_Temp,
143+
SensorID::BMS_High_Cell_Voltage, SensorID::BMS_Low_Cell_Voltage,
144+
SensorID::BMS_SOC, SensorID::BMS_Total_Voltage,
145+
SensorID::BMS_Voltage_Differential, SensorID::BMS_Charge_MOS,
146+
SensorID::BMS_Discharge_MOS
147+
};
148+
149+
for (SensorID sensorId : bmsSensors) {
150+
AlertEvent ev{ sensorId, AlertLevel::OK, millis() };
151+
xQueueSend(alertEventQueue, &ev, 0);
152+
}
153+
154+
// Debug output
155+
USBSerial.println("[AlertDisplay] Cleared BMS alerts - BMS disconnected");
156+
}
157+
158+
// Check for ESC alerts to clear if ESC is disconnected
159+
if (!escCurrentlyConnected) {
160+
// Clear all ESC-related alerts
161+
SensorID escSensors[] = {
162+
SensorID::ESC_MOS_Temp, SensorID::ESC_MCU_Temp,
163+
SensorID::ESC_CAP_Temp, SensorID::Motor_Temp,
164+
SensorID::ESC_OverCurrent_Error, SensorID::ESC_LockedRotor_Error,
165+
SensorID::ESC_OverTemp_Error, SensorID::ESC_OverVolt_Error,
166+
SensorID::ESC_VoltageDrop_Error, SensorID::ESC_ThrottleSat_Warning,
167+
SensorID::ESC_MotorCurrentOut_Error, SensorID::ESC_TotalCurrentOut_Error,
168+
SensorID::ESC_MotorVoltageOut_Error, SensorID::ESC_CapNTC_Error,
169+
SensorID::ESC_MosNTC_Error, SensorID::ESC_BusVoltRange_Error,
170+
SensorID::ESC_BusVoltSample_Error, SensorID::ESC_MotorZLow_Error,
171+
SensorID::ESC_MotorZHigh_Error, SensorID::ESC_MotorVDet1_Error,
172+
SensorID::ESC_MotorVDet2_Error, SensorID::ESC_MotorIDet2_Error,
173+
SensorID::ESC_SwHwIncompat_Error, SensorID::ESC_BootloaderBad_Error
174+
};
175+
176+
for (SensorID sensorId : escSensors) {
177+
AlertEvent ev{ sensorId, AlertLevel::OK, millis() };
178+
xQueueSend(alertEventQueue, &ev, 0);
179+
}
180+
181+
// Debug output
182+
USBSerial.println("[AlertDisplay] Cleared ESC alerts - ESC disconnected");
183+
}
184+
185+
// Check for reconnections and trigger sensor re-evaluation
186+
if (bmsCurrentlyConnected && !bmsWasConnected) {
187+
// BMS just reconnected - trigger re-evaluation of all BMS sensors
188+
USBSerial.println("[AlertDisplay] BMS reconnected - triggering sensor re-evaluation");
189+
triggerSensorReevaluation(true, false); // BMS only
190+
}
191+
192+
if (escCurrentlyConnected && !escWasConnected) {
193+
// ESC just reconnected - trigger re-evaluation of all ESC sensors
194+
USBSerial.println("[AlertDisplay] ESC reconnected - triggering sensor re-evaluation");
195+
triggerSensorReevaluation(false, true); // ESC only
196+
}
197+
198+
// Update previous states
199+
bmsWasConnected = bmsCurrentlyConnected;
200+
escWasConnected = escCurrentlyConnected;
201+
}
202+
203+
// Function to trigger sensor re-evaluation for reconnected components
204+
void triggerSensorReevaluation(bool bms, bool esc) {
205+
if (bms || esc) {
206+
// First, reset the monitor states to force re-evaluation
207+
resetMonitorStates(bms, esc);
208+
209+
// Then trigger a full sensor check
210+
checkAllSensors();
211+
212+
USBSerial.printf("[AlertDisplay] Triggered sensor re-evaluation - BMS: %s, ESC: %s\n",
213+
bms ? "yes" : "no", esc ? "yes" : "no");
214+
}
215+
}
216+
57217
// ------------ Internal implementation -------------
58218
static void alertAggregationTask(void* parameter) {
59219
AlertEvent ev;
@@ -105,19 +265,21 @@ static void recalcCountsAndPublish() {
105265
std::vector<SensorID> critList;
106266
std::vector<SensorID> warnList;
107267
for (const auto& kv : g_currentLevels) {
108-
switch (kv.second) {
109-
case AlertLevel::WARN_LOW:
110-
case AlertLevel::WARN_HIGH:
111-
warnList.push_back(kv.first);
112-
counts.warningCount++;
113-
break;
114-
case AlertLevel::CRIT_LOW:
115-
case AlertLevel::CRIT_HIGH:
116-
critList.push_back(kv.first);
117-
counts.criticalCount++;
118-
break;
119-
default:
120-
break;
268+
if (isSensorFromConnectedComponent(kv.first)) {
269+
switch (kv.second) {
270+
case AlertLevel::WARN_LOW:
271+
case AlertLevel::WARN_HIGH:
272+
warnList.push_back(kv.first);
273+
counts.warningCount++;
274+
break;
275+
case AlertLevel::CRIT_LOW:
276+
case AlertLevel::CRIT_HIGH:
277+
critList.push_back(kv.first);
278+
counts.criticalCount++;
279+
break;
280+
default:
281+
break;
282+
}
121283
}
122284
}
123285

@@ -173,19 +335,8 @@ static void recalcCountsAndPublish() {
173335
xQueueOverwrite(alertCarouselQueue, &snap);
174336
}
175337

176-
// Rotate display queue
177-
AlertSnapshot currentDisplaySnap;
178-
if (xQueuePeek(alertDisplayQueue, &currentDisplaySnap, 0) == pdTRUE) {
179-
// If the current display snapshot is the same as the carousel snapshot,
180-
// we need to rotate it to show the next set of alerts.
181-
// This logic is simplified here; in a real system, you'd manage a queue of snapshots.
182-
// For now, we just overwrite the display queue with the current carousel snapshot.
183-
// A more robust solution would involve a separate queue for display snapshots.
184-
xQueueOverwrite(alertDisplayQueue, &snap);
185-
} else {
186-
// If the display queue is empty, just overwrite it with the current carousel snapshot.
187-
xQueueOverwrite(alertDisplayQueue, &snap);
188-
}
338+
// Note: Display queue is managed separately by the alertAggregationTask
339+
// The carousel snapshot is used for other purposes
189340
}
190341

191342
/**

src/sp140/altimeter.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,26 @@ float getVerticalSpeed() {
3434
return 0.0f; // Not enough readings yet
3535
}
3636

37-
// Get oldest and newest readings
38-
const AltitudeReading& oldest = altitudeBuffer.first();
37+
// Calculate 5-second rolling average
38+
const unsigned long currentTime = millis();
39+
const unsigned long fiveSecondsAgo = currentTime - 5000; // 5 seconds ago
40+
41+
// Find the oldest reading within the last 5 seconds
42+
int oldestIndex = -1;
43+
for (int i = 0; i < altitudeBuffer.size(); i++) {
44+
if (altitudeBuffer[i].timestamp >= fiveSecondsAgo) {
45+
oldestIndex = i;
46+
break;
47+
}
48+
}
49+
50+
// If no readings within 5 seconds, use the oldest available reading
51+
if (oldestIndex == -1) {
52+
oldestIndex = 0;
53+
}
54+
55+
// Get the readings for the 5-second window
56+
const AltitudeReading& oldest = altitudeBuffer[oldestIndex];
3957
const AltitudeReading& newest = altitudeBuffer.last();
4058

4159
// Calculate time difference in seconds

0 commit comments

Comments
 (0)