Move UART command handlers into main/cmd/ for clearer layout.
Add cmd/ to CMake include paths and update documentation paths. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
#include "bosch456.h"
|
||||
#include "client_registry.h"
|
||||
#include "cmd_accel_deadzone.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_now_comm.h"
|
||||
#include "pod_settings.h"
|
||||
#include "uart_cmd.h"
|
||||
|
||||
static const char *TAG = "[ACCEL_DZ]";
|
||||
|
||||
static void reply(uint32_t deadzone, uint32_t client_id, bool success,
|
||||
uint32_t slaves_updated) {
|
||||
alox_UartMessage response;
|
||||
uart_cmd_init_response(&response, alox_MessageType_ACCEL_DEADZONE,
|
||||
alox_UartMessage_accel_deadzone_response_tag);
|
||||
response.payload.accel_deadzone_response.deadzone = deadzone;
|
||||
response.payload.accel_deadzone_response.client_id = client_id;
|
||||
response.payload.accel_deadzone_response.success = success;
|
||||
response.payload.accel_deadzone_response.slaves_updated = slaves_updated;
|
||||
uart_cmd_send(&response, TAG);
|
||||
}
|
||||
|
||||
static void apply_local_deadzone(uint32_t deadzone) {
|
||||
bma456_set_accel_deadzone(deadzone);
|
||||
if (pod_settings_save_accel_deadzone(deadzone) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "deadzone %lu applied but not saved to NVS",
|
||||
(unsigned long)deadzone);
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t push_deadzone_to_slave(const client_info_t *client,
|
||||
uint32_t deadzone) {
|
||||
if (client == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t err = client_registry_set_accel_deadzone(client->id, deadzone);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return esp_now_comm_send_accel_deadzone(client->mac, client->id, deadzone);
|
||||
}
|
||||
|
||||
static void handle_accel_deadzone(const uint8_t *data, size_t len) {
|
||||
alox_UartMessage uart_msg;
|
||||
alox_AccelDeadzoneRequest req = alox_AccelDeadzoneRequest_init_zero;
|
||||
|
||||
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "decode failed");
|
||||
reply(BMA456_DEFAULT_ACCEL_DEADZONE, 0, false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const alox_AccelDeadzoneRequest *req_ptr = UART_CMD_REQ(
|
||||
&uart_msg, alox_UartMessage_accel_deadzone_request_tag,
|
||||
accel_deadzone_request);
|
||||
if (req_ptr != NULL) {
|
||||
req = *req_ptr;
|
||||
}
|
||||
|
||||
if (req.write) {
|
||||
if (req.all_clients) {
|
||||
size_t n = client_registry_set_accel_deadzone_all(req.deadzone);
|
||||
uint32_t sent = 0;
|
||||
|
||||
for (size_t i = 0; i < client_registry_count(); i++) {
|
||||
const client_info_t *client = client_registry_at(i);
|
||||
if (client == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (esp_now_comm_send_accel_deadzone(client->mac, client->id,
|
||||
req.deadzone) == ESP_OK) {
|
||||
sent++;
|
||||
}
|
||||
}
|
||||
|
||||
if (bma456_is_ready()) {
|
||||
apply_local_deadzone(req.deadzone);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "set deadzone %lu via unicast to %u/%u slaves",
|
||||
(unsigned long)req.deadzone, (unsigned)sent, (unsigned)n);
|
||||
reply(req.deadzone, 0, sent > 0 || bma456_is_ready(), sent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.client_id == 0) {
|
||||
apply_local_deadzone(req.deadzone);
|
||||
ESP_LOGI(TAG, "set local deadzone %lu (no ESP-NOW; use -client or -all "
|
||||
"for slaves)",
|
||||
(unsigned long)req.deadzone);
|
||||
reply(req.deadzone, 0, true, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const client_info_t *client = client_registry_find_by_id(req.client_id);
|
||||
if (client == NULL) {
|
||||
ESP_LOGW(TAG, "client id %lu not found",
|
||||
(unsigned long)req.client_id);
|
||||
reply(req.deadzone, req.client_id, false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err = push_deadzone_to_slave(client, req.deadzone);
|
||||
reply(req.deadzone, req.client_id, err == ESP_OK, err == ESP_OK);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.all_clients || req.client_id == 0) {
|
||||
reply(bma456_get_accel_deadzone(), 0, true, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t dz = 0;
|
||||
esp_err_t err = client_registry_get_accel_deadzone(req.client_id, &dz);
|
||||
reply(dz, req.client_id, err == ESP_OK, 0);
|
||||
}
|
||||
|
||||
void cmd_accel_deadzone_register(void) {
|
||||
uart_cmd_register(alox_MessageType_ACCEL_DEADZONE, handle_accel_deadzone);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CMD_ACCEL_DEADZONE_H
|
||||
#define CMD_ACCEL_DEADZONE_H
|
||||
|
||||
void cmd_accel_deadzone_register(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
#include "client_registry.h"
|
||||
#include "cmd_client_info.h"
|
||||
#include "esp_log.h"
|
||||
#include "pb_encode.h"
|
||||
#include "uart_cmd.h"
|
||||
|
||||
static const char *TAG = "[CLIENT_INFO]";
|
||||
|
||||
static bool encode_clients_list(pb_ostream_t *stream, const pb_field_t *field,
|
||||
void *const *arg) {
|
||||
(void)arg;
|
||||
|
||||
size_t count = client_registry_count();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
const client_info_t *client = client_registry_at(i);
|
||||
if (client == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uart_cmd_bytes_t mac = {.data = client->mac, .len = CLIENT_MAC_LEN};
|
||||
|
||||
alox_ClientInfo proto = alox_ClientInfo_init_zero;
|
||||
proto.id = client->id;
|
||||
proto.available = client->available;
|
||||
proto.used = client->used;
|
||||
proto.last_ping = client_registry_ms_since(client->last_ping_at);
|
||||
proto.last_success_ping =
|
||||
client_registry_ms_since(client->last_success_ping_at);
|
||||
proto.version = client->version;
|
||||
proto.mac.funcs.encode = uart_cmd_encode_bytes;
|
||||
proto.mac.arg = &mac;
|
||||
|
||||
if (!pb_encode_tag_for_field(stream, field)) {
|
||||
return false;
|
||||
}
|
||||
if (!pb_encode_submessage(stream, alox_ClientInfo_fields, &proto)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void handle_client_info(const uint8_t *data, size_t len) {
|
||||
(void)data;
|
||||
(void)len;
|
||||
|
||||
alox_UartMessage response;
|
||||
uart_cmd_init_response(&response, alox_MessageType_CLIENT_INFO,
|
||||
alox_UartMessage_client_info_response_tag);
|
||||
response.payload.client_info_response.clients.funcs.encode = encode_clients_list;
|
||||
response.payload.client_info_response.clients.arg = NULL;
|
||||
|
||||
ESP_LOGI(TAG, "sending %u clients", (unsigned)client_registry_count());
|
||||
uart_cmd_send(&response, TAG);
|
||||
}
|
||||
|
||||
void cmd_client_info_register(void) {
|
||||
uart_cmd_register(alox_MessageType_CLIENT_INFO, handle_client_info);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CMD_CLIENT_INFO_H
|
||||
#define CMD_CLIENT_INFO_H
|
||||
|
||||
void cmd_client_info_register(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
#include "client_registry.h"
|
||||
#include "cmd_espnow_find_me.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_now_comm.h"
|
||||
#include "led_ring.h"
|
||||
#include "uart_cmd.h"
|
||||
|
||||
static const char *TAG = "[FIND_ME]";
|
||||
|
||||
static void reply(bool success, uint32_t client_id) {
|
||||
alox_UartMessage response;
|
||||
uart_cmd_init_response(&response, alox_MessageType_FIND_ME,
|
||||
alox_UartMessage_espnow_find_me_response_tag);
|
||||
response.payload.espnow_find_me_response.success = success;
|
||||
response.payload.espnow_find_me_response.client_id = client_id;
|
||||
uart_cmd_send(&response, TAG);
|
||||
}
|
||||
|
||||
static void handle_find_me(const uint8_t *data, size_t len) {
|
||||
alox_UartMessage uart_msg;
|
||||
|
||||
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "decode failed");
|
||||
reply(false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const alox_EspNowFindMeRequest *req = UART_CMD_REQ(
|
||||
&uart_msg, alox_UartMessage_espnow_find_me_request_tag,
|
||||
espnow_find_me_request);
|
||||
if (req == NULL) {
|
||||
ESP_LOGW(TAG, "missing find_me request");
|
||||
reply(false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->client_id == 0) {
|
||||
led_ring_find_me();
|
||||
ESP_LOGI(TAG, "find-me on master");
|
||||
reply(true, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const client_info_t *client = client_registry_find_by_id(req->client_id);
|
||||
if (client == NULL) {
|
||||
ESP_LOGW(TAG, "client id %lu not in registry",
|
||||
(unsigned long)req->client_id);
|
||||
reply(false, req->client_id);
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_now_comm_send_find_me(client->mac, req->client_id);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "find-me sent to slave %lu", (unsigned long)req->client_id);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "find-me to slave %lu failed: %s",
|
||||
(unsigned long)req->client_id, esp_err_to_name(err));
|
||||
}
|
||||
reply(err == ESP_OK, req->client_id);
|
||||
}
|
||||
|
||||
void cmd_espnow_find_me_register(void) {
|
||||
uart_cmd_register(alox_MessageType_FIND_ME, handle_find_me);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CMD_ESPNOW_FIND_ME_H
|
||||
#define CMD_ESPNOW_FIND_ME_H
|
||||
|
||||
void cmd_espnow_find_me_register(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "client_registry.h"
|
||||
#include "cmd_espnow_unicast_test.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_now_comm.h"
|
||||
#include "uart_cmd.h"
|
||||
|
||||
static const char *TAG = "[UNICAST_TEST]";
|
||||
|
||||
static void reply(bool success, uint32_t seq) {
|
||||
alox_UartMessage response;
|
||||
uart_cmd_init_response(&response, alox_MessageType_ESPNOW_UNICAST_TEST,
|
||||
alox_UartMessage_espnow_unicast_test_response_tag);
|
||||
response.payload.espnow_unicast_test_response.success = success;
|
||||
response.payload.espnow_unicast_test_response.seq = seq;
|
||||
uart_cmd_send(&response, TAG);
|
||||
}
|
||||
|
||||
static void handle_espnow_unicast_test(const uint8_t *data, size_t len) {
|
||||
alox_UartMessage uart_msg;
|
||||
|
||||
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "decode failed");
|
||||
reply(false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const alox_EspNowUnicastTestRequest *req = UART_CMD_REQ(
|
||||
&uart_msg, alox_UartMessage_espnow_unicast_test_request_tag,
|
||||
espnow_unicast_test_request);
|
||||
if (req == NULL || req->client_id == 0) {
|
||||
ESP_LOGW(TAG, "need client_id in request");
|
||||
reply(false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const client_info_t *client = client_registry_find_by_id(req->client_id);
|
||||
if (client == NULL) {
|
||||
ESP_LOGW(TAG, "client id %lu not in registry",
|
||||
(unsigned long)req->client_id);
|
||||
reply(false, req->seq);
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_now_comm_send_unicast_test(client->mac, req->seq);
|
||||
reply(err == ESP_OK, req->seq);
|
||||
}
|
||||
|
||||
void cmd_espnow_unicast_test_register(void) {
|
||||
uart_cmd_register(alox_MessageType_ESPNOW_UNICAST_TEST,
|
||||
handle_espnow_unicast_test);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CMD_ESPNOW_UNICAST_TEST_H
|
||||
#define CMD_ESPNOW_UNICAST_TEST_H
|
||||
|
||||
void cmd_espnow_unicast_test_register(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,127 @@
|
||||
#include "cmd_handler.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
#include "uart_messages.pb.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_HANDLERS 32
|
||||
|
||||
static const char *TAG = "[CMDH]";
|
||||
static QueueHandle_t cmd_queue;
|
||||
static msg_binding_t handlers[MAX_HANDLERS];
|
||||
static int handler_count;
|
||||
|
||||
static const char *message_type_name(uint16_t id) {
|
||||
switch ((alox_MessageType)id) {
|
||||
case alox_MessageType_ACK:
|
||||
return "ACK";
|
||||
case alox_MessageType_ECHO:
|
||||
return "ECHO";
|
||||
case alox_MessageType_VERSION:
|
||||
return "VERSION";
|
||||
case alox_MessageType_CLIENT_INFO:
|
||||
return "CLIENT_INFO";
|
||||
case alox_MessageType_CLIENT_INPUT:
|
||||
return "CLIENT_INPUT";
|
||||
case alox_MessageType_ACCEL_DEADZONE:
|
||||
return "ACCEL_DEADZONE";
|
||||
case alox_MessageType_ESPNOW_UNICAST_TEST:
|
||||
return "ESPNOW_UNICAST_TEST";
|
||||
case alox_MessageType_LED_RING:
|
||||
return "LED_RING";
|
||||
case alox_MessageType_OTA_START:
|
||||
return "OTA_START";
|
||||
case alox_MessageType_OTA_PAYLOAD:
|
||||
return "OTA_PAYLOAD";
|
||||
case alox_MessageType_OTA_END:
|
||||
return "OTA_END";
|
||||
case alox_MessageType_OTA_STATUS:
|
||||
return "OTA_STATUS";
|
||||
case alox_MessageType_OTA_START_ESPNOW:
|
||||
return "OTA_START_ESPNOW";
|
||||
case alox_MessageType_OTA_SLAVE_PROGRESS:
|
||||
return "OTA_SLAVE_PROGRESS";
|
||||
case alox_MessageType_FIND_ME:
|
||||
return "FIND_ME";
|
||||
case alox_MessageType_RESTART:
|
||||
return "RESTART";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
void init_cmdHandler(QueueHandle_t queue) {
|
||||
cmd_queue = queue;
|
||||
if (xTaskCreate(vCmdDispatcherTask, "cmd_dispatch", 8192, NULL, 5, NULL) !=
|
||||
pdPASS) {
|
||||
ESP_LOGE(TAG, "failed to create cmd_dispatch task");
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t msg_register_handler(uint16_t id, msg_callback_t cb) {
|
||||
if (cb == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
for (int i = 0; i < handler_count; i++) {
|
||||
if (handlers[i].msg_id == id) {
|
||||
handlers[i].callback = cb;
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
if (handler_count >= MAX_HANDLERS) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
handlers[handler_count].msg_id = id;
|
||||
handlers[handler_count].callback = cb;
|
||||
handler_count++;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t msg_post(uint16_t id, const uint8_t *data, size_t len) {
|
||||
if (cmd_queue == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
generic_msg_t msg = {.msg_id = id, .len = len, .payload = NULL};
|
||||
if (len > 0) {
|
||||
msg.payload = malloc(len);
|
||||
if (msg.payload == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memcpy(msg.payload, data, len);
|
||||
}
|
||||
|
||||
if (xQueueSend(cmd_queue, &msg, pdMS_TO_TICKS(100)) != pdPASS) {
|
||||
free(msg.payload);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void vCmdDispatcherTask(void *param) {
|
||||
(void)param;
|
||||
generic_msg_t msg;
|
||||
|
||||
while (1) {
|
||||
if (xQueueReceive(cmd_queue, &msg, portMAX_DELAY) == pdPASS) {
|
||||
bool handled = false;
|
||||
for (int i = 0; i < handler_count; i++) {
|
||||
if (handlers[i].msg_id == msg.msg_id) {
|
||||
ESP_LOGI(TAG, "trigger command %s (0x%02x)", message_type_name(msg.msg_id),
|
||||
(unsigned)msg.msg_id);
|
||||
handlers[i].callback(msg.payload, msg.len);
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!handled) {
|
||||
ESP_LOGW(TAG, "no handler for %s (0x%02x)", message_type_name(msg.msg_id),
|
||||
(unsigned)msg.msg_id);
|
||||
}
|
||||
free(msg.payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef CMD_HANDLER_H
|
||||
#define CMD_HANDLER_H
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "freertos/idf_additions.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t msg_id;
|
||||
uint8_t *payload;
|
||||
size_t len;
|
||||
} generic_msg_t;
|
||||
|
||||
typedef void (*msg_callback_t)(const uint8_t *data, size_t len);
|
||||
|
||||
typedef struct {
|
||||
uint16_t msg_id;
|
||||
msg_callback_t callback;
|
||||
} msg_binding_t;
|
||||
|
||||
void init_cmdHandler(QueueHandle_t queue);
|
||||
void vCmdDispatcherTask(void *param);
|
||||
|
||||
esp_err_t msg_register_handler(uint16_t id, msg_callback_t cb);
|
||||
esp_err_t msg_post(uint16_t id, const uint8_t *data, size_t len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,146 @@
|
||||
#include "cmd_led_ring.h"
|
||||
#include "esp_log.h"
|
||||
#include "led_ring.h"
|
||||
#include "uart_cmd.h"
|
||||
|
||||
static const char *TAG = "[LED_RING_CMD]";
|
||||
|
||||
#define LED_RING_MODE_CLEAR 0
|
||||
#define LED_RING_MODE_PROGRESS 1
|
||||
#define LED_RING_MODE_DIGIT 2
|
||||
#define LED_RING_MODE_BLINK 3
|
||||
#define LED_RING_MODE_FIND_ME 4
|
||||
|
||||
static uint8_t clamp_u8(uint32_t v) {
|
||||
if (v > 255) {
|
||||
return 255;
|
||||
}
|
||||
return (uint8_t)v;
|
||||
}
|
||||
|
||||
static uint8_t clamp_progress(uint32_t v) {
|
||||
if (v > 100) {
|
||||
return 100;
|
||||
}
|
||||
return (uint8_t)v;
|
||||
}
|
||||
|
||||
static uint8_t resolve_intensity(uint32_t intensity) {
|
||||
if (intensity == 0) {
|
||||
return LED_RING_DEFAULT_INTENSITY;
|
||||
}
|
||||
return clamp_u8(intensity);
|
||||
}
|
||||
|
||||
static void reply(bool success, uint32_t mode, uint32_t progress, uint32_t digit) {
|
||||
alox_UartMessage response;
|
||||
uart_cmd_init_response(&response, alox_MessageType_LED_RING,
|
||||
alox_UartMessage_led_ring_progress_response_tag);
|
||||
response.payload.led_ring_progress_response.success = success;
|
||||
response.payload.led_ring_progress_response.mode = mode;
|
||||
response.payload.led_ring_progress_response.progress = progress;
|
||||
response.payload.led_ring_progress_response.digit = digit;
|
||||
uart_cmd_send(&response, TAG);
|
||||
}
|
||||
|
||||
static void handle_led_ring(const uint8_t *data, size_t len) {
|
||||
alox_UartMessage uart_msg;
|
||||
alox_LedRingProgressRequest req = alox_LedRingProgressRequest_init_zero;
|
||||
|
||||
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "decode failed");
|
||||
reply(false, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const alox_LedRingProgressRequest *req_ptr = UART_CMD_REQ(
|
||||
&uart_msg, alox_UartMessage_led_ring_progress_request_tag,
|
||||
led_ring_progress_request);
|
||||
if (req_ptr != NULL) {
|
||||
req = *req_ptr;
|
||||
}
|
||||
|
||||
uint32_t mode = req.mode;
|
||||
uint8_t r = clamp_u8(req.r);
|
||||
uint8_t g = clamp_u8(req.g);
|
||||
uint8_t b = clamp_u8(req.b);
|
||||
uint8_t intensity = resolve_intensity(req.intensity);
|
||||
|
||||
led_command_t cmd = {0};
|
||||
|
||||
switch (mode) {
|
||||
case LED_RING_MODE_CLEAR:
|
||||
cmd.mode = LED_CMD_CLEAR;
|
||||
led_ring_send_command(&cmd);
|
||||
ESP_LOGI(TAG, "clear");
|
||||
reply(true, mode, 0, 0);
|
||||
return;
|
||||
|
||||
case LED_RING_MODE_PROGRESS: {
|
||||
uint8_t progress = clamp_progress(req.progress);
|
||||
cmd.mode = LED_CMD_PROGRESS;
|
||||
cmd.progress = progress;
|
||||
cmd.r = r;
|
||||
cmd.g = g;
|
||||
cmd.b = b;
|
||||
cmd.intensity = intensity;
|
||||
led_ring_send_command(&cmd);
|
||||
ESP_LOGI(TAG, "progress %u%% rgb=%u,%u,%u", (unsigned)progress,
|
||||
(unsigned)r, (unsigned)g, (unsigned)b);
|
||||
reply(true, mode, progress, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
case LED_RING_MODE_DIGIT: {
|
||||
if (req.digit > 10) {
|
||||
ESP_LOGW(TAG, "digit %lu out of range", (unsigned long)req.digit);
|
||||
reply(false, mode, 0, req.digit);
|
||||
return;
|
||||
}
|
||||
cmd.mode = LED_CMD_SET_DIGIT;
|
||||
cmd.value = (uint8_t)req.digit;
|
||||
cmd.r = r;
|
||||
cmd.g = g;
|
||||
cmd.b = b;
|
||||
cmd.intensity = intensity;
|
||||
led_ring_send_command(&cmd);
|
||||
ESP_LOGI(TAG, "digit %u rgb=%u,%u,%u", (unsigned)cmd.value, (unsigned)r,
|
||||
(unsigned)g, (unsigned)b);
|
||||
reply(true, mode, 0, req.digit);
|
||||
return;
|
||||
}
|
||||
|
||||
case LED_RING_MODE_FIND_ME:
|
||||
led_ring_find_me();
|
||||
ESP_LOGI(TAG, "find-me");
|
||||
reply(true, mode, 0, 0);
|
||||
return;
|
||||
|
||||
case LED_RING_MODE_BLINK: {
|
||||
cmd.mode = LED_CMD_BLINK;
|
||||
cmd.r = r;
|
||||
cmd.g = g;
|
||||
cmd.b = b;
|
||||
cmd.intensity = intensity;
|
||||
cmd.blink_ms = (uint16_t)(req.blink_ms > 0 ? req.blink_ms : 350);
|
||||
cmd.blink_count = req.blink_count > 0 ? (uint8_t)req.blink_count : 1;
|
||||
if (cmd.blink_count == 0) {
|
||||
cmd.blink_count = 1;
|
||||
}
|
||||
led_ring_send_command(&cmd);
|
||||
ESP_LOGI(TAG, "blink x%u %u ms rgb=%u,%u,%u", (unsigned)cmd.blink_count,
|
||||
(unsigned)cmd.blink_ms, (unsigned)r, (unsigned)g, (unsigned)b);
|
||||
reply(true, mode, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
ESP_LOGW(TAG, "unknown mode %lu", (unsigned long)mode);
|
||||
reply(false, mode, 0, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_led_ring_register(void) {
|
||||
uart_cmd_register(alox_MessageType_LED_RING, handle_led_ring);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CMD_LED_RING_H
|
||||
#define CMD_LED_RING_H
|
||||
|
||||
void cmd_led_ring_register(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,339 @@
|
||||
#include "cmd_ota.h"
|
||||
#include "led_ring.h"
|
||||
#include "ota_espnow.h"
|
||||
#include "ota_uart.h"
|
||||
#include "uart_cmd.h"
|
||||
#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
|
||||
|
||||
/** UART OTA upload to this node (master). */
|
||||
#define OTA_LED_UART_R 0
|
||||
#define OTA_LED_UART_G 0
|
||||
#define OTA_LED_UART_B 255
|
||||
/** ESP-NOW distribution from master to slaves. */
|
||||
#define OTA_LED_ESPNOW_TX_R 0
|
||||
#define OTA_LED_ESPNOW_TX_G 255
|
||||
#define OTA_LED_ESPNOW_TX_B 0
|
||||
|
||||
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,
|
||||
alox_UartMessage_ota_status_tag);
|
||||
response.payload.ota_status.status = (uint32_t)status;
|
||||
response.payload.ota_status.bytes_written = ota_uart_bytes_written();
|
||||
int slot = ota_uart_target_slot();
|
||||
response.payload.ota_status.target_slot =
|
||||
slot >= 0 ? (uint32_t)slot : 0;
|
||||
response.payload.ota_status.error = err_code;
|
||||
uart_cmd_send(&response, TAG);
|
||||
}
|
||||
|
||||
static void send_ota_failed(uint32_t err_code) {
|
||||
led_ring_ota_failed();
|
||||
send_ota_status(OTA_UART_ST_FAILED, err_code);
|
||||
}
|
||||
|
||||
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)slave_count;
|
||||
led_ring_show_ota_progress(bytes_done, total_bytes, OTA_LED_ESPNOW_TX_R,
|
||||
OTA_LED_ESPNOW_TX_G, OTA_LED_ESPNOW_TX_B);
|
||||
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;
|
||||
|
||||
send_ota_status(OTA_UART_ST_PREPARING, 0);
|
||||
|
||||
int slot = ota_uart_prepare(total_size);
|
||||
if (slot < 0) {
|
||||
send_ota_failed(1);
|
||||
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_READY;
|
||||
response.payload.ota_status.bytes_written = 0;
|
||||
response.payload.ota_status.target_slot = (uint32_t)slot;
|
||||
response.payload.ota_status.error = 0;
|
||||
uart_cmd_send(&response, TAG);
|
||||
|
||||
led_ring_show_ota_progress(0, total_size, OTA_LED_UART_R, OTA_LED_UART_G,
|
||||
OTA_LED_UART_B);
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void handle_ota_start(const uint8_t *data, size_t len) {
|
||||
alox_UartMessage uart_msg;
|
||||
alox_OtaStartPayload req = alox_OtaStartPayload_init_zero;
|
||||
|
||||
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
||||
send_ota_failed( 2);
|
||||
return;
|
||||
}
|
||||
|
||||
const alox_OtaStartPayload *req_ptr =
|
||||
UART_CMD_REQ(&uart_msg, alox_UartMessage_ota_start_tag, ota_start);
|
||||
if (req_ptr != NULL) {
|
||||
req = *req_ptr;
|
||||
}
|
||||
|
||||
if (req.total_size == 0) {
|
||||
ESP_LOGW(TAG, "OTA_START: total_size required");
|
||||
send_ota_failed( 3);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ota_uart_is_active()) {
|
||||
ESP_LOGW(TAG, "OTA_START while session active");
|
||||
send_ota_failed( 4);
|
||||
return;
|
||||
}
|
||||
|
||||
if (xTaskCreate(ota_prepare_task, "ota_prepare", OTA_PREPARE_STACK,
|
||||
(void *)(uintptr_t)req.total_size, OTA_PREPARE_PRIO,
|
||||
NULL) != pdPASS) {
|
||||
ESP_LOGE(TAG, "failed to create ota_prepare task");
|
||||
send_ota_failed( 5);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_ota_payload(const uint8_t *data, size_t len) {
|
||||
alox_UartMessage uart_msg;
|
||||
|
||||
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "OTA_PAYLOAD decode failed");
|
||||
send_ota_failed( 10);
|
||||
return;
|
||||
}
|
||||
|
||||
const alox_OtaPayload *req_ptr =
|
||||
UART_CMD_REQ(&uart_msg, alox_UartMessage_ota_payload_tag, ota_payload);
|
||||
if (req_ptr == NULL) {
|
||||
ESP_LOGW(TAG, "OTA_PAYLOAD: missing ota_payload (which=%u)",
|
||||
(unsigned)uart_msg.which_payload);
|
||||
send_ota_failed( 11);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req_ptr->data.size == 0) {
|
||||
ESP_LOGW(TAG, "OTA_PAYLOAD: empty data (seq=%lu)",
|
||||
(unsigned long)req_ptr->seq);
|
||||
send_ota_failed( 11);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ota_uart_is_active()) {
|
||||
ESP_LOGW(TAG, "OTA_PAYLOAD without active session (seq=%lu)",
|
||||
(unsigned long)req_ptr->seq);
|
||||
send_ota_failed( 12);
|
||||
return;
|
||||
}
|
||||
|
||||
ota_feed_result_t r =
|
||||
ota_uart_feed(req_ptr->data.bytes, req_ptr->data.size);
|
||||
if (r == OTA_FEED_ERROR) {
|
||||
send_ota_failed( 13);
|
||||
return;
|
||||
}
|
||||
if (r == OTA_FEED_BLOCK_WRITTEN) {
|
||||
uint32_t total = ota_uart_total_size();
|
||||
uint32_t done = ota_uart_bytes_written();
|
||||
ESP_LOGI(TAG, "OTA block ack (%lu bytes in flash)",
|
||||
(unsigned long)done);
|
||||
led_ring_show_ota_progress(done, total, OTA_LED_UART_R, OTA_LED_UART_G,
|
||||
OTA_LED_UART_B);
|
||||
send_ota_status(OTA_UART_ST_BLOCK_ACK, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (r == OTA_FEED_OK) {
|
||||
uint32_t total = ota_uart_total_size();
|
||||
if (total > 0) {
|
||||
led_ring_show_ota_progress(ota_uart_bytes_received(), total,
|
||||
OTA_LED_UART_R, OTA_LED_UART_G, OTA_LED_UART_B);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_failed( 30);
|
||||
free(job);
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
led_ring_show_ota_progress(0, image_size, OTA_LED_ESPNOW_TX_R, OTA_LED_ESPNOW_TX_G,
|
||||
OTA_LED_ESPNOW_TX_B);
|
||||
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_failed(31);
|
||||
free(job);
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
err = ota_uart_apply_boot();
|
||||
if (err != ESP_OK) {
|
||||
send_ota_failed((uint32_t)err);
|
||||
free(job);
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
led_ring_show_ota_progress(image_size, image_size, OTA_LED_ESPNOW_TX_R,
|
||||
OTA_LED_ESPNOW_TX_G, OTA_LED_ESPNOW_TX_B);
|
||||
|
||||
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 = 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);
|
||||
|
||||
led_ring_ota_success();
|
||||
free(job);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void handle_ota_end(const uint8_t *data, size_t len) {
|
||||
(void)data;
|
||||
(void)len;
|
||||
|
||||
if (!ota_uart_is_active()) {
|
||||
send_ota_failed( 20);
|
||||
return;
|
||||
}
|
||||
|
||||
ota_dist_job_t *job = calloc(1, sizeof(*job));
|
||||
if (job == NULL) {
|
||||
send_ota_failed( 21);
|
||||
return;
|
||||
}
|
||||
job->written = ota_uart_bytes_written();
|
||||
job->slot = ota_uart_target_slot();
|
||||
uint32_t uart_total = ota_uart_total_size();
|
||||
|
||||
bool success = false;
|
||||
esp_err_t err = ota_uart_finish(false, &success);
|
||||
if (err != ESP_OK || !success) {
|
||||
send_ota_failed((uint32_t)err);
|
||||
free(job);
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_total > 0) {
|
||||
led_ring_show_ota_progress(job->written, uart_total, OTA_LED_UART_R,
|
||||
OTA_LED_UART_G, OTA_LED_UART_B);
|
||||
}
|
||||
|
||||
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_failed( 22);
|
||||
free(job);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_ota_start_espnow(const uint8_t *data, size_t len) {
|
||||
(void)data;
|
||||
(void)len;
|
||||
|
||||
if (ota_uart_is_active()) {
|
||||
send_ota_failed( 40);
|
||||
return;
|
||||
}
|
||||
|
||||
const esp_partition_t *part = NULL;
|
||||
uint32_t image_size = 0;
|
||||
if (!ota_uart_get_staged_image(&part, &image_size)) {
|
||||
send_ota_failed( 41);
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err = ota_espnow_distribute(part, image_size, &s_dist_progress);
|
||||
if (err != ESP_OK) {
|
||||
send_ota_failed( 42);
|
||||
return;
|
||||
}
|
||||
|
||||
err = ota_uart_apply_boot();
|
||||
if (err != ESP_OK) {
|
||||
send_ota_failed( (uint32_t)err);
|
||||
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 = image_size;
|
||||
response.payload.ota_status.error = 0;
|
||||
uart_cmd_send(&response, TAG);
|
||||
led_ring_ota_success();
|
||||
}
|
||||
|
||||
void cmd_ota_register(void) {
|
||||
uart_cmd_register(alox_MessageType_OTA_START, handle_ota_start);
|
||||
uart_cmd_register(alox_MessageType_OTA_PAYLOAD, handle_ota_payload);
|
||||
uart_cmd_register(alox_MessageType_OTA_END, handle_ota_end);
|
||||
uart_cmd_register(alox_MessageType_OTA_START_ESPNOW, handle_ota_start_espnow);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CMD_OTA_H
|
||||
#define CMD_OTA_H
|
||||
|
||||
void cmd_ota_register(void);
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "client_registry.h"
|
||||
#include "cmd_restart.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_now_comm.h"
|
||||
#include "pod_reboot.h"
|
||||
#include "uart_cmd.h"
|
||||
|
||||
static const char *TAG = "[RESTART_CMD]";
|
||||
|
||||
static void reply(bool success, uint32_t client_id) {
|
||||
alox_UartMessage response;
|
||||
uart_cmd_init_response(&response, alox_MessageType_RESTART,
|
||||
alox_UartMessage_restart_response_tag);
|
||||
response.payload.restart_response.success = success;
|
||||
response.payload.restart_response.client_id = client_id;
|
||||
uart_cmd_send(&response, TAG);
|
||||
}
|
||||
|
||||
static void handle_restart(const uint8_t *data, size_t len) {
|
||||
alox_UartMessage uart_msg;
|
||||
|
||||
if (uart_cmd_decode(data, len, &uart_msg) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "decode failed");
|
||||
reply(false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const alox_RestartRequest *req = UART_CMD_REQ(
|
||||
&uart_msg, alox_UartMessage_restart_request_tag, restart_request);
|
||||
if (req == NULL) {
|
||||
ESP_LOGW(TAG, "missing restart request");
|
||||
reply(false, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->client_id == 0) {
|
||||
ESP_LOGI(TAG, "restart master");
|
||||
reply(true, 0);
|
||||
pod_schedule_restart();
|
||||
return;
|
||||
}
|
||||
|
||||
const client_info_t *client = client_registry_find_by_id(req->client_id);
|
||||
if (client == NULL) {
|
||||
ESP_LOGW(TAG, "client id %lu not in registry",
|
||||
(unsigned long)req->client_id);
|
||||
reply(false, req->client_id);
|
||||
return;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_now_comm_send_restart(client->mac, req->client_id);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "restart sent to slave %lu", (unsigned long)req->client_id);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "restart to slave %lu failed: %s",
|
||||
(unsigned long)req->client_id, esp_err_to_name(err));
|
||||
}
|
||||
reply(err == ESP_OK, req->client_id);
|
||||
}
|
||||
|
||||
void cmd_restart_register(void) {
|
||||
uart_cmd_register(alox_MessageType_RESTART, handle_restart);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CMD_RESTART_H
|
||||
#define CMD_RESTART_H
|
||||
|
||||
void cmd_restart_register(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "cmd_version.h"
|
||||
#include "app_config.h"
|
||||
#include "uart_cmd.h"
|
||||
|
||||
#ifndef POWERPOD_FW_VERSION
|
||||
#define POWERPOD_FW_VERSION 1u
|
||||
#endif
|
||||
|
||||
#ifndef POWERPOD_GIT_HASH
|
||||
#define POWERPOD_GIT_HASH "unknown"
|
||||
#endif
|
||||
|
||||
static const char *TAG = "[VERSION]";
|
||||
|
||||
static void handle_version(const uint8_t *data, size_t len) {
|
||||
(void)data;
|
||||
(void)len;
|
||||
|
||||
alox_UartMessage response;
|
||||
uart_cmd_init_response(&response, alox_MessageType_VERSION,
|
||||
alox_UartMessage_version_response_tag);
|
||||
response.payload.version_response.version = POWERPOD_FW_VERSION;
|
||||
response.payload.version_response.git_hash.funcs.encode = uart_cmd_encode_string;
|
||||
response.payload.version_response.git_hash.arg = (void *)POWERPOD_GIT_HASH;
|
||||
const app_config_t *cfg = app_config_get();
|
||||
if (cfg != NULL && cfg->running_partition[0] != '\0') {
|
||||
response.payload.version_response.running_partition.funcs.encode =
|
||||
uart_cmd_encode_string;
|
||||
response.payload.version_response.running_partition.arg =
|
||||
(void *)cfg->running_partition;
|
||||
}
|
||||
uart_cmd_send(&response, TAG);
|
||||
}
|
||||
|
||||
void cmd_version_register(void) {
|
||||
uart_cmd_register(alox_MessageType_VERSION, handle_version);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef CMD_VERSION_H
|
||||
#define CMD_VERSION_H
|
||||
|
||||
void cmd_version_register(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user