initial commit
This commit is contained in:
Vendored
+107
@@ -0,0 +1,107 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Alert Notification profile client.
|
||||
*
|
||||
* Copyright (c) 2011-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 ANPC_API_H
|
||||
#define ANPC_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup ALERT_NOTIFICATION_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
ANPC_ANS_SNAC_HDL_IDX, /*!< \brief Supported new alert category */
|
||||
ANPC_ANS_NA_HDL_IDX, /*!< \brief New alert */
|
||||
ANPC_ANS_NA_CCC_HDL_IDX, /*!< \brief New alert CCC descriptor */
|
||||
ANPC_ANS_SUAC_HDL_IDX, /*!< \brief Supported unread alert category */
|
||||
ANPC_ANS_UAS_HDL_IDX, /*!< \brief Unread alert status */
|
||||
ANPC_ANS_UAS_CCC_HDL_IDX, /*!< \brief Unread alert status CCC descriptor */
|
||||
ANPC_ANS_ANCP_HDL_IDX, /*!< \brief Alert notification control point */
|
||||
ANPC_ANS_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Alert Notification service.
|
||||
* Parameter pHdlList must point to an array of length \ref ANPC_ANS_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AnpcAnsDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a command to the alert notification control point.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param command Control point command.
|
||||
* \param catId Alert category ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AnpcAnsControl(dmConnId_t connId, uint16_t handle, uint8_t command, uint8_t catId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length \ref ANPC_ANS_HDL_LIST_LEN.
|
||||
* If the ATT handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if handle is found, \ref ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t AnpcAnsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg);
|
||||
|
||||
/*! \} */ /* ALERT_NOTIFICATION_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* ANPC_API_H */
|
||||
Vendored
+238
@@ -0,0 +1,238 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Alert Notification profile client.
|
||||
*
|
||||
* Copyright (c) 2011-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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "app_api.h"
|
||||
#include "anpc_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*!
|
||||
* Alert Notification service
|
||||
*/
|
||||
|
||||
/* Characteristics for discovery */
|
||||
|
||||
/*! Supported new alert category */
|
||||
static const attcDiscChar_t anpcAnsSnac =
|
||||
{
|
||||
attSnacChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! New alert */
|
||||
static const attcDiscChar_t anpcAnsNa =
|
||||
{
|
||||
attNaChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! New alert CCC descriptor */
|
||||
static const attcDiscChar_t anpcAnsNaCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Supported unread alert category */
|
||||
static const attcDiscChar_t anpcAnsSuac =
|
||||
{
|
||||
attSuacChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Unread alert status */
|
||||
static const attcDiscChar_t anpcAnsUas =
|
||||
{
|
||||
attUasChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
/*! Unread alert status CCC descriptor */
|
||||
static const attcDiscChar_t anpcAnsUasCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Alert notification control point */
|
||||
static const attcDiscChar_t anpcAnsAncp =
|
||||
{
|
||||
attAncpChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *anpcAnsDiscCharList[] =
|
||||
{
|
||||
&anpcAnsSnac, /*! Supported new alert category */
|
||||
&anpcAnsNa, /*! New alert */
|
||||
&anpcAnsNaCcc, /*! New alert CCC descriptor */
|
||||
&anpcAnsSuac, /*! Supported unread alert category */
|
||||
&anpcAnsUas, /*! Unread alert status */
|
||||
&anpcAnsUasCcc, /*! Unread alert status CCC descriptor */
|
||||
&anpcAnsAncp /*! Alert notification control point */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(ANPC_ANS_HDL_LIST_LEN == ((sizeof(anpcAnsDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Alert Notification service. Parameter
|
||||
* pHdlList must point to an array of length ANPC_ANS_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AnpcAnsDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attAnsSvcUuid,
|
||||
ANPC_ANS_HDL_LIST_LEN, (attcDiscChar_t **) anpcAnsDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a command to the alert notification control point.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param command Control point command.
|
||||
* \param catId Alert category ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AnpcAnsControl(dmConnId_t connId, uint16_t handle, uint8_t command, uint8_t catId)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
|
||||
if (handle != ATT_HANDLE_NONE)
|
||||
{
|
||||
buf[0] = command;
|
||||
buf[1] = catId;
|
||||
AttcWriteReq(connId, handle, sizeof(buf), buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length ANPC_ANS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t AnpcAnsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t *p;
|
||||
uint16_t catIdMask;
|
||||
uint8_t catId;
|
||||
uint8_t numAlert;
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
uint8_t buf[19];
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)catIdMask; (void)catId; (void)numAlert;
|
||||
|
||||
/* new alert */
|
||||
if (pMsg->handle == pHdlList[ANPC_ANS_NA_HDL_IDX])
|
||||
{
|
||||
/* parse value */
|
||||
p = pMsg->pValue;
|
||||
BSTREAM_TO_UINT8(catId, p);
|
||||
BSTREAM_TO_UINT8(numAlert, p);
|
||||
|
||||
/* null terminate string before printing */
|
||||
memcpy(buf, p, pMsg->valueLen - 2);
|
||||
buf[pMsg->valueLen - 2] = '\0';
|
||||
|
||||
APP_TRACE_INFO2("New alert cat:%d num:%d", catId, numAlert);
|
||||
APP_TRACE_INFO1("Msg:%s", buf);
|
||||
}
|
||||
/* unread alert status */
|
||||
else if (pMsg->handle == pHdlList[ANPC_ANS_UAS_HDL_IDX])
|
||||
{
|
||||
/* parse value */
|
||||
p = pMsg->pValue;
|
||||
BSTREAM_TO_UINT8(catId, p);
|
||||
BSTREAM_TO_UINT8(numAlert, p);
|
||||
|
||||
APP_TRACE_INFO2("Unread alert status cat:%d num:%d", catId, numAlert);
|
||||
}
|
||||
/* supported new alert category */
|
||||
else if (pMsg->handle == pHdlList[ANPC_ANS_SNAC_HDL_IDX])
|
||||
{
|
||||
/* parse value */
|
||||
p = pMsg->pValue;
|
||||
if (pMsg->valueLen == 1)
|
||||
{
|
||||
BSTREAM_TO_UINT8(catIdMask, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
BSTREAM_TO_UINT16(catIdMask, p);
|
||||
}
|
||||
|
||||
APP_TRACE_INFO1("Supported new alert category: 0x%04x", catIdMask);
|
||||
}
|
||||
/* supported unread alert category */
|
||||
else if (pMsg->handle == pHdlList[ANPC_ANS_SUAC_HDL_IDX])
|
||||
{
|
||||
/* parse value */
|
||||
p = pMsg->pValue;
|
||||
if (pMsg->valueLen == 1)
|
||||
{
|
||||
BSTREAM_TO_UINT8(catIdMask, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
BSTREAM_TO_UINT16(catIdMask, p);
|
||||
}
|
||||
|
||||
APP_TRACE_INFO1("Supported unread alert category: 0x%04x", catIdMask);
|
||||
}
|
||||
/* handle not found in list */
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
Vendored
+206
@@ -0,0 +1,206 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Asset Tracking profile client.
|
||||
*
|
||||
* Copyright (c) 2018-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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#ifndef ATPC_API_H
|
||||
#define ATPC_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup ASSET_TRACKING_PROFILE_CLIENT
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Enumeration of handle indexes of characteristics to be discovered. */
|
||||
enum
|
||||
{
|
||||
ATPC_CTE_ENABLE_HDL, /*!< \brief Constant Tone Extension enable. */
|
||||
ATPC_CTE_MIN_LEN_HDL, /*!< \brief Constant Tone Extension minimum length. */
|
||||
ATPC_CTE_ADV_MIN_TX_CNT_HDL, /*!< \brief Constant Tone Extension minimum transmit count. */
|
||||
ATPC_CTE_ADV_TX_DURATION_HDL, /*!< \brief Constant Tone Extension transmit duration. */
|
||||
ATPC_CTE_ADV_INTERVAL_HDL, /*!< \brief Constant Tone Extension interval. */
|
||||
ATPC_CTE_ADV_EXT_PHY_HDL, /*!< \brief Constant Tone Extension PHY. */
|
||||
ATPC_CTE_HDL_LIST_LEN, /*!< \brief Handle list length. */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Constant Tone Extension service.
|
||||
* Parameter pHdlList must point to an array of length \ref ATPC_CTE_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the Constant Tone Extension enable attribute.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param enable Enable.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteWriteEnable(dmConnId_t connId, uint16_t handle, uint8_t enable);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the Constant Tone Extension minimum length attribute.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param minLen Minimum length.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteWriteMinLen(dmConnId_t connId, uint16_t handle, uint8_t minLen);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the Constant Tone Extension minimum transmit count attribute.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param txCount Minimum transmit count.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteWriteMinTxCount(dmConnId_t connId, uint16_t handle, uint8_t txCount);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the Constant Tone Extension transmit duration attribute.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param duration Transmit duration.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteWriteTxDuration(dmConnId_t connId, uint16_t handle, uint8_t duration);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the Constant Tone Extension interval attribute.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param interval Interval.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteWriteInterval(dmConnId_t connId, uint16_t handle, uint16_t interval);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the Constant Tone Extension PHY attribute.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param phy PHY.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteWritePhy(dmConnId_t connId, uint16_t handle, uint8_t phy);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the antenna identifiers for a connection ID.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param numAntenna Number of antenna and len of pAntennaIds in bytes.
|
||||
* \param pAntennaIds Array containing identifiers of antenna for this connection.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcSetAntennaIds(dmConnId_t connId, uint8_t numAntenna, uint8_t *pAntennaIds);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Enable AoA CTE Rx request over ACL.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle CTE enable attribute handle.
|
||||
* \param length Request length.
|
||||
* \param interval Request interval.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteAclEnableReq(dmConnId_t connId, uint16_t handle, uint8_t length, uint16_t interval);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Disable AoA CTE Rx request over ACL.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle CTE enable attribute handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteAclDisableReq(dmConnId_t connId, uint16_t handle);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by application to notify the ATPC of System Events.
|
||||
*
|
||||
* \param pEvt Pointer to the Event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcProcMsg(wsfMsgHdr_t *pEvt);
|
||||
|
||||
/*! \} */ /* ASSET_TRACKING_PROFILE_CLIENT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* ATPC_API_H */
|
||||
Vendored
+418
@@ -0,0 +1,418 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Asset Tracking profile client.
|
||||
*
|
||||
* Copyright (c) 2018-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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "app_api.h"
|
||||
#include "atpc_api.h"
|
||||
#include "svc_cte.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Asset tracking profile connection states. */
|
||||
#define ATPC_CONN_STATE_ENABLING 0
|
||||
#define ATPC_CONN_STATE_DISABLING 1
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Asset Tracking Profile Client connection control block. */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t enableHandle; /*! CTE enable attribute handle. */
|
||||
uint8_t state; /*! Connection state. */
|
||||
uint8_t length; /*! Min CTE length. */
|
||||
uint16_t interval; /*! CTE interval. */
|
||||
bool_t numAntenna; /*! Number of antenna and len of pAntennaIds in bytes. */
|
||||
uint8_t *pAntennaIds; /*! Array containing identifiers of antenna for this connection. */
|
||||
} atpcConnCb_t;
|
||||
|
||||
/*! Asset Tracking Profile Server control block. */
|
||||
typedef struct
|
||||
{
|
||||
atpcConnCb_t connCb[DM_CONN_MAX]; /*! Connection control block. */
|
||||
uint8_t switchSampleRates; /*! Supported Switching Sampling Rates. */
|
||||
uint8_t switchPatternMaxLen; /*! Max Length of Switching Pattern. */
|
||||
uint8_t numAntennae; /*! Number of Antennae. */
|
||||
uint8_t cteMaxLen; /*! Max CTE Length. */
|
||||
} atpcCb_t;
|
||||
|
||||
static atpcCb_t atpcCb;
|
||||
|
||||
/*! Constant Tone Extension enable. */
|
||||
static const attcDiscChar_t atpcCteEnable =
|
||||
{
|
||||
attCteEnChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Constant Tone Extension minimum length. */
|
||||
static const attcDiscChar_t atpcCteMinLen =
|
||||
{
|
||||
attCteMinLenChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Constant Tone Extension minimum transmit count. */
|
||||
static const attcDiscChar_t atpcCteTxCnt =
|
||||
{
|
||||
attCteTxCntChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Constant Tone Extension transmit duration. */
|
||||
static const attcDiscChar_t atpcCteDurationc =
|
||||
{
|
||||
attCteTxDurChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Constant Tone Extension interval. */
|
||||
static const attcDiscChar_t atpcCteInterval =
|
||||
{
|
||||
attCteIntChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Constant Tone Extension PHY. */
|
||||
static const attcDiscChar_t atpcCtePhy =
|
||||
{
|
||||
attCtePhyChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration. */
|
||||
static const attcDiscChar_t *atpcCteDiscCharList[] =
|
||||
{
|
||||
&atpcCteEnable, /*! Constant Tone Extension enable. */
|
||||
&atpcCteMinLen, /*! Constant Tone Extension minimum length. */
|
||||
&atpcCteTxCnt, /*! Constant Tone Extension minimum transmit count. */
|
||||
&atpcCteDurationc, /*! Constant Tone Extension transmit duration. */
|
||||
&atpcCteInterval, /*! Constant Tone Extension interval. */
|
||||
&atpcCtePhy, /*! Constant Tone Extension PHY. */
|
||||
};
|
||||
|
||||
/*! sanity check: make sure handle list length matches characteristic list length. */
|
||||
WSF_CT_ASSERT(ATPC_CTE_HDL_LIST_LEN == ((sizeof(atpcCteDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by application to notify the profile of System Events.
|
||||
*
|
||||
* \param pEvt Pointer to the Event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void atpcProcWriteRsp(attEvt_t *pEvt)
|
||||
{
|
||||
dmConnId_t connId = (dmConnId_t) pEvt->hdr.param;
|
||||
|
||||
if ((pEvt->hdr.status == ATT_SUCCESS) && (pEvt->handle == atpcCb.connCb[connId-1].enableHandle))
|
||||
{
|
||||
atpcConnCb_t *pCcb = &atpcCb.connCb[connId-1];
|
||||
|
||||
switch (pCcb->state)
|
||||
{
|
||||
case ATPC_CONN_STATE_ENABLING:
|
||||
DmConnCteRxSampleStart(connId, HCI_CTE_SLOT_DURATION_2_US, pCcb->numAntenna, pCcb->pAntennaIds);
|
||||
break;
|
||||
|
||||
case ATPC_CONN_STATE_DISABLING:
|
||||
DmConnCteRxSampleStop(connId);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Constant Tone Extension service.
|
||||
* Parameter pHdlList must point to an array of length \ref ATPC_CTE_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attCteSvcUuid,
|
||||
ATPC_CTE_HDL_LIST_LEN, (attcDiscChar_t **) atpcCteDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the Constant Tone Extension enable attribute.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param enable Enable.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteWriteEnable(dmConnId_t connId, uint16_t handle, uint8_t enable)
|
||||
{
|
||||
WSF_ASSERT(handle != ATT_HANDLE_NONE);
|
||||
|
||||
AttcWriteReq(connId, handle, sizeof(uint8_t), &enable);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the Constant Tone Extension minimum length attribute.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param minLen Minimum length.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteWriteMinLen(dmConnId_t connId, uint16_t handle, uint8_t minLen)
|
||||
{
|
||||
WSF_ASSERT(handle != ATT_HANDLE_NONE);
|
||||
|
||||
AttcWriteReq(connId, handle, sizeof(uint8_t), &minLen);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the Constant Tone Extension minimum transmit count attribute.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param txCount Minimum transmit count.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteWriteMinTxCount(dmConnId_t connId, uint16_t handle, uint8_t txCount)
|
||||
{
|
||||
WSF_ASSERT(handle != ATT_HANDLE_NONE);
|
||||
|
||||
AttcWriteReq(connId, handle, sizeof(uint8_t), &txCount);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the Constant Tone Extension transmit duration attribute.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param duration Transmit duration.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteWriteTxDuration(dmConnId_t connId, uint16_t handle, uint8_t duration)
|
||||
{
|
||||
WSF_ASSERT(handle != ATT_HANDLE_NONE);
|
||||
|
||||
AttcWriteReq(connId, handle, sizeof(uint8_t), &duration);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the Constant Tone Extension interval attribute.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param interval Interval.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteWriteInterval(dmConnId_t connId, uint16_t handle, uint16_t interval)
|
||||
{
|
||||
WSF_ASSERT(handle != ATT_HANDLE_NONE);
|
||||
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t *p = buf;
|
||||
|
||||
UINT16_TO_BSTREAM(p, interval);
|
||||
|
||||
AttcWriteReq(connId, handle, sizeof(uint16_t), buf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the Constant Tone Extension PHY attribute.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param phy PHY.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteWritePhy(dmConnId_t connId, uint16_t handle, uint8_t phy)
|
||||
{
|
||||
WSF_ASSERT(handle != ATT_HANDLE_NONE)
|
||||
|
||||
AttcWriteReq(connId, handle, sizeof(uint8_t), &phy);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Enable AoA CTE Rx request over ACL.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle CTE enable attribute handle.
|
||||
* \param length Request length.
|
||||
* \param interval Request interval.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteAclEnableReq(dmConnId_t connId, uint16_t handle, uint8_t length, uint16_t interval)
|
||||
{
|
||||
atpcConnCb_t *pCcb;
|
||||
|
||||
WSF_ASSERT((connId > DM_CONN_ID_NONE) && (connId <= DM_CONN_MAX));
|
||||
WSF_ASSERT(handle != ATT_HANDLE_NONE)
|
||||
|
||||
/* Store the enable handle and CTE configuration */
|
||||
pCcb = &atpcCb.connCb[connId-1];
|
||||
pCcb->enableHandle = handle;
|
||||
pCcb->length = length;
|
||||
pCcb->interval = interval;
|
||||
pCcb->state = ATPC_CONN_STATE_ENABLING;
|
||||
|
||||
AtpcCteWriteEnable(connId, handle, CTE_ENABLE_ACL_BIT);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Disable AoA CTE Rx request over ACL.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle CTE enable attribute handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcCteAclDisableReq(dmConnId_t connId, uint16_t handle)
|
||||
{
|
||||
atpcConnCb_t *pCcb;
|
||||
|
||||
WSF_ASSERT((connId > DM_CONN_ID_NONE) && (connId <= DM_CONN_MAX));
|
||||
WSF_ASSERT(handle != ATT_HANDLE_NONE)
|
||||
|
||||
/* Set the enableHandle to ATT_HANDLE_NONE to prevent CTE rx req on ATTC_WRITE_RSP. */
|
||||
pCcb = &atpcCb.connCb[connId-1];
|
||||
pCcb->enableHandle = handle;
|
||||
pCcb->state = ATPC_CONN_STATE_DISABLING;
|
||||
|
||||
AtpcCteWriteEnable(connId, handle, CTE_ENABLE_NONE);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the antenna identifiers for a connection ID.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param numAntenna Number of antenna and len of pAntennaIds in bytes.
|
||||
* \param pAntennaIds Array containing identifiers of antenna for this connection.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcSetAntennaIds(dmConnId_t connId, uint8_t numAntenna, uint8_t *pAntennaIds)
|
||||
{
|
||||
atpcConnCb_t *pCcb;
|
||||
|
||||
WSF_ASSERT((connId > DM_CONN_ID_NONE) && (connId <= DM_CONN_MAX));
|
||||
WSF_ASSERT(numAntenna <= atpcCb.numAntennae);
|
||||
|
||||
pCcb = &atpcCb.connCb[connId-1];
|
||||
pCcb->numAntenna = numAntenna;
|
||||
pCcb->pAntennaIds = pAntennaIds;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by application to notify the ATPC of System Events.
|
||||
*
|
||||
* \param pEvt Pointer to the Event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpcProcMsg(wsfMsgHdr_t *pEvt)
|
||||
{
|
||||
atpcConnCb_t *pCcb = &atpcCb.connCb[pEvt->param - 1];
|
||||
dmEvt_t *pDmEvt = (dmEvt_t*) pEvt;
|
||||
|
||||
switch (pEvt->event)
|
||||
{
|
||||
case DM_RESET_CMPL_IND:
|
||||
DmReadAntennaInfo();
|
||||
break;
|
||||
|
||||
case DM_READ_ANTENNA_INFO_IND:
|
||||
atpcCb.cteMaxLen = pDmEvt->readAntennaInfo.cteMaxLen;
|
||||
atpcCb.switchSampleRates = pDmEvt->readAntennaInfo.switchSampleRates;
|
||||
atpcCb.numAntennae = pDmEvt->readAntennaInfo.numAntennae;
|
||||
atpcCb.switchPatternMaxLen = pDmEvt->readAntennaInfo.switchPatternMaxLen;
|
||||
break;
|
||||
|
||||
case ATTC_WRITE_RSP:
|
||||
atpcProcWriteRsp((attEvt_t *)pEvt);
|
||||
break;
|
||||
|
||||
case DM_CONN_CTE_RX_SAMPLE_START_IND:
|
||||
if ((pEvt->status == HCI_SUCCESS) && (pCcb->state == ATPC_CONN_STATE_ENABLING))
|
||||
{
|
||||
DmConnCteReqStart((dmConnId_t) pEvt->param, pCcb->interval, pCcb->length, HCI_CTE_TYPE_REQ_AOA);
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_CONN_CTE_RX_SAMPLE_STOP_IND:
|
||||
if ((pEvt->status == HCI_SUCCESS) && (pCcb->state == ATPC_CONN_STATE_DISABLING))
|
||||
{
|
||||
DmConnCteReqStop((dmConnId_t) pEvt->param);
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_CTE_REQ_FAIL_IND:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Vendored
+79
@@ -0,0 +1,79 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Asset Tracking profile server.
|
||||
*
|
||||
* Copyright (c) 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 ATPS_API_H
|
||||
#define ATPS_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup ASSET_TRACKING_PROFILE_SERVER
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Asset Tracking Profile server initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpsInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the antenna identifiers for a connection ID.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param numAntenna Number of antenna and len of pAntennaIds in bytes.
|
||||
* \param pAntennaIds Array containing identifiers of antenna for this connection.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpsSetAntennaIds(dmConnId_t connId, uint8_t numAntenna, uint8_t *pAntennaIds);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by application to notify the Asset Tracking Profile server of DM Events.
|
||||
*
|
||||
* \param pEvt Pointer to the DM Event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpsProcDmMsg(dmEvt_t *pEvt);
|
||||
|
||||
/*! \} */ /* ASSET_TRACKING_PROFILE_SERVER */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* ATPS_API_H */
|
||||
Vendored
+430
@@ -0,0 +1,430 @@
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Asset Tracking profile server.
|
||||
*
|
||||
* Copyright (c) 2018-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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "hci_defs.h"
|
||||
#include "app_api.h"
|
||||
#include "atps_api.h"
|
||||
#include "svc_cte.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Asset tracking profile connection states. */
|
||||
#define ATPS_STATE_ACL_DISABLED 0
|
||||
#define ATPS_STATE_ACL_STARTING 1
|
||||
#define ATPS_STATE_ACL_ENABLED 2
|
||||
#define ATPS_STATE_ACL_STOPPING 3
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Asset Tracking Profile Server connection control block. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t state; /*! Connection state. */
|
||||
uint8_t enableBits; /*! Constant Tone Extension enable. */
|
||||
uint8_t minLen; /*! Constant Tone Extension minimum length. */
|
||||
uint8_t minTxCount; /*! Constant Tone Extension minimum transmit count. */
|
||||
uint8_t duration; /*! Constant Tone Extension transmit duration. */
|
||||
uint16_t interval; /*! Constant Tone Extension interval. */
|
||||
uint8_t phyType; /*! Constant Tone Extension PHY type. */
|
||||
bool_t numAntenna; /*! Number of antenna and len of pAntennaIds in bytes. */
|
||||
uint8_t *pAntennaIds; /*! Array containing identifiers of antenna for this connection. */
|
||||
} atpsConnCb_t;
|
||||
|
||||
/*! Asset Tracking Profile Server control block. */
|
||||
typedef struct
|
||||
{
|
||||
atpsConnCb_t connCb[DM_CONN_MAX]; /*! Connection control block. */
|
||||
uint8_t switchSampleRates; /*! Supported Switching Sampling Rates. */
|
||||
uint8_t switchPatternMaxLen; /*! Max Length of Switching Pattern. */
|
||||
uint8_t numAntennae; /*! Number of Antennae. */
|
||||
uint8_t cteMaxLen; /*! Max CTE Length. */
|
||||
} atpsCb_t;
|
||||
|
||||
static atpsCb_t atpsCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process write enable attribute from locator.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param enableBits Enable bitfield value from client.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t atpsCteSetEnable(dmConnId_t connId, uint8_t enableBits)
|
||||
{
|
||||
atpsConnCb_t *pCcb;
|
||||
bool_t enableAcl = !!(enableBits & CTE_ENABLE_ACL_BIT);
|
||||
|
||||
if (enableBits & CTE_ENABLE_ADV_BIT)
|
||||
{
|
||||
/* Connectionless advertising CTE not supported. */
|
||||
return ATT_ERR_WRITE_REJ;
|
||||
}
|
||||
|
||||
WSF_ASSERT((connId > DM_CONN_ID_NONE) && (connId <= DM_CONN_MAX));
|
||||
|
||||
pCcb = &atpsCb.connCb[connId-1];
|
||||
|
||||
if (enableAcl)
|
||||
{
|
||||
if (pCcb->state == ATPS_STATE_ACL_DISABLED)
|
||||
{
|
||||
pCcb->state = ATPS_STATE_ACL_STARTING;
|
||||
DmConnCteTxConfig(connId, HCI_CTE_TYPE_PERMIT_AOA_RSP_BIT, pCcb->numAntenna, pCcb->pAntennaIds);
|
||||
|
||||
/* Delay write response */
|
||||
return ATT_RSP_PENDING;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pCcb->state == ATPS_STATE_ACL_ENABLED)
|
||||
{
|
||||
pCcb->state = ATPS_STATE_ACL_STOPPING;
|
||||
DmConnCteRspStop(connId);
|
||||
|
||||
/* Delay write response */
|
||||
return ATT_RSP_PENDING;
|
||||
}
|
||||
}
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process write minimum length attribute from locator.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param minLen Minimum length value.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t atpsCteSetMinLen(dmConnId_t connId, uint8_t minLen)
|
||||
{
|
||||
atpsConnCb_t *pCcb;
|
||||
|
||||
WSF_ASSERT((connId > DM_CONN_ID_NONE) && (connId <= DM_CONN_MAX));
|
||||
|
||||
if ((minLen < CTE_MIN_MIN_LEN) || (minLen > CTE_MAX_MIN_LEN) || (minLen > atpsCb.cteMaxLen))
|
||||
{
|
||||
return ATT_ERR_RANGE;
|
||||
}
|
||||
|
||||
pCcb = &atpsCb.connCb[connId-1];
|
||||
pCcb->minLen = minLen;
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process write advertising minimum tx count attribute from locator.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param minLen Minimum tx count value.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t atpsCteSetAdvMinTxCnt(dmConnId_t connId, uint8_t minTxCount)
|
||||
{
|
||||
atpsConnCb_t *pCcb;
|
||||
|
||||
WSF_ASSERT((connId > DM_CONN_ID_NONE) && (connId <= DM_CONN_MAX));
|
||||
|
||||
if ((minTxCount < CTE_MIN_MIN_TX_CNT) || (minTxCount > CTE_MAX_MIN_TX_CNT))
|
||||
{
|
||||
return ATT_ERR_RANGE;
|
||||
}
|
||||
|
||||
pCcb = &atpsCb.connCb[connId-1];
|
||||
pCcb->minTxCount = minTxCount;
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process write advertising minimum tx duration attribute from locator.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param duration Minimum tx count value.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t atpsCteSetAdvTxDuration(dmConnId_t connId, uint8_t duration)
|
||||
{
|
||||
atpsConnCb_t *pCcb;
|
||||
|
||||
WSF_ASSERT((connId > DM_CONN_ID_NONE) && (connId <= DM_CONN_MAX));
|
||||
|
||||
pCcb = &atpsCb.connCb[connId-1];
|
||||
pCcb->duration = duration;
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process write advertising intergval attribute from locator.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param interval Interval value.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t atpsCteSetAdvInterval(dmConnId_t connId, uint8_t interval)
|
||||
{
|
||||
atpsConnCb_t *pCcb;
|
||||
|
||||
WSF_ASSERT((connId > DM_CONN_ID_NONE) && (connId <= DM_CONN_MAX));
|
||||
|
||||
if (interval < CTE_MIN_INTERVAL)
|
||||
{
|
||||
return ATT_ERR_RANGE;
|
||||
}
|
||||
|
||||
pCcb = &atpsCb.connCb[connId-1];
|
||||
pCcb->interval = interval;
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process write advertising PHY attribute from locator.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param phyType PHY type.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t atpsCteSetAdvPhy(dmConnId_t connId, uint8_t phyType)
|
||||
{
|
||||
atpsConnCb_t *pCcb;
|
||||
|
||||
WSF_ASSERT((connId > DM_CONN_ID_NONE) && (connId <= DM_CONN_MAX));
|
||||
|
||||
if (phyType > CTE_PHY_2M)
|
||||
{
|
||||
return ATT_ERR_RANGE;
|
||||
}
|
||||
|
||||
pCcb = &atpsCb.connCb[connId-1];
|
||||
pCcb->phyType = phyType;
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for Continuous Tone Extension, CTE, service.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t atpsCteWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
/* Only individual write requests with response are supported. */
|
||||
if (operation != ATT_PDU_WRITE_REQ)
|
||||
{
|
||||
return ATT_ERR_NOT_SUP;
|
||||
}
|
||||
|
||||
switch (handle)
|
||||
{
|
||||
case CTE_ENABLE_HDL:
|
||||
status = atpsCteSetEnable(connId, *pValue);
|
||||
break;
|
||||
|
||||
case CTE_MIN_LEN_HDL:
|
||||
status = atpsCteSetMinLen(connId, *pValue);
|
||||
break;
|
||||
|
||||
case CTE_ADV_MIN_TX_CNT_HDL:
|
||||
status = atpsCteSetAdvMinTxCnt(connId, *pValue);
|
||||
break;
|
||||
|
||||
case CTE_ADV_TX_DURATION_HDL:
|
||||
status = atpsCteSetAdvTxDuration(connId, *pValue);
|
||||
break;
|
||||
|
||||
case CTE_ADV_INTERVAL_HDL:
|
||||
status = atpsCteSetAdvInterval(connId, *pValue);
|
||||
break;
|
||||
|
||||
case CTE_ADV_EXT_PHY_HDL:
|
||||
status = atpsCteSetAdvPhy(connId, *pValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = ATT_ERR_HANDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the antenna identifiers for a connection ID.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param numAntenna Number of antenna and len of pAntennaIds in bytes.
|
||||
* \param pAntennaIds Array containing identifiers of antenna for this connection.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpsSetAntennaIds(dmConnId_t connId, uint8_t numAntenna, uint8_t *pAntennaIds)
|
||||
{
|
||||
atpsConnCb_t *pCcb;
|
||||
|
||||
WSF_ASSERT((connId > DM_CONN_ID_NONE) && (connId <= DM_CONN_MAX));
|
||||
WSF_ASSERT(numAntenna <= atpsCb.numAntennae);
|
||||
|
||||
pCcb = &atpsCb.connCb[connId-1];
|
||||
pCcb->numAntenna = numAntenna;
|
||||
pCcb->pAntennaIds = pAntennaIds;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by application to notify the Asset Tracking Profile server of DM Events.
|
||||
*
|
||||
* \param pEvt Pointer to the DM Event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpsProcDmMsg(dmEvt_t *pEvt)
|
||||
{
|
||||
uint8_t status;
|
||||
atpsConnCb_t *pCcb = &atpsCb.connCb[pEvt->hdr.param - 1];
|
||||
|
||||
switch (pEvt->hdr.event)
|
||||
{
|
||||
case DM_RESET_CMPL_IND:
|
||||
DmReadAntennaInfo();
|
||||
break;
|
||||
|
||||
case DM_READ_ANTENNA_INFO_IND:
|
||||
atpsCb.cteMaxLen = pEvt->readAntennaInfo.cteMaxLen;
|
||||
atpsCb.switchSampleRates = pEvt->readAntennaInfo.switchSampleRates;
|
||||
atpsCb.numAntennae = pEvt->readAntennaInfo.numAntennae;
|
||||
atpsCb.switchPatternMaxLen = pEvt->readAntennaInfo.switchPatternMaxLen;
|
||||
break;
|
||||
|
||||
case DM_CONN_OPEN_IND:
|
||||
pCcb->state = ATPS_STATE_ACL_DISABLED;
|
||||
break;
|
||||
|
||||
case DM_CONN_CTE_TX_CFG_IND:
|
||||
if (pEvt->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
DmConnCteRspStart((dmConnId_t) pEvt->hdr.param);
|
||||
}
|
||||
else
|
||||
{
|
||||
AttsContinueWriteReq((dmConnId_t) pEvt->hdr.param, CTE_ENABLE_HDL, ATT_ERR_WRITE_REJ);
|
||||
pCcb->state = ATPS_STATE_ACL_DISABLED;
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_CONN_CTE_RSP_START_IND:
|
||||
status = (pEvt->hdr.status == HCI_SUCCESS) ? ATT_SUCCESS : ATT_ERR_WRITE_REJ;
|
||||
AttsContinueWriteReq((dmConnId_t) pEvt->hdr.param, CTE_ENABLE_HDL, status);
|
||||
|
||||
if (status == ATT_SUCCESS)
|
||||
{
|
||||
pCcb->enableBits |= CTE_ENABLE_ACL_BIT;
|
||||
pCcb->state = ATPS_STATE_ACL_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCcb->state = ATPS_STATE_ACL_DISABLED;
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_CONN_CTE_RSP_STOP_IND:
|
||||
status = (pEvt->hdr.status == HCI_SUCCESS) ? ATT_SUCCESS : ATT_ERR_WRITE_REJ;
|
||||
AttsContinueWriteReq((dmConnId_t) pEvt->hdr.param, CTE_ENABLE_HDL, status);
|
||||
|
||||
if (status == ATT_SUCCESS)
|
||||
{
|
||||
pCcb->enableBits &= ~CTE_ENABLE_ACL_BIT;
|
||||
pCcb->state = ATPS_STATE_ACL_DISABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
pCcb->state = ATPS_STATE_ACL_ENABLED;
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_CTE_REQ_FAIL_IND:
|
||||
if (pCcb->state == ATPS_STATE_ACL_STARTING)
|
||||
{
|
||||
pCcb->state = ATPS_STATE_ACL_DISABLED;
|
||||
}
|
||||
else if (pCcb->state == ATPS_STATE_ACL_STOPPING)
|
||||
{
|
||||
pCcb->state = ATPS_STATE_ACL_ENABLED;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Asset Tracking Profile server initialization.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void AtpsInit(void)
|
||||
{
|
||||
SvcCteCbackRegister(atpsCteWriteCback);
|
||||
SvcCteAddGroup();
|
||||
}
|
||||
Vendored
+138
@@ -0,0 +1,138 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Battery service server.
|
||||
*
|
||||
* 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 BAS_API_H
|
||||
#define BAS_API_H
|
||||
|
||||
#include "wsf_timer.h"
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup BATTERY_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Battery service configurable parameters */
|
||||
typedef struct
|
||||
{
|
||||
wsfTimerTicks_t period; /*!< \brief Battery measurement timer expiration period in seconds */
|
||||
uint16_t count; /*!< \brief Perform battery measurement after this many timer periods */
|
||||
uint8_t threshold; /*!< \brief Send battery level notification to peer when below this level. */
|
||||
} basCfg_t;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the battery service server.
|
||||
*
|
||||
* \param handlerId WSF handler ID of the application using this service.
|
||||
* \param pCfg Battery service configurable parameters.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BasInit(wsfHandlerId_t handlerId, basCfg_t *pCfg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start periodic battery level measurement. This function starts a timer to perform
|
||||
* periodic battery measurements.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param timerEvt WSF event designated by the application for the timer.
|
||||
* \param battCccIdx Index of battery level CCC descriptor in CCC descriptor handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BasMeasBattStart(dmConnId_t connId, uint8_t timerEvt, uint8_t battCccIdx);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop periodic battery level measurement.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BasMeasBattStop(dmConnId_t connId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received WSF message.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BasProcMsg(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send the battery level to the peer device.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param idx Index of battery level CCC descriptor in CCC descriptor handle table.
|
||||
* \param level The battery level.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BasSendBattLevel(dmConnId_t connId, uint8_t idx, uint8_t level);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS read callback for battery service used to read the battery level. Use this
|
||||
* function as a parameter to SvcBattCbackRegister().
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param handle ATT handle.
|
||||
* \param operation ATT operation.
|
||||
* \param offset read offset.
|
||||
* \param pAttr pointer to Attribute
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t BasReadCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, attsAttr_t *pAttr);
|
||||
|
||||
/*! \} */ /* BATTERY_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* BAS_API_H */
|
||||
Vendored
+368
@@ -0,0 +1,368 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Battery service server.
|
||||
*
|
||||
* 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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "svc_ch.h"
|
||||
#include "svc_batt.h"
|
||||
#include "app_api.h"
|
||||
#include "app_hw.h"
|
||||
#include "bas_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief battery level initialization value */
|
||||
#define BAS_BATT_LEVEL_INIT 0xFF
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Connection control block */
|
||||
typedef struct
|
||||
{
|
||||
dmConnId_t connId; /*! \brief Connection ID */
|
||||
bool_t battToSend; /*! \brief battery measurement ready to be sent on this channel */
|
||||
uint8_t sentBattLevel; /*! \brief value of last sent battery level */
|
||||
} basConn_t;
|
||||
|
||||
/*! \brief Control block */
|
||||
static struct
|
||||
{
|
||||
basConn_t conn[DM_CONN_MAX]; /*! \brief connection control block */
|
||||
wsfTimer_t measTimer; /*! \brief periodic measurement timer */
|
||||
basCfg_t cfg; /*! \brief configurable parameters */
|
||||
uint16_t currCount; /*! \brief current measurement period count */
|
||||
bool_t txReady; /*! \brief TRUE if ready to send notifications */
|
||||
uint8_t measBattLevel; /*! \brief value of last measured battery level */
|
||||
} basCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return TRUE if no connections with active measurements.
|
||||
*
|
||||
* \return TRUE if no connections active.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t basNoConnActive(void)
|
||||
{
|
||||
basConn_t *pConn = basCb.conn;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < DM_CONN_MAX; i++, pConn++)
|
||||
{
|
||||
if (pConn->connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Setup to send measurements on active connections.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void basSetupToSend(void)
|
||||
{
|
||||
basConn_t *pConn = basCb.conn;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < DM_CONN_MAX; i++, pConn++)
|
||||
{
|
||||
if (pConn->connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
pConn->battToSend = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Find next connection with measurement to send.
|
||||
*
|
||||
* \param cccIdx Battery measurement CCC descriptor index.
|
||||
*
|
||||
* \return Connection control block.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static basConn_t *basFindNextToSend(uint8_t cccIdx)
|
||||
{
|
||||
basConn_t *pConn = basCb.conn;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < DM_CONN_MAX; i++, pConn++)
|
||||
{
|
||||
if (pConn->connId != DM_CONN_ID_NONE && pConn->battToSend &&
|
||||
pConn->sentBattLevel != basCb.measBattLevel)
|
||||
{
|
||||
if (AttsCccEnabled(pConn->connId, cccIdx))
|
||||
{
|
||||
return pConn;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send periodic battery measurement.
|
||||
*
|
||||
* \param pConn Connection control block.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void basSendPeriodicBattlevel(basConn_t *pConn)
|
||||
{
|
||||
BasSendBattLevel(pConn->connId, basCb.measTimer.msg.status, basCb.measBattLevel);
|
||||
pConn->sentBattLevel = basCb.measBattLevel;
|
||||
pConn->battToSend = FALSE;
|
||||
basCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle connection open.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void basConnOpen(dmEvt_t *pMsg)
|
||||
{
|
||||
basCb.txReady = TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a received ATT handle value confirm.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void basHandleValueCnf(attEvt_t *pMsg)
|
||||
{
|
||||
basConn_t *pConn;
|
||||
|
||||
if (pMsg->hdr.status == ATT_SUCCESS && pMsg->handle == BATT_LVL_HDL)
|
||||
{
|
||||
basCb.txReady = TRUE;
|
||||
|
||||
/* find next connection to send (note ccc idx is stored in timer status) */
|
||||
if ((pConn = basFindNextToSend(basCb.measTimer.msg.status)) != NULL)
|
||||
{
|
||||
basSendPeriodicBattlevel(pConn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application when the periodic measurement
|
||||
* timer expires.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void basMeasTimerExp(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
basConn_t *pConn;
|
||||
|
||||
/* if there are active connections */
|
||||
if (basNoConnActive() == FALSE)
|
||||
{
|
||||
if (--basCb.currCount == 0)
|
||||
{
|
||||
/* reset count */
|
||||
basCb.currCount = basCb.cfg.count;
|
||||
|
||||
/* set up battery measurement to be sent on all connections */
|
||||
basSetupToSend();
|
||||
|
||||
/* read battery measurement sensor data */
|
||||
AppHwBattRead(&basCb.measBattLevel);
|
||||
|
||||
/* if ready to send measurements */
|
||||
if (basCb.txReady)
|
||||
{
|
||||
/* find next connection to send (note ccc idx is stored in timer status) */
|
||||
if ((pConn = basFindNextToSend(pMsg->status)) != NULL)
|
||||
{
|
||||
basSendPeriodicBattlevel(pConn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* restart timer */
|
||||
WsfTimerStartSec(&basCb.measTimer, basCb.cfg.period);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the battery service server.
|
||||
*
|
||||
* \param handerId WSF handler ID of the application using this service.
|
||||
* \param pCfg Battery service configurable parameters.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BasInit(wsfHandlerId_t handlerId, basCfg_t *pCfg)
|
||||
{
|
||||
basCb.measTimer.handlerId = handlerId;
|
||||
basCb.cfg = *pCfg;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start periodic battery level measurement. This function starts a timer to perform
|
||||
* periodic battery measurements.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param timerEvt WSF event designated by the application for the timer.
|
||||
* \param battCccIdx Index of battery level CCC descriptor in CCC descriptor handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BasMeasBattStart(dmConnId_t connId, uint8_t timerEvt, uint8_t battCccIdx)
|
||||
{
|
||||
/* if this is first connection */
|
||||
if (basNoConnActive())
|
||||
{
|
||||
/* initialize control block */
|
||||
basCb.measTimer.msg.event = timerEvt;
|
||||
basCb.measTimer.msg.status = battCccIdx;
|
||||
basCb.measBattLevel = BAS_BATT_LEVEL_INIT;
|
||||
basCb.currCount = basCb.cfg.count;
|
||||
|
||||
/* start timer */
|
||||
WsfTimerStartSec(&basCb.measTimer, basCb.cfg.period);
|
||||
}
|
||||
|
||||
/* set conn id and last sent battery level */
|
||||
basCb.conn[connId - 1].connId = connId;
|
||||
basCb.conn[connId - 1].sentBattLevel = BAS_BATT_LEVEL_INIT;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop periodic battery level measurement.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BasMeasBattStop(dmConnId_t connId)
|
||||
{
|
||||
/* clear connection */
|
||||
basCb.conn[connId - 1].connId = DM_CONN_ID_NONE;
|
||||
basCb.conn[connId - 1].battToSend = FALSE;
|
||||
|
||||
/* if no remaining connections */
|
||||
if (basNoConnActive())
|
||||
{
|
||||
/* stop timer */
|
||||
WsfTimerStop(&basCb.measTimer);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received WSF message.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BasProcMsg(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
if (pMsg->event == DM_CONN_OPEN_IND)
|
||||
{
|
||||
basConnOpen((dmEvt_t *) pMsg);
|
||||
}
|
||||
else if (pMsg->event == ATTS_HANDLE_VALUE_CNF)
|
||||
{
|
||||
basHandleValueCnf((attEvt_t *) pMsg);
|
||||
}
|
||||
else if (pMsg->event == basCb.measTimer.msg.event)
|
||||
{
|
||||
basMeasTimerExp(pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send the battery level to the peer device.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param idx Index of battery level CCC descriptor in CCC descriptor handle table.
|
||||
* \param level The battery level.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BasSendBattLevel(dmConnId_t connId, uint8_t idx, uint8_t level)
|
||||
{
|
||||
if (AttsCccEnabled(connId, idx))
|
||||
{
|
||||
AttsHandleValueNtf(connId, BATT_LVL_HDL, CH_BATT_LEVEL_LEN, &level);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS read callback for battery service used to read the battery level. Use this
|
||||
* function as a parameter to SvcBattCbackRegister().
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t BasReadCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, attsAttr_t *pAttr)
|
||||
{
|
||||
/* read the battery level and set attribute value */
|
||||
AppHwBattRead(pAttr->pValue);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
Vendored
+91
@@ -0,0 +1,91 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Blood Pressure profile client.
|
||||
*
|
||||
* 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 BLPC_API_H
|
||||
#define BLPC_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup BLOOD_PRESSURE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Blood Pressure service enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
BLPC_BPS_BPM_HDL_IDX, /*!< \brief Blood pressure measurement */
|
||||
BLPC_BPS_BPM_CCC_HDL_IDX, /*!< \brief Blood pressure measurement CCC descriptor */
|
||||
BLPC_BPS_ICP_HDL_IDX, /*!< \brief Intermediate cuff pressure */
|
||||
BLPC_BPS_ICP_CCC_HDL_IDX, /*!< \brief Intermediate cuff pressure CCC descriptor */
|
||||
BLPC_BPS_BPF_HDL_IDX, /*!< \brief Blood pressure feature */
|
||||
BLPC_BPS_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Blood Pressure service.
|
||||
* Parameter pHdlList must point to an array of length \ref BLPC_BPS_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpcBpsDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length \ref BLPC_BPS_HDL_LIST_LEN.
|
||||
* If the ATT handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if handle is found, \ref ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t BlpcBpsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg);
|
||||
|
||||
/*! \} */ /* BLOOD_PRESSURE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* BLPC_API_H */
|
||||
Vendored
+264
@@ -0,0 +1,264 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Blood Pressure profile collector.
|
||||
*
|
||||
* 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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_ch.h"
|
||||
#include "app_api.h"
|
||||
#include "blpc_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*!
|
||||
* Blood Pressure service
|
||||
*/
|
||||
|
||||
/* Characteristics for discovery */
|
||||
|
||||
/*! Blood pressure measurement */
|
||||
static const attcDiscChar_t blpcBpsBpm =
|
||||
{
|
||||
attBpmChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Blood pressure measurement CCC descriptor */
|
||||
static const attcDiscChar_t blpcBpsBpmCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Intermediate cuff pressure */
|
||||
static const attcDiscChar_t blpcBpsIcp =
|
||||
{
|
||||
attIcpChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Intermediate cuff pressure CCC descriptor */
|
||||
static const attcDiscChar_t blpcBpsIcpCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Blood pressure feature */
|
||||
static const attcDiscChar_t blpcBpsBpf =
|
||||
{
|
||||
attBpfChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *blpcBpsDiscCharList[] =
|
||||
{
|
||||
&blpcBpsBpm, /*! Blood pressure measurement */
|
||||
&blpcBpsBpmCcc, /*! Blood pressure measurement CCC descriptor */
|
||||
&blpcBpsIcp, /*! Intermediate cuff pressure */
|
||||
&blpcBpsIcpCcc, /*! Intermediate cuff pressure CCC descriptor */
|
||||
&blpcBpsBpf /*! Blood pressure feature */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(BLPC_BPS_HDL_LIST_LEN == ((sizeof(blpcBpsDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Parse a blood pressure measurement.
|
||||
*
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void blpcBpsParseBpm(uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
uint8_t flags;
|
||||
uint16_t systolic, diastolic, map;
|
||||
uint16_t year;
|
||||
uint8_t month, day, hour, min, sec;
|
||||
uint16_t pulseRate;
|
||||
uint8_t userId;
|
||||
uint16_t measStatus;
|
||||
uint16_t minLen = CH_BPM_FLAGS_LEN + CH_BPM_MEAS_LEN;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)systolic; (void)diastolic; (void)map;
|
||||
(void)year; (void)month; (void)day; (void)hour; (void)min; (void)sec;
|
||||
(void)pulseRate; (void)userId; (void)measStatus;
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
/* get flags */
|
||||
BSTREAM_TO_UINT8(flags, pValue);
|
||||
|
||||
/* determine expected minimum length based on flags */
|
||||
if (flags & CH_BPM_FLAG_TIMESTAMP)
|
||||
{
|
||||
minLen += CH_BPM_TIMESTAMP_LEN;
|
||||
}
|
||||
if (flags & CH_BPM_FLAG_PULSE_RATE)
|
||||
{
|
||||
minLen += CH_BPM_PULSE_RATE_LEN;
|
||||
}
|
||||
if (flags & CH_BPM_FLAG_USER_ID)
|
||||
{
|
||||
minLen += CH_BPM_USER_ID_LEN;
|
||||
}
|
||||
if (flags & CH_BPM_FLAG_MEAS_STATUS)
|
||||
{
|
||||
minLen += CH_BPM_MEAS_STATUS_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
/* verify length */
|
||||
if (len < minLen)
|
||||
{
|
||||
APP_TRACE_INFO2("Blood Pressure meas len:%d minLen:%d", len, minLen);
|
||||
return;
|
||||
}
|
||||
|
||||
/* blood pressure */
|
||||
BSTREAM_TO_UINT16(systolic, pValue);
|
||||
BSTREAM_TO_UINT16(diastolic, pValue);
|
||||
BSTREAM_TO_UINT16(map, pValue);
|
||||
APP_TRACE_INFO3(" Systolic:0x%04x Diastolic:0x%04x MAP:0x%04x", systolic, diastolic, map);
|
||||
|
||||
/* timestamp */
|
||||
if (flags & CH_BPM_FLAG_TIMESTAMP)
|
||||
{
|
||||
BSTREAM_TO_UINT16(year, pValue);
|
||||
BSTREAM_TO_UINT8(month, pValue);
|
||||
BSTREAM_TO_UINT8(day, pValue);
|
||||
BSTREAM_TO_UINT8(hour, pValue);
|
||||
BSTREAM_TO_UINT8(min, pValue);
|
||||
BSTREAM_TO_UINT8(sec, pValue);
|
||||
APP_TRACE_INFO3(" Date: %d/%d/%d", month, day, year);
|
||||
APP_TRACE_INFO3(" Time: %02d:%02d:%02d", hour, min, sec);
|
||||
}
|
||||
|
||||
/* pulse rate */
|
||||
if (flags & CH_BPM_FLAG_PULSE_RATE)
|
||||
{
|
||||
BSTREAM_TO_UINT16(pulseRate, pValue);
|
||||
APP_TRACE_INFO1(" Pulse rate:0x%04x", pulseRate);
|
||||
}
|
||||
|
||||
/* user id */
|
||||
if (flags & CH_BPM_FLAG_USER_ID)
|
||||
{
|
||||
BSTREAM_TO_UINT8(userId, pValue);
|
||||
APP_TRACE_INFO1(" User ID:%d", userId);
|
||||
}
|
||||
|
||||
/* measurement status */
|
||||
if (flags & CH_BPM_FLAG_MEAS_STATUS)
|
||||
{
|
||||
BSTREAM_TO_UINT16(measStatus, pValue);
|
||||
APP_TRACE_INFO1(" Meas. status:0x%04x", measStatus);
|
||||
}
|
||||
|
||||
APP_TRACE_INFO1(" Flags:0x%02x", flags);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Blood Pressure service. Parameter
|
||||
* pHdlList must point to an array of length BLPC_BPS_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpcBpsDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attBpsSvcUuid,
|
||||
BLPC_BPS_HDL_LIST_LEN, (attcDiscChar_t **) blpcBpsDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length BLPC_BPS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t BlpcBpsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
|
||||
{
|
||||
uint16_t feature;
|
||||
uint8_t *p;
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)feature;
|
||||
|
||||
/* blood pressure measurement */
|
||||
if (pMsg->handle == pHdlList[BLPC_BPS_BPM_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO0("BP measurement");
|
||||
|
||||
/* parse value */
|
||||
blpcBpsParseBpm(pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
/* intermediate cuff pressure */
|
||||
else if (pMsg->handle == pHdlList[BLPC_BPS_ICP_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO0("BP intermed. cuff pressure");
|
||||
|
||||
/* parse value */
|
||||
blpcBpsParseBpm(pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
/* blood pressure feature */
|
||||
else if (pMsg->handle == pHdlList[BLPC_BPS_BPF_HDL_IDX])
|
||||
{
|
||||
/* parse value */
|
||||
p = pMsg->pValue;
|
||||
BSTREAM_TO_UINT16(feature, p);
|
||||
|
||||
APP_TRACE_INFO1("BP feature:0x%04x", feature);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
Vendored
+136
@@ -0,0 +1,136 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Blood Pressure profile sensor.
|
||||
*
|
||||
* 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 BLPS_API_H
|
||||
#define BLPS_API_H
|
||||
|
||||
#include "wsf_timer.h"
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup BLOOD_PRESSURE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Configurable parameters */
|
||||
typedef struct
|
||||
{
|
||||
wsfTimerTicks_t period; /*!< \brief Measurement timer expiration period in ms */
|
||||
} blpsCfg_t;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the Blood Pressure profile sensor.
|
||||
*
|
||||
* \param handlerId WSF handler ID of the application using this service.
|
||||
* \param pCfg Configurable parameters.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsInit(wsfHandlerId_t handlerId, blpsCfg_t *pCfg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start periodic blood pressure measurement. This function starts a timer to perform
|
||||
* periodic measurements.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param timerEvt WSF event designated by the application for the timer.
|
||||
* \param icpCccIdx Index of intermediate cuff pressure CCC descriptor in CCC descriptor
|
||||
* handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsMeasStart(dmConnId_t connId, uint8_t timerEvt, uint8_t icpCccIdx);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop periodic blood pressure measurement.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsMeasStop(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Blood pressure measurement complete.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param bpmCccIdx Index of blood pressure measurement CCC descriptor in CCC descriptor
|
||||
* handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsMeasComplete(dmConnId_t connId, uint8_t bpmCccIdx);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application when the periodic measurement
|
||||
* timer expires.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsProcMsg(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the blood pressure measurement flags.
|
||||
*
|
||||
* \param flags Blood pressure measurement flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsSetBpmFlags(uint8_t flags);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the intermediate cuff pressure flags.
|
||||
*
|
||||
* \param flags Intermediate cuff pressure flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsSetIcpFlags(uint8_t flags);
|
||||
|
||||
/*! \} */ /* BLOOD_PRESSURE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* BLPS_API_H */
|
||||
Vendored
+256
@@ -0,0 +1,256 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Blood Pressure profile sensor.
|
||||
*
|
||||
* 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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "svc_ch.h"
|
||||
#include "svc_bps.h"
|
||||
#include "app_api.h"
|
||||
#include "app_hw.h"
|
||||
#include "blps_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
static struct
|
||||
{
|
||||
wsfTimer_t measTimer; /* periodic measurement timer */
|
||||
appBpm_t bpm; /* blood pressure measurement */
|
||||
blpsCfg_t cfg; /* configurable parameters */
|
||||
uint8_t bpmFlags; /* blood pressure measurement flags */
|
||||
uint8_t icpFlags; /* intermediate cuff pressure flags */
|
||||
} blpsCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Build a blood pressure measurement characteristic.
|
||||
*
|
||||
* \param pBuf Pointer to buffer to hold the built blood pressure measurement characteristic.
|
||||
* \param pBpm Blood pressure measurement values.
|
||||
*
|
||||
* \return Length of pBuf in bytes.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t blpsBuildBpm(uint8_t *pBuf, appBpm_t *pBpm)
|
||||
{
|
||||
uint8_t *p = pBuf;
|
||||
uint8_t flags = pBpm->flags;
|
||||
|
||||
/* flags */
|
||||
UINT8_TO_BSTREAM(p, flags);
|
||||
|
||||
/* measurement */
|
||||
UINT16_TO_BSTREAM(p, pBpm->systolic);
|
||||
UINT16_TO_BSTREAM(p, pBpm->diastolic);
|
||||
UINT16_TO_BSTREAM(p, pBpm->map);
|
||||
|
||||
/* time stamp */
|
||||
if (flags & CH_BPM_FLAG_TIMESTAMP)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pBpm->timestamp.year);
|
||||
UINT8_TO_BSTREAM(p, pBpm->timestamp.month);
|
||||
UINT8_TO_BSTREAM(p, pBpm->timestamp.day);
|
||||
UINT8_TO_BSTREAM(p, pBpm->timestamp.hour);
|
||||
UINT8_TO_BSTREAM(p, pBpm->timestamp.min);
|
||||
UINT8_TO_BSTREAM(p, pBpm->timestamp.sec);
|
||||
}
|
||||
|
||||
/* pulse rate */
|
||||
if (flags & CH_BPM_FLAG_PULSE_RATE)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pBpm->pulseRate);
|
||||
}
|
||||
|
||||
/* user id */
|
||||
if (flags & CH_BPM_FLAG_USER_ID)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pBpm->userId);
|
||||
}
|
||||
|
||||
/* measurement status */
|
||||
if (flags & CH_BPM_FLAG_MEAS_STATUS)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pBpm->measStatus);
|
||||
}
|
||||
|
||||
/* return length */
|
||||
return (uint8_t) (p - pBuf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the Blood Pressure profile sensor.
|
||||
*
|
||||
* \param handerId WSF handler ID of the application using this service.
|
||||
* \param pCfg Configurable parameters.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsInit(wsfHandlerId_t handlerId, blpsCfg_t *pCfg)
|
||||
{
|
||||
blpsCb.measTimer.handlerId = handlerId;
|
||||
blpsCb.cfg = *pCfg;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start periodic blood pressure measurement. This function starts a timer to perform
|
||||
* periodic measurements.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param timerEvt WSF event designated by the application for the timer.
|
||||
* \param icpCccIdx Index of intermediate cuff pressure CCC descriptor in CCC descriptor
|
||||
* handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsMeasStart(dmConnId_t connId, uint8_t timerEvt, uint8_t icpCccIdx)
|
||||
{
|
||||
/* initialize control block */
|
||||
blpsCb.measTimer.msg.param = connId;
|
||||
blpsCb.measTimer.msg.event = timerEvt;
|
||||
blpsCb.measTimer.msg.status = icpCccIdx;
|
||||
|
||||
/* start timer */
|
||||
WsfTimerStartMs(&blpsCb.measTimer, blpsCb.cfg.period);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop periodic blood pressure measurement.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsMeasStop(void)
|
||||
{
|
||||
/* stop timer */
|
||||
WsfTimerStop(&blpsCb.measTimer);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Blood pressure measurement complete.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param bpmCccIdx Index of blood pressure measurement CCC descriptor in CCC descriptor
|
||||
* handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsMeasComplete(dmConnId_t connId, uint8_t bpmCccIdx)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t len;
|
||||
|
||||
/* stop periodic measurement */
|
||||
BlpsMeasStop();
|
||||
|
||||
/* if indications enabled */
|
||||
if (AttsCccEnabled(connId, bpmCccIdx))
|
||||
{
|
||||
/* read blood pressure measurement sensor data */
|
||||
AppHwBpmRead(FALSE, &blpsCb.bpm);
|
||||
|
||||
/* set flags */
|
||||
blpsCb.bpm.flags = blpsCb.bpmFlags;
|
||||
|
||||
/* build blood pressure measurement characteristic */
|
||||
len = blpsBuildBpm(buf, &blpsCb.bpm);
|
||||
|
||||
/* send blood pressure measurement indication */
|
||||
AttsHandleValueInd(connId, BPS_BPM_HDL, len, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application when the periodic measurement
|
||||
* timer expires.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsProcMsg(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t len;
|
||||
|
||||
/* if notifications enabled (note ccc idx is stored in hdr.status) */
|
||||
if (AttsCccEnabled((dmConnId_t) pMsg->param, pMsg->status))
|
||||
{
|
||||
/* read blood pressure measurement sensor data */
|
||||
AppHwBpmRead(TRUE, &blpsCb.bpm);
|
||||
|
||||
/* set flags */
|
||||
blpsCb.bpm.flags = blpsCb.icpFlags;
|
||||
|
||||
/* build blood pressure measurement characteristic */
|
||||
len = blpsBuildBpm(buf, &blpsCb.bpm);
|
||||
|
||||
/* send intermediate cuff pressure notification */
|
||||
AttsHandleValueNtf((dmConnId_t) pMsg->param, BPS_ICP_HDL, len, buf);
|
||||
|
||||
/* restart timer */
|
||||
WsfTimerStartMs(&blpsCb.measTimer, blpsCb.cfg.period);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the blood pressure measurement flags.
|
||||
*
|
||||
* \param flags Blood pressure measurement flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsSetBpmFlags(uint8_t flags)
|
||||
{
|
||||
blpsCb.bpmFlags = flags;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the intermediate cuff pressure flags.
|
||||
*
|
||||
* \param flags Intermediate cuff pressure flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void BlpsSetIcpFlags(uint8_t flags)
|
||||
{
|
||||
blpsCb.icpFlags = flags;
|
||||
}
|
||||
Vendored
+127
@@ -0,0 +1,127 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Cycling Power Profile API.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#ifndef CPP_API_H
|
||||
#define CPP_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup CYCLING_POWER_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name Cycle Power Measurement Types
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define CPP_PM_PARAM_INSTANTANEOUS_POWER 0 /* Instantaneous Power Measurement */
|
||||
#define CPP_PM_PARAM_PEDAL_POWER 1 /* Pedal Power Balance */
|
||||
#define CPP_PM_PARAM_ACCUMULATED_TORQUE 2 /* Accumulated Torque */
|
||||
#define CPP_PM_PARAM_WHEEL_REVOLUTIONS 3 /* Wheel Revolution */
|
||||
#define CPP_PM_PARAM_LAST_WHEEL_REV_TIME 4 /* Last Wheel Revolution Event Time */
|
||||
#define CPP_PM_PARAM_CRANK_REVOLUTIONS 5 /* Crank Revolution */
|
||||
#define CPP_PM_PARAM_LAST_CRANK_TIME 6 /* Last Crank Revolution Event Time */
|
||||
#define CPP_PM_PARAM_MAX_FORCE_MAGNITUDE 7 /* Max Extreme Force Magnitudes */
|
||||
#define CPP_PM_PARAM_MIN_FORCE_MAGNITUDE 8 /* Min Extreme Force Magnitudes */
|
||||
#define CPP_PM_PARAM_MAX_TORQUE_MAGNITUDE 9 /* Max Extreme Torque Magnitudes */
|
||||
#define CPP_PM_PARAM_MIN_TORQUE_MAGNITUDE 10 /* Min Extreme Torque Magnitudes */
|
||||
#define CPP_PM_PARAM_MAX_EXTREME_ANGLE 11 /* Max Extreme Angles */
|
||||
#define CPP_PM_PARAM_MIN_EXTREME_ANGLE 12 /* Min Extreme Angles */
|
||||
#define CPP_PM_PARAM_TOP_DEAD_SPOT 13 /* Top Dead Spot Angle */
|
||||
#define CPP_PM_PARAM_BOTTOM_DEAD_SPOT 14 /* Bottom Dead Spot Angle */
|
||||
#define CPP_PM_PARAM_ACCUMULATED_ENERGY 15 /* Accumulated Energy */
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Setup connection specific variables.
|
||||
*
|
||||
* \param connId Connection ID
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CppsConnOpen(dmConnId_t connId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Notifies the collector of a Cycle Power Measurement.
|
||||
*
|
||||
* \param connId Connection ID
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CppsSendPowerMeasurement(dmConnId_t connId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set a cycle measurement parameter.
|
||||
*
|
||||
* \param type Parameter identifier
|
||||
* \param value Measurement value.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CppsSetParameter(uint8_t type, uint32_t value);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the sensor location attribute.
|
||||
*
|
||||
* \param location Sensor Location.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CppsSetSensorLocation(uint8_t location);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the features attribute.
|
||||
*
|
||||
* \param features Features bitmask.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CppsSetFeatures(uint32_t features);
|
||||
|
||||
/*! \} */ /* CYCLING_POWER_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* CPP_API_H */
|
||||
Vendored
+358
@@ -0,0 +1,358 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Cycling Power Profile Sensor Implementation.
|
||||
*
|
||||
* 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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "dm_api.h"
|
||||
#include "svc_cps.h"
|
||||
#include "svc_ch.h"
|
||||
#include "cpp_api.h"
|
||||
|
||||
/*************************************************************************************************
|
||||
* Constant Definitions
|
||||
*************************************************************************************************/
|
||||
|
||||
/*! \brief The maximum length of a power measurement */
|
||||
#define CPPS_PM_MAX_LEN 34
|
||||
|
||||
/*! \brief The maximum length of a field in a power measurement */
|
||||
#define CPPS_PM_MAX_FIELD_LEN 6
|
||||
|
||||
/*! \brief Power Measurement Flag Indicies */
|
||||
enum
|
||||
{
|
||||
CPPS_PPBP_FLAG_INDEX, /* Pedal Power Balance Present */
|
||||
CPPS_PPBR_FLAG_INDEX, /* Pedal Power Balance Reference */
|
||||
CPPS_ATP_FLAG_INDEX, /* Accumulated Torque Present */
|
||||
CPPS_ATS_FLAG_INDEX, /* Accumulated Torque Source */
|
||||
CPPS_WRDP_FLAG_INDEX, /* Wheel Revolution Data Present */
|
||||
CPPS_CRDP_FLAG_INDEX, /* Crank Revolution Data Present */
|
||||
CPPS_EFMP_FLAG_INDEX, /* Extreme Force Magnitudes Present */
|
||||
CPPS_ETMP_FLAG_INDEX, /* Extreme Torque Magnitudes Present */
|
||||
CPPS_EAP_FLAG_INDEX, /* Extreme Angles Present */
|
||||
CPPS_TDSAP_FLAG_INDEX, /* Top Dead Spot Angle Present */
|
||||
CPPS_BDSAP_FLAG_INDEX, /* Bottom Dead Spot Angle Present */
|
||||
CPPS_AEP_FLAG_INDEX, /* Accumulated Energy Present */
|
||||
CPPS_OCI_FLAG_INDEX, /* Offset Compensation Indicator */
|
||||
CPPS_NUM_FLAGS
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Power Measurement Data */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t flags; /* Power Measurement Flags */
|
||||
uint16_t insantaneousPower; /* Instantaneous Power Measurement */
|
||||
uint8_t powerBalance; /* Pedal Power Balance */
|
||||
uint16_t accumulatedTorque; /* Accumulated Torque */
|
||||
uint32_t wheelRevolutions; /* Wheel Revolution */
|
||||
uint16_t wheelEventTime; /* Last Wheel Revolution Event Time */
|
||||
uint16_t crankRevolutions; /* Crank Revolution */
|
||||
uint16_t crankEventTime; /* Last Crank Revolution Event Time */
|
||||
uint16_t maxForceMagnitude; /* Max Extreme Force Magnitudes */
|
||||
uint16_t minForceMagnitude; /* Min Extreme Force Magnitudes */
|
||||
uint16_t maxTorqueMagnitude; /* Max Extreme Torque Magnitudes */
|
||||
uint16_t minTorqueMagnitude; /* Min Extreme Torque Magnitudes */
|
||||
uint16_t maxAngle; /* Max Extreme Angles */
|
||||
uint16_t minAngle; /* Min Extreme Angles */
|
||||
uint16_t topDeadSpotAngle; /* Top Dead Spot Angle */
|
||||
uint16_t btmDeadSpotAngle; /* Bottom Dead Spot Angle */
|
||||
uint16_t accumulatedEnergy; /* Accumulated Energy */
|
||||
} cppPmData_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief measurement data */
|
||||
cppPmData_t cppsPmData;
|
||||
|
||||
/*! \brief index of measurement notification when MTU is too small to send all at once */
|
||||
uint8_t nextMeasFlag[DM_CONN_MAX];
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the sensor location attribute.
|
||||
*
|
||||
* \param location Sensor Location.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CppsSetSensorLocation(uint8_t location)
|
||||
{
|
||||
AttsSetAttr(CPS_CPSL_HDL, sizeof(uint8_t), &location);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the features attribute.
|
||||
*
|
||||
* \param features Features bitmask.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CppsSetFeatures(uint32_t features)
|
||||
{
|
||||
uint8_t tempData[4] = {UINT32_TO_BYTES(features)};
|
||||
AttsSetAttr(CPS_CPF_HDL, sizeof(tempData), tempData);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set a cycling power measurement parameter.
|
||||
*
|
||||
* \param type Parameter identifier
|
||||
* \param value Measurement value.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CppsSetParameter(uint8_t type, uint32_t value)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case CPP_PM_PARAM_INSTANTANEOUS_POWER:
|
||||
cppsPmData.insantaneousPower = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_PEDAL_POWER:
|
||||
cppsPmData.flags |= (1 << CPPS_PPBP_FLAG_INDEX);
|
||||
cppsPmData.powerBalance = (uint8_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_ACCUMULATED_TORQUE:
|
||||
cppsPmData.flags |= (1 << CPPS_ATP_FLAG_INDEX);
|
||||
cppsPmData.accumulatedTorque = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_WHEEL_REVOLUTIONS:
|
||||
cppsPmData.flags |= (1 << CPPS_WRDP_FLAG_INDEX);
|
||||
cppsPmData.wheelRevolutions = value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_LAST_WHEEL_REV_TIME:
|
||||
cppsPmData.flags |= (1 << CPPS_WRDP_FLAG_INDEX);
|
||||
cppsPmData.wheelEventTime = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_CRANK_REVOLUTIONS:
|
||||
cppsPmData.flags |= (1 << CPPS_CRDP_FLAG_INDEX);
|
||||
cppsPmData.crankRevolutions = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_LAST_CRANK_TIME:
|
||||
cppsPmData.flags |= (1 << CPPS_CRDP_FLAG_INDEX);
|
||||
cppsPmData.crankEventTime = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_MAX_FORCE_MAGNITUDE:
|
||||
cppsPmData.flags |= (1 << CPPS_EFMP_FLAG_INDEX);
|
||||
cppsPmData.maxForceMagnitude = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_MIN_FORCE_MAGNITUDE:
|
||||
cppsPmData.flags |= (1 << CPPS_EFMP_FLAG_INDEX);
|
||||
cppsPmData.minForceMagnitude = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_MAX_TORQUE_MAGNITUDE:
|
||||
cppsPmData.flags |= (1 << CPPS_ETMP_FLAG_INDEX);
|
||||
cppsPmData.maxTorqueMagnitude = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_MIN_TORQUE_MAGNITUDE:
|
||||
cppsPmData.flags |= (1 << CPPS_ETMP_FLAG_INDEX);
|
||||
cppsPmData.minTorqueMagnitude = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_MAX_EXTREME_ANGLE:
|
||||
cppsPmData.flags |= (1 << CPPS_EAP_FLAG_INDEX);
|
||||
cppsPmData.maxAngle = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_MIN_EXTREME_ANGLE:
|
||||
cppsPmData.flags |= (1 << CPPS_EAP_FLAG_INDEX);
|
||||
cppsPmData.minAngle = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_TOP_DEAD_SPOT:
|
||||
cppsPmData.flags |= (1 << CPPS_TDSAP_FLAG_INDEX);
|
||||
cppsPmData.topDeadSpotAngle = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_BOTTOM_DEAD_SPOT:
|
||||
cppsPmData.flags |= (1 << CPPS_BDSAP_FLAG_INDEX);
|
||||
cppsPmData.btmDeadSpotAngle = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CPP_PM_PARAM_ACCUMULATED_ENERGY:
|
||||
cppsPmData.flags |= (1 << CPPS_AEP_FLAG_INDEX);
|
||||
cppsPmData.accumulatedEnergy = (uint16_t) value;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Notifies the collector of a Cycle Power Measurement.
|
||||
*
|
||||
* \param connId Connection ID
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CppsSendPowerMeasurement(dmConnId_t connId)
|
||||
{
|
||||
int8_t i;
|
||||
uint16_t flags = 0;
|
||||
uint16_t len = 0;
|
||||
uint8_t msg[CPPS_PM_MAX_LEN];
|
||||
uint8_t measChar[CPPS_PM_MAX_FIELD_LEN];
|
||||
uint8_t *pMeasChar;
|
||||
uint8_t *pMsg = msg;
|
||||
uint32_t temp;
|
||||
uint16_t maxValueLen;
|
||||
|
||||
/* Get maximum length for a notification (ATT_MTU - 3) */
|
||||
maxValueLen = AttGetMtu(connId) - ATT_VALUE_NTF_LEN;
|
||||
|
||||
/* Add manditory parameters. skip flags field for now */
|
||||
UINT16_TO_BSTREAM(pMsg, 0);
|
||||
UINT16_TO_BSTREAM(pMsg, cppsPmData.insantaneousPower);
|
||||
|
||||
/* Add optional parameters */
|
||||
for (i = nextMeasFlag[connId - 1]; i < CPPS_NUM_FLAGS; i++)
|
||||
{
|
||||
/* Add data if flag is set */
|
||||
if (cppsPmData.flags & (1 << i))
|
||||
{
|
||||
pMeasChar = measChar;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case CPPS_PPBP_FLAG_INDEX:
|
||||
UINT8_TO_BSTREAM(pMeasChar, cppsPmData.powerBalance);
|
||||
break;
|
||||
case CPPS_ATP_FLAG_INDEX:
|
||||
UINT16_TO_BSTREAM(pMeasChar, cppsPmData.accumulatedTorque);
|
||||
break;
|
||||
case CPPS_WRDP_FLAG_INDEX:
|
||||
UINT32_TO_BSTREAM(pMeasChar, cppsPmData.wheelRevolutions);
|
||||
UINT16_TO_BSTREAM(pMeasChar, cppsPmData.wheelEventTime);
|
||||
break;
|
||||
case CPPS_CRDP_FLAG_INDEX:
|
||||
UINT16_TO_BSTREAM(pMeasChar, cppsPmData.crankRevolutions);
|
||||
UINT16_TO_BSTREAM(pMeasChar, cppsPmData.crankEventTime);
|
||||
break;
|
||||
case CPPS_EFMP_FLAG_INDEX:
|
||||
UINT16_TO_BSTREAM(pMeasChar, cppsPmData.maxForceMagnitude);
|
||||
UINT16_TO_BSTREAM(pMeasChar, cppsPmData.minForceMagnitude);
|
||||
break;
|
||||
case CPPS_ETMP_FLAG_INDEX:
|
||||
UINT16_TO_BSTREAM(pMeasChar, cppsPmData.maxTorqueMagnitude);
|
||||
UINT16_TO_BSTREAM(pMeasChar, cppsPmData.minTorqueMagnitude);
|
||||
break;
|
||||
case CPPS_EAP_FLAG_INDEX:
|
||||
temp = ((uint32_t)cppsPmData.maxAngle & 0xfff) | ((uint32_t)cppsPmData.minAngle << 12);
|
||||
UINT24_TO_BSTREAM(pMeasChar, temp);
|
||||
break;
|
||||
case CPPS_TDSAP_FLAG_INDEX:
|
||||
UINT16_TO_BSTREAM(pMeasChar, cppsPmData.topDeadSpotAngle);
|
||||
break;
|
||||
case CPPS_BDSAP_FLAG_INDEX:
|
||||
UINT16_TO_BSTREAM(pMeasChar, cppsPmData.btmDeadSpotAngle);
|
||||
break;
|
||||
case CPPS_AEP_FLAG_INDEX:
|
||||
UINT16_TO_BSTREAM(pMeasChar, cppsPmData.accumulatedEnergy);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add data into message buffer */
|
||||
if ((len = pMeasChar - measChar) > 0)
|
||||
{
|
||||
if ((pMsg + len - msg) <= maxValueLen)
|
||||
{
|
||||
memcpy(pMsg, measChar, len);
|
||||
pMsg += len;
|
||||
|
||||
flags |= cppsPmData.flags & (1 << i);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Buffer is full. Store current flag offset for next Notification. */
|
||||
nextMeasFlag[connId - 1] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If all flags checked reset flag index */
|
||||
if (i == CPPS_NUM_FLAGS)
|
||||
{
|
||||
nextMeasFlag[connId - 1] = 0;
|
||||
}
|
||||
|
||||
/* Set flags */
|
||||
UINT16_TO_BUF(msg, flags);
|
||||
|
||||
/* Calculate message length */
|
||||
len = (uint16_t) (pMsg - msg);
|
||||
|
||||
/* Transmit notification */
|
||||
AttsHandleValueNtf(connId, CPS_CPM_HDL, len, msg);
|
||||
|
||||
/* Clear the measurement data */
|
||||
memset(&cppsPmData, 0, sizeof(cppsPmData));
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn CppsConnOpen
|
||||
*
|
||||
* \brief Setup connection specific variables.
|
||||
*
|
||||
* \param connId Connection ID
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CppsConnOpen(dmConnId_t connId)
|
||||
{
|
||||
nextMeasFlag[connId - 1] = 0;
|
||||
}
|
||||
Vendored
+104
@@ -0,0 +1,104 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Cycling Speed and Cadence Profile API.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#ifndef CSCP_API_H
|
||||
#define CSCP_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup CYCLING_SPEED_AND_CADENCE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name Cycling Speed Measurement Parameter Types
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define CSCP_SM_PARAM_WHEEL_REVOLUTIONS 0 /* Cumulative Wheel Revolutions */
|
||||
#define CSCP_SM_PARAM_LAST_WHEEL_EVT_TIME 1 /* Last Wheel Event Time */
|
||||
#define CSCP_SM_PARAM_CRANK_REVOLUTIONS 2 /* Cumulative Crank Revolutions */
|
||||
#define CSCP_SM_PARAM_LAST_CRANK_TIME 3 /* Last Crank Event Time */
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set a cycling speed measurement parameter.
|
||||
*
|
||||
* \param type Parameter identifier
|
||||
* \param value Measurement value.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CscpsSetParameter(uint8_t type, uint32_t value);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Notifies the collector of a Cycle Speed Measurement.
|
||||
*
|
||||
* \param connId Connection ID
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CscpsSendSpeedMeasurement(dmConnId_t connId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the sensor location attribute.
|
||||
*
|
||||
* \param location Sensor Location.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CscpsSetSensorLocation(uint8_t location);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the features attribute.
|
||||
*
|
||||
* \param features Features bitmask.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CscpsSetFeatures(uint16_t features);
|
||||
|
||||
/*! \} */ /* CYCLING_SPEED_AND_CADENCE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* CSCP_API_H */
|
||||
ambiq-hal-sys/ambiq-sparkfun-sdk/third_party/exactle/ble-profiles/sources/profiles/cscp/cscps_main.c
Vendored
+185
@@ -0,0 +1,185 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Cycling Speed and Cadence Profile Sensor Implementation.
|
||||
*
|
||||
* Copyright (c) 2016-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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "dm_api.h"
|
||||
#include "svc_cscs.h"
|
||||
#include "svc_ch.h"
|
||||
#include "cscp_api.h"
|
||||
|
||||
/*************************************************************************************************
|
||||
* Constant Definitions
|
||||
*************************************************************************************************/
|
||||
|
||||
/*! \brief The maximum length of a power measurement */
|
||||
#define CSCPS_PM_MAX_LEN 11
|
||||
|
||||
/*! \brief Cycle Speed and Cadence Measurement Flag Indicies */
|
||||
enum
|
||||
{
|
||||
CSCPS_WRDP_FLAG_INDEX, /*! \brief Wheel Revolution Data Present */
|
||||
CSCPS_CRDP_FLAG_INDEX, /*! \brief Crank Revolution Data Present */
|
||||
CSCPS_NUM_FLAGS
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Cycle Speed Measurement Data */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t flags; /*! \brief Speed Measurement Flags */
|
||||
uint32_t wheelRevs; /*! \brief Cumulative Wheel Revolutions */
|
||||
uint16_t lastWheelEventTime; /*! \brief Last Wheel Event Time */
|
||||
uint16_t crankRevs; /*! \brief Cumulative Crank Revolutions */
|
||||
uint16_t lastCrankEventTime; /*! \brief Last Crank Event Time */
|
||||
} cscpSmData_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Measurement data */
|
||||
cscpSmData_t cscpsSmData;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set a cycling speed measurement parameter.
|
||||
*
|
||||
* \param type Parameter identifier
|
||||
* \param value Measurement value.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CscpsSetParameter(uint8_t type, uint32_t value)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case CSCP_SM_PARAM_WHEEL_REVOLUTIONS:
|
||||
cscpsSmData.flags |= (1 << CSCPS_WRDP_FLAG_INDEX);
|
||||
cscpsSmData.wheelRevs = value;
|
||||
break;
|
||||
|
||||
case CSCP_SM_PARAM_LAST_WHEEL_EVT_TIME:
|
||||
cscpsSmData.flags |= (1 << CSCPS_WRDP_FLAG_INDEX);
|
||||
cscpsSmData.lastWheelEventTime = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CSCP_SM_PARAM_CRANK_REVOLUTIONS:
|
||||
cscpsSmData.flags |= (1 << CSCPS_CRDP_FLAG_INDEX);
|
||||
cscpsSmData.crankRevs = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case CSCP_SM_PARAM_LAST_CRANK_TIME:
|
||||
cscpsSmData.flags |= (1 << CSCPS_CRDP_FLAG_INDEX);
|
||||
cscpsSmData.lastCrankEventTime = (uint16_t) value;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the sensor location attribute.
|
||||
*
|
||||
* \param location Sensor Location.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CscpsSetSensorLocation(uint8_t location)
|
||||
{
|
||||
AttsSetAttr(CSCS_SL_HDL, sizeof(uint8_t), &location);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the features attribute.
|
||||
*
|
||||
* \param features Features bitmask.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CscpsSetFeatures(uint16_t features)
|
||||
{
|
||||
uint8_t tempData[2] = {UINT16_TO_BYTES(features)};
|
||||
AttsSetAttr(CSCS_CSF_HDL, sizeof(tempData), tempData);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Notifies the collector of a Cycle Speed Measurement.
|
||||
*
|
||||
* \param connId Connection ID
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void CscpsSendSpeedMeasurement(dmConnId_t connId)
|
||||
{
|
||||
int8_t i;
|
||||
uint16_t len;
|
||||
uint8_t msg[CSCPS_PM_MAX_LEN];
|
||||
uint8_t *p = msg;
|
||||
|
||||
/* Add manditory parameters */
|
||||
UINT8_TO_BSTREAM(p, cscpsSmData.flags);
|
||||
|
||||
/* Add optional parameters */
|
||||
for (i = 0; i < CSCPS_NUM_FLAGS; i++)
|
||||
{
|
||||
if (cscpsSmData.flags & (1 << i))
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case CSCPS_WRDP_FLAG_INDEX:
|
||||
UINT32_TO_BSTREAM(p, cscpsSmData.wheelRevs);
|
||||
UINT16_TO_BSTREAM(p, cscpsSmData.lastWheelEventTime);
|
||||
break;
|
||||
case CSCPS_CRDP_FLAG_INDEX:
|
||||
UINT16_TO_BSTREAM(p, cscpsSmData.crankRevs);
|
||||
UINT16_TO_BSTREAM(p, cscpsSmData.lastCrankEventTime);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate message length */
|
||||
len = (uint16_t) (p - msg);
|
||||
|
||||
/* Transmit notification */
|
||||
AttsHandleValueNtf(connId, CSCS_CSM_HDL, len, msg);
|
||||
|
||||
/* Clear the measurement data */
|
||||
memset(&cscpsSmData, 0, sizeof(cscpsSmData));
|
||||
}
|
||||
Vendored
+93
@@ -0,0 +1,93 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device information service client.
|
||||
*
|
||||
* 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 DIS_API_H
|
||||
#define DIS_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup DEVICE_INFORMATION_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
DIS_MFNS_HDL_IDX, /*!< \brief Manufacturer name string */
|
||||
DIS_MNS_HDL_IDX, /*!< \brief Model number string */
|
||||
DIS_SNS_HDL_IDX, /*!< \brief Serial number string */
|
||||
DIS_HRS_HDL_IDX, /*!< \brief Hardware revision string */
|
||||
DIS_FRS_HDL_IDX, /*!< \brief Firmware revision string */
|
||||
DIS_SRS_HDL_IDX, /*!< \brief Software revision string */
|
||||
DIS_SID_HDL_IDX, /*!< \brief System ID */
|
||||
DIS_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for DIS service. Note that pHdlList
|
||||
* must point to an array of handles of length \ref DIS_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DisDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length \ref DIS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if handle is found, \ref ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t DisValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg);
|
||||
|
||||
/*! \} */ /* DEVICE_INFORMATION_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* DIS_API_H */
|
||||
Vendored
+205
@@ -0,0 +1,205 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Device information service client.
|
||||
*
|
||||
* 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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "svc_ch.h"
|
||||
#include "app_api.h"
|
||||
#include "dis_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! DIS characteristics for discovery */
|
||||
|
||||
/*! Manufacturer name string */
|
||||
static const attcDiscChar_t disMfns =
|
||||
{
|
||||
attMfnsChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Model number string */
|
||||
static const attcDiscChar_t disMns =
|
||||
{
|
||||
attMnsChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Serial number string */
|
||||
static const attcDiscChar_t disSns =
|
||||
{
|
||||
attSnsChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Hardware revision string */
|
||||
static const attcDiscChar_t disHrs =
|
||||
{
|
||||
attHrsChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Firmware revision string */
|
||||
static const attcDiscChar_t disFrs =
|
||||
{
|
||||
attFrsChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Software revision string */
|
||||
static const attcDiscChar_t disSrs =
|
||||
{
|
||||
attSrsChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! System ID */
|
||||
static const attcDiscChar_t disSid =
|
||||
{
|
||||
attSidChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *disDiscCharList[] =
|
||||
{
|
||||
&disMfns, /*! Manufacturer name string */
|
||||
&disMns, /*! Model number string */
|
||||
&disSns, /*! Serial number string */
|
||||
&disHrs, /*! Hardware revision string */
|
||||
&disFrs, /*! Firmware revision string */
|
||||
&disSrs, /*! Software revision string */
|
||||
&disSid /*! System ID */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(DIS_HDL_LIST_LEN == ((sizeof(disDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Format a string for printing.
|
||||
*
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return Buffer containing string.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
char *disFmtString(uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
static char buf[ATT_DEFAULT_PAYLOAD_LEN + 1];
|
||||
|
||||
len = (len < (sizeof(buf) - 1)) ? len : (sizeof(buf) - 1);
|
||||
|
||||
memcpy(buf, pValue, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for DIS service. Parameter pHdlList
|
||||
* must point to an array of length DIS_HDL_LIST_LEN. If discovery is successful
|
||||
* the handles of discovered characteristics and descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void DisDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attDisSvcUuid,
|
||||
DIS_HDL_LIST_LEN, (attcDiscChar_t **) disDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length DIS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t DisValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
|
||||
/* manufacturer name string */
|
||||
if (pMsg->handle == pHdlList[DIS_MFNS_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO1("Mfgr: %s", disFmtString(pMsg->pValue, pMsg->valueLen));
|
||||
}
|
||||
/* model number string */
|
||||
else if (pMsg->handle == pHdlList[DIS_MNS_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO1("Model num: %s", disFmtString(pMsg->pValue, pMsg->valueLen));
|
||||
}
|
||||
/* serial number string */
|
||||
else if (pMsg->handle == pHdlList[DIS_SNS_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO1("Serial num: %s", disFmtString(pMsg->pValue, pMsg->valueLen));
|
||||
}
|
||||
/* hardware revision string */
|
||||
else if (pMsg->handle == pHdlList[DIS_HRS_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO1("Hardware rev: %s", disFmtString(pMsg->pValue, pMsg->valueLen));
|
||||
}
|
||||
/* firmware revision string */
|
||||
else if (pMsg->handle == pHdlList[DIS_FRS_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO1("Firmware rev: %s", disFmtString(pMsg->pValue, pMsg->valueLen));
|
||||
}
|
||||
/* software revision string */
|
||||
else if (pMsg->handle == pHdlList[DIS_SRS_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO1("Software rev: %s", disFmtString(pMsg->pValue, pMsg->valueLen));
|
||||
}
|
||||
/* system id */
|
||||
else if (pMsg->handle == pHdlList[DIS_SID_HDL_IDX])
|
||||
{
|
||||
if (pMsg->valueLen == CH_SYSTEM_ID_LEN)
|
||||
{
|
||||
APP_TRACE_INFO0("System ID read ok");
|
||||
}
|
||||
}
|
||||
/* handle not found in list */
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
Vendored
+85
@@ -0,0 +1,85 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Find Me profile, locator role.
|
||||
*
|
||||
* Copyright (c) 2011-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 FMPL_API_H
|
||||
#define FMPL_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup FIND_ME_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Enumeration of handle indexes of characteristics to be discovered for immediate alert service */
|
||||
enum
|
||||
{
|
||||
FMPL_IAS_AL_HDL_IDX, /*!< \brief Alert level */
|
||||
FMPL_IAS_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Immediate Alert service. Note
|
||||
* that pHdlList must point to an array of handles of length \ref FMPL_IAS_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void FmplIasDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send an immediate alert to the peer device.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param alert Alert value.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void FmplSendAlert(dmConnId_t connId, uint16_t handle, uint8_t alert);
|
||||
|
||||
/*! \} */ /* FIND_ME_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* FMPL_API_H */
|
||||
Vendored
+92
@@ -0,0 +1,92 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Find Me profile, locator role.
|
||||
*
|
||||
* Copyright (c) 2011-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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "app_api.h"
|
||||
#include "fmpl_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Immediate Alert service characteristics for discovery */
|
||||
|
||||
/*! Alert level */
|
||||
const attcDiscChar_t fmplIasAl =
|
||||
{
|
||||
attAlChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *fmplIasDiscCharList[] =
|
||||
{
|
||||
&fmplIasAl /* Alert level */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(FMPL_IAS_HDL_LIST_LEN == ((sizeof(fmplIasDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Immediate Alert service. Note
|
||||
* that pHdlList must point to an array of handles of length FMPL_IAS_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void FmplIasDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attIasSvcUuid,
|
||||
FMPL_IAS_HDL_LIST_LEN, (attcDiscChar_t **) fmplIasDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send an immediate alert to the peer device.
|
||||
*
|
||||
* \param connId DM connection ID.
|
||||
* \param handle Attribute handle.
|
||||
* \param alert Alert value.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void FmplSendAlert(dmConnId_t connId, uint16_t handle, uint8_t alert)
|
||||
{
|
||||
uint8_t buf[1];
|
||||
|
||||
if (handle != ATT_HANDLE_NONE)
|
||||
{
|
||||
buf[0] = alert;
|
||||
AttcWriteCmd(connId, handle, 1, buf);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+88
@@ -0,0 +1,88 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief GAP profile.
|
||||
*
|
||||
* Copyright (c) 2015-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 GAP_API_H
|
||||
#define GAP_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup GAP_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
GAP_CAR_HDL_IDX, /*!< \brief Central Address Resolution */
|
||||
GAP_RPAO_HDL_IDX, /*!< \brief Resolvable Private Address Only */
|
||||
GAP_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for GAP service. Note that pHdlList
|
||||
* must point to an array of handles of length \ref GAP_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GapDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length \ref GAP_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if handle is found, \ref ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GapValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg);
|
||||
|
||||
/*! \} */ /* GAP_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* GAP_API_H */
|
||||
Vendored
+127
@@ -0,0 +1,127 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief GAP profile.
|
||||
*
|
||||
* Copyright (c) 2015-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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "app_db.h"
|
||||
#include "app_api.h"
|
||||
#include "gap_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! GAP service characteristics for discovery */
|
||||
|
||||
/*! Central Address Resolution */
|
||||
static const attcDiscChar_t gapCar =
|
||||
{
|
||||
attCarChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Resolvable Private Address Only */
|
||||
static const attcDiscChar_t gapRpao =
|
||||
{
|
||||
attRpaoChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *gapDiscCharList[] =
|
||||
{
|
||||
&gapCar, /* Central Address Resolution */
|
||||
&gapRpao /* Resolvable Private Address Only */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(GAP_HDL_LIST_LEN == ((sizeof(gapDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for GAP service. Note that pHdlList
|
||||
* must point to an array of handles of length GAP_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GapDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attGapSvcUuid,
|
||||
GAP_HDL_LIST_LEN, (attcDiscChar_t **) gapDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length GAP_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GapValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
|
||||
/* Central Address Resolution */
|
||||
if (pMsg->handle == pHdlList[GAP_CAR_HDL_IDX])
|
||||
{
|
||||
appDbHdl_t dbHdl;
|
||||
|
||||
/* if there's a device record */
|
||||
if ((dbHdl = AppDbGetHdl((dmConnId_t)pMsg->hdr.param)) != APP_DB_HDL_NONE)
|
||||
{
|
||||
if ((pMsg->pValue[0] == FALSE) || (pMsg->pValue[0] == TRUE))
|
||||
{
|
||||
/* store value in device database */
|
||||
AppDbSetPeerAddrRes(dbHdl, pMsg->pValue[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* invalid value */
|
||||
status = ATT_ERR_RANGE;
|
||||
}
|
||||
|
||||
APP_TRACE_INFO1("Central address resolution: %d", pMsg->pValue[0]);
|
||||
}
|
||||
}
|
||||
/* handle not found in list */
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
Vendored
+148
@@ -0,0 +1,148 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief GATT profile.
|
||||
*
|
||||
* Copyright (c) 2011-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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef GATT_API_H
|
||||
#define GATT_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup GATT_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
GATT_SC_HDL_IDX, /*!< \brief Service changed */
|
||||
GATT_SC_CCC_HDL_IDX, /*!< \brief Service changed client characteristic configuration descriptor */
|
||||
GATT_CSF_HDL_IDX, /*!< \brief Client Supported Features */
|
||||
GATT_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for GATT service. Note that pHdlList
|
||||
* must point to an array of handles of length \ref GATT_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GattDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length \ref GATT_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if handle is found, \ref ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GattValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS read callback for gatt service.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle ATT handle.
|
||||
* \param operation Operation selected.
|
||||
* \param offset Offset to begin read from.
|
||||
* \param pAttr Attribute to read from.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GattReadCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, attsAttr_t *pAttr);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for gatt service.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle ATT handle.
|
||||
* \param operation Operation selected.
|
||||
* \param offset Offset to begin write.
|
||||
* \param len Length of write.
|
||||
* \param pValue Pointer to buffer to write.
|
||||
* \param pAttr Attribute to write to.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GattWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set Index of the Service Changed CCCD in the ATT Server.
|
||||
*
|
||||
* \param idx Index of the Service Changed CCCD in the ATT Server.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GattSetSvcChangedIdx(uint8_t idx);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send Service Change Indications to the specified connections if they are configured to
|
||||
* do so.
|
||||
*
|
||||
* \param connId DM Connection identifier or \ref DM_CONN_ID_NONE to send to all connections.
|
||||
* \param start start handle for service changed value.
|
||||
* \param end end handle for service changed value.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GattSendServiceChangedInd(dmConnId_t connId, uint16_t start, uint16_t end);
|
||||
|
||||
/*! \} */ /* GATT_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* GATT_API_H */
|
||||
Vendored
+265
@@ -0,0 +1,265 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief GATT profile.
|
||||
*
|
||||
* Copyright (c) 2011-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_assert.h"
|
||||
#include "util/bstream.h"
|
||||
#include "app_api.h"
|
||||
#include "gatt_api.h"
|
||||
#include "svc_core.h"
|
||||
#include "att_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block. */
|
||||
typedef struct
|
||||
{
|
||||
bool_t svcChangedCccdIdxSet; /* Check if Service Changed CCCD index has been initialized. */
|
||||
uint8_t svcChangedCccdIdx; /* Stored index of Service Changed CCCD. */
|
||||
} gattServCb_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block. */
|
||||
gattServCb_t gattServCb;
|
||||
|
||||
/*! GATT service characteristics for discovery */
|
||||
|
||||
/*! Service changed */
|
||||
static const attcDiscChar_t gattSc =
|
||||
{
|
||||
attScChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Service changed client characteristic configuration descriptor */
|
||||
static const attcDiscChar_t gattScCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Client supported features */
|
||||
static const attcDiscChar_t gattCsf =
|
||||
{
|
||||
attGattCsfChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *gattDiscCharList[] =
|
||||
{
|
||||
&gattSc, /* Service changed */
|
||||
&gattScCcc, /* Service changed client characteristic configuration descriptor */
|
||||
&gattCsf /* Client supported features */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(GATT_HDL_LIST_LEN == ((sizeof(gattDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for GATT service. Parameter pHdlList
|
||||
* must point to an array of length GATT_HDL_LIST_LEN. If discovery is successful
|
||||
* the handles of discovered characteristics and descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GattDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attGattSvcUuid,
|
||||
GATT_HDL_LIST_LEN, (attcDiscChar_t **) gattDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length GATT_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GattValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
|
||||
/* service changed */
|
||||
if (pMsg->handle == pHdlList[GATT_SC_HDL_IDX])
|
||||
{
|
||||
/* perform service changed */
|
||||
AppDiscServiceChanged(pMsg);
|
||||
}
|
||||
/* handle not found in list */
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set Index of the Service Changed CCCD in the ATT Server.
|
||||
*
|
||||
* \param idx Index of the Service Changed CCCD in the ATT Server.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GattSetSvcChangedIdx(uint8_t idx)
|
||||
{
|
||||
gattServCb.svcChangedCccdIdxSet = TRUE;
|
||||
gattServCb.svcChangedCccdIdx = idx;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send Service Change Indications to the specified connections if they are configured to
|
||||
* do so.
|
||||
*
|
||||
* \param connId DM Connection identifier or \ref DM_CONN_ID_NONE to send to all connections.
|
||||
* \param start start handle for service changed value.
|
||||
* \param end end handle for service changed value.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GattSendServiceChangedInd(dmConnId_t connId, uint16_t start, uint16_t end)
|
||||
{
|
||||
uint8_t svcChangedValues[4];
|
||||
uint8_t *p;
|
||||
|
||||
if (!gattServCb.svcChangedCccdIdxSet)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
p = svcChangedValues;
|
||||
UINT16_TO_BSTREAM(p, start);
|
||||
UINT16_TO_BSTREAM(p, end);
|
||||
|
||||
/* If connection is not specified */
|
||||
if (connId == DM_CONN_ID_NONE)
|
||||
{
|
||||
/* Send to all. */
|
||||
for (connId = 1; connId <= DM_CONN_MAX; connId++)
|
||||
{
|
||||
if (AttsCccEnabled(connId, gattServCb.svcChangedCccdIdx))
|
||||
{
|
||||
AttsHandleValueInd(connId, GATT_SC_HDL, sizeof(svcChangedValues), svcChangedValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Send to only this one. */
|
||||
if (AttsCccEnabled(connId, gattServCb.svcChangedCccdIdx))
|
||||
{
|
||||
AttsHandleValueInd(connId, GATT_SC_HDL, sizeof(svcChangedValues), svcChangedValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS read callback for gatt service.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle ATT handle.
|
||||
* \param operation Operation selected.
|
||||
* \param offset Offset to begin read from.
|
||||
* \param pAttr Attribute to read from.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GattReadCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, attsAttr_t *pAttr)
|
||||
{
|
||||
switch (handle)
|
||||
{
|
||||
case GATT_CSF_HDL:
|
||||
{
|
||||
uint8_t csf[ATT_CSF_LEN];
|
||||
|
||||
AttsCsfGetFeatures(connId, csf, sizeof(csf));
|
||||
memcpy(pAttr->pValue, csf, ATT_CSF_LEN);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for gatt service.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle ATT handle.
|
||||
* \param operation Operation selected.
|
||||
* \param offset Offset to begin write.
|
||||
* \param len Length of write.
|
||||
* \param pValue Pointer to buffer to write.
|
||||
* \param pAttr Attribute to write to.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GattWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
switch (handle)
|
||||
{
|
||||
case GATT_CSF_HDL:
|
||||
status = AttsCsfWriteFeatures(connId, offset, len, pValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = ATT_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
Vendored
+143
@@ -0,0 +1,143 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Glucose profile collector.
|
||||
*
|
||||
* 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 GLPC_API_H
|
||||
#define GLPC_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup GLUCOSE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Glucose service enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
GLPC_GLS_GLM_HDL_IDX, /*!< \brief Glucose measurement */
|
||||
GLPC_GLS_GLM_CCC_HDL_IDX, /*!< \brief Glucose measurement CCC descriptor */
|
||||
GLPC_GLS_GLMC_HDL_IDX, /*!< \brief Glucose measurement context */
|
||||
GLPC_GLS_GLMC_CCC_HDL_IDX, /*!< \brief Glucose measurement context CCC descriptor */
|
||||
GLPC_GLS_GLF_HDL_IDX, /*!< \brief Glucose feature */
|
||||
GLPC_GLS_RACP_HDL_IDX, /*!< \brief Record access control point */
|
||||
GLPC_GLS_RACP_CCC_HDL_IDX, /*!< \brief Record access control point CCC descriptor */
|
||||
GLPC_GLS_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Glucose service RACP filter type */
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
uint16_t seqNum; /*!< \brief Sequence number filter */
|
||||
} param; /*!< \brief Parameter union */
|
||||
uint8_t type; /*!< \brief Filter type */
|
||||
} glpcFilter_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Glucose service.
|
||||
* Parameter pHdlList must point to an array of length \ref GLPC_GLS_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpcGlsDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length \ref GLPC_GLS_HDL_LIST_LEN.
|
||||
* If the ATT handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if handle is found, \ref ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GlpcGlsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a command to the glucose service record access control point.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param opcode Command opcode.
|
||||
* \param oper Command operator or 0 if no operator required.
|
||||
* \param pFilter Command filter parameters or NULL of no parameters required.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpcGlsRacpSend(dmConnId_t connId, uint16_t handle, uint8_t opcode, uint8_t oper,
|
||||
glpcFilter_t *pFilter);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the last received glucose measurement sequence number.
|
||||
*
|
||||
* \param seqNum Glucose measurement sequence number.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpcGlsSetLastSeqNum(uint16_t seqNum);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the last received glucose measurement sequence number.
|
||||
*
|
||||
* \return Last received glucose measurement sequence number.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t GlpcGlsGetLastSeqNum(void);
|
||||
|
||||
/*! \} */ /* GLUCOSE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* GLPC_API_H */
|
||||
Vendored
+535
@@ -0,0 +1,535 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Glucose profile collector.
|
||||
*
|
||||
* 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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_ch.h"
|
||||
#include "app_api.h"
|
||||
#include "glpc_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Length of response data contained in a received RACP message */
|
||||
#define GLPC_GLS_RACP_RSP_LEN 4
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*!
|
||||
* Glucose service characteristics for discovery
|
||||
*/
|
||||
|
||||
/*! Glucose measurement */
|
||||
static const attcDiscChar_t glpcGlsGlm =
|
||||
{
|
||||
attGlmChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Glucose measurement CCC descriptor */
|
||||
static const attcDiscChar_t glpcGlsGlmCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Glucose measurement context */
|
||||
static const attcDiscChar_t glpcGlsGlmc =
|
||||
{
|
||||
attGlmcChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Glucose measurement context CCC descriptor */
|
||||
static const attcDiscChar_t glpcGlsGlmcCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Glucose feature */
|
||||
static const attcDiscChar_t glpcGlsGlf =
|
||||
{
|
||||
attGlfChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Record access control point */
|
||||
static const attcDiscChar_t glpcGlsRacp =
|
||||
{
|
||||
attRacpChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Record access control point CCC descriptor */
|
||||
static const attcDiscChar_t glpcGlsRacpCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *glpcGlsDiscCharList[] =
|
||||
{
|
||||
&glpcGlsGlm, /*! Glucose measurement */
|
||||
&glpcGlsGlmCcc, /*! Glucose measurement CCC descriptor */
|
||||
&glpcGlsGlmc, /*! Glucose measurement context */
|
||||
&glpcGlsGlmcCcc, /*! Glucose measurement context CCC descriptor */
|
||||
&glpcGlsGlf, /*! Glucose feature */
|
||||
&glpcGlsRacp, /*! Record access control point */
|
||||
&glpcGlsRacpCcc /*! Record access control point CCC descriptor */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(GLPC_GLS_HDL_LIST_LEN == ((sizeof(glpcGlsDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*! Control block */
|
||||
static struct
|
||||
{
|
||||
uint16_t lastSeqNum; /*! Last received glucose measurement sequence number */
|
||||
} glpcCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Parse a glucose measurement.
|
||||
*
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpcGlsParseGlm(uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
uint8_t flags;
|
||||
uint16_t seqNum;
|
||||
uint16_t year;
|
||||
uint8_t month, day, hour, min, sec;
|
||||
int16_t timeOffset;
|
||||
uint16_t glucose;
|
||||
int16_t mantissa;
|
||||
int8_t exponent;
|
||||
uint8_t typeLoc;
|
||||
uint16_t sensorStatus;
|
||||
uint16_t minLen = CH_GLM_FLAGS_LEN + CH_GLM_SEQNUM_LEN + CH_GLM_TIMESTAMP_LEN;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)year; (void)month; (void)day; (void)hour; (void)min; (void)sec;
|
||||
(void)sensorStatus; (void)typeLoc; (void)exponent; (void)mantissa; (void)timeOffset;
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
/* get flags */
|
||||
BSTREAM_TO_UINT8(flags, pValue);
|
||||
|
||||
/* determine expected minimum length based on flags */
|
||||
if (flags & CH_GLM_FLAG_TIME_OFFSET)
|
||||
{
|
||||
minLen += CH_GLM_TIME_OFFSET_LEN;
|
||||
}
|
||||
if (flags & CH_GLM_FLAG_CONC_TYPE_LOC)
|
||||
{
|
||||
minLen += CH_GLM_CONC_TYPE_LOC_LEN;
|
||||
}
|
||||
if (flags & CH_GLM_FLAG_SENSOR_STATUS)
|
||||
{
|
||||
minLen += CH_GLM_SENSOR_STATUS_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
/* verify length */
|
||||
if (len < minLen)
|
||||
{
|
||||
APP_TRACE_INFO2("Glucose meas len:%d minLen:%d", len, minLen);
|
||||
return;
|
||||
}
|
||||
|
||||
/* sequence number */
|
||||
BSTREAM_TO_UINT16(seqNum, pValue);
|
||||
glpcCb.lastSeqNum = seqNum;
|
||||
|
||||
/* base time */
|
||||
BSTREAM_TO_UINT16(year, pValue);
|
||||
BSTREAM_TO_UINT8(month, pValue);
|
||||
BSTREAM_TO_UINT8(day, pValue);
|
||||
BSTREAM_TO_UINT8(hour, pValue);
|
||||
BSTREAM_TO_UINT8(min, pValue);
|
||||
BSTREAM_TO_UINT8(sec, pValue);
|
||||
APP_TRACE_INFO3(" Date: %d/%d/%d", month, day, year);
|
||||
APP_TRACE_INFO3(" Time: %02d:%02d:%02d", hour, min, sec);
|
||||
|
||||
/* time offset */
|
||||
if (flags & CH_GLM_FLAG_TIME_OFFSET)
|
||||
{
|
||||
BSTREAM_TO_UINT16(timeOffset, pValue);
|
||||
APP_TRACE_INFO1(" Time offset: %d", timeOffset);
|
||||
}
|
||||
|
||||
/* glucose concentration, type, and location */
|
||||
if (flags & CH_GLM_FLAG_CONC_TYPE_LOC)
|
||||
{
|
||||
BSTREAM_TO_UINT16(glucose, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, glucose);
|
||||
APP_TRACE_INFO2(" Glucose concentration: %de%d", mantissa, exponent);
|
||||
BSTREAM_TO_UINT8(typeLoc, pValue);
|
||||
APP_TRACE_INFO2(" Type: %d Location: %d", (typeLoc & 0x0F), (typeLoc >> 4));
|
||||
}
|
||||
|
||||
/* sensor status */
|
||||
if (flags & CH_GLM_FLAG_SENSOR_STATUS)
|
||||
{
|
||||
BSTREAM_TO_UINT16(sensorStatus, pValue);
|
||||
APP_TRACE_INFO1(" Sensor status: 0x%04x", sensorStatus);
|
||||
}
|
||||
|
||||
APP_TRACE_INFO2(" Flags: 0x%02x Sequence Number: %d", flags, seqNum);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Parse a glucose measurement context.
|
||||
*
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpcGlsParseGlmc(uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
uint8_t flags;
|
||||
uint16_t seqNum;
|
||||
uint8_t extFlags;
|
||||
uint8_t carbId;
|
||||
uint16_t carb;
|
||||
uint8_t meal;
|
||||
uint8_t testerHealth;
|
||||
uint16_t exerDuration;
|
||||
uint8_t exerIntensity;
|
||||
uint8_t medicationId;
|
||||
uint16_t medication;
|
||||
uint16_t hba1c;
|
||||
int16_t mantissa;
|
||||
int8_t exponent;
|
||||
uint16_t minLen = CH_GLMC_FLAGS_LEN + CH_GLMC_SEQNUM_LEN;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)seqNum; (void)extFlags; (void)carbId; (void)meal; (void)testerHealth;
|
||||
(void)medicationId; (void)exerIntensity; (void)exerDuration;
|
||||
(void)exponent; (void)mantissa;
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
/* get flags */
|
||||
BSTREAM_TO_UINT8(flags, pValue);
|
||||
|
||||
/* determine expected minimum length based on flags */
|
||||
if (flags & CH_GLMC_FLAG_CARB)
|
||||
{
|
||||
minLen += CH_GLMC_CARB_LEN;
|
||||
}
|
||||
if (flags & CH_GLMC_FLAG_MEAL)
|
||||
{
|
||||
minLen += CH_GLMC_MEAL_LEN;
|
||||
}
|
||||
if (flags & CH_GLMC_FLAG_TESTER)
|
||||
{
|
||||
minLen += CH_GLMC_TESTER_LEN;
|
||||
}
|
||||
if (flags & CH_GLMC_FLAG_EXERCISE)
|
||||
{
|
||||
minLen += CH_GLMC_EXERCISE_LEN;
|
||||
}
|
||||
if (flags & CH_GLMC_FLAG_MED)
|
||||
{
|
||||
minLen += CH_GLMC_MED_LEN;
|
||||
}
|
||||
if (flags & CH_GLMC_FLAG_HBA1C)
|
||||
{
|
||||
minLen += CH_GLMC_HBA1C_LEN;
|
||||
}
|
||||
if (flags & CH_GLMC_FLAG_EXT)
|
||||
{
|
||||
minLen += CH_GLMC_EXT_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
/* verify length */
|
||||
if (len < minLen)
|
||||
{
|
||||
APP_TRACE_INFO2("Glucose meas context len:%d minLen:%d", len, minLen);
|
||||
return;
|
||||
}
|
||||
|
||||
/* sequence number */
|
||||
BSTREAM_TO_UINT16(seqNum, pValue);
|
||||
|
||||
/* extended flags */
|
||||
if (flags & CH_GLMC_FLAG_EXT)
|
||||
{
|
||||
BSTREAM_TO_UINT8(extFlags, pValue);
|
||||
APP_TRACE_INFO1(" Extended Flags: 0x%02x", extFlags);
|
||||
}
|
||||
|
||||
/* carbohydrate id and carbohydrate */
|
||||
if (flags & CH_GLMC_FLAG_CARB)
|
||||
{
|
||||
BSTREAM_TO_UINT8(carbId, pValue);
|
||||
BSTREAM_TO_UINT16(carb, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, carb);
|
||||
APP_TRACE_INFO3(" Carb Id: %d Carb-kg: %de%d", carbId, mantissa, exponent);
|
||||
}
|
||||
|
||||
/* meal */
|
||||
if (flags & CH_GLMC_FLAG_MEAL)
|
||||
{
|
||||
BSTREAM_TO_UINT8(meal, pValue);
|
||||
APP_TRACE_INFO1(" Meal: %d", meal);
|
||||
}
|
||||
|
||||
/* tester-health */
|
||||
if (flags & CH_GLMC_FLAG_TESTER)
|
||||
{
|
||||
BSTREAM_TO_UINT8(testerHealth, pValue);
|
||||
APP_TRACE_INFO2(" Tester: %d Health: %d", (testerHealth & 0x0F), (testerHealth >> 4));
|
||||
}
|
||||
|
||||
/* exercise duration and exercise intensity */
|
||||
if (flags & CH_GLMC_FLAG_EXERCISE)
|
||||
{
|
||||
BSTREAM_TO_UINT16(exerDuration, pValue);
|
||||
BSTREAM_TO_UINT8(exerIntensity, pValue);
|
||||
APP_TRACE_INFO2(" Exercise Duration: %d Intensity: %d", exerDuration, exerIntensity);
|
||||
}
|
||||
|
||||
/* medication ID and medication */
|
||||
if (flags & CH_GLMC_FLAG_MED)
|
||||
{
|
||||
BSTREAM_TO_UINT8(medicationId, pValue);
|
||||
BSTREAM_TO_UINT16(medication, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, medication);
|
||||
APP_TRACE_INFO3(" Medication ID: %d Units: %de%d", medicationId, mantissa, exponent);
|
||||
}
|
||||
|
||||
/* hba1c */
|
||||
if (flags & CH_GLMC_FLAG_HBA1C)
|
||||
{
|
||||
BSTREAM_TO_UINT16(hba1c, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, hba1c);
|
||||
APP_TRACE_INFO2(" HbA1c: %de%d", mantissa, exponent);
|
||||
}
|
||||
|
||||
APP_TRACE_INFO2(" Flags: 0x%02x Sequence Number: %d", flags, seqNum);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a message received from the sensor on the record access control point.
|
||||
*
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpcGlsProcRacp(uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint16_t numRecords;
|
||||
uint16_t reqOpcode;
|
||||
uint16_t status;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)status; (void)reqOpcode; (void)numRecords;
|
||||
|
||||
/* verify length */
|
||||
if (len != GLPC_GLS_RACP_RSP_LEN)
|
||||
{
|
||||
APP_TRACE_INFO1("Unexpected RACP message length: %d", len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse message */
|
||||
BSTREAM_TO_UINT8(opcode, pValue);
|
||||
pValue++;
|
||||
if (opcode == CH_RACP_OPCODE_NUM_RSP)
|
||||
{
|
||||
BSTREAM_TO_UINT16(numRecords, pValue);
|
||||
APP_TRACE_INFO1("Number of records: %d", numRecords);
|
||||
}
|
||||
else if (opcode == CH_RACP_OPCODE_RSP)
|
||||
{
|
||||
BSTREAM_TO_UINT8(reqOpcode, pValue);
|
||||
BSTREAM_TO_UINT8(status, pValue);
|
||||
APP_TRACE_INFO2("Response opcode: %d status: %d", reqOpcode, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Glucose service. Parameter
|
||||
* pHdlList must point to an array of length GLPC_GLS_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpcGlsDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attGlsSvcUuid,
|
||||
GLPC_GLS_HDL_LIST_LEN, (attcDiscChar_t **) glpcGlsDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length GLPC_GLS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GlpcGlsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
|
||||
{
|
||||
uint16_t feature;
|
||||
uint8_t *p;
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)feature;
|
||||
|
||||
/* glucose measurement */
|
||||
if (pMsg->handle == pHdlList[GLPC_GLS_GLM_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO0("Glucose meas.");
|
||||
|
||||
/* parse value */
|
||||
glpcGlsParseGlm(pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
/* glucose measurement context */
|
||||
else if (pMsg->handle == pHdlList[GLPC_GLS_GLMC_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO0("Glucose meas. context");
|
||||
|
||||
/* parse value */
|
||||
glpcGlsParseGlmc(pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
/* record access control point */
|
||||
else if (pMsg->handle == pHdlList[GLPC_GLS_RACP_HDL_IDX])
|
||||
{
|
||||
glpcGlsProcRacp(pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
/* glucose feature */
|
||||
else if (pMsg->handle == pHdlList[GLPC_GLS_GLF_HDL_IDX])
|
||||
{
|
||||
/* parse value */
|
||||
p = pMsg->pValue;
|
||||
BSTREAM_TO_UINT16(feature, p);
|
||||
|
||||
APP_TRACE_INFO1("Glucose feature:0x%04x", feature);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a command to the glucose service record access control point.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param opcode Command opcode.
|
||||
* \param oper Command operator or 0 if no operator required.
|
||||
* \param pFilter Command filter parameters or NULL of no parameters required.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpcGlsRacpSend(dmConnId_t connId, uint16_t handle, uint8_t opcode, uint8_t oper,
|
||||
glpcFilter_t *pFilter)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t *p = buf;
|
||||
|
||||
if (handle != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* build RACP command */
|
||||
UINT8_TO_BSTREAM(p, opcode);
|
||||
UINT8_TO_BSTREAM(p, oper);
|
||||
if (pFilter != NULL)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pFilter->type);
|
||||
if (pFilter->type == CH_RACP_GLS_FILTER_SEQ)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pFilter->param.seqNum);
|
||||
}
|
||||
}
|
||||
|
||||
AttcWriteReq(connId, handle, (uint16_t) (p - buf), buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the last received glucose measurement sequence number.
|
||||
*
|
||||
* \param seqNum Glucose measurement sequence number.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpcGlsSetLastSeqNum(uint16_t seqNum)
|
||||
{
|
||||
glpcCb.lastSeqNum = seqNum;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the last received glucose measurement sequence number.
|
||||
*
|
||||
* \return Last received glucose measurement sequence number.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint16_t GlpcGlsGetLastSeqNum(void)
|
||||
{
|
||||
return glpcCb.lastSeqNum;
|
||||
}
|
||||
Vendored
+123
@@ -0,0 +1,123 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Glucose profile sensor.
|
||||
*
|
||||
* 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 GLPS_API_H
|
||||
#define GLPS_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup GLUCOSE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief All supported features of the glucose profile */
|
||||
#define GLP_ALL_SUPPORTED_FEATURES 0x000F
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the Glucose profile sensor.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application when a message that requires
|
||||
* processing by the glucose profile sensor is received.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsProcMsg(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a button press.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param btn Button press.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsBtn(dmConnId_t connId, uint8_t btn);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for glucose service record access control point. Use this
|
||||
* function as a parameter to SvcGlsCbackRegister().
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param handle ATT handle.
|
||||
* \param operation ATT operation.
|
||||
* \param offset Write offset.
|
||||
* \param len Write length.
|
||||
* \param pValue Value to write.
|
||||
* \param pAttr Attribute to write.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GlpsRacpWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the supported features of the glucose sensor.
|
||||
*
|
||||
* \param feature Feature bitmask.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsSetFeature(uint16_t feature);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the CCCD index used by the application for glucose service characteristics.
|
||||
*
|
||||
* \param glmCccIdx Glucose measurement CCCD index.
|
||||
* \param glmcCccIdx Glucose measurement context CCCD index.
|
||||
* \param racpCccIdx Record access control point CCCD index.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsSetCccIdx(uint8_t glmCccIdx, uint8_t glmcCccIdx, uint8_t racpCccIdx);
|
||||
|
||||
/*! \} */ /* GLUCOSE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* GLPS_API_H */
|
||||
Vendored
+430
@@ -0,0 +1,430 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Glucose profile example record database and access functions.
|
||||
*
|
||||
* 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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "svc_ch.h"
|
||||
#include "svc_gls.h"
|
||||
#include "app_api.h"
|
||||
#include "glps_api.h"
|
||||
#include "glps_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Number of records in example database */
|
||||
#define GLPS_DB_NUM_RECORDS 3
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Control block */
|
||||
static struct
|
||||
{
|
||||
uint8_t numRec;
|
||||
} glpsDbCb;
|
||||
|
||||
/*! Example record database */
|
||||
static glpsRec_t glpsDb[GLPS_DB_NUM_RECORDS] =
|
||||
{
|
||||
/* record 1 */
|
||||
{
|
||||
/* measurement */
|
||||
{
|
||||
CH_GLM_FLAG_TIME_OFFSET | CH_GLM_FLAG_CONC_TYPE_LOC | /* Flags */
|
||||
CH_GLM_FLAG_UNITS_MOL_L | CH_GLM_FLAG_SENSOR_STATUS,
|
||||
0x0001, /* Sequence number */
|
||||
{2012, 6, 15, 20, 52, 36}, /* Base time */
|
||||
60, /* Time offset */
|
||||
SFLT_TO_UINT16(50, -3), /* Glucose concentration (SFLOAT) */
|
||||
CH_GLM_LOC_FINGER | (CH_GLM_TYPE_ART_BLOOD << 4), /* Sample type and sample location */
|
||||
CH_GLM_STATUS_BATT_LOW /* Sensor status annunciation */
|
||||
},
|
||||
|
||||
/* context */
|
||||
{
|
||||
CH_GLMC_FLAG_CARB | CH_GLMC_FLAG_MEAL | /* Flags */
|
||||
CH_GLMC_FLAG_TESTER | CH_GLMC_FLAG_EXERCISE |
|
||||
CH_GLMC_FLAG_MED | CH_GLMC_FLAG_MED_KG |
|
||||
CH_GLMC_FLAG_HBA1C,
|
||||
0x0001, /* Sequence number */
|
||||
0, /* Extended Flags */
|
||||
CH_GLMC_CARB_DINNER, /* Carbohydrate ID */
|
||||
SFLT_TO_UINT16(12, -3), /* Carbohydrate (SFLOAT) */
|
||||
CH_GLMC_MEAL_POSTPRANDIAL, /* Meal */
|
||||
CH_GLMC_HEALTH_NONE | (CH_GLMC_TESTER_SELF << 4), /* Tester and health */
|
||||
300, /* Exercise Duration */
|
||||
99, /* Exercise Intensity */
|
||||
CH_GLMC_MED_LONG, /* Medication ID */
|
||||
SFLT_TO_UINT16(50, -6), /* Medication (SFLOAT) */
|
||||
SFLT_TO_UINT16(10, 0) /* HbA1c */
|
||||
},
|
||||
},
|
||||
|
||||
/* record 2 */
|
||||
{
|
||||
/* measurement */
|
||||
{
|
||||
CH_GLM_FLAG_CONC_TYPE_LOC | CH_GLM_FLAG_UNITS_KG_L | /* Flags */
|
||||
CH_GLM_FLAG_CONTEXT_INFO,
|
||||
0x0002, /* Sequence number */
|
||||
{2012, 6, 16, 6, 45, 20}, /* Base time */
|
||||
0, /* Time offset */
|
||||
SFLT_TO_UINT16(20, -5), /* Glucose concentration (SFLOAT) */
|
||||
CH_GLM_LOC_FINGER | (CH_GLM_TYPE_ART_BLOOD << 4), /* Sample type and sample location */
|
||||
0 /* Sensor status annunciation */
|
||||
},
|
||||
|
||||
/* context */
|
||||
{
|
||||
CH_GLMC_FLAG_CARB | CH_GLMC_FLAG_MEAL | /* Flags */
|
||||
CH_GLMC_FLAG_TESTER | CH_GLMC_FLAG_EXERCISE |
|
||||
CH_GLMC_FLAG_MED | CH_GLMC_FLAG_MED_L |
|
||||
CH_GLMC_FLAG_HBA1C,
|
||||
0x0002, /* Sequence number */
|
||||
0, /* Extended Flags */
|
||||
CH_GLMC_CARB_BREAKFAST, /* Carbohydrate ID */
|
||||
SFLT_TO_UINT16(3, -3), /* Carbohydrate (SFLOAT) */
|
||||
CH_GLMC_MEAL_PREPRANDIAL, /* Meal */
|
||||
CH_GLMC_HEALTH_NONE | (CH_GLMC_TESTER_SELF << 4), /* Tester and health */
|
||||
1000, /* Exercise Duration */
|
||||
25, /* Exercise Intensity */
|
||||
CH_GLMC_MED_LONG, /* Medication ID */
|
||||
SFLT_TO_UINT16(10, -3), /* Medication (SFLOAT) */
|
||||
SFLT_TO_UINT16(11, 0) /* HbA1c */
|
||||
},
|
||||
},
|
||||
|
||||
/* record 3 */
|
||||
{
|
||||
/* measurement */
|
||||
{
|
||||
CH_GLM_FLAG_CONC_TYPE_LOC | CH_GLM_FLAG_UNITS_KG_L, /* Flags */
|
||||
0x0003, /* Sequence number */
|
||||
{2012, 6, 16, 18, 45, 20}, /* Base time */
|
||||
0, /* Time offset */
|
||||
SFLT_TO_UINT16(20, -5), /* Glucose concentration (SFLOAT) */
|
||||
CH_GLM_LOC_FINGER | (CH_GLM_TYPE_ART_BLOOD << 4), /* Sample type and sample location */
|
||||
0 /* Sensor status annunciation */
|
||||
},
|
||||
|
||||
/* context */
|
||||
{
|
||||
CH_GLMC_FLAG_TESTER | CH_GLMC_FLAG_EXERCISE | /* Flags */
|
||||
CH_GLMC_FLAG_MED | CH_GLMC_FLAG_MED_L |
|
||||
CH_GLMC_FLAG_HBA1C,
|
||||
0x0003, /* Sequence number */
|
||||
0, /* Extended Flags */
|
||||
0, /* Carbohydrate ID */
|
||||
SFLT_TO_UINT16(0, 0), /* Carbohydrate (SFLOAT) */
|
||||
0, /* Meal */
|
||||
CH_GLMC_HEALTH_NONE | (CH_GLMC_TESTER_SELF << 4), /* Tester and health */
|
||||
1001, /* Exercise Duration */
|
||||
26, /* Exercise Intensity */
|
||||
CH_GLMC_MED_LONG, /* Medication ID */
|
||||
SFLT_TO_UINT16(15, -3), /* Medication (SFLOAT) */
|
||||
SFLT_TO_UINT16(12, 0) /* HbA1c */
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get last database record.
|
||||
*
|
||||
* \return Pointer to record or NULL if no record.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static glpsRec_t *glpsDbGetEnd(void)
|
||||
{
|
||||
if (glpsDbCb.numRec == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (glpsRec_t *) &glpsDb[glpsDbCb.numRec - 1];
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next database record after the given current record.
|
||||
*
|
||||
* \param pCurrRec Pointer to current record.
|
||||
*
|
||||
* \return Pointer to record or NULL if no record.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static glpsRec_t *glpsDbGetNext(glpsRec_t *pCurrRec)
|
||||
{
|
||||
if (glpsDbCb.numRec == 0 || pCurrRec == glpsDbGetEnd())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else if (pCurrRec == NULL)
|
||||
{
|
||||
return (glpsRec_t *) glpsDb;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (pCurrRec + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next record filtered for "all".
|
||||
*
|
||||
* \param pCurrRec Pointer to current record.
|
||||
* \param pRec Return pointer to next record, if found.
|
||||
*
|
||||
* \return CH_RACP_RSP_SUCCESS if a record is found, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t glpsDbOpAll(glpsRec_t *pCurrRec, glpsRec_t **pRec)
|
||||
{
|
||||
*pRec = glpsDbGetNext(pCurrRec);
|
||||
return (*pRec != NULL) ? CH_RACP_RSP_SUCCESS : CH_RACP_RSP_NO_RECORDS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next record filtered for "greater than or equal to sequence number".
|
||||
*
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
* \param pCurrRec Pointer to current record.
|
||||
* \param pRec Return pointer to next record, if found.
|
||||
*
|
||||
* \return CH_RACP_RSP_SUCCESS if a record is found, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t glpsDbOpGteqSeqNum(uint8_t *pFilter, glpsRec_t *pCurrRec, glpsRec_t **pRec)
|
||||
{
|
||||
uint16_t seqNum;
|
||||
|
||||
/* parse seq number */
|
||||
pFilter++;
|
||||
BYTES_TO_UINT16(seqNum, pFilter);
|
||||
|
||||
/* find record */
|
||||
while ((*pRec = glpsDbGetNext(pCurrRec)) != NULL)
|
||||
{
|
||||
if ((*pRec)->meas.seqNum >= seqNum)
|
||||
{
|
||||
return CH_RACP_RSP_SUCCESS;
|
||||
}
|
||||
pCurrRec = *pRec;
|
||||
}
|
||||
|
||||
return CH_RACP_RSP_NO_RECORDS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next record filtered for "last".
|
||||
*
|
||||
* \param pCurrRec Pointer to current record.
|
||||
* \param pRec Return pointer to next record, if found.
|
||||
*
|
||||
* \return CH_RACP_RSP_SUCCESS if a record is found, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t glpsDbOpLast(glpsRec_t *pCurrRec, glpsRec_t **pRec)
|
||||
{
|
||||
/* if current record is already last return failure */
|
||||
*pRec = glpsDbGetEnd();
|
||||
if (*pRec != NULL && *pRec != pCurrRec)
|
||||
{
|
||||
return CH_RACP_RSP_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CH_RACP_RSP_NO_RECORDS;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the glucose record database.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsDbInit(void)
|
||||
{
|
||||
glpsDbCb.numRec = GLPS_DB_NUM_RECORDS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next record that matches the given filter parameters that follows
|
||||
* the given current record.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
* \param pCurrRec Pointer to current record.
|
||||
* \param pRec Return pointer to next record, if found.
|
||||
*
|
||||
* \return CH_RACP_RSP_SUCCESS if a record is found, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t glpsDbGetNextRecord(uint8_t oper, uint8_t *pFilter, glpsRec_t *pCurrRec, glpsRec_t **pRec)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
switch (oper)
|
||||
{
|
||||
case CH_RACP_OPERATOR_ALL:
|
||||
status = glpsDbOpAll(pCurrRec, pRec);
|
||||
break;
|
||||
|
||||
case CH_RACP_OPERATOR_GTEQ:
|
||||
/* check filter type */
|
||||
if (*pFilter == CH_RACP_GLS_FILTER_SEQ)
|
||||
{
|
||||
status = glpsDbOpGteqSeqNum(pFilter, pCurrRec, pRec);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = CH_RACP_RSP_OPERAND_NOT_SUP;
|
||||
}
|
||||
break;
|
||||
|
||||
case CH_RACP_OPERATOR_LAST:
|
||||
status = glpsDbOpLast(pCurrRec, pRec);
|
||||
break;
|
||||
|
||||
case CH_RACP_OPERATOR_NULL:
|
||||
status = CH_RACP_RSP_INV_OPERATOR;
|
||||
break;
|
||||
|
||||
default:
|
||||
status = CH_RACP_RSP_OPERATOR_NOT_SUP;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Delete records that match the given filter parameters.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
*
|
||||
* \return CH_RACP_RSP_SUCCESS if records deleted, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t glpsDbDeleteRecords(uint8_t oper, uint8_t *pFilter)
|
||||
{
|
||||
/* only 'all records' is supported */
|
||||
if (oper == CH_RACP_OPERATOR_ALL)
|
||||
{
|
||||
glpsDbCb.numRec = 0;
|
||||
|
||||
return CH_RACP_RSP_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CH_RACP_RSP_OPERATOR_NOT_SUP;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the number of records matching the filter parameters.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
* \param pNumRec Returns number of records which match filter parameters.
|
||||
|
||||
*
|
||||
* \return RACP status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t glpsDbGetNumRecords(uint8_t oper, uint8_t *pFilter, uint8_t *pNumRec)
|
||||
{
|
||||
glpsRec_t *pCurrRec = NULL;
|
||||
uint8_t status;
|
||||
|
||||
*pNumRec = 0;
|
||||
while ((status = glpsDbGetNextRecord(oper, pFilter, pCurrRec, &pCurrRec)) == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
(*pNumRec)++;
|
||||
}
|
||||
|
||||
if (status == CH_RACP_RSP_NO_RECORDS)
|
||||
{
|
||||
status = CH_RACP_RSP_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate a new record.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsDbGenerateRecord(void)
|
||||
{
|
||||
if (glpsDbCb.numRec < GLPS_DB_NUM_RECORDS)
|
||||
{
|
||||
glpsDbCb.numRec++;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For conformance testing only. Toggle the sample data record number 2's medication
|
||||
* quantity unit flag between Kilograms and Liters. Also modifies quantity.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsDbToggleMedicationUnits(void)
|
||||
{
|
||||
if (glpsDb[1].context.flags & CH_GLMC_FLAG_MED_L)
|
||||
{
|
||||
/* Change medication quantity to Kilograms. */
|
||||
glpsDb[1].context.flags &= ~CH_GLMC_FLAG_MED_L;
|
||||
glpsDb[1].context.flags |= CH_GLMC_FLAG_MED_KG;
|
||||
glpsDb[1].context.medication = SFLT_TO_UINT16(50, -6);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Change medication quantiy to Liters. */
|
||||
glpsDb[1].context.flags &= ~CH_GLMC_FLAG_MED_KG;
|
||||
glpsDb[1].context.flags |= CH_GLMC_FLAG_MED_L;
|
||||
glpsDb[1].context.medication = SFLT_TO_UINT16(10, -3);
|
||||
}
|
||||
}
|
||||
Vendored
+822
@@ -0,0 +1,822 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Glucose profile sensor.
|
||||
*
|
||||
* 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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "svc_ch.h"
|
||||
#include "svc_gls.h"
|
||||
#include "app_api.h"
|
||||
#include "app_ui.h"
|
||||
#include "glps_api.h"
|
||||
#include "glps_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
static struct
|
||||
{
|
||||
uint8_t operand[GLPS_OPERAND_MAX]; /* Stored operand filter data */
|
||||
glpsRec_t *pCurrRec; /* Pointer to current measurement record */
|
||||
bool_t inProgress; /* TRUE if RACP procedure in progress */
|
||||
bool_t txReady; /* TRUE if ready to send next notification or indication */
|
||||
bool_t aborting; /* TRUE if abort procedure in progress */
|
||||
uint8_t glmCccIdx; /* Glucose measurement CCCD index */
|
||||
uint8_t glmcCccIdx; /* Glucose measurement context CCCD index */
|
||||
uint8_t racpCccIdx; /* Record access control point CCCD index */
|
||||
uint8_t oper; /* Stored operator */
|
||||
} glpsCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Build a glucose measurement characteristic.
|
||||
*
|
||||
* \param pBuf Pointer to buffer to hold the built glucose measurement.
|
||||
* \param pGlm Glucose measurement values.
|
||||
*
|
||||
* \return Length of pBuf in bytes.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t glpsBuildGlm(uint8_t *pBuf, glpsGlm_t *pGlm)
|
||||
{
|
||||
uint8_t *p = pBuf;
|
||||
uint8_t flags = pGlm->flags;
|
||||
|
||||
/* flags */
|
||||
UINT8_TO_BSTREAM(p, flags);
|
||||
|
||||
/* sequence number */
|
||||
UINT16_TO_BSTREAM(p, pGlm->seqNum);
|
||||
|
||||
/* base time */
|
||||
UINT16_TO_BSTREAM(p, pGlm->baseTime.year);
|
||||
UINT8_TO_BSTREAM(p, pGlm->baseTime.month);
|
||||
UINT8_TO_BSTREAM(p, pGlm->baseTime.day);
|
||||
UINT8_TO_BSTREAM(p, pGlm->baseTime.hour);
|
||||
UINT8_TO_BSTREAM(p, pGlm->baseTime.min);
|
||||
UINT8_TO_BSTREAM(p, pGlm->baseTime.sec);
|
||||
|
||||
/* time offset */
|
||||
if (flags & CH_GLM_FLAG_TIME_OFFSET)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pGlm->timeOffset);
|
||||
}
|
||||
|
||||
/* glucose concentration, type, and sample location */
|
||||
if (flags & CH_GLM_FLAG_CONC_TYPE_LOC)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pGlm->concentration);
|
||||
UINT8_TO_BSTREAM(p, pGlm->typeSampleLoc);
|
||||
}
|
||||
|
||||
/* sensor status annunciation */
|
||||
if (flags & CH_GLM_FLAG_SENSOR_STATUS)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pGlm->sensorStatus);
|
||||
}
|
||||
|
||||
/* return length */
|
||||
return (uint8_t) (p - pBuf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Build a glucose measurement context characteristic.
|
||||
*
|
||||
* \param pBuf Pointer to buffer to hold the built glucose measurement context.
|
||||
* \param pGlmc Glucose measurement context values.
|
||||
*
|
||||
* \return Length of pBuf in bytes.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t glpsBuildGlmc(uint8_t *pBuf, glpsGlmc_t *pGlmc)
|
||||
{
|
||||
uint8_t *p = pBuf;
|
||||
uint8_t flags = pGlmc->flags;
|
||||
|
||||
/* flags */
|
||||
UINT8_TO_BSTREAM(p, flags);
|
||||
|
||||
/* sequence number */
|
||||
UINT16_TO_BSTREAM(p, pGlmc->seqNum);
|
||||
|
||||
/* extended flags present */
|
||||
if (flags & CH_GLMC_FLAG_EXT)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pGlmc->extFlags);
|
||||
}
|
||||
|
||||
/* carbohydrate id and carbohydrate present */
|
||||
if (flags & CH_GLMC_FLAG_CARB)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pGlmc->carbId);
|
||||
UINT16_TO_BSTREAM(p, pGlmc->carb);
|
||||
}
|
||||
|
||||
/* meal present */
|
||||
if (flags & CH_GLMC_FLAG_MEAL)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pGlmc->meal);
|
||||
}
|
||||
|
||||
/* tester-health present */
|
||||
if (flags & CH_GLMC_FLAG_TESTER)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pGlmc->testerHealth);
|
||||
}
|
||||
|
||||
/* exercise duration and exercise intensity present */
|
||||
if (flags & CH_GLMC_FLAG_EXERCISE)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pGlmc->exerDuration);
|
||||
UINT8_TO_BSTREAM(p, pGlmc->exerIntensity);
|
||||
}
|
||||
|
||||
/* medication ID and medication present */
|
||||
if (flags & CH_GLMC_FLAG_MED)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pGlmc->medicationId);
|
||||
UINT16_TO_BSTREAM(p, pGlmc->medication);
|
||||
}
|
||||
|
||||
/* hba1c present */
|
||||
if (flags & CH_GLMC_FLAG_HBA1C)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pGlmc->hba1c);
|
||||
}
|
||||
|
||||
/* return length */
|
||||
return (uint8_t) (p - pBuf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a glucose measurement context notification.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param pRec Return pointer to glucose record.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsSendMeasContext(dmConnId_t connId, glpsRec_t *pRec)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t len;
|
||||
|
||||
/* build glucose measurement context characteristic */
|
||||
len = glpsBuildGlmc(buf, &glpsCb.pCurrRec->context);
|
||||
|
||||
/* send notification */
|
||||
AttsHandleValueNtf(connId, GLS_GLMC_HDL, len, buf);
|
||||
glpsCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a glucose measurement notification.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param pRec Return pointer to glucose record.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsSendMeas(dmConnId_t connId, glpsRec_t *pRec)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t len;
|
||||
|
||||
/* build glucose measurement characteristic */
|
||||
len = glpsBuildGlm(buf, &glpsCb.pCurrRec->meas);
|
||||
|
||||
/* send notification */
|
||||
AttsHandleValueNtf(connId, GLS_GLM_HDL, len, buf);
|
||||
glpsCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a RACP response indication.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param opcode RACP opcode.
|
||||
* \param status RACP status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsRacpSendRsp(dmConnId_t connId, uint8_t opcode, uint8_t status)
|
||||
{
|
||||
uint8_t buf[GLPS_RACP_RSP_LEN];
|
||||
|
||||
/* build response */
|
||||
buf[0] = CH_RACP_OPCODE_RSP;
|
||||
buf[1] = CH_RACP_OPERATOR_NULL;
|
||||
buf[2] = opcode;
|
||||
buf[3] = status;
|
||||
|
||||
/* send indication */
|
||||
AttsHandleValueInd(connId, GLS_RACP_HDL, GLPS_RACP_RSP_LEN, buf);
|
||||
glpsCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a RACP number of records response indication.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param numRec Number of records.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsRacpSendNumRecRsp(dmConnId_t connId, uint16_t numRec)
|
||||
{
|
||||
uint8_t buf[GLPS_RACP_NUM_REC_RSP_LEN];
|
||||
|
||||
/* build response */
|
||||
buf[0] = CH_RACP_OPCODE_NUM_RSP;
|
||||
buf[1] = CH_RACP_OPERATOR_NULL;
|
||||
buf[2] = UINT16_TO_BYTE0(numRec);
|
||||
buf[3] = UINT16_TO_BYTE1(numRec);
|
||||
|
||||
/* send indication */
|
||||
AttsHandleValueInd(connId, GLS_RACP_HDL, GLPS_RACP_RSP_LEN, buf);
|
||||
glpsCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle connection open.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsConnOpen(dmEvt_t *pMsg)
|
||||
{
|
||||
/* initialize */
|
||||
glpsCb.pCurrRec = NULL;
|
||||
glpsCb.aborting = FALSE;
|
||||
glpsCb.inProgress = FALSE;
|
||||
glpsCb.txReady = FALSE;
|
||||
glpsCb.oper = CH_RACP_OPERATOR_NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle connection close.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsConnClose(dmEvt_t *pMsg)
|
||||
{
|
||||
glpsCb.pCurrRec = NULL;
|
||||
glpsCb.aborting = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an ATT handle value confirm.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsHandleValueCnf(attEvt_t *pMsg)
|
||||
{
|
||||
dmConnId_t connId = (dmConnId_t) pMsg->hdr.param;
|
||||
glpsCb.txReady = TRUE;
|
||||
|
||||
/* if aborting finish that up */
|
||||
if (glpsCb.aborting)
|
||||
{
|
||||
glpsCb.aborting = FALSE;
|
||||
glpsRacpSendRsp(connId, CH_RACP_OPCODE_ABORT, CH_RACP_RSP_SUCCESS);
|
||||
}
|
||||
|
||||
/* if this is for RACP indication */
|
||||
if (pMsg->handle == GLS_RACP_HDL)
|
||||
{
|
||||
/* procedure no longer in progress */
|
||||
glpsCb.inProgress = FALSE;
|
||||
}
|
||||
/* if this is for measurement or context notification */
|
||||
else if (pMsg->handle == GLS_GLM_HDL || pMsg->handle == GLS_GLMC_HDL)
|
||||
{
|
||||
if (glpsCb.pCurrRec != NULL)
|
||||
{
|
||||
/* if measurement was sent and there is context to send */
|
||||
if (pMsg->handle == GLS_GLM_HDL && AttsCccEnabled(connId, glpsCb.glmcCccIdx) &&
|
||||
(glpsCb.pCurrRec->meas.flags & CH_GLM_FLAG_CONTEXT_INFO))
|
||||
{
|
||||
/* send context */
|
||||
glpsSendMeasContext(connId, glpsCb.pCurrRec);
|
||||
}
|
||||
/* else if there is another record */
|
||||
else if (glpsDbGetNextRecord(glpsCb.oper, glpsCb.operand,
|
||||
glpsCb.pCurrRec, &glpsCb.pCurrRec) == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
/* send measurement */
|
||||
glpsSendMeas(connId, glpsCb.pCurrRec);
|
||||
}
|
||||
/* else all records sent; send RACP response */
|
||||
else
|
||||
{
|
||||
glpsRacpSendRsp(connId, CH_RACP_OPCODE_REPORT, CH_RACP_RSP_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Verify validity of operand data. If valid, store the data.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param len Operand length.
|
||||
* \param pOperand Operand data.
|
||||
|
||||
*
|
||||
* \return RACP status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t glpsRacpOperCheck(uint8_t oper, uint16_t len, uint8_t *pOperand)
|
||||
{
|
||||
uint8_t status = CH_RACP_RSP_SUCCESS;
|
||||
uint8_t filterType;
|
||||
uint8_t filterLen = 0;
|
||||
|
||||
/* these operators have no operands */
|
||||
if (oper == CH_RACP_OPERATOR_ALL || oper == CH_RACP_OPERATOR_FIRST ||
|
||||
oper == CH_RACP_OPERATOR_LAST || oper == CH_RACP_OPERATOR_NULL)
|
||||
{
|
||||
if (len != 0)
|
||||
{
|
||||
status = CH_RACP_RSP_INV_OPERAND;
|
||||
}
|
||||
}
|
||||
/* remaining operators must have operands */
|
||||
else if (oper == CH_RACP_OPERATOR_LTEQ || oper == CH_RACP_OPERATOR_GTEQ ||
|
||||
oper == CH_RACP_OPERATOR_RANGE)
|
||||
{
|
||||
if (len == 0)
|
||||
{
|
||||
status = CH_RACP_RSP_INV_OPERAND;
|
||||
}
|
||||
else
|
||||
{
|
||||
filterType = *pOperand;
|
||||
len--;
|
||||
|
||||
/* operand length depends on filter type */
|
||||
if (filterType == CH_RACP_GLS_FILTER_SEQ)
|
||||
{
|
||||
filterLen = CH_RACP_GLS_FILTER_SEQ_LEN;
|
||||
}
|
||||
else if (filterType == CH_RACP_GLS_FILTER_TIME)
|
||||
{
|
||||
filterLen = CH_RACP_GLS_FILTER_TIME_LEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = CH_RACP_RSP_OPERAND_NOT_SUP;
|
||||
}
|
||||
|
||||
if (status == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
/* range operator has two filters, others have one */
|
||||
if (oper == CH_RACP_OPERATOR_RANGE)
|
||||
{
|
||||
filterLen *= 2;
|
||||
}
|
||||
|
||||
/* verify length */
|
||||
if (len != filterLen)
|
||||
{
|
||||
status = CH_RACP_RSP_INV_OPERAND;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* unknown operator */
|
||||
else
|
||||
{
|
||||
status = CH_RACP_RSP_OPERATOR_NOT_SUP;
|
||||
}
|
||||
|
||||
/* store operator and operand */
|
||||
if (status == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
glpsCb.oper = oper;
|
||||
memcpy(glpsCb.operand, pOperand, len);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a RACP report stored records operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param oper Operator.
|
||||
* \param pOperand Operand data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsRacpReport(dmConnId_t connId, uint8_t oper, uint8_t *pOperand)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
/* if record found */
|
||||
if ((status = glpsDbGetNextRecord(oper, pOperand, NULL, &glpsCb.pCurrRec)) == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
/* send measurement */
|
||||
glpsSendMeas(connId, glpsCb.pCurrRec);
|
||||
}
|
||||
/* if not successful send response */
|
||||
else
|
||||
{
|
||||
glpsRacpSendRsp(connId, CH_RACP_OPCODE_REPORT, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a RACP delete records operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param oper Operator.
|
||||
* \param pOperand Operand data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsRacpDelete(dmConnId_t connId, uint8_t oper, uint8_t *pOperand)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
/* delete records */
|
||||
status = glpsDbDeleteRecords(oper, pOperand);
|
||||
|
||||
/* send response */
|
||||
glpsRacpSendRsp(connId, CH_RACP_OPCODE_DELETE, status);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a RACP abort operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsRacpAbort(dmConnId_t connId)
|
||||
{
|
||||
/* if operation in progress */
|
||||
if (glpsCb.inProgress)
|
||||
{
|
||||
/* abort operation and clean up */
|
||||
glpsCb.pCurrRec = NULL;
|
||||
}
|
||||
|
||||
/* send response */
|
||||
if (glpsCb.txReady)
|
||||
{
|
||||
glpsRacpSendRsp(connId, CH_RACP_OPCODE_ABORT, CH_RACP_RSP_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
glpsCb.aborting = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a RACP report number of stored records operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param oper Operator.
|
||||
* \param pOperand Operand data.
|
||||
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsRacpReportNum(dmConnId_t connId, uint8_t oper, uint8_t *pOperand)
|
||||
{
|
||||
uint8_t status;
|
||||
uint8_t numRec;
|
||||
|
||||
/* get number of records */
|
||||
status = glpsDbGetNumRecords(oper, pOperand, &numRec);
|
||||
|
||||
if (status == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
/* send response */
|
||||
/* note: status check guarantees numRec has been initialized */
|
||||
/* coverity[uninit_use_in_call] */
|
||||
glpsRacpSendNumRecRsp(connId, numRec);
|
||||
}
|
||||
else
|
||||
{
|
||||
glpsRacpSendRsp(connId, CH_RACP_OPCODE_REPORT_NUM, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
*
|
||||
* \brief Toggle bonding flag in Glucose Feature Characteristic.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsToggleBondingFlag(void)
|
||||
{
|
||||
uint8_t *pGlpsFlagsValue;
|
||||
uint16_t len;
|
||||
|
||||
/* Get flags */
|
||||
if (AttsGetAttr(GLS_GLF_HDL, &len, &pGlpsFlagsValue) == ATT_SUCCESS)
|
||||
{
|
||||
uint16_t glpsFlags;
|
||||
|
||||
BYTES_TO_UINT16(glpsFlags, pGlpsFlagsValue);
|
||||
|
||||
if (glpsFlags & CH_GLF_MULTI_BOND)
|
||||
{
|
||||
glpsFlags &= ~CH_GLF_MULTI_BOND;
|
||||
}
|
||||
else
|
||||
{
|
||||
glpsFlags |= CH_GLF_MULTI_BOND;
|
||||
}
|
||||
|
||||
GlpsSetFeature(glpsFlags);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn GlpsInit
|
||||
*
|
||||
* \brief Initialize the Glucose profile sensor.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsInit(void)
|
||||
{
|
||||
glpsDbInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application when a message that requires
|
||||
* processing by the glucose profile sensor is received.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsProcMsg(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
switch(pMsg->event)
|
||||
{
|
||||
case DM_CONN_OPEN_IND:
|
||||
glpsConnOpen((dmEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
case DM_CONN_CLOSE_IND:
|
||||
glpsConnClose((dmEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
case ATTS_HANDLE_VALUE_CNF:
|
||||
glpsHandleValueCnf((attEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a button press.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param btn Button press.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsBtn(dmConnId_t connId, uint8_t btn)
|
||||
{
|
||||
/* button actions when connected */
|
||||
if (connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
switch (btn)
|
||||
{
|
||||
case APP_UI_BTN_2_MED:
|
||||
/* Toggle medication quantity, for test purposes only */
|
||||
glpsDbToggleMedicationUnits();
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_LONG:
|
||||
/* generate a new record */
|
||||
glpsDbGenerateRecord();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* button actions when not connected */
|
||||
else
|
||||
{
|
||||
switch (btn)
|
||||
{
|
||||
case APP_UI_BTN_2_SHORT:
|
||||
/* Toggle bonding flag */
|
||||
glpsToggleBondingFlag();
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_MED:
|
||||
/* Toggle medication quantity, for test purposes only */
|
||||
glpsDbToggleMedicationUnits();
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_LONG:
|
||||
/* generate a new record */
|
||||
glpsDbGenerateRecord();
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_EX_LONG:
|
||||
/* delete all records */
|
||||
glpsDbDeleteRecords(CH_RACP_OPERATOR_ALL, NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for glucose service record access control point. Use this
|
||||
* function as a parameter to SvcGlsCbackRegister().
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GlpsRacpWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t oper;
|
||||
uint8_t status;
|
||||
|
||||
/* sanity check on length */
|
||||
if (len < GLPS_RACP_MIN_WRITE_LEN)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
/* if control point not configured for indication */
|
||||
if (!AttsCccEnabled(connId, glpsCb.racpCccIdx))
|
||||
{
|
||||
return GLS_ERR_CCCD;
|
||||
}
|
||||
|
||||
/* parse opcode and operator and adjust remaining parameter length */
|
||||
BSTREAM_TO_UINT8(opcode, pValue);
|
||||
BSTREAM_TO_UINT8(oper, pValue);
|
||||
len -= 2;
|
||||
|
||||
/* handle a procedure in progress */
|
||||
if (opcode != CH_RACP_OPCODE_ABORT && glpsCb.inProgress)
|
||||
{
|
||||
return GLS_ERR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* handle record request when notifications not enabled */
|
||||
if (opcode == CH_RACP_OPCODE_REPORT && !AttsCccEnabled(connId, glpsCb.glmCccIdx))
|
||||
{
|
||||
return GLS_ERR_CCCD;
|
||||
}
|
||||
|
||||
/* verify operands */
|
||||
if ((status = glpsRacpOperCheck(oper, len, pValue)) == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
/* report records */
|
||||
case CH_RACP_OPCODE_REPORT:
|
||||
glpsRacpReport(connId, oper, pValue);
|
||||
break;
|
||||
|
||||
/* delete records */
|
||||
case CH_RACP_OPCODE_DELETE:
|
||||
glpsRacpDelete(connId, oper, pValue);
|
||||
break;
|
||||
|
||||
/* abort current operation */
|
||||
case CH_RACP_OPCODE_ABORT:
|
||||
glpsRacpAbort(connId);
|
||||
break;
|
||||
|
||||
/* report number of records */
|
||||
case CH_RACP_OPCODE_REPORT_NUM:
|
||||
glpsRacpReportNum(connId, oper, pValue);
|
||||
break;
|
||||
|
||||
/* unsupported opcode */
|
||||
default:
|
||||
glpsRacpSendRsp(connId, opcode, CH_RACP_RSP_OPCODE_NOT_SUP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* else invalid operands; send response with failure status */
|
||||
else
|
||||
{
|
||||
glpsRacpSendRsp(connId, opcode, status);
|
||||
}
|
||||
|
||||
/* procedure now in progress */
|
||||
glpsCb.inProgress = TRUE;
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the supported features of the glucose sensor.
|
||||
*
|
||||
* \param feature Feature bitmask.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsSetFeature(uint16_t feature)
|
||||
{
|
||||
uint8_t buf[2] = {UINT16_TO_BYTES(feature)};
|
||||
|
||||
AttsSetAttr(GLS_GLF_HDL, sizeof(buf), buf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the CCCD index used by the application for glucose service characteristics.
|
||||
*
|
||||
* \param glmCccIdx Glucose measurement CCCD index.
|
||||
* \param glmcCccIdx Glucose measurement context CCCD index.
|
||||
* \param racpCccIdx Record access control point CCCD index.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsSetCccIdx(uint8_t glmCccIdx, uint8_t glmcCccIdx, uint8_t racpCccIdx)
|
||||
{
|
||||
glpsCb.glmCccIdx = glmCccIdx;
|
||||
glpsCb.glmcCccIdx = glmCccIdx;
|
||||
glpsCb.racpCccIdx = racpCccIdx;
|
||||
}
|
||||
|
||||
Vendored
+167
@@ -0,0 +1,167 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Glucose profile sensor internal interfaces.
|
||||
*
|
||||
* 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 GLPS_MAIN_H
|
||||
#define GLPS_MAIN_H
|
||||
|
||||
#include "app_hw.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup GLUCOSE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Minimum RACP write length */
|
||||
#define GLPS_RACP_MIN_WRITE_LEN 2
|
||||
|
||||
/*! \brief RACP response length */
|
||||
#define GLPS_RACP_RSP_LEN 4
|
||||
|
||||
/*! \brief Glucose RACP number of stored records response length */
|
||||
#define GLPS_RACP_NUM_REC_RSP_LEN 4
|
||||
|
||||
/*! \brief RACP operand maximum length */
|
||||
#define GLPS_OPERAND_MAX ((CH_RACP_GLS_FILTER_TIME_LEN * 2) + 1)
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Glucose measurement structure */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t flags; /*!< \brief Flags */
|
||||
uint16_t seqNum; /*!< \brief Sequence number */
|
||||
appDateTime_t baseTime; /*!< \brief Base time */
|
||||
int16_t timeOffset; /*!< \brief Time offset */
|
||||
uint16_t concentration; /*!< \brief Glucose concentration (SFLOAT) */
|
||||
uint8_t typeSampleLoc; /*!< \brief Sample type and sample location */
|
||||
uint16_t sensorStatus; /*!< \brief Sensor status annunciation */
|
||||
} glpsGlm_t;
|
||||
|
||||
/*! \brief Glucose measurement context structure */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t flags; /*!< \brief Flags */
|
||||
uint16_t seqNum; /*!< \brief Sequence number */
|
||||
uint8_t extFlags; /*!< \brief Extended Flags */
|
||||
uint8_t carbId; /*!< \brief Carbohydrate ID */
|
||||
uint16_t carb; /*!< \brief Carbohydrate (SFLOAT) */
|
||||
uint8_t meal; /*!< \brief Meal */
|
||||
uint8_t testerHealth; /*!< \brief Tester and health */
|
||||
uint16_t exerDuration; /*!< \brief Exercise Duration */
|
||||
uint8_t exerIntensity; /*!< \brief Exercise Intensity */
|
||||
uint8_t medicationId; /*!< \brief Medication ID */
|
||||
uint16_t medication; /*!< \brief Medication (SFLOAT) */
|
||||
uint16_t hba1c; /*!< \brief HbA1c */
|
||||
} glpsGlmc_t;
|
||||
|
||||
/*! \brief Glucose measurement record */
|
||||
typedef struct
|
||||
{
|
||||
glpsGlm_t meas; /*!< \brief Glucose measurement */
|
||||
glpsGlmc_t context; /*!< \brief Glucose measurement context */
|
||||
} glpsRec_t;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the glucose record database.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsDbInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next record that matches the given filter parameters that follows
|
||||
* the given current record.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
* \param pCurrRec Pointer to current record.
|
||||
* \param pRec Return pointer to next record, if found.
|
||||
*
|
||||
* \return \ref CH_RACP_RSP_SUCCESS if a record is found, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t glpsDbGetNextRecord(uint8_t oper, uint8_t *pFilter, glpsRec_t *pCurrRec, glpsRec_t **pRec);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Delete records that match the given filter parameters.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
*
|
||||
* \return \ref CH_RACP_RSP_SUCCESS if records deleted, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t glpsDbDeleteRecords(uint8_t oper, uint8_t *pFilter);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the number of records matching the filter parameters.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
* \param pNumRec Returns number of records which match filter parameters.
|
||||
|
||||
*
|
||||
* \return RACP status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t glpsDbGetNumRecords(uint8_t oper, uint8_t *pFilter, uint8_t *pNumRec);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate a new record.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsDbGenerateRecord(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For conformance testing only. Toggle the sample data record number 2's medication
|
||||
* quantity unit flag between Kilograms and Liters. Also modifies quantity.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsDbToggleMedicationUnits(void);
|
||||
|
||||
/*! \} */ /* GLUCOSE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* GLPS_MAIN_H */
|
||||
Vendored
+203
@@ -0,0 +1,203 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Human Interface Device Profile.
|
||||
*
|
||||
* Copyright (c) 2015-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 HID_API_H
|
||||
#define HID_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup HUMAN_INTERFACE_DEVICE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Constant Values
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name Type of HID Information
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define HID_INFO_CONTROL_POINT 0 /*!< \brief Control point information. */
|
||||
#define HID_INFO_PROTOCOL_MODE 1 /*!< \brief Protocol mode information. */
|
||||
/**@}*/
|
||||
|
||||
/** \name HID Boot Report ID
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define HID_KEYBOARD_BOOT_ID 0xFF /*!< \brief Keyboard boot ID. */
|
||||
#define HID_MOUSE_BOOT_ID 0xFE /*!< \brief Mouse boot ID. */
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Callback Function Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This callback function sends a received Output Report to the application.
|
||||
*
|
||||
* \param connId The connection identifier.
|
||||
* \param id The ID of the report.
|
||||
* \param len The length of the report data in pReport.
|
||||
* \param pReport A buffer containing the report.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
typedef void (*hidOutputReportCback_t)(dmConnId_t connId, uint8_t id, uint16_t len, uint8_t *pReport);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This callback function sends a received Feature Report to the application.
|
||||
*
|
||||
* \param connId The connection identifier.
|
||||
* \param id The ID of the report.
|
||||
* \param len The length of the report data in pReport.
|
||||
* \param pReport A buffer containing the report.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
typedef void (*hidFeatureReportCback_t)(dmConnId_t connId, uint8_t id, uint16_t len, uint8_t *pReport);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This callback function notifies the application of a change in the protocol mode or
|
||||
* control point from the host.
|
||||
*
|
||||
* \param connId The connection identifier.
|
||||
* \param mode The type of information (\ref HID_INFO_CONTROL_POINT or \ref HID_INFO_PROTOCOL_MODE)
|
||||
* \param value The value of the information
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
typedef void (*hidInfoCback_t)(dmConnId_t connId, uint8_t type, uint8_t value);
|
||||
|
||||
/*! \brief HID Report Type/ID to Attribute handle map item */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t type; /*!< \brief Type */
|
||||
uint8_t id; /*!< \brief Id */
|
||||
uint16_t handle; /*!< \brief Handle */
|
||||
} hidReportIdMap_t;
|
||||
|
||||
/*! \brief HID Profile Configuration */
|
||||
typedef struct
|
||||
{
|
||||
hidReportIdMap_t *pReportIdMap; /*!< \brief A map between report Type/ID and Attribute handle */
|
||||
uint8_t reportIdMapSize; /*!< \brief The number of Reports in the ID map (pReportIdMap) */
|
||||
hidOutputReportCback_t outputCback; /*!< \brief Callback called on receipt of an Output Report */
|
||||
hidFeatureReportCback_t featureCback; /*!< \brief Callback called on receipt of a Feature Report */
|
||||
hidInfoCback_t infoCback; /*!< \brief Callback called on receipt of protocol mode or control point */
|
||||
} hidConfig_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
API Functions
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Sends an input report to the host
|
||||
*
|
||||
* \param connId The connection ID
|
||||
* \param reportId The Report ID
|
||||
* \param len The length of the report in bytes
|
||||
* \param pValue A buffer containing the report
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HidSendInputReport(dmConnId_t connId, uint8_t reportId, uint16_t len, uint8_t *pValue);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Sets the HID protocol mode for keyboard and mouse devices that support Boot Mode.
|
||||
*
|
||||
* \param protocolMode The protocol mode (\ref HID_PROTOCOL_MODE_REPORT or \ref HID_PROTOCOL_MODE_BOOT)
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HidSetProtocolMode(uint8_t protocolMode);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Gets the HID protocol mode value.
|
||||
*
|
||||
* \return The protocol mode value (\ref HID_PROTOCOL_MODE_REPORT or \ref HID_PROTOCOL_MODE_BOOT).
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HidGetProtocolMode(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Gets the HID control point value.
|
||||
*
|
||||
* \return The control point value (\ref HID_CONTROL_POINT_SUSPEND or \ref HID_CONTROL_POINT_RESUME).
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HidGetControlPoint(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the HID profile.
|
||||
*
|
||||
* \param pConfig HID Configuration structure
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HidInit(const hidConfig_t *pConfig);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called on an ATTS Write to the HID Service.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param handle ATT handle.
|
||||
* \param operation ATT operation.
|
||||
* \param offset Write offset.
|
||||
* \param len Write length.
|
||||
* \param pValue Value to write.
|
||||
* \param pAttr Attribute to write.
|
||||
*
|
||||
* \return ATT status.
|
||||
*
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HidAttsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue,
|
||||
attsAttr_t *pAttr);
|
||||
|
||||
|
||||
/*! \} */ /* HUMAN_INTERFACE_DEVICE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HID_API_H */
|
||||
Vendored
+286
@@ -0,0 +1,286 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Human Interface Device Profile.
|
||||
*
|
||||
* Copyright (c) 2015-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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "att_api.h"
|
||||
#include "svc_hid.h"
|
||||
#include "app_api.h"
|
||||
#include "hid_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! HID control block */
|
||||
typedef struct
|
||||
{
|
||||
const hidConfig_t *pConfig; /* HID Configuration passed in from the application */
|
||||
} hidCb_t;
|
||||
|
||||
hidCb_t hidCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Gets the attribute handle of a report given the type and id
|
||||
*
|
||||
* \param type The type of report (HID_REPORT_TYPE_INPUT, HID_REPORT_TYPE_OUTPUT, HID_REPORT_TYPE_FEATURE)
|
||||
* \param id The ID of the report
|
||||
*
|
||||
* \return The attribute handle for the report or ATT_HANDLE_NONE if the report is not in the map.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint16_t hidGetReportHandle(uint8_t type, uint8_t id)
|
||||
{
|
||||
hidReportIdMap_t *pMap;
|
||||
uint8_t count;
|
||||
uint8_t i;
|
||||
|
||||
WSF_ASSERT(hidCb.pConfig);
|
||||
WSF_ASSERT(hidCb.pConfig->pReportIdMap);
|
||||
|
||||
pMap = hidCb.pConfig->pReportIdMap;
|
||||
count = hidCb.pConfig->reportIdMapSize;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (pMap[i].type == type && pMap[i].id == id)
|
||||
{
|
||||
return pMap[i].handle;
|
||||
}
|
||||
}
|
||||
|
||||
return ATT_HANDLE_NONE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Gets the type and ID of a report given a handle
|
||||
*
|
||||
* \param handle The attribute handle
|
||||
*
|
||||
* \return A pointer to the hidReportIdMap_t with the type and ID
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static hidReportIdMap_t *hidGetReportIdMap(uint16_t handle)
|
||||
{
|
||||
hidReportIdMap_t *pMap;
|
||||
uint8_t count;
|
||||
uint8_t i;
|
||||
|
||||
WSF_ASSERT(hidCb.pConfig);
|
||||
WSF_ASSERT(hidCb.pConfig->pReportIdMap);
|
||||
|
||||
pMap = hidCb.pConfig->pReportIdMap;
|
||||
count = hidCb.pConfig->reportIdMapSize;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (pMap[i].handle == handle)
|
||||
{
|
||||
return &pMap[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Gets the HID control point value.
|
||||
*
|
||||
* \return The control point value (HID_CONTROL_POINT_SUSPEND or HID_CONTROL_POINT_RESUME).
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HidGetControlPoint(void)
|
||||
{
|
||||
uint16_t len = 1;
|
||||
uint8_t *pValue = NULL;
|
||||
|
||||
AttsGetAttr(HID_CONTROL_POINT_HDL, &len, &pValue);
|
||||
|
||||
return *pValue;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Gets the HID protocol mode value.
|
||||
*
|
||||
* \return The protocol mode value (HID_PROTOCOL_MODE_REPORT or HID_PROTOCOL_MODE_BOOT).
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HidGetProtocolMode(void)
|
||||
{
|
||||
uint16_t len = 1;
|
||||
uint8_t *pValue = NULL;
|
||||
|
||||
AttsGetAttr(HID_PROTOCOL_MODE_HDL, &len, &pValue);
|
||||
|
||||
return *pValue;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Sets the HID protocol mode for keyboard and mouse devices that support Boot Mode.
|
||||
*
|
||||
* \param protocolMode The protocol mode (HID_PROTOCOL_MODE_REPORT or HID_PROTOCOL_MODE_BOOT)
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HidSetProtocolMode(uint8_t protocolMode)
|
||||
{
|
||||
AttsSetAttr(HID_PROTOCOL_MODE_HDL, 1, &protocolMode);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Sends an input report to the host
|
||||
*
|
||||
* \param connId The connection ID
|
||||
* \param reportId The Report ID
|
||||
* \param len The length of the report in bytes
|
||||
* \param pValue A buffer containing the report
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HidSendInputReport(dmConnId_t connId, uint8_t reportId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint16_t handle = hidGetReportHandle(HID_REPORT_TYPE_INPUT, reportId);
|
||||
|
||||
if (handle != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* Store the attribute value */
|
||||
AttsSetAttr(handle, len, pValue);
|
||||
|
||||
/* send notification */
|
||||
AttsHandleValueNtf(connId, handle, len, pValue);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called on an ATTS Write to the HID Service.
|
||||
*
|
||||
* \return ATT status.
|
||||
*
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HidAttsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue,
|
||||
attsAttr_t *pAttr)
|
||||
{
|
||||
hidReportIdMap_t *pIdMap;
|
||||
|
||||
WSF_ASSERT(hidCb.pConfig);
|
||||
|
||||
switch (handle)
|
||||
{
|
||||
case HID_CONTROL_POINT_HDL:
|
||||
|
||||
/* notify the application */
|
||||
if (hidCb.pConfig->infoCback != NULL)
|
||||
{
|
||||
hidCb.pConfig->infoCback(connId, HID_INFO_CONTROL_POINT, *pValue);
|
||||
}
|
||||
break;
|
||||
|
||||
case HID_PROTOCOL_MODE_HDL:
|
||||
|
||||
/* Record the value of the protocol mode */
|
||||
HidSetProtocolMode(pValue[0]);
|
||||
|
||||
if (hidCb.pConfig->infoCback != NULL)
|
||||
{
|
||||
hidCb.pConfig->infoCback(connId, HID_INFO_PROTOCOL_MODE, *pValue);
|
||||
}
|
||||
break;
|
||||
|
||||
case HID_KEYBOARD_BOOT_OUT_HDL:
|
||||
|
||||
/* set the attribute value so it can be read by the host */
|
||||
AttsSetAttr(handle, len, pValue);
|
||||
|
||||
/* notify the application */
|
||||
if (hidCb.pConfig->outputCback != NULL)
|
||||
{
|
||||
pIdMap = hidGetReportIdMap(handle);
|
||||
|
||||
if (pIdMap != NULL)
|
||||
{
|
||||
hidCb.pConfig->outputCback(connId, pIdMap->id, len, pValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
pIdMap = hidGetReportIdMap(handle);
|
||||
|
||||
if (pIdMap != NULL)
|
||||
{
|
||||
/* set the attribute value so it can be read by the host */
|
||||
AttsSetAttr(handle, len, pValue);
|
||||
|
||||
/* notify the application */
|
||||
if (pIdMap->type == HID_REPORT_TYPE_FEATURE)
|
||||
{
|
||||
if (hidCb.pConfig->featureCback != NULL)
|
||||
{
|
||||
hidCb.pConfig->featureCback(connId, pIdMap->id, len, pValue);
|
||||
}
|
||||
}
|
||||
else if (pIdMap->type == HID_REPORT_TYPE_OUTPUT)
|
||||
{
|
||||
if (hidCb.pConfig->outputCback != NULL)
|
||||
{
|
||||
hidCb.pConfig->outputCback(connId, pIdMap->id, len, pValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the HID profile.
|
||||
*
|
||||
* \param pConfig HID Configuration structure
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HidInit(const hidConfig_t *pConfig)
|
||||
{
|
||||
WSF_ASSERT(pConfig);
|
||||
|
||||
/* Store the configuration */
|
||||
hidCb.pConfig = pConfig;
|
||||
}
|
||||
Vendored
+103
@@ -0,0 +1,103 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Heart Rate profile client.
|
||||
*
|
||||
* 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 HRPC_API_H
|
||||
#define HRPC_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup HEART_RATE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Heart Rate service enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
HRPC_HRS_HRM_HDL_IDX, /*!< \brief Heart rate measurement */
|
||||
HRPC_HRS_HRM_CCC_HDL_IDX, /*!< \brief Heart rate measurement CCC descriptor */
|
||||
HRPC_HRS_BSL_HDL_IDX, /*!< \brief Body sensor location */
|
||||
HRPC_HRS_HRCP_HDL_IDX, /*!< \brief Heart rate control point */
|
||||
HRPC_HRS_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Heart Rate service.
|
||||
* Parameter pHdlList must point to an array of length \ref HRPC_HRS_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpcHrsDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a command to the heart rate control point.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param command Control point command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpcHrsControl(dmConnId_t connId, uint16_t handle, uint8_t command);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length \ref HRPC_HRS_HDL_LIST_LEN.
|
||||
* If the ATT handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characterist handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if handle is found, \ref ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HrpcHrsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg);
|
||||
|
||||
/*! \} */ /* HEART_RATE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HRPC_API_H */
|
||||
Vendored
+259
@@ -0,0 +1,259 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Heart Rate profile collector.
|
||||
*
|
||||
* Copyright (c) 2011-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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_ch.h"
|
||||
#include "app_api.h"
|
||||
#include "hrpc_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*!
|
||||
* Heart Rate service
|
||||
*/
|
||||
|
||||
/* Characteristics for discovery */
|
||||
|
||||
/*! Heart rate measurement */
|
||||
static const attcDiscChar_t hrpcHrsHrm =
|
||||
{
|
||||
attHrmChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Heart rate measurement CCC descriptor */
|
||||
static const attcDiscChar_t hrpcHrsHrmCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Body sensor location */
|
||||
static const attcDiscChar_t hrpcHrsBsl =
|
||||
{
|
||||
attBslChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Heart rate control point */
|
||||
static const attcDiscChar_t hrpcHrsHrcp =
|
||||
{
|
||||
attHrcpChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *hrpcHrsDiscCharList[] =
|
||||
{
|
||||
&hrpcHrsHrm, /*! Heart rate measurement */
|
||||
&hrpcHrsHrmCcc, /*! Heart rate measurement CCC descriptor */
|
||||
&hrpcHrsBsl, /*! Body sensor location */
|
||||
&hrpcHrsHrcp, /*! Heart rate control point */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(HRPC_HRS_HDL_LIST_LEN == ((sizeof(hrpcHrsDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Parse a heart rate measurement.
|
||||
*
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hrcpHrsParseHrm(uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
uint8_t flags;
|
||||
uint16_t minLen = 1 + CH_HRM_LEN_VALUE_8BIT;
|
||||
uint16_t heartRate;
|
||||
uint16_t energyExp;
|
||||
uint16_t rrInterval;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)heartRate; (void)energyExp; (void)rrInterval;
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
/* get flags */
|
||||
BSTREAM_TO_UINT8(flags, pValue);
|
||||
|
||||
/* determine expected minimum length based on flags */
|
||||
if (flags & CH_HRM_FLAGS_VALUE_16BIT)
|
||||
{
|
||||
minLen++;
|
||||
}
|
||||
if (flags & CH_HRM_FLAGS_ENERGY_EXP)
|
||||
{
|
||||
minLen += CH_HRM_LEN_ENERGY_EXP;
|
||||
}
|
||||
if (flags & CH_HRM_FLAGS_RR_INTERVAL)
|
||||
{
|
||||
minLen += CH_HRM_LEN_RR_INTERVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* verify length */
|
||||
if (len < minLen)
|
||||
{
|
||||
APP_TRACE_INFO2("Heart Rate meas len:%d minLen:%d", len, minLen);
|
||||
return;
|
||||
}
|
||||
|
||||
/* heart rate */
|
||||
if (flags & CH_HRM_FLAGS_VALUE_16BIT)
|
||||
{
|
||||
BSTREAM_TO_UINT16(heartRate, pValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
BSTREAM_TO_UINT8(heartRate, pValue);
|
||||
}
|
||||
APP_TRACE_INFO1(" Heart rate: %d", heartRate);
|
||||
|
||||
/* energy expended */
|
||||
if (flags & CH_HRM_FLAGS_ENERGY_EXP)
|
||||
{
|
||||
BSTREAM_TO_UINT16(energyExp, pValue);
|
||||
APP_TRACE_INFO1(" Energy Exp: %d", energyExp);
|
||||
}
|
||||
|
||||
/* r-r interval */
|
||||
if (flags & CH_HRM_FLAGS_RR_INTERVAL)
|
||||
{
|
||||
/* get length of r-r interval bytes */
|
||||
len = len + CH_HRM_LEN_RR_INTERVAL - minLen;
|
||||
|
||||
/* if len is somehow missing a byte (len is odd) reduce by 1 */
|
||||
if (len & 1)
|
||||
{
|
||||
len--;
|
||||
}
|
||||
|
||||
/* parse r-r intervals */
|
||||
do
|
||||
{
|
||||
BSTREAM_TO_UINT16(rrInterval, pValue);
|
||||
APP_TRACE_INFO1(" r-r Interval: %d", rrInterval);
|
||||
len -= 2;
|
||||
} while (len > 0);
|
||||
}
|
||||
|
||||
APP_TRACE_INFO1(" Flags:0x%02x", flags);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Heart Rate service. Parameter
|
||||
* pHdlList must point to an array of length HRPC_HRS_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpcHrsDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attHrsSvcUuid,
|
||||
HRPC_HRS_HDL_LIST_LEN, (attcDiscChar_t **) hrpcHrsDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a command to the heart rate control point.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param command Control point command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpcHrsControl(dmConnId_t connId, uint16_t handle, uint8_t command)
|
||||
{
|
||||
uint8_t buf[1];
|
||||
|
||||
if (handle != ATT_HANDLE_NONE)
|
||||
{
|
||||
buf[0] = command;
|
||||
AttcWriteReq(connId, handle, sizeof(buf), buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length HRPC_HRS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HrpcHrsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t *p;
|
||||
uint8_t sensorLoc;
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
|
||||
/* heart rate measurement */
|
||||
if (pMsg->handle == pHdlList[HRPC_HRS_HRM_HDL_IDX])
|
||||
{
|
||||
/* parse value */
|
||||
hrcpHrsParseHrm(pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
/* body sensor location */
|
||||
else if (pMsg->handle == pHdlList[HRPC_HRS_BSL_HDL_IDX])
|
||||
{
|
||||
/* parse value */
|
||||
p = pMsg->pValue;
|
||||
BSTREAM_TO_UINT8(sensorLoc, p);
|
||||
|
||||
/* ignore if out of range */
|
||||
if (sensorLoc <= CH_BSENSOR_LOC_FOOT)
|
||||
{
|
||||
APP_TRACE_INFO1("Body sensor location:%d", sensorLoc);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
Vendored
+131
@@ -0,0 +1,131 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Heart Rate profile sensor.
|
||||
*
|
||||
* Copyright (c) 2011-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 HRPS_API_H
|
||||
#define HRPS_API_H
|
||||
|
||||
#include "wsf_timer.h"
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup HEART_RATE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Configurable parameters */
|
||||
typedef struct
|
||||
{
|
||||
wsfTimerTicks_t period; /*!< \brief Measurement timer expiration period in ms */
|
||||
} hrpsCfg_t;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the Heart Rate profile sensor.
|
||||
*
|
||||
* \param handlerId WSF handler ID of the application using this service.
|
||||
* \param pCfg Configurable parameters.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpsInit(wsfHandlerId_t handlerId, hrpsCfg_t *pCfg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start periodic heart rate measurement. This function starts a timer to perform
|
||||
* periodic measurements.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param timerEvt WSF event designated by the application for the timer.
|
||||
* \param hrmCccIdx Index of heart rate CCC descriptor in CCC descriptor handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpsMeasStart(dmConnId_t connId, uint8_t timerEvt, uint8_t hrmCccIdx);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop periodic heart rate measurement.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpsMeasStop(dmConnId_t connId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received WSF message.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpsProcMsg(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for heart rate service Use this function as a parameter
|
||||
* to SvcHrsCbackRegister().
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param handle ATT handle.
|
||||
* \param operation ATT operation.
|
||||
* \param offset Write offset.
|
||||
* \param len Write length.
|
||||
* \param pValue Value to write.
|
||||
* \param pAttr Attribute to write.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HrpsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the heart rate measurement flags.
|
||||
*
|
||||
* \param flags Heart rate measurement flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpsSetFlags(uint8_t flags);
|
||||
|
||||
/*! \} */ /* HEART_RATE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HRPS_API_H */
|
||||
Vendored
+465
@@ -0,0 +1,465 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Heart Rate profile sensor.
|
||||
*
|
||||
* 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_assert.h"
|
||||
#include "wsf_buf.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "svc_ch.h"
|
||||
#include "svc_hrs.h"
|
||||
#include "app_api.h"
|
||||
#include "app_hw.h"
|
||||
#include "hrps_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Connection control block */
|
||||
typedef struct
|
||||
{
|
||||
dmConnId_t connId; /*! \brief Connection ID */
|
||||
bool_t hrmToSend; /*! \brief heart rate measurement ready to be sent on this channel */
|
||||
} hrpsConn_t;
|
||||
|
||||
/*! \brief Control block */
|
||||
static struct
|
||||
{
|
||||
hrpsConn_t conn[DM_CONN_MAX]; /* \brief connection control block */
|
||||
wsfTimer_t measTimer; /* \brief periodic measurement timer */
|
||||
appHrm_t hrm; /* \brief heart rate measurement */
|
||||
hrpsCfg_t cfg; /* \brief configurable parameters */
|
||||
uint16_t energyExp; /* \brief energy expended value */
|
||||
bool_t txReady; /* \brief TRUE if ready to send notifications */
|
||||
uint8_t flags; /* \brief heart rate measurement flags */
|
||||
} hrpsCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Return TRUE if no connections with active measurements.
|
||||
*
|
||||
* \return TRUE if no connections active.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t hrpsNoConnActive(void)
|
||||
{
|
||||
hrpsConn_t *pConn = hrpsCb.conn;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < DM_CONN_MAX; i++, pConn++)
|
||||
{
|
||||
if (pConn->connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Setup to send measurements on active connections.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hrpsSetupToSend(void)
|
||||
{
|
||||
hrpsConn_t *pConn = hrpsCb.conn;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < DM_CONN_MAX; i++, pConn++)
|
||||
{
|
||||
if (pConn->connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
pConn->hrmToSend = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Find next connection with measurement to send.
|
||||
*
|
||||
* \param cccIdx Heart rate measurement CCC descriptor index.
|
||||
*
|
||||
* \return Connection control block.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static hrpsConn_t *hrpsFindNextToSend(uint8_t cccIdx)
|
||||
{
|
||||
hrpsConn_t *pConn = hrpsCb.conn;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < DM_CONN_MAX; i++, pConn++)
|
||||
{
|
||||
if (pConn->connId != DM_CONN_ID_NONE && pConn->hrmToSend)
|
||||
{
|
||||
if (AttsCccEnabled(pConn->connId, cccIdx))
|
||||
{
|
||||
return pConn;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Build a heart rate measurement characteristic.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param pBuf Pointer to buffer to hold the built heart rate measurement characteristic.
|
||||
* \param pHrm Heart rate measurement values.
|
||||
*
|
||||
* \return Length of pBuf in bytes.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t hrpsBuildHrm(dmConnId_t connId, uint8_t **pBuf, appHrm_t *pHrm)
|
||||
{
|
||||
uint8_t *pHrpsData;
|
||||
uint8_t flags = pHrm->flags;
|
||||
uint8_t i;
|
||||
uint16_t *pInterval;
|
||||
uint8_t len = 2; /* Start with 2 for flags and 1 Byte Heart Rate measurement */
|
||||
uint8_t maxLen = AttGetMtu(connId) - ATT_VALUE_NTF_LEN;
|
||||
|
||||
/* Calculate Buffer length */
|
||||
if (flags & CH_HRM_FLAGS_VALUE_16BIT)
|
||||
{
|
||||
len += 1;
|
||||
}
|
||||
|
||||
if (flags & CH_HRM_FLAGS_ENERGY_EXP)
|
||||
{
|
||||
len += 2;
|
||||
}
|
||||
|
||||
/* rr interval */
|
||||
if (flags & CH_HRM_FLAGS_RR_INTERVAL)
|
||||
{
|
||||
len += pHrm->numIntervals * sizeof(uint16_t);
|
||||
}
|
||||
|
||||
/* Adjust length if necessary */
|
||||
if (len > maxLen)
|
||||
{
|
||||
len = maxLen;
|
||||
}
|
||||
|
||||
/* Allocate buffer */
|
||||
if ((*pBuf = (uint8_t *)WsfBufAlloc(len)) != NULL)
|
||||
{
|
||||
/* Add data to buffer */
|
||||
pHrpsData = *pBuf;
|
||||
|
||||
/* flags */
|
||||
UINT8_TO_BSTREAM(pHrpsData, flags);
|
||||
|
||||
/* Subtract 2 for flags and 1 Byte Heart Rate measurement */
|
||||
len -= 2;
|
||||
|
||||
/* heart rate measurement */
|
||||
if (flags & CH_HRM_FLAGS_VALUE_16BIT)
|
||||
{
|
||||
UINT16_TO_BSTREAM(pHrpsData, (uint16_t)pHrm->heartRate);
|
||||
|
||||
/* Subtract an additional byte for a 2 byte Heart Rate measurement */
|
||||
len -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8_TO_BSTREAM(pHrpsData, pHrm->heartRate);
|
||||
}
|
||||
|
||||
/* energy expended */
|
||||
if (flags & CH_HRM_FLAGS_ENERGY_EXP)
|
||||
{
|
||||
UINT16_TO_BSTREAM(pHrpsData, pHrm->energyExp);
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
/* rr interval */
|
||||
if (flags & CH_HRM_FLAGS_RR_INTERVAL)
|
||||
{
|
||||
pInterval = pHrm->pRrInterval;
|
||||
|
||||
/* Use as many rr intervals as will fit in remaining buffer space. */
|
||||
i = pHrm->numIntervals < (len / sizeof(uint16_t)) ?
|
||||
pHrm->numIntervals : (len / sizeof(uint16_t));
|
||||
|
||||
for (; i > 0; i--, pInterval++)
|
||||
{
|
||||
UINT16_TO_BSTREAM(pHrpsData, *pInterval);
|
||||
}
|
||||
}
|
||||
|
||||
/* return length */
|
||||
return (uint8_t)(pHrpsData - *pBuf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send heart rate measurement notification
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hrpsSendHrmNtf(dmConnId_t connId)
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint8_t len;
|
||||
|
||||
/* Build heart rate measurement characteristic */
|
||||
if ((len = hrpsBuildHrm(connId, &pBuf, &hrpsCb.hrm)) > 0)
|
||||
{
|
||||
/* Send notification */
|
||||
AttsHandleValueNtf(connId, HRS_HRM_HDL, len, pBuf);
|
||||
|
||||
/* Free allocated buffer */
|
||||
WsfBufFree(pBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle connection open.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hrpsConnOpen(dmEvt_t *pMsg)
|
||||
{
|
||||
hrpsCb.txReady = TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a received ATT handle value confirm.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void hrpsHandleValueCnf(attEvt_t *pMsg)
|
||||
{
|
||||
hrpsConn_t *pConn;
|
||||
|
||||
if (pMsg->hdr.status == ATT_SUCCESS && pMsg->handle == HRS_HRM_HDL)
|
||||
{
|
||||
hrpsCb.txReady = TRUE;
|
||||
|
||||
/* find next connection to send (note ccc idx is stored in timer status) */
|
||||
if ((pConn = hrpsFindNextToSend(hrpsCb.measTimer.msg.status)) != NULL)
|
||||
{
|
||||
hrpsSendHrmNtf(pConn->connId);
|
||||
hrpsCb.txReady = FALSE;
|
||||
pConn->hrmToSend = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application when the periodic measurement
|
||||
* timer expires.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void hrpsMeasTimerExp(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
hrpsConn_t *pConn;
|
||||
|
||||
/* if there are active connections */
|
||||
if (hrpsNoConnActive() == FALSE)
|
||||
{
|
||||
|
||||
/* set up heart rate measurement to be sent on all connections */
|
||||
hrpsSetupToSend();
|
||||
|
||||
/* read heart rate measurement sensor data */
|
||||
AppHwHrmRead(&hrpsCb.hrm);
|
||||
|
||||
/* if ready to send measurements */
|
||||
if (hrpsCb.txReady)
|
||||
{
|
||||
/* find next connection to send (note ccc idx is stored in timer status) */
|
||||
if ((pConn = hrpsFindNextToSend(pMsg->status)) != NULL)
|
||||
{
|
||||
hrpsSendHrmNtf(pConn->connId);
|
||||
hrpsCb.txReady = FALSE;
|
||||
pConn->hrmToSend = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* restart timer */
|
||||
WsfTimerStartMs(&hrpsCb.measTimer, hrpsCb.cfg.period);
|
||||
|
||||
/* increment energy expended for test/demonstration purposes */
|
||||
hrpsCb.hrm.energyExp++;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the Heart Rate profile sensor.
|
||||
*
|
||||
* \param handerId WSF handler ID of the application using this service.
|
||||
* \param pCfg Configurable parameters.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpsInit(wsfHandlerId_t handlerId, hrpsCfg_t *pCfg)
|
||||
{
|
||||
hrpsCb.measTimer.handlerId = handlerId;
|
||||
hrpsCb.cfg = *pCfg;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start periodic heart rate measurement. This function starts a timer to perform
|
||||
* periodic measurements.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param timerEvt WSF event designated by the application for the timer.
|
||||
* \param hrmCccIdx Index of heart rate CCC descriptor in CCC descriptor handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpsMeasStart(dmConnId_t connId, uint8_t timerEvt, uint8_t hrmCccIdx)
|
||||
{
|
||||
/* if this is first connection */
|
||||
if (hrpsNoConnActive())
|
||||
{
|
||||
/* initialize control block */
|
||||
hrpsCb.measTimer.msg.event = timerEvt;
|
||||
hrpsCb.measTimer.msg.status = hrmCccIdx;
|
||||
|
||||
/* start timer */
|
||||
WsfTimerStartMs(&hrpsCb.measTimer, hrpsCb.cfg.period);
|
||||
}
|
||||
|
||||
/* set conn id */
|
||||
hrpsCb.conn[connId - 1].connId = connId;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop periodic heart rate measurement.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpsMeasStop(dmConnId_t connId)
|
||||
{
|
||||
/* clear connection */
|
||||
hrpsCb.conn[connId - 1].connId = DM_CONN_ID_NONE;
|
||||
hrpsCb.conn[connId - 1].hrmToSend = FALSE;
|
||||
|
||||
/* if no remaining connections */
|
||||
if (hrpsNoConnActive())
|
||||
{
|
||||
/* stop timer */
|
||||
WsfTimerStop(&hrpsCb.measTimer);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process received WSF message.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpsProcMsg(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
if (pMsg->event == DM_CONN_OPEN_IND)
|
||||
{
|
||||
hrpsConnOpen((dmEvt_t *) pMsg);
|
||||
}
|
||||
else if (pMsg->event == ATTS_HANDLE_VALUE_CNF)
|
||||
{
|
||||
hrpsHandleValueCnf((attEvt_t *) pMsg);
|
||||
}
|
||||
else if (pMsg->event == hrpsCb.measTimer.msg.event)
|
||||
{
|
||||
hrpsMeasTimerExp(pMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for heart rate service. Use this function as a parameter
|
||||
* to SvcHrsCbackRegister().
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HrpsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
|
||||
{
|
||||
if (*pValue == CH_HRCP_RESET_ENERGY_EXP)
|
||||
{
|
||||
/* reset energy expended */
|
||||
hrpsCb.hrm.energyExp = 0;
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* else unknown control point command */
|
||||
return HRS_ERR_CP_NOT_SUP;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the heart rate measurement flags.
|
||||
*
|
||||
* \param flags Heart rate measurement flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HrpsSetFlags(uint8_t flags)
|
||||
{
|
||||
hrpsCb.hrm.flags = flags;
|
||||
}
|
||||
Vendored
+91
@@ -0,0 +1,91 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Health Thermometer profile client.
|
||||
*
|
||||
* 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 HTPC_API_H
|
||||
#define HTPC_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup HEALTH_THERMOMETER_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Health Thermometer service enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
HTPC_HTS_TM_HDL_IDX, /*!< \brief Temperature measurement */
|
||||
HTPC_HTS_TM_CCC_HDL_IDX, /*!< \brief Temperature measurement CCC descriptor */
|
||||
HTPC_HTS_IT_HDL_IDX, /*!< \brief Intermediate temperature */
|
||||
HTPC_HTS_IT_CCC_HDL_IDX, /*!< \brief Intermediate temperature CCC descriptor */
|
||||
HTPC_HTS_TT_HDL_IDX, /*!< \brief Temperature type */
|
||||
HTPC_HTS_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Health Thermometer service.
|
||||
* Parameter pHdlList must point to an array of length \ref HTPC_HTS_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpcHtsDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length \ref HTPC_HTS_HDL_LIST_LEN.
|
||||
* If the ATT handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristc handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if handle is found, \ref ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HtpcHtsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg);
|
||||
|
||||
/*! \} */ /* HEALTH_THERMOMETER_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HTPC_API_H */
|
||||
Vendored
+231
@@ -0,0 +1,231 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Health Thermometer profile collector.
|
||||
*
|
||||
* 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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_ch.h"
|
||||
#include "app_api.h"
|
||||
#include "htpc_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*!
|
||||
* Health Thermometer service
|
||||
*/
|
||||
|
||||
/* Characteristics for discovery */
|
||||
|
||||
/*! Temperature measurement */
|
||||
static const attcDiscChar_t htpcHtsTm =
|
||||
{
|
||||
attTmChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Temperature measurement CCC descriptor */
|
||||
static const attcDiscChar_t htpcHtsTmCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Intermediate temperature */
|
||||
static const attcDiscChar_t htpcHtsIt =
|
||||
{
|
||||
attItChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Intermediate temperature CCC descriptor */
|
||||
static const attcDiscChar_t htpcHtsItCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Temperature type */
|
||||
static const attcDiscChar_t htpcHtsTt =
|
||||
{
|
||||
attTtChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *htpcHtsDiscCharList[] =
|
||||
{
|
||||
&htpcHtsTm, /*! Temperature measurement */
|
||||
&htpcHtsTmCcc, /*! Temperature measurement CCC descriptor */
|
||||
&htpcHtsIt, /*! Intermediate temperature */
|
||||
&htpcHtsItCcc, /*! Intermediate temperature CCC descriptor */
|
||||
&htpcHtsTt /*! Temperature type */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(HTPC_HTS_HDL_LIST_LEN == ((sizeof(htpcHtsDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Parse a temperature measurement.
|
||||
*
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void htpcHtsParseTm(uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
uint8_t flags;
|
||||
uint32_t tempUint;
|
||||
int32_t tempM;
|
||||
int8_t tempE;
|
||||
uint16_t year;
|
||||
uint8_t month, day, hour, min, sec;
|
||||
uint8_t tempType;
|
||||
uint16_t minLen = CH_TM_FLAGS_LEN + CH_TM_MEAS_LEN;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)tempM; (void)tempE; (void)tempType;
|
||||
(void)year; (void)month; (void)day; (void)hour; (void)min; (void)sec;
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
/* get flags */
|
||||
BSTREAM_TO_UINT8(flags, pValue);
|
||||
|
||||
/* determine expected minimum length based on flags */
|
||||
if (flags & CH_TM_FLAG_TIMESTAMP)
|
||||
{
|
||||
minLen += CH_TM_TIMESTAMP_LEN;
|
||||
}
|
||||
if (flags & CH_TM_FLAG_TEMP_TYPE)
|
||||
{
|
||||
minLen += CH_TM_TEMP_TYPE_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
/* verify length */
|
||||
if (len < minLen)
|
||||
{
|
||||
APP_TRACE_INFO2("Temperature meas len:%d minLen:%d", len, minLen);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Temperature */
|
||||
BSTREAM_TO_UINT32(tempUint, pValue);
|
||||
UINT32_TO_FLT(tempM, tempE, tempUint);
|
||||
APP_TRACE_INFO2(" Temperature:%de%d", tempM, tempE);
|
||||
|
||||
/* timestamp */
|
||||
if (flags & CH_TM_FLAG_TIMESTAMP)
|
||||
{
|
||||
BSTREAM_TO_UINT16(year, pValue);
|
||||
BSTREAM_TO_UINT8(month, pValue);
|
||||
BSTREAM_TO_UINT8(day, pValue);
|
||||
BSTREAM_TO_UINT8(hour, pValue);
|
||||
BSTREAM_TO_UINT8(min, pValue);
|
||||
BSTREAM_TO_UINT8(sec, pValue);
|
||||
APP_TRACE_INFO3(" Date: %d/%d/%d", month, day, year);
|
||||
APP_TRACE_INFO3(" Time: %02d:%02d:%02d", hour, min, sec);
|
||||
}
|
||||
|
||||
/* temperature type */
|
||||
if (flags & CH_TM_FLAG_TEMP_TYPE)
|
||||
{
|
||||
BSTREAM_TO_UINT8(tempType, pValue);
|
||||
APP_TRACE_INFO1(" Temp. Type:%d", tempType);
|
||||
}
|
||||
|
||||
APP_TRACE_INFO1(" Flags:0x%02x", flags);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Health Thermometer service. Parameter
|
||||
* pHdlList must point to an array of length HTPC_HTS_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpcHtsDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attHtsSvcUuid,
|
||||
HTPC_HTS_HDL_LIST_LEN, (attcDiscChar_t **) htpcHtsDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length HTPC_HTS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t HtpcHtsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
|
||||
/* temperature measurement */
|
||||
if (pMsg->handle == pHdlList[HTPC_HTS_TM_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO0("Temperature measurement");
|
||||
|
||||
/* parse value */
|
||||
htpcHtsParseTm(pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
/* intermediate cuff pressure */
|
||||
else if (pMsg->handle == pHdlList[HTPC_HTS_IT_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO0("Intermed. temperature");
|
||||
|
||||
/* parse value */
|
||||
htpcHtsParseTm(pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
/* temperature type */
|
||||
else if (pMsg->handle == pHdlList[HTPC_HTS_TT_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO1("Temperature type:%d", pMsg->pValue[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
Vendored
+136
@@ -0,0 +1,136 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Health Thermometer profile sensor.
|
||||
*
|
||||
* 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 HTPS_API_H
|
||||
#define HTPS_API_H
|
||||
|
||||
#include "wsf_timer.h"
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup HEALTH_THERMOMETER_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Configurable parameters */
|
||||
typedef struct
|
||||
{
|
||||
wsfTimerTicks_t period; /*!< \brief Measurement timer expiration period in ms */
|
||||
} htpsCfg_t;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the Health Thermometer profile sensor.
|
||||
*
|
||||
* \param handlerId WSF handler ID of the application using this service.
|
||||
* \param pCfg Configurable parameters.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsInit(wsfHandlerId_t handlerId, htpsCfg_t *pCfg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start periodic temperature measurement. This function starts a timer to perform
|
||||
* periodic measurements.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param timerEvt WSF event designated by the application for the timer.
|
||||
* \param itCccIdx Index of intermediate temperature CCC descriptor in CCC descriptor
|
||||
* handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsMeasStart(dmConnId_t connId, uint8_t timerEvt, uint8_t itCccIdx);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop periodic temperature measurement.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsMeasStop(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Temperature measurement complete.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param tmCccIdx Index of temperature measurement CCC descriptor in CCC descriptor
|
||||
* handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsMeasComplete(dmConnId_t connId, uint8_t tmCccIdx);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application when the periodic measurement
|
||||
* timer expires.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsProcMsg(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the temperature measurement flags.
|
||||
*
|
||||
* \param flags Temperature measurement flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsSetTmFlags(uint8_t flags);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the intermediate temperature flags.
|
||||
*
|
||||
* \param flags Intermediate temperature flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsSetItFlags(uint8_t flags);
|
||||
|
||||
/*! \} */ /* HEALTH_THERMOMETER_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HTPS_API_H */
|
||||
Vendored
+242
@@ -0,0 +1,242 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Health Thermometer profile sensor.
|
||||
*
|
||||
* 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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "svc_ch.h"
|
||||
#include "svc_hts.h"
|
||||
#include "app_api.h"
|
||||
#include "app_hw.h"
|
||||
#include "htps_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
static struct
|
||||
{
|
||||
wsfTimer_t measTimer; /* periodic measurement timer */
|
||||
appTm_t tm; /* temperature measurement */
|
||||
htpsCfg_t cfg; /* configurable parameters */
|
||||
uint8_t tmFlags; /* temperature measurement flags */
|
||||
uint8_t itFlags; /* intermediate temperature flags */
|
||||
} htpsCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Build a temperature measurement characteristic.
|
||||
*
|
||||
* \param pBuf Pointer to buffer to hold the built temperature measurement characteristic.
|
||||
* \param pTm Temperature measurement values.
|
||||
*
|
||||
* \return Length of pBuf in bytes.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t htpsBuildTm(uint8_t *pBuf, appTm_t *pTm)
|
||||
{
|
||||
uint8_t *p = pBuf;
|
||||
uint8_t flags = pTm->flags;
|
||||
|
||||
/* flags */
|
||||
UINT8_TO_BSTREAM(p, flags);
|
||||
|
||||
/* measurement */
|
||||
UINT32_TO_BSTREAM(p, pTm->temperature);
|
||||
|
||||
/* time stamp */
|
||||
if (flags & CH_TM_FLAG_TIMESTAMP)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pTm->timestamp.year);
|
||||
UINT8_TO_BSTREAM(p, pTm->timestamp.month);
|
||||
UINT8_TO_BSTREAM(p, pTm->timestamp.day);
|
||||
UINT8_TO_BSTREAM(p, pTm->timestamp.hour);
|
||||
UINT8_TO_BSTREAM(p, pTm->timestamp.min);
|
||||
UINT8_TO_BSTREAM(p, pTm->timestamp.sec);
|
||||
}
|
||||
|
||||
/* temperature type */
|
||||
if (flags & CH_TM_FLAG_TEMP_TYPE)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pTm->tempType);
|
||||
}
|
||||
|
||||
/* return length */
|
||||
return (uint8_t) (p - pBuf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the Health Thermometer profile sensor.
|
||||
*
|
||||
* \param handerId WSF handler ID of the application using this service.
|
||||
* \param pCfg Configurable parameters.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsInit(wsfHandlerId_t handlerId, htpsCfg_t *pCfg)
|
||||
{
|
||||
htpsCb.measTimer.handlerId = handlerId;
|
||||
htpsCb.cfg = *pCfg;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start periodic temperature measurement. This function starts a timer to perform
|
||||
* periodic measurements.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param timerEvt WSF event designated by the application for the timer.
|
||||
* \param itCccIdx Index of intermediate temperature CCC descriptor in CCC descriptor
|
||||
* handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsMeasStart(dmConnId_t connId, uint8_t timerEvt, uint8_t itCccIdx)
|
||||
{
|
||||
/* initialize control block */
|
||||
htpsCb.measTimer.msg.param = connId;
|
||||
htpsCb.measTimer.msg.event = timerEvt;
|
||||
htpsCb.measTimer.msg.status = itCccIdx;
|
||||
|
||||
/* start timer */
|
||||
WsfTimerStartMs(&htpsCb.measTimer, htpsCb.cfg.period);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop periodic temperature measurement.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsMeasStop(void)
|
||||
{
|
||||
/* stop timer */
|
||||
WsfTimerStop(&htpsCb.measTimer);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Temperature measurement complete.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param tmCccIdx Index of temperature measurement CCC descriptor in CCC descriptor
|
||||
* handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsMeasComplete(dmConnId_t connId, uint8_t tmCccIdx)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t len;
|
||||
|
||||
/* stop periodic measurement */
|
||||
HtpsMeasStop();
|
||||
|
||||
/* if indications enabled */
|
||||
if (AttsCccEnabled(connId, tmCccIdx))
|
||||
{
|
||||
/* read temperature measurement sensor data */
|
||||
AppHwTmRead(FALSE, &htpsCb.tm);
|
||||
|
||||
/* set flags */
|
||||
htpsCb.tm.flags = htpsCb.tmFlags;
|
||||
|
||||
/* build temperature measurement characteristic */
|
||||
len = htpsBuildTm(buf, &htpsCb.tm);
|
||||
|
||||
/* send temperature measurement indication */
|
||||
AttsHandleValueInd(connId, HTS_TM_HDL, len, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application when the periodic measurement
|
||||
* timer expires.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsProcMsg(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t len;
|
||||
|
||||
/* if notifications enabled (note ccc idx is stored in hdr.status) */
|
||||
if (AttsCccEnabled((dmConnId_t) pMsg->param, pMsg->status))
|
||||
{
|
||||
/* read temperature measurement sensor data */
|
||||
AppHwTmRead(TRUE, &htpsCb.tm);
|
||||
|
||||
/* set flags */
|
||||
htpsCb.tm.flags = htpsCb.itFlags;
|
||||
|
||||
/* build temperature measurement characteristic */
|
||||
len = htpsBuildTm(buf, &htpsCb.tm);
|
||||
|
||||
/* send intermediate temperature notification */
|
||||
AttsHandleValueNtf((dmConnId_t) pMsg->param, HTS_IT_HDL, len, buf);
|
||||
|
||||
/* restart timer */
|
||||
WsfTimerStartMs(&htpsCb.measTimer, htpsCb.cfg.period);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the temperature measurement flags.
|
||||
*
|
||||
* \param flags Temperature measurement flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsSetTmFlags(uint8_t flags)
|
||||
{
|
||||
htpsCb.tmFlags = flags;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the intermediate temperature flags.
|
||||
*
|
||||
* \param flags Intermediate temperature flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void HtpsSetItFlags(uint8_t flags)
|
||||
{
|
||||
htpsCb.itFlags = flags;
|
||||
}
|
||||
+267
@@ -0,0 +1,267 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange Protocol Definitions.
|
||||
*
|
||||
* Copyright (c) 2013-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 WDX_DEFS_H
|
||||
#define WDX_DEFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/*! \addtogroup WIRELESS_DATA_EXCHANGE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Base UUID: 005fXXXX-2ff2-4ed5-b045-4C7463617865 */
|
||||
#define WDX_UUID_PART1 0x65, 0x78, 0x61, 0x63, 0x74, 0x4c, 0x45, 0xb0, \
|
||||
0xd5, 0x4e, 0xf2, 0x2f
|
||||
/*! \brief Base UUID Part 2 */
|
||||
#define WDX_UUID_PART2 0x5f, 0x00
|
||||
|
||||
/*! \brief Macro for building UUIDs */
|
||||
#define WDX_UUID_BUILD(part) WDX_UUID_PART1, UINT16_TO_BYTES(part), WDX_UUID_PART2
|
||||
|
||||
/*! \brief WDX Service */
|
||||
#define WDX_SVC_UUID 0xFEF6
|
||||
|
||||
/*! \brief WDX Device Configuration Characteristic */
|
||||
#define WDX_DC_UUID WDX_UUID_BUILD(0x0002)
|
||||
|
||||
/*! \brief WDX File Transfer Control Characteristic */
|
||||
#define WDX_FTC_UUID WDX_UUID_BUILD(0x0003)
|
||||
|
||||
/*! \brief WDX File Transfer Data Characteristic */
|
||||
#define WDX_FTD_UUID WDX_UUID_BUILD(0x0004)
|
||||
|
||||
/*! \brief WDX Authentication Characteristic */
|
||||
#define WDX_AU_UUID WDX_UUID_BUILD(0x0005)
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
Constant Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name WDXS File List Configuration
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_FLIST_HANDLE 0 /*!< \brief File List handle */
|
||||
#define WDX_FLIST_FORMAT_VER 1 /*!< \brief File List version */
|
||||
#define WDX_FLIST_HDR_SIZE 7 /*!< \brief File List header length */
|
||||
#define WDX_FLIST_RECORD_SIZE 40 /*!< \brief File List record length */
|
||||
/*! \brief File list max length. */
|
||||
#define WDX_FLIST_MAX_LEN (WDX_FLIST_HDR_SIZE + (WDX_FLIST_RECORD_SIZE * (WSF_EFS_MAX_FILES-1)))
|
||||
/**@}*/
|
||||
|
||||
/*! \brief Device configuration characteristic message header length */
|
||||
#define WDX_DC_HDR_LEN 2
|
||||
|
||||
/** \name Device Configuration Characteristic oOperations
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_DC_OP_GET 0x01 /*!< \brief Get a parameter value */
|
||||
#define WDX_DC_OP_SET 0x02 /*!< \brief Set a parameter value */
|
||||
#define WDX_DC_OP_UPDATE 0x03 /*!< \brief Send an update of a parameter value */
|
||||
/**@}*/
|
||||
|
||||
/** \name Device Control Characteristic Parameter IDs
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_DC_ID_CONN_UPDATE_REQ 0x01 /*!< \brief Connection Parameter Update Request */
|
||||
#define WDX_DC_ID_CONN_PARAM 0x02 /*!< \brief Current Connection Parameters */
|
||||
#define WDX_DC_ID_DISCONNECT_REQ 0x03 /*!< \brief Disconnect Request */
|
||||
#define WDX_DC_ID_CONN_SEC_LEVEL 0x04 /*!< \brief Connection Security Level */
|
||||
#define WDX_DC_ID_SECURITY_REQ 0x05 /*!< \brief Security Request */
|
||||
#define WDX_DC_ID_SERVICE_CHANGED 0x06 /*!< \brief Service Changed */
|
||||
#define WDX_DC_ID_DELETE_BONDS 0x07 /*!< \brief Delete Bonds */
|
||||
#define WDX_DC_ID_ATT_MTU 0x08 /*!< \brief Current ATT MTU */
|
||||
#define WDX_DC_ID_PHY_UPDATE_REQ 0x09 /*!< \brief PHY update request */
|
||||
#define WDX_DC_ID_PHY 0x0A /*!< \brief Current PHY */
|
||||
#define WDX_DC_ID_BATTERY_LEVEL 0x20 /*!< \brief Battery level */
|
||||
#define WDX_DC_ID_MODEL_NUMBER 0x21 /*!< \brief Device Model */
|
||||
#define WDX_DC_ID_FIRMWARE_REV 0x22 /*!< \brief Device Firmware Revision */
|
||||
#define WDX_DC_ID_ENTER_DIAGNOSTICS 0x23 /*!< \brief Enter Diagnostic Mode */
|
||||
#define WDX_DC_ID_DIAGNOSTICS_COMPLETE 0x24 /*!< \brief Diagnostic Complete */
|
||||
#define WDX_DC_ID_DISCONNECT_AND_RESET 0x25 /*!< \brief Disconnect and Reset */
|
||||
/**@}*/
|
||||
|
||||
/** \name Device Control Parameter Lengths
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_DC_LEN_DATA_FORMAT 1 /*!< \brief Data format */
|
||||
#define WDX_DC_LEN_SEC_LEVEL 1 /*!< \brief Security Level */
|
||||
#define WDX_DC_LEN_ATT_MTU 2 /*!< \brief ATT MTU */
|
||||
#define WDX_DC_LEN_BATTERY_LEVEL 1 /*!< \brief Battery level */
|
||||
#define WDX_DC_LEN_CONN_PARAM_REQ 8 /*!< \brief Connection parameter request */
|
||||
#define WDX_DC_LEN_CONN_PARAM 7 /*!< \brief Current connection parameters */
|
||||
#define WDX_DC_LEN_PHY_UPDATE_REQ 5 /*!< \brief PHY update request */
|
||||
#define WDX_DC_LEN_PHY 3 /*!< \brief Current PHY */
|
||||
#define WDX_DC_LEN_DIAG_COMPLETE 0 /*!< \brief Diagnostic complete */
|
||||
#define WDX_DC_LEN_DEVICE_MODEL 18 /*!< \brief Device Model */
|
||||
#define WDX_DC_LEN_FIRMWARE_REV 16 /*!< \brief Firmware Revision */
|
||||
/**@}*/
|
||||
|
||||
/** \name File Transfer Control Characteristic Message Header Length
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_FTC_HDR_LEN 1 /*!< \brief Header length. */
|
||||
#define WDX_FTC_HANDLE_LEN 2 /*!< \brief Handle length. */
|
||||
|
||||
/** \name File Transfer Control Characteristic Operations
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_FTC_OP_NONE 0x00 /*!< \brief No operation */
|
||||
#define WDX_FTC_OP_GET_REQ 0x01 /*!< \brief Get a file from the server */
|
||||
#define WDX_FTC_OP_GET_RSP 0x02 /*!< \brief File get response */
|
||||
#define WDX_FTC_OP_PUT_REQ 0x03 /*!< \brief Put a file to the server */
|
||||
#define WDX_FTC_OP_PUT_RSP 0x04 /*!< \brief File put response */
|
||||
#define WDX_FTC_OP_ERASE_REQ 0x05 /*!< \brief Erase a file on the server */
|
||||
#define WDX_FTC_OP_ERASE_RSP 0x06 /*!< \brief File erase response */
|
||||
#define WDX_FTC_OP_VERIFY_REQ 0x07 /*!< \brief Verify a file (e.g. check its CRC) */
|
||||
#define WDX_FTC_OP_VERIFY_RSP 0x08 /*!< \brief File verify response */
|
||||
#define WDX_FTC_OP_ABORT 0x09 /*!< \brief Abort a get, put, or list operation in progress */
|
||||
#define WDX_FTC_OP_EOF 0x0a /*!< \brief End of file reached */
|
||||
/**@}*/
|
||||
|
||||
/** \name File Transfer Control Permissions
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_FTC_GET_PERMITTED 0x01 /*!< \brief File Get Permitted */
|
||||
#define WDX_FTC_PUT_PERMITTED 0x02 /*!< \brief File Put Permitted */
|
||||
#define WDX_FTC_ERASE_PERMITTED 0x04 /*!< \brief File Erase Permitted */
|
||||
#define WDX_FTC_VERIFY_PERMITTED 0x08 /*!< \brief File Verify Permitted */
|
||||
/**@}*/
|
||||
|
||||
/** \name File Transfer Control Characteristic Status
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_FTC_ST_SUCCESS 0 /*!< \brief Success */
|
||||
#define WDX_FTC_ST_INVALID_OP_FILE 1 /*!< \brief Invalid operation for this file */
|
||||
#define WDX_FTC_ST_INVALID_HANDLE 2 /*!< \brief Invalid file handle */
|
||||
#define WDX_FTC_ST_INVALID_OP_DATA 3 /*!< \brief Invalid operation data */
|
||||
#define WDX_FTC_ST_IN_PROGRESS 4 /*!< \brief Operation in progress */
|
||||
#define WDX_FTC_ST_VERIFICATION 5 /*!< \brief Verification failure */
|
||||
/**@}*/
|
||||
|
||||
/** \name File Transfer Control Transport
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_FTC_TRANSPORT_TYPE 0 /*!< \brief Transport Type */
|
||||
#define WDX_FTC_TRANSPORT_ID 0x0030 /*!< \brief Transport ID */
|
||||
/**@}*/
|
||||
|
||||
/*! \brief File transfer data characteristic message header length */
|
||||
#define WDX_FTD_HDR_LEN 0
|
||||
|
||||
/*! \brief Authentication message header length */
|
||||
#define WDX_AU_HDR_LEN 1
|
||||
|
||||
/** \name Authentication Characteristic Operations
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_AU_OP_START 0x01 /*!< \brief Authentication start */
|
||||
#define WDX_AU_OP_CHALLENGE 0x02 /*!< \brief Authentication challenge */
|
||||
#define WDX_AU_OP_REPLY 0x03 /*!< \brief Authentication reply */
|
||||
/**@}*/
|
||||
|
||||
/** \name Proprietary ATT Error Codes
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_APP_AUTH_REQUIRED 0x80 /*!< \brief Application authentication required */
|
||||
#define WDX_AU_ST_INVALID_MESSAGE 0x81 /*!< \brief Authentication invalid message */
|
||||
#define WDX_AU_ST_INVALID_STATE 0x82 /*!< \brief Authentication invalid state */
|
||||
#define WDX_AU_ST_AUTH_FAILED 0x83 /*!< \brief Authentication failed */
|
||||
/**@}*/
|
||||
|
||||
/** \name Authentication Characteristic Authentication Level
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_AU_LVL_NONE 0x00 /*!< \brief None */
|
||||
#define WDX_AU_LVL_USER 0x01 /*!< \brief User level */
|
||||
#define WDX_AU_LVL_MAINT 0x02 /*!< \brief Maintenance level */
|
||||
#define WDX_AU_LVL_DEBUG 0x03 /*!< \brief Debug level */
|
||||
/**@}*/
|
||||
|
||||
/** \name Authenttication Characteristic Message Parameter Lengths
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_AU_MSG_HDR_LEN 1 /*!< \brief Message header length */
|
||||
#define WDX_AU_PARAM_LEN_START 2 /*!< \brief Authentication start */
|
||||
#define WDX_AU_PARAM_LEN_CHALLENGE 16 /*!< \brief Authentication challenge */
|
||||
#define WDX_AU_PARAM_LEN_REPLY 8 /*!< \brief Authentication reply */
|
||||
/**@}*/
|
||||
|
||||
/** \name Authenttication Characteristic Random Number and Key Lengths
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_AU_RAND_LEN 16 /*!< \brief Authentication Random challenge length (bytes)*/
|
||||
#define WDX_AU_KEY_LEN 16 /*!< \brief Authentication Key length (bytes) */
|
||||
#define WDX_AU_HASH_LEN 8 /*!< \brief Authentication Hash length (bytes) */
|
||||
/**@}*/
|
||||
|
||||
/** \name WDXS Media Types
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_FLASH_MEDIA 0 /*!< \brief Flash media type. */
|
||||
#define WDX_OTA_MEDIA 1 /*!< \brief OTA media type. */
|
||||
#define WDX_RAM_MEDIA 2 /*!< \brief RAM media type. */
|
||||
#define WDX_STREAM_MEDIA 3 /*!< \brief Stream media type. */
|
||||
/**@}*/
|
||||
|
||||
/** \name WDXS File Transfer Control Command Message Lengths
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDX_FTC_ABORT_LEN 3 /*!< \brief Abort message length. */
|
||||
#define WDX_FTC_ERASE_LEN 3 /*!< \brief Erase message length. */
|
||||
#define WDX_FTC_VERIFY_LEN 3 /*!< \brief Verify message length. */
|
||||
#define WDX_FTC_PUT_LEN 16 /*!< \brief Put message length. */
|
||||
#define WDX_FTC_GET_LEN 12 /*!< \brief Get message length. */
|
||||
/**@}*/
|
||||
|
||||
/*! \} */ /* WIRELESS_DATA_EXCHANGE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WDX_DEFS_H */
|
||||
ambiq-hal-sys/ambiq-sparkfun-sdk/third_party/exactle/ble-profiles/sources/profiles/paspc/paspc_api.h
Vendored
+104
@@ -0,0 +1,104 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Phone Alert Status profile client.
|
||||
*
|
||||
* Copyright (c) 2011-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 PASPC_API_H
|
||||
#define PASPC_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup PHONE_ALERT_STATUS_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Phone Alert Status service enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
PASPC_PASS_AS_HDL_IDX, /*!< \brief Alert status */
|
||||
PASPC_PASS_AS_CCC_HDL_IDX, /*!< \brief Alert status CCC descriptor */
|
||||
PASPC_PASS_RS_HDL_IDX, /*!< \brief Ringer setting */
|
||||
PASPC_PASS_RS_CCC_HDL_IDX, /*!< \brief Ringer setting CCC descriptor */
|
||||
PASPC_PASS_RCP_HDL_IDX, /*!< \brief Ringer control point */
|
||||
PASPC_PASS_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Phone Alert Status service.
|
||||
* Parameter pHdlList must point to an array of length \ref PASPC_PASS_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PaspcPassDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a command to the ringer control point.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param command Control point command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PaspcPassControl(dmConnId_t connId, uint16_t handle, uint8_t command);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length \ref PASPC_PASS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if handle is found, \ref ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t PaspcPassValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg);
|
||||
|
||||
/*! \} */ /* PHONE_ALERT_STATUS_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* PASPC_API_H */
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Phone Alert Status profile client.
|
||||
*
|
||||
* Copyright (c) 2011-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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "app_api.h"
|
||||
#include "paspc_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*!
|
||||
* Phone Alert Status service
|
||||
*/
|
||||
|
||||
/* Characteristics for discovery */
|
||||
|
||||
|
||||
/*! Alert status */
|
||||
static const attcDiscChar_t paspcPassAs =
|
||||
{
|
||||
attAsChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Alert status CCC descriptor */
|
||||
static const attcDiscChar_t paspcPassAsCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Ringer setting */
|
||||
static const attcDiscChar_t paspcPassRs =
|
||||
{
|
||||
attRsChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Ringer setting CCC descriptor */
|
||||
static const attcDiscChar_t paspcPassRsCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Ringer control point */
|
||||
static const attcDiscChar_t paspcPassRcp =
|
||||
{
|
||||
attRcpChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *paspcPassDiscCharList[] =
|
||||
{
|
||||
&paspcPassAs, /*! Alert status */
|
||||
&paspcPassAsCcc, /*! Alert status CCC descriptor */
|
||||
&paspcPassRs, /*! Ringer setting */
|
||||
&paspcPassRsCcc, /*! Ringer setting CCC descriptor */
|
||||
&paspcPassRcp /*! Ringer control point */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(PASPC_PASS_HDL_LIST_LEN == ((sizeof(paspcPassDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Phone Alert Status service. Parameter
|
||||
* pHdlList must point to an array of length PASPC_ANS_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PaspcPassDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attPassSvcUuid,
|
||||
PASPC_PASS_HDL_LIST_LEN, (attcDiscChar_t **) paspcPassDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a command to the ringer control point.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param command Control point command.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PaspcPassControl(dmConnId_t connId, uint16_t handle, uint8_t command)
|
||||
{
|
||||
uint8_t buf[1];
|
||||
|
||||
if (handle != ATT_HANDLE_NONE)
|
||||
{
|
||||
buf[0] = command;
|
||||
AttcWriteCmd(connId, handle, sizeof(buf), buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length PASPC_PASS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t PaspcPassValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
|
||||
/* alert status */
|
||||
if (pMsg->handle == pHdlList[PASPC_PASS_AS_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO1("Phone alert status: 0x%02x", *pMsg->pValue);
|
||||
}
|
||||
/* ringer setting */
|
||||
else if (pMsg->handle == pHdlList[PASPC_PASS_RS_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO1("Ringer setting: 0x%02x", *pMsg->pValue);
|
||||
}
|
||||
/* handle not found in list */
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
ambiq-hal-sys/ambiq-sparkfun-sdk/third_party/exactle/ble-profiles/sources/profiles/plxpc/plxpc_api.h
Vendored
+108
@@ -0,0 +1,108 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Pulse Oximeter profile collector.
|
||||
*
|
||||
* 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 PLXPC_API_H
|
||||
#define PLXPC_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup PULSE_OXIMETER_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Pulse Oximeter service enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
PLXPC_PLXS_PLXSC_HDL_IDX, /*!< \brief Pulse Oximeter Spot Check measurement */
|
||||
PLXPC_PLXS_PLXSC_CCC_HDL_IDX, /*!< \brief Pulse Oximeter Spot Check measurement CCC descriptor */
|
||||
PLXPC_PLXS_PLXC_HDL_IDX, /*!< \brief Pulse Oximeter Continuous measurement */
|
||||
PLXPC_PLXS_PLXC_CCC_HDL_IDX, /*!< \brief Pulse Oximeter Continuous measurement CCC descriptor */
|
||||
PLXPC_PLXS_PLXF_HDL_IDX, /*!< \brief Pulse Oximeter features */
|
||||
PLXPC_PLXS_RACP_HDL_IDX, /*!< \brief Record access control point */
|
||||
PLXPC_PLXS_RACP_CCC_HDL_IDX, /*!< \brief Record access control point CCC descriptor */
|
||||
PLXPC_PLXS_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Pulse Oximeter service.
|
||||
* Parameter pHdlList must point to an array of length \ref PLXPC_PLXS_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpcPlxsDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length \ref PLXPC_PLXS_HDL_LIST_LEN.
|
||||
* If the ATT handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if handle is found, \ref ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t PlxpcPlxsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a command to the pulse oximeter service record access control point.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param opcode Command opcode.
|
||||
* \param oper Command operator or 0 if no operator required.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpcPlxsRacpSend(dmConnId_t connId, uint16_t handle, uint8_t opcode, uint8_t oper);
|
||||
|
||||
|
||||
/*! \} */ /* PULSE_OXIMETER_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* PLXPC_API_H */
|
||||
+546
@@ -0,0 +1,546 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Pulse Oximeter profile collector.
|
||||
*
|
||||
* 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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_ch.h"
|
||||
#include "app_api.h"
|
||||
#include "plxpc_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Length of response data contained in a received RACP message */
|
||||
#define PLXPC_PLX_RACP_RSP_LEN 4
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*!
|
||||
* Pulse Oximeter service characteristics for discovery
|
||||
*/
|
||||
|
||||
/*! Pulse Oximeter spot check measurement */
|
||||
static const attcDiscChar_t plxpcPlxsPlxsc =
|
||||
{
|
||||
attPlxscmChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Pulse Oximeter spot check measurement CCC descriptor */
|
||||
static const attcDiscChar_t plxpcPlxsPlxscCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Pulse Oximeter continuous measurement */
|
||||
static const attcDiscChar_t plxpcPlxsPlxc =
|
||||
{
|
||||
attPlxcmChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Pulse Oximeter continuous measurement CCC descriptor */
|
||||
static const attcDiscChar_t plxpcPlxsPlxcCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Pulse Oximeter features */
|
||||
static const attcDiscChar_t plxpcPlxsPlxf =
|
||||
{
|
||||
attPlxfChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Record access control point */
|
||||
static const attcDiscChar_t plxpcPlxsRacp =
|
||||
{
|
||||
attRacpChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Record access control point CCC descriptor */
|
||||
static const attcDiscChar_t plxpcPlxsRacpCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *plxpcPlxsDiscCharList[] =
|
||||
{
|
||||
&plxpcPlxsPlxsc, /*! Pulse Oximeter measurement */
|
||||
&plxpcPlxsPlxscCcc, /*! Pulse Oximeter measurement CCC descriptor */
|
||||
&plxpcPlxsPlxc, /*! Pulse Oximeter measurement context */
|
||||
&plxpcPlxsPlxcCcc, /*! Pulse Oximeter measurement context CCC descriptor */
|
||||
&plxpcPlxsPlxf, /*! Pulse Oximeter feature */
|
||||
&plxpcPlxsRacp, /*! Record access control point */
|
||||
&plxpcPlxsRacpCcc /*! Record access control point CCC descriptor */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(PLXPC_PLXS_HDL_LIST_LEN == ((sizeof(plxpcPlxsDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Parse a pulse oximeter spot check measurement.
|
||||
*
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpcPlxsParsePlxsc(uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
uint8_t flags;
|
||||
uint16_t year;
|
||||
uint8_t month, day, hour, min, sec;
|
||||
int16_t mantissa;
|
||||
int8_t exponent;
|
||||
uint16_t spo2;
|
||||
uint16_t pulse;
|
||||
uint32_t sensorStatus;
|
||||
uint16_t measurementStatus;
|
||||
uint16_t pulseAmpIndex;
|
||||
uint16_t minLen = CH_PLX_FLAGS_LEN + CH_PLX_SPO2_LEN + CH_PLX_PULSE_LEN;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)measurementStatus; (void)sensorStatus; (void)exponent; (void)mantissa;
|
||||
(void)year; (void)month; (void)day; (void)hour; (void)min; (void)sec;
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
/* get flags */
|
||||
BSTREAM_TO_UINT8(flags, pValue);
|
||||
|
||||
/* determine expected minimum length based on flags */
|
||||
if (flags & CH_PLXSC_FLAG_TIMESTAMP)
|
||||
{
|
||||
minLen += CH_PLXSC_TIMESTAMP_LEN;
|
||||
}
|
||||
if (flags & CH_PLXSC_FLAG_MEASUREMENT_STATUS)
|
||||
{
|
||||
minLen += CH_PLX_MEASUREMENT_STATUS_LEN;
|
||||
}
|
||||
if (flags & CH_PLXSC_FLAG_SENSOR_STATUS)
|
||||
{
|
||||
minLen += CH_PLX_SENSOR_STATUS_LEN;
|
||||
}
|
||||
if (flags & CH_PLXSC_FLAG_PULSE_AMP_INDX)
|
||||
{
|
||||
minLen += CH_PLX_PULSE_AMP_INDX_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
/* verify length */
|
||||
if (len < minLen)
|
||||
{
|
||||
APP_TRACE_INFO2("Pulse Oximeter meas len:%d minLen:%d", len, minLen);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get SpO2 */
|
||||
BSTREAM_TO_UINT16(spo2, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, spo2);
|
||||
APP_TRACE_INFO2(" Pulse Oximeter SpO2: %de%d", mantissa, exponent);
|
||||
|
||||
/* get pulse */
|
||||
BSTREAM_TO_UINT16(pulse, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, pulse);
|
||||
APP_TRACE_INFO2(" Pulse Oximeter Pulse: %de%d", mantissa, exponent);
|
||||
|
||||
/* timestamp */
|
||||
if (flags & CH_PLXSC_FLAG_TIMESTAMP)
|
||||
{
|
||||
/* base time */
|
||||
BSTREAM_TO_UINT16(year, pValue);
|
||||
BSTREAM_TO_UINT8(month, pValue);
|
||||
BSTREAM_TO_UINT8(day, pValue);
|
||||
BSTREAM_TO_UINT8(hour, pValue);
|
||||
BSTREAM_TO_UINT8(min, pValue);
|
||||
BSTREAM_TO_UINT8(sec, pValue);
|
||||
APP_TRACE_INFO3(" Date: %d/%d/%d", month, day, year);
|
||||
APP_TRACE_INFO3(" Time: %02d:%02d:%02d", hour, min, sec);
|
||||
}
|
||||
|
||||
/* measurement status */
|
||||
if (flags & CH_PLXSC_FLAG_MEASUREMENT_STATUS)
|
||||
{
|
||||
BSTREAM_TO_UINT16(measurementStatus, pValue);
|
||||
APP_TRACE_INFO1(" Pulse Oximeter measurement status: 0x%04", measurementStatus);
|
||||
}
|
||||
|
||||
/* sensor status */
|
||||
if (flags & CH_PLXSC_FLAG_SENSOR_STATUS)
|
||||
{
|
||||
BSTREAM_TO_UINT24(sensorStatus, pValue);
|
||||
APP_TRACE_INFO1(" Pulse Oximeter Sensor status: 0x%04x", sensorStatus);
|
||||
}
|
||||
|
||||
/* Pulse amplitde index */
|
||||
if (flags & CH_PLXSC_FLAG_PULSE_AMP_INDX)
|
||||
{
|
||||
BSTREAM_TO_UINT16(pulseAmpIndex, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, pulseAmpIndex);
|
||||
APP_TRACE_INFO2(" Pulse Oximeter Pulse Amplitude Index: %de%d", mantissa, exponent);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Parse a pulse oximeter continuous measurement.
|
||||
*
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpcPlxsParsePlxc(uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
uint8_t flags;
|
||||
int16_t mantissa;
|
||||
int8_t exponent;
|
||||
uint16_t spo2;
|
||||
uint16_t pulse;
|
||||
uint32_t sensorStatus;
|
||||
uint16_t measurementStatus;
|
||||
uint16_t pulseAmpIndex;
|
||||
uint16_t minLen = CH_PLX_FLAGS_LEN + CH_PLX_SPO2_LEN + CH_PLX_PULSE_LEN;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)measurementStatus; (void)sensorStatus; (void)exponent; (void)mantissa;
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
/* get flags */
|
||||
BSTREAM_TO_UINT8(flags, pValue);
|
||||
|
||||
/* determine expected minimum length based on flags */
|
||||
if (flags & CH_PLXC_FLAG_SPO2PR_FAST)
|
||||
{
|
||||
minLen += CH_PLXC_SPO2PR_FAST_LEN;
|
||||
}
|
||||
if (flags & CH_PLXC_FLAG_SPO2PR_SLOW)
|
||||
{
|
||||
minLen += CH_PLXC_SPO2PR_SLOW_LEN;
|
||||
}
|
||||
if (flags & CH_PLXC_FLAG_MEASUREMENT_STATUS)
|
||||
{
|
||||
minLen += CH_PLX_MEASUREMENT_STATUS_LEN;
|
||||
}
|
||||
if (flags & CH_PLXC_FLAG_SENSOR_STATUS)
|
||||
{
|
||||
minLen += CH_PLX_SENSOR_STATUS_LEN;
|
||||
}
|
||||
if (flags & CH_PLXC_FLAG_PULSE_AMP_INDX)
|
||||
{
|
||||
minLen += CH_PLX_PULSE_AMP_INDX_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
/* verify length */
|
||||
if (len < minLen)
|
||||
{
|
||||
APP_TRACE_INFO2("Pulse Oximeter meas len:%d minLen:%d", len, minLen);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get SpO2 */
|
||||
BSTREAM_TO_UINT16(spo2, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, spo2);
|
||||
APP_TRACE_INFO2(" Pulse Oximeter SpO2: %de%d", mantissa, exponent);
|
||||
|
||||
/* get pulse */
|
||||
BSTREAM_TO_UINT16(pulse, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, pulse);
|
||||
APP_TRACE_INFO2(" Pulse Oximeter Pulse: %de%d", mantissa, exponent);
|
||||
|
||||
/* SpO2PR-Fast */
|
||||
if (flags & CH_PLXC_FLAG_SPO2PR_FAST)
|
||||
{
|
||||
/* get SpO2 */
|
||||
BSTREAM_TO_UINT16(spo2, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, spo2);
|
||||
APP_TRACE_INFO2(" Pulse Oximeter SpO2-Fast: %de%d", mantissa, exponent);
|
||||
|
||||
/* get pulse */
|
||||
BSTREAM_TO_UINT16(pulse, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, pulse);
|
||||
APP_TRACE_INFO2(" Pulse Oximeter Pulse-Fast: %de%d", mantissa, exponent);
|
||||
}
|
||||
|
||||
/* SpO2PR-Slow */
|
||||
if (flags & CH_PLXC_FLAG_SPO2PR_SLOW)
|
||||
{
|
||||
/* get SpO2 */
|
||||
BSTREAM_TO_UINT16(spo2, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, spo2);
|
||||
APP_TRACE_INFO2(" Pulse Oximeter SpO2-Slow: %de%d", mantissa, exponent);
|
||||
|
||||
/* get pulse */
|
||||
BSTREAM_TO_UINT16(pulse, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, pulse);
|
||||
APP_TRACE_INFO2(" Pulse Oximeter Pulse-Slow: %de%d", mantissa, exponent);
|
||||
}
|
||||
|
||||
/* measurement status */
|
||||
if (flags & CH_PLXC_FLAG_MEASUREMENT_STATUS)
|
||||
{
|
||||
BSTREAM_TO_UINT16(measurementStatus, pValue);
|
||||
APP_TRACE_INFO1(" Pulse Oximeter measurement status: 0x%04", measurementStatus);
|
||||
}
|
||||
|
||||
/* sensor status */
|
||||
if (flags & CH_PLXC_FLAG_SENSOR_STATUS)
|
||||
{
|
||||
BSTREAM_TO_UINT24(sensorStatus, pValue);
|
||||
APP_TRACE_INFO1(" Pulse Oximeter Sensor status: 0x%04x", sensorStatus);
|
||||
}
|
||||
|
||||
/* Pulse amplitde index */
|
||||
if (flags & CH_PLXC_FLAG_PULSE_AMP_INDX)
|
||||
{
|
||||
BSTREAM_TO_UINT16(pulseAmpIndex, pValue);
|
||||
UINT16_TO_SFLT(mantissa, exponent, pulseAmpIndex);
|
||||
APP_TRACE_INFO2(" Pulse Oximeter Pulse Amplitude Index: %de%d", mantissa, exponent);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a message received from the sensor on the record access control point.
|
||||
*
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpcPlxsProcRacp(uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint16_t numRecords;
|
||||
uint16_t reqOpcode;
|
||||
uint16_t status;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)status; (void)reqOpcode; (void)numRecords;
|
||||
|
||||
/* verify length */
|
||||
if (len != PLXPC_PLX_RACP_RSP_LEN)
|
||||
{
|
||||
APP_TRACE_INFO1("Unexpected RACP message length: %d", len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse message */
|
||||
BSTREAM_TO_UINT8(opcode, pValue);
|
||||
|
||||
/* Operator unused */
|
||||
pValue++;
|
||||
|
||||
if (opcode == CH_RACP_OPCODE_NUM_RSP)
|
||||
{
|
||||
BSTREAM_TO_UINT16(numRecords, pValue);
|
||||
APP_TRACE_INFO1("Number of records: %d", numRecords);
|
||||
}
|
||||
else if (opcode == CH_RACP_OPCODE_RSP)
|
||||
{
|
||||
BSTREAM_TO_UINT8(reqOpcode, pValue);
|
||||
BSTREAM_TO_UINT8(status, pValue);
|
||||
APP_TRACE_INFO2("Response opcode: %d status: %d", reqOpcode, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Parse a pulse oximeter features.
|
||||
*
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpcPlxParsePlxf(uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
int16_t features;
|
||||
int16_t measStatusSupport;
|
||||
int16_t sensorStatusSupport;
|
||||
|
||||
uint16_t minLen = CH_PLXF_MIN_FEATURES_LEN;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)measStatusSupport; (void)sensorStatusSupport;
|
||||
|
||||
if (len >= minLen)
|
||||
{
|
||||
/* get flags */
|
||||
BSTREAM_TO_UINT16(features, pValue);
|
||||
|
||||
/* determine expected minimum length based on features */
|
||||
if (features & CH_PLF_FLAG_MEAS_STATUS_SUP)
|
||||
{
|
||||
minLen += CH_PLXF_SENSOR_SUPPORT_LEN;
|
||||
}
|
||||
|
||||
if (features & CH_PLF_FLAG_SENSOR_STATUS_SUP)
|
||||
{
|
||||
minLen += CH_PLXF_MEASUREMENT_SUPPORT_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
/* verify length */
|
||||
if (len < minLen)
|
||||
{
|
||||
APP_TRACE_INFO2("Pulse Oximeter feature len:%d minLen:%d", len, minLen);
|
||||
return;
|
||||
}
|
||||
|
||||
/* SpO2PR-Fast */
|
||||
if (features & CH_PLF_FLAG_MEAS_STATUS_SUP)
|
||||
{
|
||||
/* get Measurement Status Support */
|
||||
BSTREAM_TO_UINT16(measStatusSupport, pValue);
|
||||
APP_TRACE_INFO1(" Pulse Oximeter measurement status sypported: 0x%04", measStatusSupport);
|
||||
}
|
||||
|
||||
/* SpO2PR-Slow */
|
||||
if (features & CH_PLF_FLAG_SENSOR_STATUS_SUP)
|
||||
{
|
||||
/* get Device and Sensor Status Support */
|
||||
BSTREAM_TO_UINT16(sensorStatusSupport, pValue);
|
||||
APP_TRACE_INFO1(" Pulse Oximeter sensor status supported: 0x%04", sensorStatusSupport);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Pulse Oximeter service. Parameter
|
||||
* pHdlList must point to an array of length PLXPC_PLXS_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpcPlxsDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attPlxsSvcUuid,
|
||||
PLXPC_PLXS_HDL_LIST_LEN, (attcDiscChar_t **) plxpcPlxsDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length PLXPC_PLXS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t PlxpcPlxsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
|
||||
/* spot check measurement */
|
||||
if (pMsg->handle == pHdlList[PLXPC_PLXS_PLXSC_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO0("Pulse Oximeter spot check measurement.");
|
||||
|
||||
/* parse value */
|
||||
plxpcPlxsParsePlxsc(pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
/* continuous measurement */
|
||||
else if (pMsg->handle == pHdlList[PLXPC_PLXS_PLXC_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO0("Pulse Oximeter continuous measurement");
|
||||
|
||||
/* parse value */
|
||||
plxpcPlxsParsePlxc(pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
/* record access control point */
|
||||
else if (pMsg->handle == pHdlList[PLXPC_PLXS_RACP_HDL_IDX])
|
||||
{
|
||||
plxpcPlxsProcRacp(pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
/* pulse oximeter feature */
|
||||
else if (pMsg->handle == pHdlList[PLXPC_PLXS_PLXF_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO0("Pulse Oximeter features");
|
||||
|
||||
/* parse value */
|
||||
plxpcPlxParsePlxf(pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a command to the pulse oximeter service record access control point.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param opcode Command opcode.
|
||||
* \param oper Command operator or 0 if no operator required.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpcPlxsRacpSend(dmConnId_t connId, uint16_t handle, uint8_t opcode, uint8_t oper)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t *p = buf;
|
||||
|
||||
if (handle != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* build RACP command */
|
||||
UINT8_TO_BSTREAM(p, opcode);
|
||||
UINT8_TO_BSTREAM(p, oper);
|
||||
|
||||
AttcWriteReq(connId, handle, (uint16_t) (p - buf), buf);
|
||||
}
|
||||
}
|
||||
ambiq-hal-sys/ambiq-sparkfun-sdk/third_party/exactle/ble-profiles/sources/profiles/plxps/plxps_api.h
Vendored
+185
@@ -0,0 +1,185 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Pulse Oximeter profile sensor.
|
||||
*
|
||||
* 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 PLXPS_API_H
|
||||
#define PLXPS_API_H
|
||||
|
||||
#include "app_hw.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup PULSE_OXIMETER_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Configurable parameters */
|
||||
typedef struct
|
||||
{
|
||||
wsfTimerTicks_t period; /*!< \brief Continuous Measurement timer expiration period in ms */
|
||||
} plxpsCfg_t;
|
||||
|
||||
/*! \brief Pulse Oximeter continuous measurement structure */
|
||||
typedef appPlxCm_t plxpCm_t;
|
||||
|
||||
/*! \brief Pulse Oximeter spot check measurement structure */
|
||||
typedef appPlxScm_t plxpScm_t;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the Pulse Oximeter profile sensor.
|
||||
*
|
||||
* \param handlerId DM connection identifier.
|
||||
* \param pCfg Configuration parameters.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsInit(wsfHandlerId_t handlerId, plxpsCfg_t *pCfg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application when a message that requires
|
||||
* processing by the pulse oximeter profile sensor is received.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsProcMsg(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a button press.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param btn Button press.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsBtn(dmConnId_t connId, uint8_t btn);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for pulse oximeter service.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param handle ATT handle.
|
||||
* \param operation ATT operation.
|
||||
* \param offset Write offset.
|
||||
* \param len Write length.
|
||||
* \param pValue Value to write.
|
||||
* \param pAttr Attribute to write.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t PlxpsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the supported features of the pulse oximeter sensor.
|
||||
*
|
||||
* \param feature Feature bitmask.
|
||||
* \param measStatus Measurement status.
|
||||
* \param sensorStatus Sensor status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsSetFeature(uint16_t feature, uint16_t measStatus, uint32_t sensorStatus);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the CCCD index used by the application for pulse oximeter service characteristics.
|
||||
*
|
||||
* \param plxscCccIdx Pulse Oximeter spot check CCCD index.
|
||||
* \param plxcCccIdx Pulse Oximeter continuous CCCD index.
|
||||
* \param racpCccIdx Record access control point CCCD index.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsSetCccIdx(uint8_t plxscCccIdx, uint8_t plxcCccIdx, uint8_t racpCccIdx);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start periodic pulse oximeter measurement. This function starts a timer to perform
|
||||
* periodic measurements.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param timerEvt WSF event designated by the application for the timer.
|
||||
* \param plxmCccIdx Index of pulse oximeter CCC descriptor in CCC descriptor handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsMeasStart(dmConnId_t connId, uint8_t timerEvt, uint8_t plxmCccIdx);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop periodic pulse oximeter measurement.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsMeasStop(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a spot check measurement indication.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param pMeas Pointer to pulse oximeter spot check measurement.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpsSendSpotCheckMeas(dmConnId_t connId, plxpScm_t *pMeas);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a Continuous measurement notification.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param pMeas Pointer to Pulse Oximiter continuous measurement.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpsSendContinuousMeas(dmConnId_t connId, plxpCm_t *pMeas);
|
||||
|
||||
/*! \} */ /* PULSE_OXIMETER_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* PLXPS_API_H */
|
||||
Vendored
+261
@@ -0,0 +1,261 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Pulse Oximeter profile example record database and access functions.
|
||||
*
|
||||
* 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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "svc_ch.h"
|
||||
#include "svc_gls.h"
|
||||
#include "app_api.h"
|
||||
#include "plxps_api.h"
|
||||
#include "plxps_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Number of records in example database */
|
||||
#define PLXPS_DB_NUM_RECORDS 3
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Control block */
|
||||
static struct
|
||||
{
|
||||
uint8_t numRec;
|
||||
} plxpsDbCb;
|
||||
|
||||
/*! Example record database */
|
||||
static const plxpsRec_t plxpsDb[PLXPS_DB_NUM_RECORDS] =
|
||||
{
|
||||
/* record 1 */
|
||||
{
|
||||
/* spotCheck */
|
||||
{
|
||||
0, /* Flags */
|
||||
SFLT_TO_UINT16(96, 1), /* Pulse Oximeter Spo2 (SFLOAT) */
|
||||
SFLT_TO_UINT16(60, 1), /* Pulse Oximeter Pulse (SFLOAT) */
|
||||
{2012, 6, 15, 20, 52, 36}, /* timestamp */
|
||||
0, /* Measurement status */
|
||||
0, /* Sensor status */
|
||||
SFLT_TO_UINT16(96, 1), /* Pulse Amplitude Index */
|
||||
}
|
||||
},
|
||||
|
||||
/* record 2 */
|
||||
{
|
||||
/* spotCheck */
|
||||
{
|
||||
0, /* Flags */
|
||||
SFLT_TO_UINT16(96, 1), /* Pulse Oximeter Spo2 (SFLOAT) */
|
||||
SFLT_TO_UINT16(60, 1), /* Pulse Oximeter Pulse (SFLOAT) */
|
||||
{2012, 6, 15, 20, 52, 36}, /* timestamp */
|
||||
0, /* Measurement status */
|
||||
0, /* Sensor status */
|
||||
SFLT_TO_UINT16(96, 1), /* Pulse Amplitude Index */
|
||||
}
|
||||
},
|
||||
/* record 3 */
|
||||
{
|
||||
/* spotCheck */
|
||||
{
|
||||
0, /* Flags */
|
||||
SFLT_TO_UINT16(96, 1), /* Pulse Oximeter Spo2 (SFLOAT) */
|
||||
SFLT_TO_UINT16(60, 1), /* Pulse Oximeter Pulse (SFLOAT) */
|
||||
{2012, 6, 15, 20, 52, 36}, /* timestamp */
|
||||
0, /* Measurement status */
|
||||
0, /* Sensor status */
|
||||
SFLT_TO_UINT16(96, 1), /* Pulse Amplitude Index */
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next database record after the given current record.
|
||||
*
|
||||
* \param pCurrRec Pointer to current record.
|
||||
*
|
||||
* \return Pointer to record or NULL if no record.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static const plxpsRec_t *plxpsDbGetEnd()
|
||||
{
|
||||
return plxpsDb + plxpsDbCb.numRec;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next database record after the given current record.
|
||||
*
|
||||
* \param pCurrRec Pointer to current record.
|
||||
*
|
||||
* \return Pointer to record or NULL if no record.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static plxpsRec_t *plxpsDbGetNext(plxpsRec_t *pCurrRec)
|
||||
{
|
||||
if (plxpsDbCb.numRec == 0 || pCurrRec == plxpsDbGetEnd())
|
||||
{
|
||||
plxpsDbCb.numRec = 0;
|
||||
return NULL;
|
||||
}
|
||||
else if (pCurrRec == NULL)
|
||||
{
|
||||
return (plxpsRec_t *) plxpsDb;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (pCurrRec + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next record filtered for "all".
|
||||
*
|
||||
* \param pCurrRec Pointer to current record.
|
||||
* \param pRec Return pointer to next record, if found.
|
||||
*
|
||||
* \return CH_RACP_RSP_SUCCESS if a record is found, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t plxpsDbOpAll(plxpsRec_t *pCurrRec, plxpsRec_t **pRec)
|
||||
{
|
||||
*pRec = plxpsDbGetNext(pCurrRec);
|
||||
return (*pRec != NULL) ? CH_RACP_RSP_SUCCESS : CH_RACP_RSP_NO_RECORDS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the pulse oximeter record database.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpsDbInit(void)
|
||||
{
|
||||
plxpsDbCb.numRec = PLXPS_DB_NUM_RECORDS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next record that matches the given filter parameters that follows
|
||||
* the given current record.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pCurrRec Pointer to current record.
|
||||
* \param pRec Return pointer to next record, if found.
|
||||
*
|
||||
* \return CH_RACP_RSP_SUCCESS if a record is found, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t plxpsDbGetNextRecord(uint8_t oper, plxpsRec_t *pCurrRec, plxpsRec_t **pRec)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
if (oper == CH_RACP_OPERATOR_ALL)
|
||||
{
|
||||
status = plxpsDbOpAll(pCurrRec, pRec);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = CH_RACP_RSP_INV_OPERATOR;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Delete records that match the given filter parameters.
|
||||
*
|
||||
* \param oper Operator.
|
||||
*
|
||||
* \return CH_RACP_RSP_SUCCESS if records deleted, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t plxpsDbDeleteRecords(uint8_t oper)
|
||||
{
|
||||
/* only 'all records' is supported */
|
||||
if (oper == CH_RACP_OPERATOR_ALL)
|
||||
{
|
||||
plxpsDbCb.numRec = 0;
|
||||
|
||||
return CH_RACP_RSP_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CH_RACP_RSP_INV_OPERATOR;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the number of records matching the filter parameters.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pNumRec Returns number of records which match filter parameters.
|
||||
|
||||
*
|
||||
* \return RACP status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t plxpsDbGetNumRecords(uint8_t oper, uint8_t *pNumRec)
|
||||
{
|
||||
plxpsRec_t *pCurrRec = NULL;
|
||||
uint8_t status;
|
||||
|
||||
*pNumRec = 0;
|
||||
while ((status = plxpsDbGetNextRecord(oper, pCurrRec, &pCurrRec)) == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
(*pNumRec)++;
|
||||
}
|
||||
|
||||
if (status == CH_RACP_RSP_NO_RECORDS)
|
||||
{
|
||||
status = CH_RACP_RSP_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate a new record.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpsDbGenerateRecord(void)
|
||||
{
|
||||
if (plxpsDbCb.numRec < PLXPS_DB_NUM_RECORDS)
|
||||
{
|
||||
plxpsDbCb.numRec++;
|
||||
}
|
||||
}
|
||||
+785
@@ -0,0 +1,785 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Pulse Oximeter profile sensor.
|
||||
*
|
||||
* 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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "svc_ch.h"
|
||||
#include "svc_plxs.h"
|
||||
#include "app_api.h"
|
||||
#include "app_ui.h"
|
||||
#include "plxps_api.h"
|
||||
#include "plxps_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
static struct
|
||||
{
|
||||
wsfTimer_t measTimer; /* continuous measurement timer */
|
||||
plxpsCfg_t *pCfg; /* configurable parameters */
|
||||
plxpsRec_t *pCurrRec; /* Pointer to current measurement record */
|
||||
plxpCm_t plxpsCm; /* Continuous measurement data */
|
||||
bool_t inProgress; /* TRUE if RACP procedure in progress */
|
||||
bool_t cmTxPending; /* TRUE if Continuous Measurement tx pending */
|
||||
bool_t txReady; /* TRUE if ready to send next notification or indication */
|
||||
bool_t aborting; /* TRUE if abort procedure in progress */
|
||||
uint8_t plxscCccIdx; /* Pulse Oximeter spot check measurement CCCD index */
|
||||
uint8_t plxcCccIdx; /* Pulse Oximeter continuous measurement CCCD index */
|
||||
uint8_t racpCccIdx; /* Record access control point CCCD index */
|
||||
} plxpsCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Build a spot check measurement characteristic.
|
||||
*
|
||||
* \param pBuf Pointer to buffer to hold the built characteristic.
|
||||
* \param pScm Pulse Oximeter spot check measurement values.
|
||||
*
|
||||
* \return Length of pBuf in bytes.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t plxpsBuildScm(uint8_t *pBuf, plxpScm_t *pScm)
|
||||
{
|
||||
uint8_t *p = pBuf;
|
||||
uint8_t flags = pScm->flags;
|
||||
|
||||
/* flags */
|
||||
UINT8_TO_BSTREAM(p, flags);
|
||||
|
||||
/* Manditory SpO2 */
|
||||
UINT16_TO_BSTREAM(p, pScm->spo2);
|
||||
|
||||
/* Manditory Pulse Rate */
|
||||
UINT16_TO_BSTREAM(p, pScm->pulseRate);
|
||||
|
||||
/* Timestamp */
|
||||
if (flags & CH_PLXSC_FLAG_TIMESTAMP)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pScm->timestamp.year);
|
||||
UINT8_TO_BSTREAM(p, pScm->timestamp.month);
|
||||
UINT8_TO_BSTREAM(p, pScm->timestamp.day);
|
||||
UINT8_TO_BSTREAM(p, pScm->timestamp.hour);
|
||||
UINT8_TO_BSTREAM(p, pScm->timestamp.min);
|
||||
UINT8_TO_BSTREAM(p, pScm->timestamp.sec);
|
||||
}
|
||||
|
||||
/* Measurement Status */
|
||||
if (flags & CH_PLXSC_FLAG_MEASUREMENT_STATUS)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pScm->measStatus);
|
||||
}
|
||||
|
||||
/* Device and Sensor Status */
|
||||
if (flags & CH_PLXSC_FLAG_SENSOR_STATUS)
|
||||
{
|
||||
UINT24_TO_BSTREAM(p, pScm->sensorStatus);
|
||||
}
|
||||
|
||||
/* Pulse Amplitude Index */
|
||||
if (flags & CH_PLXSC_FLAG_PULSE_AMP_INDX)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pScm->pulseAmpIndex);
|
||||
}
|
||||
|
||||
/* return length */
|
||||
return (uint8_t) (p - pBuf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Build a Continuous measurement characteristic.
|
||||
*
|
||||
* \param pBuf Pointer to buffer to hold the built characteristic.
|
||||
* \param pCm Pulse Oximeter continuous measurement values.
|
||||
*
|
||||
* \return Length of pBuf in bytes.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t plxpsBuildCm(uint8_t *pBuf, plxpCm_t *pCm)
|
||||
{
|
||||
uint8_t *p = pBuf;
|
||||
uint8_t flags = pCm->flags;
|
||||
|
||||
/* flags */
|
||||
UINT8_TO_BSTREAM(p, flags);
|
||||
|
||||
/* Manditory SpO2 */
|
||||
UINT16_TO_BSTREAM(p, pCm->spo2);
|
||||
|
||||
/* Manditory Pulse Rate */
|
||||
UINT16_TO_BSTREAM(p, pCm->pulseRate);
|
||||
|
||||
/* SpO2PR Fast */
|
||||
if (flags & CH_PLXC_FLAG_SPO2PR_FAST)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pCm->spo2Fast);
|
||||
UINT16_TO_BSTREAM(p, pCm->pulseRateFast);
|
||||
}
|
||||
|
||||
/* SpO2PR Slow */
|
||||
if (flags & CH_PLXC_FLAG_SPO2PR_SLOW)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pCm->spo2Slow);
|
||||
UINT16_TO_BSTREAM(p, pCm->pulseRateSlow);
|
||||
}
|
||||
|
||||
/* Measurement Status */
|
||||
if (flags & CH_PLXC_FLAG_MEASUREMENT_STATUS)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pCm->measStatus);
|
||||
}
|
||||
|
||||
/* Device and Sensor Status */
|
||||
if (flags & CH_PLXC_FLAG_SENSOR_STATUS)
|
||||
{
|
||||
UINT24_TO_BSTREAM(p, pCm->sensorStatus);
|
||||
}
|
||||
|
||||
/* Pulse Amplitude Index */
|
||||
if (flags & CH_PLXC_FLAG_PULSE_AMP_INDX)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pCm->pulseAmpIndex);
|
||||
}
|
||||
|
||||
|
||||
/* return length */
|
||||
return (uint8_t) (p - pBuf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a Continuous measurement notification.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param pMeas Pointer to Pulse Oximiter continuous measurement.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpsSendContinuousMeas(dmConnId_t connId, plxpCm_t *pMeas)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t len;
|
||||
|
||||
/* build continuous measurement characteristic */
|
||||
len = plxpsBuildCm(buf, pMeas);
|
||||
|
||||
/* send notification */
|
||||
AttsHandleValueNtf(connId, PLXS_CONTINUOUS_HDL, len, buf);
|
||||
plxpsCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a spot check measurement indication.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param pMeas Pointer to pulse oximeter spot check measurement.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpsSendSpotCheckMeas(dmConnId_t connId, plxpScm_t *pMeas)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t len;
|
||||
|
||||
/* build spot check measurement characteristic */
|
||||
len = plxpsBuildScm(buf, pMeas);
|
||||
|
||||
/* send indication */
|
||||
AttsHandleValueInd(connId, PLXS_SPOT_CHECK_HDL, len, buf);
|
||||
plxpsCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a RACP response indication.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param opcode RACP opcode.
|
||||
* \param status RACP status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpsRacpSendRsp(dmConnId_t connId, uint8_t opcode, uint8_t status)
|
||||
{
|
||||
uint8_t buf[PLXPS_RACP_RSP_LEN];
|
||||
|
||||
/* build response */
|
||||
buf[0] = CH_RACP_OPCODE_RSP;
|
||||
buf[1] = CH_RACP_OPERATOR_NULL;
|
||||
buf[2] = opcode;
|
||||
buf[3] = status;
|
||||
|
||||
/* send indication */
|
||||
AttsHandleValueInd(connId, PLXS_RECORD_ACCESS_HDL, PLXPS_RACP_RSP_LEN, buf);
|
||||
plxpsCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a RACP number of records response indication.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param numRec Number of records.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpsRacpSendNumRecRsp(dmConnId_t connId, uint16_t numRec)
|
||||
{
|
||||
uint8_t buf[PLXPS_RACP_NUM_REC_RSP_LEN];
|
||||
|
||||
/* build response */
|
||||
buf[0] = CH_RACP_OPCODE_NUM_RSP;
|
||||
buf[1] = CH_RACP_OPERATOR_NULL;
|
||||
buf[2] = UINT16_TO_BYTE0(numRec);
|
||||
buf[3] = UINT16_TO_BYTE1(numRec);
|
||||
|
||||
/* send indication */
|
||||
AttsHandleValueInd(connId, PLXS_RECORD_ACCESS_HDL, PLXPS_RACP_RSP_LEN, buf);
|
||||
plxpsCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle connection open.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void plxpsConnOpen(dmEvt_t *pMsg)
|
||||
{
|
||||
/* initialize */
|
||||
plxpsCb.pCurrRec = NULL;
|
||||
plxpsCb.aborting = FALSE;
|
||||
plxpsCb.inProgress = FALSE;
|
||||
plxpsCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle connection close.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void plxpsConnClose(dmEvt_t *pMsg)
|
||||
{
|
||||
plxpsCb.pCurrRec = NULL;
|
||||
plxpsCb.aborting = FALSE;
|
||||
|
||||
PlxpsMeasStop();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an ATT handle value confirm.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void plxpsHandleValueCnf(attEvt_t *pMsg)
|
||||
{
|
||||
dmConnId_t connId = (dmConnId_t) pMsg->hdr.param;
|
||||
plxpsCb.txReady = TRUE;
|
||||
|
||||
/* send continuous measurement if necessary */
|
||||
if (plxpsCb.cmTxPending == TRUE)
|
||||
{
|
||||
plxpsSendContinuousMeas((dmConnId_t) plxpsCb.measTimer.msg.param, &plxpsCb.plxpsCm);
|
||||
plxpsCb.txReady = FALSE;
|
||||
plxpsCb.cmTxPending = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* if aborting finish that up */
|
||||
if (plxpsCb.aborting)
|
||||
{
|
||||
plxpsCb.aborting = FALSE;
|
||||
plxpsRacpSendRsp(connId, CH_RACP_OPCODE_ABORT, CH_RACP_RSP_SUCCESS);
|
||||
}
|
||||
|
||||
/* if this is for RACP indication */
|
||||
if (pMsg->handle == PLXS_RECORD_ACCESS_HDL)
|
||||
{
|
||||
/* procedure no longer in progress */
|
||||
plxpsCb.inProgress = FALSE;
|
||||
}
|
||||
/* if this is for measurement or continuous notification */
|
||||
else if (pMsg->handle == PLXS_SPOT_CHECK_HDL || pMsg->handle == PLXS_CONTINUOUS_HDL)
|
||||
{
|
||||
if (plxpsCb.pCurrRec != NULL)
|
||||
{
|
||||
/* if there is another record */
|
||||
if (plxpsDbGetNextRecord(CH_RACP_OPERATOR_ALL, plxpsCb.pCurrRec, &plxpsCb.pCurrRec) == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
/* send measurement */
|
||||
plxpsSendSpotCheckMeas(connId, (plxpScm_t*) plxpsCb.pCurrRec);
|
||||
}
|
||||
/* else all records sent; send RACP response */
|
||||
else
|
||||
{
|
||||
plxpsRacpSendRsp(connId, CH_RACP_OPCODE_REPORT, CH_RACP_RSP_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a RACP report stored records operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param oper Operator.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void plxpsRacpReport(dmConnId_t connId, uint8_t oper)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
/* if record found */
|
||||
if ((status = plxpsDbGetNextRecord(oper, NULL, &plxpsCb.pCurrRec)) == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
/* send spot check measurement */
|
||||
plxpsSendSpotCheckMeas(connId, (plxpScm_t *) plxpsCb.pCurrRec);
|
||||
}
|
||||
/* if not successful send response */
|
||||
else
|
||||
{
|
||||
plxpsRacpSendRsp(connId, CH_RACP_OPCODE_REPORT, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a RACP delete records operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param oper Operator.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void plxpsRacpDelete(dmConnId_t connId, uint8_t oper)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
/* delete records */
|
||||
status = plxpsDbDeleteRecords(oper);
|
||||
|
||||
/* send response */
|
||||
plxpsRacpSendRsp(connId, CH_RACP_OPCODE_DELETE, status);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a RACP abort operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void plxpsRacpAbort(dmConnId_t connId)
|
||||
{
|
||||
/* if operation in progress */
|
||||
if (plxpsCb.inProgress)
|
||||
{
|
||||
/* abort operation and clean up */
|
||||
plxpsCb.pCurrRec = NULL;
|
||||
}
|
||||
|
||||
/* send response */
|
||||
if (plxpsCb.txReady)
|
||||
{
|
||||
plxpsRacpSendRsp(connId, CH_RACP_OPCODE_ABORT, CH_RACP_RSP_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
plxpsCb.aborting = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a RACP report number of stored records operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param oper Operator.
|
||||
* \param pOperand Operand data.
|
||||
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void plxpsRacpReportNum(dmConnId_t connId, uint8_t oper)
|
||||
{
|
||||
uint8_t status;
|
||||
uint8_t numRec;
|
||||
|
||||
/* get number of records */
|
||||
status = plxpsDbGetNumRecords(oper, &numRec);
|
||||
|
||||
if (status == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
/* send response */
|
||||
plxpsRacpSendNumRecRsp(connId, numRec);
|
||||
}
|
||||
else
|
||||
{
|
||||
plxpsRacpSendRsp(connId, CH_RACP_OPCODE_REPORT_NUM, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the Pulse Oximeter profile sensor.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsInit(wsfHandlerId_t handlerId, plxpsCfg_t *pCfg)
|
||||
{
|
||||
plxpsCb.measTimer.handlerId = handlerId;
|
||||
plxpsCb.pCfg = pCfg;
|
||||
plxpsDbInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application when the periodic measurement
|
||||
* timer expires.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpsMeasTimerExp(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
/* read pulse oximeter measurement data */
|
||||
AppHwPlxcmRead(&plxpsCb.plxpsCm);
|
||||
|
||||
plxpsCb.cmTxPending = TRUE;
|
||||
|
||||
/* if ready to send measurements */
|
||||
if (plxpsCb.txReady)
|
||||
{
|
||||
plxpsSendContinuousMeas((dmConnId_t) plxpsCb.measTimer.msg.param, &plxpsCb.plxpsCm);
|
||||
plxpsCb.txReady = FALSE;
|
||||
plxpsCb.cmTxPending = FALSE;
|
||||
}
|
||||
|
||||
/* restart timer */
|
||||
WsfTimerStartMs(&plxpsCb.measTimer, plxpsCb.pCfg->period);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application when a message that requires
|
||||
* processing by the pulse oximeter profile sensor is received.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsProcMsg(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
if (pMsg->event == plxpsCb.measTimer.msg.event)
|
||||
{
|
||||
plxpsMeasTimerExp(pMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(pMsg->event)
|
||||
{
|
||||
case DM_CONN_OPEN_IND:
|
||||
plxpsConnOpen((dmEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
case DM_CONN_CLOSE_IND:
|
||||
plxpsConnClose((dmEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
case ATTS_HANDLE_VALUE_CNF:
|
||||
plxpsHandleValueCnf((attEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a button press.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param btn Button press.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsBtn(dmConnId_t connId, uint8_t btn)
|
||||
{
|
||||
/* button actions when connected */
|
||||
if (connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
switch (btn)
|
||||
{
|
||||
case APP_UI_BTN_2_LONG:
|
||||
/* generate a new record */
|
||||
plxpsDbGenerateRecord();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* button actions when not connected */
|
||||
else
|
||||
{
|
||||
switch (btn)
|
||||
{
|
||||
case APP_UI_BTN_2_LONG:
|
||||
/* generate a new record */
|
||||
plxpsDbGenerateRecord();
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_EX_LONG:
|
||||
/* delete all records */
|
||||
plxpsDbDeleteRecords(CH_RACP_OPERATOR_ALL);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for pulse oximeter service record access control point. Use this
|
||||
* function as a parameter to SvcPlxCbackRegister().
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t PlxpsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t oprator;
|
||||
|
||||
/* sanity check on length */
|
||||
if (len < PLXPS_RACP_MIN_WRITE_LEN)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
/* if control point not configured for indication */
|
||||
if (!AttsCccEnabled(connId, plxpsCb.racpCccIdx))
|
||||
{
|
||||
return ATT_ERR_CCCD;
|
||||
}
|
||||
|
||||
/* parse opcode and operator and adjust remaining parameter length */
|
||||
BSTREAM_TO_UINT8(opcode, pValue);
|
||||
BSTREAM_TO_UINT8(oprator, pValue);
|
||||
len -= 2;
|
||||
|
||||
/* handle a procedure in progress */
|
||||
if (opcode != CH_RACP_OPCODE_ABORT && plxpsCb.inProgress)
|
||||
{
|
||||
return ATT_ERR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* handle record request when notifications not enabled */
|
||||
if (opcode == CH_RACP_OPCODE_REPORT && !AttsCccEnabled(connId, plxpsCb.plxscCccIdx))
|
||||
{
|
||||
return ATT_ERR_CCCD;
|
||||
}
|
||||
|
||||
/* verify opcode */
|
||||
if (opcode < CH_RACP_OPCODE_REPORT || opcode > CH_RACP_OPCODE_RSP)
|
||||
{
|
||||
plxpsRacpSendRsp(connId, opcode, CH_RACP_RSP_OPCODE_NOT_SUP);
|
||||
}
|
||||
|
||||
/* verify operator */
|
||||
if ((opcode != CH_RACP_OPCODE_ABORT && oprator != CH_RACP_OPERATOR_ALL) ||
|
||||
(opcode == CH_RACP_OPCODE_ABORT && oprator != CH_RACP_OPERATOR_NULL))
|
||||
{
|
||||
if (oprator > CH_RACP_OPERATOR_LAST)
|
||||
plxpsRacpSendRsp(connId, opcode, CH_RACP_RSP_OPERATOR_NOT_SUP);
|
||||
else
|
||||
plxpsRacpSendRsp(connId, opcode, CH_RACP_RSP_INV_OPERATOR);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/* verify operands */
|
||||
if (len > 0)
|
||||
{
|
||||
plxpsRacpSendRsp(connId, opcode, CH_RACP_RSP_INV_OPERAND);
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
/* report records */
|
||||
case CH_RACP_OPCODE_REPORT:
|
||||
plxpsRacpReport(connId, oprator);
|
||||
break;
|
||||
|
||||
/* delete records */
|
||||
case CH_RACP_OPCODE_DELETE:
|
||||
plxpsRacpDelete(connId, oprator);
|
||||
break;
|
||||
|
||||
/* abort current operation */
|
||||
case CH_RACP_OPCODE_ABORT:
|
||||
plxpsRacpAbort(connId);
|
||||
break;
|
||||
|
||||
/* report number of records */
|
||||
case CH_RACP_OPCODE_REPORT_NUM:
|
||||
plxpsRacpReportNum(connId, oprator);
|
||||
break;
|
||||
|
||||
/* unsupported opcode */
|
||||
default:
|
||||
plxpsRacpSendRsp(connId, opcode, CH_RACP_RSP_OPCODE_NOT_SUP);
|
||||
break;
|
||||
}
|
||||
|
||||
/* procedure now in progress */
|
||||
plxpsCb.inProgress = TRUE;
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the supported features of the pulse oximeter sensor.
|
||||
*
|
||||
* \param feature Feature bitmask.
|
||||
* \param measStatus Measurement status.
|
||||
* \param sensorStatus Sensor status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsSetFeature(uint16_t feature, uint16_t measStatus, uint32_t sensorStatus)
|
||||
{
|
||||
uint8_t buf[CH_PLXF_MAX_FEATURES_LEN];
|
||||
uint8_t *p = buf;
|
||||
|
||||
UINT16_TO_BSTREAM(p, feature);
|
||||
|
||||
if (feature & CH_PLF_FLAG_MEAS_STATUS_SUP)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, measStatus);
|
||||
}
|
||||
|
||||
if (feature & CH_PLF_FLAG_SENSOR_STATUS_SUP)
|
||||
{
|
||||
UINT24_TO_BSTREAM(p, sensorStatus);
|
||||
}
|
||||
|
||||
AttsSetAttr(PLXS_FEATURES_HDL, (uint16_t)(p - buf), buf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the CCCD index used by the application for pulse oximeter service characteristics.
|
||||
*
|
||||
* \param plxscCccIdx Pulse Oximeter spot check CCCD index.
|
||||
* \param plxcCccIdx Pulse Oximeter continuous CCCD index.
|
||||
* \param racpCccIdx Record access control point CCCD index.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsSetCccIdx(uint8_t plxscCccIdx, uint8_t plxcCccIdx, uint8_t racpCccIdx)
|
||||
{
|
||||
plxpsCb.plxscCccIdx = plxscCccIdx;
|
||||
plxpsCb.plxcCccIdx = plxcCccIdx;
|
||||
plxpsCb.racpCccIdx = racpCccIdx;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start periodic pulse oximeter measurement. This function starts a timer to perform
|
||||
* periodic measurements.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param timerEvt WSF event designated by the application for the timer.
|
||||
* \param plxmCccIdx Index of pulse oximeter CCC descriptor in CCC descriptor handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsMeasStart(dmConnId_t connId, uint8_t timerEvt, uint8_t plxmCccIdx)
|
||||
{
|
||||
/* initialize control block */
|
||||
plxpsCb.measTimer.msg.param = connId;
|
||||
plxpsCb.measTimer.msg.event = timerEvt;
|
||||
plxpsCb.measTimer.msg.status = plxmCccIdx;
|
||||
|
||||
/* start timer */
|
||||
WsfTimerStartMs(&plxpsCb.measTimer, plxpsCb.pCfg->period);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop periodic pulse oximeter measurement.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void PlxpsMeasStop(void)
|
||||
{
|
||||
WsfTimerStop(&plxpsCb.measTimer);
|
||||
}
|
||||
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Pulse Oximeter profile sensor internal interfaces.
|
||||
*
|
||||
* 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 PLXPS_MAIN_H
|
||||
#define PLXPS_MAIN_H
|
||||
|
||||
#include "app_hw.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup PULSE_OXIMETER_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Minimum RACP write length */
|
||||
#define PLXPS_RACP_MIN_WRITE_LEN 2
|
||||
|
||||
/*! \brief RACP response length */
|
||||
#define PLXPS_RACP_RSP_LEN 4
|
||||
|
||||
/*! \brief Pulse Oximeter RACP number of stored records response length */
|
||||
#define PLXPS_RACP_NUM_REC_RSP_LEN 4
|
||||
|
||||
/*! \brief RACP operand maximum length */
|
||||
#define PLXPS_OPERAND_MAX ((CH_RACP_GLS_FILTER_TIME_LEN * 2) + 1)
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Pulse Oximeter measurement record */
|
||||
typedef struct
|
||||
{
|
||||
plxpScm_t spotCheck; /*!< \brief Pulse Oximeter spot check measurement */
|
||||
} plxpsRec_t;
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the pulse oximeter record database.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpsDbInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next record that matches the given filter parameters that follows
|
||||
* the given current record.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pCurrRec Pointer to current record.
|
||||
* \param pRec Return pointer to next record, if found.
|
||||
*
|
||||
* \return \ref CH_RACP_RSP_SUCCESS if a record is found, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t plxpsDbGetNextRecord(uint8_t oper, plxpsRec_t *pCurrRec, plxpsRec_t **pRec);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Delete records that match the given filter parameters.
|
||||
*
|
||||
* \param oper Operator.
|
||||
*
|
||||
* \return \ref CH_RACP_RSP_SUCCESS if records deleted, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t plxpsDbDeleteRecords(uint8_t oper);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the number of records matching the filter parameters.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pNumRec Returns number of records which match filter parameters.
|
||||
|
||||
*
|
||||
* \return RACP status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t plxpsDbGetNumRecords(uint8_t oper, uint8_t *pNumRec);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate a new record.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void plxpsDbGenerateRecord(void);
|
||||
|
||||
|
||||
/*! \} */ /* PULSE_OXIMETER_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* PLXPS_MAIN_H */
|
||||
Vendored
+113
@@ -0,0 +1,113 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Running Speed and Cadence Profile API.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#ifndef RSCP_API_H
|
||||
#define RSCP_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup RUNNING_SPEED_AND_CADENCE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name Running Speed and Cadence Measurement Parameter Types
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define RSCP_SM_PARAM_SPEED 0 /*!< \brief Instantaneous Speed */
|
||||
#define RSCP_SM_PARAM_CADENCE 1 /*!< \brief Instantaneous Cadence */
|
||||
#define RSCP_SM_PARAM_STRIDE_LENGTH 2 /*!< \brief Instantaneous Stride Length */
|
||||
#define RSCP_SM_PARAM_TOTAL_DISTANCE 3 /*!< \brief Total Distance */
|
||||
#define RSCP_SM_PARAM_STATUS 4 /*!< \brief Walking or Running Status (0: walking, 1: running) */
|
||||
/**@}*/
|
||||
|
||||
/** \name Running Speed and Cadence Running Status Values
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define RSCP_SM_STATUS_WALKING 0 /*!< \brief Walking */
|
||||
#define RSCP_SM_STATUS_RUNNING 1 /*!< \brief Running */
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set a running speed measurement parameter.
|
||||
*
|
||||
* \param type Parameter identifier
|
||||
* \param value Measurement value.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void RscpsSetParameter(uint8_t type, uint32_t value);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the sensor location attribute.
|
||||
*
|
||||
* \param location Sensor Location.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void RscpsSetSensorLocation(uint8_t location);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the features attribute.
|
||||
*
|
||||
* \param features Features bitmask.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void RscpsSetFeatures(uint16_t features);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Notifies the collector of a Running Speed and Cadence Measurement.
|
||||
*
|
||||
* \param connId Connection ID
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void RscpsSendSpeedMeasurement(dmConnId_t connId);
|
||||
|
||||
/*! \} */ /* RUNNING_SPEED_AND_CADENCE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* RSCP_API_H */
|
||||
ambiq-hal-sys/ambiq-sparkfun-sdk/third_party/exactle/ble-profiles/sources/profiles/rscp/rscps_main.c
Vendored
+198
@@ -0,0 +1,198 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Running Speed and Cadence Profile Sensor Implementation.
|
||||
*
|
||||
* 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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "dm_api.h"
|
||||
#include "svc_rscs.h"
|
||||
#include "svc_ch.h"
|
||||
#include "rscp_api.h"
|
||||
|
||||
/*************************************************************************************************
|
||||
* Constant Definitions
|
||||
*************************************************************************************************/
|
||||
|
||||
/*! \brief The maximum length of a power measurement */
|
||||
#define RSCPS_PM_MAX_LEN 10
|
||||
|
||||
/*! \brief Running Speed Measurement Flag Indicies */
|
||||
enum
|
||||
{
|
||||
RSCPS_ISLP_FLAG_INDEX, /*! \brief Instantaneous Stride Length Present Present */
|
||||
RSCPS_TDP_FLAG_INDEX, /*! \brief Total Distance Present */
|
||||
RSCPS_WRS_FLAG_INDEX, /*! \brief Walking or Running Status bits */
|
||||
RSCPS_NUM_FLAGS
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Running Speed Measurement Data */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t flags; /*! \brief Speed Measurement Flags */
|
||||
uint16_t speed; /*! \brief Instantaneous Speed */
|
||||
uint8_t cadence; /*! \brief Instantaneous Cadence */
|
||||
uint16_t stride; /*! \brief Instantaneous Stride Length */
|
||||
uint32_t distance; /*! \brief Total Distance */
|
||||
} rscpSmData_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Measurement data */
|
||||
rscpSmData_t rscpSmData;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the sensor location attribute.
|
||||
*
|
||||
* \param location Sensor Location.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void RscpsSetSensorLocation(uint8_t location)
|
||||
{
|
||||
AttsSetAttr(RSCS_SL_HDL, sizeof(uint8_t), &location);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the features attribute.
|
||||
*
|
||||
* \param features Features bitmask.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void RscpsSetFeatures(uint16_t features)
|
||||
{
|
||||
uint8_t tempData[2] = {UINT16_TO_BYTES(features)};
|
||||
AttsSetAttr(RSCS_RSF_HDL, sizeof(tempData), tempData);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set a running speed measurement parameter.
|
||||
*
|
||||
* \param type Parameter identifier
|
||||
* \param value Measurement value.
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void RscpsSetParameter(uint8_t type, uint32_t value)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case RSCP_SM_PARAM_SPEED:
|
||||
rscpSmData.speed = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case RSCP_SM_PARAM_CADENCE:
|
||||
rscpSmData.cadence = (uint8_t) value;
|
||||
break;
|
||||
|
||||
case RSCP_SM_PARAM_STRIDE_LENGTH:
|
||||
rscpSmData.flags |= (1 << RSCPS_ISLP_FLAG_INDEX);
|
||||
rscpSmData.stride = (uint16_t) value;
|
||||
break;
|
||||
|
||||
case RSCP_SM_PARAM_TOTAL_DISTANCE:
|
||||
rscpSmData.flags |= (1 << RSCPS_TDP_FLAG_INDEX);
|
||||
rscpSmData.distance = value;
|
||||
break;
|
||||
|
||||
case RSCP_SM_PARAM_STATUS:
|
||||
if (value)
|
||||
{
|
||||
rscpSmData.flags |= (1 << RSCPS_WRS_FLAG_INDEX);
|
||||
}
|
||||
else
|
||||
{
|
||||
rscpSmData.flags &= ~(1 << RSCPS_WRS_FLAG_INDEX);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Notifies the collector of a Cycle Speed Measurement.
|
||||
*
|
||||
* \param connId Connection ID
|
||||
*
|
||||
* \return none
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void RscpsSendSpeedMeasurement(dmConnId_t connId)
|
||||
{
|
||||
int8_t i;
|
||||
uint16_t len;
|
||||
uint8_t msg[RSCPS_PM_MAX_LEN];
|
||||
uint8_t *p = msg;
|
||||
|
||||
/* Add manditory parameters */
|
||||
UINT8_TO_BSTREAM(p, rscpSmData.flags);
|
||||
UINT16_TO_BSTREAM(p, rscpSmData.speed);
|
||||
UINT8_TO_BSTREAM(p, rscpSmData.cadence);
|
||||
|
||||
/* Add optional parameters */
|
||||
for (i = 0; i < RSCPS_NUM_FLAGS; i++)
|
||||
{
|
||||
if (rscpSmData.flags & (1 << i))
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case RSCPS_ISLP_FLAG_INDEX:
|
||||
UINT16_TO_BSTREAM(p, rscpSmData.stride);
|
||||
break;
|
||||
case RSCPS_TDP_FLAG_INDEX:
|
||||
UINT32_TO_BSTREAM(p, rscpSmData.distance);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate message length */
|
||||
len = (uint16_t) (p - msg);
|
||||
|
||||
/* Transmit notification */
|
||||
AttsHandleValueNtf(connId, RSCS_RSM_HDL, len, msg);
|
||||
|
||||
/* Clear the measurement data */
|
||||
memset(&rscpSmData, 0, sizeof(rscpSmData));
|
||||
}
|
||||
ambiq-hal-sys/ambiq-sparkfun-sdk/third_party/exactle/ble-profiles/sources/profiles/scpps/scpps_api.h
Vendored
+79
@@ -0,0 +1,79 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Scan Parameter Profile Server Application Interface.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#ifndef SCPPS_API_H
|
||||
#define SCPPS_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup SCAN_PARAMETER_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Application interval window callback */
|
||||
typedef void ScppsAppCback_t(dmConnId_t connId, uint16_t interval, uint16_t window);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to register an application scan interval window callback function
|
||||
*
|
||||
* \param cback Application interval window callback
|
||||
*
|
||||
* \return Status
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void ScppsRegisterCback(ScppsAppCback_t *cback);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called when the peer writes to SCPPS attributes
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param handle ATT handle.
|
||||
* \param operation ATT operation.
|
||||
* \param offset Write offset.
|
||||
* \param len Write length.
|
||||
* \param pValue Value to write.
|
||||
* \param pAttr Attribute to write.
|
||||
*
|
||||
* \return Status
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t ScppsAttsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr);
|
||||
|
||||
/*! \} */ /* SCAN_PARAMETER_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* SCPPS_API_H */
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Scan Parameter Profile Server.
|
||||
*
|
||||
* 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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "app_api.h"
|
||||
#include "scpps_api.h"
|
||||
#include "svc_scpss.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
static ScppsAppCback_t *scppsAppCback;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called to register an application callback function
|
||||
*
|
||||
* \param cback Application interval window callback
|
||||
*
|
||||
* \return Status
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void ScppsRegisterCback(ScppsAppCback_t *cback)
|
||||
{
|
||||
scppsAppCback = cback;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called when the peer writes to SCPPS attributes
|
||||
*
|
||||
* \return Status
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t ScppsAttsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
|
||||
{
|
||||
if (scppsAppCback && handle == SCPSS_SIW_HDL)
|
||||
{
|
||||
uint16_t interval;
|
||||
uint16_t window;
|
||||
|
||||
BSTREAM_TO_UINT16(interval, pValue);
|
||||
BSTREAM_TO_UINT16(window, pValue);
|
||||
|
||||
/* Call the callback to the application layer */
|
||||
(*scppsAppCback)(connId, interval, window);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
ambiq-hal-sys/ambiq-sparkfun-sdk/third_party/exactle/ble-profiles/sources/profiles/sensor/gyro_api.h
Vendored
+97
@@ -0,0 +1,97 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Example gyroscope service profile.
|
||||
*
|
||||
* Copyright (c) 2015-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 GYRO_API_H
|
||||
#define GYRO_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup GYROSCOPE_SERVICE_PROFILE
|
||||
* \{ */
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_os.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start service.
|
||||
*
|
||||
* \param handlerId Handler ID.
|
||||
* \param timerEvt Timer message event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GyroStart(wsfHandlerId_t handlerId, uint8_t timerEvt);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop service.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GyroStop(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Measurement stop handler.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GyroMeasStop(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Measurement start handler.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GyroMeasStart(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Measurement complete handler.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param x Gyroscope x-axis reading.
|
||||
* \param y Gyroscope y-axis reading.
|
||||
* \param z Gyroscope z-axis reading.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GyroMeasComplete(dmConnId_t connId, int16_t x, int16_t y, int16_t z);
|
||||
|
||||
/*! \} */ /* GYROSCOPE_SERVICE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* GYRO_API_H */
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Example gyroscope service profile.
|
||||
*
|
||||
* Copyright (c) 2015-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 <stdlib.h>
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "app_api.h"
|
||||
#include "att_api.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
|
||||
#include "gyro_api.h"
|
||||
#include "svc_gyro.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Control block. */
|
||||
static struct
|
||||
{
|
||||
wsfTimer_t measTimer;
|
||||
bool_t measTimerStarted;
|
||||
} gyroCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Update measurement timer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void gyroUpdateTimer(void)
|
||||
{
|
||||
uint8_t config;
|
||||
uint8_t *pConfig = NULL;
|
||||
uint8_t period;
|
||||
uint8_t *pPeriod = NULL;
|
||||
uint16_t attLen = 0;
|
||||
|
||||
/* Get config & period. */
|
||||
AttsGetAttr(GYRO_HANDLE_CONFIG, &attLen, &pConfig);
|
||||
if (pConfig == NULL)
|
||||
{
|
||||
WSF_TRACE_ERR0("gyro: unable to read config");
|
||||
return;
|
||||
}
|
||||
config = *pConfig;
|
||||
AttsGetAttr(GYRO_HANDLE_PERIOD, &attLen, &pPeriod);
|
||||
if (pPeriod == NULL)
|
||||
{
|
||||
WSF_TRACE_ERR0("gyro: unable to read period");
|
||||
return;
|
||||
}
|
||||
period = *pPeriod;
|
||||
if (period < GYRO_ATT_PERIOD_MIN)
|
||||
{
|
||||
period = GYRO_ATT_PERIOD_MIN;
|
||||
}
|
||||
|
||||
if (config == GYRO_ATT_CONFIG_ENABLE)
|
||||
{
|
||||
if (!gyroCb.measTimerStarted)
|
||||
{
|
||||
gyroCb.measTimerStarted = TRUE;
|
||||
WsfTimerStartMs(&gyroCb.measTimer, period * 10u);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gyroCb.measTimerStarted)
|
||||
{
|
||||
gyroCb.measTimerStarted = FALSE;
|
||||
WsfTimerStop(&gyroCb.measTimer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for gyroscope profile.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t gyroWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue,
|
||||
attsAttr_t *pAttr)
|
||||
{
|
||||
switch (handle)
|
||||
{
|
||||
case GYRO_HANDLE_CONFIG:
|
||||
{
|
||||
uint8_t config;
|
||||
|
||||
/* Check attribute value. */
|
||||
if (len != 1)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
config = *pValue;
|
||||
if ((config != GYRO_ATT_CONFIG_DISABLE) && (config != GYRO_ATT_CONFIG_ENABLE))
|
||||
{
|
||||
return ATT_ERR_RANGE;
|
||||
}
|
||||
|
||||
/* Save value. */
|
||||
AttsSetAttr(GYRO_HANDLE_CONFIG, len, pValue);
|
||||
|
||||
/* Enable or disable timer. */
|
||||
gyroUpdateTimer();
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
case GYRO_HANDLE_PERIOD:
|
||||
{
|
||||
uint8_t period;
|
||||
|
||||
if (len != 1)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
period = *pValue;
|
||||
if ((period < GYRO_ATT_PERIOD_MIN) || (period > GYRO_ATT_PERIOD_MAX))
|
||||
{
|
||||
return ATT_ERR_RANGE;
|
||||
}
|
||||
AttsSetAttr(GYRO_HANDLE_PERIOD, len, pValue);
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
}
|
||||
return ATT_ERR_NOT_SUP;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start service.
|
||||
*
|
||||
* \param handlerId Handler ID.
|
||||
* \param timerEvt Timer message event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GyroStart(wsfHandlerId_t handlerId, uint8_t timerEvt)
|
||||
{
|
||||
SvcGyroAddGroup();
|
||||
SvcGyroCbackRegister(gyroWriteCback);
|
||||
|
||||
gyroCb.measTimer.handlerId = handlerId;
|
||||
gyroCb.measTimer.msg.event = timerEvt;
|
||||
gyroCb.measTimerStarted = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop service.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GyroStop(void)
|
||||
{
|
||||
gyroCb.measTimerStarted = FALSE;
|
||||
WsfTimerStop(&gyroCb.measTimer);
|
||||
|
||||
SvcGyroRemoveGroup();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Measurement stop handler.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GyroMeasStop(void)
|
||||
{
|
||||
gyroCb.measTimerStarted = FALSE;
|
||||
WsfTimerStop(&gyroCb.measTimer);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Measurement start handler.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GyroMeasStart(void)
|
||||
{
|
||||
gyroUpdateTimer();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Measurement complete handler.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param x Gyroscope x-axis reading.
|
||||
* \param y Gyroscope y-axis reading.
|
||||
* \param z Gyroscope z-axis reading.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GyroMeasComplete(dmConnId_t connId, int16_t x, int16_t y, int16_t z)
|
||||
{
|
||||
gyroCb.measTimerStarted = FALSE;
|
||||
|
||||
uint8_t gyroData[6] = {UINT16_TO_BYTES(x), UINT16_TO_BYTES(y), UINT16_TO_BYTES(z)};
|
||||
AttsSetAttr(GYRO_HANDLE_DATA, sizeof(gyroData), gyroData);
|
||||
AttsHandleValueNtf(connId, GYRO_HANDLE_DATA, sizeof(gyroData), gyroData);
|
||||
|
||||
gyroUpdateTimer();
|
||||
}
|
||||
ambiq-hal-sys/ambiq-sparkfun-sdk/third_party/exactle/ble-profiles/sources/profiles/sensor/temp_api.h
Vendored
+95
@@ -0,0 +1,95 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Example temperature service profile.
|
||||
*
|
||||
* Copyright (c) 2015-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 TEMP_API_H
|
||||
#define TEMP_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup TEMPERATURE_SERVICE_PROFILE
|
||||
* \{ */
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_os.h"
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start service.
|
||||
*
|
||||
* \param handlerId Handler ID.
|
||||
* \param timerEvt Timer message event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void TempStart(wsfHandlerId_t handlerId, uint8_t timerEvt);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop service.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void TempStop(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Measurement stop handler.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void TempMeasStop(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Measurement start handler.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void TempMeasStart(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Measurement complete handler.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param temp Temperature reading.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void TempMeasComplete(dmConnId_t connId, int16_t temp);
|
||||
|
||||
/*! \} */ /* TEMPERATURE_SERVICE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* TEMP_API_H */
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Example temperature service profile.
|
||||
*
|
||||
* Copyright (c) 2015-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 <stdlib.h>
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "app_api.h"
|
||||
#include "att_api.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
|
||||
#include "temp_api.h"
|
||||
#include "svc_temp.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Control block. */
|
||||
static struct
|
||||
{
|
||||
wsfTimer_t measTimer;
|
||||
bool_t measTimerStarted;
|
||||
} tempCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Update measurement timer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void tempUpdateTimer(void)
|
||||
{
|
||||
uint8_t config;
|
||||
uint8_t *pConfig = NULL;
|
||||
uint8_t period;
|
||||
uint8_t *pPeriod = NULL;
|
||||
uint16_t attLen = 0;
|
||||
|
||||
/* Get config & period. */
|
||||
AttsGetAttr(TEMP_HANDLE_CONFIG, &attLen, &pConfig);
|
||||
if (pConfig == NULL)
|
||||
{
|
||||
WSF_TRACE_ERR0("temp: unable to read config");
|
||||
return;
|
||||
}
|
||||
config = *pConfig;
|
||||
AttsGetAttr(TEMP_HANDLE_PERIOD, &attLen, &pPeriod);
|
||||
if (pPeriod == NULL)
|
||||
{
|
||||
WSF_TRACE_ERR0("temp: unable to read period");
|
||||
return;
|
||||
}
|
||||
period = *pPeriod;
|
||||
if (period < TEMP_ATT_PERIOD_MIN)
|
||||
{
|
||||
period = TEMP_ATT_PERIOD_MIN;
|
||||
}
|
||||
|
||||
if (config == TEMP_ATT_CONFIG_ENABLE)
|
||||
{
|
||||
if (!tempCb.measTimerStarted)
|
||||
{
|
||||
tempCb.measTimerStarted = TRUE;
|
||||
WsfTimerStartMs(&tempCb.measTimer, period * 10u);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tempCb.measTimerStarted)
|
||||
{
|
||||
tempCb.measTimerStarted = FALSE;
|
||||
WsfTimerStop(&tempCb.measTimer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for temperature profile.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t tempWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue,
|
||||
attsAttr_t *pAttr)
|
||||
{
|
||||
switch (handle)
|
||||
{
|
||||
case TEMP_HANDLE_CONFIG:
|
||||
{
|
||||
uint8_t config;
|
||||
|
||||
/* Check attribute value. */
|
||||
if (len != 1)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
config = *pValue;
|
||||
if ((config != TEMP_ATT_CONFIG_DISABLE) && (config != TEMP_ATT_CONFIG_ENABLE))
|
||||
{
|
||||
return ATT_ERR_RANGE;
|
||||
}
|
||||
|
||||
/* Save value. */
|
||||
AttsSetAttr(TEMP_HANDLE_CONFIG, len, pValue);
|
||||
|
||||
/* Enable or disable timer. */
|
||||
tempUpdateTimer();
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
case TEMP_HANDLE_PERIOD:
|
||||
{
|
||||
uint8_t period;
|
||||
|
||||
if (len != 1)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
period = *pValue;
|
||||
if ((period < TEMP_ATT_PERIOD_MIN) || (period > TEMP_ATT_PERIOD_MAX))
|
||||
{
|
||||
return ATT_ERR_RANGE;
|
||||
}
|
||||
AttsSetAttr(TEMP_HANDLE_PERIOD, len, pValue);
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
}
|
||||
return ATT_ERR_NOT_SUP;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start service.
|
||||
*
|
||||
* \param handlerId Handler ID.
|
||||
* \param timerEvt Timer message event.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void TempStart(wsfHandlerId_t handlerId, uint8_t timerEvt)
|
||||
{
|
||||
SvcTempAddGroup();
|
||||
SvcTempCbackRegister(tempWriteCback);
|
||||
|
||||
tempCb.measTimer.handlerId = handlerId;
|
||||
tempCb.measTimer.msg.event = timerEvt;
|
||||
tempCb.measTimerStarted = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop service.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void TempStop(void)
|
||||
{
|
||||
TempMeasStop();
|
||||
SvcTempRemoveGroup();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Measurement stop handler.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void TempMeasStop(void)
|
||||
{
|
||||
tempCb.measTimerStarted = FALSE;
|
||||
WsfTimerStop(&tempCb.measTimer);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Measurement start handler.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void TempMeasStart(void)
|
||||
{
|
||||
tempUpdateTimer();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Measurement complete handler.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param temp Temperature reading.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void TempMeasComplete(dmConnId_t connId, int16_t temp)
|
||||
{
|
||||
tempCb.measTimerStarted = FALSE;
|
||||
|
||||
uint8_t tempData[2] = {UINT16_TO_BYTES(temp)};
|
||||
AttsSetAttr(TEMP_HANDLE_DATA, sizeof(tempData), tempData);
|
||||
AttsHandleValueNtf(connId, TEMP_HANDLE_DATA, sizeof(tempData), tempData);
|
||||
|
||||
tempUpdateTimer();
|
||||
}
|
||||
Vendored
+90
@@ -0,0 +1,90 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Time profile client.
|
||||
*
|
||||
* Copyright (c) 2011-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 TIPC_API_H
|
||||
#define TIPC_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup TIME_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Current Time service enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
TIPC_CTS_CT_HDL_IDX, /*!< \brief Current time */
|
||||
TIPC_CTS_CT_CCC_HDL_IDX, /*!< \brief Current time client characteristic configuration descriptor */
|
||||
TIPC_CTS_LTI_HDL_IDX, /*!< \brief Local time information */
|
||||
TIPC_CTS_RTI_HDL_IDX, /*!< \brief Reference time information */
|
||||
TIPC_CTS_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Current Time service. Parameter
|
||||
* pHdlList must point to an array of length \ref TIPC_CTS_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void TipcCtsDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length \ref TIPC_CTS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if handle is found, \ref ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t TipcCtsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg);
|
||||
|
||||
/*! \} */ /* TIME_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* TIPC_API_H */
|
||||
Vendored
+176
@@ -0,0 +1,176 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Time profile client.
|
||||
*
|
||||
* Copyright (c) 2011-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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "app_api.h"
|
||||
#include "tipc_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*!
|
||||
* Current Time service
|
||||
*/
|
||||
|
||||
/* Characteristics for discovery */
|
||||
|
||||
/*! Current time */
|
||||
static const attcDiscChar_t tipcCtsCt =
|
||||
{
|
||||
attCtChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Current time client characteristic configuration descriptor */
|
||||
static const attcDiscChar_t tipcCtsCtCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Local time information */
|
||||
static const attcDiscChar_t tipcCtsLti =
|
||||
{
|
||||
attLtiChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Reference time information */
|
||||
static const attcDiscChar_t tipcCtsRti =
|
||||
{
|
||||
attRtiChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *tipcCtsDiscCharList[] =
|
||||
{
|
||||
&tipcCtsCt, /* Current time */
|
||||
&tipcCtsCtCcc, /* Current time client characteristic configuration descriptor */
|
||||
&tipcCtsLti, /* Local time information */
|
||||
&tipcCtsRti /* Reference time information */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(TIPC_CTS_HDL_LIST_LEN == ((sizeof(tipcCtsDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Current Time service. Parameter
|
||||
* pHdlList must point to an array of length TIPC_CTS_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void TipcCtsDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attCtsSvcUuid,
|
||||
TIPC_CTS_HDL_LIST_LEN, (attcDiscChar_t **) tipcCtsDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length TIPC_CTS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t TipcCtsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
uint8_t *p;
|
||||
uint16_t year;
|
||||
uint8_t month, day, hour, min, sec, sec256, dayOfWeek, adjustReason;
|
||||
int8_t timeZone;
|
||||
uint8_t dstOffset, source, accuracy;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)month; (void)day; (void)hour; (void)min; (void)sec; (void)dayOfWeek; (void)adjustReason;
|
||||
(void)year; (void)sec256; (void)dstOffset; (void)accuracy; (void)timeZone; (void)source;
|
||||
|
||||
/* current time */
|
||||
if (pMsg->handle == pHdlList[TIPC_CTS_CT_HDL_IDX])
|
||||
{
|
||||
/* parse value */
|
||||
p = pMsg->pValue;
|
||||
BSTREAM_TO_UINT16(year, p);
|
||||
BSTREAM_TO_UINT8(month, p);
|
||||
BSTREAM_TO_UINT8(day, p);
|
||||
BSTREAM_TO_UINT8(hour, p);
|
||||
BSTREAM_TO_UINT8(min, p);
|
||||
BSTREAM_TO_UINT8(sec, p);
|
||||
BSTREAM_TO_UINT8(dayOfWeek, p);
|
||||
BSTREAM_TO_UINT8(sec256, p);
|
||||
BSTREAM_TO_UINT8(adjustReason, p);
|
||||
|
||||
APP_TRACE_INFO3("Date: %d/%d/%d", month, day, year);
|
||||
APP_TRACE_INFO3("Time: %02d:%02d:%02d", hour, min, sec);
|
||||
APP_TRACE_INFO3("dayOfWeek:%d sec256:%d adjustReason:%d", dayOfWeek, sec256, adjustReason);
|
||||
}
|
||||
/* local time information */
|
||||
else if (pMsg->handle == pHdlList[TIPC_CTS_LTI_HDL_IDX])
|
||||
{
|
||||
/* parse value */
|
||||
p = pMsg->pValue;
|
||||
BSTREAM_TO_UINT8(timeZone, p);
|
||||
BSTREAM_TO_UINT8(dstOffset, p);
|
||||
|
||||
APP_TRACE_INFO2("timeZone:%d dstOffset:%d", timeZone, dstOffset);
|
||||
}
|
||||
/* reference time information */
|
||||
else if (pMsg->handle == pHdlList[TIPC_CTS_RTI_HDL_IDX])
|
||||
{
|
||||
/* parse value */
|
||||
p = pMsg->pValue;
|
||||
BSTREAM_TO_UINT8(source, p);
|
||||
BSTREAM_TO_UINT8(accuracy, p);
|
||||
BSTREAM_TO_UINT8(day, p);
|
||||
BSTREAM_TO_UINT8(hour, p);
|
||||
|
||||
APP_TRACE_INFO2("Ref. time source:%d accuracy:%d", source, accuracy);
|
||||
APP_TRACE_INFO2("Last update days:%d hours:%d", day, hour);
|
||||
}
|
||||
/* handle not found in list */
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
Vendored
+228
@@ -0,0 +1,228 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief User Data Service Collector.
|
||||
*
|
||||
* Copyright (c) 2017-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 UDSC_API_H
|
||||
#define UDSC_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup USER_DATA_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief UDSC service enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
UDSC_DBCI_HDL_IDX, /*!< \brief Database Change Interval */
|
||||
UDSC_DCBI_CCC_HDL_IDX, /*!< \brief Database Change Interval CCC descriptor */
|
||||
UDSC_UI_HDL_IDX, /*!< \brief User Index */
|
||||
UDSC_UCP_IDX, /*!< \brief User Control Point */
|
||||
UDSC_UCP_CCC_HDL_IDX, /*!< \brief User Control Point CCC descriptor */
|
||||
UDSC_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/** \name User Control Point Opcodes
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define UDSC_UCP_OPCODE_RNU 0x01 /*!< \brief Register New User */
|
||||
#define UDSC_UCP_OPCODE_CONSENT 0x02 /*!< \brief Consent */
|
||||
#define UDSC_UCP_OPCODE_DUD 0x03 /*!< \brief Delete User Data */
|
||||
#define UDSC_UCP_OPCODE_RESPONSE 0x20 /*!< \brief Command Response */
|
||||
/**@}*/
|
||||
|
||||
/** \name User Control Point Response Values
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define UDSC_UCP_RSP_SUCCESS 0x01 /*!< \brief Success */
|
||||
#define UDSC_UCP_RSP_OP_NOT_SUPPORTED 0x02 /*!< \brief Opcode not supported */
|
||||
#define UDSC_UCP_RSP_INVALID_PARAMETER 0x03 /*!< \brief Invalid Parameter */
|
||||
#define UDSC_UCP_RSP_OP_FAILED 0x04 /*!< \brief Operation Failed */
|
||||
#define UDSC_UCP_RSP_NOT_AUTHORIZED 0x05 /*!< \brief User Not Authorized */
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Callback Function Datatypes
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \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 \ref UDSC_UCP_OPCODE_RNU)
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
typedef void (*UdsRspCback_t)(dmConnId_t connId, uint8_t opcode, uint8_t response, uint8_t index);
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for User Data service. Parameter
|
||||
* pHdlList must point to an array of length \ref UDSC_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length \ref UDSC_HDL_LIST_LEN.
|
||||
* If the ATT handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if handle is found, \ref ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t UdscValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read the user index characteristic.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscReadUserIndex(dmConnId_t connId, uint16_t handle);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read the database change increment characteristic.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscReadDatabaseChangeIncrement(dmConnId_t connId, uint16_t handle);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write the database change increment characteristic.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param increment DB Change Increment
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscWriteDatabaseChangeIncrement(dmConnId_t connId, uint16_t handle, uint32_t increment);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the user control point characteristic - Register New User.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param consentCode Consent code (0-9999)
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscRegisterNewUser(dmConnId_t connId, uint16_t handle, uint16_t consentCode);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the user control point characteristic - Consent.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param index User Index
|
||||
* \param consentCode Consent code (0-9999 - provided when user was registered)
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscConsent(dmConnId_t connId, uint16_t handle, uint8_t index, uint16_t consentCode);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the user control point characteristic - Delete User Data.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscDeleteUserData(dmConnId_t connId, uint16_t handle);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by the application when a connection closes.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscClose(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize User Data Service collector callbacks.
|
||||
*
|
||||
* \param handlerId Application task handler ID.
|
||||
* \param timerEvent Application timer event for control point timeout.
|
||||
* \param rspCback Callback to receive control point response messages.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscInit(wsfHandlerId_t handlerId, uint8_t timerEvent, UdsRspCback_t rspCback);
|
||||
|
||||
/*! \} */ /* USER_DATA_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* UDSC_API_H */
|
||||
Vendored
+393
@@ -0,0 +1,393 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief User Data Service Collector.
|
||||
*
|
||||
* Copyright (c) 2017-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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_ch.h"
|
||||
#include "app_api.h"
|
||||
#include "udsc_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Time to wait for control point response in seconds */
|
||||
#define UDSC_RESPONSE_TIMEOUT 45
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
static struct
|
||||
{
|
||||
UdsRspCback_t rspCback; /* Control Point Response Callback */
|
||||
wsfTimer_t rspTimer;
|
||||
|
||||
} UdscCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*!
|
||||
* User data service characteristics for discovery
|
||||
*/
|
||||
|
||||
/*! Database change increment */
|
||||
static const attcDiscChar_t udscDbci =
|
||||
{
|
||||
attDbciChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! Database change increment CCC descriptor */
|
||||
static const attcDiscChar_t udscDcbiCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! User index */
|
||||
static const attcDiscChar_t udscUi =
|
||||
{
|
||||
attUiChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! User control point */
|
||||
static const attcDiscChar_t udscUcp =
|
||||
{
|
||||
attUcpChUuid,
|
||||
0
|
||||
};
|
||||
|
||||
/*! User control point CCC descriptor */
|
||||
static const attcDiscChar_t udscUcpCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *udscDiscCharList[] =
|
||||
{
|
||||
&udscDbci, /*! Database Change Increment */
|
||||
&udscDcbiCcc, /*! Database Change Interval CCC descriptor */
|
||||
&udscUi, /*! User Index */
|
||||
&udscUcp, /*! User control point */
|
||||
&udscUcpCcc, /*! User control point CCC descriptor */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(UDSC_HDL_LIST_LEN == ((sizeof(udscDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for User Data service. Parameter
|
||||
* pHdlList must point to an array of length UDSC_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attUdsSvcUuid,
|
||||
UDSC_HDL_LIST_LEN, (attcDiscChar_t **) udscDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Parse a User Control Point message.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void udscParseUcp(dmConnId_t connId, uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
uint8_t opcode;
|
||||
|
||||
BSTREAM_TO_INT8(opcode, pValue);
|
||||
|
||||
if (opcode == UDSC_UCP_OPCODE_RESPONSE)
|
||||
{
|
||||
/* Opcode is a response message */
|
||||
uint8_t responseOpcode;
|
||||
uint8_t response, index = 0;
|
||||
|
||||
BSTREAM_TO_INT8(responseOpcode, pValue);
|
||||
BSTREAM_TO_INT8(response, pValue);
|
||||
|
||||
/* Stop the timer waiting for a control point response */
|
||||
WsfTimerStop(&UdscCb.rspTimer);
|
||||
|
||||
if ((response == UDSC_UCP_RSP_SUCCESS) && (responseOpcode == UDSC_UCP_OPCODE_RNU))
|
||||
{
|
||||
BSTREAM_TO_INT8(index, pValue);
|
||||
}
|
||||
|
||||
if (UdscCb.rspCback)
|
||||
{
|
||||
UdscCb.rspCback(connId, responseOpcode, response, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length UDSC_PLXS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t UdscValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
|
||||
/* User Control Point */
|
||||
if (pMsg->handle == pHdlList[UDSC_UCP_IDX])
|
||||
{
|
||||
APP_TRACE_INFO0("UDSC: User Control Point notification");
|
||||
|
||||
/* parse value */
|
||||
udscParseUcp((dmConnId_t) pMsg->hdr.param, pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read the user index characteristic.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscReadUserIndex(dmConnId_t connId, uint16_t handle)
|
||||
{
|
||||
if (handle != ATT_HANDLE_NONE)
|
||||
{
|
||||
AttcReadReq(connId, handle);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read the database change increment characteristic.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscReadDatabaseChangeIncrement(dmConnId_t connId, uint16_t handle)
|
||||
{
|
||||
if (handle != ATT_HANDLE_NONE)
|
||||
{
|
||||
AttcReadReq(connId, handle);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write the database change increment characteristic.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param increment DB change increment
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscWriteDatabaseChangeIncrement(dmConnId_t connId, uint16_t handle, uint32_t increment)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t *p = buf;
|
||||
|
||||
if (handle != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* build command */
|
||||
UINT32_TO_BSTREAM(p, increment);
|
||||
|
||||
AttcWriteReq(connId, handle, (uint16_t) (p - buf), buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the control point and set a timer waiting for the response.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param valueLen Size of pValue in bytes
|
||||
* \param pValue Value to write
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void udscWriteControlPoint(dmConnId_t connId, uint16_t handle, uint16_t valueLen, uint8_t *pValue)
|
||||
{
|
||||
/* Start timer waiting for response */
|
||||
WsfTimerStartSec(&UdscCb.rspTimer, UDSC_RESPONSE_TIMEOUT);
|
||||
|
||||
/* Send write request */
|
||||
AttcWriteReq(connId, handle, valueLen, pValue);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the user control point characteristic - Register New User.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param consentCode Consent code (0-9999)
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscRegisterNewUser(dmConnId_t connId, uint16_t handle, uint16_t consentCode)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t *p = buf;
|
||||
|
||||
if (handle != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* build command */
|
||||
UINT8_TO_BSTREAM(p, UDSC_UCP_OPCODE_RNU);
|
||||
UINT16_TO_BSTREAM(p, consentCode);
|
||||
|
||||
udscWriteControlPoint(connId, handle, (uint16_t) (p - buf), buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the user control point characteristic - Consent.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
* \param index User index
|
||||
* \param consentCode Consent code (0-9999 - provided when user was registered)
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscConsent(dmConnId_t connId, uint16_t handle, uint8_t index, uint16_t consentCode)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t *p = buf;
|
||||
|
||||
if (handle != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* build command */
|
||||
UINT8_TO_BSTREAM(p, UDSC_UCP_OPCODE_CONSENT);
|
||||
UINT8_TO_BSTREAM(p, index);
|
||||
UINT16_TO_BSTREAM(p, consentCode);
|
||||
|
||||
udscWriteControlPoint(connId, handle, (uint16_t) (p - buf), buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write to the user control point characteristic - Delete User Data.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param handle Attribute handle.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscDeleteUserData(dmConnId_t connId, uint16_t handle)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t *p = buf;
|
||||
|
||||
if (handle != ATT_HANDLE_NONE)
|
||||
{
|
||||
/* build command */
|
||||
UINT8_TO_BSTREAM(p, UDSC_UCP_OPCODE_DUD);
|
||||
|
||||
udscWriteControlPoint(connId, handle, (uint16_t) (p - buf), buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by the application when a connection closes.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscClose(void)
|
||||
{
|
||||
/* Stop the timer waiting for a control point response */
|
||||
WsfTimerStop(&UdscCb.rspTimer);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize User Data Service collector callbacks.
|
||||
*
|
||||
* \param handlerId Application task handler ID.
|
||||
* \param timerEvent Application timer event for control point timeout.
|
||||
* \param rspCback Callback to receive control point response messages.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UdscInit(wsfHandlerId_t handlerId, uint8_t timerEvent, UdsRspCback_t rspCback)
|
||||
{
|
||||
UdscCb.rspTimer.handlerId = handlerId;
|
||||
UdscCb.rspTimer.msg.event = timerEvent;
|
||||
|
||||
UdscCb.rspCback = rspCback;
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief UriBeacon configuration profile.
|
||||
*
|
||||
* Copyright (c) 2011-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 URICFG_API_H
|
||||
#define URICFG_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup URIBEACON_CONFIGURATION_PROFILE
|
||||
* \{ */
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "att_api.h"
|
||||
#include "svc_uricfg.h"
|
||||
#include "uricfg_defs.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Attribute write callback.
|
||||
*
|
||||
* \param handle Attribute handle.
|
||||
* \param valueLen Length of value data.
|
||||
* \param pValue Pointer to value data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
typedef void (*uriCfgAttWriteCback_t)(uint16_t handle, uint16_t valueLen, const uint8_t *pValue);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Lock change callback.
|
||||
*
|
||||
* \param lockState New lock state.
|
||||
* \param lock Lock value.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
typedef void (*uriCfgLockChangeCback_t)(uint8_t lockState, const uint8_t *pLock);
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start UriBeacon configuration service.
|
||||
*
|
||||
* \param pUriData Initial URI data value
|
||||
* \param uriDataLen Length of URI data value
|
||||
* \param uriFlags Initial URI flags value
|
||||
* \param pAdvTxPwrLevels Initial advertised tx power levels value
|
||||
* \param txPwrMode Initial tx power mode value
|
||||
* \param beaconPeriod Initial beacon period value
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UriCfgStart(const uint8_t *pUriData, uint8_t uriDataLen, uint8_t uriFlags,
|
||||
int8_t *pAdvTxPwrLevels, uint8_t txPwrMode, uint16_t beaconPeriod);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop UriBeacon configuration service.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UriCfgStop(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Register callback for written UriBeacon attributes.
|
||||
*
|
||||
* \param cback Callback to invoke when an attribute changes.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UriCfgAttWriteCbackRegister(uriCfgAttWriteCback_t cback);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Make UriBeacon lockable.
|
||||
*
|
||||
* \param lockState Initial lock state value.
|
||||
* \param pLock Initial lock value.
|
||||
* \param cback Callback to invoke when lock changes.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UriCfgMakeLockable(uint8_t lockState, uint8_t *pLock, uriCfgLockChangeCback_t cback);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set reset value of URI data.
|
||||
*
|
||||
* \param pUriData Reset value of URI data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UriCfgSetUriDataResetValue(const uint8_t *pUriData);
|
||||
|
||||
/*! \} */ /* URIBEACON_CONFIGURATION_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* URICFG_API_H */
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief UriBeacon configuration service defines.
|
||||
*
|
||||
* Copyright (c) 2011-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 URICFG_DEFS_H
|
||||
#define URICFG_DEFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup URIBEACON_CONFIGURATION_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief UriBeacon configuration service-related UUIDs */
|
||||
#define URICFG_UUID_BYTES(id) 0xd8, 0x81, 0xc9, 0x1a, 0xb9, 0x99, \
|
||||
0x96, 0xab, \
|
||||
0xba, 0x40, \
|
||||
0x86, 0x87, \
|
||||
(id & 0xFF), ((id >> 8) & 0xFF), 0x0c, 0xee
|
||||
|
||||
/*! \brief UriBeacon configuration service-related UUIDs */
|
||||
enum
|
||||
{
|
||||
URICFG_UUID_SVC = 0x2080,
|
||||
URICFG_UUID_CHR_LOCKSTATE = 0x2081,
|
||||
URICFG_UUID_CHR_LOCK = 0x2082,
|
||||
URICFG_UUID_CHR_UNLOCK = 0x2083,
|
||||
URICFG_UUID_CHR_URIDATA = 0x2084,
|
||||
URICFG_UUID_CHR_URIFLAGS = 0x2085,
|
||||
URICFG_UUID_CHR_TXPWRLEVELS = 0x2086,
|
||||
URICFG_UUID_CHR_TXPWRMODE = 0x2087,
|
||||
URICFG_UUID_CHR_BEACONPERIOD = 0x2088,
|
||||
URICFG_UUID_CHR_RESET = 0x2089
|
||||
};
|
||||
|
||||
/*! \brief Transmit power modes */
|
||||
enum
|
||||
{
|
||||
URICFG_ATT_TXPWRMODE_LOWEST = 0,
|
||||
URICFG_ATT_TXPWRMODE_LOW = 1,
|
||||
URICFG_ATT_TXPWRMODE_MEDIUM = 2,
|
||||
URICFG_ATT_TXPWRMODE_HIGH = 3
|
||||
};
|
||||
|
||||
/** \name URI Config Attributes Sizes
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define URICFG_MAXSIZE_URIDATA_ATT 18 /*!< \brief Size of URI data attribute */
|
||||
#define URICFG_SIZE_TXPWRLEVELS_ATT 4 /*!< \brief Size of transmit power levels attribute */
|
||||
#define URICFG_SIZE_LOCK_ATT 16 /*!< \brief Size of lock attribute */
|
||||
/**@}*/
|
||||
|
||||
/** \name Beacon period Attribute Values
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define URICFG_ATT_BEACONPERIOD_MIN 20 /*!< \brief Minimum period */
|
||||
#define URICFG_ATT_BEACONPERIOD_MAX 10240 /*!< \brief Maximum period */
|
||||
#define URICFG_ATT_BEACONPERIOD_DISABLE 0 /*!< \brief Value to disable beacon */
|
||||
/**@}*/
|
||||
|
||||
/** \name Default (Reset) Values of Attributes
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define URICFG_ATT_URIFLAGS_DEFAULT 0x00 /*!< \brief Default URI flags */
|
||||
#define URICFG_ATT_TXPWRMODE_DEFAULT URICFG_ATT_TXPWRMODE_LOW /*!< \brief Default TX power mode */
|
||||
#define URICFG_ATT_BEACONPERIOD_DEFAULT 1000 /*!< \brief Default beacon period in milliseconds (1 second) */
|
||||
#define URICFG_ATT_LOCK_DEFAULT_BYTES 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, \
|
||||
0x00, 0x00, \
|
||||
0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*!< \brief Default lock bytes */
|
||||
/**@}*/
|
||||
|
||||
/*! \brief UriBeacon service UUID for advertising data */
|
||||
#define URICFG_SERVICE_UUID 0xFED8
|
||||
|
||||
/*! \} */ /* URIBEACON_CONFIGURATION_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* URICFG_DEFS_H */
|
||||
+369
@@ -0,0 +1,369 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief UriBeacon configuration profile.
|
||||
*
|
||||
* Copyright (c) 2011-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 "uricfg_api.h"
|
||||
#include "app_api.h"
|
||||
#include "att_api.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "uricfg_defs.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief callback when attributes are written */
|
||||
static uriCfgAttWriteCback_t uriCfgAttWriteCback;
|
||||
|
||||
/*! \brief callback when lock status changes */
|
||||
static uriCfgLockChangeCback_t uriCfgLockChangeCback;
|
||||
|
||||
/*! \brief reset value of URI data */
|
||||
static uint8_t uriCfgDataResetValue[URICFG_MAXSIZE_URIDATA_ATT];
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for UriBeacon service.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t uriCfgBeaconWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
|
||||
{
|
||||
uint8_t lockState = 0;
|
||||
uint8_t *pLockState = NULL;
|
||||
uint16_t attLen;
|
||||
|
||||
if (AttsGetAttr(URICFG_HANDLE_LOCKSTATE, &attLen, &pLockState) == ATT_SUCCESS)
|
||||
{
|
||||
lockState = *pLockState;
|
||||
}
|
||||
|
||||
switch (handle)
|
||||
{
|
||||
case URICFG_HANDLE_LOCK:
|
||||
{
|
||||
if (uriCfgLockChangeCback != NULL)
|
||||
{
|
||||
if (!lockState)
|
||||
{
|
||||
APP_TRACE_INFO0("URI profile locking");
|
||||
lockState = 1u;
|
||||
AttsSetAttr(URICFG_HANDLE_LOCK, URICFG_SIZE_LOCK_ATT, pValue);
|
||||
AttsSetAttr(URICFG_HANDLE_LOCKSTATE, sizeof(lockState), &lockState);
|
||||
uriCfgLockChangeCback(lockState, pValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
APP_TRACE_INFO0("URI profile already locked");
|
||||
return ATT_ERR_AUTHOR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case URICFG_HANDLE_UNLOCK:
|
||||
{
|
||||
if (uriCfgLockChangeCback != NULL)
|
||||
{
|
||||
uint8_t *pLock = NULL;
|
||||
|
||||
if (lockState)
|
||||
{
|
||||
if (AttsGetAttr(URICFG_HANDLE_LOCK, &attLen, &pLock) != ATT_SUCCESS)
|
||||
{
|
||||
APP_TRACE_INFO0("URI profile failed to get lock value");
|
||||
return ATT_ERR_AUTHOR;
|
||||
}
|
||||
if (memcmp(pLock, pValue, len) != 0)
|
||||
{
|
||||
APP_TRACE_INFO0("URI profile lock mismatch");
|
||||
return ATT_ERR_AUTHOR;
|
||||
}
|
||||
APP_TRACE_INFO0("URI profile unlocking");
|
||||
lockState = 0u;
|
||||
AttsSetAttr(URICFG_HANDLE_LOCKSTATE, sizeof(lockState), &lockState);
|
||||
uriCfgLockChangeCback(lockState, pValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
APP_TRACE_INFO0("URI profile already unlocked");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case URICFG_HANDLE_URIDATA:
|
||||
{
|
||||
/* check lock */
|
||||
if (lockState)
|
||||
{
|
||||
return ATT_ERR_AUTHOR;
|
||||
}
|
||||
|
||||
/* save value */
|
||||
AttsSetAttr(handle, len, pValue);
|
||||
if (uriCfgAttWriteCback != NULL)
|
||||
{
|
||||
uriCfgAttWriteCback(handle, len, pValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case URICFG_HANDLE_URIFLAGS:
|
||||
case URICFG_HANDLE_TXPWRLEVELS:
|
||||
{
|
||||
/* check lock */
|
||||
if (lockState)
|
||||
{
|
||||
return ATT_ERR_AUTHOR;
|
||||
}
|
||||
|
||||
/* save value */
|
||||
AttsSetAttr(handle, len, pValue);
|
||||
if (uriCfgAttWriteCback != NULL)
|
||||
{
|
||||
uriCfgAttWriteCback(handle, len, pValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case URICFG_HANDLE_TXPWRMODE:
|
||||
{
|
||||
uint8_t txPwrMode;
|
||||
|
||||
/* check lock */
|
||||
if (lockState)
|
||||
{
|
||||
return ATT_ERR_AUTHOR;
|
||||
}
|
||||
|
||||
/* check value */
|
||||
txPwrMode = (uint8_t)*pValue;
|
||||
if (txPwrMode > URICFG_ATT_TXPWRMODE_HIGH)
|
||||
{
|
||||
return ATT_ERR_WRITE_REJ;
|
||||
}
|
||||
|
||||
/* save value */
|
||||
AttsSetAttr(handle, sizeof(txPwrMode), &txPwrMode);
|
||||
if (uriCfgAttWriteCback != NULL)
|
||||
{
|
||||
uriCfgAttWriteCback(handle, sizeof(txPwrMode), &txPwrMode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case URICFG_HANDLE_BEACONPERIOD:
|
||||
{
|
||||
uint16_t beaconPeriod;
|
||||
|
||||
if (lockState)
|
||||
{
|
||||
return ATT_ERR_AUTHOR;
|
||||
}
|
||||
|
||||
/* check value */
|
||||
BYTES_TO_UINT16(beaconPeriod, pValue);
|
||||
|
||||
/* save value */
|
||||
if (beaconPeriod != URICFG_ATT_BEACONPERIOD_DISABLE)
|
||||
{
|
||||
if (beaconPeriod < URICFG_ATT_BEACONPERIOD_MIN)
|
||||
{
|
||||
beaconPeriod = URICFG_ATT_BEACONPERIOD_MIN;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t beaconPeriodVal[2] = {UINT16_TO_BYTES(beaconPeriod)};
|
||||
AttsSetAttr(handle, sizeof(beaconPeriod), beaconPeriodVal);
|
||||
if (uriCfgAttWriteCback != NULL)
|
||||
{
|
||||
uriCfgAttWriteCback(handle, sizeof(beaconPeriod), (uint8_t *)&beaconPeriod);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case URICFG_HANDLE_RESET:
|
||||
{
|
||||
uint8_t resetValue;
|
||||
|
||||
if (lockState)
|
||||
{
|
||||
return ATT_ERR_AUTHOR;
|
||||
}
|
||||
|
||||
/* check value */
|
||||
resetValue = *pValue;
|
||||
|
||||
if (resetValue != 0)
|
||||
{
|
||||
uint8_t uriFlags;
|
||||
uint8_t txPwrMode;
|
||||
uint16_t beaconPeriod;
|
||||
uint8_t lock[] = {URICFG_ATT_LOCK_DEFAULT_BYTES};
|
||||
|
||||
/* reset URI data */
|
||||
AttsSetAttr(URICFG_HANDLE_URIDATA, sizeof(uriCfgDataResetValue), uriCfgDataResetValue);
|
||||
if (uriCfgAttWriteCback != NULL)
|
||||
{
|
||||
uriCfgAttWriteCback(URICFG_HANDLE_URIDATA, sizeof(uriCfgDataResetValue), uriCfgDataResetValue);
|
||||
}
|
||||
|
||||
/* reset URI flags */
|
||||
uriFlags = URICFG_ATT_URIFLAGS_DEFAULT;
|
||||
AttsSetAttr(URICFG_HANDLE_URIFLAGS, sizeof(uriFlags), &uriFlags);
|
||||
if (uriCfgAttWriteCback != NULL)
|
||||
{
|
||||
uriCfgAttWriteCback(URICFG_HANDLE_URIFLAGS, sizeof(uriFlags), &uriFlags);
|
||||
}
|
||||
|
||||
/* reset tx power mode */
|
||||
txPwrMode = URICFG_ATT_TXPWRMODE_DEFAULT;
|
||||
AttsSetAttr(URICFG_HANDLE_TXPWRMODE, sizeof(txPwrMode), &txPwrMode);
|
||||
if (uriCfgAttWriteCback != NULL)
|
||||
{
|
||||
uriCfgAttWriteCback(URICFG_HANDLE_TXPWRMODE, sizeof(txPwrMode), &txPwrMode);
|
||||
}
|
||||
|
||||
/* reset beacon period */
|
||||
beaconPeriod = URICFG_ATT_BEACONPERIOD_DEFAULT;
|
||||
uint8_t beaconPeriodVal[2] = {UINT16_TO_BYTES(beaconPeriod)};
|
||||
AttsSetAttr(URICFG_HANDLE_BEACONPERIOD, sizeof(beaconPeriod), beaconPeriodVal);
|
||||
if (uriCfgAttWriteCback != NULL)
|
||||
{
|
||||
uriCfgAttWriteCback(URICFG_HANDLE_BEACONPERIOD, sizeof(beaconPeriod), (uint8_t *)&beaconPeriod);
|
||||
}
|
||||
|
||||
/* reset lock */
|
||||
AttsSetAttr(URICFG_HANDLE_LOCK, URICFG_SIZE_LOCK_ATT, lock);
|
||||
if (uriCfgAttWriteCback != NULL)
|
||||
{
|
||||
uriCfgAttWriteCback(URICFG_HANDLE_LOCK, sizeof(lock), lock);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return ATT_ERR_NOT_SUP;
|
||||
}
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Start UriBeacon configuration service.
|
||||
*
|
||||
* \param pUriData Initial URI data value
|
||||
* \param uriDataLen Length of URI data value
|
||||
* \param uriFlags Initial URI flags value
|
||||
* \param advTxPwrLevels Initial advertised tx power levels value
|
||||
* \param txPwrMode Initial tx power mode value
|
||||
* \param beaconPeriod Initial beacon period value
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UriCfgStart(const uint8_t *pUriData, uint8_t uriDataLen, uint8_t uriFlags,
|
||||
int8_t *pAdvTxPwrLevels, uint8_t txPwrMode, uint16_t beaconPeriod)
|
||||
{
|
||||
SvcUriCfgAddGroup();
|
||||
SvcUriCfgCbackRegister(uriCfgBeaconWriteCback);
|
||||
|
||||
uint8_t lockState = 0;
|
||||
AttsSetAttr(URICFG_HANDLE_LOCKSTATE, sizeof(lockState), &lockState);
|
||||
AttsSetAttr(URICFG_HANDLE_URIDATA, uriDataLen, (uint8_t *)pUriData);
|
||||
AttsSetAttr(URICFG_HANDLE_URIFLAGS, sizeof(uriFlags), &uriFlags);
|
||||
AttsSetAttr(URICFG_HANDLE_TXPWRLEVELS, URICFG_SIZE_TXPWRLEVELS_ATT,(uint8_t *)pAdvTxPwrLevels);
|
||||
AttsSetAttr(URICFG_HANDLE_TXPWRMODE, sizeof(txPwrMode), &txPwrMode);
|
||||
uint8_t beaconPeriodVal[2] = {UINT16_TO_BYTES(beaconPeriod)};
|
||||
AttsSetAttr(URICFG_HANDLE_BEACONPERIOD, sizeof(beaconPeriod), beaconPeriodVal);
|
||||
|
||||
uriCfgAttWriteCback = NULL;
|
||||
uriCfgLockChangeCback = NULL;
|
||||
memset(uriCfgDataResetValue, 0xFFu, URICFG_MAXSIZE_URIDATA_ATT);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop UriBeacon service.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UriCfgStop(void)
|
||||
{
|
||||
SvcUriCfgRemoveGroup();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Register callback for written UriBeacon attributes.
|
||||
*
|
||||
* \param cback Callback to invoke when an attribute changes.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UriCfgAttWriteCbackRegister(uriCfgAttWriteCback_t cback)
|
||||
{
|
||||
uriCfgAttWriteCback = cback;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Make UriBeacon lockable.
|
||||
*
|
||||
* \param lockState Initial lock state value.
|
||||
* \param lock Initial lock value.
|
||||
* \param cback Callback to invoke when lock changes.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UriCfgMakeLockable(uint8_t lockState, uint8_t *pLock, uriCfgLockChangeCback_t cback)
|
||||
{
|
||||
AttsSetAttr(URICFG_HANDLE_LOCKSTATE, sizeof(lockState), &lockState);
|
||||
AttsSetAttr(URICFG_HANDLE_LOCK, URICFG_SIZE_LOCK_ATT, pLock);
|
||||
|
||||
uriCfgLockChangeCback = cback;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set reset value of URI data.
|
||||
*
|
||||
* \param pUriData Reset value of URI data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void UriCfgSetUriDataResetValue(const uint8_t *pUriData)
|
||||
{
|
||||
memcpy(uriCfgDataResetValue, pUriData, URICFG_MAXSIZE_URIDATA_ATT);
|
||||
}
|
||||
Vendored
+262
@@ -0,0 +1,262 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile application interface.
|
||||
*
|
||||
* Copyright (c) 2017-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 WDXC_API_H
|
||||
#define WDXC_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup WIRELESS_DATA_EXCHANGE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief WDXC enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
WDXC_DC_HDL_IDX, /*!< \brief WDX Device Configuration */
|
||||
WDXC_DC_CCC_HDL_IDX, /*!< \brief WDX Device Configuration CCC descriptor */
|
||||
WDXC_FTC_HDL_IDX, /*!< \brief WDX File Transfer Control */
|
||||
WDXC_FTC_CCC_HDL_IDX, /*!< \brief WDX File Transfer Control CCC descriptor */
|
||||
WDXC_FTD_HDL_IDX, /*!< \brief WDX File Transfer Data */
|
||||
WDXC_FTD_CCC_HDL_IDX, /*!< \brief WDX File Transfer Data CCC descriptor */
|
||||
WDXC_AU_HDL_IDX, /*!< \brief WDX Authenticationa */
|
||||
WDXC_AU_CCC_HDL_IDX, /*!< \brief WDX Authentication CCC descriptor */
|
||||
WDXC_HDL_LIST_LEN /*!< \brief WDX handle list length. */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/**************************************************************************************************
|
||||
Callback Function Datatypes
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WDXC File Transfer Data callback.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param handle Handle of the file.
|
||||
* \param len length of pData in bytes.
|
||||
* \param pData File data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
typedef void WdxcFtdCallback_t(dmConnId_t connId, uint16_t handle, uint16_t len, uint8_t *pData);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WDXC File Transfer Control callback.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param handle Handle of the file.
|
||||
* \param op Control operation.
|
||||
* \param status Status of operation.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
typedef void WdxcFtcCallback_t(dmConnId_t connId, uint16_t handle, uint8_t op, uint8_t status);
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the WDXC.
|
||||
*
|
||||
* \param pFtdCallback Application Callback for File Transfer Data.
|
||||
* \param pFtcCallback Application Callback for File Transfer Control.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcInit(WdxcFtdCallback_t *pFtdCallback, WdxcFtcCallback_t *pFtcCallback);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by application to notify the WDXC of DM and ATT Events.
|
||||
*
|
||||
* \param pEvt Pointer to the Event
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcProcMsg(wsfMsgHdr_t *pEvt);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Wireless Data Exchange service.
|
||||
* Parameter pHdlList must point to an array of length \ref WDXC_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcWdxsDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform File Discovery
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param pFileInfo Buffer to hold information about files
|
||||
* \param maxFiles Size of pFileInfo in number of \ref wsfEfsFileInfo_t objects
|
||||
*
|
||||
* \note When file discovery completes, the ftcCallback() will be called with operator equal to
|
||||
* \ref WDX_FTC_OP_EOF and file handle equal to \ref WDX_FLIST_HANDLE.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcDiscoverFiles(dmConnId_t connId, wsfEfsFileInfo_t *pFileInfo, uint8_t maxFiles);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to start a stream of a given file handle on the given connection.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of the file.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcStreamStart(dmConnId_t connId, uint16_t fileHdl);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop the active stream.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcStreamStop(dmConnId_t connId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to abort a wdx operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file to abort operation on peer device
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendAbort(dmConnId_t connId, uint16_t fileHdl);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to erase a file.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file to erase on peer device
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendEraseFile(dmConnId_t connId, uint16_t fileHdl);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to verify a file.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file to verify on peer device
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendVerifyFile(dmConnId_t connId, uint16_t fileHdl);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to put a block of data into a file on the peer device
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file on peer device
|
||||
* \param offset The offset from the beginning of the file in bytes
|
||||
* \param len The number of bytes to put
|
||||
* \param fileSize The size of the file in bytes
|
||||
* \param type reserved
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendPutReq(dmConnId_t connId, uint16_t fileHdl, uint32_t offset,
|
||||
uint32_t len, uint32_t fileSize, uint8_t type);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to perform a get a block of data from a file on the peer device
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file to verify on peer device
|
||||
* \param offset The offset from the beginning of the file in bytes
|
||||
* \param len The number of bytes to get
|
||||
* \param type reserved
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendGetReq(dmConnId_t connId, uint16_t fileHdl, uint32_t offset, uint32_t len, uint8_t type);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a data block to the peer device
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param len Size of pData in bytes
|
||||
* \param pData Data to put to the file
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtdSendBlock(dmConnId_t connId, uint32_t len, uint8_t *pData);
|
||||
|
||||
/*! \} */ /* WIRELESS_DATA_EXCHANGE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* WDXC_MAIN_H */
|
||||
Vendored
+211
@@ -0,0 +1,211 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile client - File Transfer.
|
||||
*
|
||||
* Copyright (c) 2017-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 <stddef.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_efs.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_wdxs.h"
|
||||
#include "wdx_defs.h"
|
||||
#include "wdxc_api.h"
|
||||
#include "wdxc_main.h"
|
||||
#include "dm_api.h"
|
||||
#include "app_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
External Variables
|
||||
**************************************************************************************************/
|
||||
extern wdxcCb_t wdxcCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to abort a wdx operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file to abort operation on peer device
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendAbort(dmConnId_t connId, uint16_t fileHdl)
|
||||
{
|
||||
uint8_t buf[WDX_FTC_ABORT_LEN];
|
||||
uint8_t *p = buf;
|
||||
uint16_t handle;
|
||||
|
||||
WSF_ASSERT(wdxcCb.conn[connId - 1].pHdlList != NULL)
|
||||
|
||||
handle = wdxcCb.conn[connId - 1].pHdlList[WDXC_FTC_HDL_IDX];
|
||||
|
||||
UINT8_TO_BSTREAM(p, WDX_FTC_OP_ABORT);
|
||||
UINT16_TO_BSTREAM(p, fileHdl);
|
||||
|
||||
AttcWriteReq(connId, handle, WDX_FTC_ABORT_LEN, buf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to erase a file.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file to erase on peer device
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendEraseFile(dmConnId_t connId, uint16_t fileHdl)
|
||||
{
|
||||
uint8_t buf[WDX_FTC_ERASE_LEN];
|
||||
uint8_t *p = buf;
|
||||
uint16_t handle;
|
||||
|
||||
WSF_ASSERT(wdxcCb.conn[connId - 1].pHdlList != NULL)
|
||||
|
||||
handle = wdxcCb.conn[connId - 1].pHdlList[WDXC_FTC_HDL_IDX];
|
||||
|
||||
UINT8_TO_BSTREAM(p, WDX_FTC_OP_ERASE_REQ);
|
||||
UINT16_TO_BSTREAM(p, fileHdl);
|
||||
|
||||
AttcWriteReq(connId, handle, WDX_FTC_ERASE_LEN, buf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to verify a file.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file to verify on peer device
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendVerifyFile(dmConnId_t connId, uint16_t fileHdl)
|
||||
{
|
||||
uint8_t buf[WDX_FTC_VERIFY_LEN];
|
||||
uint8_t *p = buf;
|
||||
uint16_t handle;
|
||||
|
||||
WSF_ASSERT(wdxcCb.conn[connId - 1].pHdlList != NULL)
|
||||
|
||||
handle = wdxcCb.conn[connId - 1].pHdlList[WDXC_FTC_HDL_IDX];
|
||||
|
||||
UINT8_TO_BSTREAM(p, WDX_FTC_OP_VERIFY_REQ);
|
||||
UINT16_TO_BSTREAM(p, fileHdl);
|
||||
|
||||
AttcWriteReq(connId, handle, WDX_FTC_VERIFY_LEN, buf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to put a block of data into a file on the peer device
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file on peer device
|
||||
* \param offset The offset from the beginning of the file in bytes
|
||||
* \param len The number of bytes to put
|
||||
* \param fileSize The size of the file in bytes
|
||||
* \param type reserved
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendPutReq(dmConnId_t connId, uint16_t fileHdl, uint32_t offset,
|
||||
uint32_t len, uint32_t fileSize, uint8_t type)
|
||||
{
|
||||
uint8_t buf[WDX_FTC_PUT_LEN];
|
||||
uint8_t *p = buf;
|
||||
uint16_t handle;
|
||||
|
||||
WSF_ASSERT(wdxcCb.conn[connId - 1].pHdlList != NULL)
|
||||
|
||||
handle = wdxcCb.conn[connId - 1].pHdlList[WDXC_FTC_HDL_IDX];
|
||||
|
||||
UINT8_TO_BSTREAM(p, WDX_FTC_OP_PUT_REQ);
|
||||
UINT16_TO_BSTREAM(p, fileHdl);
|
||||
|
||||
UINT32_TO_BSTREAM(p, offset);
|
||||
UINT32_TO_BSTREAM(p, len);
|
||||
UINT32_TO_BSTREAM(p, fileSize);
|
||||
UINT8_TO_BSTREAM(p, type);
|
||||
|
||||
AttcWriteReq(connId, handle, WDX_FTC_PUT_LEN, buf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to perform a get a block of data from a file on the peer device
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file to verify on peer device
|
||||
* \param offset The offset from the beginning of the file in bytes
|
||||
* \param len The number of bytes to get
|
||||
* \param type reserved
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendGetReq(dmConnId_t connId, uint16_t fileHdl, uint32_t offset, uint32_t len, uint8_t type)
|
||||
{
|
||||
uint8_t buf[WDX_FTC_GET_LEN];
|
||||
uint8_t *p = buf;
|
||||
uint16_t handle;
|
||||
|
||||
WSF_ASSERT(wdxcCb.conn[connId - 1].pHdlList != NULL)
|
||||
|
||||
handle = wdxcCb.conn[connId - 1].pHdlList[WDXC_FTC_HDL_IDX];
|
||||
|
||||
UINT8_TO_BSTREAM(p, WDX_FTC_OP_GET_REQ);
|
||||
UINT16_TO_BSTREAM(p, fileHdl);
|
||||
|
||||
UINT32_TO_BSTREAM(p, offset);
|
||||
UINT32_TO_BSTREAM(p, len);
|
||||
UINT8_TO_BSTREAM(p, type);
|
||||
|
||||
AttcWriteReq(connId, handle, WDX_FTC_GET_LEN, buf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a data block to the peer device
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param len Size of pData in bytes
|
||||
* \param pData Data to put to the file
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtdSendBlock(dmConnId_t connId, uint32_t len, uint8_t *pData)
|
||||
{
|
||||
uint16_t handle;
|
||||
|
||||
WSF_ASSERT(wdxcCb.conn[connId - 1].pHdlList != NULL)
|
||||
|
||||
handle = wdxcCb.conn[connId - 1].pHdlList[WDXC_FTD_HDL_IDX];
|
||||
|
||||
AttcWriteReq(connId, handle, (uint16_t) len, pData);
|
||||
}
|
||||
Vendored
+434
@@ -0,0 +1,434 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile client.
|
||||
*
|
||||
* Copyright (c) 2013-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 "util/wstr.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_efs.h"
|
||||
#include "wsf_os.h"
|
||||
#include "sec_api.h"
|
||||
#include "util/bstream.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "app_api.h"
|
||||
#include "svc_wdxs.h"
|
||||
#include "wdx_defs.h"
|
||||
#include "wdxc_api.h"
|
||||
#include "wdxc_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! WDXC control block */
|
||||
wdxcCb_t wdxcCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! UUIDs */
|
||||
static const uint8_t wdxcDcUuid[ATT_128_UUID_LEN] = {WDX_DC_UUID}; /* WDX Device Configuration Characteristic */
|
||||
static const uint8_t wdxcFtcUuid[ATT_128_UUID_LEN] = {WDX_FTC_UUID}; /* WDX File Transfer Control Characteristic */
|
||||
static const uint8_t wdxcFtdUuid[ATT_128_UUID_LEN] = {WDX_FTD_UUID}; /* WDX File Transfer Data Characteristic */
|
||||
static const uint8_t wdxcAuUuid[ATT_128_UUID_LEN] = {WDX_AU_UUID}; /* WDX Authentication Characteristic */
|
||||
|
||||
/*! WDXC Device Configuration */
|
||||
static const attcDiscChar_t wdxcWdxsDc =
|
||||
{
|
||||
wdxcDcUuid,
|
||||
ATTC_SET_UUID_128
|
||||
};
|
||||
|
||||
/*! WDXC Device Configuration CCC descriptor */
|
||||
static const attcDiscChar_t wdxcWdxsDcCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! WDXC File Transfer Control */
|
||||
static const attcDiscChar_t wdxcWdxsFtc =
|
||||
{
|
||||
wdxcFtcUuid,
|
||||
ATTC_SET_UUID_128
|
||||
};
|
||||
|
||||
/*! WDXC File Transfer Control CCC descriptor */
|
||||
static const attcDiscChar_t wdxcWdxsFtcCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! WDXC File Transfer Data */
|
||||
static const attcDiscChar_t wdxcWdxsFtd =
|
||||
{
|
||||
wdxcFtdUuid,
|
||||
ATTC_SET_UUID_128
|
||||
};
|
||||
|
||||
/*! WDXC File Transfer Data CCC descriptor */
|
||||
static const attcDiscChar_t wdxcWdxsFtdCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! WDXC Authentication */
|
||||
static const attcDiscChar_t wdxcWdxsAu =
|
||||
{
|
||||
wdxcAuUuid,
|
||||
ATTC_SET_UUID_128
|
||||
};
|
||||
|
||||
/*! WDXC Authentication CCC descriptor */
|
||||
static const attcDiscChar_t wdxcWdxsAuCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *wdxcWdxsDiscCharList[] =
|
||||
{
|
||||
&wdxcWdxsDc, /*! WDXC Device Configuration */
|
||||
&wdxcWdxsDcCcc, /*! WDXC Device Configuration CCC descriptor */
|
||||
&wdxcWdxsFtc, /*! WDXC File Transfer Control */
|
||||
&wdxcWdxsFtcCcc, /*! WDXC File Transfer Control CCC descriptor */
|
||||
&wdxcWdxsFtd, /*! WDXC File Transfer Data */
|
||||
&wdxcWdxsFtdCcc, /*! WDXC File Transfer Data CCC descriptor */
|
||||
&wdxcWdxsAu, /*! WDXC Authentication */
|
||||
&wdxcWdxsAuCcc, /*! WDXC Authentication CCC descriptor */
|
||||
};
|
||||
|
||||
/*! sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(WDXC_HDL_LIST_LEN == ((sizeof(wdxcWdxsDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
const uint8_t wdxcSvcUuid[ATT_16_UUID_LEN] = {UINT16_TO_BYTES(WDX_SVC_UUID)};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Wireless Data Exchange service.
|
||||
* Parameter pHdlList must point to an array of length WDXC_WDX_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcWdxsDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
wdxcConnCb_t *pConnCb = &wdxcCb.conn[connId - 1];
|
||||
|
||||
/* Store pointer to the attribute handles in the control block */
|
||||
pConnCb->pHdlList = pHdlList;
|
||||
|
||||
/* Perform service discovery */
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) wdxcSvcUuid,
|
||||
WDXC_HDL_LIST_LEN, (attcDiscChar_t **) wdxcWdxsDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform File Discovery
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param pFileInfo Buffer to hold information about files
|
||||
* \param maxFiles Size of pFileInfo in number of wsfEfsFileInfo_t objects
|
||||
*
|
||||
* \note When discovery is complete, the ftcCallback will be called with op equal to
|
||||
* WDX_FTC_OP_EOF and the file handle equal to WDX_FLIST_HANDLE.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcDiscoverFiles(dmConnId_t connId, wsfEfsFileInfo_t *pFileInfo, uint8_t maxFiles)
|
||||
{
|
||||
wdxcConnCb_t *pConnCb = &wdxcCb.conn[connId - 1];
|
||||
|
||||
/* Verify WDXC is Idle */
|
||||
if (pConnCb->fileHdl == WSF_EFS_INVALID_HANDLE)
|
||||
{
|
||||
uint16_t len = maxFiles * WDX_FLIST_RECORD_SIZE + WDX_FLIST_HDR_SIZE;
|
||||
|
||||
/* Update control information */
|
||||
pConnCb->pFileList = pFileInfo;
|
||||
pConnCb->fileCount = 0;
|
||||
pConnCb->maxFiles = maxFiles;
|
||||
pConnCb->fileHdl = WDX_FLIST_HANDLE;
|
||||
pConnCb->fDlPos = 0;
|
||||
|
||||
/* Perform a get on file zero (the file list handle) where the length of the get is
|
||||
* the most file information pFileInfo can hold */
|
||||
WdxcFtcSendGetReq(connId, WDX_FLIST_HANDLE, 0, len, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Parse File Listing FTD data
|
||||
*
|
||||
* \param pValue FTD Data.
|
||||
* \param len Size of pValue in bytes
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void wdxsParseFileList(dmConnId_t connId, uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
wdxcConnCb_t *pConnCb = &wdxcCb.conn[connId - 1];
|
||||
uint16_t pos = 0;
|
||||
|
||||
/* Depending on the MTU, blocks of FTD data from the file list may end mid-value.
|
||||
* Maintain a global position called wdxcCb.fDlPos, and process FTD data byte by byte */
|
||||
|
||||
while (pos < len)
|
||||
{
|
||||
if (pConnCb->fDlPos < WDX_FLIST_HDR_SIZE)
|
||||
{
|
||||
/* Ignore file list header */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Find the file index and the position within the file index (the mark) */
|
||||
uint8_t mark = (pConnCb->fDlPos - WDX_FLIST_HDR_SIZE) % WDX_FLIST_RECORD_SIZE;
|
||||
uint8_t file = (pConnCb->fDlPos - WDX_FLIST_HDR_SIZE) / WDX_FLIST_RECORD_SIZE;
|
||||
wsfEfsFileInfo_t *pInfo;
|
||||
|
||||
/* Ignore data if there is insufficient space in pConnCb->pFileList */
|
||||
if (file >= pConnCb->maxFiles)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pInfo = &pConnCb->pFileList[file];
|
||||
|
||||
/* Process a byte of data */
|
||||
switch (mark)
|
||||
{
|
||||
case 0: pConnCb->fileCount++; pInfo->handle = pValue[pos]; break;
|
||||
case 1: pInfo->handle |= ((uint16_t)pValue[pos]) << 8; break;
|
||||
case 2: pInfo->attributes.type = pValue[pos]; break;
|
||||
case 3: pInfo->attributes.permissions = pValue[pos]; break;
|
||||
case 4: pInfo->size = pValue[pos]; break;
|
||||
case 5: pInfo->size |= ((uint32_t)pValue[pos]) << 8; break;
|
||||
case 6: pInfo->size |= ((uint32_t)pValue[pos]) << 16; break;
|
||||
case 7: pInfo->size |= ((uint32_t)pValue[pos]) << 24; break;
|
||||
default:
|
||||
if (mark > 7 && mark < 8 + WSF_EFS_NAME_LEN)
|
||||
{
|
||||
pInfo->attributes.name[mark - 8] = pValue[pos];
|
||||
}
|
||||
else
|
||||
{
|
||||
pInfo->attributes.version[mark - (8 + WSF_EFS_NAME_LEN)] = pValue[pos];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pConnCb->fDlPos++;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Parse a file transfer control message.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void wdxcParseFtc(dmConnId_t connId, uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
/* Notification on a File Transfer Control (FTC) Attribute */
|
||||
wdxcConnCb_t *pConnCb = &wdxcCb.conn[connId - 1];
|
||||
uint8_t *p = pValue;
|
||||
uint8_t op, status;
|
||||
uint16_t handle;
|
||||
|
||||
BSTREAM_TO_UINT8(op, p);
|
||||
BSTREAM_TO_UINT16(handle, p);
|
||||
|
||||
if (op == WDX_FTC_OP_ABORT || op == WDX_FTC_OP_EOF)
|
||||
{
|
||||
pConnCb->fileHdl = WSF_EFS_INVALID_HANDLE;
|
||||
status = WDX_FTC_ST_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
BSTREAM_TO_UINT8(status, p)
|
||||
}
|
||||
|
||||
/* Call appliation callback */
|
||||
if (wdxcCb.pFtdCallback)
|
||||
{
|
||||
(*wdxcCb.pFtcCallback)(connId, handle, op, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Parse a wdxc file transfer data message.
|
||||
*
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void wdxcParseFtd(dmConnId_t connId, uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
wdxcConnCb_t *pConnCb = &wdxcCb.conn[connId - 1];
|
||||
|
||||
if (pConnCb->fileHdl == WDX_FLIST_HANDLE)
|
||||
{
|
||||
/* File Discovery is in progress */
|
||||
wdxsParseFileList(connId, pValue, len);
|
||||
}
|
||||
else if (pConnCb->fileHdl != WSF_EFS_INVALID_HANDLE)
|
||||
{
|
||||
/* Notify application of File Transfer Data (FTD) */
|
||||
if (wdxcCb.pFtdCallback)
|
||||
{
|
||||
(*wdxcCb.pFtdCallback)(connId, pConnCb->fileHdl, len, pValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length WDXC_WDX_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxcWdxsValueUpdate(attEvt_t *pMsg)
|
||||
{
|
||||
uint16_t *pHdlList = wdxcCb.conn[pMsg->hdr.param-1].pHdlList;
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
|
||||
/* device configuration */
|
||||
if (pMsg->handle == pHdlList[WDXC_DC_HDL_IDX])
|
||||
{
|
||||
/* Not Supported */
|
||||
}
|
||||
/* file transfer control */
|
||||
else if (pMsg->handle == pHdlList[WDXC_FTC_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO0("WDXC file transfer control.");
|
||||
wdxcParseFtc((dmConnId_t) pMsg->hdr.param, pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
/* file transfer data */
|
||||
else if (pMsg->handle == pHdlList[WDXC_FTD_HDL_IDX])
|
||||
{
|
||||
wdxcParseFtd((dmConnId_t) pMsg->hdr.param, pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
/* authentication */
|
||||
else if (pMsg->handle == pHdlList[WDXC_AU_HDL_IDX])
|
||||
{
|
||||
/* Not Supported */
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by application to notify the WDXC of System Events.
|
||||
*
|
||||
* \param pEvt Pointer to the Event
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcProcMsg(wsfMsgHdr_t *pEvt)
|
||||
{
|
||||
switch (pEvt->event)
|
||||
{
|
||||
case ATTC_HANDLE_VALUE_NTF:
|
||||
wdxcWdxsValueUpdate((attEvt_t *)pEvt);
|
||||
break;
|
||||
|
||||
case DM_CONN_CLOSE_IND:
|
||||
{
|
||||
wdxcConnCb_t *pConnCb = &wdxcCb.conn[pEvt->param - 1];
|
||||
|
||||
/* Set file handle to invalid to indicate no file operation is in progress */
|
||||
pConnCb->fileHdl = WSF_EFS_INVALID_HANDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the WDXC.
|
||||
*
|
||||
* \param pFtdCallback File transfer data callback
|
||||
* \param pFtcCallback File transfer control callback
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcInit(WdxcFtdCallback_t *pFtdCallback, WdxcFtcCallback_t *pFtcCallback)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
APP_TRACE_INFO0("WDXC: WdxcHandlerInit");
|
||||
|
||||
/* Initialize the control block */
|
||||
memset(&wdxcCb, 0, sizeof(wdxcCb));
|
||||
|
||||
for (i = 0; i < DM_CONN_MAX; i++)
|
||||
{
|
||||
wdxcCb.conn[i].fileHdl = WSF_EFS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/* Store callbacks */
|
||||
wdxcCb.pFtcCallback = pFtcCallback;
|
||||
wdxcCb.pFtdCallback = pFtdCallback;
|
||||
}
|
||||
Vendored
+141
@@ -0,0 +1,141 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile implementation.
|
||||
*
|
||||
* Copyright (c) 2013-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 WDXC_MAIN_H
|
||||
#define WDXC_MAIN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup WIRELESS_DATA_EXCHANGE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief WDXC Connection Control Block */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t *pHdlList; /*!< \brief Attrtibute Handles */
|
||||
|
||||
/* Operation in progress Control */
|
||||
uint16_t fileHdl; /*!< \brief File Handle */
|
||||
|
||||
/* File Listing Control */
|
||||
wsfEfsFileInfo_t *pFileList; /*!< \brief File Listing storage */
|
||||
uint16_t maxFiles; /*!< \brief Size of pFileList in number of wsfEfsFileInfo_t objects */
|
||||
uint16_t fileCount; /*!< \brief Number of files on peer device */
|
||||
uint16_t fDlPos; /*!< \brief Position in the download of file information */
|
||||
} wdxcConnCb_t;
|
||||
|
||||
/*! \brief WDXC Control Block */
|
||||
typedef struct
|
||||
{
|
||||
wdxcConnCb_t conn[DM_CONN_MAX]; /*!< \brief Connection control */
|
||||
WdxcFtdCallback_t *pFtdCallback; /*!< \brief File Transfer Data Application Callback */
|
||||
WdxcFtcCallback_t *pFtcCallback; /*!< \brief File Transfer Control Application Callback */
|
||||
} wdxcCb_t;
|
||||
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to abort a wdx operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file to abort operation on peer device
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendAbort(dmConnId_t connId, uint16_t fileHdl);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to erase a file.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file to erase on peer device
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendEraseFile(dmConnId_t connId, uint16_t fileHdl);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to verify a file.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file to verify on peer device
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendVerifyFile(dmConnId_t connId, uint16_t fileHdl);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to put a block of data into a file on the peer device
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file on peer device
|
||||
* \param offset The offset from the beginning of the file in bytes
|
||||
* \param len The number of bytes to put
|
||||
* \param fileSize The size of the file in bytes
|
||||
* \param type reserved
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendPutReq(dmConnId_t connId, uint16_t fileHdl, uint32_t offset,
|
||||
uint32_t len, uint32_t fileSize, uint8_t type);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to perform a get a block of data from a file on the peer device
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of file to verify on peer device
|
||||
* \param offset The offset from the beginning of the file in bytes
|
||||
* \param len The number of bytes to get
|
||||
* \param type reserved
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcFtcSendGetReq(dmConnId_t connId, uint16_t fileHdl, uint32_t offset, uint32_t len, uint8_t type);
|
||||
|
||||
/*! \} */ /* WIRELESS_DATA_EXCHANGE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* WDXC_MAIN_H */
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile client - Stream utility functions.
|
||||
*
|
||||
* Copyright (c) 2017-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 "util/wstr.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_efs.h"
|
||||
#include "util/bstream.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "app_api.h"
|
||||
#include "wdx_defs.h"
|
||||
#include "wdxc_api.h"
|
||||
#include "wdxc_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
External Variables
|
||||
**************************************************************************************************/
|
||||
extern wdxcCb_t wdxcCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a request to start a stream of a given file handle on the given connection.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param fileHdl Handle of the file.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcStreamStart(dmConnId_t connId, uint16_t fileHdl)
|
||||
{
|
||||
wdxcConnCb_t *pConnCb = &wdxcCb.conn[connId - 1];
|
||||
|
||||
/* Verify WDXC is Idle */
|
||||
if (pConnCb->fileHdl == WSF_EFS_INVALID_HANDLE)
|
||||
{
|
||||
pConnCb->fileHdl = fileHdl;
|
||||
|
||||
/* Send a get request with len set the MTU length (offset is ignored for streams) */
|
||||
WdxcFtcSendGetReq(connId, fileHdl, 0, AttGetMtu(connId), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Stop the active stream.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxcStreamStop(dmConnId_t connId)
|
||||
{
|
||||
wdxcConnCb_t *pConnCb = &wdxcCb.conn[connId - 1];
|
||||
|
||||
/* Send an abort to stop the stream */
|
||||
WdxcFtcSendAbort(connId, pConnCb->fileHdl);
|
||||
|
||||
/* Set file handle to invalid to indicate no file operation is in progress */
|
||||
pConnCb->fileHdl = WSF_EFS_INVALID_HANDLE;
|
||||
}
|
||||
Vendored
+163
@@ -0,0 +1,163 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile application interface.
|
||||
*
|
||||
* Copyright (c) 2013-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 WDXS_API_H
|
||||
#define WDXS_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
#include "wdx_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup WIRELESS_DATA_EXCHANGE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Size of RAM Media used by the application */
|
||||
#define WDXS_APP_RAM_MEDIA_SIZE 256
|
||||
|
||||
/*! \brief Device Model Name */
|
||||
#ifndef WDXS_DEVICE_MODEL
|
||||
#define WDXS_DEVICE_MODEL "WDXS App"
|
||||
#endif
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called at startup to configure WDXS authentication.
|
||||
*
|
||||
* \param reqLevel Level of authentication that is required for a client to use WDXS
|
||||
* \param pKey Authentication key (set to NULL if no authentication is required)
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsAuthenticationCfg(bool_t reqLevel, uint8_t *pKey);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle WSF events for WDXS.
|
||||
*
|
||||
* \param event event
|
||||
* \param pMsg message assiciated with event
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WSF Task Initialization for WDXS task.
|
||||
*
|
||||
* \param handlerId ID of the WDXS task
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsHandlerInit(wsfHandlerId_t handlerId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by application to notify the WDXS of ATT Events.
|
||||
*
|
||||
* \param pEvt Pointer to the ATT Event
|
||||
*
|
||||
* \return TRUE if the application should ignore the event, else FALSE.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t WdxsAttCback(attEvt_t *pEvt);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by application to notify the WDXS of DM Events.
|
||||
*
|
||||
* \param pEvt Pointer to the DM Event
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsProcDmMsg(dmEvt_t *pEvt);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the CCCD index used by the application for WDXS service characteristics.
|
||||
*
|
||||
* \param dcCccIdx Device Control CCCD index.
|
||||
* \param auCccIdx Authentication CCCD index.
|
||||
* \param ftcCccIdx File Transfer Control CCCD index.
|
||||
* \param ftdCccIdx File Transfer Data CCCD index.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsSetCccIdx(uint8_t dcCccIdx, uint8_t auCccIdx, uint8_t ftcCccIdx, uint8_t ftdCccIdx);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Registers the platform dependent Flash Media with the Embedded File System (EFS)
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsFlashMediaInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Registers the platform dependent OTA Media with the Embedded File System (EFS)
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsOtaMediaInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Resets the system.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsResetSystem(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize WDXS Device Configuration PHY.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsPhyInit(void);
|
||||
|
||||
/*! \} */ /* WIRELESS_DATA_EXCHANGE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WDXS_API_H */
|
||||
Vendored
+218
@@ -0,0 +1,218 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile implementation - Authentication.
|
||||
*
|
||||
* Copyright (c) 2013-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 "util/bstream.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_efs.h"
|
||||
#include "wsf_os.h"
|
||||
#include "sec_api.h"
|
||||
#include "svc_wdxs.h"
|
||||
#include "wdxs_api.h"
|
||||
#include "wdxs_main.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "app_api.h"
|
||||
|
||||
#if WDXS_AU_ENABLED == TRUE
|
||||
|
||||
/* WDXS Authentication Control Block */
|
||||
wdxsAuCb_t wdxsAuCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Transmit to authentication characteristic.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsAuSend(dmConnId_t connId)
|
||||
{
|
||||
APP_TRACE_INFO0("WDXS: AuSend");
|
||||
|
||||
/* if notification enabled */
|
||||
if (AttsCccEnabled(connId, wdxsCb.auCccIdx))
|
||||
{
|
||||
/* send notification */
|
||||
AttsHandleValueNtf(connId, WDXS_AU_HDL, wdxsAuCb.auMsgLen, wdxsAuCb.auMsgBuf);
|
||||
wdxsCb.txReadyMask &= ~(WDXS_TX_MASK_AU_BIT | WDXS_TX_MASK_READY_BIT);
|
||||
|
||||
wdxsAuCb.authState = WDXS_AU_STATE_WAIT_REPLY;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by WDXS event handler when the WSF Sec operation is complete.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsAuSecComplete(secAes_t *pAes)
|
||||
{
|
||||
uint8_t *p = wdxsAuCb.auMsgBuf;
|
||||
|
||||
/* Record the hash */
|
||||
memcpy(wdxsAuCb.auHash, pAes->pCiphertext, WDX_AU_HASH_LEN);
|
||||
|
||||
/* Build challenge message */
|
||||
UINT8_TO_BSTREAM(p, WDX_AU_OP_CHALLENGE);
|
||||
memcpy(p, wdxsAuCb.auRand, WDX_AU_RAND_LEN);
|
||||
wdxsAuCb.auMsgLen = WDX_AU_RAND_LEN + WDX_AU_HDR_LEN;
|
||||
|
||||
/* Update State */
|
||||
wdxsAuCb.authState = WDXS_AU_STATE_WAIT_REPLY;
|
||||
|
||||
/* Indicate TX Ready */
|
||||
wdxsCb.txReadyMask &= ~(WDXS_TX_MASK_AU_BIT | WDXS_TX_MASK_READY_BIT);
|
||||
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a request to start authentication.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsAuProcStart(dmConnId_t connId, uint8_t len, uint8_t *pValue)
|
||||
{
|
||||
/* Verify parameter length */
|
||||
if (len != WDX_AU_PARAM_LEN_START)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
/* Parse parameters */
|
||||
BSTREAM_TO_UINT8(wdxsAuCb.authLevel, pValue);
|
||||
BSTREAM_TO_UINT8(wdxsAuCb.authMode, pValue);
|
||||
|
||||
/* Generate random number */
|
||||
SecRand(wdxsAuCb.auRand, WDX_AU_RAND_LEN);
|
||||
|
||||
/* Encrypt the random number to create the hash */
|
||||
SecAes(wdxsAuCb.sessionKey, wdxsAuCb.auRand, wdxsCb.handlerId, connId, WDXS_EVT_AU_SEC_COMPLETE);
|
||||
|
||||
/* Update State */
|
||||
wdxsAuCb.authState = WDXS_AU_STATE_WAIT_SEC;
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a reply to the authentication challenge.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsAuProcReply(uint8_t len, uint8_t *pValue)
|
||||
{
|
||||
/* Verify parameter length */
|
||||
if (len != WDX_AU_PARAM_LEN_REPLY)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
if (wdxsAuCb.authState == WDXS_AU_STATE_WAIT_REPLY)
|
||||
{
|
||||
/* Verify [0-7] bytes of cipher text against what was sent by client */
|
||||
if (memcmp(wdxsAuCb.auHash, pValue, WDX_AU_HASH_LEN) == 0)
|
||||
{
|
||||
/* Successful challenge */
|
||||
wdxsAuCb.authState = WDXS_AU_STATE_AUTHORIZED;
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
return WDX_AU_ST_AUTH_FAILED;
|
||||
}
|
||||
|
||||
return WDX_AU_ST_INVALID_STATE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a write to the authentication characteristic.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsAuWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint8_t op;
|
||||
uint8_t status;
|
||||
|
||||
/* Sanity check message length */
|
||||
if (len < WDX_AU_HDR_LEN)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
/* Get Operation ID */
|
||||
BSTREAM_TO_UINT8(op, pValue);
|
||||
len -= WDX_AU_HDR_LEN;
|
||||
|
||||
APP_TRACE_INFO1("WDXS: AuWrite: op=%d", op);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case WDX_AU_OP_START:
|
||||
status = wdxsAuProcStart(connId, (uint8_t) len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_AU_OP_REPLY:
|
||||
status = wdxsAuProcReply((uint8_t) len, pValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = ATT_ERR_RANGE;
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called at startup to configure WDXS authentication.
|
||||
*
|
||||
* \param reqLevel Level of authentication that is required for a client to use WDXS
|
||||
* \param key Authentication key (set to NULL if no authentication is required)
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsAuthenticationCfg(bool_t reqLevel, uint8_t *pKey)
|
||||
{
|
||||
wdxsAuCb.reqAuthLevel = reqLevel;
|
||||
|
||||
if (pKey)
|
||||
{
|
||||
memcpy(wdxsAuCb.sessionKey, pKey, WDX_AU_KEY_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* WDXS_AU_ENABLED */
|
||||
Vendored
+608
@@ -0,0 +1,608 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile implementation - Device Configuration.
|
||||
*
|
||||
* Copyright (c) 2013-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 "util/wstr.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_efs.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_wdxs.h"
|
||||
#include "wdxs_api.h"
|
||||
#include "wdxs_main.h"
|
||||
#include "dm_api.h"
|
||||
#include "app_api.h"
|
||||
#include "app_hw.h"
|
||||
|
||||
#if WDXS_DC_ENABLED == TRUE
|
||||
|
||||
/* WDXS Device Configuration Control Block */
|
||||
wdxsDcCb_t wdxsDcCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send device configuration notification
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsDcSend(dmConnId_t connId)
|
||||
{
|
||||
APP_TRACE_INFO0("WDXS: DcSend");
|
||||
|
||||
/* if notification enabled */
|
||||
if (AttsCccEnabled(connId, wdxsCb.dcCccIdx))
|
||||
{
|
||||
/* send notification */
|
||||
AttsHandleValueNtf(connId, WDXS_DC_HDL, wdxsDcCb.dcMsgLen, wdxsDcCb.dcMsgBuf);
|
||||
wdxsCb.txReadyMask &= ~(WDXS_TX_MASK_DC_BIT | WDXS_TX_MASK_READY_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send update message for connection parameters.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsDcUpdateConnParam(dmConnId_t connId, uint8_t status)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
/* if update already waiting to be sent */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
|
||||
{
|
||||
return ATT_ERR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* build update to global buffer */
|
||||
p = wdxsDcCb.dcMsgBuf;
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_ID_CONN_PARAM);
|
||||
UINT8_TO_BSTREAM(p, status);
|
||||
UINT16_TO_BSTREAM(p, wdxsCb.connInterval);
|
||||
UINT16_TO_BSTREAM(p, wdxsCb.connLatency);
|
||||
UINT16_TO_BSTREAM(p, wdxsCb.supTimeout);
|
||||
wdxsDcCb.dcMsgLen = WDX_DC_LEN_CONN_PARAM + WDX_DC_HDR_LEN;
|
||||
|
||||
/* Indicate TX Ready */
|
||||
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
|
||||
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send update message for PHY.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsDcUpdatePhy(dmConnId_t connId, uint8_t status)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
/* if update already waiting to be sent */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
|
||||
{
|
||||
return ATT_ERR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* build update to global buffer */
|
||||
p = wdxsDcCb.dcMsgBuf;
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_ID_PHY);
|
||||
UINT8_TO_BSTREAM(p, status);
|
||||
UINT8_TO_BSTREAM(p, wdxsCb.txPhy);
|
||||
UINT8_TO_BSTREAM(p, wdxsCb.rxPhy);
|
||||
wdxsDcCb.dcMsgLen = WDX_DC_LEN_PHY + WDX_DC_HDR_LEN;
|
||||
|
||||
/* Indicate TX Ready */
|
||||
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
|
||||
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process Update Diagnostics Complete.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsDcUpdateDiagnosticsComplete(dmConnId_t connId)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
/* if update already waiting to be sent */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
|
||||
{
|
||||
return ATT_ERR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* build update to global buffer */
|
||||
p = wdxsDcCb.dcMsgBuf;
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_ID_DIAGNOSTICS_COMPLETE);
|
||||
wdxsDcCb.dcMsgLen = WDX_DC_LEN_DIAG_COMPLETE + WDX_DC_HDR_LEN;
|
||||
|
||||
/* Indicate TX Ready */
|
||||
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
|
||||
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process set connection paramter request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcSetConnParamReq(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
hciConnSpec_t connSpec;
|
||||
|
||||
/* verify parameter length */
|
||||
if (len != WDX_DC_LEN_CONN_PARAM_REQ)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
/* parse parameters */
|
||||
BSTREAM_TO_UINT16(connSpec.connIntervalMin, pValue);
|
||||
BSTREAM_TO_UINT16(connSpec.connIntervalMax, pValue);
|
||||
BSTREAM_TO_UINT16(connSpec.connLatency, pValue);
|
||||
BSTREAM_TO_UINT16(connSpec.supTimeout, pValue);
|
||||
|
||||
/* request update to connection parameters */
|
||||
DmConnUpdate(connId, &connSpec);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process set diagnostics.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcSetEnterDiadnostics(dmConnId_t connId)
|
||||
{
|
||||
return wdxsDcUpdateDiagnosticsComplete(connId);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a Set Disconnect request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcSetDisconnectReq(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
AppConnClose(connId);
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a Set Security request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcSetSecurityReq(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint8_t secLevel;
|
||||
|
||||
/* verify parameter length */
|
||||
if (len != WDX_DC_LEN_SEC_LEVEL)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
/* parse parameters */
|
||||
BSTREAM_TO_UINT8(secLevel, pValue);
|
||||
|
||||
/* Enable Security */
|
||||
if (DmConnSecLevel(connId) != DM_SEC_LEVEL_NONE)
|
||||
{
|
||||
DmSecSlaveReq(connId, secLevel);
|
||||
}
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a Set Service Changed request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcSetServiceChanged(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
/* TBD */
|
||||
return ATT_ERR_NOT_SUP;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a Set Delete Bonds request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcSetDeleteBonds(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
/* TBD */
|
||||
return ATT_ERR_NOT_SUP;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a Set Disconnect And Reset request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcSetDisconnectAndReset(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
wdxsDcCb.doReset = TRUE;
|
||||
AppConnClose(connId);
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a Get Connection Parameter request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcGetConnParam(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
return wdxsDcUpdateConnParam(connId, HCI_SUCCESS);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a Get Security Level request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcGetSecurityLevel(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
/* if update already waiting to be sent */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
|
||||
{
|
||||
return ATT_ERR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* build update to global buffer */
|
||||
p = wdxsDcCb.dcMsgBuf;
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_ID_CONN_SEC_LEVEL);
|
||||
UINT8_TO_BSTREAM(p, DmConnSecLevel(connId));
|
||||
wdxsDcCb.dcMsgLen = WDX_DC_LEN_SEC_LEVEL + WDX_DC_HDR_LEN;
|
||||
|
||||
/* Indicate TX Ready */
|
||||
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
|
||||
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a Get Current ATT MTU request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcGetAttMtu(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
/* if update already waiting to be sent */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
|
||||
{
|
||||
return ATT_ERR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* build update to global buffer */
|
||||
p = wdxsDcCb.dcMsgBuf;
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_ID_ATT_MTU);
|
||||
UINT16_TO_BSTREAM(p, AttGetMtu(connId));
|
||||
wdxsDcCb.dcMsgLen = WDX_DC_LEN_ATT_MTU + WDX_DC_HDR_LEN;
|
||||
|
||||
/* Indicate TX Ready */
|
||||
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
|
||||
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a Get Battery Level request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcGetBatteryLevel(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
/* if update already waiting to be sent */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
|
||||
{
|
||||
return ATT_ERR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* build update to global buffer */
|
||||
p = wdxsDcCb.dcMsgBuf;
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_ID_BATTERY_LEVEL);
|
||||
|
||||
/* add battery level */
|
||||
AppHwBattRead(p);
|
||||
wdxsDcCb.dcMsgLen = WDX_DC_LEN_BATTERY_LEVEL + WDX_DC_HDR_LEN;
|
||||
|
||||
/* Indicate TX Ready */
|
||||
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
|
||||
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a Get Device Model Number request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcGetDeviceModel(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
/* TODO: Add Device Model */
|
||||
char *pModelTxt = WDXS_DEVICE_MODEL;
|
||||
|
||||
/* if update already waiting to be sent */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
|
||||
{
|
||||
return ATT_ERR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* build update to global buffer */
|
||||
p = wdxsDcCb.dcMsgBuf;
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_ID_MODEL_NUMBER);
|
||||
/* Potential buffer overrun is intentional to zero out fixed length field */
|
||||
/* coverity[overrun-buffer-arg] */
|
||||
WstrnCpy((char *)p, pModelTxt, WDX_DC_LEN_DEVICE_MODEL);
|
||||
wdxsDcCb.dcMsgLen = WDX_DC_LEN_DEVICE_MODEL + WDX_DC_HDR_LEN;
|
||||
|
||||
/* Indicate TX Ready */
|
||||
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
|
||||
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a Get Firmware Revision request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcGetFirmwareRev(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
/* TODO: Add Firmware Revision */
|
||||
char *pFirmwareRev = "1.0";
|
||||
|
||||
/* if update already waiting to be sent */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
|
||||
{
|
||||
return ATT_ERR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* build update to global buffer */
|
||||
p = wdxsDcCb.dcMsgBuf;
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
|
||||
UINT8_TO_BSTREAM(p, WDX_DC_ID_FIRMWARE_REV);
|
||||
|
||||
/* Potential buffer overrun is intentional to zero out fixed length field */
|
||||
/* coverity[overrun-buffer-arg] */
|
||||
WstrnCpy((char *)p, pFirmwareRev, WDX_DC_LEN_FIRMWARE_REV);
|
||||
wdxsDcCb.dcMsgLen = WDX_DC_LEN_FIRMWARE_REV + WDX_DC_HDR_LEN;
|
||||
|
||||
/* Indicate TX Ready */
|
||||
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
|
||||
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a write to the device configuration characteristic.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsDcWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint8_t op;
|
||||
uint8_t id;
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
|
||||
/* sanity check on message length */
|
||||
if (len < WDX_DC_HDR_LEN)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
/* verify notifications are enabled */
|
||||
if (!AttsCccEnabled(connId, wdxsCb.dcCccIdx))
|
||||
{
|
||||
return ATT_ERR_CCCD;
|
||||
}
|
||||
|
||||
/* get operation and parameter ID */
|
||||
BSTREAM_TO_UINT8(op, pValue);
|
||||
BSTREAM_TO_UINT8(id, pValue);
|
||||
|
||||
/* skip over header (note pValue was incremented above) */
|
||||
len -= WDX_DC_HDR_LEN;
|
||||
|
||||
/* set operation */
|
||||
if (op == WDX_DC_OP_SET)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case WDX_DC_ID_CONN_UPDATE_REQ:
|
||||
status = wdxsDcSetConnParamReq(connId, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_DC_ID_DISCONNECT_REQ:
|
||||
status = wdxsDcSetDisconnectReq(connId, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_DC_ID_SECURITY_REQ:
|
||||
status = wdxsDcSetSecurityReq(connId, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_DC_ID_SERVICE_CHANGED:
|
||||
status = wdxsDcSetServiceChanged(connId, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_DC_ID_DELETE_BONDS:
|
||||
status = wdxsDcSetDeleteBonds(connId, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_DC_ID_ENTER_DIAGNOSTICS:
|
||||
status = wdxsDcSetEnterDiadnostics(connId);
|
||||
break;
|
||||
|
||||
case WDX_DC_ID_DISCONNECT_AND_RESET:
|
||||
status = wdxsDcSetDisconnectAndReset(connId, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_DC_ID_PHY_UPDATE_REQ:
|
||||
/* if device configuration phy callback registered */
|
||||
if (wdxsDcCb.phyWriteCback != NULL)
|
||||
{
|
||||
status = (*wdxsDcCb.phyWriteCback)(connId, op, id, len, pValue);
|
||||
break;
|
||||
}
|
||||
/* else fall through */
|
||||
|
||||
default:
|
||||
status = ATT_ERR_RANGE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* get operation */
|
||||
else if (op == WDX_DC_OP_GET)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case WDX_DC_ID_CONN_PARAM:
|
||||
status = wdxsDcGetConnParam(connId, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_DC_ID_CONN_SEC_LEVEL:
|
||||
status = wdxsDcGetSecurityLevel(connId, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_DC_ID_ATT_MTU:
|
||||
status = wdxsDcGetAttMtu(connId, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_DC_ID_BATTERY_LEVEL:
|
||||
status = wdxsDcGetBatteryLevel(connId, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_DC_ID_MODEL_NUMBER:
|
||||
status = wdxsDcGetDeviceModel(connId, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_DC_ID_FIRMWARE_REV:
|
||||
status = wdxsDcGetFirmwareRev(connId, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_DC_ID_PHY:
|
||||
/* if device configuration phy callback registered */
|
||||
if (wdxsDcCb.phyWriteCback != NULL)
|
||||
{
|
||||
status = (*wdxsDcCb.phyWriteCback)(connId, op, id, len, pValue);
|
||||
break;
|
||||
}
|
||||
/* else fall through */
|
||||
|
||||
default:
|
||||
status = ATT_ERR_RANGE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_RANGE;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Register a PHY write callback for the device configuration characteristic.
|
||||
*
|
||||
* \param cback PHY callback function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsDcPhyRegister(wdxsDcPhyWriteCback_t cback)
|
||||
{
|
||||
wdxsDcCb.phyWriteCback = cback;
|
||||
}
|
||||
|
||||
#endif /* WDXS_DC_ENABLED */
|
||||
Vendored
+518
@@ -0,0 +1,518 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile implementation - File Transfer.
|
||||
*
|
||||
* Copyright (c) 2013-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 <stddef.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_efs.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_wdxs.h"
|
||||
#include "wdxs_api.h"
|
||||
#include "wdxs_main.h"
|
||||
#include "dm_api.h"
|
||||
#include "app_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read data from file.
|
||||
*
|
||||
* \return TRUE if EOF.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static bool_t wdxsFileRead(uint16_t handle, uint32_t offset, uint32_t *pReadLen, uint8_t *pData)
|
||||
{
|
||||
bool_t eof = FALSE;
|
||||
uint32_t fileSize = WsfEfsGetFileSize(handle);
|
||||
|
||||
if (fileSize && (offset + *pReadLen > fileSize))
|
||||
{
|
||||
*pReadLen = fileSize - offset;
|
||||
eof = TRUE;
|
||||
}
|
||||
|
||||
WsfEfsGet(handle, offset, pData, (uint16_t) *pReadLen);
|
||||
|
||||
return eof;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Prepare for FTD data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsInitializeForPut(dmConnId_t connId, uint16_t handle)
|
||||
{
|
||||
uint32_t availableSize = WsfEfsGetFileMaxSize(handle);
|
||||
|
||||
/* verify file total length
|
||||
* verify offset+length is not more than total length
|
||||
*/
|
||||
if ((wdxsCb.ftTotalLen > availableSize) ||
|
||||
((wdxsCb.ftOffset + wdxsCb.ftLen) > wdxsCb.ftTotalLen))
|
||||
{
|
||||
return WDX_FTC_ST_INVALID_OP_DATA;
|
||||
}
|
||||
|
||||
/* Erase on offset of zero */
|
||||
if (wdxsCb.ftOffset == 0)
|
||||
{
|
||||
WsfEfsErase(handle);
|
||||
}
|
||||
|
||||
/* set up file put operation */
|
||||
wdxsCb.ftHandle = handle;
|
||||
wdxsCb.ftInProgress = WDX_FTC_OP_PUT_REQ;
|
||||
|
||||
return WDX_FTC_ST_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a file transfer control characteristic notification.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsFtcSend(dmConnId_t connId)
|
||||
{
|
||||
APP_TRACE_INFO0("WDXS: FTC Send");
|
||||
|
||||
/* if notification enabled */
|
||||
if (AttsCccEnabled(connId, wdxsCb.ftcCccIdx))
|
||||
{
|
||||
/* send notification */
|
||||
AttsHandleValueNtf(connId, WDXS_FTC_HDL, wdxsCb.ftcMsgLen, wdxsCb.ftcMsgBuf);
|
||||
wdxsCb.txReadyMask &= ~(WDXS_TX_MASK_FTC_BIT | WDXS_TX_MASK_READY_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a file transfer response message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsFtcSendRsp(dmConnId_t connId, uint8_t op, uint16_t handle, uint8_t status)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
/* there should not be another response message set up */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_FTC_BIT)
|
||||
{
|
||||
APP_TRACE_WARN0("WDXS: FTC message overflow");
|
||||
return;
|
||||
}
|
||||
|
||||
APP_TRACE_INFO3("WDXS: FTC SendRsp op=%d handle=%d status=%d", op, handle, status);
|
||||
|
||||
/* build message */
|
||||
p = wdxsCb.ftcMsgBuf;
|
||||
UINT8_TO_BSTREAM(p, op);
|
||||
UINT16_TO_BSTREAM(p, handle);
|
||||
|
||||
if (op != WDX_FTC_OP_ABORT && op != WDX_FTC_OP_EOF)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, status);
|
||||
}
|
||||
|
||||
if (op == WDX_FTC_OP_GET_RSP || op == WDX_FTC_OP_PUT_RSP)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, WDX_FTC_TRANSPORT_TYPE);
|
||||
UINT16_TO_BSTREAM(p, WDX_FTC_TRANSPORT_ID);
|
||||
}
|
||||
|
||||
wdxsCb.ftcMsgLen = (uint16_t) (p - wdxsCb.ftcMsgBuf);
|
||||
|
||||
/* Indicate TX Ready */
|
||||
wdxsCb.txReadyMask |= WDXS_TX_MASK_FTC_BIT;
|
||||
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a file get request.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void wdxsFtcProcGetReq(dmConnId_t connId, uint16_t handle, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
APP_TRACE_INFO2("WDXS: FTC GetReq handle=%d len=%d", handle, len);
|
||||
|
||||
/* verify operation not already in progress */
|
||||
if (wdxsCb.ftInProgress != WDX_FTC_OP_NONE)
|
||||
{
|
||||
status = WDX_FTC_ST_IN_PROGRESS;
|
||||
}
|
||||
else if ((WsfEfsGetFilePermissions(handle) & WSF_EFS_REMOTE_GET_PERMITTED) == 0)
|
||||
{
|
||||
status = WDX_FTC_ST_INVALID_OP_FILE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (handle == WDX_FLIST_HANDLE)
|
||||
{
|
||||
WdxsUpdateListing();
|
||||
}
|
||||
|
||||
/* parse operation data */
|
||||
BSTREAM_TO_UINT32(wdxsCb.ftOffset, pValue);
|
||||
BSTREAM_TO_UINT32(wdxsCb.ftLen, pValue);
|
||||
BSTREAM_TO_UINT8(wdxsCb.ftPrefXferType, pValue);
|
||||
|
||||
/* set up file get operation */
|
||||
wdxsCb.ftHandle = handle;
|
||||
wdxsCb.ftInProgress = WDX_FTC_OP_GET_REQ;
|
||||
|
||||
wdxsCb.txReadyMask |= WDXS_TX_MASK_FTD_BIT;
|
||||
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
|
||||
|
||||
status = WDX_FTC_ST_SUCCESS;
|
||||
}
|
||||
|
||||
/* send response */
|
||||
wdxsFtcSendRsp(connId, WDX_FTC_OP_GET_RSP, handle, status);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a file put request.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void wdxsFtcProcPutReq(dmConnId_t connId, uint16_t handle, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
/* verify operation not already in progress */
|
||||
if (wdxsCb.ftInProgress != WDX_FTC_OP_NONE)
|
||||
{
|
||||
status = WDX_FTC_ST_IN_PROGRESS;
|
||||
}
|
||||
/* verify permissions */
|
||||
else if ((WsfEfsGetFilePermissions(handle) & WSF_EFS_REMOTE_PUT_PERMITTED) == 0)
|
||||
{
|
||||
status = WDX_FTC_ST_INVALID_HANDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* parse operation data */
|
||||
wdxsCb.ftHandle = handle;
|
||||
BSTREAM_TO_UINT32(wdxsCb.ftOffset, pValue);
|
||||
BSTREAM_TO_UINT32(wdxsCb.ftLen, pValue);
|
||||
BSTREAM_TO_UINT32(wdxsCb.ftTotalLen, pValue);
|
||||
BSTREAM_TO_UINT8(wdxsCb.ftPrefXferType, pValue);
|
||||
|
||||
APP_TRACE_INFO3("WDXS: FTC PutReq handle=%d offset=%d, len=%d", handle, wdxsCb.ftOffset, wdxsCb.ftLen);
|
||||
|
||||
/* Initialize transfer*/
|
||||
status = wdxsInitializeForPut(connId, handle);
|
||||
}
|
||||
|
||||
APP_TRACE_INFO2("WDXS: FTC PutReq handle=%d status=%d", handle, status);
|
||||
|
||||
/* send response */
|
||||
wdxsFtcSendRsp(connId, WDX_FTC_OP_PUT_RSP, handle, status);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a file verify request.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void wdxsFtcProcVerifyReq(dmConnId_t connId, uint16_t handle)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
APP_TRACE_INFO1("WDXS: FTC VerifyReq: handle=%d", handle);
|
||||
|
||||
/* verify operation not already in progress */
|
||||
if (wdxsCb.ftInProgress != WDX_FTC_OP_NONE)
|
||||
{
|
||||
status = WDX_FTC_ST_IN_PROGRESS;
|
||||
}
|
||||
else if ((WsfEfsGetFilePermissions(handle) & WSF_EFS_REMOTE_VERIFY_PERMITTED) == 0)
|
||||
{
|
||||
status = WDX_FTC_ST_INVALID_HANDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Call the media specific validate command */
|
||||
status = WsfEfsMediaSpecificCommand(handle, WSF_EFS_VALIDATE_CMD, 0);
|
||||
}
|
||||
|
||||
/* send response */
|
||||
wdxsFtcSendRsp(connId, WDX_FTC_OP_VERIFY_RSP, handle, status);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a file erase request.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void wdxsFtcProcEraseReq(dmConnId_t connId, uint16_t handle)
|
||||
{
|
||||
uint8_t status = WDX_FTC_ST_SUCCESS;
|
||||
|
||||
APP_TRACE_INFO1("WDXS: FTC EraseReq: handle=%d", handle);
|
||||
|
||||
/* verify operation not already in progress */
|
||||
if (wdxsCb.ftInProgress != WDX_FTC_OP_NONE)
|
||||
{
|
||||
status = WDX_FTC_ST_IN_PROGRESS;
|
||||
}
|
||||
/* verify file handle */
|
||||
else if ((WsfEfsGetFilePermissions(handle) & WSF_EFS_REMOTE_ERASE_PERMITTED) == 0)
|
||||
{
|
||||
status = WDX_FTC_ST_INVALID_OP_FILE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* do file erase */
|
||||
WsfEfsErase(handle);
|
||||
}
|
||||
|
||||
/* send response */
|
||||
wdxsFtcSendRsp(connId, WDX_FTC_OP_ERASE_RSP, handle, status);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a file abort.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void wdxsFtcProcAbort(dmConnId_t connId, uint16_t handle)
|
||||
{
|
||||
APP_TRACE_INFO1("WDXS: FTC AbortReq: handle=%d", handle);
|
||||
|
||||
if (wdxsCb.ftInProgress != WDX_FTC_OP_NONE)
|
||||
{
|
||||
/* abort operation */
|
||||
if (WsfEfsGetFileType(handle) == WSF_EFS_FILE_TYPE_STREAM)
|
||||
{
|
||||
wdxsCb.ftInProgress = WDX_FTC_OP_ABORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
wdxsCb.ftInProgress = WDX_FTC_OP_NONE;
|
||||
}
|
||||
|
||||
wdxsCb.ftLen = 0;
|
||||
wdxsCb.ftOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a write to the file transfer data characteristic.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsFtdWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
/* verify put operation in progress */
|
||||
if (wdxsCb.ftInProgress != WDX_FTC_OP_PUT_REQ)
|
||||
{
|
||||
return ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
/* verify data length */
|
||||
if (len <= WDX_FTD_HDR_LEN)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
/* verify more data is expected */
|
||||
if (wdxsCb.ftLen >= len)
|
||||
{
|
||||
WsfEfsPut(wdxsCb.ftHandle, wdxsCb.ftOffset, pValue, len);
|
||||
|
||||
/* update remaining length of put request */
|
||||
wdxsCb.ftOffset += len;
|
||||
wdxsCb.ftLen -= len;
|
||||
|
||||
/* if end of put req reached */
|
||||
if (wdxsCb.ftLen == 0)
|
||||
{
|
||||
if (wdxsCb.ftOffset == wdxsCb.ftTotalLen)
|
||||
{
|
||||
/* Call the media specific WDXS Put Complete command */
|
||||
WsfEfsMediaSpecificCommand(wdxsCb.ftHandle, WSF_EFS_WDXS_PUT_COMPLETE_CMD, wdxsCb.ftTotalLen);
|
||||
}
|
||||
|
||||
/* put req done */
|
||||
wdxsCb.ftInProgress = WDX_FTC_OP_NONE;
|
||||
|
||||
/* send eof */
|
||||
wdxsFtcSendRsp(connId, WDX_FTC_OP_EOF, wdxsCb.ftHandle, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a write to the file transfer control characteristic.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsFtcWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint8_t op;
|
||||
uint16_t handle;
|
||||
|
||||
APP_TRACE_INFO1("WDXS: FTC Write: len=%d", len);
|
||||
|
||||
/* sanity check on message length */
|
||||
if (len < WDX_FTC_HDR_LEN + WDX_FTC_HANDLE_LEN)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
/* get operation and file handle */
|
||||
BSTREAM_TO_UINT8(op, pValue);
|
||||
BSTREAM_TO_UINT16(handle, pValue);
|
||||
|
||||
APP_TRACE_INFO2("WDXS: FTC Write: op=%d handle=%d", op, handle);
|
||||
|
||||
len -= WDX_FTC_HANDLE_LEN + WDX_FTC_HDR_LEN;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case WDX_FTC_OP_GET_REQ:
|
||||
wdxsFtcProcGetReq(connId, handle, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_FTC_OP_PUT_REQ:
|
||||
wdxsFtcProcPutReq(connId, handle, len, pValue);
|
||||
break;
|
||||
|
||||
case WDX_FTC_OP_VERIFY_REQ:
|
||||
wdxsFtcProcVerifyReq(connId, handle);
|
||||
break;
|
||||
|
||||
case WDX_FTC_OP_ERASE_REQ:
|
||||
wdxsFtcProcEraseReq(connId, handle);
|
||||
break;
|
||||
|
||||
case WDX_FTC_OP_ABORT:
|
||||
wdxsFtcProcAbort(connId, handle);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a file transfer data characteristic notification.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsFtdSend(dmConnId_t connId)
|
||||
{
|
||||
/* if notification enabled */
|
||||
if (AttsCccEnabled(connId, wdxsCb.ftdCccIdx))
|
||||
{
|
||||
uint8_t *pBuf;
|
||||
uint32_t readLen = AttGetMtu(connId) - ATT_VALUE_NTF_LEN;
|
||||
bool_t eof;
|
||||
uint8_t fileType = WsfEfsGetFileType(wdxsCb.ftHandle);
|
||||
|
||||
/* Check for abort when Streaming */
|
||||
if ((fileType == WSF_EFS_FILE_TYPE_STREAM) && (wdxsCb.ftInProgress == WDX_FTC_OP_ABORT))
|
||||
{
|
||||
eof = TRUE;
|
||||
readLen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
eof = FALSE;
|
||||
}
|
||||
|
||||
readLen = (readLen < wdxsCb.ftLen) ? readLen : wdxsCb.ftLen;
|
||||
|
||||
if (readLen && (pBuf = AttMsgAlloc((uint16_t)readLen, ATT_PDU_VALUE_NTF)) != NULL)
|
||||
{
|
||||
/* read data from file */
|
||||
eof = wdxsFileRead(wdxsCb.ftHandle, wdxsCb.ftOffset, &readLen, pBuf);
|
||||
|
||||
if (readLen > 0)
|
||||
{
|
||||
/* update stored offset and length (non-streaming file) */
|
||||
if (fileType == WSF_EFS_FILE_TYPE_BULK)
|
||||
{
|
||||
wdxsCb.ftLen -= readLen;
|
||||
wdxsCb.ftOffset += readLen;
|
||||
}
|
||||
|
||||
/* send notification */
|
||||
AttsHandleValueNtfZeroCpy(connId, WDXS_FTD_HDL, (uint16_t)readLen, pBuf);
|
||||
wdxsCb.txReadyMask &= ~(WDXS_TX_MASK_READY_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
AttMsgFree(pBuf, ATT_PDU_VALUE_NTF);
|
||||
}
|
||||
}
|
||||
|
||||
/* check if end of transfer reached */
|
||||
if (wdxsCb.ftLen == 0 || readLen == 0 || eof || wdxsCb.ftInProgress == WDX_FTC_OP_ABORT)
|
||||
{
|
||||
wdxsCb.ftInProgress = WDX_FTC_OP_NONE;
|
||||
wdxsCb.txReadyMask &= ~(WDXS_TX_MASK_FTD_BIT);
|
||||
}
|
||||
|
||||
if (eof)
|
||||
{
|
||||
/* send EOF */
|
||||
wdxsFtcSendRsp(connId, WDX_FTC_OP_EOF, wdxsCb.ftHandle, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+539
@@ -0,0 +1,539 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile implementation.
|
||||
*
|
||||
* Copyright (c) 2013-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 "util/wstr.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_efs.h"
|
||||
#include "wsf_os.h"
|
||||
#include "sec_api.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_wdxs.h"
|
||||
#include "wdxs_api.h"
|
||||
#include "wdxs_main.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "app_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! application control block */
|
||||
wdxsCb_t wdxsCb;
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! RAM File Media Configuration */
|
||||
#define WDXS_RAM_LOCATION ((uint32_t)WdxsRamBlock)
|
||||
#define WDXS_RAM_SIZE (WDX_FLIST_MAX_LEN + WDXS_APP_RAM_MEDIA_SIZE)
|
||||
#define WDXS_RAM_END (WDXS_RAM_LOCATION + WDXS_RAM_SIZE)
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Function Prototypes
|
||||
**************************************************************************************************/
|
||||
static uint8_t WdxsRamErase(uint32_t address, uint32_t size);
|
||||
static uint8_t WdxsRamRead(uint8_t *pBuf, uint32_t address, uint32_t size);
|
||||
static uint8_t WdxsRamWrite(const uint8_t *pBuf, uint32_t address, uint32_t size);
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Prototypes
|
||||
**************************************************************************************************/
|
||||
void WdxsAuSecComplete(secAes_t *pAes);
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Reserve RAM for use by the RAM EFS Media */
|
||||
static uint8_t WdxsRamBlock[WDXS_RAM_SIZE];
|
||||
|
||||
/*! EFS RAM Media Control Block */
|
||||
static const wsfEfsMedia_t WDXS_RamMediaCtrl =
|
||||
{
|
||||
WDXS_RAM_LOCATION,
|
||||
WDXS_RAM_LOCATION + WDXS_RAM_SIZE,
|
||||
1,
|
||||
NULL,
|
||||
WdxsRamErase,
|
||||
WdxsRamRead,
|
||||
WdxsRamWrite,
|
||||
NULL
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Erase function for the EFS RAM media.
|
||||
*
|
||||
* \return none.
|
||||
*
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t WdxsRamErase(uint32_t address, uint32_t size)
|
||||
{
|
||||
uint8_t *pMem = (uint8_t *) address;
|
||||
memset(pMem, 0xFF, size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Read function for the EFS RAM media.
|
||||
*
|
||||
* \return none.
|
||||
*
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t WdxsRamRead(uint8_t *pBuf, uint32_t address, uint32_t size)
|
||||
{
|
||||
uint8_t *pMem = (uint8_t *) address;
|
||||
memcpy(pBuf, pMem, size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Write function for the EFS RAM media.
|
||||
*
|
||||
* \return none.
|
||||
*
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t WdxsRamWrite(const uint8_t *pBuf, uint32_t address, uint32_t size)
|
||||
{
|
||||
uint8_t *pMem = (uint8_t *) address;
|
||||
memcpy(pMem, pBuf, size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Format file list information for the given file.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void wdxsFormatFileResource(uint8_t *pData, wsfEfsHandle_t handle)
|
||||
{
|
||||
UINT16_TO_BSTREAM(pData, handle);
|
||||
UINT8_TO_BSTREAM(pData, WsfEfsGetFileType(handle));
|
||||
UINT8_TO_BSTREAM(pData, WsfEfsGetFilePermissions(handle) & WSF_EFS_REMOTE_PERMISSIONS_MASK);
|
||||
UINT32_TO_BSTREAM(pData, WsfEfsGetFileSize(handle));
|
||||
WstrnCpy((char *)pData, WsfEfsGetFileName(handle), WSF_EFS_NAME_LEN);
|
||||
WstrnCpy((char *)pData+WSF_EFS_NAME_LEN, WsfEfsGetFileVersion(handle), WSF_EFS_VERSION_LEN);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Create the file list.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsUpdateListing(void)
|
||||
{
|
||||
uint8_t *pTmp;
|
||||
uint8_t header[WDX_FLIST_HDR_SIZE];
|
||||
uint8_t record[WDX_FLIST_RECORD_SIZE];
|
||||
uint32_t position = 0, totalSize = 0;
|
||||
uint32_t fileCount = 0;
|
||||
uint8_t i;
|
||||
|
||||
position = WDX_FLIST_HDR_SIZE;
|
||||
|
||||
for (i=0; i<WSF_EFS_MAX_FILES; i++)
|
||||
{
|
||||
if (WsfEfsGetFileByHandle(i) && (WsfEfsGetFilePermissions(i) & WSF_EFS_REMOTE_VISIBLE))
|
||||
{
|
||||
/* Update the total size and file count */
|
||||
totalSize += WsfEfsGetFileSize(i);
|
||||
fileCount++;
|
||||
|
||||
wdxsFormatFileResource(record, i);
|
||||
|
||||
/* Write the record */
|
||||
WsfEfsPut(WDX_FLIST_HANDLE, position, record, WDX_FLIST_RECORD_SIZE);
|
||||
position += WDX_FLIST_RECORD_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the header after calculating the total_size and file_count */
|
||||
pTmp = header;
|
||||
UINT8_TO_BSTREAM(pTmp, WDX_FLIST_FORMAT_VER);
|
||||
UINT16_TO_BSTREAM(pTmp, fileCount);
|
||||
UINT32_TO_BSTREAM(pTmp, totalSize);
|
||||
|
||||
/* Write the header */
|
||||
WsfEfsPut(WDX_FLIST_HANDLE, 0, header, WDX_FLIST_HDR_SIZE);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the CCCD index used by the application for WDXS service characteristics.
|
||||
*
|
||||
* \param dcCccIdx Device Control CCCD index.
|
||||
* \param auCccIdx Authentication CCCD index.
|
||||
* \param ftcCccIdx File Transfer Control CCCD index.
|
||||
* \param ftdCccIdx File Transfer Data CCCD index.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsSetCccIdx(uint8_t dcCccIdx, uint8_t auCccIdx, uint8_t ftcCccIdx, uint8_t ftdCccIdx)
|
||||
{
|
||||
wdxsCb.dcCccIdx = dcCccIdx;
|
||||
wdxsCb.auCccIdx = auCccIdx;
|
||||
wdxsCb.ftcCccIdx = ftcCccIdx;
|
||||
wdxsCb.ftdCccIdx = ftdCccIdx;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for proprietary service.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
#if WDXS_AU_ENABLED == TRUE
|
||||
|
||||
/* Require peer authentication before writing to any characteristic
|
||||
(except for the authentication characteristic) */
|
||||
if ((wdxsAuCb.reqAuthLevel != WDX_AU_LVL_NONE) && (handle != WDXS_AU_HDL))
|
||||
{
|
||||
if ((wdxsAuCb.authState != WDXS_AU_STATE_AUTHORIZED) || (wdxsAuCb.authLevel < wdxsAuCb.reqAuthLevel))
|
||||
{
|
||||
APP_TRACE_INFO1("WDXS: WriteCback unauthorized state=%d", wdxsAuCb.authState);
|
||||
return WDX_APP_AUTH_REQUIRED;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* WDXS_AU_ENABLED */
|
||||
|
||||
switch (handle)
|
||||
{
|
||||
#if WDXS_DC_ENABLED == TRUE
|
||||
/* Device configuration */
|
||||
case WDXS_DC_HDL:
|
||||
status = wdxsDcWrite(connId, len, pValue);
|
||||
break;
|
||||
#endif /* WDXS_DC_ENABLED */
|
||||
|
||||
/* File transfer control */
|
||||
case WDXS_FTC_HDL:
|
||||
status = wdxsFtcWrite(connId, len, pValue);
|
||||
break;
|
||||
|
||||
/* File transfer data */
|
||||
case WDXS_FTD_HDL:
|
||||
status = wdxsFtdWrite(connId, len, pValue);
|
||||
break;
|
||||
|
||||
#if WDXS_AU_ENABLED == TRUE
|
||||
/* Authentication */
|
||||
case WDXS_AU_HDL:
|
||||
status = wdxsAuWrite(connId, len, pValue);
|
||||
break;
|
||||
#endif /* WDXS_AU_ENABLED */
|
||||
|
||||
default:
|
||||
APP_TRACE_INFO1("WDXS: WriteCback unexpected handle=%d", handle);
|
||||
status = ATT_ERR_HANDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process TX data path
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void wdxsProcTxPath(void)
|
||||
{
|
||||
dmConnId_t connId;
|
||||
|
||||
/* Check for a connection */
|
||||
if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE)
|
||||
{
|
||||
/* Check if ready to transmit a message */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_READY_BIT)
|
||||
{
|
||||
|
||||
#if WDXS_DC_ENABLED == TRUE
|
||||
/* Device configuration */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
|
||||
{
|
||||
wdxsDcSend(connId);
|
||||
return;
|
||||
}
|
||||
#endif /* WDXS_DC_ENABLED */
|
||||
|
||||
/* File Transfer Control */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_FTC_BIT)
|
||||
{
|
||||
wdxsFtcSend(connId);
|
||||
return;
|
||||
}
|
||||
|
||||
#if WDXS_AU_ENABLED == TRUE
|
||||
/* Authentication */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_AU_BIT)
|
||||
{
|
||||
wdxsAuSend(connId);
|
||||
return;
|
||||
}
|
||||
#endif /* WDXS_AU_ENABLED */
|
||||
|
||||
/* File Transfer Data */
|
||||
if (wdxsCb.txReadyMask & WDXS_TX_MASK_FTD_BIT)
|
||||
{
|
||||
wdxsFtdSend(connId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief WSF event handler for application.
|
||||
*
|
||||
* \param event WSF event mask.
|
||||
* \param pMsg WSF message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
APP_TRACE_INFO1("WDXS: Task Handler Evt=%d", event);
|
||||
|
||||
if (event & WDXS_EVT_TX_PATH)
|
||||
{
|
||||
wdxsProcTxPath();
|
||||
}
|
||||
|
||||
#if WDXS_AU_ENABLED == TRUE
|
||||
|
||||
if (event & WDXS_EVT_AU_SEC_COMPLETE)
|
||||
{
|
||||
WdxsAuSecComplete((secAes_t*) pMsg);
|
||||
}
|
||||
|
||||
#endif /* WDXS_AU_ENABLED */
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by application to notify the WDXS of DM Events.
|
||||
*
|
||||
* \param pEvt Pointer to the DM Event
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsProcDmMsg(dmEvt_t *pEvt)
|
||||
{
|
||||
switch (pEvt->hdr.event)
|
||||
{
|
||||
case DM_CONN_CLOSE_IND:
|
||||
if (wdxsDcCb.doReset)
|
||||
{
|
||||
WdxsResetSystem();
|
||||
}
|
||||
break;
|
||||
|
||||
case DM_CONN_OPEN_IND:
|
||||
/* Initialize connection parameters */
|
||||
wdxsCb.txReadyMask = WDXS_TX_MASK_READY_BIT;
|
||||
wdxsCb.ftInProgress = WDX_FTC_OP_NONE;
|
||||
wdxsCb.ftLen = 0;
|
||||
wdxsCb.ftOffset = 0;
|
||||
#if WDXS_AU_ENABLED == TRUE
|
||||
wdxsAuCb.authLevel = WDX_AU_LVL_NONE;
|
||||
wdxsAuCb.authState = WDXS_AU_STATE_UNAUTHORIZED;
|
||||
#endif /* WDXS_AU_ENABLED */
|
||||
wdxsCb.connInterval = pEvt->connOpen.connInterval;
|
||||
wdxsCb.connLatency = pEvt->connOpen.connLatency;
|
||||
wdxsCb.supTimeout = pEvt->connOpen.supTimeout;
|
||||
wdxsCb.txPhy= HCI_PHY_LE_1M_BIT;
|
||||
wdxsCb.rxPhy = HCI_PHY_LE_1M_BIT;
|
||||
break;
|
||||
|
||||
case DM_CONN_UPDATE_IND:
|
||||
if (pEvt->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
wdxsCb.connInterval = pEvt->connUpdate.connInterval;
|
||||
wdxsCb.connLatency = pEvt->connUpdate.connLatency;
|
||||
wdxsCb.supTimeout = pEvt->connUpdate.supTimeout;
|
||||
}
|
||||
wdxsDcUpdateConnParam((dmConnId_t) pEvt->hdr.param, pEvt->hdr.status);
|
||||
break;
|
||||
|
||||
case DM_PHY_UPDATE_IND:
|
||||
if (pEvt->hdr.status == HCI_SUCCESS)
|
||||
{
|
||||
wdxsCb.txPhy = pEvt->phyUpdate.txPhy;
|
||||
wdxsCb.rxPhy = pEvt->phyUpdate.rxPhy;
|
||||
}
|
||||
wdxsDcUpdatePhy((dmConnId_t) pEvt->hdr.param, pEvt->hdr.status);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Called by application to notify the WDXS of ATT Events.
|
||||
*
|
||||
* \param pEvt Pointer to the ATT Event
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t WdxsAttCback(attEvt_t *pEvt)
|
||||
{
|
||||
if (pEvt->handle < WDXS_START_HDL || pEvt->handle > WDXS_END_HDL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
APP_TRACE_INFO2("WDXS: AttHook handle=%d event=%d", pEvt->handle, pEvt->hdr.event);
|
||||
|
||||
/* trigger tx data path on confirm */
|
||||
if (pEvt->hdr.event == ATTS_HANDLE_VALUE_CNF &&
|
||||
pEvt->hdr.status == ATT_SUCCESS)
|
||||
{
|
||||
wdxsCb.txReadyMask |= WDXS_TX_MASK_READY_BIT;
|
||||
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Application handler init function called during system initialization.
|
||||
*
|
||||
* \param handlerID WSF handler ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsHandlerInit(wsfHandlerId_t handlerId)
|
||||
{
|
||||
wsfEsfAttributes_t attr;
|
||||
|
||||
APP_TRACE_INFO0("WDXS: WdxsHandlerInit");
|
||||
|
||||
/* Initialize the control block */
|
||||
memset(&wdxsCb, 0, sizeof(wdxsCb));
|
||||
wdxsCb.txReadyMask = WDXS_TX_MASK_READY_BIT;
|
||||
|
||||
/* Store Handler ID */
|
||||
wdxsCb.handlerId = handlerId;
|
||||
|
||||
/* Initialize the device configuration control block */
|
||||
memset(&wdxsDcCb, 0, sizeof(wdxsDcCb));
|
||||
|
||||
/* Register the WDXS Service */
|
||||
SvcWdxsRegister(wdxsWriteCback);
|
||||
SvcWdxsAddGroup();
|
||||
|
||||
/* Initialize the embedded file system */
|
||||
WsfEfsInit();
|
||||
|
||||
/* Register the RAM Media */
|
||||
memset(WdxsRamBlock, 0xFF, sizeof(WdxsRamBlock));
|
||||
WsfEfsRegisterMedia(&WDXS_RamMediaCtrl, WDX_RAM_MEDIA);
|
||||
|
||||
/* Set attributes for the WDXS File List */
|
||||
attr.type = WSF_EFS_FILE_TYPE_BULK;
|
||||
attr.permissions = WSF_EFS_LOCAL_PUT_PERMITTED | WSF_EFS_REMOTE_GET_PERMITTED;
|
||||
WstrnCpy(attr.name, "Listing", WSF_EFS_NAME_LEN);
|
||||
WstrnCpy(attr.version, "1.0", WSF_EFS_VERSION_LEN);
|
||||
|
||||
/* Create a file in RAM to contain the list WDXS File List */
|
||||
WsfEfsAddFile(WDX_FLIST_MAX_LEN, WDX_RAM_MEDIA, &attr, WSF_EFS_FILE_OFFSET_ANY);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn WdxsOtaMediaInit
|
||||
*
|
||||
* \brief Registers the platform dependent OTA Media with the Embedded File System (EFS)
|
||||
*
|
||||
* \param None
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsOtaMediaInit(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn WdxsResetSystem
|
||||
*
|
||||
* \brief Resets the system.
|
||||
*
|
||||
* \param None
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsResetSystem(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn WdxsFlashMediaInit
|
||||
*
|
||||
* \brief Registers the platform dependent Flash Media with the Embedded File System (EFS)
|
||||
*
|
||||
* \param None
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsFlashMediaInit(void)
|
||||
{
|
||||
}
|
||||
Vendored
+327
@@ -0,0 +1,327 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile implementation.
|
||||
*
|
||||
* Copyright (c) 2013-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 WDXS_MAIN_H
|
||||
#define WDXS_MAIN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup WIRELESS_DATA_EXCHANGE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name WDXS Default Feature Set
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#ifndef WDXS_DC_ENABLED
|
||||
#define WDXS_DC_ENABLED TRUE
|
||||
#endif
|
||||
|
||||
#ifndef WDXS_AU_ENABLED
|
||||
#define WDXS_AU_ENABLED TRUE
|
||||
#endif
|
||||
|
||||
#ifndef WDXS_OTA_ENABLED
|
||||
#define WDXS_OTA_ENABLED TRUE
|
||||
#endif
|
||||
/**@}*/
|
||||
|
||||
/*! \brief Special length for streaming file */
|
||||
#define WDXS_STREAM_FILE_LEN 0xFFFFFFFF
|
||||
|
||||
/** \name WSF event types for application event handler
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDXS_EVT_TX_PATH 0x01 /*!< \brief Trigger tx data path */
|
||||
#define WDXS_EVT_AU_SEC_COMPLETE 0x02 /*!< \brief AU encryption of challenge ready */
|
||||
/**@}*/
|
||||
|
||||
/** \name TX Ready Mask Bits
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDXS_TX_MASK_READY_BIT (1<<0) /*!< \brief Ready bit */
|
||||
#define WDXS_TX_MASK_DC_BIT (1<<1) /*!< \brief DC bit */
|
||||
#define WDXS_TX_MASK_FTC_BIT (1<<2) /*!< \brief FTC bit */
|
||||
#define WDXS_TX_MASK_FTD_BIT (1<<3) /*!< \brief FTD bit */
|
||||
#define WDXS_TX_MASK_AU_BIT (1<<4) /*!< \brief AU bit */
|
||||
/**@}*/
|
||||
|
||||
/** \name Authentication states
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDXS_AU_STATE_UNAUTHORIZED 0x00 /*!< \brief Authentication has not started */
|
||||
#define WDXS_AU_STATE_HASHING 0x01 /*!< \brief Authentication hash is being calculated */
|
||||
#define WDXS_AU_STATE_WAIT_SEC 0x02 /*!< \brief Authentication challenge sent */
|
||||
#define WDXS_AU_STATE_WAIT_REPLY 0x03 /*!< \brief Authentication waiting for challenge reply */
|
||||
#define WDXS_AU_STATE_AUTHORIZED 0x04 /*!< \brief Authentication completed successfully */
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief WDXS Device Configuration PHY Write Callback */
|
||||
typedef uint8_t (*wdxsDcPhyWriteCback_t)(dmConnId_t connId, uint8_t op, uint8_t id, uint16_t len,
|
||||
uint8_t *pValue);
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief WDXS profile control block */
|
||||
typedef struct
|
||||
{
|
||||
wsfHandlerId_t handlerId; /*!< \brief WSF handler ID */
|
||||
uint8_t txReadyMask; /*!< \brief Bits indicate DC, FTC, FTD, and/or AU wish to transmit */
|
||||
|
||||
/* connection parameters */
|
||||
uint16_t connInterval; /*!< \brief connection interval */
|
||||
uint16_t connLatency; /*!< \brief connection latency */
|
||||
uint16_t supTimeout; /*!< \brief supervision timeout */
|
||||
|
||||
/* Phy parameters */
|
||||
uint8_t txPhy; /*!< \brief transmitter PHY */
|
||||
uint8_t rxPhy; /*!< \brief receiver PHY */
|
||||
|
||||
/* for file transfer */
|
||||
uint32_t ftOffset; /*!< \brief file data offset */
|
||||
uint32_t ftLen; /*!< \brief remaining data length for current operation */
|
||||
uint32_t ftTotalLen; /*!< \brief file total length */
|
||||
uint16_t ftHandle; /*!< \brief file handle */
|
||||
uint16_t ftcMsgLen; /*!< \brief message length */
|
||||
uint8_t ftcMsgBuf[ATT_DEFAULT_PAYLOAD_LEN]; /*!< \brief message buffer */
|
||||
uint8_t ftInProgress; /*!< \brief operation in progress */
|
||||
uint8_t ftPrefXferType; /*!< \brief Preferred transport type */
|
||||
|
||||
/* ccc index */
|
||||
uint8_t dcCccIdx; /*!< \brief device configuration ccc index */
|
||||
uint8_t auCccIdx; /*!< \brief authentication ccc index */
|
||||
uint8_t ftcCccIdx; /*!< \brief file transfer control ccc index */
|
||||
uint8_t ftdCccIdx; /*!< \brief file transfer data ccc index */
|
||||
} wdxsCb_t;
|
||||
|
||||
/*! \brief WDXS Device Configuration Control Block */
|
||||
typedef struct
|
||||
{
|
||||
uint16_t dcMsgLen; /*!< \brief message length */
|
||||
uint8_t dcMsgBuf[ATT_DEFAULT_PAYLOAD_LEN]; /*!< \brief message buffer */
|
||||
bool_t doReset; /*!< \brief Reset device after disconnect */
|
||||
wdxsDcPhyWriteCback_t phyWriteCback; /*!< \brief Device config PHY write callback */
|
||||
} wdxsDcCb_t;
|
||||
|
||||
/*! \brief WDXS Authentication Control Block */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t auMsgBuf[ATT_DEFAULT_PAYLOAD_LEN]; /*!< \brief message buffer */
|
||||
uint8_t auRand[WDX_AU_RAND_LEN]; /*!< \brief random challenge */
|
||||
uint8_t sessionKey[WDX_AU_KEY_LEN]; /*!< \brief session key */
|
||||
uint8_t auHash[WDX_AU_HASH_LEN]; /*!< \brief session key */
|
||||
uint16_t auMsgLen; /*!< \brief message length */
|
||||
uint8_t authLevel; /*!< \brief current authentication level */
|
||||
uint8_t authMode; /*!< \brief current authentication mode */
|
||||
uint8_t reqAuthLevel; /*!< \brief requested authentication level */
|
||||
uint8_t authState; /*!< \brief authentication protocol state */
|
||||
} wdxsAuCb_t;
|
||||
|
||||
/*! \brief WDXS event message union */
|
||||
typedef union
|
||||
{
|
||||
wsfMsgHdr_t hdr; /*!< header */
|
||||
dmEvt_t dm; /*!< DM event */
|
||||
attsCccEvt_t ccc; /*!< ATT CCC event */
|
||||
} wdxsMsg_t;
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name WDXS Control Block External Declaration
|
||||
*
|
||||
*/
|
||||
/**@{*/
|
||||
extern wdxsCb_t wdxsCb; /*!< \brief WDXS control block */
|
||||
extern wdxsAuCb_t wdxsAuCb; /*!< \brief WDXS AU control block */
|
||||
extern wdxsDcCb_t wdxsDcCb; /*!< \brief WDXS DC control block */
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Global Function Prototypes
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send device configuration notification
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsDcSend(dmConnId_t connId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a file transfer control characteristic notification.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsFtcSend(dmConnId_t connId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a file transfer data characteristic notification.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsFtdSend(dmConnId_t connId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Transmit to authentication characteristic.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsAuSend(dmConnId_t connId);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a write to the device configuration characteristic.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param len Length to write.
|
||||
* \param pValue value to write.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsDcWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a write to the file transfer control characteristic.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param len Length to write.
|
||||
* \param pValue Value to write.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsFtcWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a write to the file transfer data characteristic.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param len Length to write.
|
||||
* \param pValue Value to write.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsFtdWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a write to the authentication characteristic.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param len Length to write.
|
||||
* \param pValue Value to write
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsAuWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send update message for connection parameters.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param status Update status.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsDcUpdateConnParam(dmConnId_t connId, uint8_t status);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send update message for PHY.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param status Update status.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t wdxsDcUpdatePhy(dmConnId_t connId, uint8_t status);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Register a PHY write callback for the device configuration characteristic.
|
||||
*
|
||||
* \param cback PHY callback function.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsDcPhyRegister(wdxsDcPhyWriteCback_t cback);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Create the file list.
|
||||
*
|
||||
* \return none.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsUpdateListing(void);
|
||||
|
||||
/*! \} */ /* WIRELESS_DATA_EXCHANGE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WDXS_MAIN_H */
|
||||
Vendored
+147
@@ -0,0 +1,147 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile implementation - Device PHY Configuration.
|
||||
*
|
||||
* Copyright (c) 2013-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 "util/wstr.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_efs.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_wdxs.h"
|
||||
#include "wdxs_api.h"
|
||||
#include "wdxs_main.h"
|
||||
#include "dm_api.h"
|
||||
#include "app_api.h"
|
||||
#include "app_hw.h"
|
||||
|
||||
#if WDXS_DC_ENABLED == TRUE
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process set PHY request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcSetPhyReq(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint8_t allPhys;
|
||||
uint8_t txPhys;
|
||||
uint8_t rxPhys;
|
||||
uint16_t phyOptions;
|
||||
|
||||
/* verify parameter length */
|
||||
if (len != WDX_DC_LEN_PHY_UPDATE_REQ)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
/* parse parameters */
|
||||
BSTREAM_TO_UINT8(allPhys, pValue);
|
||||
BSTREAM_TO_UINT8(txPhys, pValue);
|
||||
BSTREAM_TO_UINT8(rxPhys, pValue);
|
||||
BSTREAM_TO_UINT16(phyOptions, pValue);
|
||||
|
||||
/* request update to PHY */
|
||||
DmSetPhy(connId, allPhys, txPhys, rxPhys, phyOptions);
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a Get PHY request.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcGetPhy(dmConnId_t connId, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
return wdxsDcUpdatePhy(connId, HCI_SUCCESS);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a PHY write to the device configuration characteristic.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsDcPhyWrite(dmConnId_t connId, uint8_t op, uint8_t id, uint16_t len, uint8_t *pValue)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
/* set operation */
|
||||
if (op == WDX_DC_OP_SET)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case WDX_DC_ID_PHY_UPDATE_REQ:
|
||||
status = wdxsDcSetPhyReq(connId, len, pValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = ATT_ERR_RANGE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* get operation */
|
||||
else if (op == WDX_DC_OP_GET)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case WDX_DC_ID_PHY:
|
||||
status = wdxsDcGetPhy(connId, len, pValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = ATT_ERR_RANGE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_RANGE;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize WDXS Device Configuration PHY.
|
||||
*
|
||||
* \param None
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WdxsPhyInit(void)
|
||||
{
|
||||
/* register device configuration phy write callback */
|
||||
wdxsDcPhyRegister(wdxsDcPhyWrite);
|
||||
}
|
||||
|
||||
#endif /* WDXS_DC_ENABLED */
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile implementation - Stream Example.
|
||||
*
|
||||
* Copyright (c) 2013-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 "util/wstr.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_efs.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_wdxs.h"
|
||||
#include "wdxs_api.h"
|
||||
#include "wdxs_main.h"
|
||||
#include "wdxs_stream.h"
|
||||
#include "dm_api.h"
|
||||
#include "att_api.h"
|
||||
#include "app_api.h"
|
||||
|
||||
/*! Type of waveform to output from the Example Stream */
|
||||
static uint8_t wdxsStreamWaveform = WDXS_STREAM_WAVEFORM_SINE;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*
|
||||
* Note: This file contains an example of creating Wireless Data Exchange
|
||||
* (WDXS) Streams. WDXS Streams are implemented as virtual Physical Media in
|
||||
* the Embedded File System (EFS). A Stream can be created in three steps:
|
||||
*
|
||||
* Step 1: Create a FileMedia_t (EFS Media Control structure) for the stream
|
||||
* containing the read function created in step 2.
|
||||
*
|
||||
* Step 2: Implement a read function for the stream. The WDXS and EFS will
|
||||
* call the read function to get data from the stream.
|
||||
*
|
||||
* Step 3: Register the media with the EFS, and add a file to the embedded
|
||||
* file system that uses the media created in step 2.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/* Step 1: Media Control Block */
|
||||
/*************************************************************************************************/
|
||||
|
||||
/* Prototype of stream read function */
|
||||
static uint8_t wdxsStreamRead(uint8_t *pBuf, uint32_t address, uint32_t len);
|
||||
|
||||
/* Example media control structure for a stream */
|
||||
static const wsfEfsMedia_t WDXS_StreamMedia =
|
||||
{
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
wdxsStreamRead,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/* Step 2: Read Function */
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Example of a media read function that generates a Sine Wave.
|
||||
*
|
||||
* \param pBuf buffer to hold stream data.
|
||||
* \param address unused in streams.
|
||||
* \param len size of pBuf in bytes.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsSineRead(uint8_t *pBuf, uint32_t address, uint32_t len)
|
||||
{
|
||||
static int8_t incr = 1;
|
||||
static uint8_t dataVal = 0;
|
||||
|
||||
/* Build data in sine waveform */
|
||||
memset(pBuf, dataVal, len);
|
||||
|
||||
if (dataVal <= 127)
|
||||
{
|
||||
incr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
incr--;
|
||||
}
|
||||
|
||||
dataVal += (incr / 2);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Example of a media read function that generates a Step Wave.
|
||||
*
|
||||
* \param pBuf buffer to hold stream data.
|
||||
* \param address unused in streams.
|
||||
* \param len size of pBuf in bytes.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsStepRead(uint8_t *pBuf, uint32_t address, uint32_t len)
|
||||
{
|
||||
static int8_t count = 0;
|
||||
static int8_t incr = 25;
|
||||
static uint8_t dataVal = 0;
|
||||
|
||||
/* Build data in step waveform */
|
||||
memset(pBuf, dataVal, len);
|
||||
|
||||
if (count++ == 5)
|
||||
{
|
||||
count = 0;
|
||||
dataVal += incr;
|
||||
|
||||
if (dataVal == 0)
|
||||
incr = 25;
|
||||
|
||||
if (dataVal == 250)
|
||||
incr = -25;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Example of a media read function that generates a Sawtooth Wave.
|
||||
*
|
||||
* \param pBuf buffer to hold stream data.
|
||||
* \param address unused in streams.
|
||||
* \param len size of pBuf in bytes.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsSawtoothRead(uint8_t *pBuf, uint32_t address, uint32_t len)
|
||||
{
|
||||
static int8_t incr = 1;
|
||||
static uint8_t dataVal = 0;
|
||||
uint32_t i;
|
||||
|
||||
/* Build data in sawtooth waveform */
|
||||
for (i=0; i<len; i++)
|
||||
{
|
||||
*pBuf++ = dataVal;
|
||||
dataVal += incr;
|
||||
|
||||
if (dataVal == 0)
|
||||
incr = 1;
|
||||
else if (dataVal == 255)
|
||||
incr = -1;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Example of a media read function.
|
||||
*
|
||||
* \param pBuf buffer to hold stream data.
|
||||
* \param address unused in streams.
|
||||
* \param len size of pBuf in bytes.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wdxsStreamRead(uint8_t *pBuf, uint32_t address, uint32_t len)
|
||||
{
|
||||
switch(wdxsStreamWaveform)
|
||||
{
|
||||
case WDXS_STREAM_WAVEFORM_SINE:
|
||||
wdxsSineRead(pBuf, address, len);
|
||||
break;
|
||||
|
||||
case WDXS_STREAM_WAVEFORM_STEP:
|
||||
wdxsStepRead(pBuf, address, len);
|
||||
break;
|
||||
|
||||
case WDXS_STREAM_WAVEFORM_SAWTOOTH:
|
||||
wdxsSawtoothRead(pBuf, address, len);
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/* Step 3: Register the stream media and adding the stream file. */
|
||||
/*************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Example of creating a WDXS stream.
|
||||
*
|
||||
* \param none
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsStreamInit(void)
|
||||
{
|
||||
wsfEsfAttributes_t attr;
|
||||
|
||||
/* Register the media for the stream */
|
||||
WsfEfsRegisterMedia(&WDXS_StreamMedia, WDX_STREAM_MEDIA);
|
||||
|
||||
/* Set the attributes for the stream */
|
||||
attr.permissions = WSF_EFS_REMOTE_VISIBLE | WSF_EFS_REMOTE_GET_PERMITTED;
|
||||
attr.type = WSF_EFS_FILE_TYPE_STREAM;
|
||||
|
||||
/* Potential buffer overrun is intentional to zero out fixed length field */
|
||||
/* coverity[overrun-buffer-arg] */
|
||||
WstrnCpy(attr.name, "Stream", WSF_EFS_NAME_LEN);
|
||||
/* coverity[overrun-buffer-arg] */
|
||||
WstrnCpy(attr.version, "1.0", WSF_EFS_VERSION_LEN);
|
||||
|
||||
/* Add a file for the stream */
|
||||
WsfEfsAddFile(0, WDX_STREAM_MEDIA, &attr, 0);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Changes the type of waveform transmitted by the stream.
|
||||
*
|
||||
* \param type - Identifier of the waveform
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsSetStreamWaveform(uint8_t type)
|
||||
{
|
||||
if (type <= WDXS_STREAM_WAVEFORM_SAWTOOTH)
|
||||
{
|
||||
wdxsStreamWaveform = type;
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Wireless Data Exchange profile implementation - Stream Example.
|
||||
*
|
||||
* Copyright (c) 2013-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 WDXS_STREAM_H
|
||||
#define WDXS_STREAM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup WIRELESS_DATA_EXCHANGE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Constant Definitions
|
||||
**************************************************************************************************/
|
||||
|
||||
/** \name WDXS Stream Waveform Types
|
||||
* Type of waveform to output from the Example Stream
|
||||
*/
|
||||
/**@{*/
|
||||
#define WDXS_STREAM_WAVEFORM_SINE 0
|
||||
#define WDXS_STREAM_WAVEFORM_STEP 1
|
||||
#define WDXS_STREAM_WAVEFORM_SAWTOOTH 2
|
||||
/**@}*/
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Example of creating a WDXS stream.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsStreamInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Changes the type of waveform transmitted by the stream.
|
||||
*
|
||||
* \param type - Identifier of the waveform
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wdxsSetStreamWaveform(uint8_t type);
|
||||
|
||||
/*! \} */ /* WIRELESS_DATA_EXCHANGE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WDXS_STREAM_H */
|
||||
|
||||
Vendored
+73
@@ -0,0 +1,73 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Arm Ltd. proprietary profile client.
|
||||
*
|
||||
* 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 WPC_API_H
|
||||
#define WPC_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup ARM_LTD_PROPRIETARY_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Arm Ltd. proprietary service P1 enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
WPC_P1_DAT_HDL_IDX, /*!< \brief Proprietary data */
|
||||
WPC_P1_NA_CCC_HDL_IDX, /*!< \brief Proprietary data client characteristic configuration descriptor */
|
||||
WPC_P1_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Arm Ltd. proprietary service P1.
|
||||
* Parameter pHdlList must point to an array of length \ref WPC_P1_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WpcP1Discover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*! \} */ /* ARM_LTD_PROPRIETARY_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* WPC_API_H */
|
||||
Vendored
+88
@@ -0,0 +1,88 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Arm Ltd. proprietary profile client.
|
||||
*
|
||||
* 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_assert.h"
|
||||
#include "util/bstream.h"
|
||||
#include "app_api.h"
|
||||
#include "wpc_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*!
|
||||
* Arm Ltd. proprietary service P1
|
||||
*/
|
||||
|
||||
/* UUIDs */
|
||||
static const uint8_t wpcP1SvcUuid[] = {ATT_UUID_P1_SERVICE}; /*! Proprietary service P1 */
|
||||
static const uint8_t wpcD1ChUuid[] = {ATT_UUID_D1_DATA}; /*! Proprietary data D1 */
|
||||
|
||||
/* Characteristics for discovery */
|
||||
|
||||
/*! Proprietary data */
|
||||
static const attcDiscChar_t wpcP1Dat =
|
||||
{
|
||||
wpcD1ChUuid,
|
||||
ATTC_SET_REQUIRED | ATTC_SET_UUID_128
|
||||
};
|
||||
|
||||
/*! Proprietary data descriptor */
|
||||
static const attcDiscChar_t wpcP1datCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *wpcP1DiscCharList[] =
|
||||
{
|
||||
&wpcP1Dat, /*! Proprietary data */
|
||||
&wpcP1datCcc /*! Proprietary data descriptor */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(WPC_P1_HDL_LIST_LEN == ((sizeof(wpcP1DiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Arm Ltd. proprietary service P1.
|
||||
* Parameter pHdlList must point to an array of length WPC_P1_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WpcP1Discover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_128_UUID_LEN, (uint8_t *) wpcP1SvcUuid,
|
||||
WPC_P1_HDL_LIST_LEN, (attcDiscChar_t **) wpcP1DiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
Vendored
+89
@@ -0,0 +1,89 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Weight Scale profile client.
|
||||
*
|
||||
* 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 WSPC_API_H
|
||||
#define WSPC_API_H
|
||||
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup WEIGHT_SCALE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Weight Scale service enumeration of handle indexes of characteristics to be discovered */
|
||||
enum
|
||||
{
|
||||
WSPC_WSS_WSM_HDL_IDX, /*!< \brief Weight scale measurement */
|
||||
WSPC_WSS_WSM_CCC_HDL_IDX, /*!< \brief Weight scale measurement CCC descriptor */
|
||||
WSPC_WSS_WSF_HDL_IDX, /*!< \brief Weight scale feature */
|
||||
WSPC_WSS_HDL_LIST_LEN /*!< \brief Handle list length */
|
||||
};
|
||||
|
||||
/**************************************************************************************************
|
||||
Function Declarations
|
||||
**************************************************************************************************/
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Weight Scale service.
|
||||
* Parameter pHdlList must point to an array of length \ref WSPC_WSS_HDL_LIST_LEN.
|
||||
* If discovery is successful the handles of discovered characteristics and
|
||||
* descriptors will be set in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WspcWssDiscover(dmConnId_t connId, uint16_t *pHdlList);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length \ref WSPC_WSS_HDL_LIST_LEN.
|
||||
* If the ATT handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return \ref ATT_SUCCESS if handle is found, \ref ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t WspcWssValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg);
|
||||
|
||||
/*! \} */ /* WEIGHT_SCALE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* WSPC_API_H */
|
||||
Vendored
+191
@@ -0,0 +1,191 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Weight Scale profile collector.
|
||||
*
|
||||
* 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_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "svc_ch.h"
|
||||
#include "app_api.h"
|
||||
#include "wspc_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*!
|
||||
* Weight Scale service characteristics for discovery
|
||||
*/
|
||||
|
||||
/*! Weight scale measurement */
|
||||
static const attcDiscChar_t wspcWssWsm =
|
||||
{
|
||||
attWmChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! Weight scale measurement CCC descriptor */
|
||||
static const attcDiscChar_t wspcWssWsmCcc =
|
||||
{
|
||||
attCliChCfgUuid,
|
||||
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
|
||||
};
|
||||
|
||||
/*! Weight scale feature */
|
||||
static const attcDiscChar_t wspcWssWsf =
|
||||
{
|
||||
attWsfChUuid,
|
||||
ATTC_SET_REQUIRED
|
||||
};
|
||||
|
||||
/*! List of characteristics to be discovered; order matches handle index enumeration */
|
||||
static const attcDiscChar_t *wspcWssDiscCharList[] =
|
||||
{
|
||||
&wspcWssWsm, /*! Weight scale measurement */
|
||||
&wspcWssWsmCcc, /*! Weight scale measurement CCC descriptor */
|
||||
&wspcWssWsf /*! Weight scale feature */
|
||||
};
|
||||
|
||||
/* sanity check: make sure handle list length matches characteristic list length */
|
||||
WSF_CT_ASSERT(WSPC_WSS_HDL_LIST_LEN == ((sizeof(wspcWssDiscCharList) / sizeof(attcDiscChar_t *))));
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Parse a weight scale measurement.
|
||||
*
|
||||
* \param pValue Pointer to buffer containing value.
|
||||
* \param len length of buffer.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void wspcWssParseWsm(uint8_t *pValue, uint16_t len)
|
||||
{
|
||||
uint8_t flags;
|
||||
uint16_t weight;
|
||||
uint16_t year;
|
||||
uint8_t month, day, hour, min, sec;
|
||||
uint16_t minLen = CH_WSM_FLAGS_LEN + CH_WSM_MEAS_LEN;
|
||||
|
||||
/* Suppress unused variable compile warning */
|
||||
(void)month; (void)day; (void)hour; (void)min; (void)sec; (void)year; (void)weight;
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
/* get flags */
|
||||
BSTREAM_TO_UINT8(flags, pValue);
|
||||
|
||||
/* determine expected minimum length based on flags */
|
||||
if (flags & CH_WSM_FLAG_TIMESTAMP)
|
||||
{
|
||||
minLen += CH_WSM_TIMESTAMP_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
/* verify length */
|
||||
if (len < minLen)
|
||||
{
|
||||
APP_TRACE_INFO2("Weight Scale meas len:%d minLen:%d", len, minLen);
|
||||
return;
|
||||
}
|
||||
|
||||
/* weight */
|
||||
BSTREAM_TO_UINT16(weight, pValue);
|
||||
if (flags & CH_WSM_FLAG_UNITS_LBS)
|
||||
{
|
||||
APP_TRACE_INFO2(" Weight: %d.%02d", (weight / 100), (weight % 100));
|
||||
}
|
||||
else /* CH_WSM_FLAG_UNITS_KG */
|
||||
{
|
||||
APP_TRACE_INFO2(" Weight: %d.%03d", (weight / 200), ((weight % 200) * 5));
|
||||
}
|
||||
|
||||
/* timestamp */
|
||||
if (flags & CH_WSM_FLAG_TIMESTAMP)
|
||||
{
|
||||
BSTREAM_TO_UINT16(year, pValue);
|
||||
BSTREAM_TO_UINT8(month, pValue);
|
||||
BSTREAM_TO_UINT8(day, pValue);
|
||||
BSTREAM_TO_UINT8(hour, pValue);
|
||||
BSTREAM_TO_UINT8(min, pValue);
|
||||
BSTREAM_TO_UINT8(sec, pValue);
|
||||
APP_TRACE_INFO3(" Date: %d/%d/%d", month, day, year);
|
||||
APP_TRACE_INFO3(" Time: %02d:%02d:%02d", hour, min, sec);
|
||||
}
|
||||
|
||||
APP_TRACE_INFO1(" Flags:0x%02x", flags);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Perform service and characteristic discovery for Weight Scale service. Parameter
|
||||
* pHdlList must point to an array of length WSPC_WSS_HDL_LIST_LEN. If discovery is
|
||||
* successful the handles of discovered characteristics and descriptors will be set
|
||||
* in pHdlList.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param pHdlList Characteristic handle list.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WspcWssDiscover(dmConnId_t connId, uint16_t *pHdlList)
|
||||
{
|
||||
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attWssSvcUuid,
|
||||
WSPC_WSS_HDL_LIST_LEN, (attcDiscChar_t **) wspcWssDiscCharList, pHdlList);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Process a value received in an ATT read response, notification, or indication
|
||||
* message. Parameter pHdlList must point to an array of length WSPC_WSS_HDL_LIST_LEN.
|
||||
* If the attribute handle of the message matches a handle in the handle list the value
|
||||
* is processed, otherwise it is ignored.
|
||||
*
|
||||
* \param pHdlList Characteristic handle list.
|
||||
* \param pMsg ATT callback message.
|
||||
*
|
||||
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t WspcWssValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
|
||||
{
|
||||
uint8_t status = ATT_SUCCESS;
|
||||
|
||||
/* weight scale measurement */
|
||||
if (pMsg->handle == pHdlList[WSPC_WSS_WSM_HDL_IDX])
|
||||
{
|
||||
APP_TRACE_INFO0("Weight measurement");
|
||||
|
||||
/* parse value */
|
||||
wspcWssParseWsm(pMsg->pValue, pMsg->valueLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ATT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
Vendored
+67
@@ -0,0 +1,67 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Weight Scale profile sensor.
|
||||
*
|
||||
* 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 WSPS_API_H
|
||||
#define WSPS_API_H
|
||||
|
||||
#include "wsf_timer.h"
|
||||
#include "att_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup WEIGHT_SCALE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Weight scale measurement complete.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param wsmCccIdx Index of weight scale measurement CCC descriptor in CCC descriptor
|
||||
* handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WspsMeasComplete(dmConnId_t connId, uint8_t wsmCccIdx);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the weight scale measurement flags.
|
||||
*
|
||||
* \param flags Weight scale measurement flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WspsSetWsmFlags(uint8_t flags);
|
||||
|
||||
/*! \} */ /* WEIGHT_SCALE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* WSPS_API_H */
|
||||
Vendored
+128
@@ -0,0 +1,128 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Weight Scale profile sensor.
|
||||
*
|
||||
* 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 "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "svc_ch.h"
|
||||
#include "svc_wss.h"
|
||||
#include "app_api.h"
|
||||
#include "app_hw.h"
|
||||
#include "wsps_api.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
static struct
|
||||
{
|
||||
appWsm_t wsm; /* weight scale measurement */
|
||||
uint8_t wsmFlags; /* flags */
|
||||
} wspsCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Build a weight scale measurement characteristic.
|
||||
*
|
||||
* \param pBuf Pointer to buffer to hold the built weight scale measurement characteristic.
|
||||
* \param pWsm Weight measurement values.
|
||||
*
|
||||
* \return Length of pBuf in bytes.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t wspsBuildWsm(uint8_t *pBuf, appWsm_t *pWsm)
|
||||
{
|
||||
uint8_t *p = pBuf;
|
||||
uint8_t flags = pWsm->flags;
|
||||
|
||||
/* flags */
|
||||
UINT8_TO_BSTREAM(p, flags);
|
||||
|
||||
/* measurement */
|
||||
UINT16_TO_BSTREAM(p, pWsm->weight);
|
||||
|
||||
/* time stamp */
|
||||
if (flags & CH_WSM_FLAG_TIMESTAMP)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pWsm->timestamp.year);
|
||||
UINT8_TO_BSTREAM(p, pWsm->timestamp.month);
|
||||
UINT8_TO_BSTREAM(p, pWsm->timestamp.day);
|
||||
UINT8_TO_BSTREAM(p, pWsm->timestamp.hour);
|
||||
UINT8_TO_BSTREAM(p, pWsm->timestamp.min);
|
||||
UINT8_TO_BSTREAM(p, pWsm->timestamp.sec);
|
||||
}
|
||||
|
||||
/* return length */
|
||||
return (uint8_t) (p - pBuf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Weight measurement complete.
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param wsmCccIdx Index of weight scale measurement CCC descriptor in CCC descriptor
|
||||
* handle table.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WspsMeasComplete(dmConnId_t connId, uint8_t wsmCccIdx)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t len;
|
||||
|
||||
/* if indications enabled */
|
||||
if (AttsCccEnabled(connId, wsmCccIdx))
|
||||
{
|
||||
/* read weight scale measurement sensor data */
|
||||
AppHwWsmRead(&wspsCb.wsm);
|
||||
|
||||
/* set flags */
|
||||
wspsCb.wsm.flags = wspsCb.wsmFlags;
|
||||
|
||||
/* build weight scale measurement characteristic */
|
||||
len = wspsBuildWsm(buf, &wspsCb.wsm);
|
||||
|
||||
/* send weight scale measurement indication */
|
||||
AttsHandleValueInd(connId, WSS_WM_HDL, len, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the weight scale measurement flags.
|
||||
*
|
||||
* \param flags Weight measurement flags.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void WspsSetWsmFlags(uint8_t flags)
|
||||
{
|
||||
wspsCb.wsmFlags = flags;
|
||||
}
|
||||
Reference in New Issue
Block a user