Newer
Older
mbed-os / targets / TARGET_Cypress / TARGET_PSOC6 / mtb-pdl-cat1 / drivers / source / cy_ipc_bt.c
@Dustin Crossman Dustin Crossman on 4 Jun 2021 22 KB Fix file modes.
/***************************************************************************//**
* \file cy_ipc_bt.c
* \version 1.0
*
* \brief
*  This driver provides the source code for BT IPC.
*
********************************************************************************
* \copyright
* Copyright 2017-2020 Cypress Semiconductor Corporation
* 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.
*******************************************************************************/

#include "cy_device.h"

#if defined (CY_IP_MXIPC)

#include "cy_ipc_bt.h"

/* Should not include this. To be removed */
#include <string.h>

/* local functions prototype */
cy_en_btipcdrv_status_t Cy_bt_handle_hpclong_msg(cy_stc_ipc_bt_context_t *btIpcContext, uint32_t * msgPtr);
cy_en_btipcdrv_status_t Cy_bt_handle_buf_add(cy_stc_ipc_bt_context_t *btIpcContext, uint32_t * msgPtr);
cy_en_btipc_buftype_t Cy_bt_get_buf_type(cy_en_btipc_hcipti_t pti);
uint32_t Cy_bt_getPLLegnth(cy_en_btipc_hcipti_t pti, uint8_t* bufAddr);
bool Cy_bt_isOffsetNeeded(cy_en_btipc_hcipti_t pti);




void Cy_BTIPC_IRQ_Handler(cy_stc_ipc_bt_context_t *btIpcContext)
{
    uint32_t shadowIntr;
    IPC_STRUCT_Type *ipcPtr;
    IPC_INTR_STRUCT_Type *ipcIntrPtr;
    uint32_t mesg[2];
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;
    uint32_t notify;
    uint32_t release;
    uint32_t channel;
    uint8_t idx;

    if (NULL == contextPtr)
        return;

    ipcIntrPtr = Cy_IPC_Drv_GetIntrBaseAddr(contextPtr->intStuctureSelf);
    shadowIntr = Cy_IPC_Drv_GetInterruptStatusMasked(ipcIntrPtr);

    /* Check to make sure the interrupt was a release interrupt */
    release = Cy_IPC_Drv_ExtractReleaseMask(shadowIntr);

    /* First process the release callback */
    if (0UL != release)  /* Check for a Release interrupt */
    {
        /* Clear the release interrupt  */
        Cy_IPC_Drv_ClearInterrupt(ipcIntrPtr, release, CY_IPC_NO_NOTIFICATION);
        /* release callback can be added here. */
        if (contextPtr->ulReleaseCallbackPtr)
            contextPtr->ulReleaseCallbackPtr();
    }

    /* Check to make sure the interrupt was a notify interrupt */
    notify = Cy_IPC_Drv_ExtractAcquireMask(shadowIntr);

    if (0UL != notify)
    {
        /* Clear the notify interrupt.  */
        Cy_IPC_Drv_ClearInterrupt(ipcIntrPtr, CY_IPC_NO_NOTIFICATION, notify);
        if (notify & (uint32_t)(0x1 << contextPtr->dlChannelHCI))
            channel = contextPtr->dlChannelHCI;
        else
            channel = contextPtr->dlChannelHPC;

        ipcPtr = Cy_IPC_Drv_GetIpcBaseAddress(channel);

        if (!Cy_IPC_Drv_ReadMsgDWord (ipcPtr, mesg))
        {
            if (channel == contextPtr->dlChannelHCI)
            {
                /* Channel will be released in the callback function */
                if (contextPtr->dlNotifyCallbackPtr)
                    contextPtr->dlNotifyCallbackPtr(mesg);
            }
            else
            {
                if (contextPtr->internal_hpc_notify_cb)
                    contextPtr->internal_hpc_notify_cb((void*)contextPtr, mesg);
                for (idx = 0; idx < MAX_BT_IPC_HPC_CB; idx++)
                {
                    if (contextPtr->hpcNotifyCallbackPtr[idx])
                        contextPtr->hpcNotifyCallbackPtr[idx](mesg);
                }
                /* Release channel for HPC message only */
                Cy_BTIPC_HPC_RelChannel(contextPtr, mesg);
            }
        }
    }
}

