Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
- Fixed Powered Up remote and Xbox Controller working only after the first
connection. All of the above Remote and Xbox Controller were introduced in
the previous beta release, so did not affect any stable release ([support#2521]).
- Fixed Xbox Controller sometimes not working the first time ([support#1509]).

[support#1509]: https://github.com/pybricks/support/issues/1509
[support#1962]: https://github.com/pybricks/support/issues/1962
[support#2468]: https://github.com/pybricks/support/issues/2468
[support#2497]: https://github.com/pybricks/support/issues/2497
Expand Down
21 changes: 16 additions & 5 deletions lib/pbio/drv/bluetooth/bluetooth.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2018-2025 The Pybricks Authors
// Copyright (c) 2018-2026 The Pybricks Authors

// Common Bluetooth driver code

Expand Down Expand Up @@ -195,15 +195,19 @@ pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect(pbdrv_bluetooth_periphe
return PBIO_ERROR_BUSY;
}

// Reset peripheral instance but keep user reference.
void *user = peri->user;
memset(peri, 0, sizeof(pbdrv_bluetooth_peripheral_t));
peri->user = user;
// Must provide matchers.
if (!config || !config->match_adv || !config->match_adv_rsp) {
return PBIO_ERROR_INVALID_ARG;
}

// Used to compare subsequent advertisements, so we should reset it.
memset(peri->bdaddr, 0, sizeof(peri->bdaddr));

// Initialize operation for handling on the main thread.
peri->config = config;
peri->func = pbdrv_bluetooth_peripheral_scan_and_connect_func;
peri->err = PBIO_ERROR_AGAIN;
peri->cancel = false;
pbio_os_timer_set(&peri->timer, config->timeout);
pbio_os_request_poll();

Expand All @@ -221,6 +225,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_disconnect(void) {

// Pass silently for already disconnected.
if (!pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL)) {
peri->err = PBIO_SUCCESS;
return PBIO_SUCCESS;
}

Expand Down Expand Up @@ -312,6 +317,7 @@ pbio_error_t pbdrv_bluetooth_await_peripheral_command(pbio_os_state_t *state, vo

void pbdrv_bluetooth_cancel_operation_request(void) {
// Only some peripheral actions support cancellation.
DEBUG_PRINT("Bluetooth operation cancel requested.\n");
peripheral_singleton.cancel = true;
}

Expand Down Expand Up @@ -340,6 +346,7 @@ pbio_error_t pbdrv_bluetooth_start_advertising(bool start) {
// Already in requested state. This makes it safe to call stop advertising
// even if it already stopped on becoming connected;
if (start == is_advertising) {
advertising_or_scan_err = PBIO_SUCCESS;
return PBIO_SUCCESS;
}

Expand Down Expand Up @@ -384,6 +391,7 @@ pbio_error_t pbdrv_bluetooth_start_broadcasting(const uint8_t *data, size_t size

if (!is_broadcasting) {
// Already stopped.
advertising_or_scan_err = PBIO_SUCCESS;
return PBIO_SUCCESS;
}
advertising_or_scan_err = PBIO_ERROR_AGAIN;
Expand All @@ -395,6 +403,7 @@ pbio_error_t pbdrv_bluetooth_start_broadcasting(const uint8_t *data, size_t size
// Avoid I/O operations if the user tries to broadcast the same data
// over and over in a tight loop.
if (is_broadcasting && pbdrv_bluetooth_broadcast_data_size == size && !memcmp(pbdrv_bluetooth_broadcast_data, data, size)) {
advertising_or_scan_err = PBIO_SUCCESS;
return PBIO_SUCCESS;
}
pbdrv_bluetooth_broadcast_data_size = size;
Expand Down Expand Up @@ -426,6 +435,7 @@ pbio_error_t pbdrv_bluetooth_start_observing(pbdrv_bluetooth_start_observing_cal
bool should_observe = callback ? true : false;

if (should_observe == pbdrv_bluetooth_is_observing) {
advertising_or_scan_err = PBIO_SUCCESS;
return PBIO_SUCCESS;
}

Expand Down Expand Up @@ -646,6 +656,7 @@ void pbdrv_bluetooth_deinit(void) {
// is, a task got stuck, so exit forcefully.
if (advertising_or_scan_err == PBIO_ERROR_AGAIN || peripheral_singleton.err == PBIO_ERROR_AGAIN) {
// Hard reset without waiting on completion of any process.
DEBUG_PRINT("Bluetooth deinit: forcing hard reset due to busy tasks.\n");
pbdrv_bluetooth_controller_reset_hard();
return;
}
Expand Down
Loading