@@ -147,31 +147,29 @@ pbio_error_t pbdrv_bluetooth_send_event_notification(pbio_os_state_t *state, pbi
147147// Functions related to connections to peripherals.
148148//
149149
150- pbdrv_bluetooth_peripheral_t peripheral_singleton ;
151-
152150pbio_error_t pbdrv_bluetooth_peripheral_get_available (pbdrv_bluetooth_peripheral_t * * peripheral , void * user ) {
153- // Only a single peripheral instance supported for now.
154- * peripheral = & peripheral_singleton ;
155-
156- if (/* Already connected. */
157- pbdrv_bluetooth_is_connected (PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL ) ||
158- /* A different user is still claiming this resource. */
159- (* peripheral )-> user ||
160- /* Busy. Could be connecting but not connected yet. */
161- (* peripheral )-> func ) {
162- return PBIO_ERROR_BUSY ;
163- }
164151
165- // Claim this device for new user.
166- ( * peripheral ) -> user = user ;
152+ for ( uint8_t i = 0 ; i < PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS ; i ++ ) {
153+ pbdrv_bluetooth_peripheral_t * peri = pbdrv_bluetooth_peripheral_get_by_index ( i ) ;
167154
168- return PBIO_SUCCESS ;
155+ // Test if not already in use, not connected, and not busy.
156+ if (!pbdrv_bluetooth_peripheral_is_connected (peri ) && !peri -> user && !peri -> func ) {
157+ // Claim this device for new user.
158+ peri -> user = user ;
159+ * peripheral = peri ;
160+ return PBIO_SUCCESS ;
161+ }
162+ }
163+
164+ // All instances are in use.
165+ * peripheral = NULL ;
166+ return PBIO_ERROR_BUSY ;
169167}
170168
171169void pbdrv_bluetooth_peripheral_release (pbdrv_bluetooth_peripheral_t * peripheral , void * user ) {
172170 // Only release if the user matches. A new user may have already safely
173171 // claimed it, and this call to release may come from an orphaned user.
174- if (peripheral -> user != user ) {
172+ if (! peripheral || peripheral -> user != user ) {
175173 return ;
176174 }
177175 peripheral -> user = NULL ;
@@ -188,7 +186,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect(pbdrv_bluetooth_periphe
188186 }
189187
190188 // Can't connect if already connected or already busy.
191- if (pbdrv_bluetooth_is_connected ( PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL ) || peri -> func ) {
189+ if (pbdrv_bluetooth_peripheral_is_connected ( peri ) || peri -> func ) {
192190 return PBIO_ERROR_BUSY ;
193191 }
194192
@@ -219,7 +217,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_disconnect(pbdrv_bluetooth_peripheral_t
219217 }
220218
221219 // Pass silently for already disconnected.
222- if (!pbdrv_bluetooth_is_connected ( PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL )) {
220+ if (!pbdrv_bluetooth_peripheral_is_connected ( peri )) {
223221 peri -> err = PBIO_SUCCESS ;
224222 return PBIO_SUCCESS ;
225223 }
@@ -233,7 +231,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_disconnect(pbdrv_bluetooth_peripheral_t
233231
234232pbio_error_t pbdrv_bluetooth_peripheral_discover_characteristic (pbdrv_bluetooth_peripheral_t * peri , pbdrv_bluetooth_peripheral_char_t * characteristic ) {
235233
236- if (!pbdrv_bluetooth_is_connected ( PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL )) {
234+ if (!pbdrv_bluetooth_peripheral_is_connected ( peri )) {
237235 return PBIO_ERROR_NO_DEV ;
238236 }
239237 if (peri -> func ) {
@@ -251,7 +249,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_discover_characteristic(pbdrv_bluetooth_
251249
252250pbio_error_t pbdrv_bluetooth_peripheral_read_characteristic (pbdrv_bluetooth_peripheral_t * peri , pbdrv_bluetooth_peripheral_char_t * characteristic ) {
253251
254- if (!pbdrv_bluetooth_is_connected ( PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL )) {
252+ if (!pbdrv_bluetooth_peripheral_is_connected ( peri )) {
255253 return PBIO_ERROR_NO_DEV ;
256254 }
257255 if (peri -> func ) {
@@ -272,7 +270,7 @@ size_t pbdrv_bluetooth_char_write_size;
272270
273271pbio_error_t pbdrv_bluetooth_peripheral_write_characteristic (pbdrv_bluetooth_peripheral_t * peri , uint16_t handle , const uint8_t * data , size_t size ) {
274272
275- if (!pbdrv_bluetooth_is_connected ( PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL )) {
273+ if (!pbdrv_bluetooth_peripheral_is_connected ( peri )) {
276274 return PBIO_ERROR_NO_DEV ;
277275 }
278276 if (peri -> func ) {
@@ -307,7 +305,10 @@ pbio_error_t pbdrv_bluetooth_await_peripheral_command(pbio_os_state_t *state, vo
307305void pbdrv_bluetooth_cancel_operation_request (void ) {
308306 // Only some peripheral actions support cancellation.
309307 DEBUG_PRINT ("Bluetooth operation cancel requested.\n" );
310- peripheral_singleton .cancel = true;
308+ for (uint8_t i = 0 ; i < PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS ; i ++ ) {
309+ pbdrv_bluetooth_peripheral_t * peri = pbdrv_bluetooth_peripheral_get_by_index (i );
310+ peri -> cancel = true;
311+ }
311312}
312313
313314//
@@ -523,7 +524,10 @@ pbio_error_t pbdrv_bluetooth_process_thread(pbio_os_state_t *state, void *contex
523524
524525 // Shorthand notation accessible throughout.
525526 bool can_send = pbdrv_bluetooth_is_connected (PBDRV_BLUETOOTH_CONNECTION_PYBRICKS );
526- pbdrv_bluetooth_peripheral_t * peri = & peripheral_singleton ;
527+
528+ // For looping over peripherals.
529+ static uint8_t peri_index ;
530+ static pbdrv_bluetooth_peripheral_t * peri ;
527531
528532 PBIO_OS_ASYNC_BEGIN (state );
529533
@@ -565,18 +569,21 @@ pbio_error_t pbdrv_bluetooth_process_thread(pbio_os_state_t *state, void *contex
565569 advertising_or_scan_func = NULL ;
566570 }
567571
568- // Handle pending peripheral task, if any.
569- if (peri -> func ) {
572+ // Handle pending peripheral tasks, one at a time.
573+ for (peri_index = 0 ; peri_index < PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS ; peri_index ++ ) {
574+ peri = pbdrv_bluetooth_peripheral_get_by_index (peri_index );
575+ if (peri -> func ) {
570576
571- // If currently observing, stop if we need to scan for a peripheral.
572- if (pbdrv_bluetooth_is_observing && peri -> func == pbdrv_bluetooth_peripheral_scan_and_connect_func ) {
573- PBIO_OS_AWAIT (state , & sub , pbdrv_bluetooth_stop_observing_func (& sub , NULL ));
574- observe_restart_requested = true;
575- }
577+ // If currently observing, stop if we need to scan for a peripheral.
578+ if (pbdrv_bluetooth_is_observing && peri -> func == pbdrv_bluetooth_peripheral_scan_and_connect_func ) {
579+ PBIO_OS_AWAIT (state , & sub , pbdrv_bluetooth_stop_observing_func (& sub , NULL ));
580+ observe_restart_requested = true;
581+ }
576582
577- PBIO_OS_AWAIT (state , & sub , peri -> err = peri -> func (& sub , peri ));
578- peri -> func = NULL ;
579- peri -> cancel = false;
583+ PBIO_OS_AWAIT (state , & sub , peri -> err = peri -> func (& sub , peri ));
584+ peri -> func = NULL ;
585+ peri -> cancel = false;
586+ }
580587 }
581588
582589 // Restart if we stopped it temporarily to scan for a peripheral or
@@ -606,21 +613,32 @@ pbio_error_t pbdrv_bluetooth_close_user_tasks(pbio_os_state_t *state, pbio_os_ti
606613
607614 static pbio_os_state_t sub ;
608615
616+ // For looping over peripherals.
617+ static uint8_t peri_index ;
618+ static pbdrv_bluetooth_peripheral_t * peri ;
619+
609620 if (pbio_os_timer_is_expired (timer )) {
610621 return PBIO_ERROR_TIMEDOUT ;
611622 }
612623
613624 PBIO_OS_ASYNC_BEGIN (state );
614625
626+ // Requests peripheral operations to cancel, if they support it.
615627 pbdrv_bluetooth_cancel_operation_request ();
616628
617- // Let ongoing user tasks finish first.
618- PBIO_OS_AWAIT (state , & sub , pbdrv_bluetooth_await_peripheral_command (& sub , & peripheral_singleton ));
619- PBIO_OS_AWAIT (state , & sub , pbdrv_bluetooth_await_advertise_or_scan_command (& sub , NULL ));
629+ for (peri_index = 0 ; peri_index < PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS ; peri_index ++ ) {
630+ peri = pbdrv_bluetooth_peripheral_get_by_index (peri_index );
631+
632+ // Await ongoing peripheral user task.
633+ PBIO_OS_AWAIT (state , & sub , pbdrv_bluetooth_await_peripheral_command (& sub , peri ));
634+
635+ // Disconnect peripheral.
636+ pbdrv_bluetooth_peripheral_disconnect (peri );
637+ PBIO_OS_AWAIT (state , & sub , pbdrv_bluetooth_await_peripheral_command (& sub , peri ));
638+ }
620639
621- // Disconnect peripheral.
622- pbdrv_bluetooth_peripheral_disconnect (& peripheral_singleton );
623- PBIO_OS_AWAIT (state , & sub , pbdrv_bluetooth_await_peripheral_command (& sub , & peripheral_singleton ));
640+ // Let ongoing user task finish first.
641+ PBIO_OS_AWAIT (state , & sub , pbdrv_bluetooth_await_advertise_or_scan_command (& sub , NULL ));
624642
625643 // Stop scanning.
626644 pbdrv_bluetooth_start_observing (NULL );
@@ -643,7 +661,16 @@ void pbdrv_bluetooth_deinit(void) {
643661 // Under normal operation ::pbdrv_bluetooth_close_user_tasks completes
644662 // normally and there should be no user activity at this point. If there
645663 // is, a task got stuck, so exit forcefully.
646- if (advertising_or_scan_err == PBIO_ERROR_AGAIN || peripheral_singleton .err == PBIO_ERROR_AGAIN ) {
664+ bool failed_to_stop = advertising_or_scan_err == PBIO_ERROR_AGAIN ;
665+ for (uint8_t i = 0 ; i < PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS ; i ++ ) {
666+ pbdrv_bluetooth_peripheral_t * peri = pbdrv_bluetooth_peripheral_get_by_index (i );
667+ if (peri -> err == PBIO_ERROR_AGAIN ) {
668+ failed_to_stop = true;
669+ break ;
670+ }
671+ }
672+
673+ if (failed_to_stop ) {
647674 // Hard reset without waiting on completion of any process.
648675 DEBUG_PRINT ("Bluetooth deinit: forcing hard reset due to busy tasks.\n" );
649676 pbdrv_bluetooth_controller_reset_hard ();
0 commit comments