Skip to content

Commit dff7279

Browse files
committed
pbio/drv/bluetooth: Keep Bluetooth always on.
It turns out that we don't need to reset Bluetooth ever, so simplify this further by taking this out. The Bluetooth button will just toggle the advertising state.
1 parent 990592f commit dff7279

File tree

7 files changed

+76
-185
lines changed

7 files changed

+76
-185
lines changed

lib/pbio/drv/bluetooth/bluetooth.c

Lines changed: 68 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -27,38 +27,6 @@
2727
#define DEBUG_PRINT(...)
2828
#endif
2929

30-
/**
31-
* Bluetooth power state. True means on (or on requested) False means off (or off requested).
32-
*/
33-
static bool power_on_requested;
34-
35-
/**
36-
* Bluetooth power enable busy state. True means that the operation is busy.
37-
*
38-
* Starts off in the reset state, so starts busy.
39-
*/
40-
static bool power_change_busy = true;
41-
42-
pbio_error_t pbdrv_bluetooth_power_on(pbio_os_state_t *state, bool on) {
43-
PBIO_OS_ASYNC_BEGIN(state);
44-
45-
// Await ongoing state change if any.
46-
PBIO_OS_AWAIT_WHILE(state, power_change_busy);
47-
48-
// Already in requested state.
49-
if (power_on_requested == on) {
50-
return PBIO_SUCCESS;
51-
}
52-
53-
// Kick the Bluetooth process and await Bluetooth to become ready again.
54-
power_change_busy = true;
55-
power_on_requested = on;
56-
pbio_os_request_poll();
57-
PBIO_OS_AWAIT_WHILE(state, power_change_busy);
58-
59-
PBIO_OS_ASYNC_END(PBIO_SUCCESS);
60-
}
61-
6230
pbdrv_bluetooth_receive_handler_t pbdrv_bluetooth_receive_handler;
6331

