mirror of https://github.com/ARMmbed/mbed-os.git
268 lines
7.1 KiB
C
268 lines
7.1 KiB
C
/*************************************************************************************************/
|
|
/*!
|
|
* \file hci_tr.c
|
|
*
|
|
* \brief HCI transport module.
|
|
*
|
|
* Copyright (c) 2011-2018 Arm Ltd. All Rights Reserved.
|
|
*
|
|
* Copyright (c) 2019 Packetcraft, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
/*************************************************************************************************/
|
|
|
|
#include <string.h>
|
|
#include "wsf_types.h"
|
|
#include "wsf_msg.h"
|
|
#include "wsf_assert.h"
|
|
#include "util/bstream.h"
|
|
#include "hci_api.h"
|
|
#include "hci_core.h"
|
|
#include "hci_tr.h"
|
|
#include "hci_drv.h"
|
|
|
|
/* PORTING: EXACTLE removed as replaced by zero copy hci driver in mbedos */
|
|
|
|
uint16_t hci_mbed_os_drv_write(uint8_t type, uint16_t len, uint8_t *pData);
|
|
|
|
/**************************************************************************************************
|
|
Data Types
|
|
**************************************************************************************************/
|
|
|
|
typedef enum
|
|
{
|
|
HCI_RX_STATE_IDLE,
|
|
HCI_RX_STATE_HEADER,
|
|
HCI_RX_STATE_DATA,
|
|
HCI_RX_STATE_COMPLETE
|
|
} hciRxState_t;
|
|
|
|
/*************************************************************************************************/
|
|
/*!
|
|
* \fn hciTrSendAclData
|
|
*
|
|
* \brief Send a complete HCI ACL packet to the transport.
|
|
*
|
|
* \param pContext Connection context.
|
|
* \param pData WSF msg buffer containing an ACL packet.
|
|
*
|
|
* \return None.
|
|
*/
|
|
/*************************************************************************************************/
|
|
void hciTrSendAclData(void *pContext, uint8_t *pData)
|
|
{
|
|
/* PORTING: sending and fragmenting done by mbed-os */
|
|
uint16_t len;
|
|
|
|
/* get 16-bit length */
|
|
BYTES_TO_UINT16(len, (pData + 2))
|
|
len += HCI_ACL_HDR_LEN;
|
|
|
|
/* transmit ACL header and data */
|
|
if (hci_mbed_os_drv_write(HCI_ACL_TYPE, len, pData) == len)
|
|
{
|
|
#if CORDIO_ZERO_COPY_HCI
|
|
/* pData is not freed as the hci_mbed_os_drv_write took ownership of the WSF buffer */
|
|
#else
|
|
/* free buffer */
|
|
hciCoreTxAclComplete((hciCoreConn_t *)pContext, pData);
|
|
#endif // CORDIO_ZERO_COPY_HCI
|
|
}
|
|
}
|
|
|
|
/*************************************************************************************************/
|
|
/*!
|
|
* \brief Send a complete HCI command to the transport.
|
|
*
|
|
* \param pCmdData WSF msg buffer containing an HCI command.
|
|
*
|
|
* \return None.
|
|
*/
|
|
/*************************************************************************************************/
|
|
void hciTrSendCmd(uint8_t *pCmdData)
|
|
{
|
|
/* PORTING: sending done by mbed-os */
|
|
uint16_t len;
|
|
|
|
/* get length */
|
|
len = pCmdData[2] + HCI_CMD_HDR_LEN;
|
|
|
|
/* transmit ACL header and data */
|
|
if (hci_mbed_os_drv_write(HCI_CMD_TYPE, len, pCmdData) == len)
|
|
{
|
|
#if CORDIO_ZERO_COPY_HCI
|
|
/* pData is not freed as the hci_mbed_os_drv_write took ownership of the WSF buffer */
|
|
#else
|
|
/* free buffer */
|
|
WsfMsgFree(pCmdData);
|
|
#endif // CORDIO_ZERO_COPY_HCI
|
|
}
|
|
}
|
|
|
|
/*************************************************************************************************/
|
|
/*!
|
|
* \fn hciSerialRxIncoming
|
|
*
|
|
* \brief Receive function. Gets called by external code when bytes are received.
|
|
*
|
|
* \param pBuf Pointer to buffer of incoming bytes.
|
|
* \param len Number of bytes in incoming buffer.
|
|
*
|
|
* \return None.
|
|
*/
|
|
/*************************************************************************************************/
|
|
void hciTrSerialRxIncoming(uint8_t *pBuf, uint8_t len)
|
|
{
|
|
static uint8_t stateRx = HCI_RX_STATE_IDLE;
|
|
static uint8_t pktIndRx;
|
|
static uint16_t iRx;
|
|
static uint8_t hdrRx[HCI_ACL_HDR_LEN];
|
|
static uint8_t *pPktRx;
|
|
static uint8_t *pDataRx;
|
|
|
|
uint8_t dataByte;
|
|
|
|
/* loop until all bytes of incoming buffer are handled */
|
|
while (len--)
|
|
{
|
|
/* read single byte from incoming buffer and advance to next byte */
|
|
dataByte = *pBuf++;
|
|
|
|
/* --- Idle State --- */
|
|
if (stateRx == HCI_RX_STATE_IDLE)
|
|
{
|
|
/* save the packet type */
|
|
pktIndRx = dataByte;
|
|
iRx = 0;
|
|
stateRx = HCI_RX_STATE_HEADER;
|
|
}
|
|
|
|
/* --- Header State --- */
|
|
else if (stateRx == HCI_RX_STATE_HEADER)
|
|
{
|
|
uint8_t hdrLen = 0;
|
|
uint16_t dataLen = 0;
|
|
|
|
/* copy current byte into the temp header buffer */
|
|
hdrRx[iRx++] = dataByte;
|
|
|
|
/* determine header length based on packet type */
|
|
switch (pktIndRx)
|
|
{
|
|
case HCI_CMD_TYPE:
|
|
hdrLen = HCI_CMD_HDR_LEN;
|
|
break;
|
|
case HCI_ACL_TYPE:
|
|
hdrLen = HCI_ACL_HDR_LEN;
|
|
break;
|
|
case HCI_EVT_TYPE:
|
|
hdrLen = HCI_EVT_HDR_LEN;
|
|
break;
|
|
default:
|
|
/* invalid packet type */
|
|
WSF_ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
/* see if entire header has been read */
|
|
if (iRx == hdrLen)
|
|
{
|
|
/* extract data length from header */
|
|
switch (pktIndRx)
|
|
{
|
|
case HCI_CMD_TYPE:
|
|
dataLen = hdrRx[2];
|
|
break;
|
|
case HCI_ACL_TYPE:
|
|
BYTES_TO_UINT16(dataLen, &hdrRx[2]);
|
|
break;
|
|
case HCI_EVT_TYPE:
|
|
dataLen = hdrRx[1];
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* allocate data buffer to hold entire packet */
|
|
if (pktIndRx == HCI_ACL_TYPE)
|
|
{
|
|
pPktRx = (uint8_t*)WsfMsgDataAlloc(hdrLen + dataLen, 0);
|
|
}
|
|
else
|
|
{
|
|
pPktRx = (uint8_t*)WsfMsgAlloc(hdrLen + dataLen);
|
|
}
|
|
|
|
if (pPktRx != NULL)
|
|
{
|
|
pDataRx = pPktRx;
|
|
|
|
/* copy header into data packet (note: memcpy is not so portable) */
|
|
{
|
|
uint8_t i;
|
|
for (i = 0; i < hdrLen; i++)
|
|
{
|
|
*pDataRx++ = hdrRx[i];
|
|
}
|
|
}
|
|
|
|
/* save number of bytes left to read */
|
|
iRx = dataLen;
|
|
if (iRx == 0)
|
|
{
|
|
stateRx = HCI_RX_STATE_COMPLETE;
|
|
}
|
|
else
|
|
{
|
|
stateRx = HCI_RX_STATE_DATA;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WSF_ASSERT(0); /* allocate falied */
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/* --- Data State --- */
|
|
else if (stateRx == HCI_RX_STATE_DATA)
|
|
{
|
|
/* write incoming byte to allocated buffer */
|
|
*pDataRx++ = dataByte;
|
|
|
|
/* determine if entire packet has been read */
|
|
iRx--;
|
|
if (iRx == 0)
|
|
{
|
|
stateRx = HCI_RX_STATE_COMPLETE;
|
|
}
|
|
}
|
|
|
|
/* --- Complete State --- */
|
|
/* ( Note Well! There is no else-if construct by design. ) */
|
|
if (stateRx == HCI_RX_STATE_COMPLETE)
|
|
{
|
|
/* deliver data */
|
|
if (pPktRx != NULL)
|
|
{
|
|
hciCoreRecv(pktIndRx, pPktRx);
|
|
}
|
|
|
|
/* reset state machine */
|
|
stateRx = HCI_RX_STATE_IDLE;
|
|
}
|
|
}
|
|
}
|