Skip to content

Commit c3eed89

Browse files
committed
sync critical alert handling and vibration logic
Unified critical alert notifications by synchronizing border flashing and vibration through a single service. Removed legacy continuous vibration task and related code, replacing it with a timer-driven approach for both border and vibration pulses. Updated API in vibration_pwm and lvgl_updates to reflect new service, improving maintainability and synchronization of critical alert feedback.
1 parent 8704e99 commit c3eed89

File tree

5 files changed

+143
-107
lines changed

5 files changed

+143
-107
lines changed

inc/sp140/lvgl/lvgl_updates.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,26 @@ void updateLvglMainScreenWithTestData(const STR_DEVICE_DATA_140_V1& deviceData);
4444
// Flash animation functions
4545
void startCruiseIconFlash();
4646
void startArmFailIconFlash();
47+
48+
/**
49+
* @brief Starts the flashing of the critical alert border.
50+
*
51+
* This function should be called from a task that has acquired the LVGL mutex.
52+
*/
4753
void startCriticalBorderFlash();
54+
55+
/**
56+
* @brief Stops the flashing of the critical alert border.
57+
*
58+
* This function should be called from a task that has acquired the LVGL mutex.
59+
*/
4860
void stopCriticalBorderFlash();
61+
62+
/**
63+
* @brief Checks if the critical alert border is currently flashing.
64+
*
65+
* @return true if the border is flashing, false otherwise.
66+
*/
4967
bool isCriticalBorderFlashing();
5068

5169
#endif // LVGL_UPDATES_H

inc/sp140/vibration_pwm.h

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ enum VibePattern {
1111
VIBE_TRIPLE_PULSE,
1212
VIBE_RAMP_UP,
1313
VIBE_RAMP_DOWN,
14-
VIBE_WAVE,
15-
VIBE_CRITICAL_CONTINUOUS // New pattern for critical alerts
14+
VIBE_WAVE
1615
};
1716

1817
// Vibration request structure for queue
@@ -59,18 +58,51 @@ void executeVibePattern(VibePattern pattern);
5958
void customVibePattern(const uint8_t intensities[], const uint16_t durations[], int steps);
6059

6160
/**
62-
* Start continuous vibration for critical alerts
61+
* @brief Pulses the vibration motor for a specific duration and intensity.
62+
*
63+
* This is a non-blocking function that sends a request to the vibe queue.
64+
*
65+
* @param duration_ms The duration of the pulse in milliseconds.
66+
* @param intensity The vibration intensity (0-255).
6367
*/
64-
void startCriticalVibration();
68+
void pulseVibration(uint16_t duration_ms, uint8_t intensity);
6569

6670
/**
67-
* Stop continuous vibration
71+
* @brief Stops all vibration immediately.
72+
*
73+
* This function clears the vibration queue and turns off the PWM signal.
6874
*/
69-
void stopCriticalVibration();
75+
void stopVibration();
7076

7177
/**
72-
* Check if critical vibration is currently active
78+
* @brief Initializes the critical alert service.
79+
*
80+
* This function sets up the necessary resources for handling synchronized critical alerts.
81+
* It should be called once during system initialization.
7382
*/
74-
bool isCriticalVibrationActive();
83+
void initCriticalAlertService();
84+
85+
/**
86+
* @brief Starts the critical alert notifications.
87+
*
88+
* Activates the synchronized vibration and border flashing. If alerts are
89+
* already running, this function has no effect.
90+
*/
91+
void startCriticalAlerts();
92+
93+
/**
94+
* @brief Stops the critical alert notifications.
95+
*
96+
* Deactivates the vibration and border flashing. If alerts are not currently
97+
* running, this function has no effect.
98+
*/
99+
void stopCriticalAlerts();
100+
101+
/**
102+
* @brief Checks if the critical alert system is currently active.
103+
*
104+
* @return true if critical alerts are active, false otherwise.
105+
*/
106+
bool isCriticalAlertActive();
75107

76108
#endif // INC_SP140_VIBRATION_PWM_H_

