From 0ac06a510af8290e2c5e3a1f43c87d232e460b9b Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 20 Feb 2020 14:37:32 +1100 Subject: [PATCH] extmod/modbluetooth: Extract out gatts_db functionality from nimble. For use by other stacks, if they need it. Work done in collaboration with Jim Mussared aka @jimmo. --- extmod/modbluetooth.c | 62 +++++++++++++++++++++ extmod/modbluetooth.h | 36 ++++++++++++- extmod/nimble/modbluetooth_nimble.c | 83 +++++------------------------ extmod/nimble/modbluetooth_nimble.h | 4 +- 4 files changed, 113 insertions(+), 72 deletions(-) diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index 1d8a73848f..75fbeedb50 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -1088,4 +1088,66 @@ bool mp_bluetooth_gatts_on_read_request(uint16_t conn_handle, uint16_t value_han } #endif +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); + entry->data = m_new(uint8_t, len); + entry->data_alloc = len; + entry->data_len = 0; + entry->append = false; + elem->value = MP_OBJ_FROM_PTR(entry); +} + +mp_bluetooth_gatts_db_entry_t *mp_bluetooth_gatts_db_lookup(mp_gatts_db_t db, uint16_t handle) { + mp_map_elem_t *elem = mp_map_lookup(db, MP_OBJ_NEW_SMALL_INT(handle), MP_MAP_LOOKUP); + if (!elem) { + return NULL; + } + return MP_OBJ_TO_PTR(elem->value); +} + +int mp_bluetooth_gatts_db_read(mp_gatts_db_t db, uint16_t handle, uint8_t **value, size_t *value_len) { + mp_bluetooth_gatts_db_entry_t *entry = mp_bluetooth_gatts_db_lookup(db, handle); + if (!entry) { + return MP_EINVAL; + } + + *value = entry->data; + *value_len = entry->data_len; + if (entry->append) { + entry->data_len = 0; + } + + return 0; +} + +int mp_bluetooth_gatts_db_write(mp_gatts_db_t db, uint16_t handle, const uint8_t *value, size_t value_len) { + mp_bluetooth_gatts_db_entry_t *entry = mp_bluetooth_gatts_db_lookup(db, handle); + if (!entry) { + return MP_EINVAL; + } + + if (value_len > entry->data_alloc) { + entry->data = m_new(uint8_t, value_len); + entry->data_alloc = value_len; + } + + memcpy(entry->data, value, value_len); + entry->data_len = value_len; + + return 0; +} + +int mp_bluetooth_gatts_db_resize(mp_gatts_db_t db, uint16_t handle, size_t len, bool append) { + mp_bluetooth_gatts_db_entry_t *entry = mp_bluetooth_gatts_db_lookup(db, handle); + if (!entry) { + return MP_EINVAL; + } + entry->data = m_renew(uint8_t, entry->data, entry->data_alloc, len); + entry->data_alloc = len; + entry->data_len = 0; + entry->append = append; + return 0; +} + #endif // MICROPY_PY_BLUETOOTH diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index 5e4e2c25a6..661130802a 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -54,10 +54,12 @@ #endif // Common constants. -#ifndef MP_BLUETOOTH_MAX_ATTR_SIZE -#define MP_BLUETOOTH_MAX_ATTR_SIZE (20) +#ifndef MP_BLUETOOTH_DEFAULT_ATTR_LEN +#define MP_BLUETOOTH_DEFAULT_ATTR_LEN (20) #endif +#define MP_BLUETOOTH_CCCB_LEN (2) + // Advertisement packet lengths #define MP_BLUETOOTH_GAP_ADV_MAX_LEN (32) @@ -267,4 +269,34 @@ void mp_bluetooth_gattc_on_data_available_end(void); void mp_bluetooth_gattc_on_write_status(uint16_t conn_handle, uint16_t value_handle, uint16_t status); #endif +// For stacks that don't manage attribute value data (currently all of them), helpers +// to store this in a map, keyed by value handle. + +typedef struct { + // Pointer to heap-allocated data. + uint8_t *data; + // Allocated size of data. + size_t data_alloc; + // Current bytes in use. + size_t data_len; + // Whether new writes append or replace existing data (default false). + bool append; +} mp_bluetooth_gatts_db_entry_t; + +typedef mp_map_t *mp_gatts_db_t; + +STATIC inline void mp_bluetooth_gatts_db_create(mp_gatts_db_t *db) { + *db = m_new(mp_map_t, 1); +} + +STATIC inline void mp_bluetooth_gatts_db_reset(mp_gatts_db_t db) { + mp_map_init(db, 0); +} + +void mp_bluetooth_gatts_db_create_entry(mp_gatts_db_t db, uint16_t handle, size_t len); +mp_bluetooth_gatts_db_entry_t *mp_bluetooth_gatts_db_lookup(mp_gatts_db_t db, uint16_t handle); +int mp_bluetooth_gatts_db_read(mp_gatts_db_t db, uint16_t handle, uint8_t **value, size_t *value_len); +int mp_bluetooth_gatts_db_write(mp_gatts_db_t db, uint16_t handle, const uint8_t *value, size_t value_len); +int mp_bluetooth_gatts_db_resize(mp_gatts_db_t db, uint16_t handle, size_t len, bool append); + #endif // MICROPY_INCLUDED_EXTMOD_MODBLUETOOTH_H diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c index f7602c35fd..8ef7c6f31d 100644 --- a/extmod/nimble/modbluetooth_nimble.c +++ b/extmod/nimble/modbluetooth_nimble.c @@ -153,17 +153,6 @@ STATIC ble_addr_t create_nimble_addr(uint8_t addr_type, const uint8_t *addr) { #endif // MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE -typedef struct { - // Pointer to heap-allocated data. - uint8_t *data; - // Allocated size of data. - size_t data_alloc; - // Current bytes in use. - size_t data_len; - // Whether new writes append or replace existing data (default false). - bool append; -} gatts_db_entry_t; - volatile int mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF; STATIC void reset_cb(int reason) { @@ -195,8 +184,8 @@ STATIC void sync_cb(void) { assert(rc == 0); } - if (MP_BLUETOOTH_MAX_ATTR_SIZE > 20) { - rc = ble_att_set_preferred_mtu(MP_BLUETOOTH_MAX_ATTR_SIZE + 3); + if (MP_BLUETOOTH_DEFAULT_ATTR_LEN > 20) { + rc = ble_att_set_preferred_mtu(MP_BLUETOOTH_DEFAULT_ATTR_LEN + 3); assert(rc == 0); } @@ -205,16 +194,6 @@ STATIC void sync_cb(void) { mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_ACTIVE; } -STATIC void create_gatts_db_entry(uint16_t handle) { - mp_map_elem_t *elem = mp_map_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, MP_OBJ_NEW_SMALL_INT(handle), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); - gatts_db_entry_t *entry = m_new(gatts_db_entry_t, 1); - entry->data = m_new(uint8_t, MP_BLUETOOTH_MAX_ATTR_SIZE); - entry->data_alloc = MP_BLUETOOTH_MAX_ATTR_SIZE; - entry->data_len = 0; - entry->append = false; - elem->value = MP_OBJ_FROM_PTR(entry); -} - STATIC void gatts_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) { switch (ctxt->op) { case BLE_GATT_REGISTER_OP_SVC: @@ -232,7 +211,7 @@ STATIC void gatts_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) { // Allocate the gatts_db storage for this characteristic. // Although this function is a callback, it's called synchronously from ble_hs_sched_start/ble_gatts_start, so safe to allocate. - create_gatts_db_entry(ctxt->chr.val_handle); + mp_bluetooth_gatts_db_create_entry(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, ctxt->chr.val_handle, MP_BLUETOOTH_DEFAULT_ATTR_LEN); break; case BLE_GATT_REGISTER_OP_DSC: @@ -241,7 +220,7 @@ STATIC void gatts_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) { DEBUG_EVENT_printf("gatts_register_cb: dsc uuid=%p handle=%d\n", &ctxt->dsc.dsc_def->uuid, ctxt->dsc.handle); // See above, safe to alloc. - create_gatts_db_entry(ctxt->dsc.handle); + mp_bluetooth_gatts_db_create_entry(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, ctxt->dsc.handle, MP_BLUETOOTH_DEFAULT_ATTR_LEN); // Unlike characteristics, we have to manually provide a way to get the handle back to the register method. *((uint16_t *)ctxt->dsc.dsc_def->arg) = ctxt->dsc.handle; @@ -291,7 +270,7 @@ int mp_bluetooth_init(void) { ble_hs_cfg.store_status_cb = ble_store_util_status_rr; MP_STATE_PORT(bluetooth_nimble_root_pointers) = m_new0(mp_bluetooth_nimble_root_pointers_t, 1); - MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db = m_new(mp_map_t, 1); + mp_bluetooth_gatts_db_create(&MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db); mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_STARTING; @@ -408,8 +387,7 @@ void mp_bluetooth_gap_advertise_stop(void) { static int characteristic_access_cb(uint16_t conn_handle, uint16_t value_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { DEBUG_EVENT_printf("characteristic_access_cb: conn_handle=%u value_handle=%u op=%u\n", conn_handle, value_handle, ctxt->op); - mp_map_elem_t *elem; - gatts_db_entry_t *entry; + mp_bluetooth_gatts_db_entry_t *entry; switch (ctxt->op) { case BLE_GATT_ACCESS_OP_READ_CHR: case BLE_GATT_ACCESS_OP_READ_DSC: @@ -420,22 +398,20 @@ static int characteristic_access_cb(uint16_t conn_handle, uint16_t value_handle, } #endif - elem = mp_map_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); - if (!elem) { + entry = mp_bluetooth_gatts_db_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, value_handle); + if (!entry) { return BLE_ATT_ERR_ATTR_NOT_FOUND; } - entry = MP_OBJ_TO_PTR(elem->value); os_mbuf_append(ctxt->om, entry->data, entry->data_len); return 0; case BLE_GATT_ACCESS_OP_WRITE_CHR: case BLE_GATT_ACCESS_OP_WRITE_DSC: - elem = mp_map_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); - if (!elem) { + entry = mp_bluetooth_gatts_db_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, value_handle); + if (!entry) { return BLE_ATT_ERR_ATTR_NOT_FOUND; } - entry = MP_OBJ_TO_PTR(elem->value); size_t offset = 0; if (entry->append) { @@ -458,7 +434,7 @@ int mp_bluetooth_gatts_register_service_begin(bool append) { } // Reset the gatt characteristic value db. - mp_map_init(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, 0); + mp_bluetooth_gatts_db_reset(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db); // By default, just register the default gap service. ble_svc_gap_init(); @@ -551,33 +527,11 @@ int mp_bluetooth_gap_disconnect(uint16_t conn_handle) { } int mp_bluetooth_gatts_read(uint16_t value_handle, uint8_t **value, size_t *value_len) { - mp_map_elem_t *elem = mp_map_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); - if (!elem) { - return MP_EINVAL; - } - gatts_db_entry_t *entry = MP_OBJ_TO_PTR(elem->value); - *value = entry->data; - *value_len = entry->data_len; - if (entry->append) { - entry->data_len = 0; - } - return 0; + return mp_bluetooth_gatts_db_read(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, value_handle, value, value_len); } int mp_bluetooth_gatts_write(uint16_t value_handle, const uint8_t *value, size_t value_len) { - mp_map_elem_t *elem = mp_map_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); - if (!elem) { - return MP_EINVAL; - } - gatts_db_entry_t *entry = MP_OBJ_TO_PTR(elem->value); - if (value_len > entry->data_alloc) { - entry->data = m_new(uint8_t, value_len); - entry->data_alloc = value_len; - } - - memcpy(entry->data, value, value_len); - entry->data_len = value_len; - return 0; + return mp_bluetooth_gatts_db_write(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, value_handle, value, value_len); } // TODO: Could use ble_gatts_chr_updated to send to all subscribed centrals. @@ -602,16 +556,7 @@ int mp_bluetooth_gatts_indicate(uint16_t conn_handle, uint16_t value_handle) { } int mp_bluetooth_gatts_set_buffer(uint16_t value_handle, size_t len, bool append) { - mp_map_elem_t *elem = mp_map_lookup(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, MP_OBJ_NEW_SMALL_INT(value_handle), MP_MAP_LOOKUP); - if (!elem) { - return MP_EINVAL; - } - gatts_db_entry_t *entry = MP_OBJ_TO_PTR(elem->value); - entry->data = m_renew(uint8_t, entry->data, entry->data_alloc, len); - entry->data_alloc = len; - entry->data_len = 0; - entry->append = append; - return 0; + return mp_bluetooth_gatts_db_resize(MP_STATE_PORT(bluetooth_nimble_root_pointers)->gatts_db, value_handle, len, append); } #if MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE diff --git a/extmod/nimble/modbluetooth_nimble.h b/extmod/nimble/modbluetooth_nimble.h index c70c3bc90a..745ff96825 100644 --- a/extmod/nimble/modbluetooth_nimble.h +++ b/extmod/nimble/modbluetooth_nimble.h @@ -27,11 +27,13 @@ #ifndef MICROPY_INCLUDED_EXTMOD_NIMBLE_MODBLUETOOTH_NIMBLE_H #define MICROPY_INCLUDED_EXTMOD_NIMBLE_MODBLUETOOTH_NIMBLE_H +#include "extmod/modbluetooth.h" + #define MP_BLUETOOTH_NIMBLE_MAX_SERVICES (8) typedef struct _mp_bluetooth_nimble_root_pointers_t { // Characteristic (and descriptor) value storage. - mp_map_t *gatts_db; + mp_gatts_db_t gatts_db; // Pending service definitions. size_t n_services;