diff --git a/epicardium/ble/app/app_main.c b/epicardium/ble/app/app_main.c deleted file mode 100644 index b279c758bb5857eb3d649fe7cc8c36f7e16ef35f..0000000000000000000000000000000000000000 --- a/epicardium/ble/app/app_main.c +++ /dev/null @@ -1,427 +0,0 @@ -/*************************************************************************************************/ -/*! - * \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" - -#include "modules/log.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); - - LOG_INFO("ble", "Confirm Value: %ld", 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 index cf054afd206ebd22563dec986f99fdc7254ba359..550077784b4b120f430c8933c4a075660aba438e 100644 --- a/epicardium/ble/app/common/app_db.c +++ b/epicardium/ble/app/common/app_db.c @@ -95,12 +95,6 @@ static appDb_t appDb; /*! When all records are allocated use this index to determine which to overwrite */ static appDbRec_t *pAppDbNewRec = appDb.rec; -/* Timer to delay writing to persistent storage until a burst of store() calls has finished */ -static TimerHandle_t store_timer; -static StaticTimer_t store_timer_buffer; -static void store_callback(); -#define STORE_DELAY pdMS_TO_TICKS(5000) - /*************************************************************************************************/ /*! * \brief Initialize the device database. @@ -117,32 +111,12 @@ void AppDbInit(void) memset(&appDb, 0, sizeof(appDb)); } epic_file_close(fd); - } - - store_timer = xTimerCreateStatic( - "appdb_store_timer", - STORE_DELAY, - pdFALSE, - NULL, - store_callback, - &store_timer_buffer - ); -} - -/* TODO this should actually put tasks into a queue. On the other end of the queue */ -/* a worker task can read tasks off the queue and execute them */ -static void store(void) -{ - LOG_INFO("appDb", "store() called, resetting timer"); - if (xTimerReset(store_timer, 10) != pdPASS) { /* (Re)start the timer */ - /* Store timer could not be reset, write to persistent storage anyway */ - store_callback(); } } -static void store_callback() +static void AppDbStore(void) { - LOG_INFO("appDb", "STORE_DELAY passed, writing to persistent storage"); + LOG_INFO("appDb", "writing to persistent storage"); int fd = epic_file_open("pairings.bin", "w"); if(fd >= 0) { @@ -198,7 +172,6 @@ appDbHdl_t AppDbNewRecord(uint8_t addrType, uint8_t *pAddr) pRec->peerAddedToRl = FALSE; pRec->peerRpao = FALSE; - store(); return (appDbHdl_t) pRec; } @@ -263,7 +236,6 @@ appDbHdl_t AppDbGetNextRecord(appDbHdl_t hdl) void AppDbDeleteRecord(appDbHdl_t hdl) { ((appDbRec_t *) hdl)->inUse = FALSE; - store(); } /*************************************************************************************************/ @@ -281,7 +253,7 @@ void AppDbValidateRecord(appDbHdl_t hdl, uint8_t keyMask) { ((appDbRec_t *) hdl)->valid = TRUE; ((appDbRec_t *) hdl)->keyValidMask = keyMask; - store(); + AppDbStore(); } /*************************************************************************************************/ @@ -371,7 +343,6 @@ void AppDbDeleteAllRecords(void) { pRec->inUse = FALSE; } - store(); } /*************************************************************************************************/ @@ -518,7 +489,6 @@ void AppDbSetKey(appDbHdl_t hdl, dmSecKeyIndEvt_t *pKey) default: break; } - store(); } /*************************************************************************************************/ @@ -551,7 +521,6 @@ void AppDbSetCccTblValue(appDbHdl_t hdl, uint16_t idx, uint16_t value) WSF_ASSERT(idx < APP_DB_NUM_CCCD); ((appDbRec_t *) hdl)->cccTbl[idx] = value; - store(); } /*************************************************************************************************/ @@ -581,7 +550,6 @@ uint8_t AppDbGetDiscStatus(appDbHdl_t hdl) void AppDbSetDiscStatus(appDbHdl_t hdl, uint8_t status) { ((appDbRec_t *) hdl)->discStatus = status; - store(); } /*************************************************************************************************/ @@ -611,7 +579,6 @@ uint16_t *AppDbGetHdlList(appDbHdl_t hdl) void AppDbSetHdlList(appDbHdl_t hdl, uint16_t *pHdlList) { memcpy(((appDbRec_t *) hdl)->hdlList, pHdlList, sizeof(((appDbRec_t *) hdl)->hdlList)); - store(); } /*************************************************************************************************/ @@ -654,7 +621,6 @@ void AppDbSetDevName(uint8_t len, char *pStr) len = (len <= sizeof(appDb.devName)) ? len : sizeof(appDb.devName); memcpy(appDb.devName, pStr, len); - store(); } /*************************************************************************************************/ @@ -684,7 +650,6 @@ bool_t AppDbGetPeerAddrRes(appDbHdl_t hdl) void AppDbSetPeerAddrRes(appDbHdl_t hdl, uint8_t addrRes) { ((appDbRec_t *)hdl)->peerAddrRes = addrRes; - store(); } /*************************************************************************************************/ @@ -715,7 +680,6 @@ void AppDbSetPeerSignCounter(appDbHdl_t hdl, uint32_t signCounter) { if(((appDbRec_t *)hdl)->peerSignCounter != signCounter) { ((appDbRec_t *)hdl)->peerSignCounter = signCounter; - store(); } } @@ -746,7 +710,6 @@ bool_t AppDbGetPeerAddedToRl(appDbHdl_t hdl) void AppDbSetPeerAddedToRl(appDbHdl_t hdl, bool_t peerAddedToRl) { ((appDbRec_t *)hdl)->peerAddedToRl = peerAddedToRl; - store(); } /*************************************************************************************************/ @@ -776,6 +739,5 @@ bool_t AppDbGetPeerRpao(appDbHdl_t hdl) void AppDbSetPeerRpao(appDbHdl_t hdl, bool_t peerRpao) { ((appDbRec_t *)hdl)->peerRpao = peerRpao; - store(); } /* clang-format on */ diff --git a/epicardium/ble/app/common/app_ui.c b/epicardium/ble/app/common/app_ui.c deleted file mode 100644 index f5c6f568a2159de62aa9707dab5d1032414d4119..0000000000000000000000000000000000000000 --- a/epicardium/ble/app/common/app_ui.c +++ /dev/null @@ -1,349 +0,0 @@ -/*************************************************************************************************/ -/*! - * \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 card10 - Should disable encryption. MAXIM bug reported to us in current static library. Requires - * this to be called before the BTLE app starts making advertisements. Avoids encryption - * rendering the frame unreadable. - * - * \return None. - */ -/*************************************************************************************************/ -void llc_api_crypto_disable_tx(); - - -/*************************************************************************************************/ -/*! - * \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: - llc_api_crypto_disable_tx(); - 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 index 02c0af400efeb96cccb1f919917dc6111d0a54f6..59b25ef07b761dd4570076cc6994d84b52310ff8 100644 --- a/epicardium/ble/ble.c +++ b/epicardium/ble/ble.c @@ -65,7 +65,6 @@ static int log_lastflushtick = 0; /*! \brief Stack initialization for app. */ extern void StackInit(void); -extern void AppInit(void); extern void bleuart_init(void); extern void bleFileTransfer_init(void); extern void bleCard10_init(void); @@ -441,7 +440,6 @@ void vBleTask(void *pvParameters) BbBleDrvSetTxPower(0); setAddress(); - AppInit(); BleStart(); AttsDynInit(); diff --git a/epicardium/ble/ble_api.h b/epicardium/ble/ble_api.h index 9040f8e436100660b2bbb7c1ef6079cdde07082a..84f27ef5d8de9caa4097524327e9cd372ec3067d 100644 --- a/epicardium/ble/ble_api.h +++ b/epicardium/ble/ble_api.h @@ -1,4 +1,9 @@ #pragma once + +#define CARD10_UUID_SUFFIX \ + 0x42, 0x23, 0x42, 0x23, 0x42, 0x23, 0x42, 0x23, 0x42, 0x23, 0x42, 0x23 +#define CARD10_UUID_PREFIX 0x02, 0x23, 0x42 + /************************************************************************************************** Function Declarations **************************************************************************************************/ diff --git a/epicardium/ble/ble_main.c b/epicardium/ble/ble_main.c index a274f270cbd0d5a74327314eef19c7c7f7dbf75a..c8fef1f669663a21453630743d6861ebee44ace1 100644 --- a/epicardium/ble/ble_main.c +++ b/epicardium/ble/ble_main.c @@ -21,6 +21,7 @@ #include "wsf_msg.h" #include "wsf_trace.h" #include "hci_api.h" +#include "l2c_api.h" #include "dm_api.h" #include "att_api.h" #include "smp_api.h" @@ -39,8 +40,16 @@ #include "rscp/rscp_api.h" #include "cccd.h" +#include "ble_api.h" +#include "epicardium.h" +#include "api/interrupt-sender.h" #include "modules/log.h" +static bool active; +static uint8_t advertising_mode = APP_MODE_NONE; +static uint8_t advertising_mode_target = APP_MODE_NONE; +static enum ble_event_type ble_event; + /************************************************************************************************** Macros **************************************************************************************************/ @@ -74,8 +83,8 @@ typedef union /*! configurable parameters for advertising */ static const appAdvCfg_t bleAdvCfg = { - {0, 0, 0}, /*! Advertising durations in ms */ - {500/0.625, 4000/0.625, 0} /*! Advertising intervals in 0.625 ms units */ + {0, 0}, /*! Advertising durations in ms */ + {500/0.625, 0} /*! Advertising intervals in 0.625 ms units */ }; /*! configurable parameters for slave */ @@ -148,19 +157,17 @@ static const uint8_t bleAdvDataDisc[] = /*! flags */ 2, /*! length */ DM_ADV_TYPE_FLAGS, /*! AD type */ - DM_FLAG_LE_GENERAL_DISC | /*! flags */ + DM_FLAG_LE_LIMITED_DISC | /*! flags */ DM_FLAG_LE_BREDR_NOT_SUP, - /*! tx power */ - 2, /*! length */ - DM_ADV_TYPE_TX_POWER, /*! AD type */ - 0, /*! tx power */ + 3, + DM_ADV_TYPE_APPEARANCE, + UINT16_TO_BYTES(CH_APPEAR_WATCH), /*! 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) + 17, + DM_ADV_TYPE_128_UUID_PART, + CARD10_UUID_SUFFIX, 0x0, CARD10_UUID_PREFIX }; /*! scan data, discoverable mode */ @@ -172,6 +179,16 @@ uint8_t bleScanDataDisc[] = 'c','a','r','d','1','0','-','0','0','0','0','0','0' }; +/*! advertising data, connectable mode */ +static const uint8_t bleAdvDataConn[] = +{ + /*! flags */ + 2, /*! length */ + DM_ADV_TYPE_FLAGS, /*! AD type */ + DM_FLAG_LE_BREDR_NOT_SUP, +}; + + /************************************************************************************************** Client Characteristic Configuration Descriptors **************************************************************************************************/ @@ -191,8 +208,113 @@ static const attsCccSet_t bleCccSet[BLE_NUM_CCC_IDX] = /*! WSF handler ID */ wsfHandlerId_t bleHandlerId; +static dmConnId_t pair_connId = DM_CONN_ID_NONE; +static uint32_t pair_confirm_value; static void BleHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg); + +static const char * const att_events[] = { + "ATTC_FIND_INFO_RSP", + "ATTC_FIND_BY_TYPE_VALUE_RSP", + "ATTC_READ_BY_TYPE_RSP", + "ATTC_READ_RSP", + "ATTC_READ_LONG_RSP", + "ATTC_READ_MULTIPLE_RSP", + "ATTC_READ_BY_GROUP_TYPE_RSP", + "ATTC_WRITE_RSP", + "ATTC_WRITE_CMD_RSP", + "ATTC_PREPARE_WRITE_RSP", + "ATTC_EXECUTE_WRITE_RSP", + "ATTC_HANDLE_VALUE_NTF", + "ATTC_HANDLE_VALUE_IND", + /* ATT server callback events */ + "ATTS_HANDLE_VALUE_CNF", + "ATTS_CCC_STATE_IND", + "ATTS_DB_HASH_CALC_CMPL_IND", + /* ATT common callback events */ + "ATT_MTU_UPDATE_IND" +}; + +static const char * const dm_events[] = { + "DM_RESET_CMPL_IND", + "DM_ADV_START_IND", + "DM_ADV_STOP_IND", + "DM_ADV_NEW_ADDR_IND", + "DM_SCAN_START_IND", + "DM_SCAN_STOP_IND", + "DM_SCAN_REPORT_IND", + "DM_CONN_OPEN_IND", + "DM_CONN_CLOSE_IND", + "DM_CONN_UPDATE_IND", + "DM_SEC_PAIR_CMPL_IND", + "DM_SEC_PAIR_FAIL_IND", + "DM_SEC_ENCRYPT_IND", + "DM_SEC_ENCRYPT_FAIL_IND", + "DM_SEC_AUTH_REQ_IND", + "DM_SEC_KEY_IND", + "DM_SEC_LTK_REQ_IND", + "DM_SEC_PAIR_IND", + "DM_SEC_SLAVE_REQ_IND", + "DM_SEC_CALC_OOB_IND", + "DM_SEC_ECC_KEY_IND", + "DM_SEC_COMPARE_IND", + "DM_SEC_KEYPRESS_IND", + "DM_PRIV_RESOLVED_ADDR_IND", + "DM_PRIV_GENERATE_ADDR_IND", + "DM_CONN_READ_RSSI_IND", + "DM_PRIV_ADD_DEV_TO_RES_LIST_IND", + "DM_PRIV_REM_DEV_FROM_RES_LIST_IND", + "DM_PRIV_CLEAR_RES_LIST_IND", + "DM_PRIV_READ_PEER_RES_ADDR_IND", + "DM_PRIV_READ_LOCAL_RES_ADDR_IND", + "DM_PRIV_SET_ADDR_RES_ENABLE_IND", + "DM_REM_CONN_PARAM_REQ_IND", + "DM_CONN_DATA_LEN_CHANGE_IND", + "DM_CONN_WRITE_AUTH_TO_IND", + "DM_CONN_AUTH_TO_EXPIRED_IND", + "DM_PHY_READ_IND", + "DM_PHY_SET_DEF_IND", + "DM_PHY_UPDATE_IND", + "DM_ADV_SET_START_IND", + "DM_ADV_SET_STOP_IND", + "DM_SCAN_REQ_RCVD_IND", + "DM_EXT_SCAN_START_IND", + "DM_EXT_SCAN_STOP_IND", + "DM_EXT_SCAN_REPORT_IND", + "DM_PER_ADV_SET_START_IND", + "DM_PER_ADV_SET_STOP_IND", + "DM_PER_ADV_SYNC_EST_IND", + "DM_PER_ADV_SYNC_EST_FAIL_IND", + "DM_PER_ADV_SYNC_LOST_IND", + "DM_PER_ADV_SYNC_TRSF_EST_IND", + "DM_PER_ADV_SYNC_TRSF_EST_FAIL_IND", + "DM_PER_ADV_SYNC_TRSF_IND", + "DM_PER_ADV_SET_INFO_TRSF_IND", + "DM_PER_ADV_REPORT_IND", + "DM_REMOTE_FEATURES_IND", + "DM_READ_REMOTE_VER_INFO_IND", + "DM_CONN_IQ_REPORT_IND", + "DM_CTE_REQ_FAIL_IND", + "DM_CONN_CTE_RX_SAMPLE_START_IND", + "DM_CONN_CTE_RX_SAMPLE_STOP_IND", + "DM_CONN_CTE_TX_CFG_IND", + "DM_CONN_CTE_REQ_START_IND", + "DM_CONN_CTE_REQ_STOP_IND", + "DM_CONN_CTE_RSP_START_IND", + "DM_CONN_CTE_RSP_STOP_IND", + "DM_READ_ANTENNA_INFO_IND", + "DM_L2C_CMD_REJ_IND", + "DM_ERROR_IND", + "DM_HW_ERROR_IND", + "DM_VENDOR_SPEC_IND" +}; + +static const char * const l2c_coc_events[] = { + "L2C_COC_CONNECT_IND", + "L2C_COC_DISCONNECT_IND", + "L2C_COC_DATA_IND", + "L2C_COC_DATA_CNF" +}; /*************************************************************************************************/ /*! * \brief Application DM callback. @@ -345,20 +467,114 @@ static void bleSetup(bleMsg_t *pMsg) 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_ADV_DATA_CONNECTABLE, sizeof(bleAdvDataConn), (uint8_t *) bleAdvDataConn); AppAdvSetData(APP_SCAN_DATA_CONNECTABLE, 0, NULL); -#if 0 - /* TODO: card10: until we have an BLE dialog, be discoverable and bondable always */ - /* start advertising; automatically set connectable/discoverable mode and bondable mode */ - AppAdvStart(APP_MODE_AUTO_INIT); -#else - /* enter discoverable and bondable mode mode by default */ - AppSetBondable(TRUE); - AppAdvStart(APP_MODE_DISCOVERABLE); -#endif + active = true; + /* TODO: Sadly, not advertising leads to a higher current consumption... */ + epic_ble_set_bondable(false); +} + +void epic_ble_set_bondable(bool bondable) +{ + if(!active) { + return; + } + + if(bondable) { + /* We need to stop advertising in between or the + * adv set will not be changed. + * Also need to wait for the stop operation to finish + * before we can start again + * Also need to set the variables first as we don't + * have a lock on the stack.*/ + AppSetBondable(TRUE); + if(advertising_mode != APP_MODE_DISCOVERABLE) { + LOG_INFO("ble", "Making bondable and discoverable"); + if(advertising_mode != APP_MODE_NONE) { + advertising_mode_target = APP_MODE_DISCOVERABLE; + advertising_mode = APP_MODE_NONE; + AppAdvStop(); + } else { + advertising_mode = APP_MODE_DISCOVERABLE; + advertising_mode_target = APP_MODE_DISCOVERABLE; + AppAdvStart(advertising_mode); + } + } + } else { + AppSetBondable(FALSE); + if(AppDbCheckBonded()) { + if(advertising_mode != APP_MODE_CONNECTABLE) { + LOG_INFO("ble", "Bonded. Making connectable"); + if(advertising_mode != APP_MODE_NONE) { + advertising_mode_target = APP_MODE_CONNECTABLE; + advertising_mode = APP_MODE_NONE; + AppAdvStop(); + } else { + advertising_mode = APP_MODE_CONNECTABLE; + advertising_mode_target = APP_MODE_CONNECTABLE; + AppAdvStart(advertising_mode); + } + } + } else { + if(advertising_mode != APP_MODE_NONE) { + LOG_INFO("ble", "Not bonded. Stop advertising"); + advertising_mode = APP_MODE_NONE; + advertising_mode_target = APP_MODE_NONE; + AppAdvStop(); + } + } + } +} + +uint32_t epic_ble_get_compare_value(void) +{ + return pair_confirm_value; +} + +void epic_ble_compare_response(bool confirmed) +{ + if(!active) { + return; + } + + if(pair_connId != DM_CONN_ID_NONE) { + LOG_INFO("ble", "Value confirmed: %u", confirmed); + DmSecCompareRsp(pair_connId, confirmed); + } else { + /* error condition */ + } +} +static void trigger_event(enum ble_event_type event) +{ + bool enabled; + epic_interrupt_is_enabled(EPIC_INT_BLE, &enabled); + if(ble_event && enabled) { + LOG_WARN("ble", "Application missed event %u", ble_event); + } + + ble_event = event; + api_interrupt_trigger(EPIC_INT_BLE); +} + +enum ble_event_type epic_ble_get_event(void) +{ + enum ble_event_type event = ble_event; + ble_event = 0; + return event; } +static void bleHandleNumericComparison(dmSecCnfIndEvt_t *pCnfInd) +{ + if(!active) { + return; + } + + pair_connId = (dmConnId_t)pCnfInd->hdr.param; + pair_confirm_value = DmSecGetCompareValue(pCnfInd->confirm); + LOG_INFO("ble", "Confirm Value: %ld", pair_confirm_value); + trigger_event(BLE_EVENT_HANDLE_NUMERIC_COMPARISON); +} /*************************************************************************************************/ /*! @@ -371,7 +587,6 @@ static void bleSetup(bleMsg_t *pMsg) /*************************************************************************************************/ static void bleProcMsg(bleMsg_t *pMsg) { - uint8_t uiEvent = APP_UI_NONE; hciLeConnCmplEvt_t *connOpen; switch(pMsg->hdr.event) @@ -391,17 +606,22 @@ static void bleProcMsg(bleMsg_t *pMsg) case DM_RESET_CMPL_IND: DmSecGenerateEccKeyReq(); bleSetup(pMsg); - uiEvent = APP_UI_RESET_CMPL; break; case DM_ADV_START_IND: - LOG_INFO("ble", "Advertisement started"); - uiEvent = APP_UI_ADV_START; + LOG_INFO("ble", "Advertisement started %u %u", advertising_mode, advertising_mode_target); + if(advertising_mode != advertising_mode_target) { + AppAdvStop(); + } + break; case DM_ADV_STOP_IND: - LOG_INFO("ble", "Advertisement stopped"); - uiEvent = APP_UI_ADV_STOP; + LOG_INFO("ble", "Advertisement stopped %u %u", advertising_mode, advertising_mode_target); + if(advertising_mode != advertising_mode_target) { + advertising_mode = advertising_mode_target; + AppAdvStart(advertising_mode); + } break; case DM_CONN_OPEN_IND: @@ -411,7 +631,6 @@ static void bleProcMsg(bleMsg_t *pMsg) connOpen->peerAddr[3], connOpen->peerAddr[2], connOpen->peerAddr[1], connOpen->peerAddr[0]); BasProcMsg(&pMsg->hdr); - uiEvent = APP_UI_CONN_OPEN; break; case DM_CONN_CLOSE_IND: @@ -442,14 +661,20 @@ static void bleProcMsg(bleMsg_t *pMsg) pMsg->dm.connClose.reason); break; } + /* Stack overwrites advertising mode after connection close. + * Force our desired mode. + */ + advertising_mode = APP_MODE_NONE; + AppAdvStop(); + bleClose(pMsg); - uiEvent = APP_UI_CONN_CLOSE; break; case DM_SEC_PAIR_CMPL_IND: LOG_INFO("ble", "Secure pairing successful, auth: 0x%02X", pMsg->dm.pairCmpl.auth); - uiEvent = APP_UI_SEC_PAIR_CMPL; + pair_connId = DM_CONN_ID_NONE; + trigger_event(BLE_EVENT_PAIRING_COMPLETE); /* After a successful pairing, bonding is disabled again. * We don't want that for now. */ AppSetBondable(TRUE); @@ -470,17 +695,16 @@ static void bleProcMsg(bleMsg_t *pMsg) pMsg->hdr.status); break; } - uiEvent = APP_UI_SEC_PAIR_FAIL; + pair_connId = DM_CONN_ID_NONE; + trigger_event(BLE_EVENT_PAIRING_FAILED); break; case DM_SEC_ENCRYPT_IND: LOG_INFO("ble", "Encrypted handshake successful"); - uiEvent = APP_UI_SEC_ENCRYPT; break; case DM_SEC_ENCRYPT_FAIL_IND: LOG_INFO("ble", "Encrypted handshake failed"); - uiEvent = APP_UI_SEC_ENCRYPT_FAIL; break; case DM_SEC_AUTH_REQ_IND: @@ -492,22 +716,16 @@ static void bleProcMsg(bleMsg_t *pMsg) break; case DM_SEC_COMPARE_IND: - AppHandleNumericComparison(&pMsg->dm.cnfInd); + bleHandleNumericComparison(&pMsg->dm.cnfInd); break; case DM_HW_ERROR_IND: LOG_ERR("ble", "HW Error"); - uiEvent = APP_UI_HW_ERROR; break; default: break; } - - if (uiEvent != APP_UI_NONE) - { - AppUiAction(uiEvent); - } } /*************************************************************************************************/ @@ -561,12 +779,25 @@ static void BleHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg) if (pMsg->event >= DM_CBACK_START && pMsg->event <= DM_CBACK_END) { + LOG_INFO("ble", "Ble got evt %d: %s", pMsg->event, dm_events[pMsg->event - DM_CBACK_START]); /* process advertising and connection-related messages */ AppSlaveProcDmMsg((dmEvt_t *) pMsg); /* process security-related messages */ AppSlaveSecProcDmMsg((dmEvt_t *) pMsg); } + else if (pMsg->event >= ATT_CBACK_START && pMsg->event <= ATT_CBACK_END) + { + LOG_INFO("ble", "Ble got evt %d: %s", pMsg->event, att_events[pMsg->event - ATT_CBACK_START]); + } + else if (pMsg->event >= L2C_COC_CBACK_START && pMsg->event <= L2C_COC_CBACK_CBACK_END) + { + LOG_INFO("ble", "Ble got evt %d: %s", pMsg->event, l2c_coc_events[pMsg->event - L2C_COC_CBACK_START]); + } + else + { + LOG_INFO("ble", "Ble got evt %d", pMsg->event); + } /* perform profile and user interface-related operations */ bleProcMsg((bleMsg_t *) pMsg); diff --git a/epicardium/ble/card10.c b/epicardium/ble/card10.c index c7fa728a42afdf5049268980a1d77deb15019524..eb9c0a2beb70fb4b7f5c4edacd24149f0c8a6b29 100644 --- a/epicardium/ble/card10.c +++ b/epicardium/ble/card10.c @@ -1,19 +1,17 @@ +#include "ble_api.h" + +#include "epicardium.h" + #include "wsf_types.h" #include "util/bstream.h" #include "wsf_assert.h" #include "att_api.h" -#include "epicardium.h" - #include <stdio.h> #include <string.h> #include <stdbool.h> #include <machine/endian.h> -#define CARD10_UUID_SUFFIX \ - 0x42, 0x23, 0x42, 0x23, 0x42, 0x23, 0x42, 0x23, 0x42, 0x23, 0x42, 0x23 -#define CARD10_UUID_PREFIX 0x02, 0x23, 0x42 - /*!< \brief Service start handle. */ #define CARD10_START_HDL 0x920 /*!< \brief Service end handle. */ diff --git a/epicardium/ble/meson.build b/epicardium/ble/meson.build index c531ae9a95d310bc4fa3b80fbac513505cb09c8f..41280358b05f0d04c470049a6d841fbea0c92fe2 100644 --- a/epicardium/ble/meson.build +++ b/epicardium/ble/meson.build @@ -4,9 +4,7 @@ ble_sources = files( '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', 'card10.c', 'filetransfer.c', diff --git a/epicardium/ble/stack.c b/epicardium/ble/stack.c index f96f2c113ae01f849a0c3b942d76c630b25e534b..a7896b68fa7c35a9d85a173b67d495ae95204e8d 100644 --- a/epicardium/ble/stack.c +++ b/epicardium/ble/stack.c @@ -186,5 +186,8 @@ void StackInit(void) /*TODO card10: Probably want to adjust this */ HciSetMaxRxAclLen(100); + + handlerId = WsfOsSetNextHandler(AppHandler); + AppHandlerInit(handlerId); } /* clang-format off */ diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index 65a29744e752e4bf4f50f507cdae11f60df1d4d2..2ab3126f3400a95b92a8765389dd0173218b9904 100644 --- a/epicardium/epicardium.h +++ b/epicardium/epicardium.h @@ -36,6 +36,7 @@ typedef _Bool bool; #define API_INTERRUPT_ENABLE 0xA #define API_INTERRUPT_DISABLE 0xB +#define API_INTERRUPT_IS_ENABLED 0xC #define API_UART_WRITE_STR 0x10 #define API_UART_READ_CHAR 0x11 @@ -147,6 +148,12 @@ typedef _Bool bool; #define API_CONFIG_GET_INTEGER 0x131 #define API_CONFIG_GET_BOOLEAN 0x132 #define API_CONFIG_SET_STRING 0x133 + +#define API_BLE_GET_COMPARE_VALUE 0x140 +#define API_BLE_COMPARE_RESPONSE 0x141 +#define API_BLE_SET_BONDABLE 0x142 +#define API_BLE_GET_EVENT 0x143 + /* clang-format on */ typedef uint32_t api_int_id_t; @@ -185,6 +192,19 @@ API(API_INTERRUPT_ENABLE, int epic_interrupt_enable(api_int_id_t int_id)); */ API(API_INTERRUPT_DISABLE, int epic_interrupt_disable(api_int_id_t int_id)); +/** + * Check if an API interrupt is enabled. + * + * :param int int_id: The interrupt to be checked + * :param bool* enabled: ``true`` will be stored here if the interrupt is enabled. + * ``false`` otherwise. + * + * :return: 0 on success, ``-EINVAL`` if the interrupt is unknown. + * + * .. versionadded:: 1.16 + */ +API(API_INTERRUPT_IS_ENABLED, int epic_interrupt_is_enabled(api_int_id_t int_id, bool *enabled)); + /** * The following interrupts are defined: */ @@ -210,9 +230,10 @@ API(API_INTERRUPT_DISABLE, int epic_interrupt_disable(api_int_id_t int_id)); #define EPIC_INT_BHI160_MAGNETOMETER 8 /** MAX86150 ECG and PPG sensor. See :c:func:`epic_isr_max86150`. */ #define EPIC_INT_MAX86150 9 - +/** Bluetooth Low Energy event. See :c:func:`epic_isr_ble`. */ +#define EPIC_INT_BLE 10 /* Number of defined interrupts. */ -#define EPIC_INT_NUM 10 +#define EPIC_INT_NUM 11 /* clang-format on */ /* @@ -2095,5 +2116,108 @@ API(API_CONFIG_GET_STRING, int epic_config_get_string(const char *key, char *buf * .. versionadded:: 1.16 */ API(API_CONFIG_SET_STRING, int epic_config_set_string(const char *key, const char *value)); + + +/** + * Bluetooth Low Energy (BLE) + * ========================== + */ + +/** + * BLE event type + */ +enum ble_event_type { + /** No event pending */ + BLE_EVENT_NONE = 0, + /** Numeric comparison requested */ + BLE_EVENT_HANDLE_NUMERIC_COMPARISON = 1, + /** A pairing procedure has failed */ + BLE_EVENT_PAIRING_FAILED = 2, + /** A pairing procedure has successfully completed */ + BLE_EVENT_PAIRING_COMPLETE = 3, +}; + + +/** + * **Interrupt Service Routine** for :c:data:`EPIC_INT_BLE` + * + * :c:func:`epic_isr_ble` is called when the BLE stack wants to signal an + * event to the application. You can use :c:func:`epic_ble_get_event` to obtain + * the event which triggered this interrupt. + * + * Currently supported events: + * + * :c:data:`BLE_EVENT_HANDLE_NUMERIC_COMPARISON`: + * An ongoing pairing procedure requires a numeric comparison to complete. + * The compare value can be retreived using :c:func:`epic_ble_get_compare_value`. + * + * :c:data:`BLE_EVENT_PAIRING_FAILED`: + * A pairing procedure failed. The stack automatically went back advertising + * and accepting new pairings. + * + * :c:data:`BLE_EVENT_PAIRING_COMPLETE`: + * A pairing procedure has completed sucessfully. + * The stack automatically persists the pairing information, creating a bond. + * + * .. versionadded:: 1.16 + */ +API_ISR(EPIC_INT_BLE, epic_isr_ble); + +/** + * Retreive the event which triggered :c:func:`epic_isr_ble` + * + * The handling code needs to ensure to handle interrupts in a timely + * manner as new events will overwrite each other. Reading the event + * automatically resets it to :c:data:`BLE_EVENT_NONE`. + * + * :return: Event which triggered the interrupt. + * + * .. versionadded:: 1.16 + */ +API(API_BLE_GET_EVENT, enum ble_event_type epic_ble_get_event(void)); + +/** + * Retrieve the compare value of an ongoing pairing procedure. + * + * If no pairing procedure is ongoing, the returned value is undefined. + * + * :return: 6 digit long compare value + * + * .. versionadded:: 1.16 + */ +API(API_BLE_GET_COMPARE_VALUE, uint32_t epic_ble_get_compare_value(void)); + +/** + * Indicate wether the user confirmed the compare value. + * + * If a pariring procedure involving a compare value is ongoing and this + * function is called with confirmed set to ``true``, it will try to + * proceed and complete the pairing process. If called with ``false``, the + * pairing procedure will be aborted. + * + * :param bool confirmed: `true` if the user confirmed the compare value. + * + * .. versionadded:: 1.16 + */ +API(API_BLE_COMPARE_RESPONSE, void epic_ble_compare_response(bool confirmed)); + +/** + * Allow or disallow new bondings to happen + * + * By default the card10 will not allow new bondings to be made. New + * bondings have to explicitly allowed by calling this function. + * + * While bonadable the card10 will change its advertisements to + * indicate to scanning hosts that it is available for discovery. + * + * When switching applications new bondings are automatically + * disallowed. + * + * :param bool bondable: `true` if new bondings should be allowed. + * + * .. versionadded:: 1.16 + */ +API(API_BLE_SET_BONDABLE, void epic_ble_set_bondable(bool bondable)); + #endif /* _EPICARDIUM_H */ diff --git a/epicardium/modules/config.c b/epicardium/modules/config.c index d4c2b74e0b2fed4915ae2670a8da39b078f6042c..cae7bde65f4e6b563fa24bb964c698f054ee3764 100644 --- a/epicardium/modules/config.c +++ b/epicardium/modules/config.c @@ -511,7 +511,7 @@ int epic_config_set_string(const char *key, const char *value_in) slot->value_offset, buf, sizeof(buf) ); if (nread == 0) { - LOG_DEBUG("card10.cfg", "could not read old value", ); + LOG_DEBUG("card10.cfg", "could not read old value"); goto complex_out; } diff --git a/epicardium/modules/hardware.c b/epicardium/modules/hardware.c index 6d118fe73ef59007c4e3cb915afdba004e678d56..1168f5a756d81ee3e3d16a15e5e4c703314b2b7a 100644 --- a/epicardium/modules/hardware.c +++ b/epicardium/modules/hardware.c @@ -289,5 +289,10 @@ int hardware_reset(void) epic_max86150_disable_sensor(); + /* + * BLE + */ + epic_ble_set_bondable(false); + return 0; } diff --git a/epicardium/modules/interrupts.c b/epicardium/modules/interrupts.c index 0ead54fc58b1d6341071cd377a8ab239bbbff8e7..d65505ea5a0629b5934057e81599d9c35d6ec454 100644 --- a/epicardium/modules/interrupts.c +++ b/epicardium/modules/interrupts.c @@ -78,6 +78,17 @@ static void interrupt_set_enabled(api_int_id_t id, bool enabled) mutex_unlock(&interrupt_mutex); } +static bool interrupt_get_enabled(api_int_id_t id) +{ + assert(id < EPIC_INT_NUM); + + bool enabled; + mutex_lock(&interrupt_mutex); + enabled = interrupt_data.int_enabled[id]; + mutex_unlock(&interrupt_mutex); + return enabled; +} + void interrupt_init(void) { if (interrupt_mutex.name == NULL) @@ -114,6 +125,17 @@ int epic_interrupt_disable(api_int_id_t int_id) interrupt_set_enabled(int_id, false); return 0; } + +int epic_interrupt_is_enabled(api_int_id_t int_id, bool *enabled) +{ + if (int_id >= EPIC_INT_NUM) { + return -EINVAL; + } + + *enabled = interrupt_get_enabled(int_id); + return 0; +} + /* }}} */ void vInterruptsTask(void *pvParameters) diff --git a/lib/sdk/Libraries/BTLE/meson.build b/lib/sdk/Libraries/BTLE/meson.build index ab0db720687c87a7cc2763511090fbcfd2370104..6dd10ee6a04dc62c8036da9681b739fa64ecf328 100644 --- a/lib/sdk/Libraries/BTLE/meson.build +++ b/lib/sdk/Libraries/BTLE/meson.build @@ -59,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_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', diff --git a/lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/apps/app/app_slave.c b/lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/apps/app/app_slave.c index bc298c74595898cbbbd05fa3dc9333e41c66505b..fa2a857c1357310749330ef63f36e00a25dfecac 100644 --- a/lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/apps/app/app_slave.c +++ b/lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/apps/app/app_slave.c @@ -206,6 +206,12 @@ static void appSetAdvScanDataFrag(uint8_t advHandle, uint8_t location) remainLen = appSlaveCb.maxAdvDataLen[advHandle]; } + if(remainLen == 0) + { + op = HCI_ADV_DATA_OP_COMP_FRAG; + DmAdvSetData(advHandle, op, APP_LOC_2_DM_LOC(location), 0, NULL); + } + /* while there remains data to be sent */ while (remainLen > 0) { @@ -257,13 +263,15 @@ static void appSetAdvScanData(uint8_t advHandle, uint8_t mode) scanLoc = APP_MODE_2_SCAN_LOC(mode); /* set advertising data */ - if (appSlaveCb.advDataOffset[advHandle][advLoc] < appSlaveCb.advDataLen[advHandle][advLoc]) + if (appSlaveCb.advDataOffset[advHandle][advLoc] < appSlaveCb.advDataLen[advHandle][advLoc] || + appSlaveCb.advDataLen[advHandle][advLoc] == 0) { appSetAdvScanDataFrag(advHandle, advLoc); } /* set scan data */ - if (appSlaveCb.advDataOffset[advHandle][scanLoc] < appSlaveCb.advDataLen[advHandle][scanLoc]) + if (appSlaveCb.advDataOffset[advHandle][scanLoc] < appSlaveCb.advDataLen[advHandle][scanLoc] || + appSlaveCb.advDataLen[advHandle][scanLoc] == 0) { appSetAdvScanDataFrag(advHandle, scanLoc); } diff --git a/preload/apps/ble/__init__.py b/preload/apps/ble/__init__.py index acf0b13530997eefaea87483283d978edf938c89..d5b0b7163a0ef44664a587bce87d8acb47af0628 100644 --- a/preload/apps/ble/__init__.py +++ b/preload/apps/ble/__init__.py @@ -2,17 +2,28 @@ import os import display import time import buttons +import sys_ble +import interrupt CONFIG_NAME = "ble.txt" MAC_NAME = "mac.txt" ACTIVE_STRING = "active=true" INACTIVE_STRING = "active=false" +ble_event = None + + +def ble_callback(_): + global ble_event + ble_event = sys_ble.get_event() def init(): if CONFIG_NAME not in os.listdir("."): with open(CONFIG_NAME, "w") as f: f.write(INACTIVE_STRING) + interrupt.set_callback(interrupt.BLE, ble_callback) + interrupt.enable_callback(interrupt.BLE) + sys_ble.set_bondable(True) def load_mac(): @@ -67,21 +78,81 @@ def selector(): disp.print("toggle", posx=25, posy=40, fg=[255, 255, 255]) -disp = display.open() -button_pressed = True init() +disp = display.open() +state = 1 +v_old = buttons.read() while True: - disp.clear() - headline() - v = buttons.read(buttons.TOP_RIGHT) - if v == 0: - button_pressed = False - - if not button_pressed and v & buttons.TOP_RIGHT != 0: - button_pressed = True - toggle() + v_new = buttons.read() + v = ~v_old & v_new + v_old = v_new + + if state == 1: + # print config screen + disp.clear() + headline() + selector() + disp.update() + state = 2 + elif state == 2: + # wait for button press or ble_event + if ble_event == sys_ble.EVENT_HANDLE_NUMERIC_COMPARISON: + ble_event = None + state = 3 + if v & buttons.TOP_RIGHT: + toggle() + state = 1 + + elif state == 3: + # print confirmation value + compare_value = sys_ble.get_compare_value() + disp.clear() + disp.print("BLE: Bond?", posy=0, fg=[0, 0, 255]) + disp.print("Code:", posy=20, fg=[0, 255, 255]) + disp.print(" %06d" % compare_value, posy=40, fg=[255, 255, 255]) + disp.print("Yes", posy=60, fg=[0, 255, 0]) + disp.print("No", posx=120, posy=60, fg=[255, 0, 0]) + + disp.update() + state = 4 + elif state == 4: + # wait for button press or ble_event + if ble_event == sys_ble.EVENT_PAIRING_FAILED: + ble_event = None + state = 6 + if v & buttons.BOTTOM_LEFT: + sys_ble.confirm_compare_value(True) + disp.clear() + disp.print("BLE Bonding", posy=0, fg=[0, 0, 255]) + disp.print("Please Wait", posy=40, fg=[255, 255, 255]) + disp.update() + state = 5 + elif v & (buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT): + sys_ble.confirm_compare_value(False) + state = 6 + + elif state == 5: + # Wait for pairing to complete + if ble_event == sys_ble.EVENT_PAIRING_FAILED: + ble_event = None + state = 6 + elif ble_event == sys_ble.EVENT_PAIRING_COMPLETE: + ble_event = None + disp.clear() + disp.print("BLE Bonding", posy=0, fg=[0, 0, 255]) + disp.print(" Success", posy=40, fg=[0, 255, 0]) + disp.update() + time.sleep(5) + os.exec("main.py") + + elif state == 6: + # display fail screen and wait 5 seconds + disp.clear() + disp.print("BLE Bonding", posy=0, fg=[0, 0, 255]) + disp.print(" Fail", posy=40, fg=[255, 0, 0]) + disp.update() + time.sleep(5) + state = 1 - selector() - disp.update() time.sleep(0.1) diff --git a/pycardium/meson.build b/pycardium/meson.build index d12e62f5ed6e58cd8699890a404ffc23a4b33f15..bd01afb49f403ec057b533285aef86da173cc334 100644 --- a/pycardium/meson.build +++ b/pycardium/meson.build @@ -14,6 +14,7 @@ modsrc = files( 'modules/os.c', 'modules/personal_state.c', 'modules/power.c', + 'modules/sys_ble.c', 'modules/sys_bme680.c', 'modules/sys_display.c', 'modules/sys_leds.c', diff --git a/pycardium/modules/interrupt.c b/pycardium/modules/interrupt.c index ad3b86d73424c91bfe6dde576f92dd4a842da968..1e7fcd89ff85d0940611f37ae170e0321aa04a27 100644 --- a/pycardium/modules/interrupt.c +++ b/pycardium/modules/interrupt.c @@ -99,6 +99,7 @@ static const mp_rom_map_elem_t interrupt_module_globals_table[] = { MP_OBJ_NEW_SMALL_INT(EPIC_INT_MAX30001_ECG) }, { MP_ROM_QSTR(MP_QSTR_MAX86150), MP_OBJ_NEW_SMALL_INT(EPIC_INT_MAX86150) }, + { MP_ROM_QSTR(MP_QSTR_BLE), MP_OBJ_NEW_SMALL_INT(EPIC_INT_BLE) }, }; static MP_DEFINE_CONST_DICT( diff --git a/pycardium/modules/qstrdefs.h b/pycardium/modules/qstrdefs.h index 2fed1b2c12052473bf878c2fb1536304df3be6fd..eb52eba6bb0334b3c02ef5857b64d7c86cf58800 100644 --- a/pycardium/modules/qstrdefs.h +++ b/pycardium/modules/qstrdefs.h @@ -190,6 +190,20 @@ Q(MAX86150) Q(ws2812) Q(set_all) +/* config */ Q(config) Q(set_string) Q(get_string) + +/* BLE */ +Q(BLE) +Q(ble) +Q(get_compare_value) +Q(confirm_compare_value) +Q(set_bondable) +Q(get_event) +Q(EVENT_NONE) +Q(EVENT_HANDLE_NUMERIC_COMPARISON) +Q(EVENT_PAIRING_COMPLETE) +Q(EVENT_PAIRING_FAILED) + diff --git a/pycardium/modules/sys_ble.c b/pycardium/modules/sys_ble.c new file mode 100644 index 0000000000000000000000000000000000000000..d262ce4100889f5c8489384a448b12b14ced653a --- /dev/null +++ b/pycardium/modules/sys_ble.c @@ -0,0 +1,71 @@ +#include "epicardium.h" + +#include "py/obj.h" +#include "py/objlist.h" +#include "py/runtime.h" + +#include <stdint.h> + +static mp_obj_t mp_ble_confirm_compare_value(mp_obj_t confirmed_obj) +{ + bool confirmed = mp_obj_is_true(confirmed_obj); + epic_ble_compare_response(confirmed); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1( + ble_confirm_compare_value_obj, mp_ble_confirm_compare_value +); + +static mp_obj_t mp_ble_get_compare_value(void) +{ + return mp_obj_new_int(epic_ble_get_compare_value()); +} +static MP_DEFINE_CONST_FUN_OBJ_0( + ble_get_compare_value_obj, mp_ble_get_compare_value +); + +static mp_obj_t mp_ble_get_event(void) +{ + return mp_obj_new_int(epic_ble_get_event()); +} +static MP_DEFINE_CONST_FUN_OBJ_0(ble_get_event_obj, mp_ble_get_event); + +static mp_obj_t mp_ble_set_bondable(mp_obj_t bondable_obj) +{ + bool bondable = mp_obj_is_true(bondable_obj); + epic_ble_set_bondable(bondable); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(ble_set_bondable_obj, mp_ble_set_bondable); + +static const mp_rom_map_elem_t ble_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sys_ble) }, + { MP_ROM_QSTR(MP_QSTR_confirm_compare_value), + MP_ROM_PTR(&ble_confirm_compare_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_compare_value), + MP_ROM_PTR(&ble_get_compare_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_event), MP_ROM_PTR(&ble_get_event_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_bondable), + MP_ROM_PTR(&ble_set_bondable_obj) }, + + /* Event Numbers */ + { MP_ROM_QSTR(MP_QSTR_EVENT_NONE), + MP_OBJ_NEW_SMALL_INT(BLE_EVENT_NONE) }, + { MP_ROM_QSTR(MP_QSTR_EVENT_HANDLE_NUMERIC_COMPARISON), + MP_OBJ_NEW_SMALL_INT(BLE_EVENT_HANDLE_NUMERIC_COMPARISON) }, + { MP_ROM_QSTR(MP_QSTR_EVENT_PAIRING_FAILED), + MP_OBJ_NEW_SMALL_INT(BLE_EVENT_PAIRING_FAILED) }, + { MP_ROM_QSTR(MP_QSTR_EVENT_PAIRING_COMPLETE), + MP_OBJ_NEW_SMALL_INT(BLE_EVENT_PAIRING_COMPLETE) }, + +}; +static MP_DEFINE_CONST_DICT(ble_module_globals, ble_module_globals_table); + +const mp_obj_module_t ble_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&ble_module_globals, +}; + +/* Register the module to make it available in Python */ +/* clang-format off */ +MP_REGISTER_MODULE(MP_QSTR_sys_ble, ble_module, MODULE_BLE_ENABLED); diff --git a/pycardium/mpconfigport.h b/pycardium/mpconfigport.h index 463891e0b3fb7db8fcdf33a4255a1218b65e2f82..7a57e34f645b0695cb1a0bb7d712caca65ea89b8 100644 --- a/pycardium/mpconfigport.h +++ b/pycardium/mpconfigport.h @@ -71,6 +71,7 @@ int mp_hal_trng_read_int(void); #define MODULE_VIBRA_ENABLED (1) #define MODULE_WS2812_ENABLED (1) #define MODULE_CONFIG_ENABLED (1) +#define MODULE_BLE_ENABLED (1) /* * This port is intended to be 32-bit, but unfortunately, int32_t for