@@ -1310,15 +1310,51 @@ int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_
1310
1310
return ble_hs_err_to_errno (err );
1311
1311
}
1312
1312
1313
+ STATIC bool match_char_uuid (const mp_obj_bluetooth_uuid_t * filter_uuid , const ble_uuid_any_t * result_uuid ) {
1314
+ if (!filter_uuid ) {
1315
+ return true;
1316
+ }
1317
+ ble_uuid_any_t filter_uuid_nimble ;
1318
+ create_nimble_uuid (filter_uuid , & filter_uuid_nimble );
1319
+ return ble_uuid_cmp (& result_uuid -> u , & filter_uuid_nimble .u ) == 0 ;
1320
+ }
1321
+
1313
1322
STATIC int ble_gattc_characteristic_cb (uint16_t conn_handle , const struct ble_gatt_error * error , const struct ble_gatt_chr * characteristic , void * arg ) {
1314
1323
DEBUG_printf ("ble_gattc_characteristic_cb: conn_handle=%d status=%d def_handle=%d val_handle=%d\n" , conn_handle , error -> status , characteristic ? characteristic -> def_handle : -1 , characteristic ? characteristic -> val_handle : -1 );
1315
1324
if (!mp_bluetooth_is_active ()) {
1316
1325
return 0 ;
1317
1326
}
1327
+
1328
+ mp_bluetooth_nimble_pending_characteristic_t * pending = & MP_STATE_PORT (bluetooth_nimble_root_pointers )-> pending_char_result ;
1329
+ if (pending -> ready ) {
1330
+ // If there's a pending characteristic, we now know what it's end handle is, report it up to modbluetooth.
1331
+ pending -> ready = 0 ;
1332
+
1333
+ // The end handle will either be the end of the query range (there are
1334
+ // no more results), or one before the current result's definition
1335
+ // handle.
1336
+ uint16_t end_handle = MP_STATE_PORT (bluetooth_nimble_root_pointers )-> char_disc_end_handle ;
1337
+ if (error -> status == 0 ) {
1338
+ end_handle = characteristic -> def_handle - 1 ;
1339
+ }
1340
+
1341
+ // Assume same conn_handle because we're limiting to a single active discovery.
1342
+ mp_bluetooth_gattc_on_characteristic_result (conn_handle , pending -> value_handle , end_handle , pending -> properties , & pending -> uuid );
1343
+ }
1344
+
1318
1345
if (error -> status == 0 ) {
1319
- mp_obj_bluetooth_uuid_t characteristic_uuid = create_mp_uuid (& characteristic -> uuid );
1320
- mp_bluetooth_gattc_on_characteristic_result (conn_handle , characteristic -> def_handle , characteristic -> val_handle , characteristic -> properties , & characteristic_uuid );
1346
+ // If there's no filter, or the filter matches, then save this result.
1347
+ if (match_char_uuid (MP_STATE_PORT (bluetooth_nimble_root_pointers )-> char_filter_uuid , & characteristic -> uuid )) {
1348
+ pending -> value_handle = characteristic -> val_handle ;
1349
+ pending -> properties = characteristic -> properties ;
1350
+ pending -> uuid = create_mp_uuid (& characteristic -> uuid );
1351
+ pending -> ready = 1 ;
1352
+ }
1321
1353
} else {
1354
+ // Finished (or failed). Allow another characteristic discovery to start.
1355
+ MP_STATE_PORT (bluetooth_nimble_root_pointers )-> char_disc_end_handle = 0 ;
1356
+
1357
+ // Report completion.
1322
1358
mp_bluetooth_gattc_on_discover_complete (MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_DONE , conn_handle , error -> status == BLE_HS_EDONE ? 0 : error -> status );
1323
1359
}
1324
1360
return 0 ;
@@ -1328,13 +1364,29 @@ int mp_bluetooth_gattc_discover_characteristics(uint16_t conn_handle, uint16_t s
1328
1364
if (!mp_bluetooth_is_active ()) {
1329
1365
return ERRNO_BLUETOOTH_NOT_ACTIVE ;
1330
1366
}
1331
- int err ;
1332
- if (uuid ) {
1333
- ble_uuid_any_t nimble_uuid ;
1334
- create_nimble_uuid (uuid , & nimble_uuid );
1335
- err = ble_gattc_disc_chrs_by_uuid (conn_handle , start_handle , end_handle , & nimble_uuid .u , & ble_gattc_characteristic_cb , NULL );
1336
- } else {
1337
- err = ble_gattc_disc_all_chrs (conn_handle , start_handle , end_handle , & ble_gattc_characteristic_cb , NULL );
1367
+
1368
+ // The implementation of characteristic discovery queries for all
1369
+ // characteristics, and then UUID filtering is applied by NimBLE on each
1370
+ // characteristic. Unfortunately, each characteristic result does not
1371
+ // include its end handle, so you need to know the next characteristic
1372
+ // before you can raise the previous one to modbluetooth. But if we let
1373
+ // NimBLE do the filtering, then we don't necessarily see the next one.
1374
+ // So we make NimBLE return all results and do the filtering here instead.
1375
+
1376
+ if (MP_STATE_PORT (bluetooth_nimble_root_pointers )-> char_disc_end_handle ) {
1377
+ // Only allow a single discovery (otherwise we'd need to track a
1378
+ // pending characteristic per conn handle).
1379
+ return MP_EBUSY ;
1380
+ }
1381
+
1382
+ // Set the uuid filter (if any). This needs to be a root pointer,
1383
+ // otherwise we'd use ble_gattc_disc_all_chrs's arg param.
1384
+ MP_STATE_PORT (bluetooth_nimble_root_pointers )-> char_filter_uuid = uuid ;
1385
+
1386
+ int err = ble_gattc_disc_all_chrs (conn_handle , start_handle , end_handle , & ble_gattc_characteristic_cb , NULL );
1387
+ if (!err ) {
1388
+ // Lock out concurrent characteristic discovery.
1389
+ MP_STATE_PORT (bluetooth_nimble_root_pointers )-> char_disc_end_handle = end_handle ;
1338
1390
}
1339
1391
return ble_hs_err_to_errno (err );
1340
1392
}
0 commit comments