@@ -44,11 +44,13 @@ static bleio_service_obj_t *m_char_discovery_service;
4444static volatile bool m_discovery_in_process ;
4545static 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}
0 commit comments