From 6fbfef63587af014cf2ccb211ba9353b71de545f Mon Sep 17 00:00:00 2001 From: andy Date: Thu, 10 Sep 2026 23:46:09 +0100 Subject: [PATCH] Fix BLE apps not scanning: use ACI GAP procedures, not raw HCI On device, scanning failed (BT Inspector showed the scan as stopped and found nothing). The firmware's GAP layer is initialised by the bt service, and ST's stack disallows raw hci_le_set_scan_* / hci_le_create_connection in that state. Switch the shared central layer to the GAP procedures: aci_gap_start_ observation_proc / aci_gap_terminate_gap_proc(GAP_OBSERVATION_PROC) for scanning, and aci_gap_create_connection (+ terminate the direct-connection proc to cancel) for connecting, with a short settle after stopping observation. Also surface the raw BLE status code on BT Inspector's scan screen ("err 0xNN") so any remaining failure is diagnosable on device. Needs the gap command group exported (BLE_API default is all). Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01LEaD4ZeAfvWLBUxXp8G11r --- bt_inspector/bt_inspector.c | 9 +++++++-- libble/ble_central.c | 19 ++++++++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/bt_inspector/bt_inspector.c b/bt_inspector/bt_inspector.c index d25bea3..b39c5ef 100644 --- a/bt_inspector/bt_inspector.c +++ b/bt_inspector/bt_inspector.c @@ -66,6 +66,7 @@ typedef struct { BcDevice devs[BC_MAX_DEVICES]; size_t count, sel, top; bool scanning; + uint8_t scan_err; } ScanModel; typedef struct { @@ -328,7 +329,10 @@ static void scan_draw(Canvas* c, void* m_) { canvas_set_font(c, FontPrimary); canvas_draw_str(c, 2, 9, "BT Inspector"); canvas_set_font(c, FontSecondary); - furi_string_printf(s, m->scanning ? "%u found" : "%u (stopped)", (unsigned)m->count); + if(m->scanning) + furi_string_printf(s, "%u found", (unsigned)m->count); + else + furi_string_printf(s, "err 0x%02X", m->scan_err); canvas_draw_str_aligned(c, 126, 9, AlignRight, AlignBottom, furi_string_get_cstr(s)); canvas_draw_line(c, 0, 11, 127, 11); if(!m->count) canvas_draw_str_aligned(c, 64, 40, AlignCenter, AlignCenter, "Scanning..."); @@ -389,7 +393,8 @@ static void scan_enter(void* ctx) { app->cur_view = ViewScan; bool ok = bc_scan_start(app->bc); if(!ok) app_log(app, "SCAN START FAILED 0x%02X", bc_last_error(app->bc)); - with_view_model(app->scan_view, ScanModel * m, { m->scanning = ok; }, true); + uint8_t err = ok ? 0 : bc_last_error(app->bc); + with_view_model(app->scan_view, ScanModel * m, { m->scanning = ok; m->scan_err = err; }, true); } // ---- page view (scrollable text with optional buttons) ----------------------- diff --git a/libble/ble_central.c b/libble/ble_central.c index 7088fd2..3d9cd10 100644 --- a/libble/ble_central.c +++ b/libble/ble_central.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -314,9 +315,11 @@ void bc_free(BleCentral* bc) { bool bc_scan_start(BleCentral* bc) { if(bc->scanning) return true; - // active scan, 50 ms interval / 30 ms window; no duplicate filtering so RSSI stays live - tBleStatus st = hci_le_set_scan_parameters(0x01, 0x50, 0x30, OWN_ADDR_TYPE, 0x00); - if(st == BLE_STATUS_SUCCESS) st = hci_le_set_scan_enable(0x01, 0x00); + // Active scan, 50 ms interval / 30 ms window, public address, no duplicate + // filtering (so RSSI stays live), accept-all filter policy. The firmware's + // GAP is initialised, so we must use the GAP observation procedure; raw + // hci_le_set_scan_* returns "command disallowed" in that state. + tBleStatus st = aci_gap_start_observation_proc(0x0050, 0x0030, 0x01, OWN_ADDR_TYPE, 0x00, 0x00); if(st != BLE_STATUS_SUCCESS) { FURI_LOG_E(TAG, "scan start failed: 0x%02X", st); bc->last_error = st; @@ -328,7 +331,7 @@ bool bc_scan_start(BleCentral* bc) { void bc_scan_stop(BleCentral* bc) { if(!bc->scanning) return; - hci_le_set_scan_enable(0x00, 0x00); + aci_gap_terminate_gap_proc(GAP_OBSERVATION_PROC); bc->scanning = false; } @@ -407,9 +410,11 @@ bool bc_connect(BleCentral* bc, const BcDevice* dev, uint32_t timeout_ms) { furi_event_flag_clear(bc->flags, FlagConnected | FlagConnFailed | FlagDisconnected | FlagDone); bc->connecting = true; bc->mtu = 23; + // Observation must fully stop before starting a connection procedure. + furi_delay_ms(100); // scan 60/30 ms, conn interval 30-50 ms, latency 0, supervision 5 s - tBleStatus st = hci_le_create_connection( - 0x60, 0x30, 0x00, dev->addr_type, dev->addr, OWN_ADDR_TYPE, 0x18, 0x28, 0, 0x01F4, 0, 0); + tBleStatus st = aci_gap_create_connection( + 0x60, 0x30, dev->addr_type, dev->addr, OWN_ADDR_TYPE, 0x18, 0x28, 0, 0x01F4, 0, 0); if(st != BLE_STATUS_SUCCESS) { FURI_LOG_E(TAG, "create_connection failed: 0x%02X", st); bc->connecting = false; @@ -418,7 +423,7 @@ bool bc_connect(BleCentral* bc, const BcDevice* dev, uint32_t timeout_ms) { } uint32_t f = furi_event_flag_wait(bc->flags, FlagConnected | FlagConnFailed, FuriFlagWaitAny, timeout_ms); if(f & FuriFlagError) { - hci_le_create_connection_cancel(); + aci_gap_terminate_gap_proc(GAP_DIRECT_CONNECTION_ESTABLISHMENT_PROC); f = furi_event_flag_wait(bc->flags, FlagConnected | FlagConnFailed, FuriFlagWaitAny, 2000); if(!(f & FlagConnected)) { bc->connecting = false;