cy_en_btipcdrv_status_t Cy_BTIPC_HCI_RelChannel(cy_stc_ipc_bt_context_t *btIpcContext, void * buf)
{
    IPC_STRUCT_Type *ipcPtr;
    cy_en_ipcdrv_status_t status;
    uint32_t rel_mask;
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;

    if ((NULL == contextPtr) || (NULL == buf))
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;

    ipcPtr = Cy_IPC_Drv_GetIpcBaseAddress (contextPtr->dlChannelHCI);

    rel_mask = (uint32_t)(1 << contextPtr->intStucturePeer);

    status = Cy_IPC_Drv_LockRelease (ipcPtr, rel_mask);

    if (status) {
        return CY_BT_IPC_DRV_ERROR_LOCK_REL;
    }
    return CY_BT_IPC_DRV_SUCCESS;
}

cy_en_btipcdrv_status_t Cy_BTIPC_HPC_RelChannel(cy_stc_ipc_bt_context_t *btIpcContext, void * buf)
{
    IPC_STRUCT_Type *ipcPtr;
    cy_en_ipcdrv_status_t status;
    uint32_t rel_mask;
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;

    if ((NULL == contextPtr) || (NULL == buf))
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;

    ipcPtr = Cy_IPC_Drv_GetIpcBaseAddress (contextPtr->dlChannelHPC);

    rel_mask = (uint32_t)(1 << contextPtr->intStucturePeer);
    status = Cy_IPC_Drv_LockRelease (ipcPtr, rel_mask);
    if (status) {
        return CY_BT_IPC_DRV_ERROR_LOCK_REL;
    }
    return CY_BT_IPC_DRV_SUCCESS;
}

void Cy_BTIPC_HPC_Notify(void *btIpcContext, uint32_t * msgPtr)
{
    cy_en_btipc_hpcpti_t pti;
    cy_stc_ipc_bt_context_t *contextPtr = (cy_stc_ipc_bt_context_t*) btIpcContext;
    if ((NULL == contextPtr) || (NULL == msgPtr))
        return;

    pti = (cy_en_btipc_hpcpti_t)((0xFF) & msgPtr[0]);

    switch (pti)
    {
        case CY_BT_IPC_HPC_LONG:
            Cy_bt_handle_hpclong_msg(contextPtr, msgPtr);
            break;
        case CY_BT_IPC_HPC_BUF_AVAIL:
            Cy_bt_handle_buf_add(contextPtr, msgPtr);
            break;
        case CY_BT_IPC_HPC_BUF_FREE:
            Cy_bt_handle_buf_add(contextPtr, msgPtr);
            break;
        default:
            /* default invalid pti */
            break;
    }
}

