/*****************************************************************************

 FILENAME:       ble_if.c

 DESCRIPTION:    implements the BLE host-controller interface

 AUTHOR:         Guy M.
 Copyright (c) 2022 Texas Instruments Inc.
 All Rights Reserved This program is the confidential and proprietary
 product of Texas Instruments Inc.  Any Unauthorized use, reproduction or
 transfer of this program is strictly prohibited.

 *****************************************************************************/
#include "ble_if.h"
#include "ble_transport.h"
#include "hci_transport.h"
#include "uart_hci.h"
#include "osi_type.h"
#include "osi_kernel.h"
#include "control_cmd_fw.h"
#ifdef CC35XX
#include <third_party/psa_crypto/include/psa/crypto.h>
#include <third_party/psa_crypto/include/psa/crypto_types.h>
#include <third_party/psa_crypto/include/psa/crypto_values.h>
#endif

/*****************************************************************************/
/* DEFINITIONS & GLOBALS                                                     */
/*****************************************************************************/
ble_if_cb_t bleIfCb;


/*****************************************************************************/
/* IMPLEMENTATION                                                            */
/*****************************************************************************/
int BleIf_OpenTransport(ble_if_transport_e transport)
{
    if (transport == BLE_IF_TRANSPORT_SERIAL)
    {
        if (HciTransport_IsInitialized(HCI_TRANSPORT_UART_BLE) == FALSE)
        {
            //Open the UART for HCI
            UartHciOpen();

            //Initialize the HCI transport
            HciTransport_Init(HCI_TRANSPORT_UART_BLE, &uartForHci);
        }

        //Register callbacks
        bleIfCb.cmd_cb = HciTransport_WriteHciPacketToCtrl;
        bleIfCb.event_cb_reg = HciTransport_HciRxCallbackbRegister;

        Report("\n\rBLE Serial transport opened\r\n");
    }
    else
    {
        //Note: shared transport was previously opened when WLAN started
        //It will not be opened here

        //Register callbacks
        bleIfCb.cmd_cb = BleTransport_SendCommand;
        bleIfCb.event_cb_reg = BleTransport_EventCallbackbRegister;

        Report("\n\rBLE Shared transport opened\r\n");
    }

    return 0;
}

int BleIf_CloseTransport()
{
    if (HciTransport_IsInitialized(HCI_TRANSPORT_UART_BLE) == TRUE)
    {
        //Close the UART for HCI
        UartHciClose();

        //Release the HCI transport
        HciTransport_Release(HCI_TRANSPORT_UART_BLE);
    }
    //Note: shared transport was previously opened when WLAN started
    //It will not be closed here

    return 0;
}

int BleIf_SendCommand(uint8_t* cmd, uint16_t cmdLen)
{
    return bleIfCb.cmd_cb(cmd, cmdLen);
}

int BleIf_EventCbRegister(ble_event_cb_t cb)
{
    if (cb == NULL)
    {
        return (-1);
    }

    bleIfCb.event_cb_reg(cb);
    return 0;
}

int BleIf_EnableBLE()
{
    int ret = 0;

#ifdef CC35XX
    ret = BleIf_SetSeed(MAX_SEED_SIZE);
    if (ret < 0)
    {
        Report("\n\r BleIf_EnableBLE: Failed to set initial seed. error number: %d", ret);
        ASSERT_GENERAL(0);
    }
#endif

    //Send BLE enable command to the controller
    ret = ctrlCmdFw_EnableBLECmd();

    if (ret < 0)
    {
        Report("\n\r BleIf_EnableBLE: Failed to enable BLE. error number: %d", ret);
        ASSERT_GENERAL(0);
    }

    //Wait for the controller to be enabled before starting host
    //Currently use sleep. TODO: Wait for FW ready massage
    Report("\n\r-------------- Wait for BLE Controller");
    osi_Sleep(2);

    return ret;
}

int BleIf_SetBdAddr(const unsigned char *pBdAddr)
{
    return ctrlCmdFw_SetBdAddrCmd(pBdAddr);
}

int BleIf_SetSeed(uint8_t size)
{
    int ret = -1;
    uint8_t seed[MAX_SEED_SIZE] = {0};

    //Validate seed size
    if (size > MAX_SEED_SIZE)
    {
        Report("\n\r BleIf_SetSeed: seed size exceeded");
        return ret;
    }

#ifdef CC35XX
    //Check crypto engine status
    psa_status_t status  = psa_crypto_init();
    if (status != PSA_SUCCESS) {
        Report("\n\r BleIf_SetSeed: Crypto is not initialized: %d", status);
        return ret;
    }

    //Get new seed from HSM
    status = psa_generate_random(seed, size);
    if (status != PSA_SUCCESS) {
        Report("\n\r BleIf_SetSeed: Failed to get initial seed. error number: %d", status);
        return ret;
    }
#endif

    //Send set initial seed to the controller
    return ctrlCmdFw_SetSeedCmd(seed, size);
}
