#include "cmd_dispatcher.h" #include "protocol.h" #include "uart_handler.h" #include "esp_system.h" #include "esp_chip_info.h" #include "esp_timer.h" #include "esp_log.h" #include "esp_mac.h" #include "esp_bt.h" #include "cJSON.h" #include #define FW_VERSION "0.1.0" static const char *TAG = "dispatch"; typedef void (*cmd_handler_t)(const char *id, cJSON *params); typedef struct { const char *name; cmd_handler_t handler; } cmd_entry_t; /* Forward declarations for handlers in other modules */ extern void bt_classic_register_commands(void); extern void bt_ble_register_commands(void); extern void personas_register_commands(void); /* --- System command handlers --- */ static void handle_ping(const char *id, cJSON *params) { (void)params; cJSON *data = cJSON_CreateObject(); cJSON_AddBoolToObject(data, "pong", cJSON_True); uart_send_response(id, STATUS_OK, data); } static void handle_reset(const char *id, cJSON *params) { (void)params; uart_send_response(id, STATUS_OK, NULL); vTaskDelay(pdMS_TO_TICKS(100)); /* let the response flush */ esp_restart(); } static void handle_get_info(const char *id, cJSON *params) { (void)params; esp_chip_info_t chip; esp_chip_info(&chip); const char *model; switch (chip.model) { case CHIP_ESP32: model = "ESP32"; break; case CHIP_ESP32S2: model = "ESP32-S2"; break; case CHIP_ESP32S3: model = "ESP32-S3"; break; case CHIP_ESP32C3: model = "ESP32-C3"; break; case CHIP_ESP32H2: model = "ESP32-H2"; break; default: model = "unknown"; break; } /* Decode feature flags */ cJSON *features = cJSON_CreateArray(); if (chip.features & CHIP_FEATURE_WIFI_BGN) cJSON_AddItemToArray(features, cJSON_CreateString("wifi")); if (chip.features & CHIP_FEATURE_BT) cJSON_AddItemToArray(features, cJSON_CreateString("bt")); if (chip.features & CHIP_FEATURE_BLE) cJSON_AddItemToArray(features, cJSON_CreateString("ble")); /* BT MAC address */ uint8_t mac[6]; esp_read_mac(mac, ESP_MAC_BT); char mac_str[18]; snprintf(mac_str, sizeof(mac_str), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); cJSON *data = cJSON_CreateObject(); cJSON_AddStringToObject(data, "chip_model", model); cJSON_AddItemToObject(data, "features", features); cJSON_AddNumberToObject(data, "revision", chip.revision); cJSON_AddNumberToObject(data, "cores", chip.cores); cJSON_AddStringToObject(data, "fw_version", FW_VERSION); cJSON_AddNumberToObject(data, "free_heap", (double)esp_get_free_heap_size()); cJSON_AddStringToObject(data, "bt_mac", mac_str); uart_send_response(id, STATUS_OK, data); } static void handle_get_status(const char *id, cJSON *params) { (void)params; int64_t uptime_ms = esp_timer_get_time() / 1000; cJSON *data = cJSON_CreateObject(); cJSON_AddNumberToObject(data, "uptime_ms", (double)uptime_ms); cJSON_AddNumberToObject(data, "free_heap", (double)esp_get_free_heap_size()); cJSON_AddBoolToObject(data, "bt_enabled", cJSON_False); cJSON_AddBoolToObject(data, "ble_enabled", cJSON_False); uart_send_response(id, STATUS_OK, data); } /* --- Command table --- */ static const cmd_entry_t cmd_table[] = { { CMD_PING, handle_ping }, { CMD_RESET, handle_reset }, { CMD_GET_INFO, handle_get_info }, { CMD_GET_STATUS, handle_get_status }, { NULL, NULL } /* sentinel */ }; void cmd_dispatcher_init(void) { ESP_LOGI(TAG, "command dispatcher ready"); /* Future: these will register their own handlers into the table */ /* bt_classic_register_commands(); */ /* bt_ble_register_commands(); */ /* personas_register_commands(); */ } void cmd_dispatch(const char *id, const char *cmd, cJSON *params) { for (const cmd_entry_t *entry = cmd_table; entry->name != NULL; entry++) { if (strcmp(entry->name, cmd) == 0) { entry->handler(id, params); return; } } ESP_LOGW(TAG, "unknown command: %s", cmd); cJSON *err = cJSON_CreateObject(); cJSON_AddStringToObject(err, "error", "unknown_command"); cJSON_AddStringToObject(err, "cmd", cmd); uart_send_response(id, STATUS_ERROR, err); }