Implemented abort for async ota update
This commit is contained in:
@ -21,13 +21,14 @@ using namespace std::chrono_literals;
|
|||||||
namespace {
|
namespace {
|
||||||
constexpr const char * const TAG = "ASYNC_OTA";
|
constexpr const char * const TAG = "ASYNC_OTA";
|
||||||
|
|
||||||
constexpr int TASK_RUNNING = BIT0;
|
constexpr int TASK_RUNNING_BIT = BIT0;
|
||||||
constexpr int START_REQUEST_BIT = BIT1;
|
constexpr int START_REQUEST_BIT = BIT1;
|
||||||
constexpr int REQUEST_RUNNING_BIT = BIT2;
|
constexpr int REQUEST_RUNNING_BIT = BIT2;
|
||||||
constexpr int REQUEST_FINISHED_BIT = BIT3;
|
constexpr int REQUEST_FINISHED_BIT = BIT3;
|
||||||
constexpr int REQUEST_SUCCEEDED_BIT = BIT4;
|
constexpr int REQUEST_SUCCEEDED_BIT = BIT4;
|
||||||
constexpr int END_TASK_BIT = BIT5;
|
constexpr int END_TASK_BIT = BIT5;
|
||||||
constexpr int TASK_ENDED = BIT6;
|
constexpr int TASK_ENDED_BIT = BIT6;
|
||||||
|
constexpr int ABORT_REQUEST_BIT = BIT7;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
EspAsyncOta::EspAsyncOta(const char *taskName, uint32_t stackSize, espcpputils::CoreAffinity coreAffinity) :
|
EspAsyncOta::EspAsyncOta(const char *taskName, uint32_t stackSize, espcpputils::CoreAffinity coreAffinity) :
|
||||||
@ -45,42 +46,48 @@ EspAsyncOta::~EspAsyncOta()
|
|||||||
|
|
||||||
tl::expected<void, std::string> EspAsyncOta::startTask()
|
tl::expected<void, std::string> EspAsyncOta::startTask()
|
||||||
{
|
{
|
||||||
if (const auto bits = m_eventGroup.getBits();
|
if (m_taskHandle)
|
||||||
bits & TASK_RUNNING || m_taskHandle)
|
|
||||||
{
|
{
|
||||||
constexpr auto msg = "task already started";
|
constexpr auto msg = "ota task handle is not null";
|
||||||
ESP_LOGW(TAG, "%s", msg);
|
ESP_LOGW(TAG, "%s", msg);
|
||||||
return tl::make_unexpected(msg);
|
return tl::make_unexpected(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_eventGroup.clearBits(TASK_RUNNING | START_REQUEST_BIT | REQUEST_RUNNING_BIT | REQUEST_FINISHED_BIT | REQUEST_SUCCEEDED_BIT | END_TASK_BIT | TASK_ENDED);
|
if (const auto bits = m_eventGroup.getBits(); bits & TASK_RUNNING_BIT)
|
||||||
|
{
|
||||||
|
constexpr auto msg = "ota task already running";
|
||||||
|
ESP_LOGW(TAG, "%s", msg);
|
||||||
|
return tl::make_unexpected(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_eventGroup.clearBits(TASK_RUNNING_BIT | START_REQUEST_BIT | REQUEST_RUNNING_BIT | REQUEST_FINISHED_BIT | REQUEST_SUCCEEDED_BIT | END_TASK_BIT | TASK_ENDED_BIT | ABORT_REQUEST_BIT);
|
||||||
|
|
||||||
const auto result = espcpputils::createTask(otaTask, m_taskName, m_stackSize, this, 10, &m_taskHandle, m_coreAffinity);
|
const auto result = espcpputils::createTask(otaTask, m_taskName, m_stackSize, this, 10, &m_taskHandle, m_coreAffinity);
|
||||||
if (result != pdPASS)
|
if (result != pdPASS)
|
||||||
{
|
{
|
||||||
auto msg = fmt::format("failed creating http task {}", result);
|
auto msg = fmt::format("failed creating ota task {}", result);
|
||||||
ESP_LOGE(TAG, "%.*s", msg.size(), msg.data());
|
ESP_LOGE(TAG, "%.*s", msg.size(), msg.data());
|
||||||
return tl::make_unexpected(std::move(msg));
|
return tl::make_unexpected(std::move(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_taskHandle)
|
if (!m_taskHandle)
|
||||||
{
|
{
|
||||||
constexpr auto msg = "http task handle is null";
|
constexpr auto msg = "ota task handle is null";
|
||||||
ESP_LOGW(TAG, "%s", msg);
|
ESP_LOGW(TAG, "%s", msg);
|
||||||
return tl::make_unexpected(msg);
|
return tl::make_unexpected(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, "created http task %s", m_taskName);
|
ESP_LOGD(TAG, "created ota task %s", m_taskName);
|
||||||
|
|
||||||
if (const auto bits = m_eventGroup.waitBits(TASK_RUNNING, false, false, std::chrono::ceil<espcpputils::ticks>(1s).count());
|
if (const auto bits = m_eventGroup.waitBits(TASK_RUNNING_BIT, false, false, std::chrono::ceil<espcpputils::ticks>(1s).count());
|
||||||
bits & TASK_RUNNING)
|
bits & TASK_RUNNING_BIT)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
ESP_LOGW(TAG, "http task %s TASK_RUNNING bit not yet set...", m_taskName);
|
ESP_LOGW(TAG, "ota task %s TASK_RUNNING_BIT bit not yet set...", m_taskName);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
if (const auto bits = m_eventGroup.waitBits(TASK_RUNNING, false, false, portMAX_DELAY);
|
if (const auto bits = m_eventGroup.waitBits(TASK_RUNNING_BIT, false, false, portMAX_DELAY);
|
||||||
bits & TASK_RUNNING)
|
bits & TASK_RUNNING_BIT)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
@ -89,7 +96,7 @@ tl::expected<void, std::string> EspAsyncOta::startTask()
|
|||||||
tl::expected<void, std::string> EspAsyncOta::endTask()
|
tl::expected<void, std::string> EspAsyncOta::endTask()
|
||||||
{
|
{
|
||||||
if (const auto bits = m_eventGroup.getBits();
|
if (const auto bits = m_eventGroup.getBits();
|
||||||
!(bits & TASK_RUNNING))
|
!(bits & TASK_RUNNING_BIT))
|
||||||
return {};
|
return {};
|
||||||
else if (bits & END_TASK_BIT)
|
else if (bits & END_TASK_BIT)
|
||||||
{
|
{
|
||||||
@ -100,18 +107,18 @@ tl::expected<void, std::string> EspAsyncOta::endTask()
|
|||||||
|
|
||||||
m_eventGroup.setBits(END_TASK_BIT);
|
m_eventGroup.setBits(END_TASK_BIT);
|
||||||
|
|
||||||
if (const auto bits = m_eventGroup.waitBits(TASK_ENDED, true, false, std::chrono::ceil<espcpputils::ticks>(1s).count());
|
if (const auto bits = m_eventGroup.waitBits(TASK_ENDED_BIT, true, false, std::chrono::ceil<espcpputils::ticks>(1s).count());
|
||||||
bits & TASK_ENDED)
|
bits & TASK_ENDED_BIT)
|
||||||
{
|
{
|
||||||
ESP_LOGD(TAG, "ota task %s ended", m_taskName);
|
ESP_LOGD(TAG, "ota task %s ended", m_taskName);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGW(TAG, "ota task %s TASK_ENDED bit not yet set...", m_taskName);
|
ESP_LOGW(TAG, "ota task %s TASK_ENDED_BIT bit not yet set...", m_taskName);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
if (const auto bits = m_eventGroup.waitBits(TASK_ENDED, true, false, portMAX_DELAY);
|
if (const auto bits = m_eventGroup.waitBits(TASK_ENDED_BIT, true, false, portMAX_DELAY);
|
||||||
bits & TASK_ENDED)
|
bits & TASK_ENDED_BIT)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
ESP_LOGD(TAG, "ota task %s ended", m_taskName);
|
ESP_LOGD(TAG, "ota task %s ended", m_taskName);
|
||||||
@ -121,7 +128,7 @@ tl::expected<void, std::string> EspAsyncOta::endTask()
|
|||||||
|
|
||||||
OtaCloudUpdateStatus EspAsyncOta::status() const
|
OtaCloudUpdateStatus EspAsyncOta::status() const
|
||||||
{
|
{
|
||||||
if (const auto bits = m_eventGroup.getBits(); !(bits & TASK_RUNNING))
|
if (const auto bits = m_eventGroup.getBits(); !(bits & TASK_RUNNING_BIT))
|
||||||
{
|
{
|
||||||
return OtaCloudUpdateStatus::NotReady;
|
return OtaCloudUpdateStatus::NotReady;
|
||||||
}
|
}
|
||||||
@ -143,7 +150,13 @@ OtaCloudUpdateStatus EspAsyncOta::status() const
|
|||||||
tl::expected<void, std::string> EspAsyncOta::trigger(std::string_view url, std::string_view cert_pem,
|
tl::expected<void, std::string> EspAsyncOta::trigger(std::string_view url, std::string_view cert_pem,
|
||||||
std::string_view client_key, std::string_view client_cert)
|
std::string_view client_key, std::string_view client_cert)
|
||||||
{
|
{
|
||||||
if (const auto bits = m_eventGroup.getBits(); !(bits & TASK_RUNNING))
|
if (!m_taskHandle)
|
||||||
|
{
|
||||||
|
if (auto result = startTask(); !result)
|
||||||
|
return tl::make_unexpected(std::move(result).error());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto bits = m_eventGroup.getBits(); !(bits & TASK_RUNNING_BIT))
|
||||||
return tl::make_unexpected("ota cloud task not running");
|
return tl::make_unexpected("ota cloud task not running");
|
||||||
else if (bits & (START_REQUEST_BIT | REQUEST_RUNNING_BIT))
|
else if (bits & (START_REQUEST_BIT | REQUEST_RUNNING_BIT))
|
||||||
return tl::make_unexpected("ota cloud already running");
|
return tl::make_unexpected("ota cloud already running");
|
||||||
@ -169,16 +182,29 @@ tl::expected<void, std::string> EspAsyncOta::trigger(std::string_view url, std::
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tl::expected<void, std::string> EspAsyncOta::abort()
|
||||||
|
{
|
||||||
|
if (const auto bits = m_eventGroup.getBits(); !(bits & (START_REQUEST_BIT | REQUEST_RUNNING_BIT)))
|
||||||
|
return tl::make_unexpected("no ota job is running!");
|
||||||
|
else if (bits & ABORT_REQUEST_BIT)
|
||||||
|
return tl::make_unexpected("an abort has already been requested!");
|
||||||
|
|
||||||
|
m_eventGroup.setBits(ABORT_REQUEST_BIT);
|
||||||
|
ESP_LOGI(TAG, "ota cloud update abort requested");
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void EspAsyncOta::update()
|
void EspAsyncOta::update()
|
||||||
{
|
{
|
||||||
if (!m_taskHandle)
|
//if (!m_taskHandle)
|
||||||
{
|
//{
|
||||||
if (const auto result = startTask(); !result)
|
// if (const auto result = startTask(); !result)
|
||||||
{
|
// {
|
||||||
ESP_LOGE(TAG, "starting OTA task failed: %.*s", result.error().size(), result.error().data());
|
// ESP_LOGE(TAG, "starting OTA task failed: %.*s", result.error().size(), result.error().data());
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
if (const auto bits = m_eventGroup.getBits(); bits & (START_REQUEST_BIT | REQUEST_RUNNING_BIT))
|
if (const auto bits = m_eventGroup.getBits(); bits & (START_REQUEST_BIT | REQUEST_RUNNING_BIT))
|
||||||
{
|
{
|
||||||
@ -229,9 +255,13 @@ void EspAsyncOta::update()
|
|||||||
|
|
||||||
void EspAsyncOta::otaTask()
|
void EspAsyncOta::otaTask()
|
||||||
{
|
{
|
||||||
auto helper = cpputils::makeCleanupHelper([&](){ m_eventGroup.clearBits(TASK_RUNNING); vTaskDelete(NULL); });
|
auto helper = cpputils::makeCleanupHelper([&](){
|
||||||
|
m_eventGroup.clearBits(TASK_RUNNING_BIT);
|
||||||
|
m_taskHandle = NULL;
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
});
|
||||||
|
|
||||||
m_eventGroup.setBits(TASK_RUNNING);
|
m_eventGroup.setBits(TASK_RUNNING_BIT);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@ -253,7 +283,10 @@ void EspAsyncOta::otaTask()
|
|||||||
|
|
||||||
m_eventGroup.setBits(REQUEST_RUNNING_BIT);
|
m_eventGroup.setBits(REQUEST_RUNNING_BIT);
|
||||||
|
|
||||||
auto helper2 = cpputils::makeCleanupHelper([&](){ m_eventGroup.clearBits(REQUEST_RUNNING_BIT); m_eventGroup.setBits(REQUEST_FINISHED_BIT); });
|
auto helper2 = cpputils::makeCleanupHelper([&](){
|
||||||
|
m_eventGroup.clearBits(REQUEST_RUNNING_BIT | ABORT_REQUEST_BIT);
|
||||||
|
m_eventGroup.setBits(REQUEST_FINISHED_BIT);
|
||||||
|
});
|
||||||
|
|
||||||
esp_http_client_config_t config{};
|
esp_http_client_config_t config{};
|
||||||
config.url = m_url.c_str();
|
config.url = m_url.c_str();
|
||||||
@ -322,6 +355,7 @@ void EspAsyncOta::otaTask()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "esp_https_ota_perform()...");
|
ESP_LOGI(TAG, "esp_https_ota_perform()...");
|
||||||
|
bool aborted{};
|
||||||
esp_err_t ota_perform_err;
|
esp_err_t ota_perform_err;
|
||||||
{
|
{
|
||||||
espchrono::millis_clock::time_point lastYield = espchrono::millis_clock::now();
|
espchrono::millis_clock::time_point lastYield = espchrono::millis_clock::now();
|
||||||
@ -337,6 +371,15 @@ void EspAsyncOta::otaTask()
|
|||||||
lastYield = espchrono::millis_clock::now();
|
lastYield = espchrono::millis_clock::now();
|
||||||
vPortYield();
|
vPortYield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_eventGroup.clearBits(ABORT_REQUEST_BIT) & ABORT_REQUEST_BIT)
|
||||||
|
{
|
||||||
|
ESP_LOGW(TAG, "abort request received");
|
||||||
|
aborted = true;
|
||||||
|
m_message = "Requested abort";
|
||||||
|
ota_perform_err = ESP_FAIL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ESP_LOG_LEVEL_LOCAL((ota_perform_err == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "esp_https_ota_perform() returned: %s", esp_err_to_name(ota_perform_err));
|
ESP_LOG_LEVEL_LOCAL((ota_perform_err == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "esp_https_ota_perform() returned: %s", esp_err_to_name(ota_perform_err));
|
||||||
@ -346,14 +389,17 @@ void EspAsyncOta::otaTask()
|
|||||||
ESP_LOG_LEVEL_LOCAL((ota_finish_err == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "esp_https_ota_finish() returned: %s", esp_err_to_name(ota_finish_err));
|
ESP_LOG_LEVEL_LOCAL((ota_finish_err == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), TAG, "esp_https_ota_finish() returned: %s", esp_err_to_name(ota_finish_err));
|
||||||
|
|
||||||
|
|
||||||
if (ota_perform_err != ESP_OK)
|
if (!aborted)
|
||||||
m_message = fmt::format("{}() failed with {} (at {})", "esp_https_ota_perform",
|
{
|
||||||
esp_err_to_name(ota_perform_err), std::chrono::milliseconds{espchrono::millis_clock::now().time_since_epoch()}.count());
|
if (ota_perform_err != ESP_OK)
|
||||||
else if (ota_finish_err != ESP_OK)
|
m_message = fmt::format("{}() failed with {} (at {})", "esp_https_ota_perform",
|
||||||
m_message = fmt::format("{}() failed with {} (at {})", "esp_https_ota_finish",
|
esp_err_to_name(ota_perform_err), std::chrono::milliseconds{espchrono::millis_clock::now().time_since_epoch()}.count());
|
||||||
esp_err_to_name(ota_finish_err), std::chrono::milliseconds{espchrono::millis_clock::now().time_since_epoch()}.count());
|
else if (ota_finish_err != ESP_OK)
|
||||||
else
|
m_message = fmt::format("{}() failed with {} (at {})", "esp_https_ota_finish",
|
||||||
m_message.clear();
|
esp_err_to_name(ota_finish_err), std::chrono::milliseconds{espchrono::millis_clock::now().time_since_epoch()}.count());
|
||||||
|
else
|
||||||
|
m_message.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (ota_perform_err == ESP_OK &&
|
if (ota_perform_err == ESP_OK &&
|
||||||
ota_finish_err == ESP_OK)
|
ota_finish_err == ESP_OK)
|
||||||
|
@ -41,6 +41,7 @@ public:
|
|||||||
const std::optional<esp_app_desc_t> &appDesc() const { return m_appDesc; }
|
const std::optional<esp_app_desc_t> &appDesc() const { return m_appDesc; }
|
||||||
OtaCloudUpdateStatus status() const;
|
OtaCloudUpdateStatus status() const;
|
||||||
tl::expected<void, std::string> trigger(std::string_view url, std::string_view cert_pem, std::string_view client_key, std::string_view client_cert);
|
tl::expected<void, std::string> trigger(std::string_view url, std::string_view cert_pem, std::string_view client_key, std::string_view client_cert);
|
||||||
|
tl::expected<void, std::string> abort();
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user