Ryan Malloy 5a853c15fc Fix event system init and add SSP auto-accept for E2E testing
Two fixes for the E2E test failures:

1. event_reporter_init() was never called in app_main(), so the
   FreeRTOS queue and reporter task were never created. Every BT
   event (pair_request, gatt_read, gatt_write, gatt_subscribe)
   was silently dropped at the NULL-queue guard.

2. SSP Numeric Comparison requires both sides to confirm, but
   bt_pair blocks until completion — creating a deadlock since
   the LLM can't send classic_pair_respond while waiting. Added
   auto_accept flag to set_ssp_mode that auto-confirms numeric
   comparison requests in the GAP callback.
2026-02-02 21:05:28 -07:00

103 lines
2.9 KiB
C

#include "protocol.h"
#include "uart_handler.h"
#include "event_reporter.h"
#include "cmd_dispatcher.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_chip_info.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "cJSON.h"
#include <string.h>
#include <stdlib.h>
#define FW_VERSION "0.1.0"
static const char *TAG = "main";
static void send_boot_event(void)
{
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;
}
cJSON *data = cJSON_CreateObject();
cJSON_AddStringToObject(data, "fw_version", FW_VERSION);
cJSON_AddStringToObject(data, "chip_model", model);
cJSON_AddNumberToObject(data, "cores", chip.cores);
cJSON_AddNumberToObject(data, "revision", chip.revision);
cJSON_AddNumberToObject(data, "free_heap", (double)esp_get_free_heap_size());
uart_send_event(EVT_BOOT, data);
}
void app_main(void)
{
/* NVS -- needed for Bluetooth bonding storage */
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_LOGW(TAG, "NVS partition issue, erasing and re-initializing");
ESP_ERROR_CHECK(nvs_flash_erase());
ESP_ERROR_CHECK(nvs_flash_init());
} else {
ESP_ERROR_CHECK(ret);
}
uart_handler_init();
event_reporter_init();
send_boot_event();
cmd_dispatcher_init();
ESP_LOGI(TAG, "mcbluetooth-esp32 v%s ready", FW_VERSION);
/* Main command loop */
for (;;) {
char *line = uart_read_line();
if (!line) {
continue;
}
cJSON *root = cJSON_Parse(line);
if (!root) {
ESP_LOGE(TAG, "bad JSON: %.64s", line);
/* best-effort error -- no id available */
uart_send_response("?", STATUS_ERROR,
cJSON_CreateString("invalid JSON"));
free(line);
continue;
}
const cJSON *j_id = cJSON_GetObjectItem(root, "id");
const cJSON *j_cmd = cJSON_GetObjectItem(root, "cmd");
cJSON *j_params = cJSON_GetObjectItem(root, "params");
const char *id = cJSON_IsString(j_id) ? j_id->valuestring : "?";
const char *cmd = cJSON_IsString(j_cmd) ? j_cmd->valuestring : NULL;
if (!cmd) {
ESP_LOGE(TAG, "missing 'cmd' field");
uart_send_response(id, STATUS_ERROR,
cJSON_CreateString("missing 'cmd' field"));
} else {
cmd_dispatch(id, cmd, j_params);
}
cJSON_Delete(root);
free(line);
}
}