summaryrefslogtreecommitdiff
path: root/extmod/nimble/modbluetooth_nimble.c
diff options
context:
space:
mode:
authorJim Mussared <jim.mussared@gmail.com>2022-08-09 16:50:58 +1000
committerDamien George <damien@micropython.org>2022-09-09 11:24:24 +1000
commitcacc96d98c2a70dc7e5194331ea70746c39746ec (patch)
tree08e45e414002f694d5510e4f7f00540df799fd04 /extmod/nimble/modbluetooth_nimble.c
parent82fc16f2982b38f6dfd0145b8012b34308d13605 (diff)
extmod/modbluetooth: Replace def_handle with end_handle in char IRQ.
This is technically a breaking change, but: a) We need the end handle to do descriptor discovery properly. b) We have no possible use for the existing definition handle in the characteristic result IRQ. None of the methods can use it, and therefore no existing code should be using it in a way that changing it to a different integer value should break. Unfortunately NimBLE doesn't make it easy to get the end handle, so also implement a mechanism to use the following characteristic to calculate the previous characteristic's end handle. Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
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);
}