Skip to content

Commit 559ce6a

Browse files
authored
Merge pull request #2356 from tannewt/central_pairing
Add connection interval and debugging
2 parents 840f88b + e8a54ea commit 559ce6a

File tree

12 files changed

+163
-23
lines changed

12 files changed

+163
-23
lines changed

.gitmodules

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@
7676
[submodule "lib/tinyusb"]
7777
path = lib/tinyusb
7878
url = https://github.com/hathach/tinyusb.git
79-
branch = develop
79+
branch = master
80+
fetchRecurseSubmodules = false
8081
[submodule "tools/huffman"]
8182
path = tools/huffman
8283
url = https://github.com/tannewt/huffman.git

ports/nrf/bluetooth/ble_drv.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ void SD_EVT_IRQHandler(void) {
134134
}
135135

136136
ble_evt_t* event = (ble_evt_t *)m_ble_evt_buf;
137+
#if CIRCUITPY_VERBOSE_BLE
138+
mp_printf(&mp_plat_print, "BLE event: 0x%04x\n", event->header.evt_id);
139+
#endif
137140

138141
if (supervisor_bluetooth_hook(event)) {
139142
continue;
@@ -145,8 +148,15 @@ void SD_EVT_IRQHandler(void) {
145148
done = it->func(event, it->param) || done;
146149
it = it->next;
147150
}
151+
#if CIRCUITPY_VERBOSE_BLE
152+
if (event->header.evt_id == BLE_GATTS_EVT_WRITE) {
153+
ble_gatts_evt_write_t* write_evt = &event->evt.gatts_evt.params.write;
154+
mp_printf(&mp_plat_print, "Write to: UUID(0x%04x) handle %x of length %d auth %x\n", write_evt->uuid.uuid, write_evt->handle, write_evt->len, write_evt->auth_required);
155+
}
148156
if (!done) {
149-
//mp_printf(&mp_plat_print, "Unhandled ble event: 0x%04x\n", event->header.evt_id);
157+
mp_printf(&mp_plat_print, "Unhandled ble event: 0x%04x\n", event->header.evt_id);
158+
150159
}
160+
#endif
151161
}
152162
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,18 @@ STATIC bool adapter_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
180180
connection->conn_handle = ble_evt->evt.gap_evt.conn_handle;
181181
connection->connection_obj = mp_const_none;
182182
connection->pair_status = PAIR_NOT_PAIRED;
183+
183184
ble_drv_add_event_handler_entry(&connection->handler_entry, connection_on_ble_evt, connection);
184185
self->connection_objs = NULL;
185186

187+
// Save the current connection parameters.
188+
memcpy(&connection->conn_params, &connected->conn_params, sizeof(ble_gap_conn_params_t));
189+
190+
#if CIRCUITPY_VERBOSE_BLE
191+
ble_gap_conn_params_t *cp = &connected->conn_params;
192+
mp_printf(&mp_plat_print, "conn params: min_ci %d max_ci %d s_l %d sup_timeout %d\n", cp->min_conn_interval, cp->max_conn_interval, cp->slave_latency, cp->conn_sup_timeout);
193+
#endif
194+
186195
// See if connection interval set by Central is out of range.
187196
// If so, negotiate our preferred range.
188197
ble_gap_conn_params_t conn_params;

ports/nrf/common-hal/_bleio/Connection.c

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,6 @@ static volatile bool m_discovery_successful;
7070
static bleio_service_obj_t *m_char_discovery_service;
7171
static bleio_characteristic_obj_t *m_desc_discovery_characteristic;
7272

73-
bool dump_events = false;
74-
7573
bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
7674
bleio_connection_internal_t *self = (bleio_connection_internal_t*)self_in;
7775

@@ -84,16 +82,9 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
8482
return false;
8583
}
8684