6432
void pbdrv_bluetooth_set_receive_handler(pbdrv_bluetooth_receive_handler_t handler) {
@@ -98,6 +66,7 @@ void pbdrv_bluetooth_init(void) {
9866
// as soon as the previous one completes + 1 byte for ring buf pointer
9967
static uint8_t stdout_buf[PBDRV_BLUETOOTH_MAX_CHAR_SIZE * 2 + 1];
10068
lwrb_init(&stdout_ring_buf, stdout_buf, PBIO_ARRAY_SIZE(stdout_buf));
69+
pbio_busy_count_up();
10170

10271
pbdrv_bluetooth_init_hci();
10372
}
@@ -450,112 +419,98 @@ pbio_error_t pbdrv_bluetooth_process_thread(pbio_os_state_t *state, void *contex
450419

451420
PBIO_OS_ASYNC_BEGIN(state);
452421

453-
while (!shutting_down) {
454-
455-
DEBUG_PRINT("Bluetooth disable requested.\n");
456-
457-
pbdrv_bluetooth_advertising_state = PBDRV_BLUETOOTH_ADVERTISING_STATE_NONE;
458-
pbdrv_bluetooth_is_observing = false;
459-
observe_restart_requested = false;
422+
init:
460423

461-
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_controller_reset(&sub, &timer));
424+
DEBUG_PRINT("Bluetooth reset.\n");
462425

463-
DEBUG_PRINT("Bluetooth is now off.\n");
464-
power_change_busy = false;
465-
pbio_os_request_poll();
426+
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_controller_reset(&sub, &timer));
466427

467-
// Bluetooth is now disabled. Await system processes to ask for enable.
468-
PBIO_OS_AWAIT_UNTIL(state, power_on_requested || shutting_down);
469-
if (shutting_down) {
470-
break;
471-
}
472-
DEBUG_PRINT("Bluetooth enable requested.\n");
428+
DEBUG_PRINT("Bluetooth enable.\n");
473429

474-
PBIO_OS_AWAIT(state, &sub, err = pbdrv_bluetooth_controller_initialize(&sub, &timer));
475-
if (err != PBIO_SUCCESS) {
476-
DEBUG_PRINT("Initialization failed. Reset and retry.\n");
477-
continue;
478-
}
430+
PBIO_OS_AWAIT(state, &sub, err = pbdrv_bluetooth_controller_initialize(&sub, &timer));
431+
if (err != PBIO_SUCCESS) {
432+
DEBUG_PRINT("Initialization failed. Reset and retry.\n");
433+
goto init;
434+
}
479435

480-
DEBUG_PRINT("Bluetooth is now on and initialized.\n");
481-
power_change_busy = false;
482-
pbio_os_request_poll();
436+
DEBUG_PRINT("Bluetooth is now on and initialized.\n");
483437

484-
pbio_os_timer_set(&status_timer, PBDRV_BLUETOOTH_STATUS_UPDATE_INTERVAL);
438+
pbio_busy_count_down();
485439

486-
// Service scheduled tasks as long as Bluetooth is enabled.
487-
while (power_on_requested && !shutting_down) {
440+
pbio_os_timer_set(&status_timer, PBDRV_BLUETOOTH_STATUS_UPDATE_INTERVAL);
488441

489-
// In principle, this wait is only needed if there is nothing to do.
490-
// In practice, leaving it here helps rather than hurts since it
491-
// allows short stdout messages to be queued rather than sent separately.
492-
PBIO_OS_AWAIT_MS(state, &timer, 1);
442+
// Service scheduled tasks as long as Bluetooth is enabled.
443+
while (!shutting_down) {
493444

494-
// Handle pending status update, if any.
495-
if (can_send && (status_data_pending || pbio_os_timer_is_expired(&status_timer))) {
445+
// In principle, this wait is only needed if there is nothing to do.
446+
// In practice, leaving it here helps rather than hurts since it
447+
// allows short stdout messages to be queued rather than sent separately.
448+
PBIO_OS_AWAIT_MS(state, &timer, 1);
496449

497-
// When a status is pending, cache it here while we write it out,
498-
// so a new status can be set in the mean time without losing it.
499-
static uint8_t status_buf[PBIO_PYBRICKS_EVENT_STATUS_REPORT_SIZE];
500-
memcpy(status_buf, status_data, PBIO_PYBRICKS_EVENT_STATUS_REPORT_SIZE);
501-
status_data_pending = false;
450+
// Handle pending status update, if any.
451+
if (can_send && (status_data_pending || pbio_os_timer_is_expired(&status_timer))) {
502452

503-
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_send_pybricks_value_notification(&sub, status_buf, sizeof(status_buf)));
453+
// When a status is pending, cache it here while we write it out,
454+
// so a new status can be set in the mean time without losing it.
455+
static uint8_t status_buf[PBIO_PYBRICKS_EVENT_STATUS_REPORT_SIZE];
456+
memcpy(status_buf, status_data, PBIO_PYBRICKS_EVENT_STATUS_REPORT_SIZE);
457+
status_data_pending = false;
504458

505-
pbio_os_timer_set(&status_timer, status_timer.duration);
506-
}
459+
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_send_pybricks_value_notification(&sub, status_buf, sizeof(status_buf)));
507460

508-
// Handle pending stdout, if any.
509-
if (can_send && lwrb_get_full(&stdout_ring_buf) != 0) {
510-
stdout_send_busy = true;
461+
pbio_os_timer_set(&status_timer, status_timer.duration);
462+
}
511463

512-
static uint8_t stdout_buf[PBDRV_BLUETOOTH_MAX_CHAR_SIZE] = { PBIO_PYBRICKS_EVENT_WRITE_STDOUT };
513-
static uint16_t stdout_len;
464+
// Handle pending stdout, if any.
465+
if (can_send && lwrb_get_full(&stdout_ring_buf) != 0) {
466+
stdout_send_busy = true;
514467

515-
stdout_len = lwrb_read(&stdout_ring_buf, &stdout_buf[1], PBDRV_BLUETOOTH_MAX_CHAR_SIZE - 1) + 1;
516-
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_send_pybricks_value_notification(&sub, stdout_buf, stdout_len));
468+
static uint8_t stdout_buf[PBDRV_BLUETOOTH_MAX_CHAR_SIZE] = { PBIO_PYBRICKS_EVENT_WRITE_STDOUT };
469+
static uint16_t stdout_len;
517470

518-
stdout_send_busy = false;
519-
}
471+
stdout_len = lwrb_read(&stdout_ring_buf, &stdout_buf[1], PBDRV_BLUETOOTH_MAX_CHAR_SIZE - 1) + 1;
472+
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_send_pybricks_value_notification(&sub, stdout_buf, stdout_len));
520473

