|
|
|
@ -47,15 +47,18 @@
|
|
|
|
|
|
|
|
|
|
#define MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_TUPLE_LEN 5
|
|
|
|
|
|
|
|
|
|
#if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
|
|
|
|
// This formula is intended to allow queuing the data of a large characteristic
|
|
|
|
|
// while still leaving room for a couple of normal (small, fixed size) events.
|
|
|
|
|
#define MICROPY_PY_BLUETOOTH_MAX_EVENT_DATA_BYTES_LEN(ringbuf_size) (MAX((int)((ringbuf_size) / 2), (int)(ringbuf_size) - 64))
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// bluetooth.BLE type. This is currently a singleton, however in the future
|
|
|
|
|
// this could allow having multiple BLE interfaces on different UARTs.
|
|
|
|
|
typedef struct {
|
|
|
|
|
mp_obj_base_t base;
|
|
|
|
|
mp_obj_t irq_handler;
|
|
|
|
|
#if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
|
|
|
|
bool irq_scheduled;
|
|
|
|
|
mp_obj_t irq_data_tuple;
|
|
|
|
|
uint8_t irq_data_addr_bytes[6];
|
|
|
|
@ -64,8 +67,6 @@ typedef struct {
|
|
|
|
|
mp_obj_array_t irq_data_data;
|
|
|
|
|
mp_obj_bluetooth_uuid_t irq_data_uuid;
|
|
|
|
|
ringbuf_t ringbuf;
|
|
|
|
|
#if MICROPY_PY_BLUETOOTH_GATTS_ON_READ_CALLBACK
|
|
|
|
|
mp_obj_t irq_read_request_data_tuple;
|
|
|
|
|
#endif
|
|
|
|
|
} mp_obj_bluetooth_ble_t;
|
|
|
|
|
|
|
|
|
@ -206,8 +207,7 @@ STATIC mp_int_t bluetooth_uuid_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bu
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
|
|
|
|
|
|
|
|
|
#if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS && MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
|
|
|
|
STATIC void ringbuf_put_uuid(ringbuf_t *ringbuf, mp_obj_bluetooth_uuid_t *uuid) {
|
|
|
|
|
assert(ringbuf_free(ringbuf) >= (size_t)uuid->type + 1);
|
|
|
|
|
ringbuf_put(ringbuf, uuid->type);
|
|
|
|
@ -252,14 +252,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_GATTS_ON_READ_CALLBACK
|
|
|
|
|
// Pre-allocate a separate data tuple for the read request "hard" irq.
|
|
|
|
|
o->irq_read_request_data_tuple = mp_obj_new_tuple(2, NULL);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
@ -268,6 +264,7 @@ STATIC mp_obj_t bluetooth_ble_make_new(const mp_obj_type_t *type, size_t n_args,
|
|
|
|
|
|
|
|
|
|
// Allocate the default ringbuf.
|
|
|
|
|
ringbuf_alloc(&o->ringbuf, MICROPY_PY_BLUETOOTH_RINGBUF_SIZE);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
MP_STATE_VM(bluetooth) = MP_OBJ_FROM_PTR(o);
|
|
|
|
|
}
|
|
|
|
@ -290,8 +287,6 @@ STATIC mp_obj_t bluetooth_ble_active(size_t n_args, const mp_obj_t *args) {
|
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_active_obj, 1, 2, bluetooth_ble_active);
|
|
|
|
|
|
|
|
|
|
STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
|
|
|
|
|
mp_obj_bluetooth_ble_t *self = MP_OBJ_TO_PTR(args[0]);
|
|
|
|
|
|
|
|
|
|
if (kwargs->used == 0) {
|
|
|
|
|
// Get config value
|
|
|
|
|
if (n_args != 2) {
|
|
|
|
@ -311,8 +306,12 @@ STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
|
|
|
|
|
mp_obj_t items[] = { MP_OBJ_NEW_SMALL_INT(addr_type), mp_obj_new_bytes(addr, MP_ARRAY_SIZE(addr)) };
|
|
|
|
|
return mp_obj_new_tuple(2, items);
|
|
|
|
|
}
|
|
|
|
|
case MP_QSTR_rxbuf:
|
|
|
|
|
#if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
|
|
|
|
case MP_QSTR_rxbuf: {
|
|
|
|
|
mp_obj_bluetooth_ble_t *self = MP_OBJ_TO_PTR(args[0]);
|
|
|
|
|
return mp_obj_new_int(self->ringbuf.size);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
case MP_QSTR_mtu:
|
|
|
|
|
return mp_obj_new_int(mp_bluetooth_get_preferred_mtu());
|
|
|
|
|
default:
|
|
|
|
@ -334,6 +333,7 @@ STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
|
|
|
|
|
bluetooth_handle_errno(mp_bluetooth_gap_set_device_name(bufinfo.buf, bufinfo.len));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
#if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
|
|
|
|
case MP_QSTR_rxbuf: {
|
|
|
|
|
// Determine new buffer sizes
|
|
|
|
|
mp_int_t ringbuf_alloc = mp_obj_get_int(e->value);
|
|
|
|
@ -347,6 +347,7 @@ STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
|
|
|
|
|
uint8_t *irq_data = m_new(uint8_t, irq_data_alloc);
|
|
|
|
|
|
|
|
|
|
// Get old buffer sizes and pointers
|
|
|
|
|
mp_obj_bluetooth_ble_t *self = MP_OBJ_TO_PTR(args[0]);
|
|
|
|
|
uint8_t *old_ringbuf_buf = self->ringbuf.buf;
|
|
|
|
|
size_t old_ringbuf_alloc = self->ringbuf.size;
|
|
|
|
|
uint8_t *old_irq_data_buf = (uint8_t *)self->irq_data_data.items;
|
|
|
|
@ -367,6 +368,7 @@ STATIC mp_obj_t bluetooth_ble_config(size_t n_args, const mp_obj_t *args, mp_map
|
|
|
|
|
m_del(uint8_t, old_irq_data_buf, old_irq_data_alloc);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
case MP_QSTR_mtu: {
|
|
|
|
|
mp_int_t mtu = mp_obj_get_int(e->value);
|
|
|
|
|
bluetooth_handle_errno(mp_bluetooth_set_preferred_mtu(mtu));
|
|
|
|
@ -845,8 +847,7 @@ const mp_obj_module_t mp_module_ubluetooth = {
|
|
|
|
|
|
|
|
|
|
// Helpers
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
#if !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
|
|
|
|
STATIC void ringbuf_extract(ringbuf_t *ringbuf, mp_obj_tuple_t *data_tuple, size_t n_u16, size_t n_u8, mp_obj_array_t *bytes_addr, size_t n_i8, mp_obj_bluetooth_uuid_t *uuid, mp_obj_array_t *bytes_data) {
|
|
|
|
|
assert(ringbuf_avail(ringbuf) >= n_u16 * 2 + n_u8 + (bytes_addr ? 6 : 0) + n_i8 + (uuid ? 1 : 0) + (bytes_data ? 1 : 0));
|
|
|
|
|
size_t j = 0;
|
|
|
|
@ -854,7 +855,7 @@ STATIC void ringbuf_extract(ringbuf_t *ringbuf, mp_obj_tuple_t *data_tuple, size
|
|
|
|
|
for (size_t i = 0; i < n_u16; ++i) {
|
|
|
|
|
data_tuple->items[j++] = MP_OBJ_NEW_SMALL_INT(ringbuf_get16(ringbuf));
|
|
|
|
|
}
|
|
|
|
|
if (n_u8) {
|
|
|
|
|
for (size_t i = 0; i < n_u8; ++i) {
|
|
|
|
|
data_tuple->items[j++] = MP_OBJ_NEW_SMALL_INT(ringbuf_get(ringbuf));
|
|
|
|
|
}
|
|
|
|
|
if (bytes_addr) {
|
|
|
|
@ -960,11 +961,166 @@ STATIC mp_obj_t bluetooth_ble_invoke_irq(mp_obj_t none_in) {
|
|
|
|
|
return mp_const_none;
|
|
|
|
|
}
|
|
|
|
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(bluetooth_ble_invoke_irq_obj, bluetooth_ble_invoke_irq);
|
|
|
|
|
#endif // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// Port API
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
|
|
|
|
|
|
|
|
|
STATIC mp_obj_t invoke_irq_handler(uint16_t event,
|
|
|
|
|
const uint16_t *u16, size_t n_u16,
|
|
|
|
|
const uint8_t *u8, size_t n_u8,
|
|
|
|
|
const uint8_t *addr,
|
|
|
|
|
const int8_t *i8, size_t n_i8,
|
|
|
|
|
const mp_obj_bluetooth_uuid_t *uuid,
|
|
|
|
|
const uint8_t *data, size_t data_len) {
|
|
|
|
|
mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
|
|
|
|
|
if (o->irq_handler == mp_const_none) {
|
|
|
|
|
return mp_const_none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mp_obj_array_t mv_addr;
|
|
|
|
|
mp_obj_array_t mv_data;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
data_tuple->len = 0;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < n_u16; ++i) {
|
|
|
|
|
data_tuple->items[data_tuple->len++] = MP_OBJ_NEW_SMALL_INT(u16[i]);
|
|
|
|
|
}
|
|
|
|
|
for (size_t i = 0; i < n_u8; ++i) {
|
|
|
|
|
data_tuple->items[data_tuple->len++] = MP_OBJ_NEW_SMALL_INT(u8[i]);
|
|
|
|
|
}
|
|
|
|
|
if (addr) {
|
|
|
|
|
mp_obj_memoryview_init(&mv_addr, 'B', 0, 6, (void *)addr);
|
|
|
|
|
data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(&mv_addr);
|
|
|
|
|
}
|
|
|
|
|
for (size_t i = 0; i < n_i8; ++i) {
|
|
|
|
|
data_tuple->items[data_tuple->len++] = MP_OBJ_NEW_SMALL_INT(i8[i]);
|
|
|
|
|
}
|
|
|
|
|
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
|
|
|
|
if (uuid) {
|
|
|
|
|
data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(uuid);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if (data) {
|
|
|
|
|
mp_obj_memoryview_init(&mv_data, 'B', 0, data_len, (void *)data);
|
|
|
|
|
data_tuple->items[data_tuple->len++] = MP_OBJ_FROM_PTR(&mv_data);
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define NULL_U16 NULL
|
|
|
|
|
#define NULL_U8 NULL
|
|
|
|
|
#define NULL_ADDR NULL
|
|
|
|
|
#define NULL_I8 NULL
|
|
|
|
|
#define NULL_UUID NULL
|
|
|
|
|
#define NULL_DATA NULL
|
|
|
|
|
|
|
|
|
|
void mp_bluetooth_gap_on_connected_disconnected(uint8_t event, uint16_t conn_handle, uint8_t addr_type, const uint8_t *addr) {
|
|
|
|
|
invoke_irq_handler(event, &conn_handle, 1, &addr_type, 1, addr, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mp_bluetooth_gatts_on_write(uint16_t conn_handle, uint16_t value_handle) {
|
|
|
|
|
uint16_t args[] = {conn_handle, value_handle};
|
|
|
|
|
invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_WRITE, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mp_bluetooth_gatts_on_indicate_complete(uint16_t conn_handle, uint16_t value_handle, uint8_t status) {
|
|
|
|
|
uint16_t args[] = {conn_handle, value_handle};
|
|
|
|
|
invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_INDICATE_DONE, args, 2, &status, 1, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_handle) {
|
|
|
|
|
uint16_t args[] = {conn_handle, value_handle};
|
|
|
|
|
mp_obj_t result = invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTS_READ_REQUEST, args, 2, NULL, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
|
|
|
|
|
return result == mp_const_none || mp_obj_is_true(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle, uint16_t value) {
|
|
|
|
|
uint16_t args[] = {conn_handle, value};
|
|
|
|
|
invoke_irq_handler(MP_BLUETOOTH_IRQ_MTU_EXCHANGED, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
|
|
|
|
void mp_bluetooth_gap_on_scan_complete(void) {
|
|
|
|
|
invoke_irq_handler(MP_BLUETOOTH_IRQ_SCAN_DONE, NULL_U16, 0, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mp_bluetooth_gap_on_scan_result(uint8_t addr_type, const uint8_t *addr, uint8_t adv_type, const int8_t rssi, const uint8_t *data, size_t data_len) {
|
|
|
|
|
int8_t args[] = {adv_type, rssi};
|
|
|
|
|
invoke_irq_handler(MP_BLUETOOTH_IRQ_SCAN_RESULT, NULL_U16, 0, &addr_type, 1, addr, args, 2, NULL_UUID, data, data_len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mp_bluetooth_gattc_on_primary_service_result(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, mp_obj_bluetooth_uuid_t *service_uuid) {
|
|
|
|
|
uint16_t args[] = {conn_handle, start_handle, end_handle};
|
|
|
|
|
invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_SERVICE_RESULT, args, 3, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, service_uuid, NULL_DATA, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mp_bluetooth_gattc_on_characteristic_result(uint16_t conn_handle, uint16_t def_handle, uint16_t value_handle, uint8_t properties, mp_obj_bluetooth_uuid_t *characteristic_uuid) {
|
|
|
|
|
uint16_t args[] = {conn_handle, def_handle, value_handle};
|
|
|
|
|
invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_CHARACTERISTIC_RESULT, args, 3, &properties, 1, NULL_ADDR, NULL_I8, 0, characteristic_uuid, NULL_DATA, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mp_bluetooth_gattc_on_descriptor_result(uint16_t conn_handle, uint16_t handle, mp_obj_bluetooth_uuid_t *descriptor_uuid) {
|
|
|
|
|
uint16_t args[] = {conn_handle, handle};
|
|
|
|
|
invoke_irq_handler(MP_BLUETOOTH_IRQ_GATTC_DESCRIPTOR_RESULT, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, descriptor_uuid, NULL_DATA, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mp_bluetooth_gattc_on_discover_complete(uint8_t event, uint16_t conn_handle, uint16_t status) {
|
|
|
|
|
uint16_t args[] = {conn_handle, status};
|
|
|
|
|
invoke_irq_handler(event, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t args[] = {conn_handle, value_handle};
|
|
|
|
|
invoke_irq_handler(event, args, 2, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, combined_data, total_len);
|
|
|
|
|
|
|
|
|
|
if (num > 1) {
|
|
|
|
|
m_del(uint8_t, (uint8_t *)combined_data, total_len);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle, uint16_t value_handle, uint16_t status) {
|
|
|
|
|
uint16_t args[] = {conn_handle, value_handle, status};
|
|
|
|
|
invoke_irq_handler(event, args, 3, NULL_U8, 0, NULL_ADDR, NULL_I8, 0, NULL_UUID, NULL_DATA, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
|
|
|
|
|
|
|
|
|
#else // !MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
|
|
|
|
// Callbacks are called in interrupt context (i.e. can't allocate), so we need to push the data
|
|
|
|
|
// into the ringbuf and schedule the callback via mp_sched_schedule.
|
|
|
|
|
|
|
|
|
@ -1169,36 +1325,12 @@ void mp_bluetooth_gattc_on_read_write_status(uint8_t event, uint16_t conn_handle
|
|
|
|
|
|
|
|
|
|
#endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE
|
|
|
|
|
|
|
|
|
|
#if MICROPY_PY_BLUETOOTH_GATTS_ON_READ_CALLBACK
|
|
|
|
|
// This can only be enabled when the thread invoking this is a MicroPython thread.
|
|
|
|
|
// On ESP32, for example, this is not the case.
|
|
|
|
|
bool mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_handle) {
|
|
|
|
|
mp_obj_bluetooth_ble_t *o = MP_OBJ_TO_PTR(MP_STATE_VM(bluetooth));
|
|
|
|
|
if (o->irq_handler != mp_const_none) {
|
|
|
|
|
// When executing code within a handler we must lock the scheduler to
|
|
|
|
|
// prevent any scheduled callbacks from running, and lock the GC to
|
|
|
|
|
// prevent any memory allocations.
|
|
|
|
|
mp_sched_lock();
|
|
|
|
|
gc_lock();
|
|
|
|
|
|
|
|
|
|
// Use pre-allocated tuple distinct to the one used by the "soft" IRQs.
|
|
|
|
|
mp_obj_tuple_t *data = MP_OBJ_TO_PTR(o->irq_read_request_data_tuple);
|
|
|
|
|
data->items[0] = MP_OBJ_NEW_SMALL_INT(conn_handle);
|
|
|
|
|
data->items[1] = MP_OBJ_NEW_SMALL_INT(value_handle);
|
|
|
|
|
data->len = 2;
|
|
|
|
|
mp_obj_t irq_ret = mp_call_function_2_protected(o->irq_handler, MP_OBJ_NEW_SMALL_INT(MP_BLUETOOTH_IRQ_GATTS_READ_REQUEST), o->irq_read_request_data_tuple);
|
|
|
|
|
|
|
|
|
|
gc_unlock();
|
|
|
|
|
mp_sched_unlock();
|
|
|
|
|
|
|
|
|
|
// If the IRQ handler explicitly returned false, then deny the read. Otherwise if it returns None/True, allow it.
|
|
|
|
|
return irq_ret != MP_OBJ_NULL && (irq_ret == mp_const_none || mp_obj_is_true(irq_ret));
|
|
|
|
|
} else {
|
|
|
|
|
// No IRQ handler, allow the read.
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
(void)conn_handle;
|
|
|
|
|
(void)value_handle;
|
|
|
|
|
// This must be handled synchronously and therefore cannot implemented with the ringbuffer.
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle, uint16_t value) {
|
|
|
|
|
MICROPY_PY_BLUETOOTH_ENTER
|
|
|
|
@ -1210,6 +1342,12 @@ void mp_bluetooth_gatts_on_mtu_exchanged(uint16_t conn_handle, uint16_t value) {
|
|
|
|
|
schedule_ringbuf(atomic_state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// GATTS DB
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void mp_bluetooth_gatts_db_create_entry(mp_gatts_db_t db, uint16_t handle, size_t len) {
|
|
|
|
|
mp_map_elem_t *elem = mp_map_lookup(db, MP_OBJ_NEW_SMALL_INT(handle), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
|
|
|
|
|
mp_bluetooth_gatts_db_entry_t *entry = m_new(mp_bluetooth_gatts_db_entry_t, 1);
|
|
|
|
|