diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index 96fbbbeab7d5b1201587ea3a6904089ab795a8a9..39cf79daadc761ff3160b4a26c7cc6c0d422b033 100644 --- a/epicardium/epicardium.h +++ b/epicardium/epicardium.h @@ -162,6 +162,13 @@ typedef _Bool bool; #define API_BLE_HID_SEND_REPORT 0x150 +#define API_BLE_ATTS_DYN_CREATE_GROUP 0x160 +#define API_BLE_ATTS_DYN_DELETE_GROUP 0x161 +#define API_BLE_ATTS_DYN_ADD_ATTR_DYN 0x163 +#define API_BLE_ATTS_DYN_ADD_ATTR 0x164 +#define API_BLE_ATTS_SET_ATTR 0x165 +#define API_BLE_ATTS_HANDLE_VALUE_NTF 0x166 +#define API_BLE_ATTS_GET_ATTR 0x167 /* clang-format on */ typedef uint32_t api_int_id_t; @@ -2499,5 +2506,12 @@ API(API_BLE_GET_SCAN_REPORT, int epic_ble_get_scan_report(struct epic_scan_repor */ API(API_BLE_HID_SEND_REPORT, int epic_ble_hid_send_report(uint8_t report_id, uint8_t *data, uint8_t len)); +API(API_BLE_ATTS_DYN_CREATE_GROUP, void *AttsDynCreateGroup(uint16_t startHandle, uint16_t endHandle)); +API(API_BLE_ATTS_DYN_DELETE_GROUP, void AttsDynDeleteGroup(void *pSvcHandle)); +API(API_BLE_ATTS_DYN_ADD_ATTR_DYN, void AttsDynAddAttrDyn(void *pSvcHandle, const uint8_t *pUuid, uint8_t uuidLen, const uint8_t *pValue, uint16_t len, uint16_t maxLen, uint8_t settings, uint8_t permissions)); +API(API_BLE_ATTS_DYN_ADD_ATTR, void AttsDynAddAttr(void *pSvcHandle, const uint8_t *pUuid, const uint8_t *pValue, uint16_t len, uint16_t maxLen, uint8_t settings, uint8_t permissions)); +API(API_BLE_ATTS_SET_ATTR, uint8_t AttsSetAttr(uint16_t handle, uint16_t valueLen, uint8_t *pValue)); +API(API_BLE_ATTS_HANDLE_VALUE_NTF, void AttsHandleValueNtf(uint8_t connId, uint16_t handle, uint16_t valueLen, uint8_t *pValue)); +API(API_BLE_ATTS_GET_ATTR, uint8_t AttsGetAttr(uint16_t handle, uint16_t *pLen, uint8_t **pValue)); #endif /* _EPICARDIUM_H */ diff --git a/lib/sdk/Libraries/BTLE/stack/ble-host/include/att_api.h b/lib/sdk/Libraries/BTLE/stack/ble-host/include/att_api.h index 0138ea019d14c696078fc62a213537e9be38c893..c1c2fd29b108559e8e97e54f8422d59e9cd693e3 100644 --- a/lib/sdk/Libraries/BTLE/stack/ble-host/include/att_api.h +++ b/lib/sdk/Libraries/BTLE/stack/ble-host/include/att_api.h @@ -981,6 +981,10 @@ void AttsDynAddAttr(void *pSvcHandle, const uint8_t *pUuid, const uint8_t *pValu /*************************************************************************************************/ void AttsDynAddAttrConst(void *pSvcHandle, const uint8_t *pUuid, const uint8_t *pValue, const uint16_t len, uint8_t settings, uint8_t permissions); + +void AttsDynAddAttrDyn(void *pSvcHandle, const uint8_t *pUuid, uint8_t uuidLen, const uint8_t *pValue, + uint16_t len, const uint16_t maxLen, uint8_t settings, uint8_t permissions); + /**@}*/ /** \name ATT Server Testing diff --git a/lib/sdk/Libraries/BTLE/stack/ble-host/sources/stack/att/atts_dyn.c b/lib/sdk/Libraries/BTLE/stack/ble-host/sources/stack/att/atts_dyn.c index 30dc989ff0afe0e83a65dcc4f703521c0af4d5d8..0348e2d5de5d43422771fea5a8641d0f8276f27b 100644 --- a/lib/sdk/Libraries/BTLE/stack/ble-host/sources/stack/att/atts_dyn.c +++ b/lib/sdk/Libraries/BTLE/stack/ble-host/sources/stack/att/atts_dyn.c @@ -351,3 +351,73 @@ void AttsDynAddAttrConst(void *pSvcHandle, const uint8_t *pUuid, const uint8_t * AttsAddGroup(&pGroup->group); } } + +void AttsDynAddAttrDyn(void *pSvcHandle, const uint8_t *pUuid, uint8_t uuidLen, const uint8_t *pValue, + uint16_t len, const uint16_t maxLen, uint8_t settings, uint8_t permissions) +{ + attsAttr_t *pAttr; + attsDynGroupCb_t *pGroup = pSvcHandle; + uint16_t handle = pGroup->group.startHandle + pGroup->currentAttr++; + + /* Verify inputs */ + WSF_ASSERT(handle <= pGroup->group.endHandle); + WSF_ASSERT(pUuid); + WSF_ASSERT(len <= maxLen); + + pAttr = pGroup->group.pAttr + (handle - pGroup->group.startHandle); + + + /* Allocate a buffer for the UUID of the attribute */ + pAttr->pUuid = attsDynAlloc(uuidLen); + WSF_ASSERT(pAttr->pUuid); + + if (pAttr->pUuid == NULL) + { + return; + } + + /* Allocate a buffer for the length of the attribute */ + pAttr->pLen = attsDynAlloc(sizeof(uint16_t)); + WSF_ASSERT(pAttr->pLen); + + if (pAttr->pLen == NULL) + { + return; + } + + /* Allocate a buffer for the value of the attribute */ + pAttr->pValue = attsDynAlloc(maxLen); + WSF_ASSERT(pAttr->pValue); + + if (pAttr->pValue == NULL) + { + return; + } + + /* Set the attribute values */ + memcpy(pAttr->pUuid, pUuid, uuidLen); + pAttr->maxLen = maxLen; + pAttr->settings = settings; + pAttr->permissions = permissions; + + + + if (pValue) + { + /* Copy the initial value */ + memcpy(pAttr->pValue, pValue, len); + *pAttr->pLen = len; + } + else + { + /* No initial value, zero value and length */ + memset(pAttr->pValue, 0, maxLen); + *pAttr->pLen = 0; + } + + /* Add the service when the last attribute has been added */ + if (handle == pGroup->group.endHandle) + { + AttsAddGroup(&pGroup->group); + } +} diff --git a/pycardium/modules/modbluetooth_card10.c b/pycardium/modules/modbluetooth_card10.c index c8443e11be9576519a13e353636ff15df39e1fd0..b59b2f192af8039cefc71168cfb34386f80002cc 100644 --- a/pycardium/modules/modbluetooth_card10.c +++ b/pycardium/modules/modbluetooth_card10.c @@ -1,6 +1,7 @@ #include "extmod/modbluetooth.h" #include "py/runtime.h" #include <stdint.h> +#include <string.h> const char *const not_implemented_message = "Not (yet) implemented on card10. See https://git.card10.badge.events.ccc.de/card10/firmware/-/issues/8"; @@ -13,7 +14,6 @@ static void raise(void) // Enables the Bluetooth stack. int mp_bluetooth_init(void) { - raise(); return 0; } @@ -26,13 +26,12 @@ void mp_bluetooth_deinit(void) // Returns true when the Bluetooth stack is enabled. bool mp_bluetooth_is_enabled(void) { - raise(); - return false; + return true; } bool mp_bluetooth_is_active(void) { - return false; + return true; } // Gets the MAC addr of this device in big-endian format. @@ -73,9 +72,50 @@ void mp_bluetooth_gap_advertise_stop(void) // Start adding services. Must be called before mp_bluetooth_register_service. int mp_bluetooth_gatts_register_service_begin(bool append) { - raise(); return 0; } + +#define ATTS_SET_UUID_128 0x01 /*!< \brief Set if the UUID is 128 bits in length */ +#define ATTS_SET_WRITE_CBACK 0x02 /*!< \brief Set if the group callback is executed when + this attribute is written by a client device */ +#define ATTS_SET_READ_CBACK 0x04 /*!< \brief Set if the group callback is executed when + this attribute is read by a client device */ +#define ATTS_SET_VARIABLE_LEN 0x08 /*!< \brief Set if the attribute has a variable length */ +#define ATTS_SET_ALLOW_OFFSET 0x10 /*!< \brief Set if writes are allowed with an offset */ +#define ATTS_SET_CCC 0x20 /*!< \brief Set if the attribute is a client characteristic + configuration descriptor */ +#define ATTS_SET_ALLOW_SIGNED 0x40 /*!< \brief Set if signed writes are allowed */ +#define ATTS_SET_REQ_SIGNED 0x80 /*!< \brief Set if signed writes are required if link + is not encrypted */ + +#define ATTS_PERMIT_READ 0x01 /*!< \brief Set if attribute can be read */ +#define ATTS_PERMIT_READ_AUTH 0x02 /*!< \brief Set if attribute read requires authentication */ +#define ATTS_PERMIT_READ_AUTHORIZ 0x04 /*!< \brief Set if attribute read requires authorization */ +#define ATTS_PERMIT_READ_ENC 0x08 /*!< \brief Set if attribute read requires encryption */ +#define ATTS_PERMIT_WRITE 0x10 /*!< \brief Set if attribute can be written */ +#define ATTS_PERMIT_WRITE_AUTH 0x20 /*!< \brief Set if attribute write requires authentication */ +#define ATTS_PERMIT_WRITE_AUTHORIZ 0x40 /*!< \brief Set if attribute write requires authorization */ +#define ATTS_PERMIT_WRITE_ENC 0x80 /*!< \brief Set if attribute write requires encryption */ + +#define ATT_PROP_BROADCAST 0x01 /*!< \brief Permit broadcasts */ +#define ATT_PROP_READ 0x02 /*!< \brief Permit reads */ +#define ATT_PROP_WRITE_NO_RSP 0x04 /*!< \brief Permit writes without response */ +#define ATT_PROP_WRITE 0x08 /*!< \brief Permit writes with response */ +#define ATT_PROP_NOTIFY 0x10 /*!< \brief Permit notifications */ +#define ATT_PROP_INDICATE 0x20 /*!< \brief Permit indications */ +#define ATT_PROP_AUTHENTICATED 0x40 /*!< \brief Permit signed writes */ +#define ATT_PROP_EXTENDED 0x80 /*!< \brief More properties defined in extended properties */ + +#define ATT_16_UUID_LEN 2 +#define UINT16_TO_BYTES(n) ((uint8_t) (n)), ((uint8_t)((n) >> 8)) +#define ATT_UUID_PRIMARY_SERVICE 0x2800 /*!< \brief Primary Service */ +#define ATT_UUID_CHARACTERISTIC 0x2803 /*!< \brief Characteristic */ +#define ATT_UUID_CLIENT_CHAR_CONFIG 0x2902 /*!< \brief Client Characteristic Configuration */ + +const uint8_t attPrimSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_PRIMARY_SERVICE)}; +const uint8_t attChUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CHARACTERISTIC)}; +const uint8_t attCliChCfgUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(ATT_UUID_CLIENT_CHAR_CONFIG)}; + // // Add a service with the given list of characteristics to the queue to be registered. // The value_handles won't be valid until after mp_bluetooth_register_service_end is called. int mp_bluetooth_gatts_register_service( @@ -88,13 +128,80 @@ int mp_bluetooth_gatts_register_service( uint16_t *handles, size_t num_characteristics ) { - raise(); + void *pSHdl; + + size_t num_descriptors_total = 0; + size_t num_ccds = 0; + for(size_t i=0; i<num_characteristics; i++) { + num_descriptors_total += num_descriptors[i]; + if(characteristic_flags[i] & ATT_PROP_NOTIFY) { + // TODO: Also handle indications + num_ccds++; + } + } + + // One handle for the service, one per characteristic, one per value, one per (CCC) descriptor + // TODO: Need to account for CCCDs + const uint16_t numHandles = 1 + num_characteristics * 2 + num_ccds + num_descriptors_total; + + const uint16_t startHandle = 0x200; + const uint16_t endHandle = startHandle + numHandles - 1; + + pSHdl = AttsDynCreateGroup(startHandle, endHandle); + // TODO NULL check + + /* Primary service */ + uint16_t uuid_len = service_uuid->type == MP_BLUETOOTH_UUID_TYPE_16 ? 2 : 16; + uint16_t currentHandle = startHandle; + AttsDynAddAttr(pSHdl, attPrimSvcUuid, service_uuid->data, uuid_len, uuid_len, 0, ATTS_PERMIT_READ); + + size_t handle_index = 0; + for (size_t i = 0; i < num_characteristics; ++i) { + uint8_t flags = characteristic_flags[i]; + mp_obj_bluetooth_uuid_t *uuid = characteristic_uuids[i]; + uint8_t uuid_len = uuid->type == MP_BLUETOOTH_UUID_TYPE_16 ? 2 : 16; + + + /* Characteristic */ + currentHandle++; + uint8_t characteristic[1 + 2 + 16] = {flags, UINT16_TO_BYTES(currentHandle + 1)}; + memcpy(characteristic + 3, uuid->data, uuid_len); + uint8_t characteristic_len = 1 + 2 + uuid_len; + AttsDynAddAttr(pSHdl, attChUuid, characteristic, characteristic_len, characteristic_len, 0, ATTS_PERMIT_READ); + + /* Value */ + currentHandle++; + uint8_t permissions = 0; + uint8_t settings = ATTS_SET_VARIABLE_LEN; + if(flags & ATT_PROP_READ) { + permissions |= ATTS_PERMIT_READ; + } + if(flags & ATT_PROP_WRITE) { + permissions |= ATTS_PERMIT_WRITE; + } + + AttsDynAddAttrDyn(pSHdl, uuid->data, uuid_len, NULL, 0, MP_BLUETOOTH_DEFAULT_ATTR_LEN, + settings, permissions); + handles[handle_index] = currentHandle; + + if(flags & ATT_PROP_NOTIFY) { + /* CCCD */ + currentHandle++; + //uint8_t initCcc[] = {UINT16_TO_BYTES(0x0000)}; + uint8_t initCcc[] = {UINT16_TO_BYTES(0x0001)}; + AttsDynAddAttr(pSHdl, attCliChCfgUuid, initCcc, sizeof(initCcc), sizeof(initCcc), + //ATTS_SET_READ_CBACK | ATTS_SET_WRITE_CBACK, ATTS_PERMIT_READ | ATTS_PERMIT_WRITE); + 0, ATTS_PERMIT_READ | ATTS_PERMIT_WRITE); + } + + handle_index++; + } + return 0; } // Register any queued services. int mp_bluetooth_gatts_register_service_end() { - raise(); return 0; } @@ -102,15 +209,18 @@ int mp_bluetooth_gatts_register_service_end() int mp_bluetooth_gatts_read( uint16_t value_handle, uint8_t **value, size_t *value_len ) { - raise(); - return 0; + uint16_t pLen; + uint8_t ret = AttsGetAttr(value_handle, &pLen, value); + + *value_len = pLen; + return ret; } // Write a value to the local gatts db (ready to be queried by a central). int mp_bluetooth_gatts_write( uint16_t value_handle, const uint8_t *value, size_t value_len ) { - raise(); - return 0; + uint8_t ret = AttsSetAttr(value_handle, value_len, (uint8_t *)value); + return ret; } // Notify the central that it should do a read. int mp_bluetooth_gatts_notify(uint16_t conn_handle, uint16_t value_handle) @@ -125,7 +235,7 @@ int mp_bluetooth_gatts_notify_send( const uint8_t *value, size_t value_len ) { - raise(); + AttsHandleValueNtf(conn_handle, value_handle, value_len, (uint8_t *)value); return 0; } // Indicate the central.