521-
// Handle pending user value notification, if any.
522-
if (can_send && user_notification_size) {
474+
stdout_send_busy = false;
475+
}
523476

524-
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_send_pybricks_value_notification(&sub,
525-
user_notification_send_buf,
526-
user_notification_size));
477+
// Handle pending user value notification, if any.
478+
if (can_send && user_notification_size) {
527479

528-
user_notification_size = 0;
529-
}
480+
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_send_pybricks_value_notification(&sub,
481+
user_notification_send_buf,
482+
user_notification_size));
530483

531-
// Handle pending advertising/scan enable/disable task, if any.
532-
if (advertising_or_scan_func) {
533-
PBIO_OS_AWAIT(state, &sub, advertising_or_scan_err = advertising_or_scan_func(&sub, NULL));
534-
advertising_or_scan_func = NULL;
535-
}
536-
537-
// Handle pending peripheral task, if any.
538-
if (peri->func) {
484+
user_notification_size = 0;
485+
}
539486

540-
// If currently observing, stop if we need to scan for a peripheral.
541-
if (pbdrv_bluetooth_is_observing && peri->func == pbdrv_bluetooth_peripheral_scan_and_connect_func) {
542-
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_stop_observing_func(&sub, NULL));
543-
observe_restart_requested = true;
544-
}
487+
// Handle pending advertising/scan enable/disable task, if any.
488+
if (advertising_or_scan_func) {
489+
PBIO_OS_AWAIT(state, &sub, advertising_or_scan_err = advertising_or_scan_func(&sub, NULL));
490+
advertising_or_scan_func = NULL;
491+
}
545492

546-
PBIO_OS_AWAIT(state, &sub, peri->err = peri->func(&sub, peri));
547-
peri->func = NULL;
548-
peri->cancel = false;
549-
}
493+
// Handle pending peripheral task, if any.
494+
if (peri->func) {
550495

551-
// Restart if we stopped it temporarily to scan for a peripheral or
552-
// when externaly requested.
553-
if (observe_restart_requested) {
554-
DEBUG_PRINT("Restart observe.\n");
496+
// If currently observing, stop if we need to scan for a peripheral.
497+
if (pbdrv_bluetooth_is_observing && peri->func == pbdrv_bluetooth_peripheral_scan_and_connect_func) {
555498
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_stop_observing_func(&sub, NULL));
556-
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_start_observing_func(&sub, NULL));
557-
observe_restart_requested = false;
499+
observe_restart_requested = true;
558500
}
501+
502+
PBIO_OS_AWAIT(state, &sub, peri->err = peri->func(&sub, peri));
503+
peri->func = NULL;
504+
peri->cancel = false;
505+
}
506+
507+
// Restart if we stopped it temporarily to scan for a peripheral or
508+
// when externaly requested.
509+
if (observe_restart_requested) {
510+
DEBUG_PRINT("Restart observe.\n");
511+
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_stop_observing_func(&sub, NULL));
512+
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_start_observing_func(&sub, NULL));
513+
observe_restart_requested = false;
559514
}
560515
}
561516

lib/pbio/include/pbdrv/bluetooth.h

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -237,19 +237,6 @@ void pbdrv_bluetooth_init(void);
237237
*/
238238
void pbdrv_bluetooth_deinit(void);
239239