cy_en_btipcdrv_status_t Cy_BTIPC_Init(cy_stc_ipc_bt_context_t *btIpcContext, cy_stc_ipc_bt_config_t * btIpcConfig)
{
    cy_en_sysint_status_t intrStatus;
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;
    uint8_t idx;

    if ((NULL == contextPtr) || (NULL == btIpcConfig))
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;

    contextPtr->dlChannelHCI = btIpcConfig->dlChannelHCI;
    contextPtr->ulChannelHCI = btIpcConfig->ulChannelHCI;

    contextPtr->dlChannelHPC = btIpcConfig->dlChannelHPC;
    contextPtr->ulChannelHPC = btIpcConfig->ulChannelHPC;

    contextPtr->intStuctureSelf = btIpcConfig->intStuctureSelf;
    contextPtr->intStucturePeer = btIpcConfig->intStucturePeer;
    contextPtr->intPeerMask = (uint32_t) (0x1 << btIpcConfig->intStucturePeer);

    contextPtr->dlNotifyCallbackPtr = btIpcConfig->dlNotifyCallbackPtr;
    contextPtr->ulReleaseCallbackPtr = btIpcConfig->ulReleaseCallbackPtr;

    contextPtr->irqHandlerPtr = btIpcConfig->irqHandlerPtr;
    contextPtr->ipcIntConfig.intrSrc = btIpcConfig->ipcIntConfig.intrSrc;
    contextPtr->ipcIntConfig.intrPriority = btIpcConfig->ipcIntConfig.intrPriority;

    contextPtr->internal_hpc_notify_cb = btIpcConfig->internal_hpc_notify_cb;

    contextPtr->dlNotifyMask = (uint32_t)((uint32_t)(0x1 << btIpcConfig->dlChannelHCI) | (uint32_t)(0x1 << btIpcConfig->dlChannelHPC));
    contextPtr->ulReleaseMask = (uint32_t)((uint32_t)(0x1 << btIpcConfig->ulChannelHCI) | (uint32_t)(0x1 << btIpcConfig->ulChannelHPC));

    for (idx = 0; idx < MAX_BT_IPC_HPC_CB; idx++)
        contextPtr->hpcNotifyCallbackPtr[idx] = NULL;

    for (idx = 0; idx < MAX_BUF_COUNT; idx++)
    {
        contextPtr->buffPool[idx].bufPtr = NULL;
        contextPtr->buffPool[idx].bufType = CY_BT_IPC_HCI_INVALID_BUF;
    }

    intrStatus = Cy_SysInt_Init(&contextPtr->ipcIntConfig, contextPtr->irqHandlerPtr);
    if (intrStatus)
    {
        return CY_BT_IPC_DRV_ERROR;
    }

    /* enable interrupt */
    NVIC_EnableIRQ(contextPtr->ipcIntConfig.intrSrc);

    /* Set IPC Interrupt mask */
    /* Allow only notify on DL channel  and release on UL channel interrupts */
    Cy_IPC_Drv_SetInterruptMask(Cy_IPC_Drv_GetIntrBaseAddr(contextPtr->intStuctureSelf), contextPtr->ulReleaseMask, contextPtr->dlNotifyMask);
    return CY_BT_IPC_DRV_SUCCESS;
 }

cy_en_btipcdrv_status_t Cy_BTIPC_Deinit(cy_stc_ipc_bt_context_t *btIpcContext)
{
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;
    uint8_t idx;

    if (NULL == contextPtr)
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;

    //Cy_IPC_Drv_SetInterruptMask(Cy_IPC_Drv_GetIntrBaseAddr(contextPtr->intStuctureSelf), ~contextPtr->ulReleaseMask, ~contextPtr->dlNotifyMask);

    /* enable interrupt */
    NVIC_DisableIRQ(contextPtr->ipcIntConfig.intrSrc);

    contextPtr->irqHandlerPtr = NULL;
    contextPtr->internal_hpc_notify_cb = NULL;

    for (idx = 0; idx < MAX_BT_IPC_HPC_CB; idx++)
        contextPtr->hpcNotifyCallbackPtr[idx] = NULL;

    for (idx = 0; idx < MAX_BUF_COUNT; idx++)
    {
        contextPtr->buffPool[idx].bufPtr = NULL;
        contextPtr->buffPool[idx].bufType = CY_BT_IPC_HCI_INVALID_BUF;
    }

    return CY_BT_IPC_DRV_SUCCESS;
}

cy_en_btipcdrv_status_t Cy_BTIPC_HCI_getPTI (cy_en_btipc_hcipti_t *pti, uint32_t *p_length, uint32_t *msgPtr)
{
    cy_stc_ipc_msg_buff_t *ipcMsgBuf;
    uint8_t *bufAddr;
    cy_en_btipc_hcipti_t mesgPti;

    if ((NULL == pti) || (NULL == msgPtr) || (NULL == p_length))
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;

    /* Incase of long messages the PTI needs to be read from DATA0[bit 8-15] */
    mesgPti = (cy_en_btipc_hcipti_t)((0xFF) & msgPtr[0]);
    if (mesgPti == CY_BT_IPC_HCI_LONG)
    {
        ipcMsgBuf = (cy_stc_ipc_msg_buff_t*)msgPtr;
        *pti = (cy_en_btipc_hcipti_t)ipcMsgBuf->actualPti;
        bufAddr = ipcMsgBuf->bufAddr;
        if (Cy_bt_isOffsetNeeded(*pti))
            bufAddr++;
    }
    else
    {
        *pti = mesgPti;
        bufAddr = (uint8_t*)msgPtr;
        /* Skip the PTI byte read from the DATA0 register */
        bufAddr++;
    }
    *p_length = Cy_bt_getPLLegnth(*pti, bufAddr);
    return CY_BT_IPC_DRV_SUCCESS;
}

