Skip to content
Snippets Groups Projects
Commit c0a3ed9e authored by schneider's avatar schneider
Browse files

Merge branch 'schneider/mp-bonding' into 'master'

Bonding dialog

See merge request !390
parents 2c026ff2 7ea488c6
No related branches found
No related tags found
1 merge request!390Bonding dialog
Pipeline #4662 passed
Showing
with 623 additions and 887 deletions
/*************************************************************************************************/
/*!
* \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 */
......@@ -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 */
/*************************************************************************************************/
/*!
* \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 */
......@@ -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();
......
#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
**************************************************************************************************/
......
......@@ -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);
......
#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. */
......
......@@ -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',
......
......@@ -186,5 +186,8 @@ void StackInit(void)
/*TODO card10: Probably want to adjust this */
HciSetMaxRxAclLen(100);
handlerId = WsfOsSetNextHandler(AppHandler);
AppHandlerInit(handlerId);
}
/* clang-format off */
......@@ -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 */
......@@ -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;
}
......
......@@ -289,5 +289,10 @@ int hardware_reset(void)
epic_max86150_disable_sensor();
/*
* BLE
*/
epic_ble_set_bondable(false);
return 0;
}
......@@ -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)
......
......@@ -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',
......
......@@ -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);
}
......
......@@ -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)
......@@ -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',
......
......@@ -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(
......
......@@ -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)
#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);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment