Skip to content
Closed
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
- Improved color detection when using default colors. Also changed the HSV calculation
for the SPIKE Color Sensor and Boost Color and Distance Sensor to make them
more similar. User code should measure HSV values again in old code ([pybricks-micropython#421]).
- Reduced user stack size to `12 KB` on SPIKE Prime Hub to make it the same as
SPIKE Essential Hub. This frees up some RAM for system resources, and we never
use this much in practice.

### Fixed
- Fixed `race=False` ignored in `pybricks.tools.multitask()` ([support#2468]).
Expand Down
1 change: 0 additions & 1 deletion bricks/_common/sources.mk
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\
drv/bluetooth/bluetooth_btstack_ev3.c \
drv/bluetooth/bluetooth_btstack_posix.c \
drv/bluetooth/bluetooth_btstack_stm32_hal.c \
drv/bluetooth/bluetooth_simulation.c \
drv/bluetooth/bluetooth_stm32_bluenrg.c \
drv/bluetooth/bluetooth_stm32_cc2640.c \
drv/bluetooth/firmware/bluetooth_init_cc2564C_1.4.c \
Expand Down
138 changes: 77 additions & 61 deletions lib/pbio/drv/bluetooth/bluetooth.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,51 +147,46 @@ pbio_error_t pbdrv_bluetooth_send_event_notification(pbio_os_state_t *state, pbi
// Functions related to connections to peripherals.
//

pbdrv_bluetooth_peripheral_t peripheral_singleton;

pbio_error_t pbdrv_bluetooth_peripheral_get_available(pbdrv_bluetooth_peripheral_t **peripheral, void *user) {
// Only a single peripheral instance supported for now.
*peripheral = &peripheral_singleton;

if (/* Already connected. */
pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL) ||
/* A different user is still claiming this resource. */
(*peripheral)->user ||
/* Busy. Could be connecting but not connected yet. */
(*peripheral)->func) {
return PBIO_ERROR_BUSY;
}

// Claim this device for new user.
(*peripheral)->user = user;
for (uint8_t i = 0; i < PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS; i++) {
pbdrv_bluetooth_peripheral_t *peri = pbdrv_bluetooth_peripheral_get_by_index(i);

return PBIO_SUCCESS;
// Test if not already in use, not connected, and not busy.
if (!pbdrv_bluetooth_peripheral_is_connected(peri) && !peri->user && !peri->func) {
// Claim this device for new user.
peri->user = user;
*peripheral = peri;
return PBIO_SUCCESS;
}
}

// All instances are in use.
*peripheral = NULL;
return PBIO_ERROR_BUSY;
}

void pbdrv_bluetooth_peripheral_release(pbdrv_bluetooth_peripheral_t *peripheral, void *user) {
// Only release if the user matches. A new user may have already safely
// claimed it, and this call to release may come from an orphaned user.
if (peripheral->user != user) {
if (!peripheral || peripheral->user != user) {
return;
}
peripheral->user = NULL;
}

const char *pbdrv_bluetooth_peripheral_get_name(void) {
pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton;
const char *pbdrv_bluetooth_peripheral_get_name(pbdrv_bluetooth_peripheral_t *peri) {
return peri->name;
}

pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect(pbdrv_bluetooth_peripheral_connect_config_t *config) {

pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton;
pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect(pbdrv_bluetooth_peripheral_t *peri, pbdrv_bluetooth_peripheral_connect_config_t *config) {

if (!pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_HCI)) {
return PBIO_ERROR_INVALID_OP;
}

// Can't connect if already connected or already busy.
if (pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL) || peri->func) {
if (pbdrv_bluetooth_peripheral_is_connected(peri) || peri->func) {
return PBIO_ERROR_BUSY;
}

Expand All @@ -214,17 +209,15 @@ pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect(pbdrv_bluetooth_periphe
return PBIO_SUCCESS;
}

pbio_error_t pbdrv_bluetooth_peripheral_disconnect(void) {

pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton;
pbio_error_t pbdrv_bluetooth_peripheral_disconnect(pbdrv_bluetooth_peripheral_t *peri) {

// Busy doing something else.
if (peri->func) {
return PBIO_ERROR_BUSY;
}

// Pass silently for already disconnected.
if (!pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL)) {
if (!pbdrv_bluetooth_peripheral_is_connected(peri)) {
peri->err = PBIO_SUCCESS;
return PBIO_SUCCESS;
}
Expand All @@ -236,11 +229,9 @@ pbio_error_t pbdrv_bluetooth_peripheral_disconnect(void) {
return PBIO_SUCCESS;
}

pbio_error_t pbdrv_bluetooth_peripheral_discover_characteristic(pbdrv_bluetooth_peripheral_char_t *characteristic) {
pbio_error_t pbdrv_bluetooth_peripheral_discover_characteristic(pbdrv_bluetooth_peripheral_t *peri, pbdrv_bluetooth_peripheral_char_t *characteristic) {

pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton;

if (!pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL)) {
if (!pbdrv_bluetooth_peripheral_is_connected(peri)) {
return PBIO_ERROR_NO_DEV;
}
if (peri->func) {
Expand All @@ -249,26 +240,24 @@ pbio_error_t pbdrv_bluetooth_peripheral_discover_characteristic(pbdrv_bluetooth_

// Initialize operation for handling on the main thread.
characteristic->handle = 0;
peripheral_singleton.char_now = characteristic;
peri->char_now = characteristic;
peri->func = pbdrv_bluetooth_peripheral_discover_characteristic_func;
peri->err = PBIO_ERROR_AGAIN;
pbio_os_request_poll();
return PBIO_SUCCESS;
}

pbio_error_t pbdrv_bluetooth_peripheral_read_characteristic(pbdrv_bluetooth_peripheral_char_t *characteristic) {

pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton;
pbio_error_t pbdrv_bluetooth_peripheral_read_characteristic(pbdrv_bluetooth_peripheral_t *peri, pbdrv_bluetooth_peripheral_char_t *characteristic) {

if (!pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL)) {
if (!pbdrv_bluetooth_peripheral_is_connected(peri)) {
return PBIO_ERROR_NO_DEV;
}
if (peri->func) {
return PBIO_ERROR_BUSY;
}

// Initialize operation for handling on the main thread.
peripheral_singleton.char_now = characteristic;
peri->char_now = characteristic;
peri->func = pbdrv_bluetooth_peripheral_read_characteristic_func;
peri->err = PBIO_ERROR_AGAIN;
pbio_os_request_poll();
Expand All @@ -279,11 +268,9 @@ uint16_t pbdrv_bluetooth_char_write_handle;
uint8_t pbdrv_bluetooth_char_write_data[PBDRV_BLUETOOTH_MAX_CHAR_SIZE];
size_t pbdrv_bluetooth_char_write_size;

pbio_error_t pbdrv_bluetooth_peripheral_write_characteristic(uint16_t handle, const uint8_t *data, size_t size) {

pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton;
pbio_error_t pbdrv_bluetooth_peripheral_write_characteristic(pbdrv_bluetooth_peripheral_t *peri, uint16_t handle, const uint8_t *data, size_t size) {

if (!pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL)) {
if (!pbdrv_bluetooth_peripheral_is_connected(peri)) {
return PBIO_ERROR_NO_DEV;
}
if (peri->func) {
Expand All @@ -306,7 +293,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_write_characteristic(uint16_t handle, co

pbio_error_t pbdrv_bluetooth_await_peripheral_command(pbio_os_state_t *state, void *context) {

pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton;
pbdrv_bluetooth_peripheral_t *peri = context;

// If the user is no longer calling this then the operation is no longer
// of interest and will be cancelled if the active function supports it.
Expand All @@ -318,7 +305,10 @@ 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;
for (uint8_t i = 0; i < PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS; i++) {
pbdrv_bluetooth_peripheral_t *peri = pbdrv_bluetooth_peripheral_get_by_index(i);
peri->cancel = true;
}
}

//
Expand Down Expand Up @@ -534,7 +524,10 @@ pbio_error_t pbdrv_bluetooth_process_thread(pbio_os_state_t *state, void *contex

// Shorthand notation accessible throughout.
bool can_send = pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_PYBRICKS);
pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton;

// For looping over peripherals.
static uint8_t peri_index;
static pbdrv_bluetooth_peripheral_t *peri;

PBIO_OS_ASYNC_BEGIN(state);

Expand Down Expand Up @@ -576,18 +569,21 @@ pbio_error_t pbdrv_bluetooth_process_thread(pbio_os_state_t *state, void *contex
advertising_or_scan_func = NULL;
}

// Handle pending peripheral task, if any.
if (peri->func) {
// Handle pending peripheral tasks, one at a time.
for (peri_index = 0; peri_index < PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS; peri_index++) {
peri = pbdrv_bluetooth_peripheral_get_by_index(peri_index);
if (peri->func) {

// If currently observing, stop if we need to scan for a peripheral.
if (pbdrv_bluetooth_is_observing && peri->func == pbdrv_bluetooth_peripheral_scan_and_connect_func) {
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_stop_observing_func(&sub, NULL));
observe_restart_requested = true;
}
// If currently observing, stop if we need to scan for a peripheral.
if (pbdrv_bluetooth_is_observing && peri->func == pbdrv_bluetooth_peripheral_scan_and_connect_func) {
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_stop_observing_func(&sub, NULL));
observe_restart_requested = true;
}

PBIO_OS_AWAIT(state, &sub, peri->err = peri->func(&sub, peri));
peri->func = NULL;
peri->cancel = false;
PBIO_OS_AWAIT(state, &sub, peri->err = peri->func(&sub, peri));
peri->func = NULL;
peri->cancel = false;
}
}

// Restart if we stopped it temporarily to scan for a peripheral or
Expand Down Expand Up @@ -617,21 +613,32 @@ pbio_error_t pbdrv_bluetooth_close_user_tasks(pbio_os_state_t *state, pbio_os_ti

static pbio_os_state_t sub;

// For looping over peripherals.
static uint8_t peri_index;
static pbdrv_bluetooth_peripheral_t *peri;

if (pbio_os_timer_is_expired(timer)) {
return PBIO_ERROR_TIMEDOUT;
}

PBIO_OS_ASYNC_BEGIN(state);

// Requests peripheral operations to cancel, if they support it.
pbdrv_bluetooth_cancel_operation_request();

// Let ongoing user tasks finish first.
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_await_peripheral_command(&sub, NULL));
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_await_advertise_or_scan_command(&sub, NULL));
for (peri_index = 0; peri_index < PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS; peri_index++) {
peri = pbdrv_bluetooth_peripheral_get_by_index(peri_index);

// Disconnect peripheral.
pbdrv_bluetooth_peripheral_disconnect();
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_await_peripheral_command(&sub, NULL));
// Await ongoing peripheral user task.
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_await_peripheral_command(&sub, peri));

// Disconnect peripheral.
pbdrv_bluetooth_peripheral_disconnect(peri);
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_await_peripheral_command(&sub, peri));
}

// Let ongoing user task finish first.
PBIO_OS_AWAIT(state, &sub, pbdrv_bluetooth_await_advertise_or_scan_command(&sub, NULL));

// Stop scanning.
pbdrv_bluetooth_start_observing(NULL);
Expand All @@ -654,7 +661,16 @@ void pbdrv_bluetooth_deinit(void) {
// Under normal operation ::pbdrv_bluetooth_close_user_tasks completes
// normally and there should be no user activity at this point. If there
// is, a task got stuck, so exit forcefully.
if (advertising_or_scan_err == PBIO_ERROR_AGAIN || peripheral_singleton.err == PBIO_ERROR_AGAIN) {
bool failed_to_stop = advertising_or_scan_err == PBIO_ERROR_AGAIN;
for (uint8_t i = 0; i < PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS; i++) {
pbdrv_bluetooth_peripheral_t *peri = pbdrv_bluetooth_peripheral_get_by_index(i);
if (peri->err == PBIO_ERROR_AGAIN) {
failed_to_stop = true;
break;
}
}

if (failed_to_stop) {
// 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();
Expand Down
12 changes: 6 additions & 6 deletions lib/pbio/drv/bluetooth/bluetooth.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,22 @@ pbio_error_t pbdrv_bluetooth_controller_reset(pbio_os_state_t *state, pbio_os_ti
pbio_error_t pbdrv_bluetooth_controller_initialize(pbio_os_state_t *state, pbio_os_timer_t *timer);

pbio_error_t pbdrv_bluetooth_start_broadcasting_func(pbio_os_state_t *state, void *context);
pbio_error_t pbdrv_bluetooth_start_advertising_func(pbio_os_state_t *state, void *context);
pbio_error_t pbdrv_bluetooth_stop_advertising_func(pbio_os_state_t *state, void *context);
pbio_error_t pbdrv_bluetooth_start_observing_func(pbio_os_state_t *state, void *context);
pbio_error_t pbdrv_bluetooth_stop_observing_func(pbio_os_state_t *state, void *context);

pbdrv_bluetooth_peripheral_t *pbdrv_bluetooth_peripheral_get_by_index(uint8_t index);
pbio_error_t pbdrv_bluetooth_peripheral_disconnect_func(pbio_os_state_t *state, void *context);
pbio_error_t pbdrv_bluetooth_peripheral_discover_characteristic_func(pbio_os_state_t *state, void *context);
pbio_error_t pbdrv_bluetooth_peripheral_read_characteristic_func(pbio_os_state_t *state, void *context);
pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect_func(pbio_os_state_t *state, void *context);
pbio_error_t pbdrv_bluetooth_peripheral_write_characteristic_func(pbio_os_state_t *state, void *context);
pbio_error_t pbdrv_bluetooth_start_advertising_func(pbio_os_state_t *state, void *context);
pbio_error_t pbdrv_bluetooth_stop_advertising_func(pbio_os_state_t *state, void *context);
pbio_error_t pbdrv_bluetooth_start_observing_func(pbio_os_state_t *state, void *context);
pbio_error_t pbdrv_bluetooth_stop_observing_func(pbio_os_state_t *state, void *context);

pbio_error_t pbdrv_bluetooth_send_pybricks_value_notification(pbio_os_state_t *state, const uint8_t *data, uint16_t size);

extern pbdrv_bluetooth_receive_handler_t pbdrv_bluetooth_receive_handler;

extern pbdrv_bluetooth_peripheral_t peripheral_singleton;

extern uint16_t pbdrv_bluetooth_char_write_handle;
extern uint8_t pbdrv_bluetooth_char_write_data[PBDRV_BLUETOOTH_MAX_CHAR_SIZE];
extern size_t pbdrv_bluetooth_char_write_size;
Expand Down
Loading