cy_en_btipcdrv_status_t Cy_BTIPC_HCI_Read (cy_stc_ipc_bt_context_t *btIpcContext, cy_en_btipc_hcipti_t pti, void *data, size_t* pLength)
{
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;
    cy_stc_ipc_msg_alloc_t ipcMsgAlloc;
    cy_stc_ipc_msg_buff_t *ipcMsgBuf;
    cy_en_btipcdrv_status_t status;
    cy_stc_ipc_msg_short_t *shortMesg;
    cy_en_btipc_hcipti_t actualPti;
    cy_en_btipc_hcipti_t mesgPti;
    uint32_t mesg[2];
    uint8_t *srcPtr;

    if ((NULL == contextPtr) || (NULL == data))
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;

    Cy_IPC_Drv_ReadDDataValue (Cy_IPC_Drv_GetIpcBaseAddress(contextPtr->dlChannelHCI), mesg);

    mesgPti = (cy_en_btipc_hcipti_t)((0xFF) & mesg[0]);

    if (mesgPti == CY_BT_IPC_HCI_LONG)
    {
        ipcMsgBuf = (cy_stc_ipc_msg_buff_t*)&mesg;
        actualPti = (cy_en_btipc_hcipti_t)ipcMsgBuf->actualPti;
        srcPtr = ipcMsgBuf->bufAddr;
        if (Cy_bt_isOffsetNeeded(actualPti))
            srcPtr++;
        *pLength = Cy_bt_getPLLegnth(actualPti, srcPtr);
    }
    else
    {
        shortMesg = (cy_stc_ipc_msg_short_t*)&mesg;
        srcPtr = &(shortMesg->db0);
        *pLength = Cy_bt_getPLLegnth(mesgPti, srcPtr);
    }

    /* To be done: memcopy needs to be removed */
    /* Need to look for better option */
    /* May be a loop or DMA */
    memcpy((uint8_t*)data, srcPtr, *pLength);

    status = Cy_BTIPC_HCI_RelChannel(contextPtr, (void *) &mesg);

    /* Send buffer back to BLE  */
    /* To be done: Should this assert If Channel release fails? */
    if ((mesgPti == CY_BT_IPC_HCI_LONG) && (!status))
    {
        ipcMsgAlloc.pti = (uint8_t)CY_BT_IPC_HPC_BUF_FREE;
        ipcMsgAlloc.bufType = Cy_bt_get_buf_type(actualPti);
        ipcMsgAlloc.bufSize = *pLength;
        ipcMsgAlloc.bufAddr = ipcMsgBuf->bufAddr;

        status = Cy_BTIPC_HPC_Write(contextPtr, &ipcMsgAlloc, (size_t) 2);
    }

    return status;
}

