diff --git a/CHANGELOG.md b/CHANGELOG.md index 7241c0b0d..12e4e371d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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]). diff --git a/bricks/_common/sources.mk b/bricks/_common/sources.mk index 77642b6bb..da7a18aa0 100644 --- a/bricks/_common/sources.mk +++ b/bricks/_common/sources.mk @@ -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 \ diff --git a/lib/pbio/drv/bluetooth/bluetooth.c b/lib/pbio/drv/bluetooth/bluetooth.c index 7ba897973..eff9bc2ad 100644 --- a/lib/pbio/drv/bluetooth/bluetooth.c +++ b/lib/pbio/drv/bluetooth/bluetooth.c @@ -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; } @@ -214,9 +209,7 @@ 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) { @@ -224,7 +217,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_disconnect(void) { } // 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; } @@ -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) { @@ -249,18 +240,16 @@ 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) { @@ -268,7 +257,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_read_characteristic(pbdrv_bluetooth_peri } // 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(); @@ -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) { @@ -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. @@ -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; + } } // @@ -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); @@ -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 @@ -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); @@ -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(); diff --git a/lib/pbio/drv/bluetooth/bluetooth.h b/lib/pbio/drv/bluetooth/bluetooth.h index 5e259c516..1d77112d0 100644 --- a/lib/pbio/drv/bluetooth/bluetooth.h +++ b/lib/pbio/drv/bluetooth/bluetooth.h @@ -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; diff --git a/lib/pbio/drv/bluetooth/bluetooth_btstack.c b/lib/pbio/drv/bluetooth/bluetooth_btstack.c index f47097ace..a388327f8 100644 --- a/lib/pbio/drv/bluetooth/bluetooth_btstack.c +++ b/lib/pbio/drv/bluetooth/bluetooth_btstack.c @@ -89,7 +89,17 @@ static struct _pbdrv_bluetooth_peripheral_platform_state_t { * are set up such that only one char is discovered at a time */ gatt_client_characteristic_t current_char; -} peripheral_platform_state; +} peripheral_platform_state[PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS]; + +static pbdrv_bluetooth_peripheral_t _peripherals[PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS]; + +pbdrv_bluetooth_peripheral_t *pbdrv_bluetooth_peripheral_get_by_index(uint8_t index) { + if (index >= PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS) { + return NULL; + } + return &_peripherals[index]; +} + #endif // PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE // hub name goes in special section so that it can be modified when flashing firmware @@ -122,7 +132,11 @@ static pbio_error_t att_error_to_pbio_error(uint8_t status) { return PBIO_ERROR_NO_DEV; case ATT_ERROR_TIMEOUT: return PBIO_ERROR_TIMEDOUT; + case BTSTACK_MEMORY_ALLOC_FAILED: + DEBUG_PRINT("BTstack out of memory.\n"); + // fallthrough default: + DEBUG_PRINT("Failed with status.%d\n", status); return PBIO_ERROR_FAILED; } } @@ -183,7 +197,7 @@ static void pbdrv_bluetooth_peripheral_disconnect_now(pbdrv_bluetooth_peripheral /** * Checks if the given peripheral is connected. */ -static bool pbdrv_bluetooth_peripheral_is_connected(pbdrv_bluetooth_peripheral_t *peri) { +bool pbdrv_bluetooth_peripheral_is_connected(pbdrv_bluetooth_peripheral_t *peri) { return peri->con_handle != HCI_CON_HANDLE_INVALID; } @@ -236,9 +250,6 @@ bool pbdrv_bluetooth_is_connected(pbdrv_bluetooth_connection_t connection) { return true; } - if (connection == PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL && peripheral_singleton.con_handle != HCI_CON_HANDLE_INVALID) { - return true; - } #endif // PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE return false; @@ -307,10 +318,6 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe // Platform-specific platform handler has priority. pbdrv_bluetooth_btstack_platform_packet_handler(packet_type, channel, packet, size); - #if PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE - pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton; - #endif // PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE - switch (hci_event_packet_get_type(packet)) { case HCI_EVENT_COMMAND_COMPLETE: { const uint8_t *rp = hci_event_command_complete_get_return_parameters(packet); @@ -343,17 +350,19 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe case GATT_EVENT_QUERY_COMPLETE: DEBUG_PRINT("GATT_EVENT_QUERY_COMPLETE\n"); break; - case GATT_EVENT_NOTIFICATION: { - if (gatt_event_notification_get_handle(packet) != peri->con_handle) { - break; - } - if (peri->config->notification_handler) { - uint16_t length = gatt_event_notification_get_value_length(packet); - const uint8_t *value = gatt_event_notification_get_value(packet); - peri->config->notification_handler(peri->user, value, length); + case GATT_EVENT_NOTIFICATION: + 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 || !peri->config || !peri->config->notification_handler) { + continue; + } + if (gatt_event_notification_get_handle(packet) == peri->con_handle) { + uint16_t length = gatt_event_notification_get_value_length(packet); + const uint8_t *value = gatt_event_notification_get_value(packet); + peri->config->notification_handler(peri->user, value, length); + } } break; - } case HCI_EVENT_LE_META: if (hci_event_le_meta_get_subevent_code(packet) != HCI_SUBEVENT_LE_CONNECTION_COMPLETE) { break; @@ -374,10 +383,15 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe le_con_handle = HCI_CON_HANDLE_INVALID; pybricks_con_handle = HCI_CON_HANDLE_INVALID; uart_con_handle = HCI_CON_HANDLE_INVALID; - } else if (hci_event_disconnection_complete_get_connection_handle(packet) == peri->con_handle) { - DEBUG_PRINT("Peripheral disconnected\n"); - gatt_client_stop_listening_for_characteristic_value_updates(&peri->platform_state->notification); - peri->con_handle = HCI_CON_HANDLE_INVALID; + } else { + 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 && hci_event_disconnection_complete_get_connection_handle(packet) == peri->con_handle) { + DEBUG_PRINT("Peripheral %u with handle %u disconnected\n", i, peri->con_handle); + gatt_client_stop_listening_for_characteristic_value_updates(&peri->platform_state->notification); + peri->con_handle = HCI_CON_HANDLE_INVALID; + } + } } break; @@ -588,7 +602,7 @@ pbio_error_t pbdrv_bluetooth_send_pybricks_value_notification(pbio_os_state_t *s pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect_func(pbio_os_state_t *state, void *context) { - pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton; + pbdrv_bluetooth_peripheral_t *peri = context; pbdrv_bluetooth_ad_match_result_flags_t flags; uint8_t btstack_error; @@ -708,6 +722,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect_func(pbio_os_state_t *s // We are done if no pairing is requested. if (!peri->config->options & PBDRV_BLUETOOTH_PERIPHERAL_OPTIONS_PAIR) { + DEBUG_PRINT("Simple connection done.\n"); return PBIO_SUCCESS; } @@ -803,7 +818,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect_func(pbio_os_state_t *s pbio_error_t pbdrv_bluetooth_peripheral_discover_characteristic_func(pbio_os_state_t *state, void *context) { - pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton; + pbdrv_bluetooth_peripheral_t *peri = context; gatt_client_characteristic_t *current_char = &peri->platform_state->current_char; uint8_t btstack_error; @@ -910,7 +925,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_discover_characteristic_func(pbio_os_sta pbio_error_t pbdrv_bluetooth_peripheral_read_characteristic_func(pbio_os_state_t *state, void *context) { - pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton; + pbdrv_bluetooth_peripheral_t *peri = context; uint8_t btstack_error; @@ -959,7 +974,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_read_characteristic_func(pbio_os_state_t pbio_error_t pbdrv_bluetooth_peripheral_write_characteristic_func(pbio_os_state_t *state, void *context) { - pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton; + pbdrv_bluetooth_peripheral_t *peri = context; uint8_t btstack_error; @@ -998,7 +1013,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_write_characteristic_func(pbio_os_state_ pbio_error_t pbdrv_bluetooth_peripheral_disconnect_func(pbio_os_state_t *state, void *context) { - pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton; + pbdrv_bluetooth_peripheral_t *peri = context; PBIO_OS_ASYNC_BEGIN(state); @@ -1065,6 +1080,12 @@ pbio_error_t pbdrv_bluetooth_stop_observing_func(pbio_os_state_t *state, void *c pbio_error_t pbdrv_bluetooth_start_broadcasting_func(pbio_os_state_t *state, void *context) { return PBIO_ERROR_NOT_SUPPORTED; } +bool pbdrv_bluetooth_peripheral_is_connected(pbdrv_bluetooth_peripheral_t *peri) { + return false; +} +pbdrv_bluetooth_peripheral_t *pbdrv_bluetooth_peripheral_get_by_index(uint8_t index) { + return NULL; +} pbio_error_t pbdrv_bluetooth_peripheral_disconnect_func(pbio_os_state_t *state, void *context) { return PBIO_ERROR_NOT_SUPPORTED; } @@ -1264,9 +1285,12 @@ void pbdrv_bluetooth_init_hci(void) { static btstack_packet_callback_registration_t hci_event_callback_registration; #if PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE - // don't need to init the whole struct, so doing this here - peripheral_singleton.platform_state = &peripheral_platform_state; - peripheral_singleton.con_handle = HCI_CON_HANDLE_INVALID; + // Attach btstack platform state to peripherals. + 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->platform_state = &peripheral_platform_state[i]; + peri->con_handle = HCI_CON_HANDLE_INVALID; + } #endif btstack_memory_init(); diff --git a/lib/pbio/drv/bluetooth/bluetooth_simulation.c b/lib/pbio/drv/bluetooth/bluetooth_simulation.c deleted file mode 100644 index 1fea286e2..000000000 --- a/lib/pbio/drv/bluetooth/bluetooth_simulation.c +++ /dev/null @@ -1,190 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2020-2023 The Pybricks Authors - -#include - -#if PBDRV_CONFIG_BLUETOOTH_SIMULATION - -#include -#include -#include -#include -#include - -#include "bluetooth.h" -#include - -#include -#include - - -char pbdrv_bluetooth_hub_name[16] = "Pybricks Hub"; - -pbio_error_t pbdrv_bluetooth_start_advertising_func(pbio_os_state_t *state, void *context) { - PBIO_OS_ASYNC_BEGIN(state); - PBIO_OS_ASYNC_END(PBIO_SUCCESS); -} - -pbio_error_t pbdrv_bluetooth_stop_advertising_func(pbio_os_state_t *state, void *context) { - PBIO_OS_ASYNC_BEGIN(state); - PBIO_OS_ASYNC_END(PBIO_SUCCESS); -} - -bool pbdrv_bluetooth_is_connected(pbdrv_bluetooth_connection_t connection) { - - if (connection == PBDRV_BLUETOOTH_CONNECTION_HCI) { - return true; - } - - if (connection == PBDRV_BLUETOOTH_CONNECTION_LE) { - return true; - } - - if (connection == PBDRV_BLUETOOTH_CONNECTION_PYBRICKS) { - return true; - } - - if (connection == PBDRV_BLUETOOTH_CONNECTION_UART) { - return false; - } - - if (connection == PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL) { - return false; - } - - return false; -} - -pbio_error_t pbdrv_bluetooth_send_pybricks_value_notification(pbio_os_state_t *state, const uint8_t *data, uint16_t size) { - PBIO_OS_ASYNC_BEGIN(state); - - // Stdout also goes to native stdout. - if (size > 1 && data[0] == PBIO_PYBRICKS_EVENT_WRITE_STDOUT) { - int ret = write(STDOUT_FILENO, data + 1, size - 1); - (void)ret; - } - - extern void virtual_hub_socket_send(const uint8_t *data, uint32_t size); - virtual_hub_socket_send(data, size); - - PBIO_OS_ASYNC_END(PBIO_SUCCESS); -} - -pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect_func(pbio_os_state_t *state, void *context) { - PBIO_OS_ASYNC_BEGIN(state); - PBIO_OS_ASYNC_END(PBIO_SUCCESS); -} - -pbio_error_t pbdrv_bluetooth_peripheral_discover_characteristic_func(pbio_os_state_t *state, void *context) { - PBIO_OS_ASYNC_BEGIN(state); - PBIO_OS_ASYNC_END(PBIO_SUCCESS); -} - -pbio_error_t pbdrv_bluetooth_peripheral_read_characteristic_func(pbio_os_state_t *state, void *context) { - PBIO_OS_ASYNC_BEGIN(state); - PBIO_OS_ASYNC_END(PBIO_SUCCESS); -} - -pbio_error_t pbdrv_bluetooth_peripheral_write_characteristic_func(pbio_os_state_t *state, void *context) { - PBIO_OS_ASYNC_BEGIN(state); - PBIO_OS_ASYNC_END(PBIO_SUCCESS); -} - -pbio_error_t pbdrv_bluetooth_peripheral_disconnect_func(pbio_os_state_t *state, void *context) { - PBIO_OS_ASYNC_BEGIN(state); - PBIO_OS_ASYNC_END(PBIO_SUCCESS); -} - -pbio_error_t pbdrv_bluetooth_start_broadcasting_func(pbio_os_state_t *state, void *context) { - PBIO_OS_ASYNC_BEGIN(state); - PBIO_OS_ASYNC_END(PBIO_SUCCESS); -} - -pbio_error_t pbdrv_bluetooth_start_observing_func(pbio_os_state_t *state, void *context) { - PBIO_OS_ASYNC_BEGIN(state); - PBIO_OS_ASYNC_END(PBIO_SUCCESS); -} - -pbio_error_t pbdrv_bluetooth_stop_observing_func(pbio_os_state_t *state, void *context) { - PBIO_OS_ASYNC_BEGIN(state); - PBIO_OS_ASYNC_END(PBIO_SUCCESS); -} - -const char *pbdrv_bluetooth_get_hub_name(void) { - return pbdrv_bluetooth_hub_name; -} - -const char *pbdrv_bluetooth_get_fw_version(void) { - return "N/A"; -} - -void pbdrv_bluetooth_controller_reset_hard(void) { -} - -pbio_error_t pbdrv_bluetooth_controller_reset(pbio_os_state_t *state, pbio_os_timer_t *timer) { - PBIO_OS_ASYNC_BEGIN(state); - PBIO_OS_ASYNC_END(PBIO_SUCCESS); -} - -pbio_error_t pbdrv_bluetooth_controller_initialize(pbio_os_state_t *state, pbio_os_timer_t *timer) { - PBIO_OS_ASYNC_BEGIN(state); - PBIO_OS_ASYNC_END(PBIO_SUCCESS); -} - -#define STDIN_HEADER_SIZE (1) - -static void pbdrv_bluetooth_simulation_tick_handler() { - #ifdef PBDRV_CONFIG_RUN_ON_CI - // CI and MicroPython test suite have lots of problems with stdin. It is - // only needed for the REPL and interactive input, so don't bother on CI. - return; - #endif - - uint8_t buf[256 + STDIN_HEADER_SIZE]; - - // This has been made non-blocking in platform.c. - ssize_t r = read(STDIN_FILENO, buf + STDIN_HEADER_SIZE, sizeof(buf) - STDIN_HEADER_SIZE); - - if (r > 0) { - buf[0] = PBIO_PYBRICKS_COMMAND_WRITE_STDIN; - pbdrv_bluetooth_receive_handler(buf, r + STDIN_HEADER_SIZE); - } else if (r == 0) { - // EOF. - } else if (errno != EAGAIN && errno != EWOULDBLOCK) { - // No data available. - } -} - -static pbio_os_process_t pbdrv_bluetooth_simulation_process; - -static pbio_os_state_t bluetooth_thread_state; -static pbio_os_state_t bluetooth_thread_err; - -/** - * Placeholder process that does not have any state. - */ -static pbio_error_t pbdrv_bluetooth_simulation_process_thread(pbio_os_state_t *state, void *context) { - - static pbio_os_timer_t simulation_timer = { - .duration = 1, - }; - - if (pbio_os_timer_is_expired(&simulation_timer)) { - pbio_os_timer_extend(&simulation_timer); - - pbdrv_bluetooth_simulation_tick_handler(); - } - - if (bluetooth_thread_err == PBIO_ERROR_AGAIN) { - bluetooth_thread_err = pbdrv_bluetooth_process_thread(&bluetooth_thread_state, NULL); - } - return bluetooth_thread_err; -} - -void pbdrv_bluetooth_init_hci(void) { - bluetooth_thread_err = PBIO_ERROR_AGAIN; - bluetooth_thread_state = 0; - pbio_os_process_start(&pbdrv_bluetooth_simulation_process, pbdrv_bluetooth_simulation_process_thread, NULL); -} - -#endif // PBDRV_CONFIG_BLUETOOTH_SIMULATION diff --git a/lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c b/lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c index 0dcd29fd9..596df473a 100644 --- a/lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c +++ b/lib/pbio/drv/bluetooth/bluetooth_stm32_bluenrg.c @@ -124,6 +124,19 @@ static const pbdrv_gpio_t mosi_gpio = { .bank = GPIOC, .pin = 3 }; static const pbdrv_gpio_t miso_gpio = { .bank = GPIOC, .pin = 2 }; static const pbdrv_gpio_t sck_gpio = { .bank = GPIOB, .pin = 13 }; +static pbdrv_bluetooth_peripheral_t peripheral_singleton; + +pbdrv_bluetooth_peripheral_t *pbdrv_bluetooth_peripheral_get_by_index(uint8_t index) { + // This platform supports only a single peripheral instance. Some of its + // states are global variables listed above. This single instance is used + // troughout the event handler. + return &peripheral_singleton; +} + +bool pbdrv_bluetooth_peripheral_is_connected(pbdrv_bluetooth_peripheral_t *peri) { + return peri == &peripheral_singleton && peri->con_handle != 0; +} + /** * Converts a BlueNRG-MS error code to a PBIO error code. * @param [in] status The BlueNRG-MS error code. @@ -307,10 +320,6 @@ bool pbdrv_bluetooth_is_connected(pbdrv_bluetooth_connection_t connection) { return true; } - if (connection == PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL && peripheral_singleton.con_handle) { - return true; - } - return false; } @@ -336,7 +345,7 @@ pbio_error_t pbdrv_bluetooth_send_pybricks_value_notification(pbio_os_state_t *s } pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect_func(pbio_os_state_t *state, void *context) { - pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton; + pbdrv_bluetooth_peripheral_t *peri = context; // Scan and connect timeout, if applicable. bool timed_out = peri->config->timeout && pbio_os_timer_is_expired(&peri->timer); @@ -455,7 +464,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect_func(pbio_os_state_t *s } pbio_error_t pbdrv_bluetooth_peripheral_discover_characteristic_func(pbio_os_state_t *state, void *context) { - pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton; + pbdrv_bluetooth_peripheral_t *peri = context; PBIO_OS_ASYNC_BEGIN(state); @@ -573,7 +582,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_write_characteristic_func(pbio_os_state_ pbio_error_t pbdrv_bluetooth_peripheral_disconnect_func(pbio_os_state_t *state, void *context) { - pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton; + pbdrv_bluetooth_peripheral_t *peri = context; PBIO_OS_ASYNC_BEGIN(state); @@ -950,7 +959,6 @@ static void handle_event(hci_event_pckt *event) { case EVT_BLUE_GATT_NOTIFICATION: { evt_gatt_attr_notification *subevt = (void *)evt->data; - pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton; if (peri->config->notification_handler) { peri->config->notification_handler(peri->user, subevt->attr_value, subevt->event_data_length - 2); } diff --git a/lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c b/lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c index 6bd6c1516..698090068 100644 --- a/lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c +++ b/lib/pbio/drv/bluetooth/bluetooth_stm32_cc2640.c @@ -143,6 +143,19 @@ static const pbdrv_bluetooth_stm32_cc2640_platform_data_t *pdata = &pbdrv_blueto // after a while. #define SCAN_RESTART_INTERVAL 3000 +static pbdrv_bluetooth_peripheral_t peripheral_singleton; + +pbdrv_bluetooth_peripheral_t *pbdrv_bluetooth_peripheral_get_by_index(uint8_t index) { + // This platform supports only a single peripheral instance. Some of its + // states are global variables listed above. This single instance is used + // troughout the event handler. + return &peripheral_singleton; +} + +bool pbdrv_bluetooth_peripheral_is_connected(pbdrv_bluetooth_peripheral_t *peri) { + return peri == &peripheral_singleton && peri->con_handle != NO_CONNECTION; +} + /** * Converts a ble error code to the most appropriate pbio error code. * @param [in] status The ble error code. @@ -348,10 +361,6 @@ bool pbdrv_bluetooth_is_connected(pbdrv_bluetooth_connection_t connection) { return true; } - if (connection == PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL && peripheral_singleton.con_handle != NO_CONNECTION) { - return true; - } - return false; } @@ -1308,7 +1317,6 @@ static void handle_event(uint8_t *packet) { case ATT_EVENT_HANDLE_VALUE_NOTI: { // TODO: match callback to handle // uint8_t attr_handle = (data[7] << 8) | data[6]; - pbdrv_bluetooth_peripheral_t *peri = &peripheral_singleton; if (peri->config->notification_handler) { peri->config->notification_handler(peri->user, &data[8], pdu_len - 2); } diff --git a/lib/pbio/include/pbdrv/bluetooth.h b/lib/pbio/include/pbdrv/bluetooth.h index bd2d3c67e..bd06c3d3f 100644 --- a/lib/pbio/include/pbdrv/bluetooth.h +++ b/lib/pbio/include/pbdrv/bluetooth.h @@ -30,8 +30,6 @@ typedef enum { PBDRV_BLUETOOTH_CONNECTION_PYBRICKS, /** The Nordic UART service. */ PBDRV_BLUETOOTH_CONNECTION_UART, - /** A LEGO Powered Up Handset peripheral connection. */ - PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL, } pbdrv_bluetooth_connection_t; /** Data structure that holds context needed for sending BLE notifications. */ @@ -373,6 +371,14 @@ pbio_error_t pbdrv_bluetooth_send_event_notification(pbio_os_state_t *state, pbi */ pbio_error_t pbdrv_bluetooth_peripheral_get_available(pbdrv_bluetooth_peripheral_t **peripheral, void *user); +/** + * Checks if the given peripheral is connected. + * + * @param [in] peri The peripheral to check. + * @return True if connected, false otherwise. + */ +bool pbdrv_bluetooth_peripheral_is_connected(pbdrv_bluetooth_peripheral_t *peri); + /** * Releases a peripheral instance for reuse by another user. * @@ -386,7 +392,7 @@ void pbdrv_bluetooth_peripheral_release(pbdrv_bluetooth_peripheral_t *peripheral * * @return The name of the connected peripheral. May not be set. */ -const char *pbdrv_bluetooth_peripheral_get_name(void); +const char *pbdrv_bluetooth_peripheral_get_name(pbdrv_bluetooth_peripheral_t *peripheral); /** * Starts scanning for a BLE device and connects to it. @@ -395,7 +401,7 @@ const char *pbdrv_bluetooth_peripheral_get_name(void); * @return ::PBIO_SUCCESS if the operation was scheduled. * ::PBIO_ERROR_BUSY if already connected or another peripheral operation is ongoing. */ -pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect(pbdrv_bluetooth_peripheral_connect_config_t *config); +pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect(pbdrv_bluetooth_peripheral_t *peripheral, pbdrv_bluetooth_peripheral_connect_config_t *config); /** * Disconnect from the peripheral. @@ -404,7 +410,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect(pbdrv_bluetooth_periphe * @return ::PBIO_SUCCESS if disconnection schefuled or when already disconnected. * ::PBIO_ERROR_BUSY if another peripheral operation is ongoing. */ -pbio_error_t pbdrv_bluetooth_peripheral_disconnect(void); +pbio_error_t pbdrv_bluetooth_peripheral_disconnect(pbdrv_bluetooth_peripheral_t *peripheral); /** * Find a characteristic by UUID and properties. @@ -417,7 +423,7 @@ pbio_error_t pbdrv_bluetooth_peripheral_disconnect(void); * ::PBIO_ERROR_BUSY if another peripheral operation is ongoing. * ::PBIO_ERROR_NO_DEV if no peripheral is connected. */ -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 *peripheral, pbdrv_bluetooth_peripheral_char_t *characteristic); /** * Read a characteristic. @@ -427,13 +433,14 @@ pbio_error_t pbdrv_bluetooth_peripheral_discover_characteristic(pbdrv_bluetooth_ * ::PBIO_ERROR_NO_DEV if not connected to a peripheral. * ::PBIO_ERROR_BUSY if another operation is ongoing. */ -pbio_error_t pbdrv_bluetooth_peripheral_read_characteristic(pbdrv_bluetooth_peripheral_char_t *characteristic); +pbio_error_t pbdrv_bluetooth_peripheral_read_characteristic(pbdrv_bluetooth_peripheral_t *peripheral, pbdrv_bluetooth_peripheral_char_t *characteristic); /** * Write a value to a peripheral characteristic without response. * * The write is queued for transmission and does not await completion. * + * @param [in] peri The peripheral to write to. * @param [in] handle The handle of the characteristic value to write. * @param [in] data The data to write. * @param [in] size The size of @p data in bytes. @@ -442,14 +449,14 @@ pbio_error_t pbdrv_bluetooth_peripheral_read_characteristic(pbdrv_bluetooth_peri * ::PBIO_ERROR_BUSY if another peripheral operation is ongoing. * ::PBIO_ERROR_INVALID_ARG if @p size is too big. */ -pbio_error_t pbdrv_bluetooth_peripheral_write_characteristic(uint16_t handle, const uint8_t *data, size_t size); +pbio_error_t pbdrv_bluetooth_peripheral_write_characteristic(pbdrv_bluetooth_peripheral_t *peripheral, uint16_t handle, const uint8_t *data, size_t size); /** * Awaits for a task associated with a peripheral to complete. Used to await * characteristic discover/read/write, scan-and-connect, or disconnect. * * @param [in] state Protothread state. Not used in all implementations. - * @param [in] context Not used. + * @param [in] context The peripheral. * @return ::PBIO_SUCCESS on completion. * ::PBIO_ERROR_AGAIN while awaiting. * or a thread specific error code if the operation failed. @@ -596,31 +603,34 @@ static inline pbio_error_t pbdrv_bluetooth_peripheral_get_available(pbdrv_blueto return PBIO_ERROR_NOT_SUPPORTED; } +static inline bool pbdrv_bluetooth_peripheral_is_connected(pbdrv_bluetooth_peripheral_t *peripheral) { + return false; +} + static inline void pbdrv_bluetooth_peripheral_release(pbdrv_bluetooth_peripheral_t *peripheral, void *user) { } -static inline const char *pbdrv_bluetooth_peripheral_get_name(void) { +static inline const char *pbdrv_bluetooth_peripheral_get_name(pbdrv_bluetooth_peripheral_t *peripheral) { return NULL; } -static inline pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect(pbdrv_bluetooth_peripheral_connect_config_t *config) { +static inline pbio_error_t pbdrv_bluetooth_peripheral_scan_and_connect(pbdrv_bluetooth_peripheral_t *peripheral, pbdrv_bluetooth_peripheral_connect_config_t *config) { return PBIO_ERROR_NOT_SUPPORTED; } -static inline pbio_error_t pbdrv_bluetooth_peripheral_disconnect(void) { +static inline pbio_error_t pbdrv_bluetooth_peripheral_disconnect(pbdrv_bluetooth_peripheral_t *peripheral) { return PBIO_ERROR_NOT_SUPPORTED; } -static inline pbio_error_t pbdrv_bluetooth_peripheral_discover_characteristic(pbdrv_bluetooth_peripheral_char_t *characteristic) { +static inline pbio_error_t pbdrv_bluetooth_peripheral_discover_characteristic(pbdrv_bluetooth_peripheral_t *peripheral, pbdrv_bluetooth_peripheral_char_t *characteristic) { return PBIO_ERROR_NOT_SUPPORTED; } -static inline pbio_error_t pbdrv_bluetooth_peripheral_read_characteristic( - pbdrv_bluetooth_peripheral_char_t *characteristic) { +static inline pbio_error_t pbdrv_bluetooth_peripheral_read_characteristic(pbdrv_bluetooth_peripheral_t *peripheral, pbdrv_bluetooth_peripheral_char_t *characteristic) { return PBIO_ERROR_NOT_SUPPORTED; } -static inline pbio_error_t pbdrv_bluetooth_peripheral_write_characteristic(uint16_t handle, const uint8_t *data, size_t size) { +static inline pbio_error_t pbdrv_bluetooth_peripheral_write_characteristic(pbdrv_bluetooth_peripheral_t *peripheral, uint16_t handle, const uint8_t *data, size_t size) { return PBIO_ERROR_NOT_SUPPORTED; } diff --git a/lib/pbio/platform/city_hub/pbdrvconfig.h b/lib/pbio/platform/city_hub/pbdrvconfig.h index f0ac37d3e..09407d8d5 100644 --- a/lib/pbio/platform/city_hub/pbdrvconfig.h +++ b/lib/pbio/platform/city_hub/pbdrvconfig.h @@ -30,6 +30,7 @@ #define PBDRV_CONFIG_BLOCK_DEVICE_FLASH_STM32_SIZE (16 * 1024) // Must match FLASH_USER_0 + FLASH_USER_1 in linker script #define PBDRV_CONFIG_BLUETOOTH (1) +#define PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS (1) #define PBDRV_CONFIG_BLUETOOTH_MAX_MTU_SIZE 158 // 158 matches LEGO firmware - could go up to ~251 - see ATT_MAX_MTU_SIZE #define PBDRV_CONFIG_BLUETOOTH_STM32_CC2640 (1) #define PBDRV_CONFIG_BLUETOOTH_STM32_CC2640_HUB_ID "\x41" diff --git a/lib/pbio/platform/essential_hub/btstack_config.h b/lib/pbio/platform/essential_hub/btstack_config.h index 51df40810..c243bdb34 100644 --- a/lib/pbio/platform/essential_hub/btstack_config.h +++ b/lib/pbio/platform/essential_hub/btstack_config.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2020-2021 The Pybricks Authors +// Copyright (c) 2020-2026 The Pybricks Authors // BlueKitchen BTStack config @@ -21,8 +21,8 @@ #define HCI_ACL_PAYLOAD_SIZE (1691 + 4) #define MAX_ATT_DB_SIZE 512 #define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 0 -#define MAX_NR_GATT_CLIENTS 1 -#define MAX_NR_HCI_CONNECTIONS 2 // CC2564C can have up to 10 connections +#define MAX_NR_GATT_CLIENTS 2 +#define MAX_NR_HCI_CONNECTIONS 3 // CC2564C can have up to 10 connections #define MAX_NR_HFP_CONNECTIONS 0 #define MAX_NR_L2CAP_CHANNELS 0 #define MAX_NR_L2CAP_SERVICES 0 @@ -30,9 +30,9 @@ #define MAX_NR_RFCOMM_MULTIPLEXERS 0 #define MAX_NR_RFCOMM_SERVICES 0 #define MAX_NR_SERVICE_RECORD_ITEMS 0 -#define MAX_NR_SM_LOOKUP_ENTRIES 0 +#define MAX_NR_SM_LOOKUP_ENTRIES 3 #define MAX_NR_WHITELIST_ENTRIES 0 -#define MAX_NR_LE_DEVICE_DB_ENTRIES 1 +#define MAX_NR_LE_DEVICE_DB_ENTRIES 3 // Link Key DB and LE Device DB using TLV on top of Flash Sector interface // #define NVM_NUM_DEVICE_DB_ENTRIES 16 diff --git a/lib/pbio/platform/essential_hub/pbdrvconfig.h b/lib/pbio/platform/essential_hub/pbdrvconfig.h index 748568ae5..e5dd82422 100644 --- a/lib/pbio/platform/essential_hub/pbdrvconfig.h +++ b/lib/pbio/platform/essential_hub/pbdrvconfig.h @@ -26,6 +26,7 @@ #define PBDRV_CONFIG_BATTERY_ADC_TEMPERATURE_CH 2 #define PBDRV_CONFIG_BLUETOOTH (1) +#define PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS (2) #define PBDRV_CONFIG_BLUETOOTH_MAX_MTU_SIZE 515 #define PBDRV_CONFIG_BLUETOOTH_BTSTACK (1) #define PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE (1) diff --git a/lib/pbio/platform/ev3/pbdrvconfig.h b/lib/pbio/platform/ev3/pbdrvconfig.h index 636022233..80c791704 100644 --- a/lib/pbio/platform/ev3/pbdrvconfig.h +++ b/lib/pbio/platform/ev3/pbdrvconfig.h @@ -46,6 +46,7 @@ #define PBDRV_CONFIG_I2C_EV3 (1) #define PBDRV_CONFIG_BLUETOOTH (1) +#define PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS (1) #define PBDRV_CONFIG_BLUETOOTH_MAX_MTU_SIZE 515 #define PBDRV_CONFIG_BLUETOOTH_BTSTACK (1) #define PBDRV_CONFIG_BLUETOOTH_BTSTACK_CLASSIC (1) diff --git a/lib/pbio/platform/move_hub/pbdrvconfig.h b/lib/pbio/platform/move_hub/pbdrvconfig.h index 41aec499f..45e9cd2bd 100644 --- a/lib/pbio/platform/move_hub/pbdrvconfig.h +++ b/lib/pbio/platform/move_hub/pbdrvconfig.h @@ -24,6 +24,7 @@ #define PBDRV_CONFIG_BLOCK_DEVICE_FLASH_STM32_SIZE (4 * 1024) // Must match FLASH_USER_0 + FLASH_USER_1 in linker script #define PBDRV_CONFIG_BLUETOOTH (1) +#define PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS (1) #define PBDRV_CONFIG_BLUETOOTH_STM32_BLUENRG (1) #define PBDRV_CONFIG_BUTTON (1) diff --git a/lib/pbio/platform/prime_hub/btstack_config.h b/lib/pbio/platform/prime_hub/btstack_config.h index 28f2db8b9..d6998b827 100644 --- a/lib/pbio/platform/prime_hub/btstack_config.h +++ b/lib/pbio/platform/prime_hub/btstack_config.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2020 The Pybricks Authors +// Copyright (c) 2020-2026 The Pybricks Authors // BlueKitchen BTStack config @@ -21,8 +21,8 @@ #define HCI_ACL_PAYLOAD_SIZE (1691 + 4) #define MAX_ATT_DB_SIZE 512 #define MAX_NR_BTSTACK_LINK_KEY_DB_MEMORY_ENTRIES 0 -#define MAX_NR_GATT_CLIENTS 1 -#define MAX_NR_HCI_CONNECTIONS 2 // CC2564C can have up to 10 connections +#define MAX_NR_GATT_CLIENTS 2 +#define MAX_NR_HCI_CONNECTIONS 3 // CC2564C can have up to 10 connections #define MAX_NR_HFP_CONNECTIONS 0 #define MAX_NR_L2CAP_CHANNELS 0 #define MAX_NR_L2CAP_SERVICES 0 @@ -30,9 +30,9 @@ #define MAX_NR_RFCOMM_MULTIPLEXERS 0 #define MAX_NR_RFCOMM_SERVICES 0 #define MAX_NR_SERVICE_RECORD_ITEMS 0 -#define MAX_NR_SM_LOOKUP_ENTRIES 0 +#define MAX_NR_SM_LOOKUP_ENTRIES 3 #define MAX_NR_WHITELIST_ENTRIES 0 -#define MAX_NR_LE_DEVICE_DB_ENTRIES 1 +#define MAX_NR_LE_DEVICE_DB_ENTRIES 3 // Link Key DB and LE Device DB using TLV on top of Flash Sector interface // #define NVM_NUM_DEVICE_DB_ENTRIES 16 diff --git a/lib/pbio/platform/prime_hub/pbdrvconfig.h b/lib/pbio/platform/prime_hub/pbdrvconfig.h index 56089db9e..e1bb4d2f8 100644 --- a/lib/pbio/platform/prime_hub/pbdrvconfig.h +++ b/lib/pbio/platform/prime_hub/pbdrvconfig.h @@ -26,6 +26,7 @@ #define PBDRV_CONFIG_BATTERY_ADC_TEMPERATURE_CH 2 #define PBDRV_CONFIG_BLUETOOTH (1) +#define PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS (2) #define PBDRV_CONFIG_BLUETOOTH_MAX_MTU_SIZE 515 #define PBDRV_CONFIG_BLUETOOTH_BTSTACK (1) #define PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE (1) diff --git a/lib/pbio/platform/prime_hub/platform.ld b/lib/pbio/platform/prime_hub/platform.ld index ba433b5b2..3fb07d7aa 100644 --- a/lib/pbio/platform/prime_hub/platform.ld +++ b/lib/pbio/platform/prime_hub/platform.ld @@ -19,4 +19,4 @@ MEMORY /* Minimal stack size to allow the build to proceed. The actual stack size is whatever is left after statically allocated memory. It can be tuned by setting PBDRV_CONFIG_BLOCK_DEVICE_RAM_SIZE. */ -_minimal_stack_size = 16K; +_minimal_stack_size = 12K; diff --git a/lib/pbio/platform/technic_hub/pbdrvconfig.h b/lib/pbio/platform/technic_hub/pbdrvconfig.h index 3eabd63de..ef7e7a690 100644 --- a/lib/pbio/platform/technic_hub/pbdrvconfig.h +++ b/lib/pbio/platform/technic_hub/pbdrvconfig.h @@ -29,6 +29,7 @@ #define PBDRV_CONFIG_BLOCK_DEVICE_FLASH_STM32_SIZE (16 * 1024) // Must match FLASH_USER_0 + FLASH_USER_1 in linker script #define PBDRV_CONFIG_BLUETOOTH (1) +#define PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS (1) #define PBDRV_CONFIG_BLUETOOTH_MAX_MTU_SIZE 158 // 158 matches LEGO firmware - could go up to ~251 - see ATT_MAX_MTU_SIZE #define PBDRV_CONFIG_BLUETOOTH_STM32_CC2640 (1) #define PBDRV_CONFIG_BLUETOOTH_STM32_CC2640_HUB_ID "\x80" diff --git a/lib/pbio/platform/test/pbdrvconfig.h b/lib/pbio/platform/test/pbdrvconfig.h index 01156de5d..30c17d4f1 100644 --- a/lib/pbio/platform/test/pbdrvconfig.h +++ b/lib/pbio/platform/test/pbdrvconfig.h @@ -8,6 +8,7 @@ #define PBDRV_CONFIG_BUTTON_TEST (1) #define PBDRV_CONFIG_BLUETOOTH (1) +#define PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS (1) #define PBDRV_CONFIG_BLUETOOTH_BTSTACK (1) #define PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE (1) #define PBDRV_CONFIG_BLUETOOTH_BTSTACK_CC2564C (1) diff --git a/lib/pbio/platform/virtual_hub/pbdrvconfig.h b/lib/pbio/platform/virtual_hub/pbdrvconfig.h index c618a4587..b129f4b5e 100644 --- a/lib/pbio/platform/virtual_hub/pbdrvconfig.h +++ b/lib/pbio/platform/virtual_hub/pbdrvconfig.h @@ -11,6 +11,7 @@ // Use Bluetooth simulation locally. #ifndef PBDRV_CONFIG_RUN_ON_CI #define PBDRV_CONFIG_BLUETOOTH (1) +#define PBDRV_CONFIG_BLUETOOTH_NUM_PERIPHERALS (2) #define PBDRV_CONFIG_BLUETOOTH_BTSTACK (1) #define PBDRV_CONFIG_BLUETOOTH_BTSTACK_LE (1) #define PBDRV_CONFIG_BLUETOOTH_BTSTACK_POSIX (1) diff --git a/pybricks/iodevices/pb_type_iodevices_lwp3device.c b/pybricks/iodevices/pb_type_iodevices_lwp3device.c index 1a6f1ace5..a7baa5cf3 100644 --- a/pybricks/iodevices/pb_type_iodevices_lwp3device.c +++ b/pybricks/iodevices/pb_type_iodevices_lwp3device.c @@ -222,12 +222,6 @@ static pbdrv_bluetooth_ad_match_result_flags_t lwp3_advertisement_response_match return flags; } -static void pb_lwp3device_assert_connected(void) { - if (!pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL)) { - mp_raise_OSError(MP_ENODEV); - } -} - static pbdrv_bluetooth_peripheral_connect_config_t scan_config = { .match_adv = lwp3_advertisement_matches, .match_adv_rsp = lwp3_advertisement_response_matches, @@ -265,15 +259,21 @@ static pbio_error_t pb_type_pupdevices_Remote_write_light_msg(mp_obj_t self_in, msg.payload[1] = rgb.g * 3 / 8; msg.payload[2] = rgb.b * 3 / 8; - return pbdrv_bluetooth_peripheral_write_characteristic(pb_lwp3device_char.handle, (const uint8_t *)&msg, sizeof(msg)); + pb_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return pbdrv_bluetooth_peripheral_write_characteristic(self->peripheral, pb_lwp3device_char.handle, (const uint8_t *)&msg, sizeof(msg)); } static mp_obj_t wait_or_await_operation(mp_obj_t self_in) { + + pb_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_in); + pb_type_async_t config = { .iter_once = pbdrv_bluetooth_await_peripheral_command, - .parent_obj = self_in, + // Using the driver function without a wrapper, so should pass its + // context parameter (the peripheral) as the parent object. + .parent_obj = self->peripheral, }; - pb_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_in); return pb_type_async_wait_or_await(&config, &self->iter, true); } @@ -296,18 +296,18 @@ static pbio_error_t pb_lwp3device_connect_thread(pbio_os_state_t *state, mp_obj_ pb_assert(pbdrv_bluetooth_peripheral_get_available(&self->peripheral, self)); // Scan and connect with timeout. - pb_assert(pbdrv_bluetooth_peripheral_scan_and_connect(&scan_config)); - PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); + pb_assert(pbdrv_bluetooth_peripheral_scan_and_connect(self->peripheral, &scan_config)); + PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); if (err != PBIO_SUCCESS) { return err; } // Copy the name so we can read it back later, and override locally. - memcpy(self->name, pbdrv_bluetooth_peripheral_get_name(), sizeof(self->name)); + memcpy(self->name, pbdrv_bluetooth_peripheral_get_name(self->peripheral), sizeof(self->name)); // Discover common lwp3 characteristic. - pb_assert(pbdrv_bluetooth_peripheral_discover_characteristic(&pb_lwp3device_char)); - PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); + pb_assert(pbdrv_bluetooth_peripheral_discover_characteristic(self->peripheral, &pb_lwp3device_char)); + PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); if (err != PBIO_SUCCESS) { goto disconnect; } @@ -337,11 +337,11 @@ static pbio_error_t pb_lwp3device_connect_thread(pbio_os_state_t *state, mp_obj_ msg.mode = REMOTE_BUTTONS_MODE_KEYSD; msg.enable_notifications = 1; - err = pbdrv_bluetooth_peripheral_write_characteristic(pb_lwp3device_char.handle, (const uint8_t *)&msg, sizeof(msg)); + err = pbdrv_bluetooth_peripheral_write_characteristic(self->peripheral, pb_lwp3device_char.handle, (const uint8_t *)&msg, sizeof(msg)); if (err != PBIO_SUCCESS) { goto disconnect; } - PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); + PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); if (err != PBIO_SUCCESS) { goto disconnect; } @@ -349,11 +349,11 @@ static pbio_error_t pb_lwp3device_connect_thread(pbio_os_state_t *state, mp_obj_ // set mode for right buttons msg.port = REMOTE_PORT_RIGHT_BUTTONS; - err = pbdrv_bluetooth_peripheral_write_characteristic(pb_lwp3device_char.handle, (const uint8_t *)&msg, sizeof(msg)); + err = pbdrv_bluetooth_peripheral_write_characteristic(self->peripheral, pb_lwp3device_char.handle, (const uint8_t *)&msg, sizeof(msg)); if (err != PBIO_SUCCESS) { goto disconnect; } - PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); + PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); if (err != PBIO_SUCCESS) { goto disconnect; } @@ -363,11 +363,11 @@ static pbio_error_t pb_lwp3device_connect_thread(pbio_os_state_t *state, mp_obj_ msg.mode = STATUS_LIGHT_MODE_RGB_0; msg.enable_notifications = 0; - err = pbdrv_bluetooth_peripheral_write_characteristic(pb_lwp3device_char.handle, (const uint8_t *)&msg, sizeof(msg)); + err = pbdrv_bluetooth_peripheral_write_characteristic(self->peripheral, pb_lwp3device_char.handle, (const uint8_t *)&msg, sizeof(msg)); if (err != PBIO_SUCCESS) { goto disconnect; } - PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); + PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); if (err != PBIO_SUCCESS) { goto disconnect; } @@ -379,7 +379,7 @@ static pbio_error_t pb_lwp3device_connect_thread(pbio_os_state_t *state, mp_obj_ if (err != PBIO_SUCCESS) { goto disconnect; } - PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); + PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); if (err != PBIO_SUCCESS) { goto disconnect; } @@ -387,9 +387,9 @@ static pbio_error_t pb_lwp3device_connect_thread(pbio_os_state_t *state, mp_obj_ return PBIO_SUCCESS; disconnect: - PBIO_OS_AWAIT(state, &unused, pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); - pbdrv_bluetooth_peripheral_disconnect(); - PBIO_OS_AWAIT(state, &unused, pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); + PBIO_OS_AWAIT(state, &unused, pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); + pbdrv_bluetooth_peripheral_disconnect(self->peripheral); + PBIO_OS_AWAIT(state, &unused, pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); PBIO_OS_ASYNC_END(PBIO_ERROR_IO); } @@ -437,7 +437,9 @@ static mp_obj_t pb_lwp3device_connect(mp_obj_t self_in, mp_obj_t name_in, mp_obj mp_obj_t pb_type_remote_button_pressed(mp_obj_t self_in) { pb_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_in); - pb_lwp3device_assert_connected(); + if (!pbdrv_bluetooth_peripheral_is_connected(self->peripheral)) { + pb_assert(PBIO_ERROR_NO_DEV); + } mp_obj_t pressed[7]; size_t num = 0; @@ -531,11 +533,14 @@ static mp_obj_t pb_lwp3device_name(size_t n_args, const mp_obj_t *args) { memcpy(self->name, name, len); self->name[len] = 0; - pb_assert(pbdrv_bluetooth_peripheral_write_characteristic(pb_lwp3device_char.handle, (const uint8_t *)&msg, sizeof(msg) - sizeof(msg.payload) + len)); + pb_assert(pbdrv_bluetooth_peripheral_write_characteristic(self->peripheral, pb_lwp3device_char.handle, (const uint8_t *)&msg, sizeof(msg) - sizeof(msg.payload) + len)); return wait_or_await_operation(self_in); } - pb_lwp3device_assert_connected(); + if (!pbdrv_bluetooth_peripheral_is_connected(self->peripheral)) { + pb_assert(PBIO_ERROR_NO_DEV); + } + return mp_obj_new_str(self->name, strlen(self->name)); } static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pb_lwp3device_name_obj, 1, 2, pb_lwp3device_name); @@ -545,7 +550,9 @@ static mp_obj_t pb_lwp3device_disconnect(mp_obj_t self_in) { // connection later. pb_lwp3device_close(self_in); - pb_assert(pbdrv_bluetooth_peripheral_disconnect()); + pb_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_in); + + pb_assert(pbdrv_bluetooth_peripheral_disconnect(self->peripheral)); return wait_or_await_operation(self_in); } static MP_DEFINE_CONST_FUN_OBJ_1(pb_lwp3device_disconnect_obj, pb_lwp3device_disconnect); @@ -633,6 +640,8 @@ static mp_obj_t pb_type_iodevices_LWP3Device_make_new(const mp_obj_type_t *type, static mp_obj_t lwp3device_write(mp_obj_t self_in, mp_obj_t buf_in) { + pb_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t bufinfo; mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); @@ -643,7 +652,7 @@ static mp_obj_t lwp3device_write(mp_obj_t self_in, mp_obj_t buf_in) { mp_raise_ValueError(MP_ERROR_TEXT("length in header wrong")); } - pb_assert(pbdrv_bluetooth_peripheral_write_characteristic(pb_lwp3device_char.handle, (const uint8_t *)bufinfo.buf, bufinfo.len)); + pb_assert(pbdrv_bluetooth_peripheral_write_characteristic(self->peripheral, pb_lwp3device_char.handle, (const uint8_t *)bufinfo.buf, bufinfo.len)); return wait_or_await_operation(self_in); } static MP_DEFINE_CONST_FUN_OBJ_2(lwp3device_write_obj, lwp3device_write); @@ -651,7 +660,9 @@ static MP_DEFINE_CONST_FUN_OBJ_2(lwp3device_write_obj, lwp3device_write); static mp_obj_t lwp3device_read(mp_obj_t self_in) { pb_lwp3device_obj_t *self = MP_OBJ_TO_PTR(self_in); - pb_lwp3device_assert_connected(); + if (!pbdrv_bluetooth_peripheral_is_connected(self->peripheral)) { + pb_assert(PBIO_ERROR_NO_DEV); + } if (!self->noti_num) { pb_assert(PBIO_ERROR_FAILED); diff --git a/pybricks/iodevices/pb_type_iodevices_xbox_controller.c b/pybricks/iodevices/pb_type_iodevices_xbox_controller.c index 529864ce0..a4198bab3 100644 --- a/pybricks/iodevices/pb_type_iodevices_xbox_controller.c +++ b/pybricks/iodevices/pb_type_iodevices_xbox_controller.c @@ -189,12 +189,12 @@ static pbdrv_bluetooth_ad_match_result_flags_t xbox_advertisement_response_match static xbox_input_map_t *pb_type_xbox_get_input(mp_obj_t self_in) { - if (!pbdrv_bluetooth_is_connected(PBDRV_BLUETOOTH_CONNECTION_PERIPHERAL)) { - mp_raise_OSError(MP_ENODEV); - } - pb_type_xbox_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!pbdrv_bluetooth_peripheral_is_connected(self->peripheral)) { + pb_assert(PBIO_ERROR_NO_DEV); + } + return &self->input_map; } @@ -307,8 +307,8 @@ static pbio_error_t xbox_connect_thread(pbio_os_state_t *state, mp_obj_t parent_ // of disconnecting from Pybricks Code if needed. retry: DEBUG_PRINT("Attempt to find XBOX controller and connect and pair.\n"); - pb_assert(pbdrv_bluetooth_peripheral_scan_and_connect(&scan_config)); - PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); + pb_assert(pbdrv_bluetooth_peripheral_scan_and_connect(self->peripheral, &scan_config)); + PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); // On Prime Hub, connecting can fail for a variety of reasons. A second // attempt usually succeeds. @@ -326,30 +326,30 @@ static pbio_error_t xbox_connect_thread(pbio_os_state_t *state, mp_obj_t parent_ // catch the case where user might not have done this at least once. // Connecting takes about a second longer this way, but we can provide // better error messages. - pb_assert(pbdrv_bluetooth_peripheral_discover_characteristic(&pb_type_xbox_char_hid_map)); - PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); + pb_assert(pbdrv_bluetooth_peripheral_discover_characteristic(self->peripheral, &pb_type_xbox_char_hid_map)); + PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); if (err != PBIO_SUCCESS) { goto disconnect; } DEBUG_PRINT("Read HID map.\n"); - pb_assert(pbdrv_bluetooth_peripheral_read_characteristic(&pb_type_xbox_char_hid_map)); - PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); + pb_assert(pbdrv_bluetooth_peripheral_read_characteristic(self->peripheral, &pb_type_xbox_char_hid_map)); + PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); if (err != PBIO_SUCCESS) { goto disconnect; } // This is the main characteristic that notifies us of button state. DEBUG_PRINT("Discover HID report.\n"); - pb_assert(pbdrv_bluetooth_peripheral_discover_characteristic(&pb_type_xbox_char_hid_report)); - PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); + pb_assert(pbdrv_bluetooth_peripheral_discover_characteristic(self->peripheral, &pb_type_xbox_char_hid_report)); + PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); if (err != PBIO_SUCCESS) { goto disconnect; } DEBUG_PRINT("Read HID report.\n"); - pb_assert(pbdrv_bluetooth_peripheral_read_characteristic(&pb_type_xbox_char_hid_report)); - PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); + pb_assert(pbdrv_bluetooth_peripheral_read_characteristic(self->peripheral, &pb_type_xbox_char_hid_report)); + PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); if (err != PBIO_SUCCESS) { goto disconnect; } @@ -358,8 +358,8 @@ static pbio_error_t xbox_connect_thread(pbio_os_state_t *state, mp_obj_t parent_ disconnect: DEBUG_PRINT("Going to disconnect because of a failure with code %d at line %u.\n", err, *state); - pb_assert(pbdrv_bluetooth_peripheral_disconnect()); - PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, NULL)); + pb_assert(pbdrv_bluetooth_peripheral_disconnect(self->peripheral)); + PBIO_OS_AWAIT(state, &unused, err = pbdrv_bluetooth_await_peripheral_command(&unused, self->peripheral)); DEBUG_PRINT("Disconnect with error code %d.\n", err); pb_assert(err); @@ -392,7 +392,9 @@ static mp_obj_t pb_type_xbox_await_operation(mp_obj_t self_in) { pb_type_xbox_obj_t *self = MP_OBJ_TO_PTR(self_in); pb_type_async_t config = { .iter_once = pbdrv_bluetooth_await_peripheral_command, - .parent_obj = self_in, + // Using the driver function without a wrapper, so should pass its + // context parameter (the peripheral) as the parent object. + .parent_obj = self->peripheral, }; return pb_type_async_wait_or_await(&config, &self->iter, true); } @@ -409,7 +411,8 @@ static mp_obj_t pb_type_xbox_disconnect(mp_obj_t self_in) { // Needed to release claim on allocated data so we can make a new // connection later. pb_type_xbox_close(self_in); - pb_assert(pbdrv_bluetooth_peripheral_disconnect()); + pb_type_xbox_obj_t *self = MP_OBJ_TO_PTR(self_in); + pb_assert(pbdrv_bluetooth_peripheral_disconnect(self->peripheral)); return pb_type_xbox_await_operation(self_in); } static MP_DEFINE_CONST_FUN_OBJ_1(pb_type_xbox_disconnect_obj, pb_type_xbox_disconnect); @@ -461,8 +464,8 @@ static mp_obj_t pb_type_xbox_make_new(const mp_obj_type_t *type, size_t n_args, static mp_obj_t pb_type_xbox_name(size_t n_args, const mp_obj_t *args) { // Asserts connection. pb_type_xbox_get_input(args[0]); - - const char *name = pbdrv_bluetooth_peripheral_get_name(); + pb_type_xbox_obj_t *self = MP_OBJ_TO_PTR(args[0]); + const char *name = pbdrv_bluetooth_peripheral_get_name(self->peripheral); return mp_obj_new_str(name, strlen(name)); } static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pb_type_xbox_name_obj, 1, 2, pb_type_xbox_name); @@ -562,8 +565,6 @@ static mp_obj_t pb_type_xbox_rumble(size_t n_args, const mp_obj_t *pos_args, mp_ PB_ARG_DEFAULT_INT(count, 1), PB_ARG_DEFAULT_INT(delay, 100)); - (void)self; - // 1 unit is 10ms, max duration is 250=2500ms. mp_int_t duration = pb_obj_get_positive_int(duration_in) / 10; mp_int_t delay = pb_obj_get_positive_int(delay_in) / 10; @@ -618,7 +619,7 @@ static mp_obj_t pb_type_xbox_rumble(size_t n_args, const mp_obj_t *pos_args, mp_ // REVISIT: Discover this handle dynamically. const uint16_t handle = 34; - pbdrv_bluetooth_peripheral_write_characteristic(handle, (const uint8_t *)&command, sizeof(command)); + pbdrv_bluetooth_peripheral_write_characteristic(self->peripheral, handle, (const uint8_t *)&command, sizeof(command)); return pb_type_xbox_await_operation(MP_OBJ_TO_PTR(self)); } static MP_DEFINE_CONST_FUN_OBJ_KW(pb_type_xbox_rumble_obj, 1, pb_type_xbox_rumble);