diff --git a/card10-cross.ini b/card10-cross.ini index ca8d05402ad57e3585656580a40b26748ede7e8d..8ccc99632335e4d8585fd3241c53ee912498250b 100644 --- a/card10-cross.ini +++ b/card10-cross.ini @@ -4,9 +4,9 @@ ar = 'arm-none-eabi-ar' strip = 'arm-none-eabi-strip' [properties] -c_args = ['-mthumb', '-mcpu=cortex-m4', '-mfloat-abi=hard', '-mfpu=fpv4-sp-d16', '-Wa,-mimplicit-it=thumb', '-ffunction-sections', '-fdata-sections', '-fsingle-precision-constant', '-fno-isolate-erroneous-paths-dereference'] +c_args = ['-mthumb', '-mcpu=cortex-m4', '-mfloat-abi=softfp', '-mfpu=fpv4-sp-d16', '-Wa,-mimplicit-it=thumb', '-ffunction-sections', '-fdata-sections', '-fsingle-precision-constant', '-fno-isolate-erroneous-paths-dereference'] -c_link_args = ['-mthumb', '-mcpu=cortex-m4', '-mfloat-abi=hard', '-mfpu=fpv4-sp-d16', '-Wl,--start-group', '-lc', '-lnosys', '-Wl,--end-group', '--specs=nano.specs'] +c_link_args = ['-mthumb', '-mcpu=cortex-m4', '-mfloat-abi=softfp', '-mfpu=fpv4-sp-d16', '-Wl,--start-group', '-lc', '-lnosys', '-Wl,--end-group', '--specs=nano.specs'] target_defs = ['-DTARGET=32665', '-DTARGET_REV=0x4131', '-DBOARD_CARD10=1'] diff --git a/epicardium/ble/app/app_main.c b/epicardium/ble/app/app_main.c new file mode 100644 index 0000000000000000000000000000000000000000..f795c4e7222adfeb7cbe5b19e15f3c1659b7827c --- /dev/null +++ b/epicardium/ble/app/app_main.c @@ -0,0 +1,423 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Application framework main module. + * + * Copyright (c) 2011-2018 Arm Ltd. All Rights Reserved. + * ARM Ltd. confidential and proprietary. + * + * IMPORTANT. Your use of this file is governed by a Software License Agreement + * ("Agreement") that must be accepted in order to download or otherwise receive a + * copy of this file. You may not use or copy this file for any purpose other than + * as described in the Agreement. If you do not agree to all of the terms of the + * Agreement do not use this file and delete all copies in your possession or control; + * if you do not have a copy of the Agreement, you must contact ARM Ltd. prior + * to any use, copying or further distribution of this software. + */ +/*************************************************************************************************/ + +/* card10: + * copied from: lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/apps/app/app_main.c + * + * Reason: we need to correctly implement AppHandleNumericComparison + */ +/* clang-format off */ +/* clang-formet turned off for easier diffing against orginal file */ +#include <string.h> +#include "wsf_types.h" +#include "wsf_msg.h" +#include "sec_api.h" +#include "wsf_trace.h" +#include "wsf_timer.h" +#include "wsf_assert.h" +#include "util/bstream.h" +#include "dm_api.h" +#include "app_api.h" +#include "app_main.h" +#include "app_ui.h" + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +/*! Configuration pointer for advertising */ +appAdvCfg_t *pAppAdvCfg; + +/*! Configuration pointer for extended and periodic advertising */ +appExtAdvCfg_t *pAppExtAdvCfg; + +/*! Configuration pointer for slave */ +appSlaveCfg_t *pAppSlaveCfg; + +/*! Configuration pointer for master */ +appMasterCfg_t *pAppMasterCfg; + +/*! Configuration pointer for extended master */ +appExtMasterCfg_t *pAppExtMasterCfg; + +/*! Configuration pointer for security */ +appSecCfg_t *pAppSecCfg; + +/*! Configuration pointer for connection parameter update */ +appUpdateCfg_t *pAppUpdateCfg; + +/*! Configuration pointer for discovery */ +appDiscCfg_t *pAppDiscCfg; + +/*! Configuration pointer for application */ +appCfg_t *pAppCfg; + +/*! Connection control block array */ +appConnCb_t appConnCb[DM_CONN_MAX]; + +/*! WSF handler ID */ +wsfHandlerId_t appHandlerId; + +/*! Main control block */ +appCb_t appCb; + +/*! Configuration structure for incoming request actions */ +const appReqActCfg_t appReqActCfg = +{ + APP_ACT_ACCEPT /*! Action for the remote connection parameter request */ +}; + +/*! Configuration pointer for incoming request actions on master */ +appReqActCfg_t *pAppMasterReqActCfg = (appReqActCfg_t *) &appReqActCfg; + +/*! Configurable pointer for incoming request actions on slave */ +appReqActCfg_t *pAppSlaveReqActCfg = (appReqActCfg_t *) &appReqActCfg; + +/*************************************************************************************************/ +/*! + * \brief Process messages from the event handler. + * + * \param pMsg Pointer to message. + * + * \return None. + */ +/*************************************************************************************************/ +static void appProcMsg(wsfMsgHdr_t *pMsg) +{ + switch(pMsg->event) + { + case APP_BTN_POLL_IND: + appUiBtnPoll(); + break; + + case APP_UI_TIMER_IND: + appUiTimerExpired(pMsg); + break; + + default: + break; + } +} + +/*************************************************************************************************/ +/*! + * \brief Check the bonded state of a connection. + * + * \param connId DM connection ID. + * + * \return Bonded state. + */ +/*************************************************************************************************/ +bool_t appCheckBonded(dmConnId_t connId) +{ + WSF_ASSERT((connId > 0) && (connId <= DM_CONN_MAX)); + + return appConnCb[connId - 1].bonded; +} + +/*************************************************************************************************/ +/*! + * \brief Check the bond-by-LTK state of a connection. + * + * \param connId DM connection ID. + * + * \return Bond-by-LTK state. + */ +/*************************************************************************************************/ +bool_t appCheckBondByLtk(dmConnId_t connId) +{ + WSF_ASSERT((connId > 0) && (connId <= DM_CONN_MAX)); + + return appConnCb[connId - 1].bondByLtk; +} + +/*************************************************************************************************/ +/*! + * \brief Return the number of existing connections of the given role. + * + * \param role Connection role + * + * \return Number of connections. + */ +/*************************************************************************************************/ +uint8_t appNumConns(uint8_t role) +{ + appConnCb_t *pCcb = appConnCb; + uint8_t i, j; + + for (i = DM_CONN_MAX, j = 0; i > 0; i--, pCcb++) + { + if ((pCcb->connId != DM_CONN_ID_NONE) && (DmConnRole(pCcb->connId) == role)) + { + j++; + } + } + + return j; +} + +/*************************************************************************************************/ +/*! + * \brief App framework handler init function called during system initialization. + * + * \param handlerID WSF handler ID for App. + * + * \return None. + */ +/*************************************************************************************************/ +void AppInit(void) +{ + appHandlerId = WsfOsSetNextHandler(AppHandler); + + AppDbInit(); +} + +/*************************************************************************************************/ +/*! + * \brief WSF event handler for app framework. + * + * \param event WSF event mask. + * \param pMsg WSF message. + * + * \return None. + */ +/*************************************************************************************************/ +void AppHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg) +{ + if (pMsg != NULL) + { + APP_TRACE_INFO1("App got evt %d", pMsg->event); + + if (pMsg->event >= APP_MASTER_MSG_START) + { + /* pass event to master handler */ + (*appCb.masterCback)(pMsg); + } + else if (pMsg->event >= APP_SLAVE_MSG_START) + { + /* pass event to slave handler */ + (*appCb.slaveCback)(pMsg); + } + else + { + appProcMsg(pMsg); + } + } + else + { + if (event & APP_BTN_DOWN_EVT) + { + AppUiBtnPressed(); + } + } +} + +/*************************************************************************************************/ +/*! + * \brief Handle a passkey request during pairing. If the passkey is to displayed, a + * random passkey is generated and displayed. If the passkey is to be entered + * the user is prompted to enter the passkey. + * + * \param pAuthReq DM authentication requested event structure. + * + * \return None. + */ +/*************************************************************************************************/ +void AppHandlePasskey(dmSecAuthReqIndEvt_t *pAuthReq) +{ + uint32_t passkey; + uint8_t buf[SMP_PIN_LEN]; + + if (pAuthReq->display) + { + /* generate random passkey, limit to 6 digit max */ + SecRand((uint8_t *) &passkey, sizeof(uint32_t)); + passkey %= 1000000; + + /* convert to byte buffer */ + buf[0] = UINT32_TO_BYTE0(passkey); + buf[1] = UINT32_TO_BYTE1(passkey); + buf[2] = UINT32_TO_BYTE2(passkey); + + /* send authentication response to DM */ + DmSecAuthRsp((dmConnId_t) pAuthReq->hdr.param, SMP_PIN_LEN, buf); + + /* display passkey */ + AppUiDisplayPasskey(passkey); + } + else + { + /* prompt user to enter passkey */ + AppUiAction(APP_UI_PASSKEY_PROMPT); + } +} + +/*************************************************************************************************/ +/*! +* \brief Handle a numeric comparison indication during pairing. The confirmation value is +* displayed and the user is prompted to verify that the local and peer confirmation +* values match. +* +* \param pCnfInd DM confirmation indication event structure. +* +* \return None. +*/ +/*************************************************************************************************/ +void AppHandleNumericComparison(dmSecCnfIndEvt_t *pCnfInd) +{ + uint32_t confirm = DmSecGetCompareValue(pCnfInd->confirm); + + /* display confirmation value */ + AppUiDisplayConfirmValue(confirm); + + /* TODO: Verify that local and peer confirmation values match */ + DmSecCompareRsp((dmConnId_t)pCnfInd->hdr.param, TRUE); +} + +/*************************************************************************************************/ +/*! + * \brief Close the connection with the give connection identifier. + * + * \param connId Connection identifier. + * + * \return None. + */ +/*************************************************************************************************/ +void AppConnClose(dmConnId_t connId) +{ + DmConnClose(DM_CLIENT_ID_APP, connId, HCI_ERR_REMOTE_TERMINATED); +} + +/*************************************************************************************************/ +/*! + * \brief Get a list of connection identifiers of open connections. + * + * \param pConnIdList Buffer to hold connection IDs (must be DM_CONN_MAX bytes). + * + * \return Number of open connections. + * + */ +/*************************************************************************************************/ +uint8_t AppConnOpenList(dmConnId_t *pConnIdList) +{ + appConnCb_t *pCcb = appConnCb; + uint8_t i; + uint8_t pos = 0; + + memset(pConnIdList, DM_CONN_ID_NONE, DM_CONN_MAX); + + for (i = DM_CONN_MAX; i > 0; i--, pCcb++) + { + if (pCcb->connId != DM_CONN_ID_NONE) + { + pConnIdList[pos++] = pCcb->connId; + } + } + + return pos; +} + +/*************************************************************************************************/ +/*! + * \brief Check if a connection is open. + * + * \return Connection ID of open connection or DM_CONN_ID_NONE if no open connections. + */ +/*************************************************************************************************/ +dmConnId_t AppConnIsOpen(void) +{ + appConnCb_t *pCcb = appConnCb; + uint8_t i; + + for (i = DM_CONN_MAX; i > 0; i--, pCcb++) + { + if (pCcb->connId != DM_CONN_ID_NONE) + { + return pCcb->connId; + } + } + + return DM_CONN_ID_NONE; +} + +/*************************************************************************************************/ +/*! + * \brief Get the device database record handle associated with an open connection. + * + * \param connId Connection identifier. + * + * \return Database record handle or APP_DB_HDL_NONE. + */ +/*************************************************************************************************/ +appDbHdl_t AppDbGetHdl(dmConnId_t connId) +{ + return appConnCb[connId-1].dbHdl; +} + +/*************************************************************************************************/ +/*! + * \brief Add device to resolving list. + * + * \param pMsg Pointer to DM callback event message. + * \param connId Connection identifier. + * + * \return None. + */ +/*************************************************************************************************/ +void AppAddDevToResList(dmEvt_t *pMsg, dmConnId_t connId) +{ + dmSecKey_t *pPeerKey; + appDbHdl_t hdl = appConnCb[connId - 1].dbHdl; + + /* if LL Privacy is supported and the peer device has distributed its IRK */ + if (HciLlPrivacySupported() && ((pPeerKey = AppDbGetKey(hdl, DM_KEY_IRK, NULL))!= NULL)) + { + /* add peer device to resolving list. If all-zero local or peer IRK is used then + LL will only use or accept local or peer identity address respectively. */ + DmPrivAddDevToResList(pPeerKey->irk.addrType, pPeerKey->irk.bdAddr, pPeerKey->irk.key, + DmSecGetLocalIrk(), TRUE, pMsg->hdr.param); + } +} + +/*************************************************************************************************/ +/*! + * \brief Update privacy mode for a given peer device. + * + * \param hdl Database record handle. + * + * \return None. + */ +/*************************************************************************************************/ +void AppUpdatePrivacyMode(appDbHdl_t hdl) +{ + /* if peer device's been added to resolving list but RPA Only attribute not found on peer device */ + if ((hdl != APP_DB_HDL_NONE) && AppDbGetPeerAddedToRl(hdl) && !AppDbGetPeerRpao(hdl)) + { + dmSecKey_t *pPeerKey = AppDbGetKey(hdl, DM_KEY_IRK, NULL); + if (pPeerKey != NULL) + { + /* set device privacy mode for this peer device */ + DmPrivSetPrivacyMode(pPeerKey->irk.addrType, pPeerKey->irk.bdAddr, DM_PRIV_MODE_DEVICE); + + /* make sure resolving list flag cleared */ + AppDbSetPeerAddedToRl(hdl, FALSE); + } + } +} +/* clang-format on */ diff --git a/epicardium/ble/app/common/app_db.c b/epicardium/ble/app/common/app_db.c new file mode 100644 index 0000000000000000000000000000000000000000..e4428f50751fd4407b3397c7111381314fd5ff45 --- /dev/null +++ b/epicardium/ble/app/common/app_db.c @@ -0,0 +1,713 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Application framework device database example, using simple RAM-based storage. + * + * Copyright (c) 2011-2018 Arm Ltd. All Rights Reserved. + * ARM Ltd. confidential and proprietary. + * + * IMPORTANT. Your use of this file is governed by a Software License Agreement + * ("Agreement") that must be accepted in order to download or otherwise receive a + * copy of this file. You may not use or copy this file for any purpose other than + * as described in the Agreement. If you do not agree to all of the terms of the + * Agreement do not use this file and delete all copies in your possession or control; + * if you do not have a copy of the Agreement, you must contact ARM Ltd. prior + * to any use, copying or further distribution of this software. + */ +/*************************************************************************************************/ + +/* card10: + * copied from: lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/apps/app/common/app_db.c + * + * Reason: we need to implement persistent storage for pairings + */ +/* clang-format off */ +/* clang-formet turned off for easier diffing against orginal file */ +#include <string.h> +#include "wsf_types.h" +#include "wsf_assert.h" +#include "util/bda.h" +#include "app_api.h" +#include "app_main.h" +#include "app_db.h" +#include "app_cfg.h" + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! Database record */ +typedef struct +{ + /*! Common for all roles */ + bdAddr_t peerAddr; /*! Peer address */ + uint8_t addrType; /*! Peer address type */ + dmSecIrk_t peerIrk; /*! Peer IRK */ + dmSecCsrk_t peerCsrk; /*! Peer CSRK */ + uint8_t keyValidMask; /*! Valid keys in this record */ + bool_t inUse; /*! TRUE if record in use */ + bool_t valid; /*! TRUE if record is valid */ + bool_t peerAddedToRl; /*! TRUE if peer device's been added to resolving list */ + bool_t peerRpao; /*! TRUE if RPA Only attribute's present on peer device */ + + /*! For slave local device */ + dmSecLtk_t localLtk; /*! Local LTK */ + uint8_t localLtkSecLevel; /*! Local LTK security level */ + bool_t peerAddrRes; /*! TRUE if address resolution's supported on peer device (master) */ + + /*! For master local device */ + dmSecLtk_t peerLtk; /*! Peer LTK */ + uint8_t peerLtkSecLevel; /*! Peer LTK security level */ + + /*! for ATT server local device */ + uint16_t cccTbl[APP_DB_NUM_CCCD]; /*! Client characteristic configuration descriptors */ + uint32_t peerSignCounter; /*! Peer Sign Counter */ + + /*! for ATT client */ + uint16_t hdlList[APP_DB_HDL_LIST_LEN]; /*! Cached handle list */ + uint8_t discStatus; /*! Service discovery and configuration status */ +} appDbRec_t; + +/*! Database type */ +typedef struct +{ + appDbRec_t rec[APP_DB_NUM_RECS]; /*! Device database records */ + char devName[ATT_DEFAULT_PAYLOAD_LEN]; /*! Device name */ + uint8_t devNameLen; /*! Device name length */ +} appDb_t; + +/************************************************************************************************** + Local Variables +**************************************************************************************************/ + +/*! Database */ +static appDb_t appDb; + +/*! When all records are allocated use this index to determine which to overwrite */ +static appDbRec_t *pAppDbNewRec = appDb.rec; + +/*************************************************************************************************/ +/*! + * \brief Initialize the device database. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbInit(void) +{ + return; +} + +/*************************************************************************************************/ +/*! + * \brief Create a new device database record. + * + * \param addrType Address type. + * \param pAddr Peer device address. + * + * \return Database record handle. + */ +/*************************************************************************************************/ +appDbHdl_t AppDbNewRecord(uint8_t addrType, uint8_t *pAddr) +{ + appDbRec_t *pRec = appDb.rec; + uint8_t i; + + /* find a free record */ + for (i = APP_DB_NUM_RECS; i > 0; i--, pRec++) + { + if (!pRec->inUse) + { + break; + } + } + + /* if all records were allocated */ + if (i == 0) + { + /* overwrite a record */ + pRec = pAppDbNewRec; + + /* get next record to overwrite */ + pAppDbNewRec++; + if (pAppDbNewRec == &appDb.rec[APP_DB_NUM_RECS]) + { + pAppDbNewRec = appDb.rec; + } + } + + /* initialize record */ + memset(pRec, 0, sizeof(appDbRec_t)); + pRec->inUse = TRUE; + pRec->addrType = addrType; + BdaCpy(pRec->peerAddr, pAddr); + pRec->peerAddedToRl = FALSE; + pRec->peerRpao = FALSE; + + return (appDbHdl_t) pRec; +} + +/*************************************************************************************************/ +/*! +* \brief Get the next database record for a given record. For the first record, the function +* should be called with 'hdl' set to 'APP_DB_HDL_NONE'. +* +* \param hdl Database record handle. +* +* \return Next record handle found. APP_DB_HDL_NONE, otherwise. +*/ +/*************************************************************************************************/ +appDbHdl_t AppDbGetNextRecord(appDbHdl_t hdl) +{ + appDbRec_t *pRec; + + /* if first record is requested */ + if (hdl == APP_DB_HDL_NONE) + { + pRec = appDb.rec; + } + /* if valid record passed in */ + else if (AppDbRecordInUse(hdl)) + { + pRec = (appDbRec_t *)hdl; + pRec++; + } + /* invalid record passed in */ + else + { + return APP_DB_HDL_NONE; + } + + /* look for next valid record */ + while (pRec < &appDb.rec[APP_DB_NUM_RECS]) + { + /* if record is in use */ + if (pRec->inUse && pRec->valid) + { + /* record found */ + return (appDbHdl_t)pRec; + } + + /* look for next record */ + pRec++; + } + + /* end of records */ + return APP_DB_HDL_NONE; +} + +/*************************************************************************************************/ +/*! + * \brief Delete a new device database record. + * + * \param hdl Database record handle. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbDeleteRecord(appDbHdl_t hdl) +{ + ((appDbRec_t *) hdl)->inUse = FALSE; +} + +/*************************************************************************************************/ +/*! + * \brief Validate a new device database record. This function is called when pairing is + * successful and the devices are bonded. + * + * \param hdl Database record handle. + * \param keyMask Bitmask of keys to validate. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbValidateRecord(appDbHdl_t hdl, uint8_t keyMask) +{ + ((appDbRec_t *) hdl)->valid = TRUE; + ((appDbRec_t *) hdl)->keyValidMask = keyMask; +} + +/*************************************************************************************************/ +/*! + * \brief Check if a record has been validated. If it has not, delete it. This function + * is typically called when the connection is closed. + * + * \param hdl Database record handle. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbCheckValidRecord(appDbHdl_t hdl) +{ + if (((appDbRec_t *) hdl)->valid == FALSE) + { + AppDbDeleteRecord(hdl); + } +} + +/*************************************************************************************************/ +/*! +* \brief Check if a database record is in use. + +* \param hdl Database record handle. +* +* \return TURE if record in use. FALSE, otherwise. +*/ +/*************************************************************************************************/ +bool_t AppDbRecordInUse(appDbHdl_t hdl) +{ + appDbRec_t *pRec = appDb.rec; + uint8_t i; + + /* see if record is in database record list */ + for (i = APP_DB_NUM_RECS; i > 0; i--, pRec++) + { + if (pRec->inUse && pRec->valid && (pRec == ((appDbRec_t *)hdl))) + { + return TRUE; + } + } + + return FALSE; +} + +/*************************************************************************************************/ +/*! + * \brief Check if there is a stored bond with any device. + * + * \param hdl Database record handle. + * + * \return TRUE if a bonded device is found, FALSE otherwise. + */ +/*************************************************************************************************/ +bool_t AppDbCheckBonded(void) +{ + appDbRec_t *pRec = appDb.rec; + uint8_t i; + + /* find a record */ + for (i = APP_DB_NUM_RECS; i > 0; i--, pRec++) + { + if (pRec->inUse) + { + return TRUE; + } + } + + return FALSE; +} + +/*************************************************************************************************/ +/*! + * \brief Delete all database records. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbDeleteAllRecords(void) +{ + appDbRec_t *pRec = appDb.rec; + uint8_t i; + + /* set in use to false for all records */ + for (i = APP_DB_NUM_RECS; i > 0; i--, pRec++) + { + pRec->inUse = FALSE; + } +} + +/*************************************************************************************************/ +/*! + * \brief Find a device database record by peer address. + * + * \param addrType Address type. + * \param pAddr Peer device address. + * + * \return Database record handle or APP_DB_HDL_NONE if not found. + */ +/*************************************************************************************************/ +appDbHdl_t AppDbFindByAddr(uint8_t addrType, uint8_t *pAddr) +{ + appDbRec_t *pRec = appDb.rec; + uint8_t peerAddrType = DmHostAddrType(addrType); + uint8_t i; + + /* find matching record */ + for (i = APP_DB_NUM_RECS; i > 0; i--, pRec++) + { + if (pRec->inUse && (pRec->addrType == peerAddrType) && BdaCmp(pRec->peerAddr, pAddr)) + { + return (appDbHdl_t) pRec; + } + } + + return APP_DB_HDL_NONE; +} + +/*************************************************************************************************/ +/*! + * \brief Find a device database record by data in an LTK request. + * + * \param encDiversifier Encryption diversifier associated with key. + * \param pRandNum Pointer to random number associated with key. + * + * \return Database record handle or APP_DB_HDL_NONE if not found. + */ +/*************************************************************************************************/ +appDbHdl_t AppDbFindByLtkReq(uint16_t encDiversifier, uint8_t *pRandNum) +{ + appDbRec_t *pRec = appDb.rec; + uint8_t i; + + /* find matching record */ + for (i = APP_DB_NUM_RECS; i > 0; i--, pRec++) + { + if (pRec->inUse && (pRec->localLtk.ediv == encDiversifier) && + (memcmp(pRec->localLtk.rand, pRandNum, SMP_RAND8_LEN) == 0)) + { + return (appDbHdl_t) pRec; + } + } + + return APP_DB_HDL_NONE; +} + +/*************************************************************************************************/ +/*! + * \brief Get a key from a device database record. + * + * \param hdl Database record handle. + * \param type Type of key to get. + * \param pSecLevel If the key is valid, the security level of the key. + * + * \return Pointer to key if key is valid or NULL if not valid. + */ +/*************************************************************************************************/ +dmSecKey_t *AppDbGetKey(appDbHdl_t hdl, uint8_t type, uint8_t *pSecLevel) +{ + dmSecKey_t *pKey = NULL; + + /* if key valid */ + if ((type & ((appDbRec_t *) hdl)->keyValidMask) != 0) + { + switch(type) + { + case DM_KEY_LOCAL_LTK: + *pSecLevel = ((appDbRec_t *) hdl)->localLtkSecLevel; + pKey = (dmSecKey_t *) &((appDbRec_t *) hdl)->localLtk; + break; + + case DM_KEY_PEER_LTK: + *pSecLevel = ((appDbRec_t *) hdl)->peerLtkSecLevel; + pKey = (dmSecKey_t *) &((appDbRec_t *) hdl)->peerLtk; + break; + + case DM_KEY_IRK: + pKey = (dmSecKey_t *)&((appDbRec_t *)hdl)->peerIrk; + break; + + case DM_KEY_CSRK: + pKey = (dmSecKey_t *)&((appDbRec_t *)hdl)->peerCsrk; + break; + + default: + break; + } + } + + return pKey; +} + +/*************************************************************************************************/ +/*! + * \brief Set a key in a device database record. + * + * \param hdl Database record handle. + * \param pKey Key data. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbSetKey(appDbHdl_t hdl, dmSecKeyIndEvt_t *pKey) +{ + switch(pKey->type) + { + case DM_KEY_LOCAL_LTK: + ((appDbRec_t *) hdl)->localLtkSecLevel = pKey->secLevel; + ((appDbRec_t *) hdl)->localLtk = pKey->keyData.ltk; + break; + + case DM_KEY_PEER_LTK: + ((appDbRec_t *) hdl)->peerLtkSecLevel = pKey->secLevel; + ((appDbRec_t *) hdl)->peerLtk = pKey->keyData.ltk; + break; + + case DM_KEY_IRK: + ((appDbRec_t *)hdl)->peerIrk = pKey->keyData.irk; + + /* make sure peer record is stored using its identity address */ + ((appDbRec_t *)hdl)->addrType = pKey->keyData.irk.addrType; + BdaCpy(((appDbRec_t *)hdl)->peerAddr, pKey->keyData.irk.bdAddr); + break; + + case DM_KEY_CSRK: + ((appDbRec_t *)hdl)->peerCsrk = pKey->keyData.csrk; + + /* sign counter must be initialized to zero when CSRK is generated */ + ((appDbRec_t *)hdl)->peerSignCounter = 0; + break; + + default: + break; + } +} + +/*************************************************************************************************/ +/*! + * \brief Get the client characteristic configuration descriptor table. + * + * \param hdl Database record handle. + * + * \return Pointer to client characteristic configuration descriptor table. + */ +/*************************************************************************************************/ +uint16_t *AppDbGetCccTbl(appDbHdl_t hdl) +{ + return ((appDbRec_t *) hdl)->cccTbl; +} + +/*************************************************************************************************/ +/*! + * \brief Set a value in the client characteristic configuration table. + * + * \param hdl Database record handle. + * \param idx Table index. + * \param value client characteristic configuration value. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbSetCccTblValue(appDbHdl_t hdl, uint16_t idx, uint16_t value) +{ + WSF_ASSERT(idx < APP_DB_NUM_CCCD); + + ((appDbRec_t *) hdl)->cccTbl[idx] = value; +} + +/*************************************************************************************************/ +/*! + * \brief Get the discovery status. + * + * \param hdl Database record handle. + * + * \return Discovery status. + */ +/*************************************************************************************************/ +uint8_t AppDbGetDiscStatus(appDbHdl_t hdl) +{ + return ((appDbRec_t *) hdl)->discStatus; +} + +/*************************************************************************************************/ +/*! + * \brief Set the discovery status. + * + * \param hdl Database record handle. + * \param state Discovery status. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbSetDiscStatus(appDbHdl_t hdl, uint8_t status) +{ + ((appDbRec_t *) hdl)->discStatus = status; +} + +/*************************************************************************************************/ +/*! + * \brief Get the cached handle list. + * + * \param hdl Database record handle. + * + * \return Pointer to handle list. + */ +/*************************************************************************************************/ +uint16_t *AppDbGetHdlList(appDbHdl_t hdl) +{ + return ((appDbRec_t *) hdl)->hdlList; +} + +/*************************************************************************************************/ +/*! + * \brief Set the cached handle list. + * + * \param hdl Database record handle. + * \param pHdlList Pointer to handle list. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbSetHdlList(appDbHdl_t hdl, uint16_t *pHdlList) +{ + memcpy(((appDbRec_t *) hdl)->hdlList, pHdlList, sizeof(((appDbRec_t *) hdl)->hdlList)); +} + +/*************************************************************************************************/ +/*! + * \brief Get the device name. + * + * \param pLen Returned device name length. + * + * \return Pointer to UTF-8 string containing device name or NULL if not set. + */ +/*************************************************************************************************/ +char *AppDbGetDevName(uint8_t *pLen) +{ + /* if first character of name is NULL assume it is uninitialized */ + if (appDb.devName[0] == 0) + { + *pLen = 0; + return NULL; + } + else + { + *pLen = appDb.devNameLen; + return appDb.devName; + } +} + +/*************************************************************************************************/ +/*! + * \brief Set the device name. + * + * \param len Device name length. + * \param pStr UTF-8 string containing device name. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbSetDevName(uint8_t len, char *pStr) +{ + /* check for maximum device length */ + len = (len <= sizeof(appDb.devName)) ? len : sizeof(appDb.devName); + + memcpy(appDb.devName, pStr, len); +} + +/*************************************************************************************************/ +/*! + * \brief Get address resolution attribute value read from a peer device. + * + * \param hdl Database record handle. + * + * \return TRUE if address resolution is supported in peer device. FALSE, otherwise. + */ +/*************************************************************************************************/ +bool_t AppDbGetPeerAddrRes(appDbHdl_t hdl) +{ + return ((appDbRec_t *)hdl)->peerAddrRes; +} + +/*************************************************************************************************/ +/*! + * \brief Set address resolution attribute value for a peer device. + * + * \param hdl Database record handle. + * \param addrRes Address resolution attribue value. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbSetPeerAddrRes(appDbHdl_t hdl, uint8_t addrRes) +{ + ((appDbRec_t *)hdl)->peerAddrRes = addrRes; +} + +/*************************************************************************************************/ +/*! + * \brief Get sign counter for a peer device. + * + * \param hdl Database record handle. + * + * \return Sign counter for peer device. + */ +/*************************************************************************************************/ +uint32_t AppDbGetPeerSignCounter(appDbHdl_t hdl) +{ + return ((appDbRec_t *)hdl)->peerSignCounter; +} + +/*************************************************************************************************/ +/*! + * \brief Set sign counter for a peer device. + * + * \param hdl Database record handle. + * \param signCounter Sign counter for peer device. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbSetPeerSignCounter(appDbHdl_t hdl, uint32_t signCounter) +{ + ((appDbRec_t *)hdl)->peerSignCounter = signCounter; +} + +/*************************************************************************************************/ +/*! + * \brief Get the peer device added to resolving list flag value. + * + * \param hdl Database record handle. + * + * \return TRUE if peer device's been added to resolving list. FALSE, otherwise. + */ +/*************************************************************************************************/ +bool_t AppDbGetPeerAddedToRl(appDbHdl_t hdl) +{ + return ((appDbRec_t *)hdl)->peerAddedToRl; +} + +/*************************************************************************************************/ +/*! + * \brief Set the peer device added to resolving list flag to a given value. + * + * \param hdl Database record handle. + * \param peerAddedToRl Peer device added to resolving list flag value. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbSetPeerAddedToRl(appDbHdl_t hdl, bool_t peerAddedToRl) +{ + ((appDbRec_t *)hdl)->peerAddedToRl = peerAddedToRl; +} + +/*************************************************************************************************/ +/*! + * \brief Get the resolvable private address only attribute flag for a given peer device. + * + * \param hdl Database record handle. + * + * \return TRUE if RPA Only attribute is present on peer device. FALSE, otherwise. + */ +/*************************************************************************************************/ +bool_t AppDbGetPeerRpao(appDbHdl_t hdl) +{ + return ((appDbRec_t *)hdl)->peerRpao; +} + +/*************************************************************************************************/ +/*! + * \brief Set the resolvable private address only attribute flag for a given peer device. + * + * \param hdl Database record handle. + * \param peerRpao Resolvable private address only attribute flag value. + * + * \return None. + */ +/*************************************************************************************************/ +void AppDbSetPeerRpao(appDbHdl_t hdl, bool_t peerRpao) +{ + ((appDbRec_t *)hdl)->peerRpao = peerRpao; +} +/* clang-format on */ diff --git a/epicardium/ble/app/common/app_ui.c b/epicardium/ble/app/common/app_ui.c new file mode 100644 index 0000000000000000000000000000000000000000..089e9dbbe615dc3787fec1a03712985b91537050 --- /dev/null +++ b/epicardium/ble/app/common/app_ui.c @@ -0,0 +1,335 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Application framework user interface. + * + * Copyright (c) 2011-2018 Arm Ltd. All Rights Reserved. + * ARM Ltd. confidential and proprietary. + * + * IMPORTANT. Your use of this file is governed by a Software License Agreement + * ("Agreement") that must be accepted in order to download or otherwise receive a + * copy of this file. You may not use or copy this file for any purpose other than + * as described in the Agreement. If you do not agree to all of the terms of the + * Agreement do not use this file and delete all copies in your possession or control; + * if you do not have a copy of the Agreement, you must contact ARM Ltd. prior + * to any use, copying or further distribution of this software. + */ +/*************************************************************************************************/ + +#include "wsf_types.h" +#include "wsf_os.h" +#include "wsf_trace.h" +#include "app_ui.h" + +/* card10: + * copied from: lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/apps/app/common/app_ui.c + * + * Reason: has several user interactions which we likley have to implement + */ + +/* clang-format off */ +/* clang-formet turned off for easier diffing against orginal file */ +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +/*! \brief Callback struct */ +appUiCback_t appUiCbackTbl; + +/*************************************************************************************************/ +/*! + * \brief Perform a user interface action based on the event value passed to the function. + * + * \param event User interface event value. + * + * \return None. + */ +/*************************************************************************************************/ +void AppUiAction(uint8_t event) +{ + switch (event) + { + case APP_UI_NONE: + /* no action */ + break; + + case APP_UI_RESET_CMPL: + APP_TRACE_INFO0(">>> Reset complete <<<"); + break; + + case APP_UI_ADV_START: + APP_TRACE_INFO0(">>> Advertising started <<<"); + break; + + case APP_UI_ADV_STOP: + APP_TRACE_INFO0(">>> Advertising stopped <<<"); + break; + + case APP_UI_SCAN_START: + APP_TRACE_INFO0(">>> Scanning started <<<"); + break; + + case APP_UI_SCAN_STOP: + APP_TRACE_INFO0(">>> Scanning stopped <<<"); + break; + + case APP_UI_SCAN_REPORT: + APP_TRACE_INFO0(">>> Scan data received from peer <<<"); + break; + + case APP_UI_CONN_OPEN: + APP_TRACE_INFO0(">>> Connection opened <<<"); + break; + + case APP_UI_CONN_CLOSE: + APP_TRACE_INFO0(">>> Connection closed <<<"); + break; + + case APP_UI_SEC_PAIR_CMPL: + APP_TRACE_INFO0(">>> Pairing completed successfully <<<"); + break; + + case APP_UI_SEC_PAIR_FAIL: + APP_TRACE_INFO0(">>> Pairing failed <<<"); + break; + + case APP_UI_SEC_ENCRYPT: + APP_TRACE_INFO0(">>> Connection encrypted <<<"); + break; + + case APP_UI_SEC_ENCRYPT_FAIL: + APP_TRACE_INFO0(">>> Encryption failed <<<"); + break; + + case APP_UI_PASSKEY_PROMPT: + APP_TRACE_INFO0(">>> Prompt user to enter passkey <<<"); + break; + + case APP_UI_ALERT_CANCEL: + APP_TRACE_INFO0(">>> Cancel a low or high alert <<<"); + break; + + case APP_UI_ALERT_LOW: + APP_TRACE_INFO0(">>> Low alert <<<"); + break; + + case APP_UI_ALERT_HIGH: + APP_TRACE_INFO0(">>> High alert <<<"); + break; + + case APP_UI_ADV_SET_START_IND: + APP_TRACE_INFO0(">>> Advertising set(s) started <<<"); + break; + + case APP_UI_ADV_SET_STOP_IND: + APP_TRACE_INFO0(">>> Advertising set(s) stopped <<<"); + break; + + case APP_UI_SCAN_REQ_RCVD_IND: + APP_TRACE_INFO0(">>> Scan request received <<<"); + break; + + case APP_UI_EXT_SCAN_START_IND: + APP_TRACE_INFO0(">>> Extended scanning started <<<"); + break; + + case APP_UI_EXT_SCAN_STOP_IND: + APP_TRACE_INFO0(">>> Extended scanning stopped <<<"); + break; + + case APP_UI_PER_ADV_SET_START_IND: + APP_TRACE_INFO0(">>> Periodic advertising set started <<<"); + break; + + case APP_UI_PER_ADV_SET_STOP_IND: + APP_TRACE_INFO0(">>> Periodic advertising set stopped <<<"); + break; + + case APP_UI_PER_ADV_SYNC_EST_IND: + APP_TRACE_INFO0(">>> Periodic advertising sync established <<<"); + break; + + case APP_UI_PER_ADV_SYNC_LOST_IND: + APP_TRACE_INFO0(">>> Periodic advertising sync lost <<<"); + break; + + default: + break; + } + + if (appUiCbackTbl.actionCback) + { + (*appUiCbackTbl.actionCback)(event); + } +} + +/*************************************************************************************************/ +/*! + * \brief Display a passkey. + * + * \param passkey Passkey to display. + * + * \return None. + */ +/*************************************************************************************************/ +void AppUiDisplayPasskey(uint32_t passkey) +{ + APP_TRACE_INFO1(">>> Passkey: %d <<<", passkey); +} + +/*************************************************************************************************/ +/*! +* \brief Display a confirmation value. +* +* \param confirm Confirm value to display. +* +* \return None. +*/ +/*************************************************************************************************/ +void AppUiDisplayConfirmValue(uint32_t confirm) +{ + APP_TRACE_INFO1(">>> Confirm Value: %d <<<", confirm); +} + +/*************************************************************************************************/ +/*! + * \brief Display an RSSI value. + * + * \param rssi Rssi value to display. + * + * \return None. + */ +/*************************************************************************************************/ +void AppUiDisplayRssi(int8_t rssi) +{ + APP_TRACE_INFO1(">>> RSSI: %d dBm<<<", rssi); +} + +/*************************************************************************************************/ +/*! + * \brief Handle a UI timer expiration event. + * + * \param pMsg Pointer to message. + * + * \return None. + */ +/*************************************************************************************************/ +void appUiTimerExpired(wsfMsgHdr_t *pMsg) +{ + +} + +/*************************************************************************************************/ +/*! + * \brief Perform button press polling. This function is called to handle WSF + * message APP_BTN_POLL_IND. + * + * \return None. + */ +/*************************************************************************************************/ +void appUiBtnPoll(void) +{ + if (appUiCbackTbl.btnPollCback) + { + (*appUiCbackTbl.btnPollCback)(); + } +} + +/*************************************************************************************************/ +/*! + * \brief Handle a hardware button press. This function is called to handle WSF + * event APP_BTN_DOWN_EVT. + * + * \return None. + */ +/*************************************************************************************************/ +void AppUiBtnPressed(void) +{ + +} + +/*************************************************************************************************/ +/*! + * \brief Register a callback function to receive application button press events. + * + * \return None. + * + * \note Registered by application to receive button events + */ +/*************************************************************************************************/ +void AppUiBtnRegister(appUiBtnCback_t btnCback) +{ + appUiCbackTbl.btnCback = btnCback; +} + +/*************************************************************************************************/ +/*! + * \brief Register a callback function to receive action events. + * + * \return None. + * + * \note Registered by platform + */ +/*************************************************************************************************/ +void AppUiActionRegister(appUiActionCback_t actionCback) +{ + appUiCbackTbl.actionCback = actionCback; +} + +/*************************************************************************************************/ +/*! + * \brief Register a callback function to receive APP_BTN_POLL_IND events. + * + * \return None. + * + * \note Registered by platform + */ +/*************************************************************************************************/ +void AppUiBtnPollRegister(appUiBtnPollCback_t btnPollCback) +{ + appUiCbackTbl.btnPollCback = btnPollCback; +} + +/*************************************************************************************************/ +/*! + * \brief Play a sound. + * + * \param pSound Pointer to sound tone/duration array. + * + * \return None. + */ +/*************************************************************************************************/ +void AppUiSoundPlay(const appUiSound_t *pSound) +{ + +} + +/*************************************************************************************************/ +/*! + * \brief Stop the sound that is currently playing. + * + * \return None. + */ +/*************************************************************************************************/ +void AppUiSoundStop(void) +{ + +} + +/*************************************************************************************************/ +/*! + * \brief Button test function-- for test purposes only. + * + * \return None. + */ +/*************************************************************************************************/ +void AppUiBtnTest(uint8_t btn) +{ + if (appUiCbackTbl.btnCback) + { + (*appUiCbackTbl.btnCback)(btn); + } +} + +/* clang-format on */ diff --git a/epicardium/ble/ble.c b/epicardium/ble/ble.c new file mode 100644 index 0000000000000000000000000000000000000000..9a2da1942627e02ca57bbdf518464c59ec3e37b4 --- /dev/null +++ b/epicardium/ble/ble.c @@ -0,0 +1,210 @@ +#include "modules/log.h" + +#include "fs_util.h" + +#include "wsf_types.h" +#include "wsf_buf.h" +#include "wsf_trace.h" +#include "ble_api.h" +#include "hci_vs.h" +#include "att_api.h" + +#include "FreeRTOS.h" +#include "timers.h" + +#include <stdio.h> +#include <string.h> +#include <stdbool.h> + +#define WSF_BUF_POOLS 6 +#define WSF_BUF_SIZE 0x1048 + +uint32_t SystemHeapSize = WSF_BUF_SIZE; +uint32_t SystemHeap[WSF_BUF_SIZE / 4]; +uint32_t SystemHeapStart; + +/* Task ID for the ble handler */ +static TaskHandle_t ble_task_id = NULL; + +/*! Default pool descriptor. */ +/* clang-format off */ +static wsfBufPoolDesc_t mainPoolDesc[WSF_BUF_POOLS] = +{ + { 16, 8 }, + { 32, 4 }, + { 64, 4 }, + { 128, 4 }, + { 256, 4 }, + { 512, 4 } +}; +/* clang-format on */ + +static StaticTimer_t x; +static TimerHandle_t timerWakeup = NULL; +static int lasttick = 0; + +/*! \brief Stack initialization for app. */ +extern void StackInit(void); +extern void AppInit(void); +extern void bleuart_init(void); + +/*************************************************************************************************/ +void PalSysAssertTrap(void) +{ + while (1) { + } +} +/*************************************************************************************************/ +static bool_t myTrace(const uint8_t *pBuf, uint32_t len) +{ + extern uint8_t wsfCsNesting; + + if (wsfCsNesting == 0) { + fwrite(pBuf, len, 1, stdout); + return TRUE; + } + + return FALSE; +} +/*************************************************************************************************/ +static void WsfInit(void) +{ + uint32_t bytesUsed __attribute__((unused)); + WsfTimerInit(); + + SystemHeapStart = (uint32_t)&SystemHeap; + memset(SystemHeap, 0, sizeof(SystemHeap)); + //printf("SystemHeapStart = 0x%x\n", SystemHeapStart); + //printf("SystemHeapSize = 0x%x\n", SystemHeapSize); + + WsfTraceRegisterHandler(myTrace); + WsfTraceEnable(TRUE); + + bytesUsed = WsfBufInit(WSF_BUF_POOLS, mainPoolDesc); + APP_TRACE_INFO1("bytesUsed = %u", (unsigned int)bytesUsed); +} +/*************************************************************************************************/ +/* TODO: We need a source of MACs */ +static void setAddress(void) +{ + uint8_t bdAddr[6] = { 0x02, 0x02, 0x44, 0x8B, 0x05, 0x00 }; + char buf[32]; + + fs_read_text_file("mac.txt", buf, sizeof(buf)); + APP_TRACE_INFO1("mac file contents: %s", buf); + int a, b, c, d, e, f; + if (sscanf(buf, "%x:%x:%x:%x:%x:%x", &a, &b, &c, &d, &e, &f) == 6) { + bdAddr[0] = f; + bdAddr[1] = e; + bdAddr[2] = d; + bdAddr[3] = c; + bdAddr[4] = b; + bdAddr[5] = a; + } + + LOG_INFO( + "ble", + "Setting MAC address to %02X:%02X:%02X:%02X:%02X:%02X", + bdAddr[5], + bdAddr[4], + bdAddr[3], + bdAddr[2], + bdAddr[1], + bdAddr[0] + ); + HciVsSetBdAddr(bdAddr); +} +/*************************************************************************************************/ +static void vTimerCallback(xTimerHandle pxTimer) +{ + //printf("wake\n"); + int tick = xTaskGetTickCount(); + //printf("WsfTimerUpdate(%d)\n", tick - lasttick); + WsfTimerUpdate(tick - lasttick); + lasttick = tick; + //printf("done\n"); +} +/*************************************************************************************************/ +static void notify(void) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + if (xPortIsInsideInterrupt()) { + vTaskNotifyGiveFromISR(ble_task_id, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + } else { + xTaskNotifyGive(ble_task_id); + } +} +/*************************************************************************************************/ +void WsfTimerNotify(void) +{ + //printf("WsfTimerNotify\n"); + // TODO: Can we do this without waking up the task? + // xTimerChangePeriodFromISR exists + notify(); +} +/*************************************************************************************************/ +void wsf_ble_signal_event(void) +{ + //printf("wsf_ble_signal_event\n"); + notify(); +} +/*************************************************************************************************/ +static void scheduleTimer(void) +{ + bool_t timerRunning; + wsfTimerTicks_t time_to_next_expire; + + vTimerCallback(NULL); + time_to_next_expire = WsfTimerNextExpiration(&timerRunning); + + if (timerRunning) { + //printf("time_to_next_expire = %d\n", time_to_next_expire); + //printf("change period\n"); + if (timerWakeup != NULL) { + xTimerChangePeriod( + timerWakeup, + pdMS_TO_TICKS(time_to_next_expire), + 0 + ); + //printf("insert done\n"); + } else { + LOG_ERR("ble", "Could not create timer"); + } + } else { + APP_TRACE_INFO0("No timer running"); + } +} +/*************************************************************************************************/ +void vBleTask(void *pvParameters) +{ + ble_task_id = xTaskGetCurrentTaskHandle(); + WsfInit(); + StackInit(); + setAddress(); + + NVIC_SetPriority(BTLE_SFD_TO_IRQn, 2); + NVIC_SetPriority(BTLE_TX_DONE_IRQn, 2); + NVIC_SetPriority(BTLE_RX_RCVD_IRQn, 2); + AppInit(); + BleStart(); + AttsDynInit(); + + bleuart_init(); + + lasttick = xTaskGetTickCount(); + + timerWakeup = xTimerCreateStatic( + "timerWakeup", /* name */ + pdMS_TO_TICKS(1), /* period/time */ + pdFALSE, /* auto reload */ + NULL, /* timer ID */ + vTimerCallback, + &x); /* callback */ + + while (1) { + ulTaskNotifyTake(pdTRUE, portTICK_PERIOD_MS * 1000); + wsfOsDispatcher(); + scheduleTimer(); + } +} diff --git a/epicardium/ble/ble_api.h b/epicardium/ble/ble_api.h new file mode 100644 index 0000000000000000000000000000000000000000..9040f8e436100660b2bbb7c1ef6079cdde07082a --- /dev/null +++ b/epicardium/ble/ble_api.h @@ -0,0 +1,13 @@ +#pragma once +/************************************************************************************************** + Function Declarations +**************************************************************************************************/ +/*************************************************************************************************/ +/*! + * \brief Start the application. + * + * \return None. + */ +/*************************************************************************************************/ +void BleStart(void); + diff --git a/epicardium/ble/ble_main.c b/epicardium/ble/ble_main.c new file mode 100644 index 0000000000000000000000000000000000000000..4c0971e7b4964781f473b6d0ba1e461f3fd99561 --- /dev/null +++ b/epicardium/ble/ble_main.c @@ -0,0 +1,513 @@ +/* card10: + * Copied from lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/apps/fit/fit_main.c + * + * Also have a look at lib/sdk/Applications/EvKitExamples/BLE_fit/fit_main.c which has some changes + * to this file regarding handling of OOB paring data + * + * This file contains some application logic taken from the "fit" example. + * + * Things have been renamed: + * fit -> ble + * Fit -> Ble + * FIT -> BLE + */ +/* clang-format off */ +/* clang-formet turned off for easier diffing against orginal file */ +#include <string.h> +#include "wsf_types.h" +#include "util/bstream.h" +#include "wsf_msg.h" +#include "wsf_trace.h" +#include "hci_api.h" +#include "dm_api.h" +#include "att_api.h" +#include "smp_api.h" +#include "app_api.h" +#include "app_db.h" +#include "app_ui.h" +#include "app_hw.h" +#include "svc_ch.h" +#include "svc_core.h" +#include "svc_hrs.h" +#include "svc_dis.h" +#include "svc_batt.h" +#include "svc_rscs.h" +#include "bas/bas_api.h" +#include "hrps/hrps_api.h" +#include "rscp/rscp_api.h" + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! WSF message event starting value */ +#define BLE_MSG_START 0xA0 + +/*! WSF message event enumeration */ +enum +{ + BLE_BATT_TIMER_IND = BLE_MSG_START, /*! Battery measurement timer expired */ +}; + +/************************************************************************************************** + Data Types +**************************************************************************************************/ + +/*! Application message type */ +typedef union +{ + wsfMsgHdr_t hdr; + dmEvt_t dm; + attsCccEvt_t ccc; + attEvt_t att; +} bleMsg_t; + +/************************************************************************************************** + Configurable Parameters +**************************************************************************************************/ + +/*! configurable parameters for advertising */ +static const appAdvCfg_t bleAdvCfg = +{ + {60000, 0, 0}, /*! Advertising durations in ms */ + {500/0.625, 4000/0.625, 0} /*! Advertising intervals in 0.625 ms units */ +}; + +/*! configurable parameters for slave */ +static const appSlaveCfg_t bleSlaveCfg = +{ + 1, /*! Maximum connections */ +}; + +/*! configurable parameters for security */ +static const appSecCfg_t bleSecCfg = +{ + DM_AUTH_BOND_FLAG | DM_AUTH_SC_FLAG, /*! Authentication and bonding flags */ + 0, /*! Initiator key distribution flags */ + DM_KEY_DIST_LTK, /*! Responder key distribution flags */ + FALSE, /*! TRUE if Out-of-band pairing data is present */ + TRUE /*! TRUE to initiate security upon connection */ +}; + +/*! configurable parameters for connection parameter update */ +static const appUpdateCfg_t bleUpdateCfg = +{ + 6000, /*! Connection idle period in ms before attempting + connection parameter update; set to zero to disable */ + 800/1.25, /*! Minimum connection interval in 1.25ms units */ + 1000/1.25, /*! Maximum connection interval in 1.25ms units */ + 0, /*! Connection latency */ + 9000/10, /*! Supervision timeout in 10ms units */ + 5 /*! Number of update attempts before giving up */ +}; + +/*! battery measurement configuration */ +static const basCfg_t bleBasCfg = +{ + 30, /*! Battery measurement timer expiration period in seconds */ + 1, /*! Perform battery measurement after this many timer periods */ + 100 /*! Send battery level notification to peer when below this level. */ +}; + +/*! SMP security parameter configuration */ +static const smpCfg_t bleSmpCfg = +{ + 3000, /*! 'Repeated attempts' timeout in msec */ + SMP_IO_NO_IN_NO_OUT, /*! I/O Capability */ + 7, /*! Minimum encryption key length */ + 16, /*! Maximum encryption key length */ + 3, /*! Attempts to trigger 'repeated attempts' timeout */ + 0, /*! Device authentication requirements */ +}; + +/************************************************************************************************** + Advertising Data +**************************************************************************************************/ + +/*! advertising data, discoverable mode */ +static const uint8_t bleAdvDataDisc[] = +{ + /*! flags */ + 2, /*! length */ + DM_ADV_TYPE_FLAGS, /*! AD type */ + DM_FLAG_LE_GENERAL_DISC | /*! flags */ + DM_FLAG_LE_BREDR_NOT_SUP, + + /*! tx power */ + 2, /*! length */ + DM_ADV_TYPE_TX_POWER, /*! AD type */ + 0, /*! tx power */ + + /*! service UUID list */ + 5, /*! length */ + DM_ADV_TYPE_16_UUID, /*! AD type */ + UINT16_TO_BYTES(ATT_UUID_DEVICE_INFO_SERVICE), + UINT16_TO_BYTES(ATT_UUID_BATTERY_SERVICE) +}; + +/*! scan data, discoverable mode */ +static const uint8_t bleScanDataDisc[] = +{ + /*! device name */ + 7, /*! length */ + DM_ADV_TYPE_LOCAL_NAME, /*! AD type */ + 'c','a','r','d','1','0' +}; + +/************************************************************************************************** + Client Characteristic Configuration Descriptors +**************************************************************************************************/ + +/*! enumeration of client characteristic configuration descriptors */ +enum +{ + BLE_GATT_SC_CCC_IDX, /*! GATT service, service changed characteristic */ + BLE_BATT_LVL_CCC_IDX, /*! Battery service, battery level characteristic */ + BLE_NUM_CCC_IDX +}; + +/*! client characteristic configuration descriptors settings, indexed by above enumeration */ +static const attsCccSet_t bleCccSet[BLE_NUM_CCC_IDX] = +{ + /* cccd handle value range security level */ + {GATT_SC_CH_CCC_HDL, ATT_CLIENT_CFG_INDICATE, DM_SEC_LEVEL_NONE}, /* BLE_GATT_SC_CCC_IDX */ + {BATT_LVL_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* BLE_BATT_LVL_CCC_IDX */ +}; + +/************************************************************************************************** + Global Variables +**************************************************************************************************/ + +/*! WSF handler ID */ +wsfHandlerId_t bleHandlerId; + + +static void BleHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg); +/*************************************************************************************************/ +/*! + * \brief Application DM callback. + * + * \param pDmEvt DM callback event + * + * \return None. + */ +/*************************************************************************************************/ +static void bleDmCback(dmEvt_t *pDmEvt) +{ + dmEvt_t *pMsg; + uint16_t len; + + len = DmSizeOfEvt(pDmEvt); + + if ((pMsg = WsfMsgAlloc(len)) != NULL) + { + memcpy(pMsg, pDmEvt, len); + WsfMsgSend(bleHandlerId, pMsg); + } +} + +/*************************************************************************************************/ +/*! + * \brief Application ATT callback. + * + * \param pEvt ATT callback event + * + * \return None. + */ +/*************************************************************************************************/ +static void bleAttCback(attEvt_t *pEvt) +{ + attEvt_t *pMsg; + + if ((pMsg = WsfMsgAlloc(sizeof(attEvt_t) + pEvt->valueLen)) != NULL) + { + memcpy(pMsg, pEvt, sizeof(attEvt_t)); + pMsg->pValue = (uint8_t *) (pMsg + 1); + memcpy(pMsg->pValue, pEvt->pValue, pEvt->valueLen); + WsfMsgSend(bleHandlerId, pMsg); + } +} + +/*************************************************************************************************/ +/*! + * \brief Application ATTS client characteristic configuration callback. + * + * \param pDmEvt DM callback event + * + * \return None. + */ +/*************************************************************************************************/ +static void bleCccCback(attsCccEvt_t *pEvt) +{ + attsCccEvt_t *pMsg; + appDbHdl_t dbHdl; + + /* if CCC not set from initialization and there's a device record */ + if ((pEvt->handle != ATT_HANDLE_NONE) && + ((dbHdl = AppDbGetHdl((dmConnId_t) pEvt->hdr.param)) != APP_DB_HDL_NONE)) + { + /* store value in device database */ + AppDbSetCccTblValue(dbHdl, pEvt->idx, pEvt->value); + } + + if ((pMsg = WsfMsgAlloc(sizeof(attsCccEvt_t))) != NULL) + { + memcpy(pMsg, pEvt, sizeof(attsCccEvt_t)); + WsfMsgSend(bleHandlerId, pMsg); + } +} + + + +/*************************************************************************************************/ +/*! + * \brief Process CCC state change. + * + * \param pMsg Pointer to message. + * + * \return None. + */ +/*************************************************************************************************/ +static void bleProcCccState(bleMsg_t *pMsg) +{ + APP_TRACE_INFO3("ccc state ind value:%d handle:%d idx:%d", pMsg->ccc.value, pMsg->ccc.handle, pMsg->ccc.idx); + + /* handle battery level CCC */ + if (pMsg->ccc.idx == BLE_BATT_LVL_CCC_IDX) + { + if (pMsg->ccc.value == ATT_CLIENT_CFG_NOTIFY) + { + BasMeasBattStart((dmConnId_t) pMsg->ccc.hdr.param, BLE_BATT_TIMER_IND, BLE_BATT_LVL_CCC_IDX); + } + else + { + BasMeasBattStop((dmConnId_t) pMsg->ccc.hdr.param); + } + return; + } +} + +/*************************************************************************************************/ +/*! + * \brief Perform UI actions on connection close. + * + * \param pMsg Pointer to message. + * + * \return None. + */ +/*************************************************************************************************/ +static void bleClose(bleMsg_t *pMsg) +{ + /* stop battery measurement */ + BasMeasBattStop((dmConnId_t) pMsg->hdr.param); +} + +/*************************************************************************************************/ +/*! + * \brief Set up advertising and other procedures that need to be performed after + * device reset. + * + * \param pMsg Pointer to message. + * + * \return None. + */ +/*************************************************************************************************/ +static void bleSetup(bleMsg_t *pMsg) +{ + /* set advertising and scan response data for discoverable mode */ + AppAdvSetData(APP_ADV_DATA_DISCOVERABLE, sizeof(bleAdvDataDisc), (uint8_t *) bleAdvDataDisc); + AppAdvSetData(APP_SCAN_DATA_DISCOVERABLE, sizeof(bleScanDataDisc), (uint8_t *) bleScanDataDisc); + + /* set advertising and scan response data for connectable mode */ + AppAdvSetData(APP_ADV_DATA_CONNECTABLE, 0, NULL); + AppAdvSetData(APP_SCAN_DATA_CONNECTABLE, 0, NULL); + + /* start advertising; automatically set connectable/discoverable mode and bondable mode */ + AppAdvStart(APP_MODE_AUTO_INIT); +} + + +/*************************************************************************************************/ +/*! + * \brief Process messages from the event handler. + * + * \param pMsg Pointer to message. + * + * \return None. + */ +/*************************************************************************************************/ +static void bleProcMsg(bleMsg_t *pMsg) +{ + uint8_t uiEvent = APP_UI_NONE; + + switch(pMsg->hdr.event) + { + case BLE_BATT_TIMER_IND: + BasProcMsg(&pMsg->hdr); + break; + + case ATTS_HANDLE_VALUE_CNF: + BasProcMsg(&pMsg->hdr); + break; + + case ATTS_CCC_STATE_IND: + bleProcCccState(pMsg); + break; + + case DM_RESET_CMPL_IND: + DmSecGenerateEccKeyReq(); + bleSetup(pMsg); + uiEvent = APP_UI_RESET_CMPL; + break; + + case DM_ADV_START_IND: + uiEvent = APP_UI_ADV_START; + break; + + case DM_ADV_STOP_IND: + uiEvent = APP_UI_ADV_STOP; + break; + + case DM_CONN_OPEN_IND: + BasProcMsg(&pMsg->hdr); + uiEvent = APP_UI_CONN_OPEN; + break; + + case DM_CONN_CLOSE_IND: + bleClose(pMsg); + uiEvent = APP_UI_CONN_CLOSE; + break; + + case DM_SEC_PAIR_CMPL_IND: + uiEvent = APP_UI_SEC_PAIR_CMPL; + break; + + case DM_SEC_PAIR_FAIL_IND: + uiEvent = APP_UI_SEC_PAIR_FAIL; + break; + + case DM_SEC_ENCRYPT_IND: + uiEvent = APP_UI_SEC_ENCRYPT; + break; + + case DM_SEC_ENCRYPT_FAIL_IND: + uiEvent = APP_UI_SEC_ENCRYPT_FAIL; + break; + + case DM_SEC_AUTH_REQ_IND: + AppHandlePasskey(&pMsg->dm.authReq); + break; + + case DM_SEC_ECC_KEY_IND: + DmSecSetEccKey(&pMsg->dm.eccMsg.data.key); + break; + + case DM_SEC_COMPARE_IND: + AppHandleNumericComparison(&pMsg->dm.cnfInd); + break; + + case DM_HW_ERROR_IND: + uiEvent = APP_UI_HW_ERROR; + break; + + default: + break; + } + + if (uiEvent != APP_UI_NONE) + { + AppUiAction(uiEvent); + } +} + +/*************************************************************************************************/ +/*! + * \brief Application handler init function called during system initialization. + * + * \param handlerID WSF handler ID. + * + * \return None. + */ +/*************************************************************************************************/ +static void BleHandlerInit(void) +{ + APP_TRACE_INFO0("BleHandlerInit"); + + /* store handler ID */ + bleHandlerId =WsfOsSetNextHandler(BleHandler); + + /* Set configuration pointers */ + pAppAdvCfg = (appAdvCfg_t *) &bleAdvCfg; + pAppSlaveCfg = (appSlaveCfg_t *) &bleSlaveCfg; + pAppSecCfg = (appSecCfg_t *) &bleSecCfg; + pAppUpdateCfg = (appUpdateCfg_t *) &bleUpdateCfg; + + /* Initialize application framework */ + AppSlaveInit(); + + /* Set stack configuration pointers */ + pSmpCfg = (smpCfg_t *) &bleSmpCfg; + + /* initialize battery service server */ + BasInit(bleHandlerId, (basCfg_t *) &bleBasCfg); +} + +/*************************************************************************************************/ +/*! + * \brief WSF event handler for application. + * + * \param event WSF event mask. + * \param pMsg WSF message. + * + * \return None. + */ +/*************************************************************************************************/ +static void BleHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg) +{ + if (pMsg != NULL) + { + APP_TRACE_INFO1("Ble got evt %d", pMsg->event); + + if (pMsg->event >= DM_CBACK_START && pMsg->event <= DM_CBACK_END) + { + /* process advertising and connection-related messages */ + AppSlaveProcDmMsg((dmEvt_t *) pMsg); + + /* process security-related messages */ + AppSlaveSecProcDmMsg((dmEvt_t *) pMsg); + } + + /* perform profile and user interface-related operations */ + bleProcMsg((bleMsg_t *) pMsg); + } +} + +/*************************************************************************************************/ +/*! + * \brief Start the application. + * + * \return None. + */ +/*************************************************************************************************/ +void BleStart(void) +{ + + BleHandlerInit(); + + /* Register for stack callbacks */ + DmRegister(bleDmCback); + DmConnRegister(DM_CLIENT_ID_APP, bleDmCback); + AttRegister(bleAttCback); + AttConnRegister(AppServerConnCback); + AttsCccRegister(BLE_NUM_CCC_IDX, (attsCccSet_t *) bleCccSet, bleCccCback); + + /* Initialize attribute server database */ + SvcCoreAddGroup(); + SvcDisAddGroup(); // Device Information Service + SvcBattCbackRegister(BasReadCback, NULL); + SvcBattAddGroup(); + + /* Reset the device */ + DmDevReset(); +} +/* clang-format on */ diff --git a/epicardium/ble/meson.build b/epicardium/ble/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..02f2eeb58e44eb2840f3bb8bc0a1cf979822bad1 --- /dev/null +++ b/epicardium/ble/meson.build @@ -0,0 +1,11 @@ +ble_sources = files( + 'ble.c', + 'stack.c', + 'ble_main.c', + 'svc_dis.c', + 'svc_core.c', + 'app/app_main.c', + 'app/common/app_db.c', + 'app/common/app_ui.c', + 'uart.c' +) diff --git a/epicardium/ble/stack.c b/epicardium/ble/stack.c new file mode 100644 index 0000000000000000000000000000000000000000..690d1cb1447c05e841f157b4edb494ba2241460e --- /dev/null +++ b/epicardium/ble/stack.c @@ -0,0 +1,189 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Stack initialization + * + * Copyright (c) 2016-2017 ARM Ltd. All Rights Reserved. + * ARM Ltd. confidential and proprietary. + * + * IMPORTANT. Your use of this file is governed by a Software License Agreement + * ("Agreement") that must be accepted in order to download or otherwise receive a + * copy of this file. You may not use or copy this file for any purpose other than + * as described in the Agreement. If you do not agree to all of the terms of the + * Agreement do not use this file and delete all copies in your possession or control; + * if you do not have a copy of the Agreement, you must contact ARM Ltd. prior + * to any use, copying or further distribution of this software. + */ +/*************************************************************************************************/ + +/* + * This file initializes the different components of the whole BLE stack. This inlucdes link level, + * HCI, security, etc... + * + * This file has been copied from lib/sdk/Applications/EvKitExamples/BLE_fit/stack_fit.c + * + * NOTE: Different stack_*.c files in the SDK initialize different components. We have to + * be very carefull to intitialize all needed components here. Think e.g. SecRandInit() ... + * + * Many components are related to the role of the device. Different components need to be + * initialized for central and peripheral roles. + */ +/* clang-format off */ +/* clang-formet turned off for easier diffing against orginal file */ +#include <stdio.h> +#include <string.h> +#include "wsf_types.h" +#include "wsf_os.h" +#include "util/bstream.h" +#include "ble_api.h" +#include "hci_handler.h" +#include "dm_handler.h" +#include "l2c_handler.h" +#include "att_handler.h" +#include "smp_handler.h" +#include "l2c_api.h" +#include "att_api.h" +#include "smp_api.h" +#include "app_api.h" +#include "svc_dis.h" +#include "svc_core.h" +#include "sec_api.h" +#include "ll_init_api.h" + +/* TODO: card10: Where does this number come from? Is there any documentation? */ +#define LL_IMPL_REV 0x2303 + +/* TODO: card10: Where does this number come from? Is there any documentation? */ +#define LL_MEMORY_FOOTPRINT 0xC152 + +uint8_t LlMem[LL_MEMORY_FOOTPRINT]; + +const LlRtCfg_t _ll_cfg = { + /* Device */ + /*compId*/ LL_COMP_ID_ARM, + /*implRev*/ LL_IMPL_REV, + /*btVer*/ LL_VER_BT_CORE_SPEC_5_0, + /*_align32 */ 0, // padding for alignment + + /* Advertiser */ + /*maxAdvSets*/ 4, // 4 Extended Advertising Sets + /*maxAdvReports*/ 8, + /*maxExtAdvDataLen*/ LL_MAX_ADV_DATA_LEN, + /*defExtAdvDataFrag*/ 64, + /*auxDelayUsec*/ 0, + + /* Scanner */ + /*maxScanReqRcvdEvt*/ 4, + /*maxExtScanDataLen*/ LL_MAX_ADV_DATA_LEN, + + /* Connection */ + /*maxConn*/ 2, + /*numTxBufs*/ 16, + /*numRxBufs*/ 16, + /*maxAclLen*/ 512, + /*defTxPwrLvl*/ 0, + /*ceJitterUsec*/ 0, + + /* DTM */ + /*dtmRxSyncMs*/ 10000, + + /* PHY */ + /*phy2mSup*/ TRUE, + /*phyCodedSup*/ TRUE, + /*stableModIdxTxSup*/ FALSE, + /*stableModIdxRxSup*/ FALSE +}; + +const BbRtCfg_t _bb_cfg = { + /*clkPpm*/ 20, + /*rfSetupDelayUsec*/ BB_RF_SETUP_DELAY_US, + /*maxScanPeriodMsec*/ BB_MAX_SCAN_PERIOD_MS, + /*schSetupDelayUsec*/ BB_SCH_SETUP_DELAY_US +}; + +/*************************************************************************************************/ +/*! + * \brief Initialize stack. + * + * \return None. + */ +/*************************************************************************************************/ +void StackInit(void) +{ + wsfHandlerId_t handlerId; + +/* card10: We do not use the SDMA HCI at the moment. The block below is not compiled. */ +#ifndef ENABLE_SDMA + uint32_t memUsed; + + /* Initialize link layer. */ + LlInitRtCfg_t ll_init_cfg = + { + .pBbRtCfg = &_bb_cfg, + .wlSizeCfg = 4, + .rlSizeCfg = 4, + .plSizeCfg = 4, + .pLlRtCfg = &_ll_cfg, + .pFreeMem = LlMem, + .freeMemAvail = LL_MEMORY_FOOTPRINT + }; + +#ifdef DATS_APP_USE_LEGACY_API + memUsed = LlInitControllerExtInit(&ll_init_cfg); +#else /* DATS_APP_USE_LEGACY_API */ + memUsed = LlInitControllerExtInit(&ll_init_cfg); +#endif /* DATS_APP_USE_LEGACY_API */ + if(memUsed != LL_MEMORY_FOOTPRINT) + { + printf("Controller memory mismatch 0x%x != 0x%x\n", (unsigned int)memUsed, + (unsigned int)LL_MEMORY_FOOTPRINT); + } +#endif + + + /* card10: + * These calls register a queue for callbacks in the OS abstraction + * and then pass a handle down to modules which uses them to + * internally handle callbacks. + * + * No idea why the modules don't call WsfOsSetNextHandler() + * internally ... */ + handlerId = WsfOsSetNextHandler(HciHandler); + HciHandlerInit(handlerId); + + SecInit(); + SecAesInit(); + SecCmacInit(); + SecEccInit(); + + handlerId = WsfOsSetNextHandler(DmHandler); + DmDevVsInit(0); + DmAdvInit(); + DmConnInit(); + DmConnSlaveInit(); + DmSecInit(); + DmSecLescInit(); + DmPrivInit(); + DmPhyInit(); + DmHandlerInit(handlerId); + + handlerId = WsfOsSetNextHandler(L2cSlaveHandler); + L2cSlaveHandlerInit(handlerId); + L2cInit(); + L2cSlaveInit(); + + handlerId = WsfOsSetNextHandler(AttHandler); + AttHandlerInit(handlerId); + AttsInit(); + AttsIndInit(); + + handlerId = WsfOsSetNextHandler(SmpHandler); + SmpHandlerInit(handlerId); + SmprInit(); + SmprScInit(); + + /*TODO card10: Probably want to adjust this */ + HciSetMaxRxAclLen(100); +} +/* clang-format off */ diff --git a/epicardium/ble/svc_core.c b/epicardium/ble/svc_core.c new file mode 100644 index 0000000000000000000000000000000000000000..a8618dc6b2e5aa682265b7af7de74f4eb4fa4334 --- /dev/null +++ b/epicardium/ble/svc_core.c @@ -0,0 +1,349 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Example GATT and GAP service implementations. + * + * Copyright (c) 2009-2018 Arm Ltd. All Rights Reserved. + * ARM Ltd. confidential and proprietary. + * + * IMPORTANT. Your use of this file is governed by a Software License Agreement + * ("Agreement") that must be accepted in order to download or otherwise receive a + * copy of this file. You may not use or copy this file for any purpose other than + * as described in the Agreement. If you do not agree to all of the terms of the + * Agreement do not use this file and delete all copies in your possession or control; + * if you do not have a copy of the Agreement, you must contact ARM Ltd. prior + * to any use, copying or further distribution of this software. + */ +/*************************************************************************************************/ + +/* card10: + * copied from lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/services/svc_core.c + */ +/* clang-format off */ +/* clang-formet turned off for easier diffing against orginal file */ +#include "wsf_types.h" +#include "att_api.h" +#include "att_uuid.h" +#include "util/bstream.h" +#include "svc_core.h" +#include "svc_ch.h" +#include "svc_cfg.h" +#include "wsf_assert.h" + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! Characteristic read permissions */ +#ifndef CORE_SEC_PERMIT_READ +#define CORE_SEC_PERMIT_READ SVC_SEC_PERMIT_READ +#endif + +/*! Characteristic write permissions */ +#ifndef CORE_SEC_PERMIT_WRITE +#define CORE_SEC_PERMIT_WRITE SVC_SEC_PERMIT_WRITE +#endif + +/*! Default device name */ +#define CORE_DEFAULT_DEV_NAME "card10" + +/*! Length of default device name */ +#define CORE_DEFAULT_DEV_NAME_LEN 6 + +/************************************************************************************************** + GAP group +**************************************************************************************************/ + +/* service */ +static const uint8_t gapValSvc[] = {UINT16_TO_BYTES(ATT_UUID_GAP_SERVICE)}; +static const uint16_t gapLenSvc = sizeof(gapValSvc); + +/* device name characteristic */ +static const uint8_t gapValDnCh[] = {ATT_PROP_READ | ATT_PROP_WRITE, UINT16_TO_BYTES(GAP_DN_HDL), UINT16_TO_BYTES(ATT_UUID_DEVICE_NAME)}; +static const uint16_t gapLenDnCh = sizeof(gapValDnCh); + +/* device name */ +static uint8_t gapValDn[ATT_DEFAULT_PAYLOAD_LEN] = CORE_DEFAULT_DEV_NAME; +static uint16_t gapLenDn = CORE_DEFAULT_DEV_NAME_LEN; + +/* appearance characteristic */ +static const uint8_t gapValApCh[] = {ATT_PROP_READ, UINT16_TO_BYTES(GAP_AP_HDL), UINT16_TO_BYTES(ATT_UUID_APPEARANCE)}; +static const uint16_t gapLenApCh = sizeof(gapValApCh); + +/* appearance */ +static uint8_t gapValAp[] = {UINT16_TO_BYTES(CH_APPEAR_UNKNOWN)}; +static const uint16_t gapLenAp = sizeof(gapValAp); + +/* central address resolution characteristic */ +static const uint8_t gapValCarCh[] = {ATT_PROP_READ, UINT16_TO_BYTES(GAP_CAR_HDL), UINT16_TO_BYTES(ATT_UUID_CAR)}; +static const uint16_t gapLenCarCh = sizeof(gapValCarCh); + +/* central address resolution */ +static uint8_t gapValCar[] = {FALSE}; +static const uint16_t gapLenCar = sizeof(gapValCar); +#if 0 +/* TODO card10: + * Enable these if "privacy" is enabled. See svc_core.h lien 38 */ + +/* resolvable private address only characteristic */ +static const uint8_t gapValRpaoCh[] = {ATT_PROP_READ, UINT16_TO_BYTES(GAP_RPAO_HDL), UINT16_TO_BYTES(ATT_UUID_RPAO)}; +static const uint16_t gapLenRpaoCh = sizeof(gapValRpaoCh); + +/* resolvable private address only */ +static uint8_t gapValRpao[] = {0}; +static const uint16_t gapLenRpao = sizeof(gapValRpao); +#endif + +/* Attribute list for GAP group */ +static const attsAttr_t gapList[] = +{ + { + attPrimSvcUuid, + (uint8_t *) gapValSvc, + (uint16_t *) &gapLenSvc, + sizeof(gapValSvc), + 0, + ATTS_PERMIT_READ + }, + { + attChUuid, + (uint8_t *) gapValDnCh, + (uint16_t *) &gapLenDnCh, + sizeof(gapValDnCh), + 0, + ATTS_PERMIT_READ + }, + { + attDnChUuid, + gapValDn, + &gapLenDn, + sizeof(gapValDn), + (ATTS_SET_VARIABLE_LEN | ATTS_SET_WRITE_CBACK), + (ATTS_PERMIT_READ | CORE_SEC_PERMIT_WRITE) + }, + { + attChUuid, + (uint8_t *) gapValApCh, + (uint16_t *) &gapLenApCh, + sizeof(gapValApCh), + 0, + ATTS_PERMIT_READ + }, + { + attApChUuid, + gapValAp, + (uint16_t *) &gapLenAp, + sizeof(gapValAp), + 0, + ATTS_PERMIT_READ + }, + { + attChUuid, + (uint8_t *) gapValCarCh, + (uint16_t *) &gapLenCarCh, + sizeof(gapValCarCh), + 0, + ATTS_PERMIT_READ + }, + { + attCarChUuid, + gapValCar, + (uint16_t *) &gapLenCar, + sizeof(gapValCar), + 0, + ATTS_PERMIT_READ + }, +#if 0 +/* TODO card10: + * Enable these if "privacy" is enabled. See svc_core.h lien 38 */ + { + attChUuid, + (uint8_t *) gapValRpaoCh, + (uint16_t *) &gapLenRpaoCh, + sizeof(gapValRpaoCh), + 0, + ATTS_PERMIT_READ + }, + { + attRpaoChUuid, + gapValRpao, + (uint16_t *) &gapLenRpao, + sizeof(gapValRpao), + 0, + ATTS_PERMIT_READ + } +#endif +}; + +/* GAP group structure */ +static attsGroup_t svcGapGroup = +{ + NULL, + (attsAttr_t *) gapList, + NULL, + NULL, + GAP_START_HDL, + GAP_END_HDL +}; + +WSF_CT_ASSERT(((sizeof(gapList) / sizeof(gapList[0])) == GAP_END_HDL - GAP_START_HDL + 1)); +/************************************************************************************************** + GATT group +**************************************************************************************************/ + +/* service */ +static const uint8_t gattValSvc[] = {UINT16_TO_BYTES(ATT_UUID_GATT_SERVICE)}; +static const uint16_t gattLenSvc = sizeof(gattValSvc); + +/* service changed characteristic */ +static const uint8_t gattValScCh[] = {ATT_PROP_INDICATE, UINT16_TO_BYTES(GATT_SC_HDL), UINT16_TO_BYTES(ATT_UUID_SERVICE_CHANGED)}; +static const uint16_t gattLenScCh = sizeof(gattValScCh); + +/* service changed */ +static const uint8_t gattValSc[] = {UINT16_TO_BYTES(0x0001), UINT16_TO_BYTES(0xFFFF)}; +static const uint16_t gattLenSc = sizeof(gattValSc); + +/* service changed client characteristic configuration */ +static uint8_t gattValScChCcc[] = {UINT16_TO_BYTES(0x0000)}; +static const uint16_t gattLenScChCcc = sizeof(gattValScChCcc); + +/* Attribute list for GATT group */ +static const attsAttr_t gattList[] = +{ + { + attPrimSvcUuid, + (uint8_t *) gattValSvc, + (uint16_t *) &gattLenSvc, + sizeof(gattValSvc), + 0, + ATTS_PERMIT_READ + }, + { + attChUuid, + (uint8_t *) gattValScCh, + (uint16_t *) &gattLenScCh, + sizeof(gattValScCh), + 0, + ATTS_PERMIT_READ + }, + { + attScChUuid, + (uint8_t *) gattValSc, + (uint16_t *) &gattLenSc, + sizeof(gattValSc), + 0, + 0 + }, + { + attCliChCfgUuid, + gattValScChCcc, + (uint16_t *) &gattLenScChCcc, + sizeof(gattValScChCcc), + ATTS_SET_CCC, + (ATTS_PERMIT_READ | CORE_SEC_PERMIT_WRITE) + }, +}; + +/* GATT group structure */ +static attsGroup_t svcGattGroup = +{ + NULL, + (attsAttr_t *) gattList, + NULL, + NULL, + GATT_START_HDL, + GATT_END_HDL +}; + +WSF_CT_ASSERT(((sizeof(gattList) / sizeof(gattList[0])) == GATT_END_HDL - GATT_START_HDL + 1)); + +/*************************************************************************************************/ +/*! + * \brief Add the services to the attribute server. + * + * \return None. + */ +/*************************************************************************************************/ +void SvcCoreAddGroup(void) +{ + AttsAddGroup(&svcGapGroup); + AttsAddGroup(&svcGattGroup); +} + +/*************************************************************************************************/ +/*! + * \brief Remove the services from the attribute server. + * + * \return None. + */ +/*************************************************************************************************/ +void SvcCoreRemoveGroup(void) +{ + AttsRemoveGroup(GAP_START_HDL); + AttsRemoveGroup(GATT_START_HDL); +} + +/*************************************************************************************************/ +/*! + * \brief Register callbacks for the service. + * + * \param readCback Read callback function. + * \param writeCback Write callback function. + * + * \return None. + */ +/*************************************************************************************************/ +void SvcCoreGapCbackRegister(attsReadCback_t readCback, attsWriteCback_t writeCback) +{ + svcGapGroup.readCback = readCback; + svcGapGroup.writeCback = writeCback; +} + +/*************************************************************************************************/ +/*! + * \brief Register callbacks for the service. + * + * \param readCback Read callback function. + * \param writeCback Write callback function. + * + * \return None. + */ +/*************************************************************************************************/ +void SvcCoreGattCbackRegister(attsReadCback_t readCback, attsWriteCback_t writeCback) +{ + svcGattGroup.readCback = readCback; + svcGattGroup.writeCback = writeCback; +} + +/*************************************************************************************************/ +/*! + * \brief Update the central address resolution attribute value. + * + * \param value New value. + * + * \return None. + */ +/*************************************************************************************************/ +void SvcCoreGapCentAddrResUpdate(bool_t value) +{ + gapValCar[0] = value; +} + +/*************************************************************************************************/ +/*! + * \brief Add the Resolvable Private Address Only (RPAO) characteristic to the GAP service. + * The RPAO characteristic should be added only when DM Privacy is enabled. + * + * \return None. + */ +/*************************************************************************************************/ +void SvcCoreGapAddRpaoCh(void) +{ + /* if RPAO characteristic not already in GAP service */ + if (svcGapGroup.endHandle < GAP_RPAO_HDL) + { + svcGapGroup.endHandle = GAP_RPAO_HDL; + } +} +/* clang-format on */ diff --git a/epicardium/ble/svc_dis.c b/epicardium/ble/svc_dis.c new file mode 100644 index 0000000000000000000000000000000000000000..8ce2786486458369498b744207a61c8dfa8d0644 --- /dev/null +++ b/epicardium/ble/svc_dis.c @@ -0,0 +1,336 @@ +/*************************************************************************************************/ +/*! + * \file + * + * \brief Example Device Information Service implementation. + * + * Copyright (c) 2011-2018 Arm Ltd. All Rights Reserved. + * ARM Ltd. confidential and proprietary. + * + * IMPORTANT. Your use of this file is governed by a Software License Agreement + * ("Agreement") that must be accepted in order to download or otherwise receive a + * copy of this file. You may not use or copy this file for any purpose other than + * as described in the Agreement. If you do not agree to all of the terms of the + * Agreement do not use this file and delete all copies in your possession or control; + * if you do not have a copy of the Agreement, you must contact ARM Ltd. prior + * to any use, copying or further distribution of this software. + */ +/*************************************************************************************************/ + +/* card10: + * Copied from lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/services/svc_dis.c + * + * Contains adaptions for the card10 (e.g. manufacturer name) + */ +/* clang-format off */ +/* clang-formet turned off for easier diffing against orginal file */ +#include "wsf_types.h" +#include "att_api.h" +#include "wsf_assert.h" +#include "wsf_trace.h" +#include "util/bstream.h" +#include "svc_dis.h" +#include "svc_cfg.h" + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! Characteristic read permissions */ +#ifndef DIS_SEC_PERMIT_READ +#define DIS_SEC_PERMIT_READ SVC_SEC_PERMIT_READ +#endif + +/*! Default manufacturer name */ +#define DIS_DEFAULT_MFR_NAME "CCC" + +/*! Length of default manufacturer name */ +#define DIS_DEFAULT_MFR_NAME_LEN 3 + +/*! Default model number */ +#define DIS_DEFAULT_MODEL_NUM "1" + +/*! Length of default model number */ +#define DIS_DEFAULT_MODEL_NUM_LEN 1 + +/*! Default serial number */ +#define DIS_DEFAULT_SERIAL_NUM "1" + +/*! Length of default serial number */ +#define DIS_DEFAULT_SERIAL_NUM_LEN 1 + +/*! Default firmware revision */ +#define DIS_DEFAULT_FW_REV "<git hash>" + +/*! Length of default firmware revision */ +#define DIS_DEFAULT_FW_REV_LEN 10 + +/*! Default hardware revision */ +#define DIS_DEFAULT_HW_REV "1" + +/*! Length of default hardware revision */ +#define DIS_DEFAULT_HW_REV_LEN 1 + +/*! Default software revision */ +#define DIS_DEFAULT_SW_REV "1" + +/*! Length of default software revision */ +#define DIS_DEFAULT_SW_REV_LEN 1 + +/************************************************************************************************** + Service variables +**************************************************************************************************/ + +/* Device information service declaration */ +static const uint8_t disValSvc[] = {UINT16_TO_BYTES(ATT_UUID_DEVICE_INFO_SERVICE)}; +static const uint16_t disLenSvc = sizeof(disValSvc); + +/* Manufacturer name string characteristic */ +static const uint8_t disValMfrCh[] = {ATT_PROP_READ, UINT16_TO_BYTES(DIS_MFR_HDL), UINT16_TO_BYTES(ATT_UUID_MANUFACTURER_NAME)}; +static const uint16_t disLenMfrCh = sizeof(disValMfrCh); + +/* Manufacturer name string */ +static const uint8_t disUuMfr[] = {UINT16_TO_BYTES(ATT_UUID_MANUFACTURER_NAME)}; +static uint8_t disValMfr[DIS_MAXSIZE_MFR_ATT] = DIS_DEFAULT_MFR_NAME; +static uint16_t disLenMfr = DIS_DEFAULT_MFR_NAME_LEN; + +/* System ID characteristic */ +static const uint8_t disValSidCh[] = {ATT_PROP_READ, UINT16_TO_BYTES(DIS_SID_HDL), UINT16_TO_BYTES(ATT_UUID_SYSTEM_ID)}; +static const uint16_t disLenSidCh = sizeof(disValSidCh); + +/* System ID */ +static const uint8_t disUuSid[] = {UINT16_TO_BYTES(ATT_UUID_SYSTEM_ID)}; +static uint8_t disValSid[DIS_SIZE_SID_ATT] = {0x01, 0x02, 0x03, 0x04, 0x05, UINT16_TO_BYTE0(HCI_ID_ARM), UINT16_TO_BYTE1(HCI_ID_ARM), 0x00}; +static const uint16_t disLenSid = sizeof(disValSid); + +/* Model number string characteristic */ +static const uint8_t disValMnCh[] = {ATT_PROP_READ, UINT16_TO_BYTES(DIS_MN_HDL), UINT16_TO_BYTES(ATT_UUID_MODEL_NUMBER)}; +static const uint16_t disLenMnCh = sizeof(disValMnCh); + +/* Model number string */ +static const uint8_t disUuMn[] = {UINT16_TO_BYTES(ATT_UUID_MODEL_NUMBER)}; +static uint8_t disValMn[DIS_MAXSIZE_MN_ATT] = DIS_DEFAULT_MODEL_NUM; +static uint16_t disLenMn = DIS_DEFAULT_MODEL_NUM_LEN; + +/* Serial number string characteristic */ +static const uint8_t disValSnCh[] = {ATT_PROP_READ, UINT16_TO_BYTES(DIS_SN_HDL), UINT16_TO_BYTES(ATT_UUID_SERIAL_NUMBER)}; +static const uint16_t disLenSnCh = sizeof(disValSnCh); + +/* Serial number string */ +static const uint8_t disUuSn[] = {UINT16_TO_BYTES(ATT_UUID_SERIAL_NUMBER)}; +static uint8_t disValSn[DIS_MAXSIZE_SN_ATT] = DIS_DEFAULT_SERIAL_NUM; +static uint16_t disLenSn = DIS_DEFAULT_SERIAL_NUM_LEN; + +/* Firmware revision string characteristic */ +static const uint8_t disValFwrCh[] = {ATT_PROP_READ, UINT16_TO_BYTES(DIS_FWR_HDL), UINT16_TO_BYTES(ATT_UUID_FIRMWARE_REV)}; +static const uint16_t disLenFwrCh = sizeof(disValFwrCh); + +/* Firmware revision string */ +static const uint8_t disUuFwr[] = {UINT16_TO_BYTES(ATT_UUID_FIRMWARE_REV)}; +static uint8_t disValFwr[DIS_MAXSIZE_FWR_ATT] = DIS_DEFAULT_FW_REV; +static uint16_t disLenFwr = DIS_DEFAULT_FW_REV_LEN; + +/* Hardware revision string characteristic */ +static const uint8_t disValHwrCh[] = {ATT_PROP_READ, UINT16_TO_BYTES(DIS_HWR_HDL), UINT16_TO_BYTES(ATT_UUID_HARDWARE_REV)}; +static const uint16_t disLenHwrCh = sizeof(disValHwrCh); + +/* Hardware revision string */ +static const uint8_t disUuHwr[] = {UINT16_TO_BYTES(ATT_UUID_HARDWARE_REV)}; +static uint8_t disValHwr[DIS_MAXSIZE_HWR_ATT] = DIS_DEFAULT_HW_REV; +static uint16_t disLenHwr = DIS_DEFAULT_HW_REV_LEN; + +/* Software revision string characteristic */ +static const uint8_t disValSwrCh[] = {ATT_PROP_READ, UINT16_TO_BYTES(DIS_SWR_HDL), UINT16_TO_BYTES(ATT_UUID_SOFTWARE_REV)}; +static const uint16_t disLenSwrCh = sizeof(disValSwrCh); + +/* Software revision string */ +static const uint8_t disUuSwr[] = {UINT16_TO_BYTES(ATT_UUID_SOFTWARE_REV)}; +static uint8_t disValSwr[DIS_MAXSIZE_SWR_ATT] = DIS_DEFAULT_SW_REV; +static uint16_t disLenSwr = DIS_DEFAULT_SW_REV_LEN; + +/* Registration certificate data characteristic */ +static const uint8_t disValRcdCh[] = {ATT_PROP_READ, UINT16_TO_BYTES(DIS_RCD_HDL), UINT16_TO_BYTES(ATT_UUID_11073_CERT_DATA)}; +static const uint16_t disLenRcdCh = sizeof(disValRcdCh); + +/* Registration certificate data */ +static const uint8_t disUuRcd[] = {UINT16_TO_BYTES(ATT_UUID_11073_CERT_DATA)}; +static uint8_t disValRcd[DIS_SIZE_RCD_ATT] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const uint16_t disLenRcd = sizeof(disValRcd); + +/* Attribute list for dis group */ +static const attsAttr_t disList[] = +{ + { + attPrimSvcUuid, + (uint8_t *) disValSvc, + (uint16_t *) &disLenSvc, + sizeof(disValSvc), + 0, + ATTS_PERMIT_READ + }, + { + attChUuid, + (uint8_t *) disValMfrCh, + (uint16_t *) &disLenMfrCh, + sizeof(disValMfrCh), + 0, + ATTS_PERMIT_READ + }, + { + disUuMfr, + (uint8_t *) disValMfr, + (uint16_t *) &disLenMfr, + sizeof(disValMfr), + ATTS_SET_VARIABLE_LEN, + DIS_SEC_PERMIT_READ + }, + { + attChUuid, + (uint8_t *) disValSidCh, + (uint16_t *) &disLenSidCh, + sizeof(disValSidCh), + 0, + ATTS_PERMIT_READ + }, + { + disUuSid, + disValSid, + (uint16_t *) &disLenSid, + sizeof(disValSid), + 0, + DIS_SEC_PERMIT_READ + }, + { + attChUuid, + (uint8_t *) disValMnCh, + (uint16_t *) &disLenMnCh, + sizeof(disValMnCh), + 0, + ATTS_PERMIT_READ + }, + { + disUuMn, + (uint8_t *) disValMn, + (uint16_t *) &disLenMn, + sizeof(disValMn), + ATTS_SET_VARIABLE_LEN, + DIS_SEC_PERMIT_READ + }, + { + attChUuid, + (uint8_t *) disValSnCh, + (uint16_t *) &disLenSnCh, + sizeof(disValSnCh), + 0, + ATTS_PERMIT_READ + }, + { + disUuSn, + (uint8_t *) disValSn, + (uint16_t *) &disLenSn, + sizeof(disValSn), + ATTS_SET_VARIABLE_LEN, + DIS_SEC_PERMIT_READ + }, + { + attChUuid, + (uint8_t *) disValFwrCh, + (uint16_t *) &disLenFwrCh, + sizeof(disValFwrCh), + 0, + ATTS_PERMIT_READ + }, + { + disUuFwr, + (uint8_t *) disValFwr, + (uint16_t *) &disLenFwr, + sizeof(disValFwr), + ATTS_SET_VARIABLE_LEN, + DIS_SEC_PERMIT_READ + }, + { + attChUuid, + (uint8_t *) disValHwrCh, + (uint16_t *) &disLenHwrCh, + sizeof(disValHwrCh), + 0, + ATTS_PERMIT_READ + }, + { + disUuHwr, + (uint8_t *) disValHwr, + (uint16_t *) &disLenHwr, + sizeof(disValHwr), + ATTS_SET_VARIABLE_LEN, + DIS_SEC_PERMIT_READ + }, + { + attChUuid, + (uint8_t *) disValSwrCh, + (uint16_t *) &disLenSwrCh, + sizeof(disValSwrCh), + 0, + ATTS_PERMIT_READ + }, + { + disUuSwr, + (uint8_t *) disValSwr, + (uint16_t *) &disLenSwr, + sizeof(disValSwr), + ATTS_SET_VARIABLE_LEN, + DIS_SEC_PERMIT_READ + }, + { + attChUuid, + (uint8_t *) disValRcdCh, + (uint16_t *) &disLenRcdCh, + sizeof(disValRcdCh), + 0, + ATTS_PERMIT_READ + }, + { + disUuRcd, + (uint8_t *) disValRcd, + (uint16_t *) &disLenRcd, + sizeof(disValRcd), + 0, + DIS_SEC_PERMIT_READ + }, +}; + +/* DIS group structure */ +static attsGroup_t svcDisGroup = +{ + NULL, + (attsAttr_t *) disList, + NULL, + NULL, + DIS_START_HDL, + DIS_END_HDL +}; + +WSF_CT_ASSERT(((sizeof(disList) / sizeof(disList[0])) == DIS_END_HDL - DIS_START_HDL + 1)); +/*************************************************************************************************/ +/*! + * \brief Add the services to the attribute server. + * + * \return None. + */ +/*************************************************************************************************/ +void SvcDisAddGroup(void) +{ + AttsAddGroup(&svcDisGroup); +} + +/*************************************************************************************************/ +/*! + * \brief Remove the services from the attribute server. + * + * \return None. + */ +/*************************************************************************************************/ +void SvcDisRemoveGroup(void) +{ + AttsRemoveGroup(DIS_START_HDL); +} +/* clang-format on */ diff --git a/epicardium/ble/uart.c b/epicardium/ble/uart.c new file mode 100644 index 0000000000000000000000000000000000000000..d902e3426f1adb4a5e92538beb897a2e2bcc2ef5 --- /dev/null +++ b/epicardium/ble/uart.c @@ -0,0 +1,175 @@ +#include "modules/modules.h" + +#include "wsf_types.h" +#include "util/bstream.h" +#include "att_api.h" + +#include "FreeRTOS.h" +#include "timers.h" + +#include <stdio.h> +#include <string.h> +#include <stdbool.h> + +#define UART_START_HDL 0x800 /*!< \brief Service start handle. */ +#define UART_END_HDL (UART_MAX_HDL - 1) /*!< \brief Service end handle. */ + +/************************************************************************************************** + Handles +**************************************************************************************************/ + +/*! \brief UART Service Handles */ +enum { UART_SVC_HDL = UART_START_HDL, /*!< \brief UART service declaration */ + UART_RX_CH_HDL, /*!< \brief UART rx characteristic */ + UART_RX_HDL, /*!< \brief UART rx value */ + UART_TX_CH_HDL, /*!< \brief UART tx characteristic */ + UART_TX_HDL, /*!< \brief UART tx value */ + UART_TX_CH_CCC_HDL, /*!< \brief UART tx CCCD */ + UART_MAX_HDL /*!< \brief Maximum handle. */ +}; +/**@}*/ + +/* clang-format off */ +static const uint8_t UARTSvc[] = {0x9E,0xCA,0xDC,0x24,0x0E,0xE5,0xA9,0xE0,0x93,0xF3,0xA3,0xB5,0x01,0x00,0x40,0x6E}; + +static const uint8_t uartRxCh[] = {ATT_PROP_WRITE, UINT16_TO_BYTES(UART_RX_HDL), 0x9E,0xCA,0xDC,0x24,0x0E,0xE5,0xA9,0xE0,0x93,0xF3,0xA3,0xB5,0x02,0x00,0x40,0x6E}; +const uint8_t attUartRxChUuid[] = {0x9E,0xCA,0xDC,0x24,0x0E,0xE5, 0xA9,0xE0,0x93,0xF3,0xA3,0xB5,0x02,0x00,0x40,0x6E}; + +static const uint8_t uartTxCh[] = {ATT_PROP_READ | ATT_PROP_NOTIFY, UINT16_TO_BYTES(UART_TX_HDL), 0x9E,0xCA,0xDC,0x24,0x0E,0xE5,0xA9,0xE0,0x93,0xF3,0xA3,0xB5,0x03,0x00,0x40,0x6E}; +const uint8_t attUartTxChUuid[] = {0x9E,0xCA,0xDC,0x24,0x0E,0xE5, 0xA9,0xE0,0x93,0xF3,0xA3,0xB5,0x03,0x00,0x40,0x6E}; +/* clang-format on */ + +static void *SvcUARTAddGroupDyn(void) +{ + void *pSHdl; + uint8_t initCcc[] = { UINT16_TO_BYTES(0x0000) }; + + /* Create the service */ + pSHdl = AttsDynCreateGroup(UART_START_HDL, UART_END_HDL); + + if (pSHdl != NULL) { + /* clang-format off */ + /* Primary service */ + AttsDynAddAttrConst( pSHdl, attPrimSvcUuid, UARTSvc, sizeof(UARTSvc), + 0, ATTS_PERMIT_READ); + + /* UART rx characteristic */ + AttsDynAddAttrConst( pSHdl, attChUuid, uartRxCh, sizeof(uartRxCh), + 0, ATTS_PERMIT_READ); + // XXX: attUartRxChUuid is 16 bytes but nothing says so.... + /* UART rx value */ + // XXX: not sure if max value of 128 is fine... + AttsDynAddAttr( pSHdl, attUartRxChUuid, NULL, 0, 128, + ATTS_SET_WRITE_CBACK | ATTS_SET_VARIABLE_LEN, ATTS_PERMIT_WRITE); + + /* UART tx characteristic */ + AttsDynAddAttrConst( pSHdl, attChUuid, uartTxCh, sizeof(uartTxCh), + 0, ATTS_PERMIT_READ); + /* UART tx value */ + /* TODO: do we need ATTS_SET_READ_CBACK ? */ + AttsDynAddAttr( pSHdl, attUartTxChUuid, NULL, 0, sizeof(uint8_t), + ATTS_SET_READ_CBACK, ATTS_PERMIT_READ); + /* UART tx CCC descriptor */ + AttsDynAddAttr( pSHdl, attCliChCfgUuid, initCcc, sizeof(uint16_t), sizeof(uint16_t), + ATTS_SET_CCC, ATTS_PERMIT_READ | ATTS_PERMIT_WRITE); + /* clang-format on */ + } + + return pSHdl; +} + +dmConnId_t active_connection = 0; + +static uint8_t UARTReadCback( + dmConnId_t connId, + uint16_t handle, + uint8_t operation, + uint16_t offset, + attsAttr_t *pAttr +) { + printf("read callback\n"); + return ATT_SUCCESS; +} + +static uint8_t UARTWriteCback( + dmConnId_t connId, + uint16_t handle, + uint8_t operation, + uint16_t offset, + uint16_t len, + uint8_t *pValue, + attsAttr_t *pAttr +) { + active_connection = connId; + + //printf("UARTWriteCback %d: ", len); + int i; + for (i = 0; i < len; i++) { + //printf("%c", pValue[i]); + serial_enqueue_char(pValue[i]); + } + serial_enqueue_char('\r'); + //printf("\n"); + +#if 0 + AttsSetAttr(UART_TX_HDL, len, pValue); + AttsHandleValueNtf(connId, UART_TX_HDL, len, pValue); +#endif + + return ATT_SUCCESS; +} + +uint8_t ble_uart_tx_buf[129]; +uint8_t ble_uart_buf_tx_fill; +int ble_uart_lasttick = 0; + +void ble_uart_write(uint8_t *pValue, uint8_t len) +{ + int i; + for (i = 0; i < len; i++) { + if (pValue[i] >= 0x20 && pValue[i] < 0x7f) { + ble_uart_tx_buf[ble_uart_buf_tx_fill] = pValue[i]; + ble_uart_buf_tx_fill++; + } else if (pValue[i] == '\r' || pValue[i] == '\n') { + if (ble_uart_buf_tx_fill > 0) { + AttsSetAttr( + UART_TX_HDL, + ble_uart_buf_tx_fill, + ble_uart_tx_buf + ); + if (active_connection) { + int x = xTaskGetTickCount() - + ble_uart_lasttick; + if (x < 100) { + // Ugly hack if we already send something recently. + // TODO: figure out how fast we can send or use indications + vTaskDelay(100 - x); + } + //printf("notify: "); + //int j; + //for(j=0;j<ble_uart_buf_tx_fill;j++) { + // printf("%02x ", ble_uart_tx_buf[j]); + //} + //printf("\n"); + AttsHandleValueNtf( + active_connection, + UART_TX_HDL, + ble_uart_buf_tx_fill, + ble_uart_tx_buf + ); + ble_uart_lasttick = xTaskGetTickCount(); + } + ble_uart_buf_tx_fill = 0; + } + } + } +} + +void bleuart_init(void) +{ + /* Add the UART service dynamically */ + void *pSHdl; + pSHdl = SvcUARTAddGroupDyn(); + AttsDynRegister(pSHdl, UARTReadCback, UARTWriteCback); + //AttsDynRegister(pSHdl, NULL, UARTWriteCback); +} diff --git a/epicardium/main.c b/epicardium/main.c index c90d008248e0562c184701099be9ff59d7639b60..ebadaf954765295f48d33fe1e703d60ccbaaab05 100644 --- a/epicardium/main.c +++ b/epicardium/main.c @@ -25,6 +25,8 @@ TaskHandle_t dispatcher_task_id; +void vBleTask(void *pvParameters); + /* * API dispatcher task. This task will sleep until an API call is issued and * then wake up to dispatch it. @@ -103,6 +105,18 @@ int main(void) abort(); } + /* BLE */ + if (xTaskCreate( + vBleTask, + (const char *)"BLE", + configMINIMAL_STACK_SIZE * 10, + NULL, + tskIDLE_PRIORITY + 1, + NULL) != pdPASS) { + LOG_CRIT("startup", "Failed to create %s task!", "BLE"); + abort(); + } + LOG_INFO("startup", "Initializing dispatcher ..."); api_dispatcher_init(); diff --git a/epicardium/meson.build b/epicardium/meson.build index c5dc701d6164c79246e9a6aa8bc761c01626b32e..9b3880a81e8dcf3ea17ef76411328cc54a2f15f1 100644 --- a/epicardium/meson.build +++ b/epicardium/meson.build @@ -65,6 +65,7 @@ freertos = static_library( ########################################################################## subdir('modules/') +subdir('ble/') subdir('l0der/') @@ -75,7 +76,8 @@ elf = executable( 'support.c', module_sources, l0der_sources, - dependencies: [libcard10, max32665_startup_core0, maxusb, libff13], + ble_sources, + dependencies: [libcard10, max32665_startup_core0, maxusb, libff13, ble], link_with: [api_dispatcher_lib, freertos], link_whole: [max32665_startup_core0_lib, board_card10_lib, newlib_heap_lib], include_directories: [freertos_includes], diff --git a/epicardium/modules/meson.build b/epicardium/modules/meson.build index 113e3cb8ecaebc932a65ce9e6124cc2ff3be60ce..d02549569f0ae789435567c1115864a1fa2f860f 100644 --- a/epicardium/modules/meson.build +++ b/epicardium/modules/meson.build @@ -9,5 +9,5 @@ module_sources = files( 'stream.c', 'vibra.c', 'light_sensor.c', - 'rtc.c' + 'rtc.c', ) diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h index 182fdae7e1bee27bce1b3d56d94f35bce9eb979e..5dbda13c1af2b98a863077e8813fda66c3fbede2 100644 --- a/epicardium/modules/modules.h +++ b/epicardium/modules/modules.h @@ -1,6 +1,7 @@ #ifndef MODULES_H #define MODULES_H +#include <stdint.h> /* ---------- FAT fs ------------------------------------------------------ */ /* Number of bits to use for indexing into our internal pool of files/directories * This indirectly specifies the size of the pool as 2^EPIC_FAT_FD_INDEX_BITS @@ -15,13 +16,17 @@ void fatfs_init(void); #define SERIAL_READ_BUFFER_SIZE 128 void vSerialTask(void *pvParameters); +void serial_enqueue_char(char chr); + /* ---------- PMIC --------------------------------------------------------- */ /* In 1/10s */ #define PMIC_PRESS_SLEEP 20 #define PMIC_PRESS_POWEROFF 40 void vPmicTask(void *pvParameters); +/* ---------- BLE ---------------------------------------------------------- */ +void ble_uart_write(uint8_t *pValue, uint8_t len); + // Forces an unlock of the display. Only to be used in epicardium void disp_forcelock(); - #endif /* MODULES_H */ diff --git a/epicardium/modules/serial.c b/epicardium/modules/serial.c index 8cffa3ac40f8a66ddcd7dc0c5491cc4b5d8b59f8..db188ebe4474e8ac03cf0dbe773bf00e28e49e6e 100644 --- a/epicardium/modules/serial.c +++ b/epicardium/modules/serial.c @@ -29,6 +29,7 @@ void epic_uart_write_str(const char *str, intptr_t length) { UART_Write(ConsoleUart, (uint8_t *)str, length); cdcacm_write((uint8_t *)str, length); + ble_uart_write((uint8_t *)str, length); } /* @@ -72,7 +73,7 @@ static void uart_callback(uart_req_t *req, int error) portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } -static void enqueue_char(char chr) +void serial_enqueue_char(char chr) { if (chr == 0x3) { /* Control-C */ @@ -122,15 +123,15 @@ void vSerialTask(void *pvParameters) ulTaskNotifyTake(pdTRUE, portTICK_PERIOD_MS * 1000); if (read_req.num > 0) { - enqueue_char(*read_req.data); + serial_enqueue_char(*read_req.data); } while (UART_NumReadAvail(ConsoleUart) > 0) { - enqueue_char(UART_ReadByte(ConsoleUart)); + serial_enqueue_char(UART_ReadByte(ConsoleUart)); } while (cdcacm_num_read_avail() > 0) { - enqueue_char(cdcacm_read()); + serial_enqueue_char(cdcacm_read()); } } } diff --git a/lib/sdk/Libraries/BTLE/meson.build b/lib/sdk/Libraries/BTLE/meson.build index b80f44af67413181f8e89fd75159b4f861a1f354..ab0db720687c87a7cc2763511090fbcfd2370104 100644 --- a/lib/sdk/Libraries/BTLE/meson.build +++ b/lib/sdk/Libraries/BTLE/meson.build @@ -1,3 +1,8 @@ +# cordio-phy.a +cc = meson.get_compiler('c') +libcordiophy = cc.find_library('cordio-phy', dirs: meson.current_source_dir()) + + includes = include_directories( 'wsf/include', 'stack/ble-host/include', @@ -45,7 +50,7 @@ sources = files( 'stack/ble-profiles/sources/apps/watch/watch_main.c', 'stack/ble-profiles/sources/apps/datc/datc_main.c', 'stack/ble-profiles/sources/apps/gluc/gluc_main.c', -'stack/ble-profiles/sources/apps/fit/fit_main.c', +#'stack/ble-profiles/sources/apps/fit/fit_main.c', 'stack/ble-profiles/sources/apps/cycling/cycling_main.c', 'stack/ble-profiles/sources/apps/sensor/sensor_main.c', 'stack/ble-profiles/sources/apps/app/app_disc.c', @@ -54,11 +59,11 @@ sources = files( 'stack/ble-profiles/sources/apps/app/app_master_ae.c', 'stack/ble-profiles/sources/apps/app/app_slave_leg.c', 'stack/ble-profiles/sources/apps/app/app_slave_ae.c', -'stack/ble-profiles/sources/apps/app/app_main.c', +#'stack/ble-profiles/sources/apps/app/app_main.c', 'stack/ble-profiles/sources/apps/app/app_server.c', 'stack/ble-profiles/sources/apps/app/app_master_leg.c', -'stack/ble-profiles/sources/apps/app/common/app_db.c', -'stack/ble-profiles/sources/apps/app/common/app_ui.c', +#'stack/ble-profiles/sources/apps/app/common/app_db.c', +#'stack/ble-profiles/sources/apps/app/common/app_ui.c', 'stack/ble-profiles/sources/apps/app/common/app_hw.c', 'stack/ble-profiles/sources/apps/app/app_terminal.c', 'stack/ble-profiles/sources/apps/wdxs/wdxs_oad.c', @@ -111,7 +116,7 @@ sources = files( 'stack/ble-profiles/sources/services/svc_rscs.c', 'stack/ble-profiles/sources/services/svc_hts.c', 'stack/ble-profiles/sources/services/svc_temp.c', -'stack/ble-profiles/sources/services/svc_core.c', +#'stack/ble-profiles/sources/services/svc_core.c', 'stack/ble-profiles/sources/services/svc_hid.c', 'stack/ble-profiles/sources/services/svc_scpss.c', 'stack/ble-profiles/sources/services/svc_hrs.c', @@ -120,7 +125,7 @@ sources = files( 'stack/ble-profiles/sources/services/svc_ipss.c', 'stack/ble-profiles/sources/services/svc_wdxs.c', 'stack/ble-profiles/sources/services/svc_uricfg.c', -'stack/ble-profiles/sources/services/svc_dis.c', +#'stack/ble-profiles/sources/services/svc_dis.c', 'stack/ble-profiles/sources/services/svc_px.c', 'stack/ble-profiles/sources/services/svc_batt.c', 'stack/ble-profiles/sources/services/svc_wss.c', @@ -409,22 +414,40 @@ sources = files( 'link_layer/controller/sources/common/sch/sch_list.c', ) + +ble_compileargs = [ + '-DWSF_ASSERT_ENABLED=TRUE', + '-DWSF_MS_PER_TICK=1', + '-DINIT_BROADCASTER', + '-DINIT_PERIPHERAL', + '-DINIT_ENCRYPTED', +] + +if get_option('ble_trace') + ble_compileargs += [ + '-DWSF_TRACE_ENABLED=TRUE', + ] +endif + lib = static_library( 'ble', sources, include_directories: includes, - dependencies: periphdriver, - c_args: ['-w', - '-DLHCI_ENABLE_VS=TRUE', - '-DBB_CLK_RATE_HZ=1600000', - '-DLCTR_CONN_NO_TIFS_REASSEMBLY=1', - '-DBB_ENABLE_INLINE_ENC_TX=1', - '-DBB_ENABLE_INLINE_DEC_RX=1', - '-DFORCE_PMU_WAKEUP=1'] + dependencies: [periphdriver, libcordiophy], + c_args: [ + '-w', + '-DLHCI_ENABLE_VS=TRUE', + '-DBB_CLK_RATE_HZ=1600000', + '-DLCTR_CONN_NO_TIFS_REASSEMBLY=1', + '-DBB_ENABLE_INLINE_ENC_TX=1', + '-DBB_ENABLE_INLINE_DEC_RX=1', + '-DFORCE_PMU_WAKEUP=1', + ] + ble_compileargs, ) ble = declare_dependency( include_directories: includes, link_with: lib, - dependencies: periphdriver, + compile_args: ble_compileargs, + dependencies: [periphdriver, libcordiophy], ) diff --git a/lib/sdk/Libraries/BTLE/stack/ble-host/include/svc_core.h b/lib/sdk/Libraries/BTLE/stack/ble-host/include/svc_core.h deleted file mode 100644 index 3555b57143c98c147c3ba88abfee9574ce6656bf..0000000000000000000000000000000000000000 --- a/lib/sdk/Libraries/BTLE/stack/ble-host/include/svc_core.h +++ /dev/null @@ -1,171 +0,0 @@ -/* Copyright (c) 2009-2019 Arm Limited - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/*************************************************************************************************/ -/*! - * \brief Example GATT and GAP service implementations. - */ -/*************************************************************************************************/ - -#ifndef SVC_CORE_H -#define SVC_CORE_H - - -#ifdef __cplusplus -extern "C" { -#endif - -/*! \addtogroup GATT_AND_GAP_SERVICE - * \{ */ - - -/************************************************************************************************** - Handle Ranges -**************************************************************************************************/ -/** \name GAP Service Handles - * \note GAP -- RPAO characterstic added only when DM Privacy enabled - */ -/**@{*/ -#define GAP_START_HDL 0x01 /*!< \brief GAP start handle */ -#define GAP_END_HDL (GAP_MAX_HDL - 3) /*!< \brief GAP end handle */ -/**@}*/ - -/** \name GATT Service Handles - * - */ -/**@{*/ -#define GATT_START_HDL 0x10 /*!< \brief GATT start handle */ -#define GATT_END_HDL (GATT_MAX_HDL - 1) /*!< \brief GATT end handle */ -/**@}*/ - -/************************************************************************************************** - Handles -**************************************************************************************************/ - -/** \name GAP Service Handles - * - */ -/**@{*/ -/*! \brief GAP service handle */ -enum -{ - GAP_SVC_HDL = GAP_START_HDL, /*!< \brief GAP service declaration */ - GAP_DN_CH_HDL, /*!< \brief Device name characteristic */ - GAP_DN_HDL, /*!< \brief Device name */ - GAP_AP_CH_HDL, /*!< \brief Appearance characteristic */ - GAP_AP_HDL, /*!< \brief Appearance */ - GAP_CAR_CH_HDL, /*!< \brief Central address resolution characteristic */ - GAP_CAR_HDL, /*!< \brief Central address resolution */ - GAP_RPAO_CH_HDL, /*!< \brief Resolvable private address only characteristic */ - GAP_RPAO_HDL, /*!< \brief Resolvable private address only */ - GAP_MAX_HDL /*!< \brief GAP maximum handle */ -}; -/**@}*/ - -/** \name GATT Service Handles - * - */ -/**@{*/ -/*! \brief GATT service handles */ -enum -{ - GATT_SVC_HDL = GATT_START_HDL, /*!< \brief GATT service declaration */ - GATT_SC_CH_HDL, /*!< \brief Service changed characteristic */ - GATT_SC_HDL, /*!< \brief Service changed */ - GATT_SC_CH_CCC_HDL, /*!< \brief Service changed client characteristic configuration descriptor */ - GATT_CSF_CH_HDL, /*!< \brief Client supported features characteristic */ - GATT_CSF_HDL, /*!< \brief Client supported features */ - GATT_DBH_CH_HDL, /*!< \brief Database hash characteristic */ - GATT_DBH_HDL, /*!< \brief Database hash */ - GATT_MAX_HDL /*!< \brief GATT maximum handle */ -}; -/**@}*/ - -/************************************************************************************************** - Function Declarations -**************************************************************************************************/ - -/*************************************************************************************************/ -/*! - * \brief Add the services to the attribute server. - * - * \return None. - */ -/*************************************************************************************************/ -void SvcCoreAddGroup(void); - -/*************************************************************************************************/ -/*! - * \brief Remove the services from the attribute server. - * - * \return None. - */ -/*************************************************************************************************/ -void SvcCoreRemoveGroup(void); - -/*************************************************************************************************/ -/*! - * \brief Register callbacks for the service. - * - * \param readCback Read callback function. - * \param writeCback Write callback function. - * - * \return None. - */ -/*************************************************************************************************/ -void SvcCoreGattCbackRegister(attsReadCback_t readCback, attsWriteCback_t writeCback); - -/*************************************************************************************************/ -/*! - * \brief Register callbacks for the service. - * - * \param readCback Read callback function. - * \param writeCback Write callback function. - * - * \return None. - */ -/*************************************************************************************************/ -void SvcCoreGapCbackRegister(attsReadCback_t readCback, attsWriteCback_t writeCback); - -/*************************************************************************************************/ -/*! - * \brief Update the central address resolution attribute value. - * - * \param value New value. - * - * \return None. - */ -/*************************************************************************************************/ -void SvcCoreGapCentAddrResUpdate(bool_t value); - -/*************************************************************************************************/ -/*! - * \brief Add the Resolvable Private Address Only (RPAO) characteristic to the GAP service. - * The RPAO characteristic should be added only when DM Privacy is enabled. - * - * \return None. - */ -/*************************************************************************************************/ -void SvcCoreGapAddRpaoCh(void); - -/*! \} */ /* GATT_AND_GAP_SERVICE */ - -#ifdef __cplusplus -}; -#endif - -#endif /* SVC_CORE_H */ - diff --git a/lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/services/svc_core.h b/lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/services/svc_core.h index 7f246ad711b25e8c6083dc1d05f44e1689dfa003..05dbe5e79d65dd6f45acb23d57e8a5e1e6bb91db 100644 --- a/lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/services/svc_core.h +++ b/lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/services/svc_core.h @@ -33,6 +33,8 @@ extern "C" { Handle Ranges **************************************************************************************************/ /** \name GAP Service Handles + * TODO card10: + * WTF! * \note GAP -- RPAO characterstic added only when DM Privacy enabled */ /**@{*/ diff --git a/lib/sdk/Libraries/BTLE/stack/platform/max32665/wsf_os.c b/lib/sdk/Libraries/BTLE/stack/platform/max32665/wsf_os.c index d4e0c647b0d4be27ee15b89e2b368ff8a72916bf..62012a7d4bb84a58ac72aff1bd1eff0c3047ff8b 100644 --- a/lib/sdk/Libraries/BTLE/stack/platform/max32665/wsf_os.c +++ b/lib/sdk/Libraries/BTLE/stack/platform/max32665/wsf_os.c @@ -132,7 +132,7 @@ void WsfSetEvent(wsfHandlerId_t handlerId, wsfEventMask_t event) WSF_CS_EXIT(cs); /* set event in OS */ - // wsf_mbed_ble_signal_event(); + wsf_ble_signal_event(); } /*************************************************************************************************/ @@ -157,7 +157,7 @@ void WsfTaskSetReady(wsfHandlerId_t handlerId, wsfTaskEvent_t event) WSF_CS_EXIT(cs); /* set event in OS */ - // wsf_mbed_ble_signal_event(); + wsf_ble_signal_event(); } /*************************************************************************************************/ diff --git a/lib/sdk/Libraries/BTLE/wsf/include/wsf_os.h b/lib/sdk/Libraries/BTLE/wsf/include/wsf_os.h index 674ffb73d1f572074448d48066ab141b0c337304..a9ffd502c8009414b4501723a6667bb79c24f950 100644 --- a/lib/sdk/Libraries/BTLE/wsf/include/wsf_os.h +++ b/lib/sdk/Libraries/BTLE/wsf/include/wsf_os.h @@ -216,6 +216,7 @@ void wsfOsDispatcher(void); /*************************************************************************************************/ void WsfOsInit(void); +void wsf_ble_signal_event(void); /*! \} */ /* WSF_OS_API */ #ifdef __cplusplus diff --git a/lib/sdk/Libraries/BTLE/wsf/include/wsf_timer.h b/lib/sdk/Libraries/BTLE/wsf/include/wsf_timer.h index 41259e38c80ec073d008931f4d7f6896ef64bbf1..0ba11f66625fc3c719cf18209f637166f607add9 100644 --- a/lib/sdk/Libraries/BTLE/wsf/include/wsf_timer.h +++ b/lib/sdk/Libraries/BTLE/wsf/include/wsf_timer.h @@ -164,6 +164,8 @@ void WsfTimerSleep(void); /*************************************************************************************************/ void WsfTimerSleepUpdate(void); +void WsfTimerNotify(void); + /*! \} */ /* WSF_TIMER_API */ #ifdef __cplusplus diff --git a/lib/sdk/Libraries/BTLE/wsf/sources/port/baremetal/wsf_timer.c b/lib/sdk/Libraries/BTLE/wsf/sources/port/baremetal/wsf_timer.c index 3ed48a4360efaee01858a83c15e31c64b8afd888..4b0134315c96f2e025f85413830ff80240654c1b 100644 --- a/lib/sdk/Libraries/BTLE/wsf/sources/port/baremetal/wsf_timer.c +++ b/lib/sdk/Libraries/BTLE/wsf/sources/port/baremetal/wsf_timer.c @@ -111,7 +111,9 @@ static void wsfTimerRemove(wsfTimer_t *pTimer) { wsfTimer_t *pElem; wsfTimer_t *pPrev = NULL; + bool_t newHead = FALSE; + /* TODO: why is there no lock here? */ pElem = (wsfTimer_t *) wsfTimerTimerQueue.pHead; /* find timer in queue */ @@ -128,10 +130,21 @@ static void wsfTimerRemove(wsfTimer_t *pTimer) /* if timer found remove from queue */ if (pElem != NULL) { + if (pElem == wsfTimerTimerQueue.pHead) + { + newHead = TRUE; + } WsfQueueRemove(&wsfTimerTimerQueue, pTimer, pPrev); pTimer->isStarted = FALSE; } + + if (newHead) + { + /* We have a new head. Notify the OS. */ + /* TODO: Not sure if this should be inside a lock */ + WsfTimerNotify(); + } } /*************************************************************************************************/ @@ -179,6 +192,13 @@ static void wsfTimerInsert(wsfTimer_t *pTimer, wsfTimerTicks_t ticks) /* task schedule unlock */ WsfTaskUnlock(); + + if(wsfTimerTimerQueue.pHead == pTimer) + { + /* The timer is new head. Notify the OS. */ + /* TODO: Not sure if this should be inside the lock */ + WsfTimerNotify(); + } } /*************************************************************************************************/ @@ -380,6 +400,10 @@ wsfTimer_t *WsfTimerServiceExpired(wsfTaskId_t taskId) WSF_TRACE_INFO1("Timer expired pTimer:0x%x", pElem); + /* We have a new head. Notify the OS. */ + /* TODO: Not sure if this should be inside the lock */ + WsfTimerNotify(); + /* return timer */ return pElem; } diff --git a/meson_options.txt b/meson_options.txt index e0a79c540133acc94716e895ed5e8697cfe2847b..bb96608f53ba3363e9e5a3b96dfb6eb6e11086df 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -5,3 +5,11 @@ option( description: 'Whether to print debug messages on the serial console' ) + +option( + 'ble_trace', + type: 'boolean', + value: false, + + description: 'Whether to enable WSF TRACE prints', +)