cy_en_btipcdrv_status_t Cy_BTIPC_HCI_Write(cy_stc_ipc_bt_context_t *btIpcContext, cy_en_btipc_hcipti_t pti, void *data, size_t length)
{
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;
    cy_en_btipcdrv_status_t status;
    uint8_t *destBuf;
    cy_stc_ipc_msg_buff_t ipcPacket;
    cy_en_btipc_buftype_t bufType;
    cy_stc_ipc_msg_short_t ipcShort;
    uint32_t *msgPtr;
    uint8_t *bPtr;

    if ((NULL == contextPtr) || (NULL == data))
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;

    /* Check if it is short message or buffer needed */
    if (length > MAX_SHORT_MESG_LENGTH) /* Long messge */
    {
        /* Get the buffer type based on the payload type indeicator */
        bufType = Cy_bt_get_buf_type(pti);
        /* Pick a free buffe from the pool of buffers */
        status = Cy_BTIPC_GetBuffer (contextPtr, (void **)&destBuf, bufType);
        if (status)
            return status;

        /* Copy payload to BLE buffer */
        /* To be done: memcopy needs to be removed */
        /* Need to look for better option */
        /* May be a loop or DMA */
        bPtr = destBuf;
        /* Skip pad byte if needed */
        if (Cy_bt_isOffsetNeeded(pti))
            bPtr++;
        memcpy(bPtr, data, length);
        ipcPacket.pti = (uint8_t) CY_BT_IPC_HCI_LONG;
        ipcPacket.actualPti = (uint8_t)pti;
        ipcPacket.bufAddr = destBuf;
        /* end of buffer preperation */
        msgPtr = (uint32_t*)&ipcPacket;
    }
    else /* Short Message */
    {
        ipcShort.pti = pti;
        /* To be done: memcopy needs to be removed */
        /* Need to look for better option */
        /* Loop is fine as max 8 bytes need to be copied */
        memcpy (&(ipcShort.db0), data, length);
        msgPtr = (uint32_t*)&ipcShort;
    }
    if (!Cy_IPC_Drv_SendMsgDWord (Cy_IPC_Drv_GetIpcBaseAddress(contextPtr->ulChannelHCI),
                                contextPtr->intPeerMask, msgPtr))
        return CY_BT_IPC_DRV_SUCCESS;
    else
        return CY_BT_IPC_DRV_ERROR_LOCK_ACQUIRE;
}

cy_en_btipcdrv_status_t Cy_BTIPC_HPC_Write(cy_stc_ipc_bt_context_t *btIpcContext, void *data, size_t length)
{
    uint32_t *dataPtr = (uint32_t*) data;
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;

    if ((NULL == contextPtr) || (NULL == data))
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;

    if (!Cy_IPC_Drv_SendMsgDWord (Cy_IPC_Drv_GetIpcBaseAddress(contextPtr->ulChannelHPC),
                                contextPtr->intPeerMask, (uint32_t*) dataPtr))
        return CY_BT_IPC_DRV_SUCCESS;
    else
        return CY_BT_IPC_DRV_ERROR_LOCK_ACQUIRE;

}

cy_en_btipcdrv_status_t Cy_BTIPC_HPC_RegisterCb(cy_stc_ipc_bt_context_t *btIpcContext,     cy_ipc_bt_callback_ptr_t hpcNotifyCallbackPtr)
{
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;
    uint8_t idx;
    uint8_t placed;

    if ((NULL == contextPtr) || (NULL == hpcNotifyCallbackPtr))
    {
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;
    }

    placed = 0;
    for (idx = 0; idx < MAX_BT_IPC_HPC_CB; idx++)
    {
        if (contextPtr->hpcNotifyCallbackPtr[idx] == NULL)
        {
            contextPtr->hpcNotifyCallbackPtr[idx] = hpcNotifyCallbackPtr;
            placed = 1;
            break;
        }
    }

    if (placed)
        return CY_BT_IPC_DRV_SUCCESS;
    else
        return CY_BT_IPC_DRV_ERROR;
}

cy_en_btipcdrv_status_t Cy_BTIPC_HPC_UnregisterCb(cy_stc_ipc_bt_context_t *btIpcContext,     cy_ipc_bt_callback_ptr_t hpcNotifyCallbackPtr)
{
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;
    uint8_t idx;
    uint8_t found;

    if ((NULL == contextPtr) || (NULL == hpcNotifyCallbackPtr))
    {
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;
    }

    found = 0;
    for (idx = 0; idx < MAX_BT_IPC_HPC_CB; idx++)
    {
        if (contextPtr->hpcNotifyCallbackPtr[idx] == hpcNotifyCallbackPtr)
        {
            contextPtr->hpcNotifyCallbackPtr[idx] = NULL;
            found = 1;
            break;
        }
    }

    if (found)
        return CY_BT_IPC_DRV_SUCCESS;
    else
        return CY_BT_IPC_DRV_ERROR;
}

cy_en_btipcdrv_status_t Cy_BTIPC_GetBuffer (cy_stc_ipc_bt_context_t *btIpcContext, void **bufPtr, cy_en_btipc_buftype_t bufType)
{
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;
    uint8_t idx;
    uint8_t found;
    uint32_t interruptState;

    if ((NULL == contextPtr) || (NULL == bufPtr))
    {
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;
    }

    interruptState = Cy_SysLib_EnterCriticalSection();

    found = 0;
    for (idx = 0; idx < MAX_BUF_COUNT; idx++)
    {
        if ((contextPtr->buffPool[idx].bufType == bufType) && (contextPtr->buffPool[idx].bufPtr != NULL))
        {
            *bufPtr = (void*)contextPtr->buffPool[idx].bufPtr;
            contextPtr->buffPool[idx].bufPtr = NULL;
            contextPtr->buffPool[idx].bufType = CY_BT_IPC_HCI_INVALID_BUF;
            found = 1;
            break;
        }
    }

    Cy_SysLib_ExitCriticalSection(interruptState);

    if (found)
        return CY_BT_IPC_DRV_SUCCESS;
    else
    {
        *bufPtr = NULL;
        return CY_BT_IPC_DRV_ERROR_BUF_GET;
    }
}

cy_en_btipcdrv_status_t Cy_BTIPC_PutBuffer(cy_stc_ipc_bt_context_t *btIpcContext, cy_stc_ipc_bt_buf_t *bufDecriptor)
{
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;
    uint8_t idx;
    uint8_t done;
    uint32_t interruptState;

    if ((NULL == contextPtr) || (NULL == bufDecriptor) || (bufDecriptor->bufPtr == NULL))
    {
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;
    }

    interruptState = Cy_SysLib_EnterCriticalSection();

    done = 0;
    for (idx = 0; idx < MAX_BUF_COUNT; idx++)
    {
        if (contextPtr->buffPool[idx].bufPtr == NULL)
        {
            contextPtr->buffPool[idx] = *bufDecriptor;
            done = 1;
            break;
        }
    }

    Cy_SysLib_ExitCriticalSection(interruptState);

    if (done)
        return CY_BT_IPC_DRV_SUCCESS;
    else
        return CY_BT_IPC_DRV_ERROR_BUF_FULL;
}


/* Local function implmentation */
cy_en_btipcdrv_status_t Cy_bt_handle_hpclong_msg(cy_stc_ipc_bt_context_t *btIpcContext, uint32_t * msgPtr)
{
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;
    cy_stc_ipc_msg_init_t *ptr;
    cy_stc_ipc_bt_buf_t bufDescriptor;
    cy_en_btipcdrv_status_t status;
    uint8_t i;
    uint8_t bufCount;

    uint8_t *bPtr;
    uint16_t *sPtr;
    uint32_t *uiPtr;

    if ((NULL == contextPtr) || (NULL == msgPtr))
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;

    ptr = (cy_stc_ipc_msg_init_t*)(* (msgPtr+1));

    if (NULL == ptr)
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;

    bufCount = ptr->payLoadLen/BUFFER_DESCRIPTION_LEN;
    /* Add code to extract boot type from initi structure */
    //msgId
    //bootType
    /* point to the start of buffer pool */
    ptr++;
    bPtr = (uint8_t*)ptr;

    for (i = 0; i < bufCount; i++)
    {
        bufDescriptor.bufType = (cy_en_btipc_buftype_t) (*bPtr++);
        sPtr = (uint16_t*)bPtr;
        bufDescriptor.bufLen = *(sPtr++);
        uiPtr = (uint32_t*)sPtr;
        bufDescriptor.bufPtr = (uint8_t*)(*uiPtr++);
        status = Cy_BTIPC_PutBuffer(contextPtr, &bufDescriptor);
        if (status)
        {
            /* Need to check if some cleaning needed for error condition */
            return status;
        }
        bPtr = (uint8_t*)uiPtr;
    }
    return CY_BT_IPC_DRV_SUCCESS;
}

cy_en_btipcdrv_status_t Cy_bt_handle_buf_add(cy_stc_ipc_bt_context_t *btIpcContext, uint32_t * msgPtr)
{
    cy_stc_ipc_bt_buf_t bufDescriptor;
    cy_stc_ipc_msg_alloc_t allocBuf;
    cy_stc_ipc_bt_context_t *contextPtr = btIpcContext;

    if ((NULL == contextPtr) || (NULL == msgPtr))
        return CY_BT_IPC_DRV_ERROR_BAD_HANDLE;
    allocBuf = *(cy_stc_ipc_msg_alloc_t*)(msgPtr);
    bufDescriptor.bufType = (cy_en_btipc_buftype_t) allocBuf.bufType;
    bufDescriptor.bufLen = allocBuf.bufSize;
    bufDescriptor.bufPtr = (uint8_t*) allocBuf.bufAddr;

    return Cy_BTIPC_PutBuffer(contextPtr, &bufDescriptor);
}

