From 1cd07a0099628b22243fd04aaab9dc6ef9dcd594 Mon Sep 17 00:00:00 2001 From: Piyush Shah Date: Wed, 6 Apr 2022 23:14:03 +0530 Subject: [PATCH] ota: Minor improvements - Expose some internal APIs - External OTA callbacks can now call the internal function to manage OTA - Applications can explicitly send the OTA fetch publish message to check if OTA is available in case of OTA using Topics - Handle network connectivity loss using keep-alive - Send "rejected" as OTA status for project/version mismatch, instead of "failed". --- .../esp_rainmaker/include/esp_rmaker_ota.h | 25 +++++++++++++++++ .../esp_rainmaker/src/ota/esp_rmaker_ota.c | 27 +++++++++++-------- .../src/ota/esp_rmaker_ota_using_topics.c | 16 ++++++----- 3 files changed, 51 insertions(+), 17 deletions(-) diff --git a/components/esp_rainmaker/include/esp_rmaker_ota.h b/components/esp_rainmaker/include/esp_rmaker_ota.h index e66b957..6dc7962 100644 --- a/components/esp_rainmaker/include/esp_rmaker_ota.h +++ b/components/esp_rainmaker/include/esp_rmaker_ota.h @@ -34,6 +34,8 @@ typedef enum { OTA_STATUS_FAILED, /** OTA was delayed by the application */ OTA_STATUS_DELAYED, + /** OTA rejected due to some reason (wrong project, version, etc.) */ + OTA_STATUS_REJECTED, } ota_status_t; /** OTA Workflow type */ @@ -145,6 +147,29 @@ esp_err_t esp_rmaker_ota_enable(esp_rmaker_ota_config_t *ota_config, esp_rmaker_ */ esp_err_t esp_rmaker_ota_report_status(esp_rmaker_ota_handle_t ota_handle, ota_status_t status, char *additional_info); +/** Default OTA callback + * + * This is the default OTA callback which will get used if you do not pass your own callback. You can call this + * even from your callback, in case you want better control on when the OTA can proceed and yet let the actual + * OTA process be managed by the RainMaker Core. + * + * @param[in] handle An OTA handle assigned by the ESP RainMaker Core + * @param[in] ota_data The data to be used for the OTA + * + * @return ESP_OK if the OTA was successful + * @return ESP_FAIL if the OTA failed. + * */ +esp_err_t esp_rmaker_ota_default_cb(esp_rmaker_ota_handle_t handle, esp_rmaker_ota_data_t *ota_data); + +/** Fetch OTA Info + * + * For OTA using Topics, this API can be used to explicitly ask the backend if an OTA is available. + * If it is, then the OTA callback would get invoked. + * + * @return ESP_OK if the OTA fetch publish message was successful. + * @return error on failure + */ +esp_err_t esp_rmaker_ota_fetch(void); #ifdef __cplusplus } #endif diff --git a/components/esp_rainmaker/src/ota/esp_rmaker_ota.c b/components/esp_rainmaker/src/ota/esp_rmaker_ota.c index 829a625..5fab781 100644 --- a/components/esp_rainmaker/src/ota/esp_rmaker_ota.c +++ b/components/esp_rainmaker/src/ota/esp_rmaker_ota.c @@ -47,6 +47,8 @@ char *esp_rmaker_ota_status_to_string(ota_status_t status) return "failed"; case OTA_STATUS_DELAYED: return "delayed"; + case OTA_STATUS_REJECTED: + return "rejected"; default: return "invalid"; } @@ -108,27 +110,28 @@ static esp_err_t validate_image_header(esp_rmaker_ota_handle_t ota_handle, ESP_LOGD(TAG, "Running firmware version: %s", running_app_info.version); } -#ifndef CONFIG_ESP_RMAKER_SKIP_VERSION_CHECK - if (memcmp(new_app_info->version, running_app_info.version, sizeof(new_app_info->version)) == 0) { - ESP_LOGW(TAG, "Current running version is same as the new. We will not continue the update."); - esp_rmaker_ota_report_status(ota_handle, OTA_STATUS_FAILED, "Same version received"); - return ESP_FAIL; - } -#endif - #ifndef CONFIG_ESP_RMAKER_SKIP_PROJECT_NAME_CHECK if (memcmp(new_app_info->project_name, running_app_info.project_name, sizeof(new_app_info->project_name)) != 0) { ESP_LOGW(TAG, "OTA Image built for Project: %s. Expected: %s", new_app_info->project_name, running_app_info.project_name); - esp_rmaker_ota_report_status(ota_handle, OTA_STATUS_FAILED, "Project Name mismatch"); + esp_rmaker_ota_report_status(ota_handle, OTA_STATUS_REJECTED, "Project Name mismatch"); return ESP_FAIL; } #endif +#ifndef CONFIG_ESP_RMAKER_SKIP_VERSION_CHECK + if (memcmp(new_app_info->version, running_app_info.version, sizeof(new_app_info->version)) == 0) { + ESP_LOGW(TAG, "Current running version is same as the new. We will not continue the update."); + esp_rmaker_ota_report_status(ota_handle, OTA_STATUS_REJECTED, "Same version received"); + return ESP_FAIL; + } +#endif + + return ESP_OK; } -static esp_err_t esp_rmaker_ota_default_cb(esp_rmaker_ota_handle_t ota_handle, esp_rmaker_ota_data_t *ota_data) +esp_err_t esp_rmaker_ota_default_cb(esp_rmaker_ota_handle_t ota_handle, esp_rmaker_ota_data_t *ota_data) { if (!ota_data->url) { return ESP_FAIL; @@ -146,7 +149,8 @@ static esp_err_t esp_rmaker_ota_default_cb(esp_rmaker_ota_handle_t ota_handle, e .cert_pem = ota_data->server_cert, .timeout_ms = 5000, .buffer_size = DEF_HTTP_RX_BUFFER_SIZE, - .buffer_size_tx = buffer_size_tx + .buffer_size_tx = buffer_size_tx, + .keep_alive_enable = true }; #ifdef CONFIG_ESP_RMAKER_SKIP_COMMON_NAME_CHECK config.skip_cert_common_name_check = true; @@ -220,6 +224,7 @@ static esp_err_t esp_rmaker_ota_default_cb(esp_rmaker_ota_handle_t ota_handle, e } } if (err != ESP_OK) { + ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed %s", esp_err_to_name(err)); char description[40]; snprintf(description, sizeof(description), "OTA failed: Error %s", esp_err_to_name(err)); esp_rmaker_ota_report_status(ota_handle, OTA_STATUS_FAILED, description); diff --git a/components/esp_rainmaker/src/ota/esp_rmaker_ota_using_topics.c b/components/esp_rainmaker/src/ota/esp_rmaker_ota_using_topics.c index 5aa011a..10f7304 100644 --- a/components/esp_rainmaker/src/ota/esp_rmaker_ota_using_topics.c +++ b/components/esp_rainmaker/src/ota/esp_rmaker_ota_using_topics.c @@ -169,13 +169,12 @@ end: return; } -#ifdef CONFIG_ESP_RMAKER_OTA_AUTOFETCH -static void esp_rmaker_ota_fetch(void *priv) +esp_err_t esp_rmaker_ota_fetch(void) { esp_rmaker_node_info_t *info = esp_rmaker_node_get_info(esp_rmaker_get_node()); if (!info) { ESP_LOGE(TAG, "Node info not found. Cant send otafetch request"); - return; + return ESP_FAIL; } char publish_payload[150]; json_gen_str_t jstr; @@ -192,8 +191,13 @@ static void esp_rmaker_ota_fetch(void *priv) if (err != ESP_OK) { ESP_LOGE(TAG, "OTA Fetch Publish Error %d", err); } + return err; +} + +void esp_rmaker_ota_timer_cb_fetch(void *priv) +{ + esp_rmaker_ota_fetch(); } -#endif /* CONFIG_ESP_RMAKER_OTA_AUTOFETCH */ static esp_err_t esp_rmaker_ota_subscribe(void *priv_data) { @@ -215,10 +219,10 @@ static void esp_rmaker_ota_work_fn(void *priv_data) { esp_rmaker_ota_subscribe(priv_data); #ifdef CONFIG_ESP_RMAKER_OTA_AUTOFETCH - esp_rmaker_ota_fetch(priv_data); + esp_rmaker_ota_fetch(); if (ota_autofetch_period > 0) { esp_timer_create_args_t autofetch_timer_conf = { - .callback = esp_rmaker_ota_fetch, + .callback = esp_rmaker_ota_timer_cb_fetch, .arg = priv_data, .dispatch_method = ESP_TIMER_TASK, .name = "ota_autofetch_tm"