Skip to content

esp32: enable BLE synchronous events and BLE pairing/boindng #7046

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 22, 2022
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
73 changes: 72 additions & 1 deletion extmod/modbluetooth.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "py/objarray.h"
#include "py/qstr.h"
#include "py/runtime.h"
#include "py/stackctrl.h"
#include "extmod/modbluetooth.h"
#include <string.h>

Expand Down Expand Up @@ -1135,7 +1136,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluetooth_ble_invoke_irq_obj, bluetooth_ble_inv

#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS

STATIC mp_obj_t invoke_irq_handler(uint16_t event,
STATIC mp_obj_t invoke_irq_handler_run(uint16_t event,
const mp_int_t *numeric, size_t n_unsigned, size_t n_signed,
const uint8_t *addr,
const mp_obj_bluetooth_uuid_t *uuid,
Expand Down Expand Up @@ -1185,6 +1186,76 @@ STATIC mp_obj_t invoke_irq_handler(uint16_t event,
return result;
}

#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS_WITH_INTERLOCK

// On some systems the BLE event callbacks may occur on a system thread which is not
// a MicroPython thread. In such cases the callback must set up relevant MicroPython
// state and obtain the GIL, to synchronised with the rest of the runtime.

#if MICROPY_ENABLE_PYSTACK
#error not supported
#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,
const mp_obj_bluetooth_uuid_t *uuid,
const uint8_t **data, size_t *data_len, size_t n_data) {

// This code may run on an existing MicroPython thread, or a non-MicroPython thread
// that's not using the mp_thread_get_state() value. In the former case the state
// must be restored once this callback finishes.
mp_state_thread_t *ts_orig = mp_thread_get_state();

mp_state_thread_t ts;
if (ts_orig == NULL) {
mp_thread_set_state(&ts);
mp_stack_set_top(&ts + 1); // need to include ts in root-pointer scan
mp_stack_set_limit(MICROPY_PY_BLUETOOTH_SYNC_EVENT_STACK_SIZE - 1024);
ts.gc_lock_depth = 0;
ts.mp_pending_exception = MP_OBJ_NULL;
mp_locals_set(mp_state_ctx.thread.dict_locals); // set from the outer context
mp_globals_set(mp_state_ctx.thread.dict_globals); // set from the outer context
MP_THREAD_GIL_ENTER();
}

mp_obj_t result = mp_const_none;
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_sched_lock();
result = invoke_irq_handler_run(event, numeric, n_unsigned, n_signed, addr, uuid, data, data_len, n_data);
mp_sched_unlock();
nlr_pop();
} else {
// Uncaught exception, print it out.
mp_sched_unlock();
mp_printf(MICROPY_ERROR_PRINTER, "Unhandled exception in IRQ callback handler\n");
mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(nlr.ret_val));
}

if (ts_orig == NULL) {
MP_THREAD_GIL_EXIT();
mp_thread_set_state(ts_orig);
}

return result;
}

#else

// BLE event callbacks are called directly from the MicroPython runtime, so additional
// synchronisation is not needed, and BLE event handlers can be called directly.

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,
const mp_obj_bluetooth_uuid_t *uuid,
const uint8_t **data, size_t *data_len, size_t n_data) {
return invoke_irq_handler_run(event, numeric, n_unsigned, n_signed, addr, uuid, data, data_len, n_data);
}

#endif

#define NULL_NUMERIC NULL
#define NULL_ADDR NULL
#define NULL_UUID NULL
Expand Down
6 changes: 5 additions & 1 deletion ports/esp32/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,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})
Expand Down
4 changes: 4 additions & 0 deletions ports/esp32/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@
// extended modules
#ifndef MICROPY_PY_BLUETOOTH
#define MICROPY_PY_BLUETOOTH (1)
#define MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS (1)
#define MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS_WITH_INTERLOCK (1)
#define MICROPY_PY_BLUETOOTH_SYNC_EVENT_STACK_SIZE (CONFIG_BT_NIMBLE_TASK_STACK_SIZE)
#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
Expand Down