Skip to content

Commit 6ea01ea

Browse files
committed
Central is connecting; characteristics can be read and written
1 parent 140904e commit 6ea01ea

12 files changed

Lines changed: 182 additions & 97 deletions

File tree

ports/nrf/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ INC += -I../../supervisor/shared/usb
9191
ifeq ($(DEBUG), 1)
9292
CFLAGS += -ggdb
9393
# You may want to enable these flags to make setting breakpoints easier.
94-
# CFLAGS += -fno-inline -fno-ipa-sra
94+
CFLAGS += -fno-inline -fno-ipa-sra
9595
else
9696
CFLAGS += -Os -DNDEBUG
9797
# TODO: Test with -flto

ports/nrf/common-hal/bleio/Central.c

Lines changed: 87 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,13 @@ static bleio_service_obj_t *m_char_discovery_service;
4444
static volatile bool m_discovery_in_process;
4545
static volatile bool m_discovery_successful;
4646

47-
STATIC bool discover_next_services(bleio_central_obj_t *self, uint16_t start_handle) {
47+
// service_uuid may be NULL, to discover all services.
48+
STATIC bool discover_next_services(bleio_central_obj_t *self, uint16_t start_handle, ble_uuid_t *service_uuid) {
4849
m_discovery_successful = false;
4950
m_discovery_in_process = true;
5051

51-
uint32_t err_code = sd_ble_gattc_primary_services_discover(self->conn_handle, start_handle, NULL);
52+
uint32_t err_code = sd_ble_gattc_primary_services_discover(self->conn_handle, start_handle, service_uuid);
53+
5254
if (err_code != NRF_SUCCESS) {
5355
mp_raise_OSError_msg(translate("Failed to discover services"));
5456
}
@@ -88,15 +90,26 @@ STATIC void on_primary_srv_discovery_rsp(ble_gattc_evt_prim_srvc_disc_rsp_t *res
8890

8991
bleio_service_obj_t *service = m_new_obj(bleio_service_obj_t);
9092
service->base.type = &bleio_service_type;
93+
9194
service->device = MP_OBJ_FROM_PTR(central);
9295
service->characteristic_list = mp_obj_new_list(0, NULL);
9396
service->start_handle = gattc_service->handle_range.start_handle;
9497
service->end_handle = gattc_service->handle_range.end_handle;
9598
service->handle = gattc_service->handle_range.start_handle;
9699

97-
bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t);
98-
bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid);
99-
service->uuid = uuid;
100+
if (gattc_service->uuid.type != BLE_UUID_TYPE_UNKNOWN) {
101+
// Known service UUID.
102+
bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t);
103+
uuid->base.type = &bleio_uuid_type;
104+
bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_service->uuid);
105+
service->uuid = uuid;
106+
service->device = MP_OBJ_FROM_PTR(central);
107+
} else {
108+
// The discovery response contained a 128-bit UUID that has not yet been registered with the
109+
// softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it.
110+
// For now, just set the UUID to NULL.
111+
service->uuid = NULL;
112+
}
100113

101114
mp_obj_list_append(central->service_list, service);
102115
}
@@ -114,10 +127,18 @@ STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio
114127
bleio_characteristic_obj_t *characteristic = m_new_obj(bleio_characteristic_obj_t);
115128
characteristic->base.type = &bleio_characteristic_type;
116129

117-
bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t);
118-
uuid->base.type = &bleio_uuid_type;
119-
bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid);
120-
characteristic->uuid = uuid;
130+
if (gattc_char->uuid.type != BLE_UUID_TYPE_UNKNOWN) {
131+
// Known characteristic UUID.
132+
bleio_uuid_obj_t *uuid = m_new_obj(bleio_uuid_obj_t);
133+
uuid->base.type = &bleio_uuid_type;
134+
bleio_uuid_construct_from_nrf_ble_uuid(uuid, &gattc_char->uuid);
135+
characteristic->uuid = uuid;
136+
} else {
137+
// The discovery response contained a 128-bit UUID that has not yet been registered with the
138+
// softdevice via sd_ble_uuid_vs_add(). We need to fetch the 128-bit value and register it.
139+
// For now, just set the UUID to NULL.
140+
characteristic->uuid = NULL;
141+
}
121142