240-
/**
241-
* Turns the Bluetooth chip power on or off. Await the operation.
242-
*
243-
* If it is already in the requested power state, this completes successfully
244-
* right away.
245-
*
246-
* @param [in] state The protothread state.
247-
* @param [in] on If true, turns power on, otherwise turns power off.
248-
* @return ::PBIO_SUCCESS on completion,
249-
* ::PBIO_ERROR_AGAIN while awaiting.
250-
*/
251-
pbio_error_t pbdrv_bluetooth_power_on(pbio_os_state_t *state, bool on);
252-
253240
/**
254241
* Gets the bluetooth hub name.
255242
*/
@@ -524,10 +511,6 @@ static inline void pbdrv_bluetooth_init(void) {
524511
static inline void pbdrv_bluetooth_deinit(void) {
525512
}
526513

527-
static inline pbio_error_t pbdrv_bluetooth_power_on(pbio_os_state_t *state, bool on) {
528-
return PBIO_ERROR_NOT_SUPPORTED;
529-
}
530-
531514
static inline const char *pbdrv_bluetooth_get_hub_name(void) {
532515
return "Pybricks Hub";
533516
}

lib/pbio/sys/hmi_pup.c

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -157,15 +157,6 @@ static pbio_error_t run_ui(pbio_os_state_t *state, pbio_os_timer_t *timer) {
157157

158158
static pbio_os_state_t sub;
159159

160-
/**
161-
* Persistent state indicating whether we were connected the last time the
162-
* HMI ran. If it was connected before but not now, we know we became
163-
* disconnected. This is when we restart Bluetooth to get a new address and
164-
* avoid reconnection issues. We also want to do that on boot, so we start
165-
* this in true.
166-
*/
167-
static bool previously_connected = true;
168-
169160
PBIO_OS_ASYNC_BEGIN(state);
170161

171162
for (;;) {
@@ -182,28 +173,15 @@ static pbio_error_t run_ui(pbio_os_state_t *state, pbio_os_timer_t *timer) {
182173
DEBUG_PRINT("Connected: yes\n");
183174
pbsys_status_set(PBIO_PYBRICKS_STATUS_BLE_HOST_CONNECTED);
184175
pbsys_status_clear(PBIO_PYBRICKS_STATUS_BLE_ADVERTISING);
185-
previously_connected = true;
186176
// No need to stop advertising since this is automatic.
187177
} else {
188178
// Not connected right now.
189179
DEBUG_PRINT("Connected: No\n");
190-
if (previously_connected) {
191-
// Became disconnected just now or some time throughout the
192-
// last user program run. Reset Bluetooth to get a new address.
193-
// Also used the very first time we power on.
194-
DEBUG_PRINT("Reset Bluetooth.\n");
195-
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_power_on(&sub, false));
196-
}
197180
pbsys_status_clear(PBIO_PYBRICKS_STATUS_BLE_HOST_CONNECTED);
198-
previously_connected = false;
199181

200-
// Enable or disable Bluetooth depending on user setting. This is
201-
// a safe no-op if this was already set.
202-
DEBUG_PRINT("Bluetooth is configured to be: %s. \n", pbsys_storage_settings_bluetooth_enabled_get() ? "on" : "off");
203-
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_power_on(&sub, pbsys_storage_settings_bluetooth_enabled_get()));
204-
205-
// Update advertising state.
182+
// Enable or disable advertising depending on user setting.
206183
bool do_advertise = pbsys_storage_settings_bluetooth_enabled_get();
184+
DEBUG_PRINT("Advertising is configured to be: %s. \n", do_advertise ? "on" : "off");
207185
if (do_advertise) {
208186
pbsys_status_set(PBIO_PYBRICKS_STATUS_BLE_ADVERTISING);
209187
} else {
@@ -243,11 +221,11 @@ static pbio_error_t run_ui(pbio_os_state_t *state, pbio_os_timer_t *timer) {
243221
// Wait for button press, external program start, or connection change.
244222
pbdrv_button_get_pressed() ||
245223
pbsys_main_program_start_is_requested() ||
246-
pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_LE) != previously_connected;
224+
pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_LE) != pbsys_status_test(PBIO_PYBRICKS_STATUS_BLE_HOST_CONNECTED);
247225
}));
248226

249227
// Became connected or disconnected, so go back to handle it.
250-
if (pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_LE) != previously_connected) {
228+
if (pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_LE) != pbsys_status_test(PBIO_PYBRICKS_STATUS_BLE_HOST_CONNECTED)) {
251229
DEBUG_PRINT("Connection changed.\n");
252230
continue;
253231
}
@@ -296,11 +274,9 @@ static pbio_error_t run_ui(pbio_os_state_t *state, pbio_os_timer_t *timer) {
296274
}
297275

