37
37
#define GREEN_LED 2
38
38
#define BLUE_LED 4
39
39
40
+ // System state LED color:
41
+ // Red: System is running, has not checked in to memfault (wifi might be bad)
42
+ // Green: System is running, has checked in to memfault
43
+ // Blue: System is performing an OTA update
44
+ static int s_led_color = RED_LED ;
45
+
40
46
static const char * TAG = "example" ;
41
47
42
48
/* Console command history can be stored to and loaded from a file.
@@ -128,7 +134,7 @@ void *g_unaligned_buffer;
128
134
129
135
static bool prv_handle_ota_upload_available (void * user_ctx ) {
130
136
// set blue when performing update
131
- gpio_set_level ( BLUE_LED , 1 ) ;
137
+ s_led_color = BLUE_LED ;
132
138
133
139
MEMFAULT_LOG_INFO ("Starting OTA download ..." );
134
140
return true;
@@ -166,15 +172,15 @@ static void prv_memfault_ota(void) {
166
172
167
173
MEMFAULT_LOG_INFO ("Checking for OTA Update" );
168
174
169
- // clear ota-in-progress indicator
170
- gpio_set_level (BLUE_LED , 0 );
171
175
int rv = memfault_esp_port_ota_update (& handler );
172
176
if (rv == 0 ) {
173
177
MEMFAULT_LOG_INFO ("Up to date!" );
178
+ s_led_color = GREEN_LED ;
174
179
} else if (rv == 1 ) {
175
180
MEMFAULT_LOG_INFO ("Update available!" );
176
181
} else if (rv < 0 ) {
177
182
MEMFAULT_LOG_ERROR ("OTA update failed, rv=%d" , rv );
183
+ s_led_color = RED_LED ;
178
184
}
179
185
}
180
186
#else
@@ -213,7 +219,7 @@ static void prv_poster_task(void *args) {
213
219
int err = memfault_esp_port_http_client_post_data ();
214
220
// if the check-in succeeded, set green, otherwise clear.
215
221
// gives a quick eyeball check that the app is alive and well
216
- gpio_set_level ( GREEN_LED , err == 0 );
222
+ s_led_color = ( err == 0 ) ? GREEN_LED : RED_LED ;
217
223
218
224
memfault_metrics_heartbeat_add (MEMFAULT_METRICS_KEY (PosterTaskNumSchedules ), 1 );
219
225
memfault_esp_port_wifi_autojoin ();
@@ -298,6 +304,20 @@ static void prv_initialize_task_watchdog(void) {
298
304
}
299
305
#endif
300
306
307
+ static void prv_heartbeat_led_callback (MEMFAULT_UNUSED TimerHandle_t handle ) {
308
+ static bool s_led_state = false;
309
+ s_led_state = !s_led_state ;
310
+
311
+ const gpio_num_t leds [] = {RED_LED , GREEN_LED , BLUE_LED };
312
+ for (size_t i = 0 ; i < sizeof (leds ) / sizeof (leds [0 ]); i ++ ) {
313
+ if (leds [i ] == s_led_color ) {
314
+ gpio_set_level (s_led_color , s_led_state );
315
+ } else {
316
+ gpio_set_level (leds [i ], 0 );
317
+ }
318
+ }
319
+ }
320
+
301
321
static void led_init (void ) {
302
322
const gpio_num_t leds [] = {RED_LED , GREEN_LED , BLUE_LED };
303
323
@@ -306,6 +326,24 @@ static void led_init(void) {
306
326
gpio_set_direction (leds [i ], GPIO_MODE_OUTPUT );
307
327
gpio_set_level (leds [i ], 0 );
308
328
}
329
+
330
+ // create a timer that blinks the LED, indicating the app is alive
331
+ const char * const pcTimerName = "HeartbeatLED" ;
332
+ const TickType_t xTimerPeriodInTicks = pdMS_TO_TICKS (500 );
333
+
334
+ TimerHandle_t timer ;
335
+
336
+ #if MEMFAULT_FREERTOS_PORT_USE_STATIC_ALLOCATION != 0
337
+ static StaticTimer_t s_heartbeat_led_timer_context ;
338
+ timer = xTimerCreateStatic (pcTimerName , xTimerPeriodInTicks , pdTRUE , NULL ,
339
+ prv_heartbeat_led_callback , & s_heartbeat_led_timer_context );
340
+ #else
341
+ timer = xTimerCreate (pcTimerName , xTimerPeriodInTicks , pdTRUE , NULL , prv_heartbeat_led_callback );
342
+ #endif
343
+
344
+ MEMFAULT_ASSERT (timer != 0 );
345
+
346
+ xTimerStart (timer , 0 );
309
347
}
310
348
311
349
// This task started by cpu_start.c::start_cpu0_default().
0 commit comments