Skip to content

Commit 63a8db8

Browse files
authored
Merge pull request #9597 from tannewt/fix_ble_hid_peripheral
Implement more ESP BLE Descriptor support
2 parents a0a4e14 + fdc564c commit 63a8db8

File tree

6 files changed

+142
-101
lines changed

6 files changed

+142
-101
lines changed

ports/espressif/common-hal/_bleio/Adapter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable
8585

8686
// ble_hs_cfg.reset_cb = blecent_on_reset;
8787
ble_hs_cfg.sync_cb = _on_sync;
88-
// ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
88+
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
8989

9090
ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_NO_IO;
9191
ble_hs_cfg.sm_bonding = 1;

ports/espressif/common-hal/_bleio/Characteristic.c

Lines changed: 3 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -22,32 +22,6 @@
2222

2323
static int characteristic_on_ble_gap_evt(struct ble_gap_event *event, void *param);
2424

25-
static volatile int _completion_status;
26-
static uint64_t _timeout_start_time;
27-
28-
static void _reset_completion_status(void) {
29-
_completion_status = 0;
30-
}
31-
32-
// Wait for a status change, recorded in a callback.
33-
// Try twice because sometimes we get a BLE_HS_EAGAIN.
34-
// Maybe we should try more than twice.
35-
static int _wait_for_completion(uint32_t timeout_msecs) {
36-
for (int tries = 1; tries <= 2; tries++) {
37-
_timeout_start_time = common_hal_time_monotonic_ms();
38-
while ((_completion_status == 0) &&
39-
(common_hal_time_monotonic_ms() < _timeout_start_time + timeout_msecs) &&
40-
!mp_hal_is_interrupted()) {
41-
RUN_BACKGROUND_TASKS;
42-
}
43-
if (_completion_status != BLE_HS_EAGAIN) {
44-
// Quit, because either the status is either zero (OK) or it's an error.
45-
break;
46-
}
47-
}
48-
return _completion_status;
49-
}
50-
5125
void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service,
5226
uint16_t handle, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props,
5327
bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm,
@@ -151,35 +125,7 @@ bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_character
151125
return self->service;
152126
}
153127

154-
typedef struct {
155-
uint8_t *buf;
156-
uint16_t len;
157-
} _read_info_t;
158-
159-
static int _read_cb(uint16_t conn_handle,
160-
const struct ble_gatt_error *error,
161-
struct ble_gatt_attr *attr,
162-
void *arg) {
163-
_read_info_t *read_info = (_read_info_t *)arg;
164-
switch (error->status) {
165-
case 0: {
166-
int len = MIN(read_info->len, OS_MBUF_PKTLEN(attr->om));
167-
os_mbuf_copydata(attr->om, attr->offset, len, read_info->buf);
168-
read_info->len = len;
169-
}
170-
MP_FALLTHROUGH;
171-
172-
default:
173-
#if CIRCUITPY_VERBOSE_BLE
174-
// For debugging.
175-
mp_printf(&mp_plat_print, "Read status: %d\n", error->status);
176-
#endif
177-
break;
178-
}
179-
_completion_status = error->status;
180128

181-
return 0;
182-
}
183129