298276
// Stop advertising if we are still doing so.
299-
if (pbsys_status_test(PBIO_PYBRICKS_STATUS_BLE_ADVERTISING)) {
300-
DEBUG_PRINT("Stop advertising on HMI exit.\n");
301-
pbdrv_bluetooth_start_advertising(false);
302-
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_await_advertise_or_scan_command(&sub, NULL));
303-
}
277+
DEBUG_PRINT("Stop advertising on HMI exit.\n");
278+
pbdrv_bluetooth_start_advertising(false);
279+
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_await_advertise_or_scan_command(&sub, NULL));
304280

305281
// Wait for all buttons to be released so the user doesn't accidentally
306282
// push their robot off course.

lib/pbio/test/sys/test_bluetooth.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,7 @@ static pbio_error_t test_bluetooth(pbio_os_state_t *state, void *context) {
2626

2727
pbsys_host_init();
2828

29-
// power should be initialized to off
30-
tt_want_uint_op(pbio_test_bluetooth_get_control_state(), ==, PBIO_TEST_BLUETOOTH_STATE_OFF);
31-
32-
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_power_on(&sub, false));
33-
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_power_on(&sub, true));
34-
29+
// power should be initialized by the time pbdrv completes.
3530
tt_want_uint_op(pbio_test_bluetooth_get_control_state(), ==, PBIO_TEST_BLUETOOTH_STATE_ON);
3631

3732
pbdrv_bluetooth_start_advertising(true);

pybricks/common/pb_type_ble.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -551,12 +551,6 @@ mp_obj_t pb_type_BLE_new(mp_obj_t broadcast_channel_in, mp_obj_t observe_channel
551551
mp_raise_ValueError(MP_ERROR_TEXT("Too many observe channels"));
552552
}
553553

554-
// Raise if Bluetooth is attempted to be used while not enabled.
555-
#if PBSYS_CONFIG_HMI_PUP_BLUETOOTH_BUTTON
556-
if (!pbsys_storage_settings_bluetooth_enabled_get() && (num_observe_channels > 0 || broadcast_channel_in != mp_const_none)) {
557-
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Bluetooth not enabled"));
558-
}
559-
#endif // PBSYS_CONFIG_HMI_PUP_BLUETOOTH_BUTTON
560554
pb_obj_BLE_t *self = mp_obj_malloc_var_with_finaliser(pb_obj_BLE_t, observed_data_t, num_observe_channels, &pb_type_BLE);
561555
self->broadcast_channel = broadcast_channel_in;
562556

pybricks/iodevices/pb_type_iodevices_lwp3device.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -378,12 +378,6 @@ static pbio_error_t pb_lwp3device_connect_thread(pbio_os_state_t *state, mp_obj_
378378

379379
static mp_obj_t pb_lwp3device_connect(mp_obj_t self_in, mp_obj_t name_in, mp_obj_t timeout_in, lwp3_hub_kind_t hub_kind, pbdrv_bluetooth_receive_handler_t notification_handler, bool pair) {
380380

381-
#if PBSYS_CONFIG_HMI_PUP_BLUETOOTH_BUTTON
382-
if (!pbsys_storage_settings_bluetooth_enabled_get()) {
383-
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Bluetooth not enabled"));
384-
}
385-
#endif // PBSYS_CONFIG_HMI_PUP_BLUETOOTH_BUTTON
386-
387381
pb_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_in);
388382

389383
self->iter = NULL;

pybricks/iodevices/pb_type_iodevices_xbox_controller.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -372,12 +372,6 @@ static mp_obj_t pb_type_xbox_make_new(const mp_obj_type_t *type, size_t n_args,
372372
#endif // PYBRICKS_HUB_TECHNICHUB
373373
);
374374

375-
#if PBSYS_CONFIG_HMI_PUP_BLUETOOTH_BUTTON
376-
if (!pbsys_storage_settings_bluetooth_enabled_get()) {
377-
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("Bluetooth not enabled"));
378-
}
379-
#endif // PBSYS_CONFIG_HMI_PUP_BLUETOOTH_BUTTON
380-
381375
pb_module_tools_assert_blocking();
382376

383377
pb_type_xbox_obj_t *self = mp_obj_malloc(pb_type_xbox_obj_t, type);

0 commit comments

Comments
 (0)