#include "ota_confirm.h" #include "esp_log.h" #include "esp_ota_ops.h" #include "esp_partition.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" static const char *TAG = "[OTA_CONFIRM]"; /** Long enough for early crash loops (e.g. assert in a worker task) to reboot * before we cancel rollback; short enough that a follow-up OTA is not blocked * for long (esp_ota_begin fails while PENDING_VERIFY). */ #define OTA_CONFIRM_DELAY_MS 8000u static void ota_confirm_task(void *param) { (void)param; vTaskDelay(pdMS_TO_TICKS(OTA_CONFIRM_DELAY_MS)); const esp_partition_t *running = esp_ota_get_running_partition(); if (running == NULL) { ESP_LOGW(TAG, "no running partition"); vTaskDelete(NULL); return; } esp_ota_img_states_t state = ESP_OTA_IMG_UNDEFINED; esp_err_t err = esp_ota_get_state_partition(running, &state); if (err != ESP_OK) { /* otadata missing / non-OTA slot — nothing to confirm. */ ESP_LOGI(TAG, "ota state unavailable (%s) — skip confirm", esp_err_to_name(err)); vTaskDelete(NULL); return; } if (state != ESP_OTA_IMG_PENDING_VERIFY) { ESP_LOGI(TAG, "running %s state=%d — no pending verify", running->label, (int)state); vTaskDelete(NULL); return; } err = esp_ota_mark_app_valid_cancel_rollback(); if (err != ESP_OK) { ESP_LOGE(TAG, "mark_app_valid failed: %s", esp_err_to_name(err)); } else { ESP_LOGI(TAG, "app confirmed valid (%s) — rollback cancelled", running->label); } vTaskDelete(NULL); } void ota_confirm_schedule(void) { if (xTaskCreate(ota_confirm_task, "ota_confirm", 3072, NULL, 3, NULL) != pdPASS) { ESP_LOGE(TAG, "failed to create confirm task — attempting immediate mark"); (void)esp_ota_mark_app_valid_cancel_rollback(); } }