Add per-slave ESP-NOW OTA progress over UART and fix dashboard updates.
Expose OTA_SLAVE_PROGRESS on the master, track per-slave state during distribution, run ESP-NOW OTA in a background task so the host can poll while slaves update, and show master/slave progress in the dashboard with table layout and faster WebSocket refresh during uploads. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -20,6 +20,7 @@ idf_component_register(
|
||||
"cmd_accel_deadzone.c"
|
||||
"cmd_espnow_unicast_test.c"
|
||||
"cmd_ota.c"
|
||||
"cmd_ota_slave_progress.c"
|
||||
"ota_uart.c"
|
||||
"ota_espnow.c"
|
||||
"client_registry.c"
|
||||
|
||||
+23
-1
@@ -207,6 +207,7 @@ Host and master speak nanopb-encoded `UartMessage` inside UART frames (byte 0 =
|
||||
| 18 | `OTA_END` | Implemented — flush, `esp_ota_end`, push image to slaves via ESP-NOW, set boot |
|
||||
| 19 | `OTA_STATUS` | Device → host (prepare/ready/block ACK/success/failed) |
|
||||
| 20 | `OTA_START_ESPNOW` | Implemented — re-distribute staged image to slaves only |
|
||||
| 21 | `OTA_SLAVE_PROGRESS` | Implemented (`cmd_ota_slave_progress.c`) — query per-slave ESP-NOW OTA progress |
|
||||
|
||||
Regenerate C code:
|
||||
|
||||
@@ -260,7 +261,28 @@ Host upload:
|
||||
go run . -port /dev/ttyUSB0 ota build/powerpod.bin
|
||||
```
|
||||
|
||||
`OtaStatusPayload.status`: `1` preparing, `2` ready, `3` block_ack, `4` success, `5` failed.
|
||||
`OtaStatusPayload.status`: `1` preparing, `2` ready, `3` block_ack, `4` success, `5` failed, `6` distributing (`bytes_written` = progress, `target_slot` = slave count).
|
||||
|
||||
### OTA_SLAVE_PROGRESS command
|
||||
|
||||
**Request:** framed `15` (`0x15`) + optional `ota_slave_progress_request` (`client_id`; `0` = all slaves in the current/last distribution session).
|
||||
|
||||
**Response:** `ota_slave_progress_response`:
|
||||
|
||||
| Field | Meaning |
|
||||
|-------|---------|
|
||||
| `active` | ESP-NOW distribution running |
|
||||
| `total_bytes` | Image size |
|
||||
| `aggregate_bytes` | Overall bytes sent to all slaves |
|
||||
| `slave_count` | Number of slaves in session |
|
||||
| `slaves[]` | Per slave: `client_id`, `bytes_written`, `total_bytes`, `status`, `error` |
|
||||
|
||||
Per-slave `status`: `0` idle, `1` preparing, `2` ready, `3` block_ack/distributing, `4` success, `5` failed.
|
||||
|
||||
```bash
|
||||
go run . -port /dev/ttyUSB0 ota-progress
|
||||
go run . -port /dev/ttyUSB0 ota-progress -client 16
|
||||
```
|
||||
|
||||
### ACCEL_DEADZONE command
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ static const char *message_type_name(uint16_t id) {
|
||||
return "OTA_STATUS";
|
||||
case alox_MessageType_OTA_START_ESPNOW:
|
||||
return "OTA_START_ESPNOW";
|
||||
case alox_MessageType_OTA_SLAVE_PROGRESS:
|
||||
return "OTA_SLAVE_PROGRESS";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
+83
-17
@@ -5,12 +5,20 @@
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "[OTA_CMD]";
|
||||
|
||||
#define OTA_PREPARE_STACK 8192
|
||||
#define OTA_PREPARE_PRIO 5
|
||||
#define OTA_DIST_STACK 8192
|
||||
#define OTA_DIST_PRIO 5
|
||||
|
||||
typedef struct {
|
||||
uint32_t written;
|
||||
int slot;
|
||||
} ota_dist_job_t;
|
||||
static void send_ota_status(ota_uart_status_t status, uint32_t err_code) {
|
||||
alox_UartMessage response;
|
||||
uart_cmd_init_response(&response, alox_MessageType_OTA_STATUS,
|
||||
@@ -24,6 +32,35 @@ static void send_ota_status(ota_uart_status_t status, uint32_t err_code) {
|
||||
uart_cmd_send(&response, TAG);
|
||||
}
|
||||
|
||||
static void send_ota_distributing(uint32_t kind, uint32_t bytes_done,
|
||||
uint32_t target_slot) {
|
||||
alox_UartMessage response;
|
||||
uart_cmd_init_response(&response, alox_MessageType_OTA_STATUS,
|
||||
alox_UartMessage_ota_status_tag);
|
||||
response.payload.ota_status.status = (uint32_t)OTA_UART_ST_DISTRIBUTING;
|
||||
response.payload.ota_status.bytes_written = bytes_done;
|
||||
response.payload.ota_status.target_slot = target_slot;
|
||||
response.payload.ota_status.error = kind;
|
||||
uart_cmd_send(&response, TAG);
|
||||
}
|
||||
|
||||
static void ota_dist_aggregate(uint32_t bytes_done, uint32_t total_bytes,
|
||||
uint8_t slave_count) {
|
||||
(void)total_bytes;
|
||||
send_ota_distributing(OTA_DIST_AGGREGATE, bytes_done, (uint32_t)slave_count);
|
||||
}
|
||||
|
||||
static void ota_dist_per_slave(uint32_t slave_id, uint32_t bytes_done,
|
||||
uint32_t total_bytes) {
|
||||
(void)total_bytes;
|
||||
send_ota_distributing(OTA_DIST_PER_SLAVE, bytes_done, slave_id);
|
||||
}
|
||||
|
||||
static const ota_espnow_progress_cbs_t s_dist_progress = {
|
||||
.aggregate = ota_dist_aggregate,
|
||||
.per_slave = ota_dist_per_slave,
|
||||
};
|
||||
|
||||
static void ota_prepare_task(void *param) {
|
||||
uint32_t total_size = (uint32_t)(uintptr_t)param;
|
||||
|
||||
@@ -128,46 +165,54 @@ static void handle_ota_payload(const uint8_t *data, size_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t finish_master_ota_and_distribute(void) {
|
||||
uint32_t written = ota_uart_bytes_written();
|
||||
int slot = ota_uart_target_slot();
|
||||
bool success = false;
|
||||
esp_err_t err = ota_uart_finish(false, &success);
|
||||
if (err != ESP_OK || !success) {
|
||||
send_ota_status(OTA_UART_ST_FAILED, (uint32_t)err);
|
||||
return err;
|
||||
static void ota_distribute_task(void *param) {
|
||||
ota_dist_job_t *job = (ota_dist_job_t *)param;
|
||||
if (job == NULL) {
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
const esp_partition_t *part = NULL;
|
||||
uint32_t image_size = 0;
|
||||
if (!ota_uart_get_staged_image(&part, &image_size)) {
|
||||
send_ota_status(OTA_UART_ST_FAILED, 30);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
free(job);
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
err = ota_espnow_distribute(part, image_size);
|
||||
send_ota_distributing(OTA_DIST_AGGREGATE, 0, 0);
|
||||
|
||||
esp_err_t err = ota_espnow_distribute(part, image_size, &s_dist_progress);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "slave OTA distribution failed: %s", esp_err_to_name(err));
|
||||
ota_uart_clear_staged();
|
||||
send_ota_status(OTA_UART_ST_FAILED, 31);
|
||||
return err;
|
||||
free(job);
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
err = ota_uart_apply_boot();
|
||||
if (err != ESP_OK) {
|
||||
send_ota_status(OTA_UART_ST_FAILED, (uint32_t)err);
|
||||
return err;
|
||||
free(job);
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
alox_UartMessage response;
|
||||
uart_cmd_init_response(&response, alox_MessageType_OTA_STATUS,
|
||||
alox_UartMessage_ota_status_tag);
|
||||
response.payload.ota_status.status = (uint32_t)OTA_UART_ST_SUCCESS;
|
||||
response.payload.ota_status.bytes_written = written;
|
||||
response.payload.ota_status.target_slot = slot >= 0 ? (uint32_t)slot : 0;
|
||||
response.payload.ota_status.bytes_written = job->written;
|
||||
response.payload.ota_status.target_slot =
|
||||
job->slot >= 0 ? (uint32_t)job->slot : 0;
|
||||
response.payload.ota_status.error = 0;
|
||||
uart_cmd_send(&response, TAG);
|
||||
return ESP_OK;
|
||||
|
||||
free(job);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void handle_ota_end(const uint8_t *data, size_t len) {
|
||||
@@ -179,7 +224,28 @@ static void handle_ota_end(const uint8_t *data, size_t len) {
|
||||
return;
|
||||
}
|
||||
|
||||
(void)finish_master_ota_and_distribute();
|
||||
ota_dist_job_t *job = calloc(1, sizeof(*job));
|
||||
if (job == NULL) {
|
||||
send_ota_status(OTA_UART_ST_FAILED, 21);
|
||||
return;
|
||||
}
|
||||
job->written = ota_uart_bytes_written();
|
||||
job->slot = ota_uart_target_slot();
|
||||
|
||||
bool success = false;
|
||||
esp_err_t err = ota_uart_finish(false, &success);
|
||||
if (err != ESP_OK || !success) {
|
||||
send_ota_status(OTA_UART_ST_FAILED, (uint32_t)err);
|
||||
free(job);
|
||||
return;
|
||||
}
|
||||
|
||||
if (xTaskCreate(ota_distribute_task, "ota_dist", OTA_DIST_STACK, job,
|
||||
OTA_DIST_PRIO, NULL) != pdPASS) {
|
||||
ESP_LOGE(TAG, "failed to create ota_dist task");
|
||||
send_ota_status(OTA_UART_ST_FAILED, 22);
|
||||
free(job);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_ota_start_espnow(const uint8_t *data, size_t len) {
|
||||
@@ -198,7 +264,7 @@ static void handle_ota_start_espnow(const uint8_t *data, size_t len) {
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err = ota_espnow_distribute(part, image_size);
|
||||
esp_err_t err = ota_espnow_distribute(part, image_size, &s_dist_progress);
|
||||
if (err != ESP_OK) {
|
||||
send_ota_status(OTA_UART_ST_FAILED, 42);
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "cmd_ota_slave_progress.h"
|
||||
#include "ota_espnow.h"
|
||||
#include "uart_cmd.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "[OTA_PROG]";
|
||||
|
||||
static void handle_ota_slave_progress(const uint8_t *data, size_t len) {
|
||||
alox_UartMessage uart_msg;
|
||||
uint32_t filter = 0;
|
||||
|
||||
if (uart_cmd_decode(data, len, &uart_msg) == ESP_OK) {
|
||||
const alox_OtaSlaveProgressRequest *req =
|
||||
UART_CMD_REQ(&uart_msg, alox_UartMessage_ota_slave_progress_request_tag,
|
||||
ota_slave_progress_request);
|
||||
if (req != NULL) {
|
||||
filter = req->client_id;
|
||||
}
|
||||
}
|
||||
|
||||
alox_UartMessage response;
|
||||
uart_cmd_init_response(
|
||||
&response, alox_MessageType_OTA_SLAVE_PROGRESS,
|
||||
alox_UartMessage_ota_slave_progress_response_tag);
|
||||
ota_espnow_progress_query(filter, &response.payload.ota_slave_progress_response);
|
||||
|
||||
ESP_LOGI(TAG, "query client_id=%lu -> %u slave(s) active=%d",
|
||||
(unsigned long)filter,
|
||||
(unsigned)response.payload.ota_slave_progress_response.slaves_count,
|
||||
(int)response.payload.ota_slave_progress_response.active);
|
||||
uart_cmd_send(&response, TAG);
|
||||
}
|
||||
|
||||
void cmd_ota_slave_progress_register(void) {
|
||||
uart_cmd_register(alox_MessageType_OTA_SLAVE_PROGRESS,
|
||||
handle_ota_slave_progress);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CMD_OTA_SLAVE_PROGRESS_H
|
||||
#define CMD_OTA_SLAVE_PROGRESS_H
|
||||
|
||||
void cmd_ota_slave_progress_register(void);
|
||||
|
||||
#endif
|
||||
+124
-3
@@ -36,10 +36,90 @@ typedef struct {
|
||||
uint8_t mac[OTA_MAX_TARGETS][6];
|
||||
uint32_t id[OTA_MAX_TARGETS];
|
||||
uint32_t expected_bytes;
|
||||
uint32_t total_bytes;
|
||||
ota_espnow_progress_cbs_t progress;
|
||||
} ota_dist_t;
|
||||
|
||||
static ota_dist_t s_dist;
|
||||
|
||||
typedef struct {
|
||||
uint32_t client_id;
|
||||
uint32_t bytes_written;
|
||||
uint32_t status;
|
||||
uint32_t error;
|
||||
} ota_prog_entry_t;
|
||||
|
||||
static struct {
|
||||
bool active;
|
||||
uint32_t total_bytes;
|
||||
uint32_t aggregate_bytes;
|
||||
uint8_t count;
|
||||
ota_prog_entry_t entries[OTA_MAX_TARGETS];
|
||||
} s_prog;
|
||||
|
||||
static void prog_begin(uint32_t total_bytes) {
|
||||
s_prog.active = true;
|
||||
s_prog.total_bytes = total_bytes;
|
||||
s_prog.aggregate_bytes = 0;
|
||||
s_prog.count = s_dist.count;
|
||||
for (uint8_t i = 0; i < s_dist.count; i++) {
|
||||
s_prog.entries[i].client_id = s_dist.id[i];
|
||||
s_prog.entries[i].bytes_written = 0;
|
||||
s_prog.entries[i].status = OTA_ST_PREPARING;
|
||||
s_prog.entries[i].error = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void prog_end(void) { s_prog.active = false; }
|
||||
|
||||
static void prog_set_aggregate(uint32_t bytes_done) {
|
||||
s_prog.aggregate_bytes = bytes_done;
|
||||
}
|
||||
|
||||
static void prog_update_idx(int idx, uint32_t status, uint32_t bytes,
|
||||
uint32_t error) {
|
||||
if (idx < 0 || idx >= (int)s_prog.count) {
|
||||
return;
|
||||
}
|
||||
ota_prog_entry_t *e = &s_prog.entries[idx];
|
||||
e->status = status;
|
||||
if (bytes > e->bytes_written) {
|
||||
e->bytes_written = bytes;
|
||||
}
|
||||
if (error != 0) {
|
||||
e->error = error;
|
||||
}
|
||||
}
|
||||
|
||||
void ota_espnow_progress_query(uint32_t filter_client_id,
|
||||
alox_OtaSlaveProgressResponse *out) {
|
||||
if (out == NULL) {
|
||||
return;
|
||||
}
|
||||
*out = (alox_OtaSlaveProgressResponse)alox_OtaSlaveProgressResponse_init_zero;
|
||||
out->active = s_prog.active;
|
||||
out->total_bytes = s_prog.total_bytes;
|
||||
out->aggregate_bytes = s_prog.aggregate_bytes;
|
||||
out->slave_count = s_prog.count;
|
||||
|
||||
for (uint8_t i = 0; i < s_prog.count; i++) {
|
||||
const ota_prog_entry_t *e = &s_prog.entries[i];
|
||||
if (filter_client_id != 0 && e->client_id != filter_client_id) {
|
||||
continue;
|
||||
}
|
||||
if (out->slaves_count >=
|
||||
sizeof(out->slaves) / sizeof(out->slaves[0])) {
|
||||
break;
|
||||
}
|
||||
alox_OtaSlaveProgressEntry *dst = &out->slaves[out->slaves_count++];
|
||||
dst->client_id = e->client_id;
|
||||
dst->bytes_written = e->bytes_written;
|
||||
dst->total_bytes = s_prog.total_bytes;
|
||||
dst->status = e->status;
|
||||
dst->error = e->error;
|
||||
}
|
||||
}
|
||||
|
||||
static int find_target_index(const uint8_t mac[6]) {
|
||||
for (uint8_t i = 0; i < s_dist.count; i++) {
|
||||
if (memcmp(s_dist.mac[i], mac, 6) == 0) {
|
||||
@@ -179,9 +259,15 @@ void ota_espnow_master_on_status(const uint8_t slave_mac[6],
|
||||
|
||||
switch (status->status) {
|
||||
case OTA_ST_READY:
|
||||
prog_update_idx(idx, OTA_ST_READY, 0, 0);
|
||||
xEventGroupSetBits(s_eg, bit);
|
||||
break;
|
||||
case OTA_ST_BLOCK_ACK:
|
||||
prog_update_idx(idx, OTA_ST_BLOCK_ACK, status->bytes_written, 0);
|
||||
if (s_dist.progress.per_slave != NULL) {
|
||||
s_dist.progress.per_slave(s_dist.id[idx], status->bytes_written,
|
||||
s_dist.total_bytes);
|
||||
}
|
||||
if (status->bytes_written >= s_dist.expected_bytes) {
|
||||
xEventGroupSetBits(s_eg, bit);
|
||||
} else {
|
||||
@@ -191,9 +277,12 @@ void ota_espnow_master_on_status(const uint8_t slave_mac[6],
|
||||
}
|
||||
break;
|
||||
case OTA_ST_SUCCESS:
|
||||
prog_update_idx(idx, OTA_ST_SUCCESS, status->bytes_written, 0);
|
||||
xEventGroupSetBits(s_eg, bit);
|
||||
break;
|
||||
case OTA_ST_FAILED:
|
||||
prog_update_idx(idx, OTA_ST_FAILED, status->bytes_written,
|
||||
status->error);
|
||||
ESP_LOGW(TAG, "slave %lu OTA failed (err=%lu)",
|
||||
(unsigned long)s_dist.id[idx], (unsigned long)status->error);
|
||||
break;
|
||||
@@ -220,7 +309,8 @@ static size_t collect_targets(void) {
|
||||
}
|
||||
|
||||
static esp_err_t distribute_image(const esp_partition_t *partition,
|
||||
uint32_t size) {
|
||||
uint32_t size,
|
||||
const ota_espnow_progress_cbs_t *progress) {
|
||||
if (s_eg == NULL) {
|
||||
s_eg = xEventGroupCreate();
|
||||
if (s_eg == NULL) {
|
||||
@@ -228,6 +318,13 @@ static esp_err_t distribute_image(const esp_partition_t *partition,
|
||||
}
|
||||
}
|
||||
|
||||
memset(&s_dist.progress, 0, sizeof(s_dist.progress));
|
||||
if (progress != NULL) {
|
||||
s_dist.progress = *progress;
|
||||
}
|
||||
s_dist.total_bytes = size;
|
||||
prog_begin(size);
|
||||
|
||||
ESP_LOGI(TAG, "distributing %lu bytes from %s to %u slave(s)",
|
||||
(unsigned long)size, partition->label, (unsigned)s_dist.count);
|
||||
|
||||
@@ -240,15 +337,22 @@ static esp_err_t distribute_image(const esp_partition_t *partition,
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "OTA_START to slave %lu failed",
|
||||
(unsigned long)s_dist.id[i]);
|
||||
prog_end();
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wait_target_bits(target_mask, OTA_PREPARE_TIMEOUT_MS)) {
|
||||
ESP_LOGE(TAG, "timeout waiting for slave OTA ready");
|
||||
prog_end();
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
prog_set_aggregate(0);
|
||||
if (s_dist.progress.aggregate != NULL) {
|
||||
s_dist.progress.aggregate(0, size, s_dist.count);
|
||||
}
|
||||
|
||||
uint8_t block_buf[OTA_UART_FLASH_BLOCK_SIZE];
|
||||
uint32_t offset = 0;
|
||||
uint32_t seq = 0;
|
||||
@@ -263,6 +367,7 @@ static esp_err_t distribute_image(const esp_partition_t *partition,
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "partition read @%lu failed: %s", (unsigned long)offset,
|
||||
esp_err_to_name(err));
|
||||
prog_end();
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -277,6 +382,7 @@ static esp_err_t distribute_image(const esp_partition_t *partition,
|
||||
err = esp_now_comm_send_ota_payload(s_dist.mac[i], seq,
|
||||
block_buf + sent, chunk);
|
||||
if (err != ESP_OK) {
|
||||
prog_end();
|
||||
return err;
|
||||
}
|
||||
}
|
||||
@@ -293,6 +399,7 @@ static esp_err_t distribute_image(const esp_partition_t *partition,
|
||||
if (!wait_target_bits(target_mask, OTA_BLOCK_TIMEOUT_MS)) {
|
||||
ESP_LOGE(TAG, "timeout block ack @%lu bytes",
|
||||
(unsigned long)s_dist.expected_bytes);
|
||||
prog_end();
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
ESP_LOGI(TAG, "block ack @%lu/%lu (%lu%%)",
|
||||
@@ -303,34 +410,48 @@ static esp_err_t distribute_image(const esp_partition_t *partition,
|
||||
(unsigned long)block_len);
|
||||
}
|
||||
offset += block_len;
|
||||
prog_set_aggregate(offset);
|
||||
if (s_dist.progress.aggregate != NULL) {
|
||||
s_dist.progress.aggregate(offset, size, s_dist.count);
|
||||
}
|
||||
}
|
||||
|
||||
xEventGroupClearBits(s_eg, target_mask);
|
||||
for (uint8_t i = 0; i < s_dist.count; i++) {
|
||||
err = esp_now_comm_send_ota_end(s_dist.mac[i]);
|
||||
if (err != ESP_OK) {
|
||||
prog_end();
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wait_target_bits(target_mask, OTA_END_TIMEOUT_MS)) {
|
||||
ESP_LOGE(TAG, "timeout waiting for slave OTA success");
|
||||
prog_end();
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
prog_set_aggregate(size);
|
||||
prog_end();
|
||||
ESP_LOGI(TAG, "ESP-NOW OTA complete for %u slave(s)", (unsigned)s_dist.count);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t ota_espnow_distribute(const esp_partition_t *partition, uint32_t size) {
|
||||
esp_err_t ota_espnow_distribute(const esp_partition_t *partition, uint32_t size,
|
||||
const ota_espnow_progress_cbs_t *progress) {
|
||||
if (partition == NULL || size == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (collect_targets() == 0) {
|
||||
ESP_LOGI(TAG, "no available slaves — skip ESP-NOW OTA");
|
||||
memset(&s_prog, 0, sizeof(s_prog));
|
||||
s_prog.total_bytes = size;
|
||||
if (progress != NULL && progress->aggregate != NULL) {
|
||||
progress->aggregate(size, size, 0);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
return distribute_image(partition, size);
|
||||
return distribute_image(partition, size, progress);
|
||||
}
|
||||
|
||||
+18
-1
@@ -4,10 +4,20 @@
|
||||
#include "esp_err.h"
|
||||
#include "esp_now_messages.pb.h"
|
||||
#include "esp_partition.h"
|
||||
#include "uart_messages.pb.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
/** bytes_done, total_bytes, number of slaves targeted. */
|
||||
void (*aggregate)(uint32_t bytes_done, uint32_t total_bytes,
|
||||
uint8_t slave_count);
|
||||
/** Per-slave block ACK (slave_id, bytes_written on that slave, total_bytes). */
|
||||
void (*per_slave)(uint32_t slave_id, uint32_t bytes_done, uint32_t total_bytes);
|
||||
} ota_espnow_progress_cbs_t;
|
||||
|
||||
/** Master: read staged image from partition and push to all available slaves. */
|
||||
esp_err_t ota_espnow_distribute(const esp_partition_t *partition, uint32_t size);
|
||||
esp_err_t ota_espnow_distribute(const esp_partition_t *partition, uint32_t size,
|
||||
const ota_espnow_progress_cbs_t *progress);
|
||||
|
||||
/** Master: handle slave → master OTA status / block ACK. */
|
||||
void ota_espnow_master_on_status(const uint8_t slave_mac[6],
|
||||
@@ -20,4 +30,11 @@ void ota_espnow_slave_on_payload(const uint8_t master_mac[6],
|
||||
const alox_EspNowOtaPayload *payload);
|
||||
void ota_espnow_slave_on_end(const uint8_t master_mac[6]);
|
||||
|
||||
/**
|
||||
* Fill UART OtaSlaveProgressResponse from tracked per-slave state.
|
||||
* filter_client_id 0 = all slaves in the last/current distribution session.
|
||||
*/
|
||||
void ota_espnow_progress_query(uint32_t filter_client_id,
|
||||
alox_OtaSlaveProgressResponse *out);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,8 +17,14 @@ typedef enum {
|
||||
OTA_UART_ST_BLOCK_ACK = 3,
|
||||
OTA_UART_ST_SUCCESS = 4,
|
||||
OTA_UART_ST_FAILED = 5,
|
||||
/** ESP-NOW slave distribution in progress (see OTA_DIST_* in cmd_ota.c). */
|
||||
OTA_UART_ST_DISTRIBUTING = 6,
|
||||
} ota_uart_status_t;
|
||||
|
||||
/** OtaStatusPayload.error when status == OTA_UART_ST_DISTRIBUTING. */
|
||||
#define OTA_DIST_AGGREGATE 0u
|
||||
#define OTA_DIST_PER_SLAVE 1u
|
||||
|
||||
typedef enum {
|
||||
OTA_FEED_OK = 0,
|
||||
OTA_FEED_BLOCK_WRITTEN,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "cmd_client_info.h"
|
||||
#include "cmd_version.h"
|
||||
#include "cmd_ota.h"
|
||||
#include "cmd_ota_slave_progress.h"
|
||||
#include "esp_now_comm.h"
|
||||
#include "powerpod.h"
|
||||
#include "driver/gpio.h"
|
||||
@@ -168,6 +169,7 @@ void app_main(void) {
|
||||
cmd_accel_deadzone_register();
|
||||
cmd_espnow_unicast_test_register();
|
||||
cmd_ota_register();
|
||||
cmd_ota_slave_progress_register();
|
||||
}
|
||||
|
||||
uint8_t current_digit = 10;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(alox_UartMessage, alox_UartMessage, AUTO)
|
||||
PB_BIND(alox_UartMessage, alox_UartMessage, 2)
|
||||
|
||||
|
||||
PB_BIND(alox_Ack, alox_Ack, AUTO)
|
||||
@@ -54,6 +54,15 @@ PB_BIND(alox_OtaEndPayload, alox_OtaEndPayload, AUTO)
|
||||
PB_BIND(alox_OtaStatusPayload, alox_OtaStatusPayload, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_OtaSlaveProgressRequest, alox_OtaSlaveProgressRequest, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_OtaSlaveProgressEntry, alox_OtaSlaveProgressEntry, AUTO)
|
||||
|
||||
|
||||
PB_BIND(alox_OtaSlaveProgressResponse, alox_OtaSlaveProgressResponse, 2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-1.0.0-dev */
|
||||
|
||||
#ifndef PB_ALOX_MAIN_PROTO_UART_MESSAGES_PB_H_INCLUDED
|
||||
#define PB_ALOX_MAIN_PROTO_UART_MESSAGES_PB_H_INCLUDED
|
||||
#ifndef PB_ALOX_UART_MESSAGES_PB_H_INCLUDED
|
||||
#define PB_ALOX_UART_MESSAGES_PB_H_INCLUDED
|
||||
#include <pb.h>
|
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
@@ -23,7 +23,8 @@ typedef enum _alox_MessageType {
|
||||
alox_MessageType_OTA_PAYLOAD = 17,
|
||||
alox_MessageType_OTA_END = 18,
|
||||
alox_MessageType_OTA_STATUS = 19,
|
||||
alox_MessageType_OTA_START_ESPNOW = 20
|
||||
alox_MessageType_OTA_START_ESPNOW = 20,
|
||||
alox_MessageType_OTA_SLAVE_PROGRESS = 21
|
||||
} alox_MessageType;
|
||||
|
||||
/* Struct definitions */
|
||||
@@ -99,8 +100,8 @@ typedef struct _alox_OtaStartPayload {
|
||||
uint32_t total_size;
|
||||
} alox_OtaStartPayload;
|
||||
|
||||
/* Host → device: firmware chunk (up to 200 bytes); device buffers 4 KiB before flash write. */
|
||||
typedef PB_BYTES_ARRAY_T(200) alox_OtaPayload_data_t;
|
||||
/* Host → device: firmware chunk (up to 200 bytes); device buffers 4 KiB before flash write. */
|
||||
typedef struct _alox_OtaPayload {
|
||||
uint32_t seq;
|
||||
alox_OtaPayload_data_t data;
|
||||
@@ -112,7 +113,7 @@ typedef struct _alox_OtaEndPayload {
|
||||
} alox_OtaEndPayload;
|
||||
|
||||
/* Device → host status (also used as ACK after each 4 KiB written).
|
||||
status: 1=preparing, 2=ready, 3=block_ack, 4=success, 5=failed */
|
||||
status: 1=preparing, 2=ready, 3=block_ack, 4=success, 5=failed, 6=distributing */
|
||||
typedef struct _alox_OtaStatusPayload {
|
||||
uint32_t status;
|
||||
uint32_t bytes_written;
|
||||
@@ -120,6 +121,29 @@ typedef struct _alox_OtaStatusPayload {
|
||||
uint32_t error;
|
||||
} alox_OtaStatusPayload;
|
||||
|
||||
/* Host → master: query ESP-NOW slave OTA progress (client_id 0 = all slaves in session). */
|
||||
typedef struct _alox_OtaSlaveProgressRequest {
|
||||
uint32_t client_id;
|
||||
} alox_OtaSlaveProgressRequest;
|
||||
|
||||
typedef struct _alox_OtaSlaveProgressEntry {
|
||||
uint32_t client_id;
|
||||
uint32_t bytes_written;
|
||||
uint32_t total_bytes;
|
||||
/* * 0=idle, 1=preparing, 2=ready, 3=distributing, 4=success, 5=failed */
|
||||
uint32_t status;
|
||||
uint32_t error;
|
||||
} alox_OtaSlaveProgressEntry;
|
||||
|
||||
typedef struct _alox_OtaSlaveProgressResponse {
|
||||
bool active;
|
||||
uint32_t total_bytes;
|
||||
uint32_t aggregate_bytes;
|
||||
uint32_t slave_count;
|
||||
pb_size_t slaves_count;
|
||||
alox_OtaSlaveProgressEntry slaves[16];
|
||||
} alox_OtaSlaveProgressResponse;
|
||||
|
||||
typedef struct _alox_UartMessage {
|
||||
alox_MessageType type;
|
||||
pb_size_t which_payload;
|
||||
@@ -137,6 +161,8 @@ typedef struct _alox_UartMessage {
|
||||
alox_AccelDeadzoneResponse accel_deadzone_response;
|
||||
alox_EspNowUnicastTestRequest espnow_unicast_test_request;
|
||||
alox_EspNowUnicastTestResponse espnow_unicast_test_response;
|
||||
alox_OtaSlaveProgressRequest ota_slave_progress_request;
|
||||
alox_OtaSlaveProgressResponse ota_slave_progress_response;
|
||||
} payload;
|
||||
} alox_UartMessage;
|
||||
|
||||
@@ -147,8 +173,8 @@ extern "C" {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _alox_MessageType_MIN alox_MessageType_UNKNOWN
|
||||
#define _alox_MessageType_MAX alox_MessageType_OTA_START_ESPNOW
|
||||
#define _alox_MessageType_ARRAYSIZE ((alox_MessageType)(alox_MessageType_OTA_START_ESPNOW+1))
|
||||
#define _alox_MessageType_MAX alox_MessageType_OTA_SLAVE_PROGRESS
|
||||
#define _alox_MessageType_ARRAYSIZE ((alox_MessageType)(alox_MessageType_OTA_SLAVE_PROGRESS+1))
|
||||
|
||||
#define alox_UartMessage_type_ENUMTYPE alox_MessageType
|
||||
|
||||
@@ -168,6 +194,9 @@ extern "C" {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define alox_UartMessage_init_default {_alox_MessageType_MIN, 0, {alox_Ack_init_default}}
|
||||
#define alox_Ack_init_default {0}
|
||||
@@ -185,6 +214,9 @@ extern "C" {
|
||||
#define alox_OtaPayload_init_default {0, {0, {0}}}
|
||||
#define alox_OtaEndPayload_init_default {0}
|
||||
#define alox_OtaStatusPayload_init_default {0, 0, 0, 0}
|
||||
#define alox_OtaSlaveProgressRequest_init_default {0}
|
||||
#define alox_OtaSlaveProgressEntry_init_default {0, 0, 0, 0, 0}
|
||||
#define alox_OtaSlaveProgressResponse_init_default {0, 0, 0, 0, 0, {alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default, alox_OtaSlaveProgressEntry_init_default}}
|
||||
#define alox_UartMessage_init_zero {_alox_MessageType_MIN, 0, {alox_Ack_init_zero}}
|
||||
#define alox_Ack_init_zero {0}
|
||||
#define alox_EchoPayload_init_zero {{{NULL}, NULL}}
|
||||
@@ -201,6 +233,9 @@ extern "C" {
|
||||
#define alox_OtaPayload_init_zero {0, {0, {0}}}
|
||||
#define alox_OtaEndPayload_init_zero {0}
|
||||
#define alox_OtaStatusPayload_init_zero {0, 0, 0, 0}
|
||||
#define alox_OtaSlaveProgressRequest_init_zero {0}
|
||||
#define alox_OtaSlaveProgressEntry_init_zero {0, 0, 0, 0, 0}
|
||||
#define alox_OtaSlaveProgressResponse_init_zero {0, 0, 0, 0, 0, {alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero, alox_OtaSlaveProgressEntry_init_zero}}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define alox_EchoPayload_data_tag 1
|
||||
@@ -239,6 +274,17 @@ extern "C" {
|
||||
#define alox_OtaStatusPayload_bytes_written_tag 2
|
||||
#define alox_OtaStatusPayload_target_slot_tag 3
|
||||
#define alox_OtaStatusPayload_error_tag 4
|
||||
#define alox_OtaSlaveProgressRequest_client_id_tag 1
|
||||
#define alox_OtaSlaveProgressEntry_client_id_tag 1
|
||||
#define alox_OtaSlaveProgressEntry_bytes_written_tag 2
|
||||
#define alox_OtaSlaveProgressEntry_total_bytes_tag 3
|
||||
#define alox_OtaSlaveProgressEntry_status_tag 4
|
||||
#define alox_OtaSlaveProgressEntry_error_tag 5
|
||||
#define alox_OtaSlaveProgressResponse_active_tag 1
|
||||
#define alox_OtaSlaveProgressResponse_total_bytes_tag 2
|
||||
#define alox_OtaSlaveProgressResponse_aggregate_bytes_tag 3
|
||||
#define alox_OtaSlaveProgressResponse_slave_count_tag 4
|
||||
#define alox_OtaSlaveProgressResponse_slaves_tag 5
|
||||
#define alox_UartMessage_type_tag 1
|
||||
#define alox_UartMessage_ack_payload_tag 2
|
||||
#define alox_UartMessage_echo_payload_tag 3
|
||||
@@ -253,6 +299,8 @@ extern "C" {
|
||||
#define alox_UartMessage_accel_deadzone_response_tag 12
|
||||
#define alox_UartMessage_espnow_unicast_test_request_tag 13
|
||||
#define alox_UartMessage_espnow_unicast_test_response_tag 14
|
||||
#define alox_UartMessage_ota_slave_progress_request_tag 15
|
||||
#define alox_UartMessage_ota_slave_progress_response_tag 16
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define alox_UartMessage_FIELDLIST(X, a) \
|
||||
@@ -269,7 +317,9 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,ota_status,payload.ota_status), 10)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,accel_deadzone_request,payload.accel_deadzone_request), 11) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,accel_deadzone_response,payload.accel_deadzone_response), 12) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_unicast_test_request,payload.espnow_unicast_test_request), 13) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_unicast_test_response,payload.espnow_unicast_test_response), 14)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_unicast_test_response,payload.espnow_unicast_test_response), 14) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,ota_slave_progress_request,payload.ota_slave_progress_request), 15) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,ota_slave_progress_response,payload.ota_slave_progress_response), 16)
|
||||
#define alox_UartMessage_CALLBACK NULL
|
||||
#define alox_UartMessage_DEFAULT NULL
|
||||
#define alox_UartMessage_payload_ack_payload_MSGTYPE alox_Ack
|
||||
@@ -285,6 +335,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload,espnow_unicast_test_response,payload
|
||||
#define alox_UartMessage_payload_accel_deadzone_response_MSGTYPE alox_AccelDeadzoneResponse
|
||||
#define alox_UartMessage_payload_espnow_unicast_test_request_MSGTYPE alox_EspNowUnicastTestRequest
|
||||
#define alox_UartMessage_payload_espnow_unicast_test_response_MSGTYPE alox_EspNowUnicastTestResponse
|
||||
#define alox_UartMessage_payload_ota_slave_progress_request_MSGTYPE alox_OtaSlaveProgressRequest
|
||||
#define alox_UartMessage_payload_ota_slave_progress_response_MSGTYPE alox_OtaSlaveProgressResponse
|
||||
|
||||
#define alox_Ack_FIELDLIST(X, a) \
|
||||
|
||||
@@ -386,6 +438,30 @@ X(a, STATIC, SINGULAR, UINT32, error, 4)
|
||||
#define alox_OtaStatusPayload_CALLBACK NULL
|
||||
#define alox_OtaStatusPayload_DEFAULT NULL
|
||||
|
||||
#define alox_OtaSlaveProgressRequest_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 1)
|
||||
#define alox_OtaSlaveProgressRequest_CALLBACK NULL
|
||||
#define alox_OtaSlaveProgressRequest_DEFAULT NULL
|
||||
|
||||
#define alox_OtaSlaveProgressEntry_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, client_id, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, bytes_written, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, total_bytes, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, status, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, error, 5)
|
||||
#define alox_OtaSlaveProgressEntry_CALLBACK NULL
|
||||
#define alox_OtaSlaveProgressEntry_DEFAULT NULL
|
||||
|
||||
#define alox_OtaSlaveProgressResponse_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, active, 1) \
|
||||
X(a, STATIC, SINGULAR, UINT32, total_bytes, 2) \
|
||||
X(a, STATIC, SINGULAR, UINT32, aggregate_bytes, 3) \
|
||||
X(a, STATIC, SINGULAR, UINT32, slave_count, 4) \
|
||||
X(a, STATIC, REPEATED, MESSAGE, slaves, 5)
|
||||
#define alox_OtaSlaveProgressResponse_CALLBACK NULL
|
||||
#define alox_OtaSlaveProgressResponse_DEFAULT NULL
|
||||
#define alox_OtaSlaveProgressResponse_slaves_MSGTYPE alox_OtaSlaveProgressEntry
|
||||
|
||||
extern const pb_msgdesc_t alox_UartMessage_msg;
|
||||
extern const pb_msgdesc_t alox_Ack_msg;
|
||||
extern const pb_msgdesc_t alox_EchoPayload_msg;
|
||||
@@ -402,6 +478,9 @@ extern const pb_msgdesc_t alox_OtaStartPayload_msg;
|
||||
extern const pb_msgdesc_t alox_OtaPayload_msg;
|
||||
extern const pb_msgdesc_t alox_OtaEndPayload_msg;
|
||||
extern const pb_msgdesc_t alox_OtaStatusPayload_msg;
|
||||
extern const pb_msgdesc_t alox_OtaSlaveProgressRequest_msg;
|
||||
extern const pb_msgdesc_t alox_OtaSlaveProgressEntry_msg;
|
||||
extern const pb_msgdesc_t alox_OtaSlaveProgressResponse_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define alox_UartMessage_fields &alox_UartMessage_msg
|
||||
@@ -420,6 +499,9 @@ extern const pb_msgdesc_t alox_OtaStatusPayload_msg;
|
||||
#define alox_OtaPayload_fields &alox_OtaPayload_msg
|
||||
#define alox_OtaEndPayload_fields &alox_OtaEndPayload_msg
|
||||
#define alox_OtaStatusPayload_fields &alox_OtaStatusPayload_msg
|
||||
#define alox_OtaSlaveProgressRequest_fields &alox_OtaSlaveProgressRequest_msg
|
||||
#define alox_OtaSlaveProgressEntry_fields &alox_OtaSlaveProgressEntry_msg
|
||||
#define alox_OtaSlaveProgressResponse_fields &alox_OtaSlaveProgressResponse_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
/* alox_UartMessage_size depends on runtime parameters */
|
||||
@@ -428,8 +510,7 @@ extern const pb_msgdesc_t alox_OtaStatusPayload_msg;
|
||||
/* alox_ClientInfo_size depends on runtime parameters */
|
||||
/* alox_ClientInfoResponse_size depends on runtime parameters */
|
||||
/* alox_ClientInputResponse_size depends on runtime parameters */
|
||||
/* alox_OtaPayload_size depends on runtime parameters */
|
||||
#define ALOX_MAIN_PROTO_UART_MESSAGES_PB_H_MAX_SIZE alox_OtaStatusPayload_size
|
||||
#define ALOX_UART_MESSAGES_PB_H_MAX_SIZE alox_OtaSlaveProgressResponse_size
|
||||
#define alox_AccelDeadzoneRequest_size 16
|
||||
#define alox_AccelDeadzoneResponse_size 20
|
||||
#define alox_Ack_size 0
|
||||
@@ -437,6 +518,10 @@ extern const pb_msgdesc_t alox_OtaStatusPayload_msg;
|
||||
#define alox_EspNowUnicastTestRequest_size 12
|
||||
#define alox_EspNowUnicastTestResponse_size 8
|
||||
#define alox_OtaEndPayload_size 0
|
||||
#define alox_OtaPayload_size 209
|
||||
#define alox_OtaSlaveProgressEntry_size 30
|
||||
#define alox_OtaSlaveProgressRequest_size 6
|
||||
#define alox_OtaSlaveProgressResponse_size 532
|
||||
#define alox_OtaStartPayload_size 6
|
||||
#define alox_OtaStatusPayload_size 24
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ enum MessageType {
|
||||
OTA_END = 18;
|
||||
OTA_STATUS = 19;
|
||||
OTA_START_ESPNOW = 20;
|
||||
OTA_SLAVE_PROGRESS = 21;
|
||||
}
|
||||
|
||||
message UartMessage {
|
||||
@@ -36,6 +37,8 @@ message UartMessage {
|
||||
AccelDeadzoneResponse accel_deadzone_response = 12;
|
||||
EspNowUnicastTestRequest espnow_unicast_test_request = 13;
|
||||
EspNowUnicastTestResponse espnow_unicast_test_response = 14;
|
||||
OtaSlaveProgressRequest ota_slave_progress_request = 15;
|
||||
OtaSlaveProgressResponse ota_slave_progress_response = 16;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,10 +122,32 @@ message OtaPayload {
|
||||
message OtaEndPayload {}
|
||||
|
||||
// Device → host status (also used as ACK after each 4 KiB written).
|
||||
// status: 1=preparing, 2=ready, 3=block_ack, 4=success, 5=failed
|
||||
// status: 1=preparing, 2=ready, 3=block_ack, 4=success, 5=failed, 6=distributing
|
||||
message OtaStatusPayload {
|
||||
uint32 status = 1;
|
||||
uint32 bytes_written = 2;
|
||||
uint32 target_slot = 3;
|
||||
uint32 error = 4;
|
||||
}
|
||||
|
||||
// Host → master: query ESP-NOW slave OTA progress (client_id 0 = all slaves in session).
|
||||
message OtaSlaveProgressRequest {
|
||||
uint32 client_id = 1;
|
||||
}
|
||||
|
||||
message OtaSlaveProgressEntry {
|
||||
uint32 client_id = 1;
|
||||
uint32 bytes_written = 2;
|
||||
uint32 total_bytes = 3;
|
||||
/** 0=idle, 1=preparing, 2=ready, 3=distributing, 4=success, 5=failed */
|
||||
uint32 status = 4;
|
||||
uint32 error = 5;
|
||||
}
|
||||
|
||||
message OtaSlaveProgressResponse {
|
||||
bool active = 1;
|
||||
uint32 total_bytes = 2;
|
||||
uint32 aggregate_bytes = 3;
|
||||
uint32 slave_count = 4;
|
||||
repeated OtaSlaveProgressEntry slaves = 5 [(nanopb).max_count = 16];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user