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".
This commit is contained in:
Piyush Shah
2022-04-06 23:14:03 +05:30
parent 5af4f64d3c
commit 1cd07a0099
3 changed files with 51 additions and 17 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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"