14
14
15
15
#include <string.h>
16
16
#include <freertos/FreeRTOS.h>
17
+ #include <freertos/timers.h>
17
18
#include <freertos/task.h>
19
+ #include <esp_event.h>
18
20
#include <esp_log.h>
19
21
#include <esp_ota_ops.h>
20
22
#include <esp_partition.h>
21
23
#include <esp_https_ota.h>
22
24
#include <esp_wifi_types.h>
23
25
#include <esp_wifi.h>
26
+ #include <nvs.h>
24
27
#if CONFIG_BT_ENABLED
25
28
#include <esp_bt.h>
26
29
#endif /* CONFIG_BT_ENABLED */
27
30
28
31
#include <esp_rmaker_utils.h>
32
+ #include <esp_rmaker_common_events.h>
33
+
34
+ #include "esp_rmaker_internal.h"
29
35
#include "esp_rmaker_ota_internal.h"
30
36
31
37
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL (4 , 4 , 0 )
44
50
45
51
#endif /* !IDF4.4 */
46
52
static const char * TAG = "esp_rmaker_ota" ;
53
+ static TimerHandle_t s_ota_rollback_timer ;
47
54
48
55
#define OTA_REBOOT_TIMER_SEC 10
49
56
#define DEF_HTTP_TX_BUFFER_SIZE 1024
50
57
#define DEF_HTTP_RX_BUFFER_SIZE CONFIG_ESP_RMAKER_OTA_HTTP_RX_BUFFER_SIZE
51
-
58
+ #define RMAKER_OTA_ROLLBACK_WAIT_PERIOD CONFIG_ESP_RMAKER_OTA_ROLLBACK_WAIT_PERIOD
52
59
extern const char esp_rmaker_ota_def_cert [] asm("_binary_rmaker_ota_server_crt_start" );
53
60
const char * ESP_RMAKER_OTA_DEFAULT_SERVER_CERT = esp_rmaker_ota_def_cert ;
54
61
char * esp_rmaker_ota_status_to_string (ota_status_t status )
@@ -71,6 +78,8 @@ char *esp_rmaker_ota_status_to_string(ota_status_t status)
71
78
}
72
79
esp_err_t esp_rmaker_ota_report_status (esp_rmaker_ota_handle_t ota_handle , ota_status_t status , char * additional_info )
73
80
{
81
+ ESP_LOGI (TAG , "Reporting %s: %s" , esp_rmaker_ota_status_to_string (status ), additional_info );
82
+
74
83
if (!ota_handle ) {
75
84
return ESP_FAIL ;
76
85
}
@@ -267,7 +276,19 @@ esp_err_t esp_rmaker_ota_default_cb(esp_rmaker_ota_handle_t ota_handle, esp_rmak
267
276
ota_finish_err = esp_https_ota_finish (https_ota_handle );
268
277
if ((err == ESP_OK ) && (ota_finish_err == ESP_OK )) {
269
278
ESP_LOGI (TAG , "OTA upgrade successful. Rebooting in %d seconds..." , OTA_REBOOT_TIMER_SEC );
279
+ #ifdef CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
280
+ nvs_handle handle ;
281
+ esp_err_t err = nvs_open_from_partition (ESP_RMAKER_NVS_PART_NAME , RMAKER_OTA_NVS_NAMESPACE , NVS_READWRITE , & handle );
282
+ if (err == ESP_OK ) {
283
+ uint8_t ota_update = 1 ;
284
+ nvs_set_blob (handle , RMAKER_OTA_UPDATE_FLAG_NVS_NAME , & ota_update , sizeof (ota_update ));
285
+ nvs_close (handle );
286
+ }
287
+ /* Success will be reported after a reboot since Rollback is enabled */
288
+ esp_rmaker_ota_report_status (ota_handle , OTA_STATUS_IN_PROGRESS , "Rebooting into new firmware" );
289
+ #else
270
290
esp_rmaker_ota_report_status (ota_handle , OTA_STATUS_SUCCESS , "OTA Upgrade finished successfully" );
291
+ #endif
271
292
esp_rmaker_reboot (OTA_REBOOT_TIMER_SEC );
272
293
return ESP_OK ;
273
294
} else {
@@ -284,6 +305,101 @@ esp_err_t esp_rmaker_ota_default_cb(esp_rmaker_ota_handle_t ota_handle, esp_rmak
284
305
return ESP_FAIL ;
285
306
}
286
307
308
+
309
+ static void event_handler (void * arg , esp_event_base_t event_base ,
310
+ int32_t event_id , void * event_data )
311
+ {
312
+ esp_rmaker_ota_t * ota = (esp_rmaker_ota_t * )arg ;
313
+ esp_event_handler_unregister (RMAKER_COMMON_EVENT , RMAKER_MQTT_EVENT_CONNECTED , & event_handler );
314
+ esp_rmaker_ota_report_status ((esp_rmaker_ota_handle_t )ota , OTA_STATUS_SUCCESS , "OTA Upgrade finished and verified successfully" );
315
+ esp_ota_mark_app_valid_cancel_rollback ();
316
+ ota -> ota_in_progress = false;
317
+ if (s_ota_rollback_timer ) {
318
+ xTimerStop (s_ota_rollback_timer , portMAX_DELAY );
319
+ xTimerDelete (s_ota_rollback_timer , portMAX_DELAY );
320
+ s_ota_rollback_timer = NULL ;
321
+ }
322
+ if (ota -> type == OTA_USING_TOPICS ) {
323
+ esp_rmaker_ota_fetch ();
324
+ }
325
+ }
326
+
327
+ static void esp_ota_rollback (TimerHandle_t handle )
328
+ {
329
+ ESP_LOGE (TAG , "Could not verify firmware even after %d seconds since boot-up. Rolling back." ,
330
+ RMAKER_OTA_ROLLBACK_WAIT_PERIOD );
331
+ esp_ota_mark_app_invalid_rollback_and_reboot ();
332
+ }
333
+
334
+ static esp_err_t esp_ota_check_for_mqtt (esp_rmaker_ota_t * ota )
335
+ {
336
+ s_ota_rollback_timer = xTimerCreate ("ota_rollback_tm" , (RMAKER_OTA_ROLLBACK_WAIT_PERIOD * 1000 ) / portTICK_PERIOD_MS ,
337
+ pdTRUE , NULL , esp_ota_rollback );
338
+ if (s_ota_rollback_timer ) {
339
+ xTimerStart (s_ota_rollback_timer , 0 );
340
+ } else {
341
+ ESP_LOGW (TAG , "Could not create rollback timer. Will require manual reboot if firmware verification fails" );
342
+ }
343
+
344
+ return esp_event_handler_register (RMAKER_COMMON_EVENT , RMAKER_MQTT_EVENT_CONNECTED , & event_handler , ota );
345
+ }
346
+
347
+ static void esp_rmaker_ota_manage_rollback (esp_rmaker_ota_config_t * ota_config , esp_rmaker_ota_t * ota )
348
+ {
349
+ const esp_partition_t * running = esp_ota_get_running_partition ();
350
+ esp_ota_img_states_t ota_state ;
351
+ if (esp_ota_get_state_partition (running , & ota_state ) == ESP_OK ) {
352
+ ESP_LOGI (TAG , "OTA state = %d" , ota_state );
353
+ /* Not checking for CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE here because the firmware may have
354
+ * it disabled, but bootloader may have it enabled, in which case, we will have to
355
+ * handle this state.
356
+ */
357
+ if (ota_state == ESP_OTA_IMG_PENDING_VERIFY ) {
358
+ ESP_LOGI (TAG , "First Boot after an OTA" );
359
+ /* Run diagnostic function */
360
+ bool diagnostic_is_ok = true;
361
+ if (ota_config -> ota_diag ) {
362
+ diagnostic_is_ok = ota_config -> ota_diag ();
363
+ }
364
+ if (diagnostic_is_ok ) {
365
+ ESP_LOGI (TAG , "Diagnostics completed successfully! Continuing execution ..." );
366
+ /* Will not mark the image valid here immediately, but instead will wait for
367
+ * MQTT connection. The below flag will tell the OTA functions that the earlier
368
+ * OTA is still in progress.
369
+ */
370
+ ota -> ota_in_progress = true;
371
+ esp_ota_check_for_mqtt (ota );
372
+ } else {
373
+ ESP_LOGE (TAG , "Diagnostics failed! Start rollback to the previous version ..." );
374
+ esp_ota_mark_app_invalid_rollback_and_reboot ();
375
+ }
376
+ #ifdef CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
377
+ } else {
378
+ /* If rollback is enabled, and the ota update flag is found, it means that the firmware was rolled back
379
+ */
380
+ nvs_handle handle ;
381
+ esp_err_t err = nvs_open_from_partition (ESP_RMAKER_NVS_PART_NAME , RMAKER_OTA_NVS_NAMESPACE , NVS_READWRITE , & handle );
382
+ if (err == ESP_OK ) {
383
+ uint8_t ota_update = 0 ;
384
+ size_t len = sizeof (ota_update );
385
+ if ((err = nvs_get_blob (handle , RMAKER_OTA_UPDATE_FLAG_NVS_NAME , & ota_update , & len )) == ESP_OK ) {
386
+ ota -> rolled_back = true;
387
+ nvs_erase_key (handle , RMAKER_OTA_UPDATE_FLAG_NVS_NAME );
388
+ if (ota -> type == OTA_USING_PARAMS ) {
389
+ /* Calling this only for OTA_USING_PARAMS, because for OTA_USING_TOPICS,
390
+ * the work queue function will manage the status reporting later.
391
+ */
392
+ esp_rmaker_ota_report_status ((esp_rmaker_ota_handle_t )ota ,
393
+ OTA_STATUS_REJECTED , "Firmware rolled back" );
394
+ }
395
+ }
396
+ nvs_close (handle );
397
+ }
398
+ #endif
399
+ }
400
+ }
401
+ }
402
+
287
403
static const esp_rmaker_ota_config_t ota_default_config = {
288
404
.server_cert = esp_rmaker_ota_def_cert ,
289
405
};
@@ -307,26 +423,6 @@ esp_err_t esp_rmaker_ota_enable(esp_rmaker_ota_config_t *ota_config, esp_rmaker_
307
423
ESP_LOGE (TAG , "Failed to allocate memory for esp_rmaker_ota_t" );
308
424
return ESP_ERR_NO_MEM ;
309
425
}
310
- const esp_partition_t * running = esp_ota_get_running_partition ();
311
- esp_ota_img_states_t ota_state ;
312
- if (esp_ota_get_state_partition (running , & ota_state ) == ESP_OK ) {
313
- ESP_LOGI (TAG , "OTA state = %d" , ota_state );
314
- if (ota_state == ESP_OTA_IMG_PENDING_VERIFY ) {
315
- ESP_LOGI (TAG , "First Boot after an OTA" );
316
- /* Run diagnostic function */
317
- bool diagnostic_is_ok = true;
318
- if (ota_config -> ota_diag ) {
319
- diagnostic_is_ok = ota_config -> ota_diag ();
320
- }
321
- if (diagnostic_is_ok ) {
322
- ESP_LOGI (TAG , "Diagnostics completed successfully! Continuing execution ..." );
323
- esp_ota_mark_app_valid_cancel_rollback ();
324
- } else {
325
- ESP_LOGE (TAG , "Diagnostics failed! Start rollback to the previous version ..." );
326
- esp_ota_mark_app_invalid_rollback_and_reboot ();
327
- }
328
- }
329
- }
330
426
if (ota_config -> ota_cb ) {
331
427
ota -> ota_cb = ota_config -> ota_cb ;
332
428
} else {
@@ -342,6 +438,7 @@ esp_err_t esp_rmaker_ota_enable(esp_rmaker_ota_config_t *ota_config, esp_rmaker_
342
438
err = esp_rmaker_ota_enable_using_topics (ota );
343
439
}
344
440
if (err == ESP_OK ) {
441
+ esp_rmaker_ota_manage_rollback (ota_config , ota );
345
442
ota_init_done = true;
346
443
} else {
347
444
free (ota );
0 commit comments