diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index e379a8c6a304c..2d22c17dc900b 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -66,9 +66,12 @@ typedef struct { mp_obj_base_t base; mp_obj_t irq_handler; + mp_obj_t irq_data_tuple; + #if MICROPY_PY_BLUETOOTH_IRQ_CAN_BE_ON_SEPARATE_THREAD + mp_obj_t irq_event; + #endif #if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS bool irq_scheduled; - mp_obj_t irq_data_tuple; uint8_t irq_data_addr_bytes[6]; uint16_t irq_data_data_alloc; mp_obj_array_t irq_data_addr; @@ -260,10 +263,10 @@ STATIC mp_obj_t bluetooth_ble_make_new(const mp_obj_type_t *type, size_t n_args, o->irq_handler = mp_const_none; - #if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS // Pre-allocate the event data tuple to prevent needing to allocate in the IRQ handler. o->irq_data_tuple = mp_obj_new_tuple(MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN, NULL); + #if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS // Pre-allocated buffers for address, payload and uuid. mp_obj_memoryview_init(&o->irq_data_addr, 'B', 0, 0, o->irq_data_addr_bytes); o->irq_data_data_alloc = MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN(MICROPY_PY_BLUETOOTH_RINGBUF_SIZE); @@ -274,6 +277,10 @@ STATIC mp_obj_t bluetooth_ble_make_new(const mp_obj_type_t *type, size_t n_args, ringbuf_alloc(&o->ringbuf, MICROPY_PY_BLUETOOTH_RINGBUF_SIZE); #endif + #if MICROPY_PY_BLUETOOTH_IRQ_CAN_BE_ON_SEPARATE_THREAD + mp_bluetooth_port_sync_init(); + #endif + MP_STATE_VM(bluetooth) = MP_OBJ_FROM_PTR(o); } return MP_STATE_VM(bluetooth); @@ -1111,6 +1118,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluetooth_ble_invoke_irq_obj, bluetooth_ble_inv #if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS +#if MICROPY_PY_BLUETOOTH_IRQ_CAN_BE_ON_SEPARATE_THREAD +STATIC mp_obj_t bluetooth_ble_invoke_irq(mp_obj_t bluetooth_in) { + mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(bluetooth_in); + o->irq_event = mp_call_function_2(o->irq_handler, o->irq_event, o->irq_data_tuple); + mp_bluetooth_port_sync_signal_done(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluetooth_ble_invoke_irq_obj, bluetooth_ble_invoke_irq); +#endif + STATIC mp_obj_t invoke_irq_handler(uint16_t event, const mp_int_t *numeric, size_t n_unsigned, size_t n_signed, const uint8_t *addr, @@ -1125,8 +1142,7 @@ STATIC mp_obj_t invoke_irq_handler(uint16_t event, mp_obj_array_t mv_data[2]; assert(n_data <= 2); - mp_obj_tuple_t *data_tuple = mp_local_alloc(sizeof(mp_obj_tuple_t) + sizeof(mp_obj_t) * MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN); - data_tuple->base.type = &mp_type_tuple; + mp_obj_tuple_t *data_tuple = MP_OBJ_TO_PTR(o->irq_data_tuple); data_tuple->len = 0; for (size_t i = 0; i < n_unsigned; ++i) { @@ -1154,11 +1170,18 @@ STATIC mp_obj_t invoke_irq_handler(uint16_t event, } assert(data_tuple->len <= MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN); - mp_obj_t result = mp_call_function_2(o->irq_handler, MP_OBJ_NEW_SMALL_INT(event), MP_OBJ_FROM_PTR(data_tuple)); - - mp_local_free(data_tuple); + #if MICROPY_PY_BLUETOOTH_IRQ_CAN_BE_ON_SEPARATE_THREAD + if (!mp_bluetooth_port_sync_is_main_thread()) { + o->irq_event = MP_OBJ_NEW_SMALL_INT(event); + while (!mp_sched_schedule(MP_OBJ_FROM_PTR(&bluetooth_ble_invoke_irq_obj), MP_OBJ_FROM_PTR(o))) { + mp_bluetooth_port_sync_yield(); + } + mp_bluetooth_port_sync_wait_for_signal(); + return o->irq_event; + } + #endif - return result; + return mp_call_function_2(o->irq_handler, MP_OBJ_NEW_SMALL_INT(event), MP_OBJ_FROM_PTR(data_tuple)); } #define NULL_NUMERIC NULL diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index d126ad6c11344..9c5fb6725d09c 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -405,6 +405,14 @@ int mp_bluetooth_l2cap_recvinto(uint16_t conn_handle, uint16_t cid, uint8_t *buf int mp_bluetooth_hci_cmd(uint16_t ogf, uint16_t ocf, const uint8_t *req, size_t req_len, uint8_t *resp, size_t resp_len, uint8_t *status); #endif // MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD +#if MICROPY_PY_BLUETOOTH_IRQ_CAN_BE_ON_SEPARATE_THREAD +void mp_bluetooth_port_sync_init(void); +bool mp_bluetooth_port_sync_is_main_thread(void); +void mp_bluetooth_port_sync_yield(void); +void mp_bluetooth_port_sync_wait_for_signal(void); +void mp_bluetooth_port_sync_signal_done(void); +#endif + ///////////////////////////////////////////////////////////////////////////// // API implemented by modbluetooth (called by port-specific implementations): diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c index e3a2f872e5ecb..f653b95d3e699 100644 --- a/extmod/nimble/modbluetooth_nimble.c +++ b/extmod/nimble/modbluetooth_nimble.c @@ -1791,9 +1791,9 @@ STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, unio case BLE_STORE_OBJ_TYPE_OUR_SEC: { // // Find our secret for this remote device, matching this ediv/rand key. - assert(ble_addr_cmp(&key->sec.peer_addr, BLE_ADDR_ANY)); // Must have address. + // TODO: Support cases where key->sec.peer_addr is BLE_ADDR_ANY, and + // key->sec.ediv_rand_present is false. assert(key->sec.idx == 0); - assert(key->sec.ediv_rand_present); key_data = (const uint8_t *)&key->sec.peer_addr; key_data_len = sizeof(ble_addr_t); break; diff --git a/ports/esp32/main/CMakeLists.txt b/ports/esp32/main/CMakeLists.txt index 656045da90a21..3c3c723138de4 100644 --- a/ports/esp32/main/CMakeLists.txt +++ b/ports/esp32/main/CMakeLists.txt @@ -172,11 +172,15 @@ target_compile_options(${MICROPY_TARGET} PUBLIC -Wno-missing-field-initializers ) +# Additional include directories needed for private NimBLE headers. +target_include_directories(${MICROPY_TARGET} PUBLIC + ${IDF_PATH}/components/bt/host/nimble/nimble +) + # Add additional extmod and usermod components. target_link_libraries(${MICROPY_TARGET} micropy_extmod_btree) target_link_libraries(${MICROPY_TARGET} usermod) - # Collect all of the include directories and compile definitions for the IDF components. foreach(comp ${IDF_COMPONENTS}) micropy_gather_target_properties(__idf_${comp}) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 8788963cb3209..b6eb9adf3f33c 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -124,7 +124,10 @@ // extended modules #ifndef MICROPY_PY_BLUETOOTH #define MICROPY_PY_BLUETOOTH (1) +#define MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS (1) +#define MICROPY_PY_BLUETOOTH_IRQ_CAN_BE_ON_SEPARATE_THREAD (1) #define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (1) +#define MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING (1) #define MICROPY_BLUETOOTH_NIMBLE (1) #define MICROPY_BLUETOOTH_NIMBLE_BINDINGS_ONLY (1) #endif diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index cf668216df9e3..8d077c5293508 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -213,3 +213,28 @@ void mp_hal_wake_main_task_from_isr(void) { portYIELD_FROM_ISR(); } } + +/******************************************************************************/ +// Bluetooth event synchronisation helpers. + +SemaphoreHandle_t mp_bluetooth_port_sync_sem; + +void mp_bluetooth_port_sync_init(void) { + mp_bluetooth_port_sync_sem = xSemaphoreCreateBinary(); +} + +bool mp_bluetooth_port_sync_is_main_thread(void) { + return xTaskGetCurrentTaskHandle() == mp_main_task_handle; +} + +void mp_bluetooth_port_sync_yield(void) { + vPortYield(); +} + +void mp_bluetooth_port_sync_wait_for_signal(void) { + xSemaphoreTake(mp_bluetooth_port_sync_sem, portMAX_DELAY); +} + +void mp_bluetooth_port_sync_signal_done(void) { + xSemaphoreGive(mp_bluetooth_port_sync_sem); +}