122143
characteristic->props.broadcast = gattc_char->char_props.broadcast;
123144
characteristic->props.indicate = gattc_char->char_props.indicate;
@@ -137,25 +158,18 @@ STATIC void on_char_discovery_rsp(ble_gattc_evt_char_disc_rsp_t *response, bleio
137158
m_discovery_in_process = false;
138159
}
139160

140-
STATIC void on_ble_evt(ble_evt_t *ble_evt, void *central_in) {
161+
STATIC void central_on_ble_evt(ble_evt_t *ble_evt, void *central_in) {
141162
bleio_central_obj_t *central = (bleio_central_obj_t*)central_in;
142163

143164
switch (ble_evt->header.evt_id) {
144165
case BLE_GAP_EVT_CONNECTED:
145-
{
146-
ble_gap_conn_params_t conn_params;
147166
central->conn_handle = ble_evt->evt.gap_evt.conn_handle;
148-
149-
sd_ble_gap_ppcp_get(&conn_params);
150-
sd_ble_gap_conn_param_update(ble_evt->evt.gap_evt.conn_handle, &conn_params);
167+
central->waiting_to_connect = false;
151168
break;
152-
}
153169

154170
case BLE_GAP_EVT_TIMEOUT:
155-
if (central->attempting_to_connect) {
156-
// Signal that connection attempt has timed out.
157-
central->attempting_to_connect = false;
158-
}
171+
// Handle will be invalid.
172+
central->waiting_to_connect = false;
159173
break;
160174

161175
case BLE_GAP_EVT_DISCONNECTED:
@@ -172,14 +186,6 @@ STATIC void on_ble_evt(ble_evt_t *ble_evt, void *central_in) {
172186
on_char_discovery_rsp(&ble_evt->evt.gattc_evt.params.char_disc_rsp, central);
173187
break;
174188

175-
case BLE_GATTS_EVT_SYS_ATTR_MISSING:
176-
sd_ble_gatts_sys_attr_set(ble_evt->evt.gatts_evt.conn_handle, NULL, 0, 0);
177-
break;
178-
179-
case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
180-
sd_ble_gatts_exchange_mtu_reply(central->conn_handle, BLE_GATT_ATT_MTU_DEFAULT);
181-
break;
182-
183189
case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
184190
sd_ble_gap_sec_params_reply(central->conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
185191
break;
@@ -193,21 +199,24 @@ STATIC void on_ble_evt(ble_evt_t *ble_evt, void *central_in) {
193199
}
194200
}
195201

196-
void common_hal_bleio_central_construct(bleio_central_obj_t *self, bleio_address_obj_t *address) {
202+
void common_hal_bleio_central_construct(bleio_central_obj_t *self) {
197203
common_hal_bleio_adapter_set_enabled(true);
198204

199205
self->service_list = mp_obj_new_list(0, NULL);
200206
self->gatt_role = GATT_ROLE_CLIENT;
201207
self->conn_handle = BLE_CONN_HANDLE_INVALID;
202208
}
203209

204-
void common_hal_bleio_central_connect(bleio_central_obj_t *self, mp_float_t timeout) {
210+
void common_hal_bleio_central_connect(bleio_central_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout, mp_obj_t service_uuids) {
205211
common_hal_bleio_adapter_set_enabled(true);
206-
ble_drv_add_event_handler(on_ble_evt, self);
212+
ble_drv_add_event_handler(central_on_ble_evt, self);
207213

208214
ble_gap_addr_t addr;
209-
addr.addr_type = self->address.type;
210-
memcpy(addr.addr, self->address.bytes, NUM_BLEIO_ADDRESS_BYTES);
215+
216+
addr.addr_type = address->type;
217+
mp_buffer_info_t address_buf_info;
218+
mp_get_buffer_raise(address->bytes, &address_buf_info, MP_BUFFER_READ);
219+
memcpy(addr.addr, (uint8_t *) address_buf_info.buf, NUM_BLEIO_ADDRESS_BYTES);
211220

212221
ble_gap_scan_params_t scan_params = {
213222
.interval = MSEC_TO_UNITS(100, UNIT_0_625_MS),
@@ -224,58 +233,76 @@ void common_hal_bleio_central_connect(bleio_central_obj_t *self, mp_float_t time
224233
.slave_latency = 0, // number of conn events
225234
};
226235

227-
self->attempting_to_connect = true;
236+
self->waiting_to_connect = true;
228237

229238
uint32_t err_code = sd_ble_gap_connect(&addr, &scan_params, &conn_params, BLE_CONN_CFG_TAG_CUSTOM);
230239

231240
if (err_code != NRF_SUCCESS) {
232241
mp_raise_OSError_msg_varg(translate("Failed to start connecting, error 0x%04x"), err_code);
233242
}
234243

235-
while (self->conn_handle == BLE_CONN_HANDLE_INVALID && self->attempting_to_connect) {
236-
#ifdef MICROPY_VM_HOOK_LOOP
237-
MICROPY_VM_HOOK_LOOP
238-
#endif
244+
while (self->waiting_to_connect) {
245+
MICROPY_VM_HOOK_LOOP;
239246
}
240247

241-
if (!self->attempting_to_connect) {
248+
if (self->conn_handle == BLE_CONN_HANDLE_INVALID) {
242249
mp_raise_OSError_msg(translate("Failed to connect: timeout"));
243250
}
244251

245-
// Conenction successful.
246-
// Now discover all services on the remote peripheral. Ask for services repeatedly
247-
// until no more are left.
252+
// Connection successful.
253+
// Now discover services on the remote peripheral.
254+
255+
if (service_uuids == mp_const_none) {
248256

249-
uint16_t next_start_handle;
257+
// List of service UUID's not given, so discover all available services.
250258

251-
next_start_handle = BLE_GATT_HANDLE_START;
259+
uint16_t next_start_handle = BLE_GATT_HANDLE_START;
252260

253-
while (1) {
254-
if(!discover_next_services(self, next_start_handle)) {
255-
break;
261+
while (discover_next_services(self, next_start_handle, MP_OBJ_NULL)) {
262+
// discover_next_services() appends to service_list.
263+
const mp_obj_list_t *service_list = MP_OBJ_TO_PTR(self->service_list);
264+
265+
// Get the most recently discovered service, and then ask for services
266+
// whose handles start after the last attribute handle inside that service.
267+
const bleio_service_obj_t *service = service_list->items[service_list->len - 1];
268+
next_start_handle = service->end_handle + 1;
256269
}
270+
} else {
271+
mp_obj_iter_buf_t iter_buf;
272+
mp_obj_t iterable = mp_getiter(service_uuids, &iter_buf);
273+
mp_obj_t uuid_obj;
274+
while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
275+
if (!MP_OBJ_IS_TYPE(uuid_obj, &bleio_uuid_type)) {
276+
mp_raise_ValueError(translate("non-UUID found in service_uuids"));
277+
}
278+
bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj);
257279

258-
// discover_next_services() appends to service_list.
259-
const mp_obj_list_t *service_list = MP_OBJ_TO_PTR(self->service_list);
280+
ble_uuid_t nrf_uuid;
281+
bleio_uuid_convert_to_nrf_ble_uuid(uuid, &nrf_uuid);
260282

261-
// Get the most recently discovered service, and ask for services with handles
262-
// starting after the last attribute handle of t
263-
const bleio_service_obj_t *service = service_list->items[service_list->len - 1];
264-
next_start_handle = service->end_handle + 1;
283+
// Service might or might not be discovered; that's ok. Caller has to check
284+
// Central.remote_services to find out.
285+
// We only need to call this once for each service to discover.
286+
discover_next_services(self, BLE_GATT_HANDLE_START, &nrf_uuid);
287+
}
265288
}
266289

267-
// Now, for each service, discover its characteristics.
268-
// find characteristics in each service
290+
269291
const mp_obj_list_t *service_list = MP_OBJ_TO_PTR(self->service_list);
270292
for (size_t i = 0; i < service_list->len; ++i) {
271293
bleio_service_obj_t *service = service_list->items[i];
272294

273-
next_start_handle = service->start_handle;
295+
// Skip the service if it had an unknown (unregistered) UUID.
296+
if (service->uuid == NULL) {
297+
continue;
298+
}
274299

275-
while (1) {
276-
if (!discover_next_characteristics(self, service, service->start_handle)) {
277-
break;
278-
}
300+
uint16_t next_start_handle = service->start_handle;
301+
302+
// Stop when we go past the end of the range of handles for this service or
303+
// discovery call returns nothing.
304+
while (next_start_handle <= service->end_handle &&
305+
discover_next_characteristics(self, service, next_start_handle)) {
279306

280307
// discover_next_characteristics() appends to the characteristic_list.
281308
const mp_obj_list_t *characteristic_list = MP_OBJ_TO_PTR(service->characteristic_list);
@@ -284,10 +311,6 @@ void common_hal_bleio_central_connect(bleio_central_obj_t *self, mp_float_t time
284311
const bleio_characteristic_obj_t *characteristic =
285312
characteristic_list->items[characteristic_list->len - 1];
286313
next_start_handle = characteristic->handle + 1;
287-
if (next_start_handle >= service->end_handle) {
288-
// Went past the end of the range of handles for this service.
289-
break;
290-
}
291314
}
292315
}
293316
}

ports/nrf/common-hal/bleio/Central.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@
3636
typedef struct {
3737
mp_obj_base_t base;
3838
gatt_role_t gatt_role;
39-
bleio_address_obj_t address;
40-
volatile bool attempting_to_connect;
39+
volatile bool waiting_to_connect;
4140
volatile uint16_t conn_handle;
4241
mp_obj_t service_list;
4342
} bleio_central_obj_t;

ports/nrf/common-hal/bleio/Characteristic.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ STATIC uint16_t get_cccd(bleio_characteristic_obj_t *characteristic) {
6060
}
6161

6262
STATIC void gatts_read(bleio_characteristic_obj_t *characteristic) {
63-
// This might be BLE_CONN_HANDLE_INVALID if we're not conected, but that's OK, because
63+
// This might be BLE_CONN_HANDLE_INVALID if we're not connected, but that's OK, because
6464
// we can still read and write the local value.
6565
const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device);
6666

@@ -135,8 +135,15 @@ STATIC void gatts_notify_indicate(bleio_characteristic_obj_t *characteristic, mp
135135

136136
}
137137

138+
STATIC void check_connected(uint16_t conn_handle) {
139+
if (conn_handle == BLE_CONN_HANDLE_INVALID) {
140+
mp_raise_OSError_msg(translate("Not connected"));
141+
}
142+
}
143+
138144
STATIC void gattc_read(bleio_characteristic_obj_t *characteristic) {
139145
const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device);
146+
check_connected(conn_handle);
140147

141148
m_read_characteristic = characteristic;
142149

@@ -152,6 +159,7 @@ STATIC void gattc_read(bleio_characteristic_obj_t *characteristic) {
152159

153160
STATIC void gattc_write(bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *bufinfo) {
154161
const uint16_t conn_handle = common_hal_bleio_device_get_conn_handle(characteristic->service->device);
162+
check_connected(conn_handle);
155163

156164
ble_gattc_write_params_t write_params = {
157165
.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL,

ports/nrf/common-hal/bleio/Scanner.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ static ble_data_t m_scan_buffer = {
4545
BLE_GAP_SCAN_BUFFER_MIN
4646
};
4747

48-
STATIC void on_ble_evt(ble_evt_t *ble_evt, void *scanner_in) {
48+
STATIC void scanner_on_ble_evt(ble_evt_t *ble_evt, void *scanner_in) {
4949
bleio_scanner_obj_t *scanner = (bleio_scanner_obj_t*)scanner_in;
5050
ble_gap_evt_adv_report_t *report = &ble_evt->evt.gap_evt.params.adv_report;
5151

@@ -79,7 +79,7 @@ void common_hal_bleio_scanner_construct(bleio_scanner_obj_t *self) {
7979

8080
void common_hal_bleio_scanner_scan(bleio_scanner_obj_t *self, mp_float_t timeout, mp_float_t interval, mp_float_t window) {
8181
common_hal_bleio_adapter_set_enabled(true);
82-
ble_drv_add_event_handler(on_ble_evt, self);
82+
ble_drv_add_event_handler(scanner_on_ble_evt, self);
8383

8484
ble_gap_scan_params_t scan_params = {
8585
.interval = SEC_TO_UNITS(interval, UNIT_0_625_MS),

0 commit comments

Comments
 (0)