/***************************************************************************
 *
 * Copyright 2015-2019 BES.
 * All rights reserved. All unpublished rights reserved.
 *
 * No part of this work may be used or reproduced in any form or by any
 * means, or stored in a database or retrieval system, without prior written
 * permission of BES.
 *
 * Use of this work is governed by a license granted by BES.
 * This work contains confidential and proprietary information of
 * BES. which is protected by copyright, trade secret,
 * trademark and other intellectual property rights.
 *
 ****************************************************************************/
#include "stdbool.h"
#include "hal_intersys.h"
#include "hal_iomux.h"
#include "hal_uart.h"
#include "hal_trace.h"
#include "string.h"
#include "hal_chipid.h"
#include "heap_api.h"
#include "bt_drv.h"
#include "bt_drv_2300p_internal.h"
#include "bt_drv.h"
#include "bt_drv_interface.h"

#define BT_UART_BRIDGE_BUF_LEN (1024)

static const struct HAL_UART_CFG_T uart_cfg = {
    .parity = HAL_UART_PARITY_NONE,
    .stop = HAL_UART_STOP_BITS_1,
    .data = HAL_UART_DATA_BITS_8,
    .flow = HAL_UART_FLOW_CONTROL_NONE,
    .tx_level = HAL_UART_FIFO_LEVEL_1_2,
    .rx_level = HAL_UART_FIFO_LEVEL_1_4,
    .baud = 115200,
    .dma_rx = true,
    .dma_tx = true,
    .dma_rx_stop_on_err = false,
};

#if (DEBUG_PORT == 1)
enum HAL_UART_ID_T br_uart = HAL_UART_ID_0;
#else
enum HAL_UART_ID_T br_uart = HAL_UART_ID_1;
#endif
enum HAL_INTERSYS_ID_T br_intersys = HAL_INTERSYS_ID_0;

static volatile bool uart_rx_done = false;
static volatile bool uart_tx_done = false;
static volatile bool bt_rx_done = false;
static volatile bool bt_tx_done = false;

static unsigned char *uart_rx_data_p;
static volatile unsigned int uart_rx_len = 0;

static unsigned char *bt_rx_data_p;
static volatile unsigned int bt_rx_len = 0;

static void uart_rx(uint32_t xfer_size, int dma_error, union HAL_UART_IRQ_T status)
{
    if (dma_error) {
        BT_DRV_TRACE(1,"uart_rx dma error: xfer_size=%d", xfer_size);
        uart_rx_len = 0;
    } else if (status.BE || status.FE || status.OE || status.PE) {
        BT_DRV_TRACE(2,"uart_rx uart error: xfer_size=%d, status=0x%08x", xfer_size, status.reg);
        uart_rx_len = 0;
    } else {
        uart_rx_len = xfer_size;
    }
    uart_rx_done = true;
}

static void uart_tx(uint32_t xfer_size, int dma_error)
{
    if (dma_error) {
        BT_DRV_TRACE(1,"uart_tx dma error: xfer_size=%d", xfer_size);
    }
    uart_tx_done = true;
}

#ifdef VCO_TEST_TOOL
static unsigned int bt_rx(const unsigned char *data, unsigned int len);

void vco_test_simu_bt_rx(void)
{
    const  unsigned char hci_bt_vco_test_event[] = {0x04, 0x0e, 0x04, 0x05, 0xaa,0xfc,0x00};
    bt_rx(hci_bt_vco_test_event, sizeof(hci_bt_vco_test_event));
}
#endif

static unsigned int bt_rx(const unsigned char *data, unsigned int len)
{
    unsigned int processed = len;


    hal_intersys_stop_recv(br_intersys);
    if (bt_rx_len + processed > BT_UART_BRIDGE_BUF_LEN) {
        BT_DRV_TRACE(3,"bt_rx data too long: bt_rx_len=%d, len=%d, limit=%d", bt_rx_len, processed, sizeof(bt_rx_data_p));
        processed = BT_UART_BRIDGE_BUF_LEN-bt_rx_len;
    }
    if (processed > 0) {
        memcpy(bt_rx_data_p + bt_rx_len, data, processed);
        if((data[0] == 0x4) && (data[2] == 0xc) && (data[4] == 0x1) && (data[5] == 0x10))
        {
            *(uint8_t *)(bt_rx_data_p + bt_rx_len+7) = 0x09;
            *(uint8_t *)(bt_rx_data_p + bt_rx_len+10) = 0x09;
        }
        if(data[0] == 0x4 && data[1] == 0xe && data[4] == 0x3 && data[5] == 0xc)
        {
             memset((uint32_t *)BT_EM_ADDR_BASE,0,BT_EM_SIZE/4);
            *(uint32_t *)0xd02201e4 = 0;
        }
        BT_DRV_TRACE(0,"[TX]:");
        DUMP8("%02x ",bt_rx_data_p + bt_rx_len,processed);
        bt_rx_len += processed;
        bt_rx_done = true;
    }
    return len;
}

