summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2022-09-21 13:22:27 +1000
committerDamien George <damien@micropython.org>2022-09-22 11:49:58 +1000
commitdb668742a5986ab1de9c0474ef268c00fb1879e7 (patch)
tree584a3acb4e439b2b0201f508e3510724154c0604
parented41d517466f329112529a20f9808f1c1724f759 (diff)
extmod/modbluetooth: Do GATTC reassembly in protected uPy context.
The calls to m_new and m_del require an exclusive uPy (really a GC) context. In particular these functions cannot be called directly from a FreeRTOS task on esp32. Fixes issue #9369. Signed-off-by: Damien George <damien@micropython.org>
-rw-r--r--extmod/modbluetooth.c67
1 files changed, 39 insertions, 28 deletions
diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c
index f02130818..acdbf8d85 100644
--- a/extmod/modbluetooth.c
+++ b/extmod/modbluetooth.c
@@ -52,6 +52,9 @@
#error pairing and bonding require synchronous modbluetooth events
#endif
+// NimBLE can have fragmented data for GATTC events, so requires reassembly.
+#define MICROPY_PY_BLUETOOTH_USE_GATTC_EVENT_DATA_REASSEMBLY MICROPY_BLUETOOTH_NIMBLE
+
#define MP_BLUETOOTH_CONNECT_DEFAULT_SCAN_DURATION_MS 2000
#define MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN 5
@@ -1168,6 +1171,34 @@ STATIC mp_obj_t invoke_irq_handler_run(uint16_t event,
data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(uuid);
}
#endif
+
+ #if MICROPY_PY_BLUETOOTH_USE_GATTC_EVENT_DATA_REASSEMBLY
+ void *buf_to_free = NULL;
+ uint16_t buf_to_free_len = 0;
+ if (event == MP_BLUETOOTH_IRQ_GATTC_NOTIFY || event == MP_BLUETOOTH_IRQ_GATTC_INDICATE || event == MP_BLUETOOTH_IRQ_GATTC_READ_RESULT) {
+ if (n_data > 1) {
+ // Fragmented buffer, need to combine into a new heap-allocated buffer
+ // in order to pass to Python.
+ // Only gattc_on_data_available calls this code, so data and data_len are writable.
+ uint16_t total_len = 0;
+ for (size_t i = 0; i < n_data; ++i) {
+ total_len += data_len[i];
+ }
+ uint8_t *buf = m_new(uint8_t, total_len);
+ uint8_t *p = buf;
+ for (size_t i = 0; i < n_data; ++i) {
+ memcpy(p, data[i], data_len[i]);
+ p += data_len[i];
+ }
+ data[0] = buf;
+ data_len[0] = total_len;
+ n_data = 1;
+ buf_to_free = buf;
+ buf_to_free_len = total_len;
+ }
+ }
+ #endif
+
for (size_t i = 0; i < n_data; ++i) {
if (data[i]) {
mp_obj_memoryview_init(&mv_data[i], 'B', 0, data_len[i], (void *)data[i]);
@@ -1176,10 +1207,17 @@ STATIC mp_obj_t invoke_irq_handler_run(uint16_t event,
data_tuple->items[data_tuple->len++] = mp_const_none;
}
}
+
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));
+ #if MICROPY_PY_BLUETOOTH_USE_GATTC_EVENT_DATA_REASSEMBLY
+ if (buf_to_free != NULL) {
+ m_del(uint8_t, (uint8_t *)buf_to_free, buf_to_free_len);
+ }
+ #endif
+
mp_local_free(data_tuple);
return result;
@@ -1393,35 +1431,8 @@ void mp_bluetooth_gattc_on_discover_complete(uint8_t event, uint16_t conn_handle
}
void mp_bluetooth_gattc_on_data_available(uint8_t event, uint16_t conn_handle, uint16_t value_handle, const uint8_t **data, uint16_t *data_len, size_t num) {
- const uint8_t *combined_data;
- uint16_t total_len;
-
- if (num > 1) {
- // Fragmented buffer, need to combine into a new heap-allocated buffer
- // in order to pass to Python.
- total_len = 0;
- for (size_t i = 0; i < num; ++i) {
- total_len += data_len[i];
- }
- uint8_t *buf = m_new(uint8_t, total_len);
- uint8_t *p = buf;
- for (size_t i = 0; i < num; ++i) {
- memcpy(p, data[i], data_len[i]);
- p += data_len[i];
- }
- combined_data = buf;
- } else {
- // Single buffer, use directly.
- combined_data = *data;
- total_len = *data_len;
- }
-
mp_int_t args[] = {conn_handle, value_handle};
- invoke_irq_handler(event, args, 2, 0, NULL_ADDR, NULL_UUID, &combined_data, &total_len, 1);
-
- if (num > 1) {
- m_del(uint8_t, (uint8_t *)combined_data, total_len);
- }
+ invoke_irq_handler(event, args, 2, 0, NULL_ADDR, NULL_UUID, data, data_len, num);
}
void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle, uint16_t value_handle, uint16_t status) {