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 -------------
1012QueueHandle_t alertEventQueue = NULL ;
@@ -30,6 +32,72 @@ static void alertAggregationTask(void* parameter);
3032static void recalcCountsAndPublish ();
3133static 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 -------------
34102void 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 -------------
58218static 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, ¤tDisplaySnap, 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/* *
0 commit comments