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.
This commit is contained in:
parent
397b164eee
commit
5a853c15fc
@ -46,6 +46,7 @@ static struct {
|
||||
esp_bt_io_cap_t io_cap;
|
||||
char pin_code[17];
|
||||
bool ssp_enabled;
|
||||
bool auto_accept; /* Auto-confirm SSP pairing (for testing) */
|
||||
/* Pending pairing state */
|
||||
char pending_pair_address[18];
|
||||
char pending_pair_cmd_id[32];
|
||||
@ -132,10 +133,16 @@ static void gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
|
||||
|
||||
event_report_pair_request(addr_str, "numeric_comparison", (int)passkey);
|
||||
|
||||
if (classic_state.auto_accept) {
|
||||
/* Auto-confirm for automated E2E testing */
|
||||
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
|
||||
ESP_LOGI(TAG, "cfm_req: auto-accepted (auto_accept=true)");
|
||||
} else {
|
||||
/* Stash address so pair_respond can reply */
|
||||
strncpy(classic_state.pending_pair_address, addr_str,
|
||||
sizeof(classic_state.pending_pair_address) - 1);
|
||||
classic_state.pair_type = PAIR_TYPE_NUMERIC_COMPARISON;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -575,11 +582,19 @@ void cmd_classic_set_ssp_mode(const char *id, cJSON *params)
|
||||
esp_bt_gap_set_security_param(ESP_BT_SP_IOCAP_MODE, &iocap,
|
||||
sizeof(iocap));
|
||||
|
||||
ESP_LOGI(TAG, "SSP mode set to '%s' (io_cap=%d)", mode, new_cap);
|
||||
/* Optional auto_accept flag for automated testing */
|
||||
const cJSON *j_auto = cJSON_GetObjectItem(params, "auto_accept");
|
||||
if (cJSON_IsBool(j_auto)) {
|
||||
classic_state.auto_accept = cJSON_IsTrue(j_auto);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "SSP mode set to '%s' (io_cap=%d, auto_accept=%d)",
|
||||
mode, new_cap, classic_state.auto_accept);
|
||||
|
||||
cJSON *data = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(data, "mode", mode);
|
||||
cJSON_AddNumberToObject(data, "io_cap", new_cap);
|
||||
cJSON_AddBoolToObject(data, "auto_accept", classic_state.auto_accept);
|
||||
uart_send_response(id, STATUS_OK, data);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "protocol.h"
|
||||
#include "uart_handler.h"
|
||||
#include "event_reporter.h"
|
||||
#include "cmd_dispatcher.h"
|
||||
|
||||
#include "nvs_flash.h"
|
||||
@ -57,6 +58,7 @@ void app_main(void)
|
||||
}
|
||||
|
||||
uart_handler_init();
|
||||
event_reporter_init();
|
||||
send_boot_event();
|
||||
cmd_dispatcher_init();
|
||||
|
||||
|
||||
@ -74,7 +74,10 @@ def register_tools(mcp: FastMCP) -> None:
|
||||
return {"error": str(e)}
|
||||
|
||||
@mcp.tool()
|
||||
async def esp32_set_ssp_mode(mode: str) -> dict[str, Any]:
|
||||
async def esp32_set_ssp_mode(
|
||||
mode: str,
|
||||
auto_accept: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
"""Set the Secure Simple Pairing (SSP) mode on the ESP32.
|
||||
|
||||
SSP mode determines which pairing association model the ESP32
|
||||
@ -90,6 +93,11 @@ def register_tools(mcp: FastMCP) -> None:
|
||||
io_cap).
|
||||
"passkey_display" — ESP32 displays a passkey for the
|
||||
remote device to enter.
|
||||
auto_accept: When true, the ESP32 automatically confirms
|
||||
numeric comparison pairing requests without waiting for
|
||||
a classic_pair_respond command. Useful for automated
|
||||
E2E testing where both sides need to confirm but the
|
||||
MCP tool calls are sequential.
|
||||
|
||||
Returns:
|
||||
Response data confirming the new SSP mode, or an error dict
|
||||
@ -99,9 +107,13 @@ def register_tools(mcp: FastMCP) -> None:
|
||||
if mode not in valid_modes:
|
||||
return {"error": f"Invalid SSP mode '{mode}'. Must be one of: {sorted(valid_modes)}"}
|
||||
|
||||
params: dict[str, Any] = {"mode": mode}
|
||||
if auto_accept:
|
||||
params["auto_accept"] = True
|
||||
|
||||
try:
|
||||
client = get_client()
|
||||
resp = await client.send_command(CMD_CLASSIC_SET_SSP_MODE, {"mode": mode})
|
||||
resp = await client.send_command(CMD_CLASSIC_SET_SSP_MODE, params)
|
||||
if resp.status == Status.OK:
|
||||
return resp.data
|
||||
return {"error": resp.data.get("error", "Failed to set SSP mode")}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user