#include "cmd_led_ring.h" #include "client_registry.h" #include "esp_log.h" #include "esp_now_comm.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 #define LED_RING_MODE_COLOR 5 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); } bool cmd_led_ring_apply(const alox_LedRingProgressRequest *req) { if (req == NULL) { return false; } 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); return true; case LED_RING_MODE_COLOR: cmd.mode = LED_CMD_SET_COLOR; cmd.r = r; cmd.g = g; cmd.b = b; cmd.intensity = intensity; led_ring_send_command(&cmd); return true; case LED_RING_MODE_PROGRESS: { cmd.mode = LED_CMD_PROGRESS; cmd.progress = clamp_progress(req->progress); cmd.r = r; cmd.g = g; cmd.b = b; cmd.intensity = intensity; led_ring_send_command(&cmd); return true; } case LED_RING_MODE_DIGIT: if (req->digit > 10) { return false; } 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); return true; case LED_RING_MODE_FIND_ME: led_ring_find_me(); return true; 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); return true; default: return false; } } static void reply(bool success, uint32_t mode, uint32_t progress, uint32_t digit, uint32_t client_id, uint32_t slaves_updated) { 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; response.payload.led_ring_progress_response.client_id = client_id; response.payload.led_ring_progress_response.slaves_updated = slaves_updated; uart_cmd_send(&response, TAG); } static esp_err_t push_led_ring_to_slave(const client_info_t *client, const alox_LedRingProgressRequest *req) { if (client == NULL || req == NULL) { return ESP_ERR_INVALID_ARG; } return esp_now_comm_send_led_ring(client->mac, client->id, req); } 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, 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; if (req.all_clients) { size_t n = client_registry_count(); uint32_t sent = 0; for (size_t i = 0; i < n; i++) { const client_info_t *client = client_registry_at(i); if (client == NULL) { continue; } if (push_led_ring_to_slave(client, &req) == ESP_OK) { sent++; } } bool local_ok = true; if (!req.slaves_only) { local_ok = cmd_led_ring_apply(&req); } ESP_LOGI(TAG, "LED ring mode %lu → %u/%u slaves%s", (unsigned long)mode, (unsigned)sent, (unsigned)n, req.slaves_only ? "" : " + master"); reply(local_ok || sent > 0, mode, req.progress, req.digit, 0, sent); return; } if (req.client_id == 0) { bool ok = cmd_led_ring_apply(&req); ESP_LOGI(TAG, "LED ring mode %lu on master", (unsigned long)mode); reply(ok, mode, req.progress, req.digit, 0, 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, mode, req.progress, req.digit, req.client_id, 0); return; } esp_err_t err = push_led_ring_to_slave(client, &req); if (err == ESP_OK) { ESP_LOGI(TAG, "LED ring mode %lu → slave %lu", (unsigned long)mode, (unsigned long)req.client_id); } else { ESP_LOGW(TAG, "LED ring to slave %lu failed: %s", (unsigned long)req.client_id, esp_err_to_name(err)); } reply(err == ESP_OK, mode, req.progress, req.digit, req.client_id, err == ESP_OK ? 1 : 0); } void cmd_led_ring_register(void) { uart_cmd_register(alox_MessageType_LED_RING, handle_led_ring); }