Distribute master OTA images to slaves over ESP-NOW.
After UART OTA the master reads the staged partition in 4 KiB blocks (200 B ESP-NOW chunks), waits for per-slave block ACKs, and fixes the final partial block. Slaves reuse ota_uart; send pacing and logging improve reliability. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+56
-11
@@ -19,6 +19,13 @@ typedef struct {
|
||||
|
||||
static ota_uart_state_t s_ota;
|
||||
|
||||
static struct {
|
||||
bool valid;
|
||||
const esp_partition_t *partition;
|
||||
uint32_t size;
|
||||
int target_slot;
|
||||
} s_staged;
|
||||
|
||||
static int partition_slot(const esp_partition_t *part) {
|
||||
if (part == NULL) {
|
||||
return -1;
|
||||
@@ -144,7 +151,38 @@ ota_feed_result_t ota_uart_feed(const uint8_t *data, size_t len) {
|
||||
|
||||
uint32_t ota_uart_bytes_written(void) { return s_ota.written; }
|
||||
|
||||
esp_err_t ota_uart_finish(bool *success_out) {
|
||||
bool ota_uart_get_staged_image(const esp_partition_t **partition_out,
|
||||
uint32_t *size_out) {
|
||||
if (!s_staged.valid || s_staged.partition == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (partition_out != NULL) {
|
||||
*partition_out = s_staged.partition;
|
||||
}
|
||||
if (size_out != NULL) {
|
||||
*size_out = s_staged.size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ota_uart_clear_staged(void) { memset(&s_staged, 0, sizeof(s_staged)); }
|
||||
|
||||
esp_err_t ota_uart_apply_boot(void) {
|
||||
if (!s_staged.valid || s_staged.partition == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
esp_err_t err = esp_ota_set_boot_partition(s_staged.partition);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
ESP_LOGI(TAG, "boot partition set to %s (slot %d)",
|
||||
s_staged.partition->label, s_staged.target_slot);
|
||||
ota_uart_clear_staged();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ota_uart_finish(bool set_boot, bool *success_out) {
|
||||
if (success_out != NULL) {
|
||||
*success_out = false;
|
||||
}
|
||||
@@ -165,20 +203,27 @@ esp_err_t ota_uart_finish(bool *success_out) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_ota_set_boot_partition(s_ota.update_partition);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed: %s", esp_err_to_name(err));
|
||||
memset(&s_ota, 0, sizeof(s_ota));
|
||||
return err;
|
||||
}
|
||||
ota_uart_clear_staged();
|
||||
s_staged.valid = true;
|
||||
s_staged.partition = s_ota.update_partition;
|
||||
s_staged.size = s_ota.written;
|
||||
s_staged.target_slot = s_ota.target_slot;
|
||||
|
||||
ESP_LOGI(TAG, "OTA complete: %lu bytes written to %s (slot %d), reboot to run",
|
||||
(unsigned long)s_ota.written, s_ota.update_partition->label,
|
||||
s_ota.target_slot);
|
||||
ESP_LOGI(TAG, "OTA image staged: %lu bytes on %s (slot %d)",
|
||||
(unsigned long)s_staged.size, s_staged.partition->label,
|
||||
s_staged.target_slot);
|
||||
|
||||
memset(&s_ota, 0, sizeof(s_ota));
|
||||
|
||||
if (set_boot) {
|
||||
err = ota_uart_apply_boot();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (success_out != NULL) {
|
||||
*success_out = true;
|
||||
}
|
||||
memset(&s_ota, 0, sizeof(s_ota));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user