Fix mouse coordinates, sequence BLE discovery/encryption, and prevent mouse from disabling on-screen keyboard

This commit is contained in:
Adolfo Reyna
2026-06-26 21:47:08 -04:00
parent 68bf8f5a01
commit 28ff01561a
13 changed files with 912 additions and 42 deletions
@@ -815,7 +815,9 @@ static error_t api_scan_start(struct Device* device) {
struct ble_gap_disc_params disc_params = {};
disc_params.passive = 0;
disc_params.filter_duplicates = 1;
disc_params.filter_duplicates = 0;
disc_params.itvl = 160; // 100 ms
disc_params.window = 160; // 100 ms
uint8_t own_addr_type;
ble_hs_id_infer_auto(0, &own_addr_type);
@@ -21,6 +21,14 @@ constexpr auto* TAG = "esp32_ble_scan";
// Using BleCtx* (not Device*) so we avoid keeping a static Device reference.
static BleCtx* s_scan_ctx = nullptr;
struct LoggedDevice {
ble_addr_t addr;
bool has_name;
};
constexpr size_t MAX_LOGGED_DEVICES = 128;
static LoggedDevice s_logged_devices[MAX_LOGGED_DEVICES];
static size_t s_logged_count = 0;
// ---- Scan data helpers ----
void ble_scan_clear_results(struct Device* device) {
@@ -28,6 +36,8 @@ void ble_scan_clear_results(struct Device* device) {
xSemaphoreTake(ctx->scan_mutex, portMAX_DELAY);
ctx->scan_count = 0;
memset(ctx->scan_results, 0, sizeof(ctx->scan_results));
s_logged_count = 0;
memset(s_logged_devices, 0, sizeof(s_logged_devices));
xSemaphoreGive(ctx->scan_mutex);
}
@@ -49,7 +59,8 @@ int ble_gap_disc_event_handler(struct ble_gap_event* event, void* arg) {
record.connected = false;
struct ble_hs_adv_fields fields;
if (ble_hs_adv_parse_fields(&fields, disc.data, disc.length_data) == 0) {
bool parsed_fields = (ble_hs_adv_parse_fields(&fields, disc.data, disc.length_data) == 0);
if (parsed_fields) {
if (fields.name != nullptr && fields.name_len > 0) {
size_t copy_len = std::min<size_t>(fields.name_len, BT_NAME_MAX);
memcpy(record.name, fields.name, copy_len);
@@ -57,6 +68,7 @@ int ble_gap_disc_event_handler(struct ble_gap_event* event, void* arg) {
}
}
bool should_publish = false;
{
xSemaphoreTake(ctx->scan_mutex, portMAX_DELAY);
bool found = false;
@@ -65,32 +77,99 @@ int ble_gap_disc_event_handler(struct ble_gap_event* event, void* arg) {
// Deduplicate: merge name from SCAN_RSP without clobbering ADV_IND name
if (record.name[0] != '\0') {
memcpy(ctx->scan_results[i].name, record.name, BT_NAME_MAX + 1);
} else {
// If this packet doesn't have a name, keep the previously discovered name
memcpy(record.name, ctx->scan_results[i].name, BT_NAME_MAX + 1);
}
ctx->scan_results[i].rssi = record.rssi;
found = true;
should_publish = (record.name[0] != '\0');
break;
}
}
if (!found && ctx->scan_count < 64) {
if (!found && record.name[0] != '\0' && ctx->scan_count < 64) {
ctx->scan_results[ctx->scan_count] = record;
ctx->scan_addrs[ctx->scan_count] = disc.addr; // full addr (type+val)
ctx->scan_count++;
should_publish = true;
}
xSemaphoreGive(ctx->scan_mutex);
}
struct BtEvent e = {};
e.type = BT_EVENT_PEER_FOUND;
e.peer = record;
ble_publish_event(device, e);
// USB Serial logging for unique devices
bool logged_already = false;
size_t found_idx = 0;
for (size_t i = 0; i < s_logged_count; ++i) {
if (s_logged_devices[i].addr.type == disc.addr.type &&
memcmp(s_logged_devices[i].addr.val, disc.addr.val, BT_ADDR_LEN) == 0) {
logged_already = true;
found_idx = i;
break;
}
}
bool name_updated = false;
if (logged_already) {
if (!s_logged_devices[found_idx].has_name && record.name[0] != '\0') {
s_logged_devices[found_idx].has_name = true;
name_updated = true;
}
}
if (!logged_already && s_logged_count < MAX_LOGGED_DEVICES) {
s_logged_devices[s_logged_count].addr = disc.addr;
s_logged_devices[s_logged_count].has_name = (record.name[0] != '\0');
s_logged_count++;
}
if (!logged_already || name_updated) {
char mac_str[18];
snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x",
disc.addr.val[5], disc.addr.val[4], disc.addr.val[3],
disc.addr.val[2], disc.addr.val[1], disc.addr.val[0]);
char extra_info[128] = "";
int pos = 0;
if (parsed_fields) {
if (fields.appearance_is_present) {
pos += snprintf(extra_info + pos, sizeof(extra_info) - pos, " App:0x%04x", fields.appearance);
}
if (fields.num_uuids16 > 0) {
pos += snprintf(extra_info + pos, sizeof(extra_info) - pos, " UUID16:%d", (int)fields.num_uuids16);
if (fields.uuids16 != nullptr) {
uint16_t u16 = fields.uuids16[0].value;
pos += snprintf(extra_info + pos, sizeof(extra_info) - pos, "(0x%04x)", (int)u16);
}
}
if (fields.num_uuids128 > 0) {
pos += snprintf(extra_info + pos, sizeof(extra_info) - pos, " UUID128:%d", (int)fields.num_uuids128);
}
if (fields.mfg_data_len > 0) {
pos += snprintf(extra_info + pos, sizeof(extra_info) - pos, " Mfg:%d", (int)fields.mfg_data_len);
}
}
LOG_I(TAG, "[BLE SCAN] Unique Device: MAC=%s RSSI=%d Name=%s%s%s",
mac_str, (int)record.rssi, record.name[0] ? record.name : "<null>",
extra_info, name_updated ? " (Name Updated)" : "");
}
if (should_publish) {
struct BtEvent e = {};
e.type = BT_EVENT_PEER_FOUND;
e.peer = record;
ble_publish_event(device, e);
}
break;
}
case BLE_GAP_EVENT_DISC_COMPLETE:
LOG_I(TAG, "Scan complete (reason=%d)", event->disc_complete.reason);
// Keep scan_active=true; resolveNextUnnamedPeer clears it and fires ScanFinished
// once name resolution finishes, so the UI spinner stays active throughout.
ble_resolve_next_unnamed_peer(device, 0);
ble_set_scan_active(device, false);
{
struct BtEvent e = {};
e.type = BT_EVENT_SCAN_FINISHED;
ble_publish_event(device, e);
}
break;
default: