Make controller input best-effort and harden OTA rollback.
Accel/tap use fire-and-forget ESP-NOW with a 10 ms FreeRTOS-safe cadence, OTA recovers from seq gaps and auto-reboots after success, and bootloader app rollback confirms after a stable boot. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+18
-7
@@ -10,6 +10,7 @@
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
#include "ota_uart.h"
|
||||
#include "pod_reboot.h"
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "[OTA_ESPNOW]";
|
||||
@@ -186,6 +187,10 @@ static bool any_target_failed(void) {
|
||||
/**
|
||||
* Wait until all want_bits are set, or OTA_EG_FAIL_BIT (slave FAILED).
|
||||
* Returns true only when every target bit is set; false on fail or timeout.
|
||||
*
|
||||
* Wait only for *still missing* bits. Waiting on the full mask with "any bit"
|
||||
* busy-spins after the first slave ACK (already-set bits make WaitBits return
|
||||
* immediately) and starves IDLE → task_wdt.
|
||||
*/
|
||||
static bool wait_target_bits(uint32_t want_bits, uint32_t timeout_ms) {
|
||||
if (s_eg == NULL || want_bits == 0) {
|
||||
@@ -194,7 +199,6 @@ static bool wait_target_bits(uint32_t want_bits, uint32_t timeout_ms) {
|
||||
|
||||
const TickType_t start = xTaskGetTickCount();
|
||||
const TickType_t timeout_ticks = pdMS_TO_TICKS(timeout_ms);
|
||||
const EventBits_t wait_mask = want_bits | OTA_EG_FAIL_BIT;
|
||||
|
||||
while (true) {
|
||||
TickType_t elapsed = xTaskGetTickCount() - start;
|
||||
@@ -203,16 +207,19 @@ static bool wait_target_bits(uint32_t want_bits, uint32_t timeout_ms) {
|
||||
}
|
||||
TickType_t remain = timeout_ticks - elapsed;
|
||||
|
||||
EventBits_t got =
|
||||
xEventGroupWaitBits(s_eg, wait_mask, pdFALSE, pdFALSE, remain);
|
||||
if (got & OTA_EG_FAIL_BIT) {
|
||||
EventBits_t have = xEventGroupGetBits(s_eg);
|
||||
if (have & OTA_EG_FAIL_BIT) {
|
||||
xEventGroupClearBits(s_eg, OTA_EG_FAIL_BIT);
|
||||
return false;
|
||||
}
|
||||
if ((got & want_bits) == want_bits) {
|
||||
if ((have & want_bits) == want_bits) {
|
||||
xEventGroupClearBits(s_eg, want_bits);
|
||||
return true;
|
||||
}
|
||||
|
||||
EventBits_t missing = want_bits & ~have;
|
||||
(void)xEventGroupWaitBits(s_eg, missing | OTA_EG_FAIL_BIT, pdFALSE,
|
||||
pdFALSE, remain);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,9 +321,10 @@ static void process_slave_payload(const uint8_t master_mac[6],
|
||||
|
||||
ota_feed_result_t r = ota_uart_feed_chunk(payload->seq, payload->data.bytes,
|
||||
payload->data.size);
|
||||
/* Gap: keep session; master block-retries from the last ACK boundary. */
|
||||
if (r == OTA_FEED_SEQ_GAP) {
|
||||
led_ring_ota_failed();
|
||||
send_slave_status(master_mac, OTA_ST_FAILED, ota_uart_bytes_written(), 16);
|
||||
ESP_LOGW(TAG, "ESP-NOW OTA seq gap (got %lu) — waiting for retry",
|
||||
(unsigned long)payload->seq);
|
||||
return;
|
||||
}
|
||||
if (r == OTA_FEED_SEQ_DUP) {
|
||||
@@ -371,6 +379,9 @@ static void process_slave_end(const uint8_t master_mac[6]) {
|
||||
led_ring_ota_success();
|
||||
ESP_LOGI(TAG, "slave OTA success (%lu bytes), reboot to run",
|
||||
(unsigned long)written);
|
||||
/* Boot partition already set in ota_uart_finish(true); must reboot or we
|
||||
* keep running the old image while the master expects the new one. */
|
||||
pod_schedule_restart();
|
||||
}
|
||||
|
||||
static void ota_slave_work_task(void *param) {
|
||||
|
||||
Reference in New Issue
Block a user