summaryrefslogtreecommitdiff
path: root/extmod/nimble/modbluetooth_nimble.c
diff options
context:
space:
mode:
Diffstat (limited to 'extmod/nimble/modbluetooth_nimble.c')
-rw-r--r--extmod/nimble/modbluetooth_nimble.c70
1 files changed, 61 insertions, 9 deletions
diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c
index c26c09e61..b0194446b 100644
--- a/extmod/nimble/modbluetooth_nimble.c
+++ b/extmod/nimble/modbluetooth_nimble.c
@@ -1310,15 +1310,51 @@ int mp_bluetooth_gattc_discover_primary_services(uint16_t conn_handle, const mp_
return ble_hs_err_to_errno(err);
}
+STATIC bool match_char_uuid(const mp_obj_bluetooth_uuid_t *filter_uuid, const ble_uuid_any_t *result_uuid) {
+ if (!filter_uuid) {
+ return true;
+ }
+ ble_uuid_any_t filter_uuid_nimble;
+ create_nimble_uuid(filter_uuid, &filter_uuid_nimble);
+ return ble_uuid_cmp(&result_uuid->u, &filter_uuid_nimble.u) == 0;
+}
+
STATIC int ble_gattc_characteristic_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *characteristic, void *arg) {
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);
if (!mp_bluetooth_is_active()) {
return 0;
}
+
+ mp_bluetooth_nimble_pending_characteristic_t *pending = &MP_STATE_PORT(bluetooth_nimble_root_pointers)->pending_char_result;
+ if (pending->ready) {
+ // If there's a pending characteristic, we now know what it's end handle is, report it up to modbluetooth.
+ pending->ready = 0;
+
+ // The end handle will either be the end of the query range (there are
+ // no more results), or one before the current result's definition
+ // handle.
+ uint16_t end_handle = MP_STATE_PORT(bluetooth_nimble_root_pointers)->char_disc_end_handle;
+ if (error->status == 0) {
+ end_handle = characteristic->def_handle - 1;
+ }
+
+ // Assume same conn_handle because we're limiting to a single active discovery.
+ mp_bluetooth_gattc_on_characteristic_result(conn_handle, pending->value_handle, end_handle, pending->properties, &pending->uuid);
+ }
+
if (error->status == 0) {
- mp_obj_bluetooth_uuid_t characteristic_uuid = create_mp_uuid(&characteristic->uuid);
- mp_bluetooth_gattc_on_characteristic_result(conn_handle, characteristic->def_handle, characteristic->val_handle, characteristic->properties, &characteristic_uuid);
+ // If there's no filter, or the filter matches, then save this result.
+ if (match_char_uuid(MP_STATE_PORT(bluetooth_nimble_root_pointers)->char_filter_uuid, &characteristic->uuid)) {
+ pending->value_handle = characteristic->val_handle;
+ pending->properties = characteristic->properties;
+ pending->uuid = create_mp_uuid(&characteristic->uuid);
+ pending->ready = 1;
+ }
} else {
+ // Finished (or failed). Allow another characteristic discovery to start.
+ MP_STATE_PORT(bluetooth_nimble_root_pointers)->char_disc_end_handle = 0;
+
+ // Report completion.
mp_bluetooth_gattc_on_discover_complete(MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_DONE, conn_handle, error->status == BLE_HS_EDONE ? 0 : error->status);
}
return 0;
@@ -1328,13 +1364,29 @@ int mp_bluetooth_gattc_discover_characteristics(uint16_t conn_handle, uint16_t s
if (!mp_bluetooth_is_active()) {
return ERRNO_BLUETOOTH_NOT_ACTIVE;
}
- int err;
- if (uuid) {
- ble_uuid_any_t nimble_uuid;
- create_nimble_uuid(uuid, &nimble_uuid);
- err = ble_gattc_disc_chrs_by_uuid(conn_handle, start_handle, end_handle, &nimble_uuid.u, &ble_gattc_characteristic_cb, NULL);
- } else {
- err = ble_gattc_disc_all_chrs(conn_handle, start_handle, end_handle, &ble_gattc_characteristic_cb, NULL);
+
+ // The implementation of characteristic discovery queries for all
+ // characteristics, and then UUID filtering is applied by NimBLE on each
+ // characteristic. Unfortunately, each characteristic result does not
+ // include its end handle, so you need to know the next characteristic
+ // before you can raise the previous one to modbluetooth. But if we let
+ // NimBLE do the filtering, then we don't necessarily see the next one.
+ // So we make NimBLE return all results and do the filtering here instead.
+
+ if (MP_STATE_PORT(bluetooth_nimble_root_pointers)->char_disc_end_handle) {
+ // Only allow a single discovery (otherwise we'd need to track a
+ // pending characteristic per conn handle).
+ return MP_EBUSY;
+ }
+
+ // Set the uuid filter (if any). This needs to be a root pointer,
+ // otherwise we'd use ble_gattc_disc_all_chrs's arg param.
+ MP_STATE_PORT(bluetooth_nimble_root_pointers)->char_filter_uuid = uuid;
+
+ int err = ble_gattc_disc_all_chrs(conn_handle, start_handle, end_handle, &ble_gattc_characteristic_cb, NULL);
+ if (!err) {
+ // Lock out concurrent characteristic discovery.
+ MP_STATE_PORT(bluetooth_nimble_root_pointers)->char_disc_end_handle = end_handle;
}
return ble_hs_err_to_errno(err);
}