Skip to content

Commit 66ae6c4

Browse files
committed
pbio/drv/bluetooth: Shut down gracefully.
Before the Bluetooth overhaul, we were just powering down. In the recent commits, this was not yet implemented, so the hub would stay connected or keep advertising once turned off and charging. Poweroff is now back, but we also gracefully disconnect first to be nice to Pybricks Code.
1 parent 05aec12 commit 66ae6c4

File tree

6 files changed

+61
-7
lines changed

6 files changed

+61
-7
lines changed

lib/pbio/drv/bluetooth/bluetooth.c

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <pbdrv/bluetooth.h>
1313

14+
#include <pbio/busy_count.h>
1415
#include <pbio/error.h>
1516
#include <pbio/os.h>
1617
#include <pbio/protocol.h>
@@ -411,6 +412,8 @@ pbio_error_t pbdrv_bluetooth_await_advertise_or_scan_command(pbio_os_state_t *st
411412
return advertising_or_scan_func ? advertising_or_scan_err : PBIO_SUCCESS;
412413
}
413414

415+
static bool shutting_down;
416+
414417
/**
415418
* This is the main high level pbdrv/bluetooth thread. It is driven forward by
416419
* the platform-specific HCI process whenever there is new data to process or
@@ -434,7 +437,9 @@ pbio_error_t pbdrv_bluetooth_process_thread(pbio_os_state_t *state, void *contex
434437

435438
PBIO_OS_ASYNC_BEGIN(state);
436439

437-
for (;;) {
440+
while (!shutting_down) {
441+
442+
DEBUG_PRINT("Bluetooth disable requested.\n");
438443

439444
pbdrv_bluetooth_is_broadcasting = false;
440445
pbdrv_bluetooth_is_observing = false;
@@ -447,7 +452,10 @@ pbio_error_t pbdrv_bluetooth_process_thread(pbio_os_state_t *state, void *contex
447452
pbio_os_request_poll();
448453

449454
// Bluetooth is now disabled. Await system processes to ask for enable.
450-
PBIO_OS_AWAIT_UNTIL(state, power_on_requested);
455+
PBIO_OS_AWAIT_UNTIL(state, power_on_requested || shutting_down);
456+
if (shutting_down) {
457+
break;
458+
}
451459
DEBUG_PRINT("Bluetooth enable requested.\n");
452460

453461
PBIO_OS_AWAIT(state, &sub, err = pbdrv_bluetooth_controller_initialize(&sub, &timer));
@@ -463,9 +471,11 @@ pbio_error_t pbdrv_bluetooth_process_thread(pbio_os_state_t *state, void *contex
463471
pbio_os_timer_set(&status_timer, PBDRV_BLUETOOTH_STATUS_UPDATE_INTERVAL);
464472

465473
// Service scheduled tasks as long as Bluetooth is enabled.
466-
while (power_on_requested) {
474+
while (power_on_requested && !shutting_down) {
467475

468-
// REVISIT: Only needed if there is nothing to do
476+
// In principle, this wait is only needed if there is nothing to do.
477+
// In practice, leaving it here helps rather than hurts since it
478+
// allows short stdout messages to be queued rather than sent separately.
469479
PBIO_OS_AWAIT_MS(state, &timer, 1);
470480

471481
// Handle pending status update, if any.
@@ -534,11 +544,26 @@ pbio_error_t pbdrv_bluetooth_process_thread(pbio_os_state_t *state, void *contex
534544
observe_restart_requested = false;
535545
}
536546
}
537-
538-
DEBUG_PRINT("Bluetooth disable requested.\n");
539547
}
540548

549+
DEBUG_PRINT("Shutdown requested.\n");
550+
551+
// Power down the chip. This will disconnect from the host first.
552+
// The peripheral has already been disconnected in the cleanup that runs after
553+
// every program. If we change that behavior, we can do the disconnect here.
554+
555+
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_controller_reset(&sub, &timer));
556+
557+
pbio_busy_count_down();
558+
541559
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
542560
}
543561

562+
void pbdrv_bluetooth_deinit(void) {
563+
pbio_busy_count_up();
564+
pbdrv_bluetooth_cancel_operation_request();
565+
shutting_down = true;
566+
pbio_os_request_poll();
567+
}
568+
544569
#endif // PBDRV_CONFIG_BLUETOOTH_STM32_CC2640

lib/pbio/drv/bluetooth/bluetooth_btstack.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,11 @@ pbio_error_t pbdrv_bluetooth_controller_reset(pbio_os_state_t *state, pbio_os_ti
858858

859859
PBIO_OS_ASYNC_BEGIN(state);
860860

861-
// TODO: Reset state
861+
// Disconnect gracefully if connected to host.
862+
if (le_con_handle != HCI_CON_HANDLE_INVALID) {
863+
gap_disconnect(le_con_handle);
864+
PBIO_OS_AWAIT_UNTIL(state, le_con_handle == HCI_CON_HANDLE_INVALID);
865+
}
862866

863867
hci_power_control(HCI_POWER_OFF);
864868
PBIO_OS_AWAIT_UNTIL(state, hci_get_state() == HCI_STATE_OFF);

lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,15 @@ static pbio_error_t init_uart_service(pbio_os_state_t *state, void *context) {
12401240
pbio_error_t pbdrv_bluetooth_controller_reset(pbio_os_state_t *state, pbio_os_timer_t *timer) {
12411241
PBIO_OS_ASYNC_BEGIN(state);
12421242

1243+
// Disconnect gracefully if connected to host.
1244+
if (conn_handle) {
1245+
PBIO_OS_AWAIT_WHILE(state, write_xfer_size);
1246+
aci_gap_terminate_begin(conn_handle, HCI_OE_USER_ENDED_CONNECTION);
1247+
PBIO_OS_AWAIT_UNTIL(state, hci_command_status);
1248+
aci_gap_terminate_end();
1249+
PBIO_OS_AWAIT_UNTIL(state, conn_handle == 0);
1250+
}
1251+
12431252
pybricks_notify_en = uart_tx_notify_en = false;
12441253
conn_handle = peripheral_singleton.con_handle = 0;
12451254

lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1840,6 +1840,13 @@ static pbio_error_t init_uart_service(pbio_os_state_t *state, void *context) {
18401840
pbio_error_t pbdrv_bluetooth_controller_reset(pbio_os_state_t *state, pbio_os_timer_t *timer) {
18411841
PBIO_OS_ASYNC_BEGIN(state);
18421842

1843+
// Disconnect gracefully if connected to host.
1844+
if (conn_handle != NO_CONNECTION) {
1845+
PBIO_OS_AWAIT_WHILE(state, write_xfer_size);
1846+
GAP_TerminateLinkReq(conn_handle, 0x13);
1847+
PBIO_OS_AWAIT_UNTIL(state, conn_handle == NO_CONNECTION);
1848+
}
1849+
18431850
pybricks_notify_en = uart_tx_notify_en = false;
18441851
conn_handle = peripheral_singleton.con_handle = NO_CONNECTION;
18451852

lib/pbio/drv/core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ void pbdrv_init(void) {
101101
void pbdrv_deinit(void) {
102102

103103
pbdrv_imu_deinit();
104+
pbdrv_bluetooth_deinit();
104105

105106
while (pbio_busy_count_busy()) {
106107
pbio_os_run_processes_once();

lib/pbio/include/pbdrv/bluetooth.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,11 @@ typedef void (*pbdrv_bluetooth_start_observing_callback_t)(pbdrv_bluetooth_ad_ty
232232
*/
233233
void pbdrv_bluetooth_init(void);
234234

235+
/**
236+
* Deinitializes the Bluetooth driver.
237+
*/
238+
void pbdrv_bluetooth_deinit(void);
239+
235240
/**
236241
* Turns the Bluetooth chip power on or off. Await the operation.
237242
*
@@ -503,6 +508,9 @@ pbio_error_t pbdrv_bluetooth_await_advertise_or_scan_command(pbio_os_state_t *st
503508
static inline void pbdrv_bluetooth_init(void) {
504509
}
505510

511+
static inline void pbdrv_bluetooth_deinit(void) {
512+
}
513+
506514
static inline pbio_error_t pbdrv_bluetooth_power_on(pbio_os_state_t *state, bool on) {
507515
return PBIO_ERROR_NOT_SUPPORTED;
508516
}

0 commit comments

Comments
 (0)