static void bt_tx(const unsigned char *data, unsigned int len)
{
    bt_tx_done = true;
}

void btdrv_uart_bridge_loop(void)
{
    int ret;
    union HAL_UART_IRQ_T mask;

    syspool_init();

    syspool_get_buff(&uart_rx_data_p, BT_UART_BRIDGE_BUF_LEN);
    syspool_get_buff(&bt_rx_data_p, BT_UART_BRIDGE_BUF_LEN);

    if (br_uart == HAL_UART_ID_0) {
        hal_iomux_set_uart0();
        hal_trace_switch(HAL_TRACE_TRANSPORT_UART1);
        hal_iomux_set_uart1();
    } else {
        hal_iomux_set_uart1();
        hal_trace_switch(HAL_TRACE_TRANSPORT_UART0);
        //hal_iomux_set_uart0();
    }

    ret = hal_uart_open(br_uart, &uart_cfg);
    if (ret) {
        BT_DRV_TRACE(0,"Failed to open uart");
        return;
    }

    hal_uart_irq_set_dma_handler(br_uart, uart_rx, uart_tx);
    mask.reg = 0;
    mask.BE = 1;
    mask.FE = 1;
    mask.OE = 1;
    mask.PE = 1;
    mask.RT = 1;
    hal_uart_dma_recv_mask(br_uart, uart_rx_data_p, BT_UART_BRIDGE_BUF_LEN, NULL, NULL,&mask);

    ret = hal_intersys_open(br_intersys, HAL_INTERSYS_MSG_HCI, bt_rx, bt_tx, false);
    if (ret) {
        BT_DRV_TRACE(0,"Failed to open intersys");
        return;
    }
    hal_intersys_start_recv(br_intersys);
    BT_DRV_TRACE(0,"Enter bridge mode");

    while (1) {
        if (uart_rx_done) {
            uart_rx_done = false;
            if (uart_rx_len > 0) {
                BT_DRV_TRACE(0,"[RX]:");
                DUMP8("%02x ",uart_rx_data_p,uart_rx_len);
#ifdef LAURENT_ALGORITHM
                btdrv_ble_test_bridge_intsys_callback(uart_rx_data_p);
#endif

#ifdef VCO_TEST_TOOL
                if(btdrv_vco_test_bridge_intsys_callback(uart_rx_data_p))
                {
                    uart_rx_len =0;
                    continue ;
                }
#endif
                hal_intersys_send(br_intersys, HAL_INTERSYS_MSG_HCI, uart_rx_data_p, uart_rx_len);
            } else {
                bt_tx_done = true;
            }
        }
        if (uart_tx_done) {
            uart_tx_done = false;
            bt_rx_len = 0;
            hal_intersys_start_recv(br_intersys);
        }
        if (bt_rx_done) {
            bt_rx_done = false;
            if (bt_rx_len > 0) {
                hal_uart_dma_send(br_uart, bt_rx_data_p, bt_rx_len, NULL, NULL);
            } else {
                uart_tx_done = true;
            }
        }
        if (bt_tx_done) {
            bt_tx_done = false;
            hal_uart_dma_recv_mask(br_uart, uart_rx_data_p, BT_UART_BRIDGE_BUF_LEN, NULL, NULL,&mask);
        }
#ifdef VCO_TEST_TOOL
        if(btdrv_get_vco_test_process_flag())
        {
            btdrv_vco_test_process(btdrv_get_vco_test_process_flag());
            vco_test_simu_bt_rx();
        }
#endif
    }
}

