/* Copyright (c) 2009-2019 Arm Limited
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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.
 */

/*************************************************************************************************/
/*!
 *  \brief HCI core interfaces.
 */
/*************************************************************************************************/
#ifndef HCI_CORE_H
#define HCI_CORE_H

#include "hci_core_ps.h"
#include "wsf_queue.h"
#include "wsf_os.h"
#include "hci_api.h"
#include "cfg_stack.h"

#ifdef __cplusplus
extern "C" {
#endif

/**************************************************************************************************
  Callback Function Types
**************************************************************************************************/

/*! \brief HCI Reset sequence callback type */
typedef void(*hciResetSeq_t)(uint8_t *pMsg, uint16_t opcode);

/**************************************************************************************************
  Data Types
**************************************************************************************************/

/*! \brief Per-connection structure for ACL packet accounting */
typedef struct
{
  uint8_t           *pTxAclPkt;                   /*!< \brief Fragmenting TX ACL packet pointer */
  uint8_t           *pNextTxFrag;                 /*!< \brief Next TX ACL packet fragment */
  uint8_t           *pRxAclPkt;                   /*!< \brief RX ACL packet pointer */
  uint8_t           *pNextRxFrag;                 /*!< \brief Next RX ACL packet fragment */
  uint16_t          handle;                       /*!< \brief Connection handle */
  uint16_t          txAclRemLen;                  /*!< \brief Fragmenting TX ACL packet remaining length */
  uint16_t          rxAclRemLen;                  /*!< \brief Fragmented RX ACL packet remaining length */
  bool_t            fragmenting;                  /*!< \brief TRUE if fragmenting a TX ACL packet */
  bool_t            flowDisabled;                 /*!< \brief TRUE if data flow disabled */
  uint8_t           queuedBufs;                   /*!< \brief Queued ACL buffers on this connection */
  uint8_t           outBufs;                      /*!< \brief Outstanding ACL buffers sent to controller */
} hciCoreConn_t;

/*! \brief Main control block for dual-chip implementation */
typedef struct
{
  hciCoreConn_t     conn[DM_CONN_MAX];            /*!< \brief Connection structures */
  uint8_t           leStates[HCI_LE_STATES_LEN];  /*!< \brief Controller LE supported states */
  bdAddr_t          bdAddr;                       /*!< \brief Bluetooth device address */
  wsfQueue_t        aclQueue;                     /*!< \brief HCI ACL TX queue */
  hciCoreConn_t     *pConnRx;                     /*!< \brief Connection struct for current transport RX packet */
  uint16_t          maxRxAclLen;                  /*!< \brief Maximum reassembled RX ACL packet length */
  uint16_t          bufSize;                      /*!< \brief Controller ACL data buffer size */
  uint8_t           aclQueueHi;                   /*!< \brief Disable flow when this many ACL buffers queued */
  uint8_t           aclQueueLo;                   /*!< \brief Enable flow when this many ACL buffers queued */
  uint8_t           availBufs;                    /*!< \brief Current avail ACL data buffers */
  uint8_t           numBufs;                      /*!< \brief Controller number of ACL data buffers */
  uint8_t           whiteListSize;                /*!< \brief Controller white list size */
  uint8_t           numCmdPkts;                   /*!< \brief Controller command packed count */
  uint32_t          leSupFeat;                    /*!< \brief Controller LE supported features */
  int8_t            advTxPwr;                     /*!< \brief Controller advertising TX power */
  uint8_t           resListSize;                  /*!< \brief Controller resolving list size */
  uint16_t          maxAdvDataLen;                /*!< \brief Controller maximum advertisement (or scan response) data length */
  uint8_t           numSupAdvSets;                /*!< \brief Controller maximum number of advertising sets */
  uint8_t           perAdvListSize;               /*!< \brief Controller periodic advertising list size */
  hciLocalVerInfo_t locVerInfo;                   /*!< \brief Controller version information */
  hciResetSeq_t     extResetSeq;                  /*!< \brief HCI extended reset sequence callback */
} hciCoreCb_t;

/**************************************************************************************************
  Global Variables
**************************************************************************************************/

/*! \brief Control block */
extern hciCoreCb_t hciCoreCb;

/*! \brief Event mask */
extern const uint8_t hciEventMask[HCI_EVT_MASK_LEN];

/*! \brief LE event mask */
extern const uint8_t hciLeEventMask[HCI_LE_EVT_MASK_LEN];

/*! \brief Event mask page 2 */
extern const uint8_t hciEventMaskPage2[HCI_EVT_MASK_LEN];

/*! \brief LE supported features configuration mask */
extern uint32_t hciLeSupFeatCfg;

/**************************************************************************************************
  Function Declarations
**************************************************************************************************/

/*************************************************************************************************/
/*!
 *  \brief  HCI core initialization.
 *
 *  \return None.
 */
/*************************************************************************************************/
void hciCoreInit(void);

/*************************************************************************************************/
/*!
 *  \fn     hciCoreResetStart
 *
 *  \brief  Start the HCI reset sequence.
 *
 *  \return None.
 */
/*************************************************************************************************/
void hciCoreResetStart(void);

/*************************************************************************************************/
/*!
 *  \brief  Perform internal processing on HCI connection open.
 *
 *  \param  handle  Connection handle.
 *
 *  \return None.
 */
/*************************************************************************************************/
void hciCoreConnOpen(uint16_t handle);

/*************************************************************************************************/
/*!
 *  \brief  Perform internal processing on HCI connection close.
 *
 *  \param  handle  Connection handle.
 *
 *  \return None.
 */
/*************************************************************************************************/
void hciCoreConnClose(uint16_t handle);

/*************************************************************************************************/
/*!
 *  \brief  Get a connection structure by handle
 *
 *  \param  handle  Connection handle.
 *
 *  \return Pointer to connection structure or NULL if not found.
 */
/*************************************************************************************************/
hciCoreConn_t *hciCoreConnByHandle(uint16_t handle);

/*************************************************************************************************/
/*!
 *  \brief  Send ACL data to transport.
 *
 *  \param  pConn    Pointer to connection structure.
 *  \param  pData    WSF buffer containing an ACL packet.
 *
 *  \return None.
 */
/*************************************************************************************************/
void hciCoreSendAclData(hciCoreConn_t *pConn, uint8_t *pData);

/*************************************************************************************************/
/*!
 *  \brief  Service the TX data path.
 *
 *  \param  bufs    Number of new buffers now available.
 *
 *  \return None.
 */
/*************************************************************************************************/
void hciCoreTxReady(uint8_t bufs);

/*************************************************************************************************/
/*!
 *  \brief  Send ACL packets, start of packet.
 *
 *  \param  pConn    Pointer to connection structure.
 *  \param  len      ACL packet length.
 *  \param  pData    WSF buffer containing an ACL packet.
 *
 *  \return None.
 */
/*************************************************************************************************/
void hciCoreTxAclStart(hciCoreConn_t *pConn, uint16_t len, uint8_t *pData);

/*************************************************************************************************/
/*!
 *  \brief  Send ACL packets, continuation of fragmented packets.
 *
 *  \param  pConn    Pointer to connection structure.  If set non-NULL, then a fragment is
 *                   sent from this connection structure.  If NULL the function finds the next
 *                   connection structure with a fragment to be sent.
 *
 *  \return TRUE if packet sent, FALSE otherwise.
 */
/*************************************************************************************************/
bool_t hciCoreTxAclContinue(hciCoreConn_t *pConn);

/*************************************************************************************************/
/*!
 *  \brief  This function is called from the HCI transport layer when transmission of an ACL
 *          packet is complete.
 *
 *  \param  pConn    Pointer to connection structure.
 *  \param  pData    WSF buffer containing an ACL packet.
 *
 *  \return None.
 */
/*************************************************************************************************/
void hciCoreTxAclComplete(hciCoreConn_t *pConn, uint8_t *pData);

/*************************************************************************************************/
/*!
 *  \brief  Reassemble an ACL packet.
 *
 *  \param  pData   Input ACL packet.
 *
 *  \return pointer to ACL packet to send, or NULL if no packet to send.
 */
/*************************************************************************************************/
uint8_t *hciCoreAclReassembly(uint8_t *pData);

/*************************************************************************************************/
/*!
 *  \brief  Check if a TX ACL packet is being fragmented.
 *
 *  \param  pConn Connection context.
 *
 *  \return TRUE if fragmenting a TX ACL packet, FALSE otherwise.
 */
/*************************************************************************************************/
bool_t hciCoreTxAclDataFragmented(hciCoreConn_t *pConn);

#ifdef __cplusplus
};
#endif

#endif /* HCI_CORE_H */
