/*************************************************************************************************/ /*! * \file * * \brief Device manager periodic advertising sync transfer (PAST) module. * * 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. */ /*************************************************************************************************/ #include #include "wsf_types.h" #include "wsf_msg.h" #include "wsf_assert.h" #include "wsf_trace.h" #include "dm_api.h" #include "dm_main.h" #include "dm_adv.h" #include "dm_conn.h" #include "dm_scan.h" /************************************************************************************************** Macros **************************************************************************************************/ /*! DM past event handler messages */ enum { /* messages from API */ DM_PAST_MSG_API_RCV_ENABLE = DM_MSG_START(DM_ID_PAST), /*!< Enable receiving report */ DM_PAST_MSG_API_SYNC_TRSF, /*!< Transfer sync */ DM_PAST_MSG_API_SET_INFO_TRSF, /*!< Transfer set info */ DM_PAST_MSG_API_CFG, /*!< Configure PAST parameters */ DM_PAST_MSG_API_DEFAULT_CFG /*!< Configure PAST default parameters */ }; /************************************************************************************************** Local Variables **************************************************************************************************/ /* action function table */ static const dmPastAct_t dmPastAct[] = { dmPastActRptRcvEnable, dmPastActSyncTsfr, dmPastActSetInfoTrsf, dmPastActConfig, dmPastActDefaultConfig }; /*! DM PAST component function interface */ static const dmFcnIf_t dmPastFcnIf = { dmEmptyReset, dmPastHciHandler, dmPastMsgHandler }; /*************************************************************************************************/ /*! * \brief Initialize DM Periodic Advertising Sync Transfer (PAST) module. * * \return None. */ /*************************************************************************************************/ void DmPastInit(void) { /* set function interface table */ dmFcnIfTbl[DM_ID_PAST] = (dmFcnIf_t *) &dmPastFcnIf; } /*************************************************************************************************/ /*! * \brief DM PAST HCI event handler. * * \param pEvent Pointer to HCI callback event structure. * * \return None. */ /*************************************************************************************************/ void dmPastHciHandler(hciEvt_t *pEvent) { dmConnCcb_t *pCcb = dmConnCcbByHandle(pEvent->hdr.param); /* if ccb found */ if (pCcb != NULL) { /* set conn id */ pEvent->hdr.param = pCcb->connId; if (pEvent->hdr.event == HCI_LE_PER_ADV_SYNC_TRSF_CMD_CMPL_CBACK_EVT) { pEvent->hdr.event = DM_PER_ADV_SYNC_TRSF_IND; (*dmCb.cback)((dmEvt_t *) pEvent); } else if (pEvent->hdr.event == HCI_LE_PER_ADV_SET_INFO_TRSF_CMD_CMPL_CBACK_EVT) { pEvent->hdr.event = DM_PER_ADV_SET_INFO_TRSF_IND; (*dmCb.cback)((dmEvt_t *) pEvent); } } } /*************************************************************************************************/ /*! * \brief DM PAST event handler. * * \param pMsg WSF message. * * \return None. */ /*************************************************************************************************/ void dmPastMsgHandler(wsfMsgHdr_t *pMsg) { /* execute action function */ (*dmPastAct[DM_MSG_MASK(pMsg->event)])((dmPastMsg_t *) pMsg); } /*************************************************************************************************/ /*! * \brief Enable receiving report action function. * * \param pMsg WSF message. * * \return None. */ /*************************************************************************************************/ void dmPastActRptRcvEnable(dmPastMsg_t *pMsg) { dmSyncCb_t *pScb; /* look up scb from sync id */ if ((pScb = dmSyncCbById((dmSyncId_t) pMsg->hdr.param)) != NULL) { HciLeSetPerAdvRcvEnableCmd(pScb->handle, (pMsg->hdr.status ? TRUE : FALSE)); } } /*************************************************************************************************/ /*! * \brief Transfer sync action function. * * \param pMsg WSF message. * * \return None. */ /*************************************************************************************************/ void dmPastActSyncTsfr(dmPastMsg_t *pMsg) { dmSyncCb_t *pScb; /* look up scb from sync id */ if ((pScb = dmSyncCbById((dmSyncId_t) pMsg->hdr.param)) != NULL) { dmConnCcb_t *pCcb; /* look up ccb from conn id */ if ((pCcb = dmConnCcbById(pMsg->apiPastTrsf.connId)) != NULL) { HciLePerAdvSyncTrsfCmd(pCcb->handle, pMsg->apiPastTrsf.serviceData, pScb->handle); } } } /*************************************************************************************************/ /*! * \brief Transfer set info action function. * * \param pMsg WSF message. * * \return None. */ /*************************************************************************************************/ void dmPastActSetInfoTrsf(dmPastMsg_t *pMsg) { uint8_t advHandle = (uint8_t) pMsg->hdr.param; /* if periodic advertising is currently in progress for the advertising set */ if (dmPerAdvState(advHandle) == DM_ADV_PER_STATE_ADVERTISING) { dmConnCcb_t *pCcb; /* look up ccb from conn id */ if ((pCcb = dmConnCcbById(pMsg->apiPastTrsf.connId)) != NULL) { HciLePerAdvSetInfoTrsfCmd(pCcb->handle, pMsg->apiPastTrsf.serviceData, advHandle); } } } /*************************************************************************************************/ /*! * \brief Configure PAST action function. * * \param pMsg WSF message. * * \return None. */ /*************************************************************************************************/ void dmPastActConfig(dmPastMsg_t *pMsg) { dmConnCcb_t *pCcb; /* look up ccb from conn id */ if ((pCcb = dmConnCcbById((dmConnId_t) pMsg->hdr.param)) != NULL) { HciLeSetPerAdvSyncTrsfParamsCmd(pCcb->handle, pMsg->apiPastCfg.mode, pMsg->apiPastCfg.skip, pMsg->apiPastCfg.syncTimeout, pMsg->apiPastCfg.cteType); } } /*************************************************************************************************/ /*! * \brief Configure default PAST action function. * * \param pMsg WSF message. * * \return None. */ /*************************************************************************************************/ void dmPastActDefaultConfig(dmPastMsg_t *pMsg) { HciLeSetDefaultPerAdvSyncTrsfParamsCmd(pMsg->apiPastCfg.mode, pMsg->apiPastCfg.skip, pMsg->apiPastCfg.syncTimeout, pMsg->apiPastCfg.cteType); } /*************************************************************************************************/ /*! * \brief Enable or disable reports for the periodic advertising identified by the sync id. * * \param syncId Sync identifier. * \param enable TRUE to enable reporting, FALSE to disable reporting. * * \return None. */ /*************************************************************************************************/ void DmPastRptRcvEnable(dmSyncId_t syncId, bool_t enable) { wsfMsgHdr_t *pMsg; if ((pMsg = WsfMsgAlloc(sizeof(wsfMsgHdr_t))) != NULL) { pMsg->param = syncId; pMsg->event = DM_PAST_MSG_API_RCV_ENABLE; pMsg->status = enable; WsfMsgSend(dmCb.handlerId, pMsg); } } /*************************************************************************************************/ /*! * \brief Send synchronization information about the periodic advertising identified by the * sync id to a connected device. * * \param connId Connection identifier. * \param serviceData Value provided by the Host. * \param syncId Sync identifier. * * \return None. */ /*************************************************************************************************/ void DmPastSyncTrsf(dmConnId_t connId, uint16_t serviceData, dmSyncId_t syncId) { dmPastApiTrsf_t *pMsg; if ((pMsg = WsfMsgAlloc(sizeof(dmPastApiTrsf_t))) != NULL) { pMsg->hdr.param = syncId; pMsg->hdr.event = DM_PAST_MSG_API_SYNC_TRSF; pMsg->serviceData = serviceData; pMsg->connId = connId; WsfMsgSend(dmCb.handlerId, pMsg); } } /*************************************************************************************************/ /*! * \brief Send synchronization information about the periodic advertising in an advertising * set to a connected device. * * \param connId Connection identifier. * \param serviceData Value provided by the Host. * \param advHandle Advertising handle. * * \return None. */ /*************************************************************************************************/ void DmPastSetInfoTrsf(dmConnId_t connId, uint16_t serviceData, uint8_t advHandle) { dmPastApiTrsf_t *pMsg; if ((pMsg = WsfMsgAlloc(sizeof(dmPastApiTrsf_t))) != NULL) { pMsg->hdr.param = advHandle; pMsg->hdr.event = DM_PAST_MSG_API_SET_INFO_TRSF; pMsg->serviceData = serviceData; pMsg->connId = connId; WsfMsgSend(dmCb.handlerId, pMsg); } } /*************************************************************************************************/ /*! * \brief Specify how the Controller should process periodic advertising synchronization * information received from the device identified by the connection handle. * * \param connId Connection identifier. * \param mode Action to be taken when periodic advertising info is received. * \param skip Number of consecutive periodic advertising packets that the receiver * may skip after successfully receiving a periodic advertising packet. * \param syncTimeout Maximum permitted time between successful receives. If this time is * exceeded, synchronization is lost. * \param cteType Whether to only synchronize to periodic advertising with certain * types of Constant Tone Extension. * * \return None. */ /*************************************************************************************************/ void DmPastConfig(dmConnId_t connId, uint8_t mode, uint16_t skip, uint16_t syncTimeout, uint8_t cteType) { dmPastApiCfg_t *pMsg; if ((pMsg = WsfMsgAlloc(sizeof(dmPastApiCfg_t))) != NULL) { pMsg->hdr.param = connId; pMsg->hdr.event = DM_PAST_MSG_API_CFG; pMsg->mode = mode; pMsg->skip = skip; pMsg->syncTimeout = syncTimeout; pMsg->cteType = cteType; WsfMsgSend(dmCb.handlerId, pMsg); } } /*************************************************************************************************/ /*! * \brief Specify the initial value for the mode, skip, timeout, and Constant Tone Extension type * to be used for all subsequent connections over the LE transport. * * \param mode Action to be taken when periodic advertising info is received. * \param skip Number of consecutive periodic advertising packets that the receiver * may skip after successfully receiving a periodic advertising packet. * \param syncTimeout Maximum permitted time between successful receives. If this time is * exceeded, synchronization is lost. * \param cteType Whether to only synchronize to periodic advertising with certain * types of Constant Tone Extension. * * \return None. */ /*************************************************************************************************/ void DmPastDefaultConfig(uint8_t mode, uint16_t skip, uint16_t syncTimeout, uint8_t cteType) { dmPastApiCfg_t *pMsg; if ((pMsg = WsfMsgAlloc(sizeof(dmPastApiCfg_t))) != NULL) { pMsg->hdr.event = DM_PAST_MSG_API_DEFAULT_CFG; pMsg->mode = mode; pMsg->skip = skip; pMsg->syncTimeout = syncTimeout; pMsg->cteType = cteType; WsfMsgSend(dmCb.handlerId, pMsg); } }