proper state machine

This commit is contained in:
J. Nick Koston 2025-06-29 19:31:01 -05:00
parent 8e00fedc67
commit 59bcbe7fef
No known key found for this signature in database
2 changed files with 20 additions and 14 deletions

View File

@ -119,8 +119,7 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin
// ESP-IDF implementation // ESP-IDF implementation
if (index == 0) { if (index == 0) {
this->ota_init_(filename.c_str()); this->ota_init_(filename.c_str());
this->ota_started_ = false; this->ota_state_ = OTAState::IDLE;
this->ota_success_ = false;
// Create OTA backend // Create OTA backend
auto backend = ota::make_ota_backend(); auto backend = ota::make_ota_backend();
@ -129,15 +128,16 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin
auto result = backend->begin(0); auto result = backend->begin(0);
if (result != ota::OTA_RESPONSE_OK) { if (result != ota::OTA_RESPONSE_OK) {
ESP_LOGE(TAG, "OTA begin failed: %d", result); ESP_LOGE(TAG, "OTA begin failed: %d", result);
this->ota_state_ = OTAState::FAILED;
return; return;
} }
// Store the backend pointer // Store the backend pointer
this->ota_backend_ = backend.release(); this->ota_backend_ = backend.release();
this->ota_started_ = true; this->ota_state_ = OTAState::STARTED;
} }
if (!this->ota_started_ || !this->ota_backend_) { if (this->ota_state_ != OTAState::STARTED && this->ota_state_ != OTAState::IN_PROGRESS) {
// Begin failed or was aborted // Begin failed or was aborted
return; return;
} }
@ -145,6 +145,7 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin
// Write data // Write data
if (len > 0) { if (len > 0) {
auto *backend = static_cast<ota::OTABackend *>(this->ota_backend_); auto *backend = static_cast<ota::OTABackend *>(this->ota_backend_);
this->ota_state_ = OTAState::IN_PROGRESS;
auto result = backend->write(data, len); auto result = backend->write(data, len);
if (result != ota::OTA_RESPONSE_OK) { if (result != ota::OTA_RESPONSE_OK) {
@ -152,8 +153,7 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin
backend->abort(); backend->abort();
delete backend; delete backend;
this->ota_backend_ = nullptr; this->ota_backend_ = nullptr;
this->ota_started_ = false; this->ota_state_ = OTAState::FAILED;
this->ota_success_ = false;
return; return;
} }
@ -165,15 +165,14 @@ void OTARequestHandler::handleUpload(AsyncWebServerRequest *request, const Strin
auto *backend = static_cast<ota::OTABackend *>(this->ota_backend_); auto *backend = static_cast<ota::OTABackend *>(this->ota_backend_);
auto result = backend->end(); auto result = backend->end();
if (result == ota::OTA_RESPONSE_OK) { if (result == ota::OTA_RESPONSE_OK) {
this->ota_success_ = true; this->ota_state_ = OTAState::SUCCESS;
this->schedule_ota_reboot_(); this->schedule_ota_reboot_();
} else { } else {
ESP_LOGE(TAG, "OTA end failed: %d", result); ESP_LOGE(TAG, "OTA end failed: %d", result);
this->ota_success_ = false; this->ota_state_ = OTAState::FAILED;
} }
delete backend; delete backend;
this->ota_backend_ = nullptr; this->ota_backend_ = nullptr;
this->ota_started_ = false;
} }
#endif // USE_ESP_IDF #endif // USE_ESP_IDF
#endif // USE_WEBSERVER_OTA #endif // USE_WEBSERVER_OTA
@ -195,7 +194,7 @@ void OTARequestHandler::handleRequest(AsyncWebServerRequest *request) {
#ifdef USE_ESP_IDF #ifdef USE_ESP_IDF
// For ESP-IDF, we use direct send() instead of beginResponse() // For ESP-IDF, we use direct send() instead of beginResponse()
// to ensure the response is sent immediately before the reboot. // to ensure the response is sent immediately before the reboot.
request->send(200, "text/plain", this->ota_success_ ? "Update Successful!" : "Update Failed!"); request->send(200, "text/plain", this->ota_state_ == OTAState::SUCCESS ? "Update Successful!" : "Update Failed!");
return; return;
#endif // USE_ESP_IDF #endif // USE_ESP_IDF
response->addHeader("Connection", "close"); response->addHeader("Connection", "close");

View File

@ -130,8 +130,7 @@ class OTARequestHandler : public AsyncWebHandler {
OTARequestHandler(WebServerBase *parent) : parent_(parent) { OTARequestHandler(WebServerBase *parent) : parent_(parent) {
#if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA) #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
this->ota_backend_ = nullptr; this->ota_backend_ = nullptr;
this->ota_started_ = false; this->ota_state_ = OTAState::IDLE;
this->ota_success_ = false;
#endif #endif
} }
void handleRequest(AsyncWebServerRequest *request) override; void handleRequest(AsyncWebServerRequest *request) override;
@ -157,9 +156,17 @@ class OTARequestHandler : public AsyncWebHandler {
private: private:
#if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA) #if defined(USE_ESP_IDF) && defined(USE_WEBSERVER_OTA)
// OTA state machine
enum class OTAState : uint8_t{
IDLE = 0, // No OTA in progress
STARTED, // OTA begin() succeeded
IN_PROGRESS, // Writing data
SUCCESS, // OTA end() succeeded
FAILED // OTA failed at any stage
};
void *ota_backend_{nullptr}; void *ota_backend_{nullptr};
bool ota_started_{false}; OTAState ota_state_{OTAState::IDLE};
bool ota_success_{false};
#endif #endif
}; };