87-
// For debugging.
88-
if (dump_events) {
89-
mp_printf(&mp_plat_print, "Connection event: 0x%04x\n", ble_evt->header.evt_id);
90-
}
91-
9285
switch (ble_evt->header.evt_id) {
9386
case BLE_GAP_EVT_DISCONNECTED:
9487
break;
95-
case BLE_GAP_EVT_CONN_PARAM_UPDATE: // 0x12
96-
break;
9788
case BLE_GAP_EVT_PHY_UPDATE_REQUEST: {
9889
ble_gap_phys_t const phys = {
9990
.rx_phys = BLE_GAP_PHY_AUTO,
@@ -124,15 +115,61 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
124115
sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0);
125116
break;
126117

127-
case BLE_GATTS_EVT_HVN_TX_COMPLETE: // Capture this for now. 0x55
118+
#if CIRCUITPY_VERBOSE_BLE
119+
// Use read authorization to snoop on all reads when doing verbose debugging.
120+
case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: {
121+
122+
ble_gatts_evt_rw_authorize_request_t *request =
123+
&ble_evt->evt.gatts_evt.params.authorize_request;
124+
125+
mp_printf(&mp_plat_print, "Read %x offset %d ", request->request.read.handle, request->request.read.offset);
126+
uint8_t value_bytes[22];
127+
ble_gatts_value_t value;
128+
value.offset = request->request.read.offset;
129+
value.len = 22;
130+
value.p_value = value_bytes;
131+
132+
sd_ble_gatts_value_get(self->conn_handle, request->request.read.handle, &value);
133+
size_t len = value.len;
134+
if (len > 22) {
135+
len = 22;
136+
}
137+
for (uint8_t i = 0; i < len; i++) {
138+
mp_printf(&mp_plat_print, " %02x", value_bytes[i]);
139+
}
140+
mp_printf(&mp_plat_print, "\n");
141+
ble_gatts_rw_authorize_reply_params_t reply;
142+
reply.type = request->type;
143+
reply.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS;
144+
reply.params.read.update = false;
145+
reply.params.read.offset = request->request.read.offset;
146+
sd_ble_gatts_rw_authorize_reply(self->conn_handle, &reply);
128147
break;
148+
}
149+
#endif
129150

151+
case BLE_GATTS_EVT_HVN_TX_COMPLETE: // Capture this for now. 0x55
152+
break;
130153
case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: {
154+
self->conn_params_updating = true;
131155
ble_gap_evt_conn_param_update_request_t *request =
132156
&ble_evt->evt.gap_evt.params.conn_param_update_request;
133157
sd_ble_gap_conn_param_update(self->conn_handle, &request->conn_params);
134158
break;
135159
}
160+
case BLE_GAP_EVT_CONN_PARAM_UPDATE: { // 0x12
161+
ble_gap_evt_conn_param_update_t *result =
162+
&ble_evt->evt.gap_evt.params.conn_param_update;
163+
164+
#if CIRCUITPY_VERBOSE_BLE
165+
ble_gap_conn_params_t *cp = &ble_evt->evt.gap_evt.params.conn_param_update.conn_params;
166+
mp_printf(&mp_plat_print, "conn params updated: min_ci %d max_ci %d s_l %d sup_timeout %d\n", cp->min_conn_interval, cp->max_conn_interval, cp->slave_latency, cp->conn_sup_timeout);
167+
#endif
168+
169+
memcpy(&self->conn_params, &result->conn_params, sizeof(ble_gap_conn_params_t));
170+
self->conn_params_updating = false;
171+
break;
172+
}
136173
case BLE_GAP_EVT_SEC_PARAMS_REQUEST: {
137174
ble_gap_sec_keyset_t keyset = {
138175
.keys_own = {
@@ -212,9 +249,9 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) {
212249

213250
default:
214251
// For debugging.
215-
if (dump_events) {
252+
#if CIRCUITPY_VERBOSE_BLE
216253
mp_printf(&mp_plat_print, "Unhandled connection event: 0x%04x\n", ble_evt->header.evt_id);
217-
}
254+
#endif
218255

219256
return false;
220257
}
@@ -262,6 +299,25 @@ void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bo
262299
check_sec_status(self->sec_status);
263300
}
264301

302+
mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_internal_t *self) {
303+
while (self->conn_params_updating && !mp_hal_is_interrupted()) {
304+
RUN_BACKGROUND_TASKS;
305+
}
306+
return 1.25f * self->conn_params.min_conn_interval;
307+
}
308+
309+
void common_hal_bleio_connection_set_connection_interval(bleio_connection_internal_t *self, mp_float_t new_interval) {
310+
self->conn_params_updating = true;
311+
uint16_t interval = new_interval / 1.25f;
312+
self->conn_params.min_conn_interval = interval;
313+
self->conn_params.max_conn_interval = interval;
314+
uint32_t status = NRF_ERROR_BUSY;
315+
while (status == NRF_ERROR_BUSY) {
316+
status = sd_ble_gap_conn_param_update(self->conn_handle, &self->conn_params);
317+
RUN_BACKGROUND_TASKS;
318+
}
319+
check_nrf_error(status);
320+
}
265321

266322
// service_uuid may be NULL, to discover all services.
267323
STATIC bool discover_next_services(bleio_connection_internal_t* connection, uint16_t start_handle, ble_uuid_t *service_uuid) {
@@ -600,6 +656,7 @@ STATIC void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t
600656
ble_drv_remove_event_handler(discovery_on_ble_evt, self);
601657

602658
}
659+
603660
mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_connection_obj_t *self, mp_obj_t service_uuids_whitelist) {
604661
discover_remote_services(self->connection, service_uuids_whitelist);
605662
// Convert to a tuple and then clear the list so the callee will take ownership.
@@ -609,7 +666,6 @@ mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_conne
609666
return services_tuple;
610667
}
611668

612-
613669
uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self) {
614670
if (self == NULL || self->connection == NULL) {
615671
return BLE_CONN_HANDLE_INVALID;

ports/nrf/common-hal/_bleio/Connection.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ typedef struct {
6363
uint8_t sec_status; // Internal security status.
6464
mp_obj_t connection_obj;
6565
ble_drv_evt_handler_entry_t handler_entry;
66+
ble_gap_conn_params_t conn_params;
67+
volatile bool conn_params_updating;
6668
} bleio_connection_internal_t;
6769

6870
typedef struct {

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self,
119119

120120
bleio_attribute_gatts_set_security_mode(&char_attr_md.read_perm, characteristic->read_perm);
121121
bleio_attribute_gatts_set_security_mode(&char_attr_md.write_perm, characteristic->write_perm);
122+
#if CIRCUITPY_VERBOSE_BLE
123+
// Turn on read authorization so that we receive an event to print on every read.
124+
char_attr_md.rd_auth = true;
125+
#endif
122126

123127
ble_gatts_attr_t char_attr = {
124128
.p_uuid = &char_uuid,
@@ -137,6 +141,9 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self,
137141
characteristic->cccd_handle = char_handles.cccd_handle;
138142
characteristic->sccd_handle = char_handles.sccd_handle;
139143
characteristic->handle = char_handles.value_handle;
144+
#if CIRCUITPY_VERBOSE_BLE
145+
mp_printf(&mp_plat_print, "Char handle %x user %x cccd %x sccd %x\n", characteristic->handle, characteristic->user_desc_handle, characteristic->cccd_handle, characteristic->sccd_handle);
146+
#endif
140147

141148
mp_obj_list_append(self->characteristic_list, MP_OBJ_FROM_PTR(characteristic));
142149
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,11 @@ size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_
187187
read_info.done = false;
188188
ble_drv_add_event_handler(_on_gattc_read_rsp_evt, &read_info);
189189

190-
check_nrf_error(sd_ble_gattc_read(conn_handle, handle, 0));
190+
uint32_t nrf_error = NRF_ERROR_BUSY;
191+
while (nrf_error == NRF_ERROR_BUSY) {
192+
nrf_error = sd_ble_gattc_read(conn_handle, handle, 0);
193+
}
194+
check_nrf_error(nrf_error);
191195

192196
while (!read_info.done) {
193197
RUN_BACKGROUND_TASKS;

py/circuitpy_mpconfig.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,4 +666,6 @@ void supervisor_run_background_tasks_if_tick(void);
666666
#define CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS 1000
667667
#define CIRCUITPY_BOOT_OUTPUT_FILE "/boot_out.txt"
668668

669+
#define CIRCUITPY_VERBOSE_BLE 0
670+
669671
#endif // __INCLUDED_MPCONFIG_CIRCUITPY_H

shared-bindings/_bleio/Connection.c

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,57 @@ const mp_obj_property_t bleio_connection_paired_obj = {
193193
(mp_obj_t)&mp_const_none_obj },
194194
};
195195

196+
197+
//| .. attribute:: connection_interval
198+
//|
199+
//| Time between transmissions in milliseconds. Will be multiple of 1.25ms. Lower numbers
200+
//| increase speed and decrease latency but increase power consumption.
201+
//|
202+
//| When setting connection_interval, the peer may reject the new interval and
203+
//| `connection_interval` will then remain the same.
204+
//|
205+
//| Apple has additional guidelines that dictate should be a multiple of 15ms except if HID is
206+
//| available. When HID is available Apple devices may accept 11.25ms intervals.
207+
//|
208+
//|
209+
STATIC mp_obj_t bleio_connection_get_connection_interval(mp_obj_t self_in) {
210+
bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in);
211+
212+
ensure_connected(self);
213+
return mp_obj_new_float(common_hal_bleio_connection_get_connection_interval(self->connection));
214+
}
215+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_connection_get_connection_interval_obj, bleio_connection_get_connection_interval);
216+
217+
STATIC mp_obj_t bleio_connection_set_connection_interval(mp_obj_t self_in, mp_obj_t interval_in) {
218+
bleio_connection_obj_t *self = MP_OBJ_TO_PTR(self_in);
219+
220+
mp_float_t interval = mp_obj_get_float(interval_in);
221+
222+
ensure_connected(self);
223+
common_hal_bleio_connection_set_connection_interval(self->connection, interval);
224+
225+
return mp_const_none;
226+
}
227+
STATIC MP_DEFINE_CONST_FUN_OBJ_2(bleio_connection_set_connection_interval_obj, bleio_connection_set_connection_interval);
228+
229+
const mp_obj_property_t bleio_connection_connection_interval_obj = {
230+
.base.type = &mp_type_property,
231+
.proxy = { (mp_obj_t)&bleio_connection_get_connection_interval_obj,
232+
(mp_obj_t)&bleio_connection_set_connection_interval_obj,
233+
(mp_obj_t)&mp_const_none_obj },
234+
};
235+
196236
STATIC const mp_rom_map_elem_t bleio_connection_locals_dict_table[] = {
197237
// Methods
198238
{ MP_ROM_QSTR(MP_QSTR_pair), MP_ROM_PTR(&bleio_connection_pair_obj) },
199239
{ MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&bleio_connection_disconnect_obj) },
200240
{ MP_ROM_QSTR(MP_QSTR_discover_remote_services), MP_ROM_PTR(&bleio_connection_discover_remote_services_obj) },
201241

202242
// Properties
203-
{ MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_connection_connected_obj) },
204-
{ MP_ROM_QSTR(MP_QSTR_paired), MP_ROM_PTR(&bleio_connection_paired_obj) },
243+
{ MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&bleio_connection_connected_obj) },
244+
{ MP_ROM_QSTR(MP_QSTR_paired), MP_ROM_PTR(&bleio_connection_paired_obj) },
245+
{ MP_ROM_QSTR(MP_QSTR_connection_interval), MP_ROM_PTR(&bleio_connection_connection_interval_obj) },
246+
205247
};
206248

