Skip to content

Commit 0238748

Browse files
committed
Refactor critical alert border and vibration handling
Moves control of the critical alert border and vibration to the UI task using a new 'criticalAlertsActive' flag in AlertUIUpdate. Adds direct control functions for the border flash, updates alert aggregation and vibration logic, and simplifies border stopping logic. This improves synchronization and ensures UI updates are handled atomically.
1 parent 084e462 commit 0238748

File tree

6 files changed

+62
-28
lines changed

6 files changed

+62
-28
lines changed

inc/sp140/alert_display.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,16 @@ extern QueueHandle_t alertCarouselQueue; // depth 1, overwrite
3131
struct AlertUIUpdate {
3232
// Counter data
3333
AlertCounts counts;
34-
34+
3535
// Display message data
3636
SensorID displayId; // Valid sensor when showDisplay == true
3737
AlertLevel displayLevel; // Alert level for dynamic abbreviations
3838
bool displayCritical; // true = critical colouring
3939
bool showDisplay; // false = hide label
40-
40+
41+
// Critical alert state (for border/vibration control)
42+
bool criticalAlertsActive; // true = show red border + vibration
43+
4144
// Synchronization
4245
uint32_t updateEpoch; // Ensures atomicity
4346
};

inc/sp140/lvgl/lvgl_updates.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,11 @@ void stopCriticalBorderFlash();
6666
*/
6767
bool isCriticalBorderFlashing();
6868

69+
/**
70+
* @brief Direct control functions for use within UI task (no mutex).
71+
* These should only be called when the LVGL mutex is already held.
72+
*/
73+
void startCriticalBorderFlashDirect();
74+
void stopCriticalBorderFlashDirect();
75+
6976
#endif // LVGL_UPDATES_H