cy_en_btipc_buftype_t Cy_bt_get_buf_type(cy_en_btipc_hcipti_t pti)
{
    cy_en_btipc_buftype_t bufType;
    /* To be done: Currently retruning Control buffer for all PTIs. Need to change it once we have clarity on it */
    switch (pti)
    {
        case CY_BT_IPC_HCI_CMD:
            bufType = CY_BT_IPC_CTRL_BUF;
            break;
        case CY_BT_IPC_HCI_ACL:
            bufType = CY_BT_IPC_CTRL_BUF;
            break;
        case CY_BT_IPC_HCI_SCO:
            bufType = CY_BT_IPC_CTRL_BUF;
            break;
        case CY_BT_IPC_HCI_EVT:
            bufType = CY_BT_IPC_CTRL_BUF;
            break;
        case CY_BT_IPC_HCI_ISO:
            bufType = CY_BT_IPC_CTRL_BUF;
            break;
        case CY_BT_IPC_HCI_DIAG:
            bufType = CY_BT_IPC_CTRL_BUF;
            break;
        case CY_BT_IPC_HCI_MPAF:
            bufType = CY_BT_IPC_CTRL_BUF;
            break;
        case CY_BT_IPC_HCI_SLIPH5:
            bufType = CY_BT_IPC_CTRL_BUF;
            break;
        default:
            bufType = CY_BT_IPC_HCI_INVALID_BUF;
            break;
    }
    return bufType;
}

uint32_t Cy_bt_getPLLegnth(cy_en_btipc_hcipti_t pti, uint8_t* bufAddr)
{
    uint32_t length;
    switch (pti)
    {
        case CY_BT_IPC_HCI_CMD:
            length = (uint32_t)(((BTHCI_CMD_HDR_t*)bufAddr)->params_len);
            length += sizeof(BTHCI_CMD_HDR_t);
            break;
        case CY_BT_IPC_HCI_ACL:
            length = (uint32_t)(((BTHCI_ACL_HDR_t*)bufAddr)->data_len);
            length += sizeof(BTHCI_ACL_HDR_t);
            break;
        case CY_BT_IPC_HCI_SCO:
            length = (uint32_t)(((BTHCI_SCO_HDR_t*)bufAddr)->data_len);
            length += sizeof(BTHCI_SCO_HDR_t);
            break;
        case CY_BT_IPC_HCI_EVT:
            length = (uint32_t)(((BTHCI_EVENT_HDR_t*)bufAddr)->params_len);
            length += sizeof(BTHCI_EVENT_HDR_t);
            break;
        case CY_BT_IPC_HCI_ISO:
            length = (uint32_t)(((BTHCI_ISO_HDR_t*)bufAddr)->data_len);
            length += sizeof(BTHCI_ISO_HDR_t);
            break;
        /* To be done: Header length for the remaining PTI needs to be updated */
        case CY_BT_IPC_HCI_DIAG:
            length = 0;
            break;
        case CY_BT_IPC_HCI_MPAF:
            length = 0;
            break;
        case CY_BT_IPC_HCI_SLIPH5:
            length = 0;
            break;
        default:
            length = 0;
            break;
    }
    return length;
}

bool Cy_bt_isOffsetNeeded(cy_en_btipc_hcipti_t pti)
{
    switch (pti)
    {
        case CY_BT_IPC_HCI_CMD:
        case CY_BT_IPC_HCI_SCO:
            return true;
        case CY_BT_IPC_HCI_ACL:
        case CY_BT_IPC_HCI_EVT:
        case CY_BT_IPC_HCI_ISO:
        case CY_BT_IPC_HCI_DIAG:
        case CY_BT_IPC_HCI_MPAF:
        case CY_BT_IPC_HCI_SLIPH5:
        default:
            return false;
    }
}

#endif