207249
STATIC MP_DEFINE_CONST_DICT(bleio_connection_locals_dict, bleio_connection_locals_dict_table);

shared-bindings/_bleio/Connection.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,7 @@ extern bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *se
4040
extern bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self);
4141
extern mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_connection_obj_t *self, mp_obj_t service_uuids_whitelist);
4242

43+
mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_internal_t *self);
44+
void common_hal_bleio_connection_set_connection_interval(bleio_connection_internal_t *self, mp_float_t new_interval);
45+
4346
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BLEIO_CONNECTION_H

shared-bindings/displayio/OnDiskBitmap.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
//|
6060
//| with open("/sample.bmp", "rb") as f:
6161
//| odb = displayio.OnDiskBitmap(f)
62-
//| face = displayio.TileGrid(odb, pixel_shader=displayio.ColorConverter(), position=(0,0))
62+
//| face = displayio.TileGrid(odb, pixel_shader=displayio.ColorConverter())
6363
//| splash.append(face)
6464
//| # Wait for the image to load.
6565
//| board.DISPLAY.wait_for_frame()

supervisor/shared/bluetooth.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,12 @@ bleio_characteristic_obj_t supervisor_ble_length_characteristic;
5151
bleio_uuid_obj_t supervisor_ble_length_uuid;
5252
bleio_characteristic_obj_t supervisor_ble_contents_characteristic;
5353
bleio_uuid_obj_t supervisor_ble_contents_uuid;
54+
55+
// This is the base UUID for CircuitPython services and characteristics.
5456
const uint8_t circuitpython_base_uuid[16] = {0x6e, 0x68, 0x74, 0x79, 0x50, 0x74, 0x69, 0x75, 0x63, 0x72, 0x69, 0x43, 0x00, 0x00, 0xaf, 0xad };
55-
uint8_t circuitpython_advertising_data[] = { 0x02, 0x01, 0x06, 0x02, 0x0a, 0x00, 0x11, 0x07, 0x6e, 0x68, 0x74, 0x79, 0x50, 0x74, 0x69, 0x75, 0x63, 0x72, 0x69, 0x43, 0x00, 0x01, 0xaf, 0xad, 0x06, 0x08, 0x43, 0x49, 0x52, 0x43, 0x55 };
57+
// This standard advertisement advertises the CircuitPython editing service and a CIRCUITPY short name.
58+
uint8_t circuitpython_advertising_data[] = { 0x02, 0x01, 0x06, 0x02, 0x0a, 0x00, 0x11, 0x07, 0x6e, 0x68, 0x74, 0x79, 0x50, 0x74, 0x69, 0x75, 0x63, 0x72, 0x69, 0x43, 0x00, 0x01, 0xaf, 0xad, 0x06, 0x08, 0x43, 0x49, 0x52, 0x43, 0x55 };
59+
// This scan response advertises the full CIRCUITPYXXXX device name.
5660
uint8_t circuitpython_scan_response_data[15] = {0x0e, 0x09, 0x43, 0x49, 0x52, 0x43, 0x55, 0x49, 0x54, 0x50, 0x59, 0x00, 0x00, 0x00, 0x00};
5761
mp_obj_list_t service_list;
5862
mp_obj_t service_list_items[1];
@@ -86,7 +90,7 @@ void supervisor_start_bluetooth(void) {
8690
characteristic_list.len = 0;
8791
characteristic_list.items = characteristic_list_items;
8892
mp_seq_clear(characteristic_list.items, 0, characteristic_list.alloc, sizeof(*characteristic_list.items));
89-
93+
9094
_common_hal_bleio_service_construct(&supervisor_ble_service, &supervisor_ble_service_uuid, false /* is secondary */, &characteristic_list);
9195

9296
// File length
@@ -225,7 +229,7 @@ void supervisor_bluetooth_background(void) {
225229
uint16_t current_length = ((uint16_t*) current_command)[0];
226230
if (current_length > 0 && current_length == current_offset) {
227231
uint16_t command = ((uint16_t *) current_command)[1];
228-
232+
229233
if (command == 1) {
230234
uint16_t max_len = 20; //supervisor_ble_contents_characteristic.max_length;
231235
uint8_t buf[max_len];
@@ -274,7 +278,7 @@ void supervisor_bluetooth_background(void) {
274278
f_write(&active_file, &data, 1, &actual);
275279
}
276280
}
277-
281+
278282
f_lseek(&active_file, offset);
279283
uint8_t* data = (uint8_t *) (current_command + 4);
280284
UINT written;

0 commit comments

Comments
 (0)