3737#define GREEN_LED 2
3838#define BLUE_LED 4
3939
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+
4046static const char * TAG = "example" ;
4147
4248/* Console command history can be stored to and loaded from a file.
@@ -128,7 +134,7 @@ void *g_unaligned_buffer;
128134
129135static bool prv_handle_ota_upload_available (void * user_ctx ) {
130136 // set blue when performing update
131- gpio_set_level ( BLUE_LED , 1 ) ;
137+ s_led_color = BLUE_LED ;
132138
133139 MEMFAULT_LOG_INFO ("Starting OTA download ..." );
134140 return true;
@@ -166,15 +172,15 @@ static void prv_memfault_ota(void) {
166172
167173 MEMFAULT_LOG_INFO ("Checking for OTA Update" );
168174
169- // clear ota-in-progress indicator
170- gpio_set_level (BLUE_LED , 0 );
171175 int rv = memfault_esp_port_ota_update (& handler );
172176 if (rv == 0 ) {
173177 MEMFAULT_LOG_INFO ("Up to date!" );
178+ s_led_color = GREEN_LED ;
174179 } else if (rv == 1 ) {
175180 MEMFAULT_LOG_INFO ("Update available!" );
176181 } else if (rv < 0 ) {
177182 MEMFAULT_LOG_ERROR ("OTA update failed, rv=%d" , rv );
183+ s_led_color = RED_LED ;
178184 }
179185}
180186#else
@@ -213,7 +219,7 @@ static void prv_poster_task(void *args) {
213219 int err = memfault_esp_port_http_client_post_data ();
214220 // if the check-in succeeded, set green, otherwise clear.
215221 // 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 ;
217223
218224 memfault_metrics_heartbeat_add (MEMFAULT_METRICS_KEY (PosterTaskNumSchedules ), 1 );
219225 memfault_esp_port_wifi_autojoin ();
@@ -298,6 +304,20 @@ static void prv_initialize_task_watchdog(void) {
298304}
299305#endif
300306
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+
301321static void led_init (void ) {
302322 const gpio_num_t leds [] = {RED_LED , GREEN_LED , BLUE_LED };
303323
@@ -306,6 +326,24 @@ static void led_init(void) {
306326 gpio_set_direction (leds [i ], GPIO_MODE_OUTPUT );
307327 gpio_set_level (leds [i ], 0 );
308328 }
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 );
309347}
310348
311349// This task started by cpu_start.c::start_cpu0_default().
0 commit comments