initial commit
This commit is contained in:
Vendored
+102
@@ -0,0 +1,102 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Health/medical collector sample application.
|
||||
*
|
||||
* Copyright (c) 2012-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef MEDC_API_H
|
||||
#define MEDC_API_H
|
||||
|
||||
#include "wsf_os.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Profile identifier used for MedcSetProfile() */
|
||||
enum
|
||||
{
|
||||
MEDC_ID_HRP, /*! Heart rate profile */
|
||||
MEDC_ID_BLP, /*! Blood pressure profile */
|
||||
MEDC_ID_GLP, /*! Glucose profile */
|
||||
MEDC_ID_WSP, /*! Weight scale profile */
|
||||
MEDC_ID_HTP, /*! Health thermometer profile */
|
||||
MEDC_ID_PLX /*! Pulse oximeter profile */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start the application.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void MedcStart(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Application handler init function called during system initialization.
|
||||
*
|
||||
* \param handlerID WSF handler ID for App.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void MedcHandlerInit(wsfHandlerId_t handlerId);
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WSF event handler for the application.
|
||||
*
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void MedcHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the profile to be used by the application. This function is called internally
|
||||
* by MedcHandlerInit() with a default value. It may also be called by the system
|
||||
* to configure the profile after executing MedcHandlerInit() and before executing
|
||||
* MedcStart().
|
||||
*
|
||||
* \param profile Profile identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void MedcSetProfile(uint8_t profile);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* MEDC_API_H */
|
||||
Vendored
+220
@@ -0,0 +1,220 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Health/medical collector, Blood Pressure profile
|
||||
*
|
||||
* Copyright (c) 2012-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "app_cfg.h"
|
||||
#include "app_api.h"
|
||||
#include "app_db.h"
|
||||
#include "svc_ch.h"
|
||||
#include "blpc/blpc_api.h"
|
||||
#include "medc/medc_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Discovery Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Start of cached blood pressure service handles; begins after DIS */
|
||||
#define MEDC_DISC_BPS_START (MEDC_DISC_DIS_START + DIS_HDL_LIST_LEN)
|
||||
|
||||
/* Total cached handle list length */
|
||||
#define MEDC_DISC_HDL_LIST_LEN (MEDC_DISC_BPS_START + BLPC_BPS_HDL_LIST_LEN)
|
||||
|
||||
/*! Pointers into handle list for blood pressure service handles */
|
||||
static uint16_t *pMedcBpsHdlList = &medcCb.hdlList[MEDC_DISC_BPS_START];
|
||||
|
||||
/* sanity check: make sure handle list length is <= app db handle list length */
|
||||
WSF_CT_ASSERT(MEDC_DISC_HDL_LIST_LEN <= APP_DB_HDL_LIST_LEN);
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Configuration Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/* List of characteristics to configure after service discovery */
|
||||
static const attcDiscCfg_t medcCfgBpsList[] =
|
||||
{
|
||||
/* Read: Blood pressure feature */
|
||||
{NULL, 0, BLPC_BPS_BPF_HDL_IDX},
|
||||
|
||||
/* Write: Blood pressure measurement CCC descriptor */
|
||||
{medcCccIndVal, sizeof(medcCccIndVal), BLPC_BPS_BPM_CCC_HDL_IDX},
|
||||
|
||||
/* Write: Intermediate cuff pressure CCC descriptor */
|
||||
{medcCccNtfVal, sizeof(medcCccNtfVal), BLPC_BPS_ICP_CCC_HDL_IDX},
|
||||
};
|
||||
|
||||
/* Characteristic configuration list length */
|
||||
#define MEDC_CFG_BPS_LIST_LEN (sizeof(medcCfgBpsList) / sizeof(attcDiscCfg_t))
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void medcBlpInit(void);
|
||||
static bool_t medcBlpDiscover(dmConnId_t connId);
|
||||
static void medcBlpConfigure(dmConnId_t connId, uint8_t status);
|
||||
static void medcBlpProcMsg(wsfMsgHdr_t *pMsg);
|
||||
static void medcBlpBtn(dmConnId_t connId, uint8_t btn);
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! profile interface pointer */
|
||||
medcIf_t medcBlpIf =
|
||||
{
|
||||
medcBlpInit,
|
||||
medcBlpDiscover,
|
||||
medcBlpConfigure,
|
||||
medcBlpProcMsg,
|
||||
medcBlpBtn
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a received ATT read response, notification, or indication.
|
||||
*
|
||||
* \param pMsg Pointer to ATT callback event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcBpsValueUpdate(attEvt_t *pMsg)
|
||||
{
|
||||
if (pMsg->hdr.status == ATT_SUCCESS)
|
||||
{
|
||||
/* determine which profile the handle belongs to; start with most likely */
|
||||
|
||||
/* blood pressure */
|
||||
if (BlpcBpsValueUpdate(pMedcBpsHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* device information */
|
||||
if (DisValueUpdate(pMedcDisHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* GATT */
|
||||
if (GattValueUpdate(pMedcGattHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process messages from the event handler.
|
||||
*
|
||||
* \param pMsg Pointer to message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcBlpProcMsg(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
switch(pMsg->event)
|
||||
{
|
||||
case ATTC_READ_RSP:
|
||||
case ATTC_HANDLE_VALUE_NTF:
|
||||
case ATTC_HANDLE_VALUE_IND:
|
||||
medcBpsValueUpdate((attEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Profile initialization function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcBlpInit(void)
|
||||
{
|
||||
/* set handle list length */
|
||||
medcCb.hdlListLen = MEDC_DISC_HDL_LIST_LEN;
|
||||
|
||||
/* set autoconnect UUID */
|
||||
medcCb.autoUuid[0] = ATT_UUID_BLOOD_PRESSURE_SERVICE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Discover service for profile.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return TRUE - finished discovering services. FALSE - more services are to be discovered.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t medcBlpDiscover(dmConnId_t connId)
|
||||
{
|
||||
/* discover blood pressure service */
|
||||
BlpcBpsDiscover(connId, pMedcBpsHdlList);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure service for profile.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param status APP_DISC_CFG_START or APP_DISC_CFG_CONN_START.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcBlpConfigure(dmConnId_t connId, uint8_t status)
|
||||
{
|
||||
/* configure blood pressure service */
|
||||
AppDiscConfigure(connId, status, MEDC_CFG_BPS_LIST_LEN,
|
||||
(attcDiscCfg_t *) medcCfgBpsList,
|
||||
BLPC_BPS_HDL_LIST_LEN, pMedcBpsHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a button press.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param btn Button press.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcBlpBtn(dmConnId_t connId, uint8_t btn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Vendored
+344
@@ -0,0 +1,344 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Health/medical collector, glucose profile
|
||||
*
|
||||
* Copyright (c) 2012-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "app_cfg.h"
|
||||
#include "app_api.h"
|
||||
#include "app_db.h"
|
||||
#include "app_ui.h"
|
||||
#include "svc_ch.h"
|
||||
#include "glpc/glpc_api.h"
|
||||
#include "medc/medc_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Discovery Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Start of cached glucose service handles; begins after DIS */
|
||||
#define MEDC_DISC_GLS_START (MEDC_DISC_DIS_START + DIS_HDL_LIST_LEN)
|
||||
|
||||
/* Total cached handle list length */
|
||||
#define MEDC_DISC_HDL_LIST_LEN (MEDC_DISC_GLS_START + GLPC_GLS_HDL_LIST_LEN)
|
||||
|
||||
/*! Pointers into handle list for glucose service handles */
|
||||
static uint16_t *pMedcGlsHdlList = &medcCb.hdlList[MEDC_DISC_GLS_START];
|
||||
|
||||
/* sanity check: make sure handle list length is <= app db handle list length */
|
||||
WSF_CT_ASSERT(MEDC_DISC_HDL_LIST_LEN <= APP_DB_HDL_LIST_LEN);
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Configuration Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/* List of characteristics to configure after service discovery */
|
||||
static const attcDiscCfg_t medcCfgGlsList[] =
|
||||
{
|
||||
/* Read: glucose feature */
|
||||
{NULL, 0, GLPC_GLS_GLF_HDL_IDX},
|
||||
|
||||
/* Write: glucose measurement CCC descriptor */
|
||||
{medcCccNtfVal, sizeof(medcCccIndVal), GLPC_GLS_GLM_CCC_HDL_IDX},
|
||||
|
||||
/* Write: glucose measurement context CCC descriptor */
|
||||
{medcCccNtfVal, sizeof(medcCccIndVal), GLPC_GLS_GLMC_CCC_HDL_IDX},
|
||||
|
||||
/* Write: record access control point CCC descriptor */
|
||||
{medcCccIndVal, sizeof(medcCccIndVal), GLPC_GLS_RACP_CCC_HDL_IDX}
|
||||
};
|
||||
|
||||
/* Characteristic configuration list length */
|
||||
#define MEDC_CFG_GLS_LIST_LEN (sizeof(medcCfgGlsList) / sizeof(attcDiscCfg_t))
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
static struct
|
||||
{
|
||||
wsfTimer_t racpTimer; /*! RACP procedure timer */
|
||||
bool_t inProgress; /*! RACP procedure in progress */
|
||||
} medcGlpCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void medcGlpInit(void);
|
||||
static bool_t medcGlpDiscover(dmConnId_t connId);
|
||||
static void medcGlpConfigure(dmConnId_t connId, uint8_t status);
|
||||
static void medcGlpProcMsg(wsfMsgHdr_t *pMsg);
|
||||
static void medcGlpBtn(dmConnId_t connId, uint8_t btn);
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! profile interface pointer */
|
||||
medcIf_t medcGlpIf =
|
||||
{
|
||||
medcGlpInit,
|
||||
medcGlpDiscover,
|
||||
medcGlpConfigure,
|
||||
medcGlpProcMsg,
|
||||
medcGlpBtn
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a received ATT read response, notification, or indication.
|
||||
*
|
||||
* \param pMsg Pointer to ATT callback event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcGlsValueUpdate(attEvt_t *pMsg)
|
||||
{
|
||||
if (pMsg->hdr.status == ATT_SUCCESS)
|
||||
{
|
||||
/* determine which profile the handle belongs to; start with most likely */
|
||||
|
||||
/* glucose */
|
||||
if (GlpcGlsValueUpdate(pMedcGlsHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* device information */
|
||||
if (DisValueUpdate(pMedcDisHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* GATT */
|
||||
if (GattValueUpdate(pMedcGattHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Profile initialization function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcGlpInit(void)
|
||||
{
|
||||
/* set handle list length */
|
||||
medcCb.hdlListLen = MEDC_DISC_HDL_LIST_LEN;
|
||||
|
||||
/* set autoconnect UUID */
|
||||
medcCb.autoUuid[0] = ATT_UUID_GLUCOSE_SERVICE;
|
||||
|
||||
/* initialize timer */
|
||||
medcGlpCb.racpTimer.handlerId = medcCb.handlerId;
|
||||
medcGlpCb.racpTimer.msg.event = MEDC_TIMER_IND;
|
||||
|
||||
/* initialize sequence number */
|
||||
GlpcGlsSetLastSeqNum(1);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Discover service for profile.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return TRUE - finished discovering services. FALSE - more services are to be discovered.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t medcGlpDiscover(dmConnId_t connId)
|
||||
{
|
||||
/* discover glucose service */
|
||||
GlpcGlsDiscover(connId, pMedcGlsHdlList);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure service for profile.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param status APP_DISC_CFG_START or APP_DISC_CFG_CONN_START.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcGlpConfigure(dmConnId_t connId, uint8_t status)
|
||||
{
|
||||
/* configure glucose service */
|
||||
AppDiscConfigure(connId, status, MEDC_CFG_GLS_LIST_LEN,
|
||||
(attcDiscCfg_t *) medcCfgGlsList,
|
||||
GLPC_GLS_HDL_LIST_LEN, pMedcGlsHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process messages from the event handler.
|
||||
*
|
||||
* \param pMsg Pointer to message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcGlpProcMsg(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
switch(pMsg->event)
|
||||
{
|
||||
case ATTC_READ_RSP:
|
||||
case ATTC_HANDLE_VALUE_NTF:
|
||||
/* process value update */
|
||||
medcGlsValueUpdate((attEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
case ATTC_WRITE_RSP:
|
||||
/* if write to RACP was successful, start procedure timer */
|
||||
if ((((attEvt_t *) pMsg)->hdr.status == ATT_SUCCESS) &&
|
||||
(((attEvt_t *) pMsg)->handle == pMedcGlsHdlList[GLPC_GLS_RACP_HDL_IDX]))
|
||||
{
|
||||
medcGlpCb.inProgress = TRUE;
|
||||
medcGlpCb.racpTimer.msg.param = pMsg->param; /* conn ID */
|
||||
WsfTimerStartSec(&medcGlpCb.racpTimer, ATT_MAX_TRANS_TIMEOUT);
|
||||
}
|
||||
break;
|
||||
|
||||
case ATTC_HANDLE_VALUE_IND:
|
||||
/* if procedure in progress stop procedure timer */
|
||||
if (medcGlpCb.inProgress)
|
||||
{
|
||||
medcGlpCb.inProgress = FALSE;
|
||||
WsfTimerStop(&medcGlpCb.racpTimer);
|
||||
}
|
||||
|
||||
/* process value */
|
||||
medcGlsValueUpdate((attEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
case DM_CONN_CLOSE_IND:
|
||||
/* if procedure in progress stop procedure timer */
|
||||
if (medcGlpCb.inProgress)
|
||||
{
|
||||
medcGlpCb.inProgress = FALSE;
|
||||
WsfTimerStop(&medcGlpCb.racpTimer);
|
||||
}
|
||||
break;
|
||||
|
||||
case MEDC_TIMER_IND:
|
||||
/* if procedure in progress then close connection */
|
||||
if (medcGlpCb.inProgress && pMsg->param != DM_CONN_ID_NONE)
|
||||
{
|
||||
medcGlpCb.inProgress = FALSE;
|
||||
|
||||
/* if configured to disconnect upon ATT transaction timeout */
|
||||
if (pAppCfg->disconnect)
|
||||
{
|
||||
AppConnClose((dmConnId_t)pMsg->param);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a button press.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param btn Button press.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcGlpBtn(dmConnId_t connId, uint8_t btn)
|
||||
{
|
||||
glpcFilter_t filter;
|
||||
|
||||
/* button actions when connected */
|
||||
if (connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
/* handle must be set to send RACP command */
|
||||
if (pMedcGlsHdlList[GLPC_GLS_RACP_HDL_IDX] == ATT_HANDLE_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (btn)
|
||||
{
|
||||
case APP_UI_BTN_1_SHORT:
|
||||
/* report all records */
|
||||
GlpcGlsRacpSend(connId, pMedcGlsHdlList[GLPC_GLS_RACP_HDL_IDX],
|
||||
CH_RACP_OPCODE_REPORT, CH_RACP_OPERATOR_ALL, NULL);
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_1_MED:
|
||||
/* report records greater than sequence number */
|
||||
filter.type = CH_RACP_GLS_FILTER_SEQ;
|
||||
filter.param.seqNum = GlpcGlsGetLastSeqNum();
|
||||
GlpcGlsRacpSend(connId, pMedcGlsHdlList[GLPC_GLS_RACP_HDL_IDX],
|
||||
CH_RACP_OPCODE_REPORT, CH_RACP_OPERATOR_GTEQ, &filter);
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_SHORT:
|
||||
/* report number of records */
|
||||
GlpcGlsRacpSend(connId, pMedcGlsHdlList[GLPC_GLS_RACP_HDL_IDX],
|
||||
CH_RACP_OPCODE_REPORT_NUM, CH_RACP_OPERATOR_ALL, NULL);
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_MED:
|
||||
/* report number of records greater than sequence number */
|
||||
filter.type = CH_RACP_GLS_FILTER_SEQ;
|
||||
filter.param.seqNum = GlpcGlsGetLastSeqNum();
|
||||
GlpcGlsRacpSend(connId, pMedcGlsHdlList[GLPC_GLS_RACP_HDL_IDX],
|
||||
CH_RACP_OPCODE_REPORT_NUM, CH_RACP_OPERATOR_GTEQ, &filter);
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_LONG:
|
||||
/* abort */
|
||||
GlpcGlsRacpSend(connId, pMedcGlsHdlList[GLPC_GLS_RACP_HDL_IDX],
|
||||
CH_RACP_OPCODE_ABORT, CH_RACP_OPERATOR_NULL, NULL);
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_EX_LONG:
|
||||
/* delete all records */
|
||||
GlpcGlsRacpSend(connId, pMedcGlsHdlList[GLPC_GLS_RACP_HDL_IDX],
|
||||
CH_RACP_OPCODE_DELETE, CH_RACP_OPERATOR_ALL, NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+223
@@ -0,0 +1,223 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Health/medical collector, Heart Rate profile
|
||||
*
|
||||
* Copyright (c) 2012-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "app_cfg.h"
|
||||
#include "app_api.h"
|
||||
#include "app_db.h"
|
||||
#include "svc_ch.h"
|
||||
#include "hrpc/hrpc_api.h"
|
||||
#include "medc/medc_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Discovery Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Start of cached heart rate service handles; begins after DIS */
|
||||
#define MEDC_DISC_HRS_START (MEDC_DISC_DIS_START + DIS_HDL_LIST_LEN)
|
||||
|
||||
/* Total cached handle list length */
|
||||
#define MEDC_DISC_HDL_LIST_LEN (MEDC_DISC_HRS_START + HRPC_HRS_HDL_LIST_LEN)
|
||||
|
||||
/*! Pointers into handle list heart rate service handles */
|
||||
static uint16_t *pMedcHrsHdlList = &medcCb.hdlList[MEDC_DISC_HRS_START];
|
||||
|
||||
/* sanity check: make sure handle list length is <= app db handle list length */
|
||||
WSF_CT_ASSERT(MEDC_DISC_HDL_LIST_LEN <= APP_DB_HDL_LIST_LEN);
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Configuration Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/* HRS Control point "Reset Energy Expended" */
|
||||
static const uint8_t medcHrsRstEnExp[] = {CH_HRCP_RESET_ENERGY_EXP};
|
||||
|
||||
/* List of characteristics to configure after service discovery */
|
||||
static const attcDiscCfg_t medcCfgHrsList[] =
|
||||
{
|
||||
/* Read: HRS Body sensor location */
|
||||
{NULL, 0, HRPC_HRS_BSL_HDL_IDX},
|
||||
|
||||
/* Write: HRS Control point "Reset Energy Expended" */
|
||||
{medcHrsRstEnExp, sizeof(medcHrsRstEnExp), HRPC_HRS_HRCP_HDL_IDX},
|
||||
|
||||
/* Write: HRS Heart rate measurement CCC descriptor */
|
||||
{medcCccNtfVal, sizeof(medcCccNtfVal), HRPC_HRS_HRM_CCC_HDL_IDX},
|
||||
};
|
||||
|
||||
/* Characteristic configuration list length */
|
||||
#define MEDC_CFG_HRS_LIST_LEN (sizeof(medcCfgHrsList) / sizeof(attcDiscCfg_t))
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void medcHrpInit(void);
|
||||
static bool_t medcHrpDiscover(dmConnId_t connId);
|
||||
static void medcHrpConfigure(dmConnId_t connId, uint8_t status);
|
||||
static void medcHrpProcMsg(wsfMsgHdr_t *pMsg);
|
||||
static void medcHrpBtn(dmConnId_t connId, uint8_t btn);
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! profile interface pointer */
|
||||
medcIf_t medcHrpIf =
|
||||
{
|
||||
medcHrpInit,
|
||||
medcHrpDiscover,
|
||||
medcHrpConfigure,
|
||||
medcHrpProcMsg,
|
||||
medcHrpBtn
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a received ATT read response, notification, or indication.
|
||||
*
|
||||
* \param pMsg Pointer to ATT callback event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcHrsValueUpdate(attEvt_t *pMsg)
|
||||
{
|
||||
if (pMsg->hdr.status == ATT_SUCCESS)
|
||||
{
|
||||
/* determine which profile the handle belongs to; start with most likely */
|
||||
|
||||
/* heart rate */
|
||||
if (HrpcHrsValueUpdate(pMedcHrsHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* device information */
|
||||
if (DisValueUpdate(pMedcDisHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* GATT */
|
||||
if (GattValueUpdate(pMedcGattHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process messages from the event handler.
|
||||
*
|
||||
* \param pMsg Pointer to message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcHrpProcMsg(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
switch(pMsg->event)
|
||||
{
|
||||
case ATTC_READ_RSP:
|
||||
case ATTC_HANDLE_VALUE_NTF:
|
||||
case ATTC_HANDLE_VALUE_IND:
|
||||
medcHrsValueUpdate((attEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Profile initialization function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcHrpInit(void)
|
||||
{
|
||||
/* set handle list length */
|
||||
medcCb.hdlListLen = MEDC_DISC_HDL_LIST_LEN;
|
||||
|
||||
/* set autoconnect UUID */
|
||||
medcCb.autoUuid[0] = ATT_UUID_HEART_RATE_SERVICE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Discover service for profile.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return TRUE - finished discovering services. FALSE - more services are to be discovered.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t medcHrpDiscover(dmConnId_t connId)
|
||||
{
|
||||
/* discover heart rate service */
|
||||
HrpcHrsDiscover(connId, pMedcHrsHdlList);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure service for profile.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param status APP_DISC_CFG_START or APP_DISC_CFG_CONN_START.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcHrpConfigure(dmConnId_t connId, uint8_t status)
|
||||
{
|
||||
/* configure heart rate service */
|
||||
AppDiscConfigure(connId, status, MEDC_CFG_HRS_LIST_LEN,
|
||||
(attcDiscCfg_t *) medcCfgHrsList,
|
||||
HRPC_HRS_HDL_LIST_LEN, pMedcHrsHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a button press.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param btn Button press.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcHrpBtn(dmConnId_t connId, uint8_t btn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Vendored
+220
@@ -0,0 +1,220 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Health/medical collector, Health Thermometer profile
|
||||
*
|
||||
* Copyright (c) 2012-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "app_cfg.h"
|
||||
#include "app_api.h"
|
||||
#include "app_db.h"
|
||||
#include "svc_ch.h"
|
||||
#include "htpc/htpc_api.h"
|
||||
#include "medc/medc_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Discovery Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Start of cached health thermometer service handles; begins after DIS */
|
||||
#define MEDC_DISC_HTS_START (MEDC_DISC_DIS_START + DIS_HDL_LIST_LEN)
|
||||
|
||||
/* Total cached handle list length */
|
||||
#define MEDC_DISC_HDL_LIST_LEN (MEDC_DISC_HTS_START + HTPC_HTS_HDL_LIST_LEN)
|
||||
|
||||
/*! Pointers into handle list for health thermometer service handles */
|
||||
static uint16_t *pMedcHtsHdlList = &medcCb.hdlList[MEDC_DISC_HTS_START];
|
||||
|
||||
/* sanity check: make sure handle list length is <= app db handle list length */
|
||||
WSF_CT_ASSERT(MEDC_DISC_HDL_LIST_LEN <= APP_DB_HDL_LIST_LEN);
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Configuration Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/* List of characteristics to configure after service discovery */
|
||||
static const attcDiscCfg_t medcCfgHtsList[] =
|
||||
{
|
||||
/* Read: Temperature type */
|
||||
{NULL, 0, HTPC_HTS_TT_HDL_IDX},
|
||||
|
||||
/* Write: Temperature measurement CCC descriptor */
|
||||
{medcCccIndVal, sizeof(medcCccIndVal), HTPC_HTS_TM_CCC_HDL_IDX},
|
||||
|
||||
/* Write: Intermediate temperature CCC descriptor */
|
||||
{medcCccNtfVal, sizeof(medcCccNtfVal), HTPC_HTS_IT_CCC_HDL_IDX},
|
||||
};
|
||||
|
||||
/* Characteristic configuration list length */
|
||||
#define MEDC_CFG_HTS_LIST_LEN (sizeof(medcCfgHtsList) / sizeof(attcDiscCfg_t))
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void medcHtpInit(void);
|
||||
static bool_t medcHtpDiscover(dmConnId_t connId);
|
||||
static void medcHtpConfigure(dmConnId_t connId, uint8_t status);
|
||||
static void medcHtpProcMsg(wsfMsgHdr_t *pMsg);
|
||||
static void medcHtpBtn(dmConnId_t connId, uint8_t btn);
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! profile interface pointer */
|
||||
medcIf_t medcHtpIf =
|
||||
{
|
||||
medcHtpInit,
|
||||
medcHtpDiscover,
|
||||
medcHtpConfigure,
|
||||
medcHtpProcMsg,
|
||||
medcHtpBtn
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a received ATT read response, notification, or indication.
|
||||
*
|
||||
* \param pMsg Pointer to ATT callback event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcHtsValueUpdate(attEvt_t *pMsg)
|
||||
{
|
||||
if (pMsg->hdr.status == ATT_SUCCESS)
|
||||
{
|
||||
/* determine which profile the handle belongs to; start with most likely */
|
||||
|
||||
/* health thermometer */
|
||||
if (HtpcHtsValueUpdate(pMedcHtsHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* device information */
|
||||
if (DisValueUpdate(pMedcDisHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* GATT */
|
||||
if (GattValueUpdate(pMedcGattHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process messages from the event handler.
|
||||
*
|
||||
* \param pMsg Pointer to message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcHtpProcMsg(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
switch(pMsg->event)
|
||||
{
|
||||
case ATTC_READ_RSP:
|
||||
case ATTC_HANDLE_VALUE_NTF:
|
||||
case ATTC_HANDLE_VALUE_IND:
|
||||
medcHtsValueUpdate((attEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Profile initialization function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcHtpInit(void)
|
||||
{
|
||||
/* set handle list length */
|
||||
medcCb.hdlListLen = MEDC_DISC_HDL_LIST_LEN;
|
||||
|
||||
/* set autoconnect UUID */
|
||||
medcCb.autoUuid[0] = ATT_UUID_HEALTH_THERM_SERVICE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Discover service for profile.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return TRUE - finished discovering services. FALSE - more services are to be discovered.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t medcHtpDiscover(dmConnId_t connId)
|
||||
{
|
||||
/* discover health thermometer service */
|
||||
HtpcHtsDiscover(connId, pMedcHtsHdlList);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure service for profile.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param status APP_DISC_CFG_START or APP_DISC_CFG_CONN_START.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcHtpConfigure(dmConnId_t connId, uint8_t status)
|
||||
{
|
||||
/* configure health thermometer service */
|
||||
AppDiscConfigure(connId, status, MEDC_CFG_HTS_LIST_LEN,
|
||||
(attcDiscCfg_t *) medcCfgHtsList,
|
||||
HTPC_HTS_HDL_LIST_LEN, pMedcHtsHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a button press.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param btn Button press.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcHtpBtn(dmConnId_t connId, uint8_t btn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Vendored
+940
@@ -0,0 +1,940 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Health/medical collector sample application for the following profiles:
|
||||
* Heart Rate profile collector
|
||||
* Blood Pressure profile collector
|
||||
* Glucose profile collector
|
||||
* Weight scale profile collector
|
||||
* Health Thermometer profile collector
|
||||
* Pulse Oximeter profile collector
|
||||
*
|
||||
* Copyright (c) 2012-2019 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "util/bstream.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "hci_api.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "smp_api.h"
|
||||
#include "app_cfg.h"
|
||||
#include "app_api.h"
|
||||
#include "app_db.h"
|
||||
#include "app_ui.h"
|
||||
#include "svc_ch.h"
|
||||
#include "svc_core.h"
|
||||
#include "gatt/gatt_api.h"
|
||||
#include "dis/dis_api.h"
|
||||
#include "medc/medc_api.h"
|
||||
#include "medc/medc_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Profile Configuration
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Heart rate profile included */
|
||||
#ifndef MEDC_HRP_INCLUDED
|
||||
#define MEDC_HRP_INCLUDED TRUE
|
||||
#endif
|
||||
|
||||
/* Blood pressure profile included */
|
||||
#ifndef MEDC_BLP_INCLUDED
|
||||
#define MEDC_BLP_INCLUDED TRUE
|
||||
#endif
|
||||
|
||||
/* Glucose profile included */
|
||||
#ifndef MEDC_GLP_INCLUDED
|
||||
#define MEDC_GLP_INCLUDED TRUE
|
||||
#endif
|
||||
|
||||
/* Weight scale profile included */
|
||||
#ifndef MEDC_WSP_INCLUDED
|
||||
#define MEDC_WSP_INCLUDED TRUE
|
||||
#endif
|
||||
|
||||
/* Health thermometer profile included */
|
||||
#ifndef MEDC_HTP_INCLUDED
|
||||
#define MEDC_HTP_INCLUDED TRUE
|
||||
#endif
|
||||
|
||||
/* Pulse oximeter profile included */
|
||||
#ifndef MEDC_PLX_INCLUDED
|
||||
#define MEDC_PLX_INCLUDED TRUE
|
||||
#endif
|
||||
|
||||
/* Default profile to use */
|
||||
#ifndef MEDC_PROFILE
|
||||
#define MEDC_PROFILE MEDC_ID_HRP
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Configurable Parameters
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! configurable parameters for master */
|
||||
const appMasterCfg_t medcMasterCfg =
|
||||
{
|
||||
96, /*! The scan interval, in 0.625 ms units */
|
||||
48, /*! The scan window, in 0.625 ms units */
|
||||
4000, /*! The scan duration in ms */
|
||||
DM_DISC_MODE_NONE, /*! The GAP discovery mode */
|
||||
DM_SCAN_TYPE_ACTIVE /*! The scan type (active or passive) */
|
||||
};
|
||||
|
||||
/*! configurable parameters for security */
|
||||
static const appSecCfg_t medcSecCfg =
|
||||
{
|
||||
DM_AUTH_BOND_FLAG, /*! Authentication and bonding flags */
|
||||
0, /*! Initiator key distribution flags */
|
||||
DM_KEY_DIST_LTK, /*! Responder key distribution flags */
|
||||
FALSE, /*! TRUE if Out-of-band pairing data is present */
|
||||
FALSE /*! TRUE to initiate security upon connection */
|
||||
};
|
||||
|
||||
/*! SMP security parameter configuration */
|
||||
static const smpCfg_t medcSmpCfg =
|
||||
{
|
||||
500, /*! 'Repeated attempts' timeout in msec */
|
||||
SMP_IO_DISP_ONLY, /*! I/O Capability */
|
||||
7, /*! Minimum encryption key length */
|
||||
16, /*! Maximum encryption key length */
|
||||
1, /*! Attempts to trigger 'repeated attempts' timeout */
|
||||
0, /*! Device authentication requirements */
|
||||
64000, /*! Maximum repeated attempts timeout in msec */
|
||||
64000, /*! Time msec before attemptExp decreases */
|
||||
2 /*! Repeated attempts multiplier exponent */
|
||||
};
|
||||
|
||||
/*! Connection parameters */
|
||||
static const hciConnSpec_t medcConnCfg =
|
||||
{
|
||||
40, /*! Minimum connection interval in 1.25ms units */
|
||||
40, /*! Maximum connection interval in 1.25ms units */
|
||||
0, /*! Connection latency */
|
||||
600, /*! Supervision timeout in 10ms units */
|
||||
0, /*! Unused */
|
||||
0 /*! Unused */
|
||||
};
|
||||
|
||||
/*! Configurable parameters for service and characteristic discovery */
|
||||
static const appDiscCfg_t medcDiscCfg =
|
||||
{
|
||||
FALSE, /*! TRUE to wait for a secure connection before initiating discovery */
|
||||
FALSE /*! TRUE to fall back on database hash to verify handles when no bond exists. */
|
||||
};
|
||||
|
||||
static const appCfg_t medcAppCfg =
|
||||
{
|
||||
TRUE, /*! TRUE to abort service discovery if service not found */
|
||||
TRUE /*! TRUE to disconnect if ATT transaction times out */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Discovery Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Discovery states: enumeration of services to be discovered */
|
||||
enum
|
||||
{
|
||||
MEDC_DISC_GATT_SVC, /*! GATT service */
|
||||
MEDC_DISC_DIS_SVC, /*! Device Information service */
|
||||
MEDC_DISC_MED_SVC, /*! Configured med. service */
|
||||
MEDC_DISC_SVC_MAX /*! Discovery complete */
|
||||
};
|
||||
|
||||
/*! Pointers into handle list for each service's handles */
|
||||
uint16_t *pMedcGattHdlList = &medcCb.hdlList[MEDC_DISC_GATT_START];
|
||||
uint16_t *pMedcDisHdlList = &medcCb.hdlList[MEDC_DISC_DIS_START];
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Configuration Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Configuration states: enumeration of services to be discovered */
|
||||
enum
|
||||
{
|
||||
MEDC_CFG_DIS_SVC, /*! DIS services */
|
||||
MEDC_CFG_GATT_SVC, /*! GATT services */
|
||||
MEDC_CFG_MED_SVC, /*! Configured med. service */
|
||||
MEDC_CFG_SVC_MAX /*! Configuration complete */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data for configuration after service discovery
|
||||
*/
|
||||
|
||||
/* Default value for CCC indications */
|
||||
const uint8_t medcCccIndVal[2] = {UINT16_TO_BYTES(ATT_CLIENT_CFG_INDICATE)};
|
||||
|
||||
/* Default value for CCC notifications */
|
||||
const uint8_t medcCccNtfVal[2] = {UINT16_TO_BYTES(ATT_CLIENT_CFG_NOTIFY)};
|
||||
|
||||
/* Default value for Client Supported Features (enable Robust Caching) */
|
||||
const uint8_t medcCsfVal[1] = {ATTS_CSF_ROBUST_CACHING};
|
||||
|
||||
/* HRS Control point "Reset Energy Expended" */
|
||||
/* static const uint8_t medcHrsRstEnExp[] = {CH_HRCP_RESET_ENERGY_EXP}; */\
|
||||
|
||||
/* List of DIS characteristics to configure after service discovery */
|
||||
static const attcDiscCfg_t medcCfgDisList[] =
|
||||
{
|
||||
/* Read: DIS Manufacturer name string */
|
||||
{NULL, 0, DIS_MFNS_HDL_IDX},
|
||||
|
||||
/* Read: DIS Model number string */
|
||||
{NULL, 0, DIS_MNS_HDL_IDX},
|
||||
|
||||
/* Read: DIS Serial number string */
|
||||
{NULL, 0, DIS_SNS_HDL_IDX},
|
||||
|
||||
/* Read: DIS Hardware revision string */
|
||||
{NULL, 0, DIS_HRS_HDL_IDX},
|
||||
|
||||
/* Read: DIS Firmware revision string */
|
||||
{NULL, 0, DIS_FRS_HDL_IDX},
|
||||
|
||||
/* Read: DIS Software revision string */
|
||||
{NULL, 0, DIS_SRS_HDL_IDX},
|
||||
|
||||
/* Read: DIS System ID */
|
||||
{NULL, 0, DIS_SID_HDL_IDX}
|
||||
};
|
||||
|
||||
/* List of GATT characteristics to configure after service discovery */
|
||||
static const attcDiscCfg_t medcCfgGattList[] =
|
||||
{
|
||||
/* Write: GATT service changed ccc descriptor */
|
||||
{medcCccIndVal, sizeof(medcCccIndVal), GATT_SC_CCC_HDL_IDX},
|
||||
|
||||
/* Write: GATT client supported features */
|
||||
{medcCsfVal, sizeof(medcCsfVal), GATT_CSF_HDL_IDX},
|
||||
};
|
||||
|
||||
/* Characteristic configuration list length */
|
||||
#define MEDC_CFG_GATT_LIST_LEN (sizeof(medcCfgGattList) / sizeof(attcDiscCfg_t))
|
||||
#define MEDC_CFG_DIS_LIST_LEN (sizeof(medcCfgDisList) / sizeof(attcDiscCfg_t))
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! application control block */
|
||||
medcCb_t medcCb;
|
||||
|
||||
/*! connection control block */
|
||||
typedef struct {
|
||||
appDbHdl_t dbHdl; /*! Device database record handle type */
|
||||
uint8_t addrType; /*! Type of address of device to connect to */
|
||||
bdAddr_t addr; /*! Address of device to connect to */
|
||||
bool_t doConnect; /*! TRUE to issue connect on scan complete */
|
||||
} medcConnInfo_t;
|
||||
|
||||
medcConnInfo_t medcConnInfo;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Application DM callback.
|
||||
*
|
||||
* \param pDmEvt DM callback event
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcDmCback(dmEvt_t *pDmEvt)
|
||||
{
|
||||
dmEvt_t *pMsg;
|
||||
uint16_t len;
|
||||
uint16_t reportLen;
|
||||
|
||||
len = DmSizeOfEvt(pDmEvt);
|
||||
|
||||
if (pDmEvt->hdr.event == DM_SCAN_REPORT_IND)
|
||||
{
|
||||
reportLen = pDmEvt->scanReport.len;
|
||||
}
|
||||
else
|
||||
{
|
||||
reportLen = 0;
|
||||
}
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(len + reportLen)) != NULL)
|
||||
{
|
||||
memcpy(pMsg, pDmEvt, len);
|
||||
if (pDmEvt->hdr.event == DM_SCAN_REPORT_IND)
|
||||
{
|
||||
pMsg->scanReport.pData = (uint8_t *) ((uint8_t *) pMsg + len);
|
||||
memcpy(pMsg->scanReport.pData, pDmEvt->scanReport.pData, reportLen);
|
||||
}
|
||||
WsfMsgSend(medcCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Application ATT callback.
|
||||
*
|
||||
* \param pEvt ATT callback event
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcAttCback(attEvt_t *pEvt)
|
||||
{
|
||||
attEvt_t *pMsg;
|
||||
|
||||
if ((pMsg = WsfMsgAlloc(sizeof(attEvt_t) + pEvt->valueLen)) != NULL)
|
||||
{
|
||||
memcpy(pMsg, pEvt, sizeof(attEvt_t));
|
||||
pMsg->pValue = (uint8_t *) (pMsg + 1);
|
||||
memcpy(pMsg->pValue, pEvt->pValue, pEvt->valueLen);
|
||||
WsfMsgSend(medcCb.handlerId, pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform actions on scan start.
|
||||
*
|
||||
* \param pMsg Pointer to DM callback event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcScanStart(dmEvt_t *pMsg)
|
||||
{
|
||||
if (pMsg->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
medcCb.scanning = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform actions on scan stop.
|
||||
*
|
||||
* \param pMsg Pointer to DM callback event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcScanStop(dmEvt_t *pMsg)
|
||||
{
|
||||
if (pMsg->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
medcCb.scanning = FALSE;
|
||||
medcCb.autoConnect = FALSE;
|
||||
|
||||
/* Open connection */
|
||||
if (medcConnInfo.doConnect)
|
||||
{
|
||||
APP_TRACE_INFO0("medcScanStop: Opening Connection");
|
||||
|
||||
AppConnOpen(medcConnInfo.addrType, medcConnInfo.addr, medcConnInfo.dbHdl);
|
||||
medcConnInfo.doConnect = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a scan report.
|
||||
*
|
||||
* \param pMsg Pointer to DM callback event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcScanReport(dmEvt_t *pMsg)
|
||||
{
|
||||
uint8_t *pData;
|
||||
uint8_t len;
|
||||
appDbHdl_t dbHdl;
|
||||
bool_t connect = FALSE;
|
||||
|
||||
/* disregard if not scanning or autoconnecting */
|
||||
if (!medcCb.scanning || !medcCb.autoConnect)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* if we already have a bond with this device then connect to it */
|
||||
if ((dbHdl = AppDbFindByAddr(pMsg->scanReport.addrType, pMsg->scanReport.addr)) != APP_DB_HDL_NONE)
|
||||
{
|
||||
connect = TRUE;
|
||||
}
|
||||
/* otherwise look for desired service in advertising data */
|
||||
else
|
||||
{
|
||||
/* find Service UUID list; if full list not found search for partial */
|
||||
if ((pData = DmFindAdType(DM_ADV_TYPE_16_UUID, pMsg->scanReport.len,
|
||||
pMsg->scanReport.pData)) == NULL)
|
||||
{
|
||||
pData = DmFindAdType(DM_ADV_TYPE_16_UUID_PART, pMsg->scanReport.len,
|
||||
pMsg->scanReport.pData);
|
||||
}
|
||||
|
||||
/* if found and length checks out ok */
|
||||
if (pData != NULL && pData[DM_AD_LEN_IDX] >= (ATT_16_UUID_LEN + 1))
|
||||
{
|
||||
len = pData[DM_AD_LEN_IDX] - 1;
|
||||
pData += DM_AD_DATA_IDX;
|
||||
|
||||
while ((!connect) && (len >= ATT_16_UUID_LEN))
|
||||
{
|
||||
int8_t i;
|
||||
|
||||
for (i=0; i < MEDC_MAX_AUTO_UUID; i++)
|
||||
{
|
||||
if (medcCb.autoUuid[i] == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (BYTES_UINT16_CMP(pData, medcCb.autoUuid[i]))
|
||||
{
|
||||
connect = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pData += ATT_16_UUID_LEN;
|
||||
len -= ATT_16_UUID_LEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (connect)
|
||||
{
|
||||
APP_TRACE_INFO0("medcScanReport: Peer found.");
|
||||
|
||||
/* stop scanning and connect */
|
||||
medcCb.autoConnect = FALSE;
|
||||
AppScanStop();
|
||||
|
||||
/* Store peer information for connect on scan stop */
|
||||
medcConnInfo.addrType = pMsg->scanReport.addrType;
|
||||
memcpy(medcConnInfo.addr, pMsg->scanReport.addr, sizeof(bdAddr_t));
|
||||
medcConnInfo.dbHdl = dbHdl;
|
||||
medcConnInfo.doConnect = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform UI actions on connection open.
|
||||
*
|
||||
* \param pMsg Pointer to DM callback event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcOpen(dmEvt_t *pMsg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set up procedures that need to be performed after device reset.
|
||||
*
|
||||
* \param pMsg Pointer to DM callback event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcSetup(dmEvt_t *pMsg)
|
||||
{
|
||||
medcCb.scanning = FALSE;
|
||||
medcCb.autoConnect = FALSE;
|
||||
medcConnInfo.doConnect = FALSE;
|
||||
|
||||
DmConnSetConnSpec((hciConnSpec_t *) &medcConnCfg);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Button press callback.
|
||||
*
|
||||
* \param btn Button press.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcBtnCback(uint8_t btn)
|
||||
{
|
||||
dmConnId_t connId;
|
||||
|
||||
/* button actions when connected */
|
||||
if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE)
|
||||
{
|
||||
switch (btn)
|
||||
{
|
||||
case APP_UI_BTN_1_LONG:
|
||||
/* disconnect */
|
||||
AppConnClose(connId);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* all other button presses-- send to profile */
|
||||
medcCb.pIf->btn(connId, btn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* button actions when not connected */
|
||||
else
|
||||
{
|
||||
switch (btn)
|
||||
{
|
||||
case APP_UI_BTN_1_SHORT:
|
||||
/* if scanning cancel scanning */
|
||||
if (medcCb.scanning)
|
||||
{
|
||||
AppScanStop();
|
||||
}
|
||||
/* else auto connect */
|
||||
else if (!medcCb.autoConnect)
|
||||
{
|
||||
medcCb.autoConnect = TRUE;
|
||||
medcConnInfo.doConnect = FALSE;
|
||||
AppScanStart(medcMasterCfg.discMode, medcMasterCfg.scanType,
|
||||
medcMasterCfg.scanDuration);
|
||||
}
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_1_LONG:
|
||||
/* clear all bonding info */
|
||||
AppClearAllBondingInfo();
|
||||
break;
|
||||
|
||||
default:
|
||||
/* all other button presses-- send to profile */
|
||||
medcCb.pIf->btn(connId, btn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Discovery callback.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param status Service or configuration status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcDiscCback(dmConnId_t connId, uint8_t status)
|
||||
{
|
||||
switch(status)
|
||||
{
|
||||
case APP_DISC_INIT:
|
||||
/* set handle list when initialization requested */
|
||||
AppDiscSetHdlList(connId, medcCb.hdlListLen, medcCb.hdlList);
|
||||
break;
|
||||
|
||||
case APP_DISC_READ_DATABASE_HASH:
|
||||
/* Read peer's database hash */
|
||||
AppDiscReadDatabaseHash(connId);
|
||||
break;
|
||||
|
||||
case APP_DISC_SEC_REQUIRED:
|
||||
/* initiate security */
|
||||
AppMasterSecurityReq(connId);
|
||||
break;
|
||||
|
||||
case APP_DISC_START:
|
||||
/* initialize discovery state */
|
||||
medcCb.discState = MEDC_DISC_GATT_SVC;
|
||||
|
||||
/* discover GATT service */
|
||||
GattDiscover(connId, pMedcGattHdlList);
|
||||
break;
|
||||
|
||||
case APP_DISC_FAILED:
|
||||
if (pAppCfg->abortDisc)
|
||||
{
|
||||
/* if discovery failed for desired service then disconnect */
|
||||
if (medcCb.discState == MEDC_DISC_MED_SVC)
|
||||
{
|
||||
AppConnClose(connId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Else falls through. */
|
||||
|
||||
case APP_DISC_CMPL:
|
||||
/* next discovery state */
|
||||
medcCb.discState++;
|
||||
|
||||
if (medcCb.discState == MEDC_DISC_DIS_SVC)
|
||||
{
|
||||
/* discover device information service */
|
||||
DisDiscover(connId, pMedcDisHdlList);
|
||||
}
|
||||
else if (medcCb.discState == MEDC_DISC_MED_SVC)
|
||||
{
|
||||
/* discover med profile service */
|
||||
if (medcCb.pIf->discover(connId) == FALSE)
|
||||
{
|
||||
/* There are other profiles to discover. Stay in the MEDC_DISC_MED_SVC state */
|
||||
medcCb.discState = MEDC_DISC_MED_SVC - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* discovery complete */
|
||||
AppDiscComplete(connId, APP_DISC_CMPL);
|
||||
|
||||
/* start configuration: configure DIS service */
|
||||
medcCb.cfgState = MEDC_CFG_DIS_SVC;
|
||||
AppDiscConfigure(connId, APP_DISC_CFG_START, MEDC_CFG_DIS_LIST_LEN,
|
||||
(attcDiscCfg_t *) medcCfgDisList,
|
||||
DIS_HDL_LIST_LEN, pMedcDisHdlList);
|
||||
}
|
||||
break;
|
||||
|
||||
case APP_DISC_CFG_START:
|
||||
/* start configuration: configure DIS service */
|
||||
medcCb.cfgState = MEDC_CFG_DIS_SVC;
|
||||
AppDiscConfigure(connId, APP_DISC_CFG_START, MEDC_CFG_DIS_LIST_LEN,
|
||||
(attcDiscCfg_t *) medcCfgDisList,
|
||||
DIS_HDL_LIST_LEN, pMedcDisHdlList);
|
||||
break;
|
||||
|
||||
case APP_DISC_CFG_CMPL:
|
||||
/* next configuration state */
|
||||
medcCb.cfgState++;
|
||||
|
||||
if (medcCb.cfgState == MEDC_CFG_GATT_SVC)
|
||||
{
|
||||
/* configure GATT */
|
||||
AppDiscConfigure(connId, APP_DISC_CFG_START, MEDC_CFG_GATT_LIST_LEN,
|
||||
(attcDiscCfg_t *) medcCfgGattList,
|
||||
GATT_HDL_LIST_LEN, pMedcGattHdlList);
|
||||
}
|
||||
else if (medcCb.cfgState == MEDC_CFG_MED_SVC)
|
||||
{
|
||||
/* configure med profile service */
|
||||
medcCb.pIf->configure(connId, APP_DISC_CFG_START);
|
||||
}
|
||||
else
|
||||
{
|
||||
AppDiscComplete(connId, status);
|
||||
}
|
||||
break;
|
||||
|
||||
case APP_DISC_CFG_CONN_START:
|
||||
/* no connection setup configuration */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process messages from the event handler.
|
||||
*
|
||||
* \param pMsg Pointer to message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcProcMsg(dmEvt_t *pMsg)
|
||||
{
|
||||
uint8_t uiEvent = APP_UI_NONE;
|
||||
|
||||
switch(pMsg->hdr.event)
|
||||
{
|
||||
case ATTC_READ_RSP:
|
||||
case ATTC_WRITE_RSP:
|
||||
case ATTC_HANDLE_VALUE_NTF:
|
||||
case ATTC_HANDLE_VALUE_IND:
|
||||
case MEDC_TIMER_IND:
|
||||
medcCb.pIf->procMsg(&pMsg->hdr);
|
||||
break;
|
||||
|
||||
case ATT_MTU_UPDATE_IND:
|
||||
APP_TRACE_INFO1("Negotiated MTU %d", ((attEvt_t *)pMsg)->mtu);
|
||||
break;
|
||||
|
||||
case DM_RESET_CMPL_IND:
|
||||
AttsCalculateDbHash();
|
||||
medcSetup(pMsg);
|
||||
uiEvent = APP_UI_RESET_CMPL;
|
||||
break;
|
||||
|
||||
case DM_SCAN_START_IND:
|
||||
medcScanStart(pMsg);
|
||||
uiEvent = APP_UI_SCAN_START;
|
||||
break;
|
||||
|
||||
case DM_SCAN_STOP_IND:
|
||||
medcScanStop(pMsg);
|
||||
uiEvent = APP_UI_SCAN_STOP;
|
||||
break;
|
||||
|
||||
case DM_SCAN_REPORT_IND:
|
||||
medcScanReport(pMsg);
|
||||
break;
|
||||
|
||||
case DM_CONN_OPEN_IND:
|
||||
medcOpen(pMsg);
|
||||
uiEvent = APP_UI_CONN_OPEN;
|
||||
break;
|
||||
|
||||
case DM_CONN_CLOSE_IND:
|
||||
medcCb.pIf->procMsg(&pMsg->hdr);
|
||||
uiEvent = APP_UI_CONN_CLOSE;
|
||||
break;
|
||||
|
||||
case DM_SEC_PAIR_CMPL_IND:
|
||||
uiEvent = APP_UI_SEC_PAIR_CMPL;
|
||||
break;
|
||||
|
||||
case DM_SEC_PAIR_FAIL_IND:
|
||||
uiEvent = APP_UI_SEC_PAIR_FAIL;
|
||||
break;
|
||||
|
||||
case DM_SEC_ENCRYPT_IND:
|
||||
medcCb.pIf->procMsg(&pMsg->hdr);
|
||||
uiEvent = APP_UI_SEC_ENCRYPT;
|
||||
break;
|
||||
|
||||
case DM_SEC_ENCRYPT_FAIL_IND:
|
||||
medcCb.pIf->procMsg(&pMsg->hdr);
|
||||
uiEvent = APP_UI_SEC_ENCRYPT_FAIL;
|
||||
break;
|
||||
|
||||
case DM_SEC_AUTH_REQ_IND:
|
||||
AppHandlePasskey(&pMsg->authReq);
|
||||
break;
|
||||
|
||||
case DM_PRIV_CLEAR_RES_LIST_IND:
|
||||
APP_TRACE_INFO1("Clear resolving list status 0x%02x", pMsg->hdr.status);
|
||||
break;
|
||||
|
||||
case DM_VENDOR_SPEC_CMD_CMPL_IND:
|
||||
{
|
||||
#if defined(AM_PART_APOLLO) || defined(AM_PART_APOLLO2)
|
||||
|
||||
uint8_t *param_ptr = &pMsg->vendorSpecCmdCmpl.param[0];
|
||||
|
||||
switch (pMsg->vendorSpecCmdCmpl.opcode)
|
||||
{
|
||||
case 0xFC20: //read at address
|
||||
{
|
||||
uint32_t read_value;
|
||||
|
||||
BSTREAM_TO_UINT32(read_value, param_ptr);
|
||||
|
||||
APP_TRACE_INFO3("VSC 0x%0x complete status %x param %x",
|
||||
pMsg->vendorSpecCmdCmpl.opcode,
|
||||
pMsg->hdr.status,
|
||||
read_value);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
APP_TRACE_INFO2("VSC 0x%0x complete status %x",
|
||||
pMsg->vendorSpecCmdCmpl.opcode,
|
||||
pMsg->hdr.status);
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (uiEvent != APP_UI_NONE)
|
||||
{
|
||||
AppUiAction(uiEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Application handler init function called during system initialization.
|
||||
*
|
||||
* \param handlerID WSF handler ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void MedcHandlerInit(wsfHandlerId_t handlerId)
|
||||
{
|
||||
APP_TRACE_INFO0("MedcHandlerInit");
|
||||
|
||||
/* store handler ID */
|
||||
medcCb.handlerId = handlerId;
|
||||
|
||||
/* Set configuration pointers */
|
||||
pAppMasterCfg = (appMasterCfg_t *) &medcMasterCfg;
|
||||
pAppSecCfg = (appSecCfg_t *) &medcSecCfg;
|
||||
pAppDiscCfg = (appDiscCfg_t *) &medcDiscCfg;
|
||||
pAppCfg = (appCfg_t *) &medcAppCfg;
|
||||
|
||||
/* Set stack configuration pointers */
|
||||
pSmpCfg = (smpCfg_t *) &medcSmpCfg;
|
||||
|
||||
/* Initialize application framework */
|
||||
AppMasterInit();
|
||||
AppDiscInit();
|
||||
|
||||
/* Set default profile to use */
|
||||
MedcSetProfile(MEDC_PROFILE);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WSF event handler for application.
|
||||
*
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void MedcHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
if (pMsg != NULL)
|
||||
{
|
||||
APP_TRACE_INFO1("Medc got evt %d", pMsg->event);
|
||||
|
||||
/* process ATT messages */
|
||||
if (pMsg->event <= ATT_CBACK_END)
|
||||
{
|
||||
/* process discovery-related ATT messages */
|
||||
AppDiscProcAttMsg((attEvt_t *) pMsg);
|
||||
|
||||
/* process server-related ATT messages */
|
||||
AppServerProcAttMsg(pMsg);
|
||||
}
|
||||
/* process DM messages */
|
||||
else if (pMsg->event <= DM_CBACK_END)
|
||||
{
|
||||
/* process advertising and connection-related messages */
|
||||
AppMasterProcDmMsg((dmEvt_t *) pMsg);
|
||||
|
||||
/* process security-related messages */
|
||||
AppMasterSecProcDmMsg((dmEvt_t *) pMsg);
|
||||
|
||||
/* process discovery-related messages */
|
||||
AppDiscProcDmMsg((dmEvt_t *) pMsg);
|
||||
}
|
||||
|
||||
/* perform profile and user interface-related operations */
|
||||
medcProcMsg((dmEvt_t *) pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start the application.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void MedcStart(void)
|
||||
{
|
||||
/* Register for stack callbacks */
|
||||
DmRegister(medcDmCback);
|
||||
DmConnRegister(DM_CLIENT_ID_APP, medcDmCback);
|
||||
AttRegister(medcAttCback);
|
||||
|
||||
/* Register for app framework button callbacks */
|
||||
AppUiBtnRegister(medcBtnCback);
|
||||
|
||||
/* Initialize attribute server database */
|
||||
SvcCoreAddGroup();
|
||||
|
||||
/* Register for app framework discovery callbacks */
|
||||
AppDiscRegister(medcDiscCback);
|
||||
|
||||
/* Reset the device */
|
||||
DmDevReset();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the profile to be used by the application. This function is called internally
|
||||
* by MedcHandlerInit() with a default value. It may also be called by the system
|
||||
* to configure the profile after executing MedcHandlerInit() and before executing
|
||||
* MedcStart().
|
||||
*
|
||||
* \param profile Profile identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void MedcSetProfile(uint8_t profile)
|
||||
{
|
||||
switch (profile)
|
||||
{
|
||||
#if MEDC_HRP_INCLUDED == TRUE
|
||||
case MEDC_ID_HRP:
|
||||
medcCb.pIf = &medcHrpIf;
|
||||
medcCb.pIf->init();
|
||||
break;
|
||||
#endif
|
||||
#if MEDC_BLP_INCLUDED == TRUE
|
||||
case MEDC_ID_BLP:
|
||||
medcCb.pIf = &medcBlpIf;
|
||||
medcCb.pIf->init();
|
||||
break;
|
||||
#endif
|
||||
#if MEDC_GLP_INCLUDED == TRUE
|
||||
case MEDC_ID_GLP:
|
||||
medcCb.pIf = &medcGlpIf;
|
||||
medcCb.pIf->init();
|
||||
break;
|
||||
#endif
|
||||
#if MEDC_WSP_INCLUDED == TRUE
|
||||
case MEDC_ID_WSP:
|
||||
medcCb.pIf = &medcWspIf;
|
||||
medcCb.pIf->init();
|
||||
break;
|
||||
#endif
|
||||
#if MEDC_HTP_INCLUDED == TRUE
|
||||
case MEDC_ID_HTP:
|
||||
medcCb.pIf = &medcHtpIf;
|
||||
medcCb.pIf->init();
|
||||
break;
|
||||
#endif
|
||||
#if MEDC_PLX_INCLUDED == TRUE
|
||||
case MEDC_ID_PLX:
|
||||
medcCb.pIf = &medcPlxpIf;
|
||||
medcCb.pIf->init();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
APP_TRACE_WARN1("MedcSetProfile invalid profile:%d", profile);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Vendored
+138
@@ -0,0 +1,138 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Health/medical collector sample application interface file.
|
||||
*
|
||||
* Copyright (c) 2012-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#ifndef MEDC_MAIN_H
|
||||
#define MEDC_MAIN_H
|
||||
|
||||
#include "gatt/gatt_api.h"
|
||||
#include "dis/dis_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! the Client handle list, medcCb.hdlList[], is set as follows:
|
||||
*
|
||||
* ------------------------------- <- MEDC_DISC_GATT_START
|
||||
* | GATT handles |
|
||||
* |... |
|
||||
* ------------------------------- <- MEDC_DISC_DIS_START
|
||||
* | DIS handles |
|
||||
* | ... |
|
||||
* ------------------------------- <- Configured med service start
|
||||
* | Med service handles |
|
||||
* | ... |
|
||||
* -------------------------------
|
||||
*/
|
||||
|
||||
/*! Maximum number of Service UUID for autoconnect */
|
||||
#define MEDC_MAX_AUTO_UUID 2
|
||||
|
||||
/*! Start of each service's handles in the the handle list */
|
||||
#define MEDC_DISC_GATT_START 0
|
||||
#define MEDC_DISC_DIS_START (MEDC_DISC_GATT_START + GATT_HDL_LIST_LEN)
|
||||
|
||||
/*! WSF message event starting value */
|
||||
#define MEDC_MSG_START 0xA0
|
||||
|
||||
/*! WSF message event enumeration */
|
||||
enum
|
||||
{
|
||||
MEDC_TIMER_IND = MEDC_MSG_START, /*! Timer expired */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! profile interface callback functions */
|
||||
typedef void (*medcInitCback_t)(void);
|
||||
typedef bool_t (*medcDiscoverCback_t)(dmConnId_t connId);
|
||||
typedef void (*medcConfigureCback_t)(dmConnId_t connId, uint8_t status);
|
||||
typedef void (*medcProcMsgCback_t)(wsfMsgHdr_t *pMsg);
|
||||
typedef void (*medcBtnCback_t)(dmConnId_t connId, uint8_t btn);
|
||||
|
||||
/*! profile interface structure */
|
||||
typedef struct
|
||||
{
|
||||
medcInitCback_t init;
|
||||
medcDiscoverCback_t discover;
|
||||
medcConfigureCback_t configure;
|
||||
medcProcMsgCback_t procMsg;
|
||||
medcBtnCback_t btn;
|
||||
} medcIf_t;
|
||||
|
||||
/*! application control block */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t hdlList[APP_DB_HDL_LIST_LEN]; /*! Cached handle list */
|
||||
medcIf_t *pIf; /*! Profile interface */
|
||||
wsfHandlerId_t handlerId; /*! WSF hander ID */
|
||||
uint16_t autoUuid[MEDC_MAX_AUTO_UUID]; /*! Service UUID for autoconnect */
|
||||
bool_t scanning; /*! TRUE if scanning */
|
||||
bool_t autoConnect; /*! TRUE if auto-connecting */
|
||||
uint8_t hdlListLen; /*! Cached handle list length */
|
||||
uint8_t discState; /*! Service discovery state */
|
||||
uint8_t cfgState; /*! Service configuration state */
|
||||
} medcCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Default value for CCC indications and notifications */
|
||||
extern const uint8_t medcCccIndVal[2];
|
||||
|
||||
/*! Default value for CCC notifications */
|
||||
extern const uint8_t medcCccNtfVal[2];
|
||||
|
||||
/*! Pointers into handle list for GATT and DIS service handles */
|
||||
extern uint16_t *pMedcGattHdlList;
|
||||
extern uint16_t *pMedcDisHdlList;
|
||||
|
||||
/*! application control block */
|
||||
extern medcCb_t medcCb;
|
||||
|
||||
/*! profile interface pointers */
|
||||
extern medcIf_t medcHrpIf; /* heart rate profile */
|
||||
extern medcIf_t medcBlpIf; /* blood pressure profile */
|
||||
extern medcIf_t medcGlpIf; /* glucose profile */
|
||||
extern medcIf_t medcWspIf; /* weight scale profile */
|
||||
extern medcIf_t medcHtpIf; /* health thermometer profile */
|
||||
extern medcIf_t medcPlxpIf; /* pulse oximeter profile */
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* MEDC_MAIN_H */
|
||||
|
||||
Vendored
+381
@@ -0,0 +1,381 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Health/medical collector, Pulse Oximeter profile
|
||||
*
|
||||
* Copyright (c) 2016-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "app_cfg.h"
|
||||
#include "app_api.h"
|
||||
#include "app_db.h"
|
||||
#include "app_ui.h"
|
||||
#include "app_main.h"
|
||||
#include "svc_ch.h"
|
||||
#include "plxpc/plxpc_api.h"
|
||||
#include "medc/medc_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Discovery Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Start of cached health pulse oximeter service handles; begins after DIS */
|
||||
#define MEDC_DISC_PLXS_START (MEDC_DISC_DIS_START + DIS_HDL_LIST_LEN)
|
||||
|
||||
/* Total cached handle list length */
|
||||
#define MEDC_DISC_HDL_LIST_LEN (MEDC_DISC_PLXS_START + PLXPC_PLXS_HDL_LIST_LEN)
|
||||
|
||||
/*! Pointers into handle list for health pulse oximeter service handles */
|
||||
static uint16_t *pMedcPlxsHdlList = &medcCb.hdlList[MEDC_DISC_PLXS_START];
|
||||
|
||||
/* sanity check: make sure handle list length is <= app db handle list length */
|
||||
WSF_CT_ASSERT(MEDC_DISC_HDL_LIST_LEN <= APP_DB_HDL_LIST_LEN);
|
||||
|
||||
/* Default MTU */
|
||||
#define MEDC_PLX_DEFAULT_MTU 50
|
||||
|
||||
/**************************************************************************************************
|
||||
Configurable Parameters
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! ATT configurable parameters (increase MTU) */
|
||||
static const attCfg_t medcPlxpAttCfg =
|
||||
{
|
||||
15, /* ATT server service discovery connection idle timeout in seconds */
|
||||
MEDC_PLX_DEFAULT_MTU, /* desired ATT MTU */
|
||||
ATT_MAX_TRANS_TIMEOUT, /* transcation timeout in seconds */
|
||||
4 /* number of queued prepare writes supported by server */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Configuration Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/* List of characteristics to configure after service discovery */
|
||||
static const attcDiscCfg_t medcCfgPlxsList[] =
|
||||
{
|
||||
/* Read: Features */
|
||||
{NULL, 0, PLXPC_PLXS_PLXF_HDL_IDX},
|
||||
|
||||
/* Write: Spot Check CCC descriptor */
|
||||
{medcCccIndVal, sizeof(medcCccIndVal), PLXPC_PLXS_PLXSC_CCC_HDL_IDX},
|
||||
|
||||
/* Write: Continuous Measurement CCC descriptor */
|
||||
{medcCccNtfVal, sizeof(medcCccNtfVal), PLXPC_PLXS_PLXC_CCC_HDL_IDX},
|
||||
|
||||
/* Write: Record Access Control Point CCC descriptor */
|
||||
{medcCccIndVal, sizeof(medcCccIndVal), PLXPC_PLXS_RACP_CCC_HDL_IDX},
|
||||
};
|
||||
|
||||
/* Characteristic configuration list length */
|
||||
#define MEDC_CFG_PLXS_LIST_LEN (sizeof(medcCfgPlxsList) / sizeof(attcDiscCfg_t))
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
static struct
|
||||
{
|
||||
wsfTimer_t racpTimer; /*! RACP procedure timer */
|
||||
bool_t inProgress; /*! RACP procedure in progress */
|
||||
bool_t restoreConnection; /*! Indicates if a dropped connection should be restored */
|
||||
} medcPlxCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void medcPlxpInit(void);
|
||||
static bool_t medcPlxpDiscover(dmConnId_t connId);
|
||||
static void medcPlxpConfigure(dmConnId_t connId, uint8_t status);
|
||||
static void medcPlxpProcMsg(wsfMsgHdr_t *pMsg);
|
||||
static void medcPlxpBtn(dmConnId_t connId, uint8_t btn);
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! profile interface pointer */
|
||||
medcIf_t medcPlxpIf =
|
||||
{
|
||||
medcPlxpInit,
|
||||
medcPlxpDiscover,
|
||||
medcPlxpConfigure,
|
||||
medcPlxpProcMsg,
|
||||
medcPlxpBtn
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
External Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! MEDC application master configuration */
|
||||
extern const appMasterCfg_t medcMasterCfg;
|
||||
|
||||
/*! App connection control block */
|
||||
extern appConnCb_t appConnCb[DM_CONN_MAX];
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a received ATT read response, notification, or indication.
|
||||
*
|
||||
* \param pMsg Pointer to ATT callback event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcPlxsValueUpdate(attEvt_t *pMsg)
|
||||
{
|
||||
if (pMsg->hdr.status == ATT_SUCCESS)
|
||||
{
|
||||
/* determine which profile the handle belongs to; start with most likely */
|
||||
|
||||
/* pulse oximeter */
|
||||
if (PlxpcPlxsValueUpdate(pMedcPlxsHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* device information */
|
||||
if (DisValueUpdate(pMedcDisHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* GATT */
|
||||
if (GattValueUpdate(pMedcGattHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process messages from the event handler.
|
||||
*
|
||||
* \param pMsg Pointer to message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcPlxpProcMsg(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
appConnCb_t *pCb;
|
||||
|
||||
switch(pMsg->event)
|
||||
{
|
||||
case DM_CONN_CLOSE_IND:
|
||||
/* if procedure in progress stop procedure timer */
|
||||
if (medcPlxCb.inProgress)
|
||||
{
|
||||
medcPlxCb.inProgress = FALSE;
|
||||
WsfTimerStop(&medcPlxCb.racpTimer);
|
||||
}
|
||||
|
||||
if (medcPlxCb.restoreConnection == TRUE)
|
||||
{
|
||||
medcCb.autoConnect = TRUE;
|
||||
AppScanStart(medcMasterCfg.discMode, medcMasterCfg.scanType,
|
||||
medcMasterCfg.scanDuration);
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_SEC_ENCRYPT_IND:
|
||||
if (medcPlxCb.restoreConnection == TRUE)
|
||||
{
|
||||
AppDiscConfigure((dmConnId_t) pMsg->param, HCI_SUCCESS, MEDC_CFG_PLXS_LIST_LEN,
|
||||
(attcDiscCfg_t *) medcCfgPlxsList,
|
||||
PLXPC_PLXS_HDL_LIST_LEN, pMedcPlxsHdlList);
|
||||
|
||||
medcPlxCb.restoreConnection = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_SEC_ENCRYPT_FAIL_IND:
|
||||
if (medcPlxCb.restoreConnection == TRUE)
|
||||
{
|
||||
/* look up app connection control block from DM connection ID */
|
||||
pCb = &appConnCb[pMsg->param - 1];
|
||||
|
||||
pCb->initiatingSec = FALSE;
|
||||
|
||||
/* if database record handle valid */
|
||||
if (pCb->dbHdl != APP_DB_HDL_NONE)
|
||||
{
|
||||
AppDbDeleteRecord(pCb->dbHdl);
|
||||
pCb->dbHdl = APP_DB_HDL_NONE;
|
||||
}
|
||||
|
||||
AppMasterSecurityReq((dmConnId_t) pMsg->param);
|
||||
}
|
||||
break;
|
||||
|
||||
case ATTC_READ_RSP:
|
||||
case ATTC_HANDLE_VALUE_NTF:
|
||||
medcPlxsValueUpdate((attEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
case ATTC_WRITE_RSP:
|
||||
/* if write to RACP was successful, start procedure timer */
|
||||
if ((((attEvt_t *) pMsg)->hdr.status == ATT_SUCCESS) &&
|
||||
(((attEvt_t *) pMsg)->handle == pMedcPlxsHdlList[PLXPC_PLXS_RACP_HDL_IDX]))
|
||||
{
|
||||
medcPlxCb.inProgress = TRUE;
|
||||
medcPlxCb.racpTimer.msg.param = pMsg->param; /* conn ID */
|
||||
WsfTimerStartSec(&medcPlxCb.racpTimer, ATT_MAX_TRANS_TIMEOUT);
|
||||
}
|
||||
break;
|
||||
|
||||
case ATTC_HANDLE_VALUE_IND:
|
||||
/* if procedure in progress stop procedure timer */
|
||||
if (medcPlxCb.inProgress)
|
||||
{
|
||||
medcPlxCb.inProgress = FALSE;
|
||||
WsfTimerStop(&medcPlxCb.racpTimer);
|
||||
}
|
||||
|
||||
medcPlxsValueUpdate((attEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
case MEDC_TIMER_IND:
|
||||
/* if procedure in progress then close connection */
|
||||
if (medcPlxCb.inProgress && pMsg->param != DM_CONN_ID_NONE)
|
||||
{
|
||||
medcPlxCb.inProgress = FALSE;
|
||||
|
||||
/* if configured to disconnect upon ATT transaction timeout */
|
||||
if (pAppCfg->disconnect)
|
||||
{
|
||||
AppConnClose((dmConnId_t)pMsg->param);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Profile initialization function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcPlxpInit(void)
|
||||
{
|
||||
/* Set configuration pointers */
|
||||
pAttCfg = (attCfg_t *) &medcPlxpAttCfg;
|
||||
|
||||
/* set handle list length */
|
||||
medcCb.hdlListLen = MEDC_DISC_HDL_LIST_LEN;
|
||||
|
||||
/* set autoconnect UUID */
|
||||
medcCb.autoUuid[0] = ATT_UUID_PULSE_OXIMITER_SERVICE;
|
||||
|
||||
/* initialize timer */
|
||||
medcPlxCb.racpTimer.handlerId = medcCb.handlerId;
|
||||
medcPlxCb.racpTimer.msg.event = MEDC_TIMER_IND;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Discover service for profile.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return TRUE - finished discovering services. FALSE - more services are to be discovered.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t medcPlxpDiscover(dmConnId_t connId)
|
||||
{
|
||||
/* discover health pulse oximeter service */
|
||||
PlxpcPlxsDiscover(connId, pMedcPlxsHdlList);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure service for profile.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param status APP_DISC_CFG_START or APP_DISC_CFG_CONN_START.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcPlxpConfigure(dmConnId_t connId, uint8_t status)
|
||||
{
|
||||
/* configure health pulse oximeter service */
|
||||
AppDiscConfigure(connId, status, MEDC_CFG_PLXS_LIST_LEN,
|
||||
(attcDiscCfg_t *) medcCfgPlxsList,
|
||||
PLXPC_PLXS_HDL_LIST_LEN, pMedcPlxsHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a button press.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param btn Button press.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcPlxpBtn(dmConnId_t connId, uint8_t btn)
|
||||
{
|
||||
/* button actions when connected */
|
||||
if (connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
switch (btn)
|
||||
{
|
||||
case APP_UI_BTN_1_MED:
|
||||
medcPlxCb.restoreConnection = TRUE;
|
||||
AppConnClose(connId);
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_SHORT:
|
||||
PlxpcPlxsRacpSend(connId, pMedcPlxsHdlList[PLXPC_PLXS_RACP_HDL_IDX], CH_RACP_OPCODE_DELETE, CH_RACP_OPERATOR_ALL);
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_MED:
|
||||
PlxpcPlxsRacpSend(connId, pMedcPlxsHdlList[PLXPC_PLXS_RACP_HDL_IDX], CH_RACP_OPCODE_REPORT, CH_RACP_OPERATOR_ALL);
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_LONG:
|
||||
PlxpcPlxsRacpSend(connId, pMedcPlxsHdlList[PLXPC_PLXS_RACP_HDL_IDX], CH_RACP_OPCODE_REPORT_NUM, CH_RACP_OPERATOR_ALL);
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_EX_LONG:
|
||||
PlxpcPlxsRacpSend(connId, pMedcPlxsHdlList[PLXPC_PLXS_RACP_HDL_IDX], CH_RACP_OPCODE_ABORT, CH_RACP_OPERATOR_ALL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+315
@@ -0,0 +1,315 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Health/medical collector, Weight Scale profile
|
||||
*
|
||||
* Copyright (c) 2012-2019 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_msg.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "app_cfg.h"
|
||||
#include "app_api.h"
|
||||
#include "app_db.h"
|
||||
#include "app_ui.h"
|
||||
#include "svc_ch.h"
|
||||
#include "wspc/wspc_api.h"
|
||||
#include "udsc/udsc_api.h"
|
||||
#include "medc/medc_main.h"
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Discovery Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Discovery states: enumeration of services to be discovered */
|
||||
enum
|
||||
{
|
||||
MEDC_DISC_WSP_UDS_SVC, /*! User data service */
|
||||
MEDC_DISC_WSP_WSS_SVC, /*! Weight scale service */
|
||||
};
|
||||
|
||||
/* Start of cached weight scale service handles; begins after DIS */
|
||||
#define MEDC_DISC_WSS_START (MEDC_DISC_DIS_START + DIS_HDL_LIST_LEN)
|
||||
|
||||
/* Start of User Data Service handles; begins after weight scale serivce */
|
||||
#define MEDC_DISC_UDS_START (MEDC_DISC_WSS_START + WSPC_WSS_HDL_LIST_LEN)
|
||||
|
||||
/* Total cached handle list length */
|
||||
#define MEDC_DISC_HDL_LIST_LEN (MEDC_DISC_UDS_START + UDSC_HDL_LIST_LEN)
|
||||
|
||||
/*! Pointers into handle list for weight scale service handles */
|
||||
static uint16_t *pMedcWssHdlList = &medcCb.hdlList[MEDC_DISC_WSS_START];
|
||||
|
||||
/*! Pointers into handle list for weight scale service handles */
|
||||
static uint16_t *pMedcUdsHdlList = &medcCb.hdlList[MEDC_DISC_UDS_START];
|
||||
|
||||
/*! Weight Scale Profile discovery state */
|
||||
static uint8_t pMedcWspDiscState;
|
||||
|
||||
/* sanity check: make sure handle list length is <= app db handle list length */
|
||||
WSF_CT_ASSERT(MEDC_DISC_HDL_LIST_LEN <= APP_DB_HDL_LIST_LEN);
|
||||
|
||||
/**************************************************************************************************
|
||||
ATT Client Configuration Data
|
||||
**************************************************************************************************/
|
||||
|
||||
/* List of characteristics to configure after service discovery */
|
||||
static const attcDiscCfg_t medcCfgWssList[] =
|
||||
{
|
||||
/* Read: Weight scale feature */
|
||||
{NULL, 0, MEDC_DISC_WSS_START + WSPC_WSS_WSF_HDL_IDX},
|
||||
|
||||
/* Write: Weight scale measurement CCC descriptor */
|
||||
{medcCccIndVal, sizeof(medcCccIndVal), MEDC_DISC_WSS_START + WSPC_WSS_WSM_CCC_HDL_IDX},
|
||||
|
||||
/* Write: Database Change Interval CCC descriptor */
|
||||
{medcCccNtfVal, sizeof(medcCccNtfVal), MEDC_DISC_UDS_START + UDSC_DCBI_CCC_HDL_IDX},
|
||||
|
||||
/* Write: User Data Service Control Point CCC descriptor */
|
||||
{medcCccIndVal, sizeof(medcCccIndVal), MEDC_DISC_UDS_START + UDSC_UCP_CCC_HDL_IDX}
|
||||
};
|
||||
|
||||
/* Characteristic configuration list length */
|
||||
#define MEDC_CFG_WSS_LIST_LEN (sizeof(medcCfgWssList) / sizeof(attcDiscCfg_t))
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
static void medcWspInit(void);
|
||||
static bool_t medcWspDiscover(dmConnId_t connId);
|
||||
static void medcWspConfigure(dmConnId_t connId, uint8_t status);
|
||||
static void medcWspProcMsg(wsfMsgHdr_t *pMsg);
|
||||
static void medcWspBtn(dmConnId_t connId, uint8_t btn);
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! profile interface pointer */
|
||||
medcIf_t medcWspIf =
|
||||
{
|
||||
medcWspInit,
|
||||
medcWspDiscover,
|
||||
medcWspConfigure,
|
||||
medcWspProcMsg,
|
||||
medcWspBtn
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a received ATT read response, notification, or indication.
|
||||
*
|
||||
* \param pMsg Pointer to ATT callback event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcWssValueUpdate(attEvt_t *pMsg)
|
||||
{
|
||||
if (pMsg->hdr.status == ATT_SUCCESS)
|
||||
{
|
||||
/* determine which profile the handle belongs to; start with most likely */
|
||||
|
||||
/* weight scale */
|
||||
if (WspcWssValueUpdate(pMedcWssHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* user data service */
|
||||
if (UdscValueUpdate(pMedcUdsHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* device information */
|
||||
if (DisValueUpdate(pMedcDisHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/* GATT */
|
||||
if (GattValueUpdate(pMedcGattHdlList, pMsg) == ATT_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process messages from the event handler.
|
||||
*
|
||||
* \param pMsg Pointer to message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcWspProcMsg(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
switch(pMsg->event)
|
||||
{
|
||||
case DM_CONN_CLOSE_IND:
|
||||
/* initialize discovery state */
|
||||
pMedcWspDiscState = MEDC_DISC_WSP_UDS_SVC;
|
||||
|
||||
/* Notify UDSC the connection closed */
|
||||
UdscClose();
|
||||
break;
|
||||
|
||||
case ATTC_HANDLE_VALUE_IND:
|
||||
medcWssValueUpdate((attEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
case MEDC_TIMER_IND:
|
||||
APP_TRACE_INFO0("medcWspProcMsg - Timeout waiting for UDS control point response.");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief UDS Control Point Response Callback.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param opcode Cmd opcode being responded to.
|
||||
* \param response Response code.
|
||||
* \param index USer index (only set when opcode is UDSC_UCP_OPCODE_RNU)
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcWspUdsRspCallback(dmConnId_t connId, uint8_t opcode, uint8_t response, uint8_t index)
|
||||
{
|
||||
APP_TRACE_INFO3("medcWspUdsRspCallback - op: %d rsp: %d index: %d", opcode, response, index);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Profile initialization function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcWspInit(void)
|
||||
{
|
||||
/* set handle list length */
|
||||
medcCb.hdlListLen = MEDC_DISC_HDL_LIST_LEN;
|
||||
|
||||
/* set autoconnect UUID */
|
||||
medcCb.autoUuid[0] = ATT_UUID_WEIGHT_SCALE_SERVICE;
|
||||
medcCb.autoUuid[1] = ATT_UUID_USER_DATA_SERVICE;
|
||||
|
||||
/* Register the UDS Control Point Callback */
|
||||
UdscInit(medcCb.handlerId, MEDC_TIMER_IND, medcWspUdsRspCallback);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Discover service for profile.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
*
|
||||
* \return TRUE - finished discovering services. FALSE - more services are to be discovered.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t medcWspDiscover(dmConnId_t connId)
|
||||
{
|
||||
if (pMedcWspDiscState == MEDC_DISC_WSP_UDS_SVC)
|
||||
{
|
||||
/* user data service */
|
||||
UdscDiscover(connId, pMedcUdsHdlList);
|
||||
pMedcWspDiscState++;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (pMedcWspDiscState == MEDC_DISC_WSP_WSS_SVC)
|
||||
{
|
||||
/* discover weight scale service */
|
||||
WspcWssDiscover(connId, pMedcWssHdlList);
|
||||
pMedcWspDiscState++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Configure service for profile.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param status APP_DISC_CFG_START or APP_DISC_CFG_CONN_START.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcWspConfigure(dmConnId_t connId, uint8_t status)
|
||||
{
|
||||
/* configure weight scale service */
|
||||
AppDiscConfigure(connId, status, MEDC_CFG_WSS_LIST_LEN,
|
||||
(attcDiscCfg_t *) medcCfgWssList,
|
||||
WSPC_WSS_HDL_LIST_LEN, medcCb.hdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a button press.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param btn Button press.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void medcWspBtn(dmConnId_t connId, uint8_t btn)
|
||||
{
|
||||
switch (btn)
|
||||
{
|
||||
case APP_UI_BTN_2_SHORT:
|
||||
UdscRegisterNewUser(connId, pMedcUdsHdlList[UDSC_UCP_IDX], 1234);
|
||||
break;
|
||||
case APP_UI_BTN_2_MED:
|
||||
UdscConsent(connId, pMedcUdsHdlList[UDSC_UCP_IDX], 2, 1234);
|
||||
break;
|
||||
case APP_UI_BTN_2_LONG:
|
||||
UdscDeleteUserData(connId, pMedcUdsHdlList[UDSC_UCP_IDX]);
|
||||
break;
|
||||
case APP_UI_BTN_2_EX_LONG:
|
||||
UdscDeleteUserData(connId, pMedcUdsHdlList[UDSC_UCP_IDX]);
|
||||
break;
|
||||
case APP_UI_BTN_1_SHORT:
|
||||
UdscReadDatabaseChangeIncrement(connId, pMedcUdsHdlList[UDSC_DBCI_HDL_IDX]);
|
||||
break;
|
||||
case APP_UI_BTN_1_MED:
|
||||
UdscReadUserIndex(connId, pMedcUdsHdlList[UDSC_UI_HDL_IDX]);
|
||||
break;
|
||||
case APP_UI_BTN_1_EX_LONG:
|
||||
UdscWriteDatabaseChangeIncrement(connId, pMedcUdsHdlList[UDSC_DBCI_HDL_IDX], 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user