184130
size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self, uint8_t *buf, size_t len) {
185131
// Do GATT operations only if this characteristic has been added to a registered service.
@@ -188,14 +134,7 @@ size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *sel
188134
}
189135
uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection);
190136
if (common_hal_bleio_service_get_is_remote(self->service)) {
191-
_read_info_t read_info = {
192-
.buf = buf,
193-
.len = len
194-
};
195-
_reset_completion_status();
196-
CHECK_NIMBLE_ERROR(ble_gattc_read(conn_handle, self->handle, _read_cb, &read_info));
197-
CHECK_NIMBLE_ERROR(_wait_for_completion(2000));
198-
return read_info.len;
137+
return bleio_gattc_read(conn_handle, self->handle, buf, len);
199138
} else {
200139
len = MIN(self->current_value_len, len);
201140
memcpy(buf, self->current_value, len);
@@ -209,24 +148,13 @@ size_t common_hal_bleio_characteristic_get_max_length(bleio_characteristic_obj_t
209148
return self->max_length;
210149
}
211150

212-
static int _write_cb(uint16_t conn_handle,
213-
const struct ble_gatt_error *error,
214-
struct ble_gatt_attr *attr,
215-
void *arg) {
216-
_completion_status = error->status;
217-
218-
return 0;
219-
}
220-
221151
void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) {
222152
if (common_hal_bleio_service_get_is_remote(self->service)) {
223153
uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection);
224154
if ((self->props & CHAR_PROP_WRITE_NO_RESPONSE) != 0) {
225155
CHECK_NIMBLE_ERROR(ble_gattc_write_no_rsp_flat(conn_handle, self->handle, bufinfo->buf, bufinfo->len));
226156
} else {
227-
_reset_completion_status();
228-
CHECK_NIMBLE_ERROR(ble_gattc_write_flat(conn_handle, self->handle, bufinfo->buf, bufinfo->len, _write_cb, NULL));
229-
CHECK_NIMBLE_ERROR(_wait_for_completion(2000));
157+
bleio_gattc_write(conn_handle, self->handle, bufinfo->buf, bufinfo->len);
230158
}
231159
} else {
232160
// Validate data length for local characteristics only.
@@ -394,9 +322,7 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self,
394322
(notify ? 1 << 0 : 0) |
395323
(indicate ? 1 << 1: 0);
396324

397-
_reset_completion_status();
398-
CHECK_NIMBLE_ERROR(ble_gattc_write_flat(conn_handle, self->cccd_handle, &cccd_value, 2, _write_cb, NULL));
399-
CHECK_NIMBLE_ERROR(_wait_for_completion(2000));
325+
bleio_gattc_write(conn_handle, self->cccd_handle, (uint8_t *)&cccd_value, 2);
400326
}
401327

402328
void bleio_characteristic_set_observer(bleio_characteristic_obj_t *self, mp_obj_t observer) {

ports/espressif/common-hal/_bleio/Descriptor.c

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "py/runtime.h"
1111

1212
#include "shared-bindings/_bleio/__init__.h"
13+
#include "shared-bindings/_bleio/Attribute.h"
1314
#include "shared-bindings/_bleio/Descriptor.h"
1415
#include "shared-bindings/_bleio/Service.h"
1516
#include "shared-bindings/_bleio/UUID.h"
@@ -24,6 +25,31 @@ void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_c
2425
self->write_perm = write_perm;
2526
self->initial_value = mp_obj_new_bytes(initial_value_bufinfo->buf, initial_value_bufinfo->len);
2627

28+
// Map CP's property values to Nimble's flag values.
29+
self->flags = 0;
30+
if (read_perm != SECURITY_MODE_NO_ACCESS) {
31+
self->flags |= BLE_ATT_F_READ;
32+
}
33+
if (write_perm != SECURITY_MODE_NO_ACCESS) {
34+
self->flags |= BLE_ATT_F_WRITE;
35+
}
36+
if (read_perm == SECURITY_MODE_ENC_WITH_MITM || write_perm == SECURITY_MODE_ENC_WITH_MITM ||
37+
read_perm == SECURITY_MODE_SIGNED_WITH_MITM || write_perm == SECURITY_MODE_SIGNED_WITH_MITM) {
38+
mp_raise_NotImplementedError(MP_ERROR_TEXT("MITM security not supported"));
39+
}
40+
if (read_perm == SECURITY_MODE_ENC_NO_MITM) {
41+
self->flags |= BLE_ATT_F_READ_ENC;
42+
}
43+
if (read_perm == SECURITY_MODE_SIGNED_NO_MITM) {
44+
self->flags |= BLE_ATT_F_READ_AUTHEN;
45+
}
46+
if (write_perm == SECURITY_MODE_ENC_NO_MITM) {
47+
self->flags |= BLE_ATT_F_WRITE_ENC;
48+
}
49+
if (write_perm == SECURITY_MODE_SIGNED_NO_MITM) {
50+
self->flags |= BLE_ATT_F_WRITE_AUTHEN;
51+
}
52+
2753
const mp_int_t max_length_max = BLE_ATT_ATTR_MAX_LEN;
2854
if (max_length < 0 || max_length > max_length_max) {
2955
mp_raise_ValueError_varg(MP_ERROR_TEXT("max_length must be 0-%d when fixed_length is %s"),
@@ -42,38 +68,35 @@ bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio
4268
}
4369

4470
size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8_t *buf, size_t len) {
45-
// Do GATT operations only if this descriptor has been registered
46-
if (self->handle != BLEIO_HANDLE_INVALID) {
71+
if (self->characteristic == NULL) {
72+
return 0;
73+
}
74+
if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) {
4775
uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection);
48-
(void)conn_handle;
76+
return bleio_gattc_read(conn_handle, self->handle, buf, len);
77+
} else {
78+
mp_buffer_info_t bufinfo;
79+
mp_get_buffer(self->initial_value, &bufinfo, MP_BUFFER_READ);
80+
len = MIN(bufinfo.len, len);
81+
memcpy(buf, bufinfo.buf, len);
82+
return len;
4983
}
5084

51-
// TODO: Implement this.
52-
5385
return 0;
5486
}
5587

5688
void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo) {
57-
// TODO: Implement this.
58-
// Do GATT operations only if this descriptor has been registered.
59-
if (self->handle != BLEIO_HANDLE_INVALID) {
60-
// uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection);
61-
if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) {
62-
// false means WRITE_REQ, not write-no-response
63-
// common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, false);
64-
} else {
65-
// Validate data length for local descriptors only.
66-
if (self->fixed_length && bufinfo->len != self->max_length) {
67-
mp_raise_ValueError(MP_ERROR_TEXT("Value length != required fixed length"));
68-
}
69-
if (bufinfo->len > self->max_length) {
70-
mp_raise_ValueError(MP_ERROR_TEXT("Value length > max_length"));
71-
}
72-
73-
// common_hal_bleio_gatts_write(self->handle, conn_handle, bufinfo);
74-
}
89+
if (self->characteristic == NULL) {
90+
return;
7591
}
7692

93+
if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) {
94+
uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection);
95+
bleio_gattc_write(conn_handle, self->handle, bufinfo->buf, bufinfo->len);
96+
} else {
97+
// Descriptor values should be set via the initial_value when used locally.
98+
mp_raise_NotImplementedError(NULL);
99+
}
77100
}
78101

79102
int bleio_descriptor_access_cb(uint16_t conn_handle, uint16_t attr_handle,

ports/espressif/common-hal/_bleio/Service.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self,
8686
const char *user_description) {
8787
mp_obj_list_append(self->characteristic_list, MP_OBJ_FROM_PTR(characteristic));
8888

89+
if (user_description != NULL) {
90+
mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_user_description);
91+
}
92+
8993
// Delete the old version of the service.
9094
if (self->characteristic_list->len > 1) {
9195
ble_gatts_delete_svc(&self->uuid->nimble_ble_uuid.u);

ports/espressif/common-hal/_bleio/__init__.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,25 @@
99
#include <string.h>
1010

1111
#include "py/runtime.h"
12+
#include "shared/runtime/interrupt_char.h"
13+
1214
#include "shared-bindings/_bleio/__init__.h"
1315
#include "shared-bindings/_bleio/Adapter.h"
1416
#include "shared-bindings/_bleio/Characteristic.h"
1517
#include "shared-bindings/_bleio/Connection.h"
1618
#include "shared-bindings/_bleio/Descriptor.h"
1719
#include "shared-bindings/_bleio/Service.h"
1820
#include "shared-bindings/_bleio/UUID.h"
21+
#include "shared-bindings/time/__init__.h"
1922
#include "supervisor/shared/bluetooth/bluetooth.h"
2023

2124
#include "common-hal/_bleio/__init__.h"
2225
#include "common-hal/_bleio/ble_events.h"
2326

2427
#include "nvs_flash.h"
2528

29+
static volatile int _completion_status;
30+
static uint64_t _timeout_start_time;
2631

2732
background_callback_t bleio_background_callback;
2833

@@ -152,3 +157,83 @@ void common_hal_bleio_check_connected(uint16_t conn_handle) {
152157
mp_raise_ConnectionError(MP_ERROR_TEXT("Not connected"));
153158
}
154159
}
160+
161+
static void _reset_completion_status(void) {
162+
_completion_status = 0;
163+
}
164+
165+
// Wait for a status change, recorded in a callback.
166+
// Try twice because sometimes we get a BLE_HS_EAGAIN.
167+
// Maybe we should try more than twice.
168+
static int _wait_for_completion(uint32_t timeout_msecs) {
169+
for (int tries = 1; tries <= 2; tries++) {
170+
_timeout_start_time = common_hal_time_monotonic_ms();
171+
while ((_completion_status == 0) &&
172+
(common_hal_time_monotonic_ms() < _timeout_start_time + timeout_msecs) &&
173+
!mp_hal_is_interrupted()) {
174+
RUN_BACKGROUND_TASKS;
175+
}
176+
if (_completion_status != BLE_HS_EAGAIN) {
177+
// Quit, because either the status is either zero (OK) or it's an error.
178+
break;
179+
}
180+
}
181+
return _completion_status;
182+
}
183+
184+
typedef struct {
185+
uint8_t *buf;
186+
uint16_t len;
187+
} _read_info_t;
188+
189+
static int _read_cb(uint16_t conn_handle,
190+
const struct ble_gatt_error *error,
191+
struct ble_gatt_attr *attr,
192+
void *arg) {
193+
_read_info_t *read_info = (_read_info_t *)arg;
194+
switch (error->status) {
195+
case 0: {
196+
int len = MIN(read_info->len, OS_MBUF_PKTLEN(attr->om));
197+
os_mbuf_copydata(attr->om, attr->offset, len, read_info->buf);
198+
read_info->len = len;
199+
}
200+
MP_FALLTHROUGH;
201+
202+
default:
203+
#if CIRCUITPY_VERBOSE_BLE
204+
// For debugging.
205+
mp_printf(&mp_plat_print, "Read status: %d\n", error->status);
206+
#endif
207+
break;
208+
}
209+
_completion_status = error->status;
210+
211+
return 0;
212+
}
213+
214+
int bleio_gattc_read(uint16_t conn_handle, uint16_t value_handle, uint8_t *buf, size_t len) {
215+
_read_info_t read_info = {
216+
.buf = buf,
217+
.len = len
218+
};
219+
_reset_completion_status();
220+
CHECK_NIMBLE_ERROR(ble_gattc_read(conn_handle, value_handle, _read_cb, &read_info));
221+
CHECK_NIMBLE_ERROR(_wait_for_completion(2000));
222+
return read_info.len;
223+
}
224+
225+
226+
static int _write_cb(uint16_t conn_handle,
227+
const struct ble_gatt_error *error,
228+
struct ble_gatt_attr *attr,
229+
void *arg) {
230+
_completion_status = error->status;
231+
232+
return 0;
233+
}
234+
235+
void bleio_gattc_write(uint16_t conn_handle, uint16_t value_handle, uint8_t *buf, size_t len) {
236+
_reset_completion_status();
237+
CHECK_NIMBLE_ERROR(ble_gattc_write_flat(conn_handle, value_handle, buf, len, _write_cb, NULL));
238+
CHECK_NIMBLE_ERROR(_wait_for_completion(2000));
239+
}

ports/espressif/common-hal/_bleio/__init__.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,6 @@ void check_notify(BaseType_t result);
4343
#define UNIT_1_MS (1000)
4444
#define UNIT_1_25_MS (1250)
4545
#define UNIT_10_MS (10000)
46+
47+
int bleio_gattc_read(uint16_t conn_handle, uint16_t value_handle, uint8_t *buf, size_t len);
48+
void bleio_gattc_write(uint16_t conn_handle, uint16_t value_handle, uint8_t *buf, size_t len);

0 commit comments

Comments
 (0)