src/sp140/alert_display.cpp

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#include <algorithm>
66
#include "../../inc/sp140/lvgl/lvgl_alerts.h"
77
#include "../../inc/sp140/lvgl/lvgl_updates.h"
8-
#include "../../inc/sp140/vibration_pwm.h" // For alert vibrations
8+
#include "../../inc/sp140/vibration_pwm.h"
99

1010
// ------------ Globals -------------
1111
QueueHandle_t alertEventQueue = NULL;
@@ -44,6 +44,9 @@ void initAlertDisplay() {
4444
return;
4545
}
4646

47+
// Init the new alert service
48+
initCriticalAlertService();
49+
4750
// Create aggregation task (low priority)
4851
xTaskCreate(alertAggregationTask, "AlertAgg", 3072, NULL, 1, &alertAggregationTaskHandle);
4952
USBSerial.println("[AlertDisplay] Init complete");
@@ -194,24 +197,14 @@ static void recalcCountsAndPublish() {
194197
*/
195198
static void handleAlertVibration(const AlertCounts& newCounts, const AlertCounts& previousCounts) {
196199
if (newCounts.criticalCount > 0) {
197-
// Start continuous vibration for critical alerts (if not already active)
198-
if (!isCriticalVibrationActive()) {
199-
startCriticalVibration();
200-
}
201-
202-
// Start critical border flashing (if not already active)
203-
if (!isCriticalBorderFlashing()) {
204-
startCriticalBorderFlash();
200+
// Use the new synchronized alert service
201+
if (!isCriticalAlertActive()) {
202+
startCriticalAlerts();
205203
}
206204
} else {
207-
// Stop critical vibration if no critical alerts remain
208-
if (isCriticalVibrationActive()) {
209-
stopCriticalVibration();
210-
}
211-
212-
// Stop critical border flashing if no critical alerts remain
213-
if (isCriticalBorderFlashing()) {
214-
stopCriticalBorderFlash();
205+
// Stop synchronized alerts if no critical alerts remain
206+
if (isCriticalAlertActive()) {
207+
stopCriticalAlerts();
215208
}
216209

217210
// Handle warning transitions (only when no critical alerts)

src/sp140/lvgl/lvgl_updates.cpp

Lines changed: 23 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "../../../inc/sp140/lvgl/lvgl_updates.h"
22
#include "../../../inc/sp140/esp32s3-config.h"
33
#include "../../../inc/sp140/globals.h"
4+
#include "../../../inc/sp140/vibration_pwm.h"
5+
#include "../../../inc/sp140/shared-config.h"
46

57
// Flash timer globals - definitions
68
lv_timer_t* cruise_flash_timer = NULL;
@@ -175,79 +177,47 @@ void startArmFailIconFlash() {
175177

176178
// --- Critical Alert Border Flashing Implementation ---
177179
static void critical_border_flash_timer_cb(lv_timer_t* timer) {
178-
// This callback runs within the LVGL task handler, which is already protected by lvglMutex
180+
// This callback runs within the LVGL task handler, so no mutex needed here.
181+
if (critical_border != NULL) {
182+
// Toggle visibility: 300ms on, 700ms off
183+
bool is_on = !lv_obj_has_flag(critical_border, LV_OBJ_FLAG_HIDDEN);
184+
if (is_on) {
185+
lv_obj_add_flag(critical_border, LV_OBJ_FLAG_HIDDEN);
186+
lv_timer_set_period(timer, 700); // Off duration
187+
} else {
188+
lv_obj_clear_flag(critical_border, LV_OBJ_FLAG_HIDDEN);
189+
lv_timer_set_period(timer, 300); // On duration
179190

180-
if (critical_border == NULL) {
181-
// Safety check
182-
if (critical_border_flash_timer != NULL) {
183-
lv_timer_del(critical_border_flash_timer);
184-
critical_border_flash_timer = NULL;
191+
// Trigger vibration pulse in sync with border "on"
192+
if (ENABLE_VIBE) {
193+
pulseVibration(300, 200); // 300ms pulse, intensity 200
194+
}
185195
}
186-
isFlashingCriticalBorder = false;
187-
return;
188-
}
189-
190-
// Toggle visibility
191-
if (lv_obj_has_flag(critical_border, LV_OBJ_FLAG_HIDDEN)) {
192-
lv_obj_clear_flag(critical_border, LV_OBJ_FLAG_HIDDEN);
193-
} else {
194-
lv_obj_add_flag(critical_border, LV_OBJ_FLAG_HIDDEN);
195196
}
196197
}
197198

198199
void startCriticalBorderFlash() {
199-
// This function can be called from other tasks, so protect with mutex
200-
if (xSemaphoreTake(lvglMutex, pdMS_TO_TICKS(50)) == pdTRUE) { // Use a timeout
201-
if (critical_border == NULL) {
202-
xSemaphoreGive(lvglMutex);
203-
return; // Can't flash if border doesn't exist
200+
if (xSemaphoreTake(lvglMutex, pdMS_TO_TICKS(50)) == pdTRUE) {
201+
if (critical_border != NULL && !isFlashingCriticalBorder) {
202+
isFlashingCriticalBorder = true;
203+
lv_obj_clear_flag(critical_border, LV_OBJ_FLAG_HIDDEN); // Start visible
204+
critical_border_flash_timer = lv_timer_create(critical_border_flash_timer_cb, 300, NULL);
204205
}
205-
206-
// If a flash timer is already running, delete it first
207-
if (critical_border_flash_timer != NULL) {
208-
lv_timer_del(critical_border_flash_timer);
209-
critical_border_flash_timer = NULL;
210-
}
211-
212-
// Reset state and start flashing
213-
isFlashingCriticalBorder = true;
214-
215-
// Start with the border visible
216-
lv_obj_clear_flag(critical_border, LV_OBJ_FLAG_HIDDEN);
217-
218-
// Create the timer (500ms interval for on/off cycle - matches vibration rate)
219-
critical_border_flash_timer = lv_timer_create(critical_border_flash_timer_cb, 500, NULL);
220-
if (critical_border_flash_timer == NULL) {
221-
// Failed to create timer, reset state
222-
isFlashingCriticalBorder = false;
223-
lv_obj_add_flag(critical_border, LV_OBJ_FLAG_HIDDEN); // Hide it again
224-
USBSerial.println("Error: Failed to create critical border flash timer!");
225-
}
226-
227206
xSemaphoreGive(lvglMutex);
228-
} else {
229-
USBSerial.println("Warning: Failed to acquire LVGL mutex for startCriticalBorderFlash");
230207
}
231208
}
232209

233210
void stopCriticalBorderFlash() {
234-
// This function can be called from other tasks, so protect with mutex
235-
if (xSemaphoreTake(lvglMutex, pdMS_TO_TICKS(50)) == pdTRUE) { // Use a timeout
211+
if (xSemaphoreTake(lvglMutex, pdMS_TO_TICKS(50)) == pdTRUE) {
236212
if (critical_border_flash_timer != NULL) {
237213
lv_timer_del(critical_border_flash_timer);
238214
critical_border_flash_timer = NULL;
239215
}
240-
241-
isFlashingCriticalBorder = false;
242-
243-
// Hide the border
244216
if (critical_border != NULL) {
245217
lv_obj_add_flag(critical_border, LV_OBJ_FLAG_HIDDEN);
246218
}
247-
219+
isFlashingCriticalBorder = false;
248220
xSemaphoreGive(lvglMutex);
249-
} else {
250-
USBSerial.println("Warning: Failed to acquire LVGL mutex for stopCriticalBorderFlash");
251221
}
252222
}
253223

src/sp140/vibration_pwm.cpp

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "sp140/vibration_pwm.h"
22
#include "Arduino.h"
33
#include "sp140/shared-config.h"
4+
#include "sp140/lvgl/lvgl_updates.h"
45

56
const int VIBE_PWM_PIN = 46; // TODO: move to config
67
const int VIBE_PWM_FREQ = 1000; // Adjust as needed
@@ -75,12 +76,6 @@ bool initVibeMotor() {
7576
return false;
7677
}
7778

78-
// Create critical vibration task - also pin to core 1, lower priority
79-
xTaskCreatePinnedToCore(criticalVibeTask, "CriticalVibe", 2048, NULL, 1, &criticalVibeTaskHandle, 1);
80-
if (criticalVibeTaskHandle == NULL) {
81-
return false;
82-
}
83-
8479
return true;
8580
}
8681

@@ -99,6 +94,29 @@ void pulseVibeMotor() {
9994
xQueueSend(vibeQueue, &request, 0); // Don't wait if queue is full
10095
}
10196

97+
/**
98+
* @brief Pulses the vibration motor for a specific duration and intensity.
99+
*/
100+
void pulseVibration(uint16_t duration_ms, uint8_t intensity) {
101+
if (!ENABLE_VIBE || vibeQueue == NULL) return;
102+
103+
VibeRequest request = {
104+
.duration_ms = duration_ms,
105+
.intensity = intensity
106+
};
107+
xQueueSend(vibeQueue, &request, 0);
108+
}
109+
110+
/**
111+
* @brief Stops all vibration immediately.
112+
*/
113+
void stopVibration() {
114+
if (vibeQueue != NULL) {
115+
xQueueReset(vibeQueue);
116+
}
117+
ledcWrite(VIBE_PWM_CHANNEL, 0);
118+
}
119+
102120
/**
103121
* Run a custom vibration pattern using an array of intensities
104122
* @param pattern Array of intensity values (0-255)
@@ -177,11 +195,6 @@ void executeVibePattern(VibePattern pattern) {
177195
}
178196
ledcWrite(VIBE_PWM_CHANNEL, 0);
179197
break;
180-
181-
case VIBE_CRITICAL_CONTINUOUS:
182-
// This pattern is handled by the continuous vibration task
183-
startCriticalVibration();
184-
break;
185198
}
186199
}
187200

@@ -201,35 +214,45 @@ void customVibePattern(const uint8_t intensities[], const uint16_t durations[],
201214
ledcWrite(VIBE_PWM_CHANNEL, 0);
202215
}
203216

217+
// Service state for critical alerts
218+
static bool g_critical_alert_active = false;
219+
204220
/**
205-
* Start continuous vibration for critical alerts
221+
* @brief Initializes the critical alert service.
206222
*/
207-
void startCriticalVibration() {
208-
if (!ENABLE_VIBE) return;
223+
void initCriticalAlertService() {
224+
// Initialization can be expanded if needed in the future.
225+
}
209226

210-
if (!criticalVibrationActive) {
211-
criticalVibrationActive = true;
212-
if (criticalVibeTaskHandle != NULL) {
213-
vTaskResume(criticalVibeTaskHandle);
214-
}
227+
/**
228+
* @brief Starts the critical alert notifications.
229+
*/
230+
void startCriticalAlerts() {
231+
if (g_critical_alert_active) {
232+
return;
215233
}
234+
g_critical_alert_active = true;
235+
236+
// Start the single master LVGL timer, which will handle both border and vibration
237+
startCriticalBorderFlash();
216238
}
217239

218240
/**
219-
* Stop continuous vibration
241+
* @brief Stops the critical alert notifications.
220242
*/
221-
void stopCriticalVibration() {
222-
if (criticalVibrationActive) {
223-
criticalVibrationActive = false;
224-
// Turn off vibration immediately
225-
ledcWrite(VIBE_PWM_CHANNEL, 0);
226-
// Task will suspend itself on next iteration
243+
void stopCriticalAlerts() {
244+
if (!g_critical_alert_active) {
245+
return;
227246
}
247+
g_critical_alert_active = false;
248+
249+
// Stop the master LVGL timer
250+
stopCriticalBorderFlash();
228251
}
229252

230253
/**
231-
* Check if critical vibration is currently active
254+
* @brief Checks if the critical alert system is currently active.
232255
*/
233-
bool isCriticalVibrationActive() {
234-
return criticalVibrationActive;
256+
bool isCriticalAlertActive() {
257+
return g_critical_alert_active;
235258
}

0 commit comments

Comments
 (0)