src/sp140/alert_display.cpp

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ static void alertAggregationTask(void* parameter) {
8686
update.displayId = g_activeList[g_rotateIdx];
8787
update.displayLevel = g_currentLevels[g_activeList[g_rotateIdx]];
8888
update.displayCritical = g_showingCrit;
89+
update.criticalAlertsActive = (g_currentCounts.criticalCount > 0);
8990
update.updateEpoch = g_epoch;
9091
if (alertUIQueue) {
9192
xQueueOverwrite(alertUIQueue, &update);
@@ -99,6 +100,7 @@ static void alertAggregationTask(void* parameter) {
99100
AlertUIUpdate update;
100101
update.counts = g_currentCounts;
101102
update.showDisplay = false;
103+
update.criticalAlertsActive = (g_currentCounts.criticalCount > 0);
102104
update.updateEpoch = g_epoch;
103105
if (alertUIQueue) xQueueOverwrite(alertUIQueue, &update);
104106
hideSent = true;
@@ -154,6 +156,7 @@ static void recalcCountsAndPublish() {
154156

155157
AlertUIUpdate update;
156158
update.counts = g_currentCounts;
159+
update.criticalAlertsActive = (g_currentCounts.criticalCount > 0);
157160
update.updateEpoch = g_epoch;
158161

159162
if (g_activeList.empty()) {
@@ -165,6 +168,9 @@ static void recalcCountsAndPublish() {
165168
update.displayCritical = g_showingCrit;
166169
}
167170

171+
USBSerial.printf("[Alert] Sending UI update: crit=%d warn=%d critActive=%d\n",
172+
update.counts.criticalCount, update.counts.warningCount, update.criticalAlertsActive);
173+
168174
if (alertUIQueue) {
169175
xQueueOverwrite(alertUIQueue, &update);
170176
}
@@ -187,25 +193,16 @@ static void recalcCountsAndPublish() {
187193

188194
/**
189195
* Handle vibration alerts based on state transitions
196+
* Note: This now only handles one-shot vibration patterns.
197+
* Critical alert border/vibration is handled by UI task based on criticalAlertsActive flag.
190198
*/
191199
static void handleAlertVibration(const AlertCounts& newCounts, const AlertCounts& previousCounts) {
192-
if (newCounts.criticalCount > 0) {
193-
// Use the new synchronized alert service
194-
if (!isCriticalAlertActive()) {
195-
startCriticalAlerts();
196-
}
197-
} else {
198-
// Stop synchronized alerts if no critical alerts remain
199-
if (isCriticalAlertActive()) {
200-
stopCriticalAlerts();
201-
}
202-
203-
// Handle warning transitions (only when no critical alerts)
204-
if (previousCounts.warningCount == 0 && newCounts.warningCount > 0) {
205-
// Short delay to sync with UI
206-
vTaskDelay(pdMS_TO_TICKS(250));
207-
// Transition from 0 warnings to >0 warnings - trigger double pulse
208-
executeVibePattern(VIBE_DOUBLE_PULSE);
209-
}
200+
// Handle warning transitions (only when no critical alerts)
201+
if (newCounts.criticalCount == 0 &&
202+
previousCounts.warningCount == 0 && newCounts.warningCount > 0) {
203+
// Short delay to sync with UI
204+
vTaskDelay(pdMS_TO_TICKS(100));
205+
// Transition from 0 warnings to >0 warnings - trigger double pulse
206+
executeVibePattern(VIBE_DOUBLE_PULSE);
210207
}
211208
}

src/sp140/lvgl/lvgl_updates.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,26 @@ bool isCriticalBorderFlashing() {
225225
return isFlashingCriticalBorder;
226226
}
227227

228+
// Direct control functions for use within UI task (no mutex)
229+
void startCriticalBorderFlashDirect() {
230+
if (critical_border != NULL && !isFlashingCriticalBorder) {
231+
isFlashingCriticalBorder = true;
232+
lv_obj_clear_flag(critical_border, LV_OBJ_FLAG_HIDDEN); // Start visible
233+
critical_border_flash_timer = lv_timer_create(critical_border_flash_timer_cb, 300, NULL);
234+
}
235+
}
236+
237+
void stopCriticalBorderFlashDirect() {
238+
if (critical_border_flash_timer != NULL) {
239+
lv_timer_del(critical_border_flash_timer);
240+
critical_border_flash_timer = NULL;
241+
}
242+
if (critical_border != NULL) {
243+
lv_obj_add_flag(critical_border, LV_OBJ_FLAG_HIDDEN);
244+
}
245+
isFlashingCriticalBorder = false;
246+
}
247+
228248
// Update the climb rate indicator
229249
void updateClimbRateIndicator(float climbRate) {
230250
// Clamp climb rate to displayable range (-0.6 to +0.6 m/s)

src/sp140/sp140.ino

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,12 +452,25 @@ void refreshDisplay() {
452452
if (xQueueReceive(alertUIQueue, &alertUpdate, 0) == pdTRUE) {
453453
// Update counter and display atomically
454454
updateAlertCounterDisplay(alertUpdate.counts);
455-
455+
456456
if (alertUpdate.showDisplay) {
457457
lv_showAlertTextWithLevel(alertUpdate.displayId, alertUpdate.displayLevel, alertUpdate.displayCritical);
458458
} else {
459459
lv_hideAlertText();
460460
}
461+
462+
// Control critical border and vibration based on state
463+
static bool lastCriticalState = false;
464+
if (alertUpdate.criticalAlertsActive != lastCriticalState) {
465+
if (alertUpdate.criticalAlertsActive) {
466+
USBSerial.println("[UI] Starting critical border flash");
467+
startCriticalBorderFlashDirect(); // Direct control - we already have the mutex
468+
} else {
469+
USBSerial.println("[UI] Stopping critical border flash");
470+
stopCriticalBorderFlashDirect(); // Direct control - we already have the mutex
471+
}
472+
lastCriticalState = alertUpdate.criticalAlertsActive;
473+
}
461474
}
462475

463476
// General LVGL update handler

src/sp140/vibration_pwm.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -244,14 +244,8 @@ void stopCriticalAlerts() {
244244
}
245245
g_critical_alert_active = false;
246246

247-
// Stop the master LVGL timer - retry if mutex is busy
247+
// Stop the master LVGL timer
248248
stopCriticalBorderFlash();
249-
250-
// Verify the border actually stopped - retry up to 3 times if needed
251-
for (int retry = 0; retry < 3 && isCriticalBorderFlashing(); retry++) {
252-
vTaskDelay(pdMS_TO_TICKS(20)); // Brief delay
253-
stopCriticalBorderFlash();
254-
}
255249
}
256250

257251
/**

0 commit comments

Comments
 (0)