#include "system/includes.h"
#include "config/config_interface.h"
#include "system/event.h"
#include "app_online_cfg.h"
#include "asm/uart_dev.h"
#include "app_config.h"
#include "app_sound_box_tool.h"

#define LOG_TAG     "[CI-UART]"
#define LOG_ERROR_ENABLE
#define LOG_INFO_ENABLE
#define LOG_DUMP_ENABLE
#include "debug.h"

#if (TCFG_ONLINE_ENABLE || TCFG_SOUNDBOX_TOOL_ENABLE)
struct config_uart {
    u32 baudrate;
    int flowcontrol;
    const char *dev_name;
};

struct uart_hdl {

    struct config_uart config;

    uart_bus_t *udev;
    void *dbuf;

    void *pRxBuffer;

    u8 ucRxIndex;
    u8 rx_type;

    u16 data_length;

    void *pTxBuffer;

    void (*packet_handler)(const u8 *packet, int size);
};


typedef struct {
    //head
    u16 preamble;
    u8  type;
    u16 length;
    u8  crc8;
    u16 crc16;
    u8 payload[0];
} _GNU_PACKED_	uart_packet_t;

#define UART_FORMAT_HEAD  sizeof(uart_packet_t)

typedef struct {
    //head
    u16 preamble0;
    u8  preamble1;
    u16 crc16;
    u8  length;
    u8 	type;
    u8  sq;
    u8 	payload[0];
} _GNU_PACKED_	uart_tool_packet_t;

#define UART_TOOL_FORMAT_HEAD  sizeof(uart_tool_packet_t)

extern u16 crc_get_16bit(const void *src, u32 len);

static void dummy_handler(const u8 *packet, int size);

#define UART_PREAMBLE       		 0xBED6
#define UART_NEW_TOOL_PREAMBLE0      0xAA5A
#define UART_NEW_TOOL_PREAMBLE1      0xA5

#define UART_RX_SIZE        0x100
#define UART_TX_SIZE        0x30
#define UART_DB_SIZE        0x100
#define UART_BAUD_RATE      115200

#ifdef HAVE_MALLOC
static struct uart_hdl *hdl;
#define __this      (hdl)
#else
static struct uart_hdl hdl;
#define __this      (&hdl)

static u8 pRxBuffer_static[UART_RX_SIZE] __attribute__((aligned(4)));       //rx memory
static u8 pTxBuffer_static[UART_TX_SIZE] __attribute__((aligned(4)));       //tx memory
static u8 devBuffer_static[UART_DB_SIZE] __attribute__((aligned(4)));       //dev DMA memory
#endif

void ci_data_rx_handler(u8 type)
{
    u16 crc16;
    uart_tool_packet_t *p_newtool;

    __this->rx_type = type;

    if (type == CI_UART && __this->udev) {
        __this->data_length += __this->udev->read(&__this->pRxBuffer[__this->data_length], (UART_RX_SIZE - __this->data_length), 0);//串口读取buf剩余空间的长度，实际长度比buf长，导致越界改写问题
    }

    /* log_info("Rx : %d", __this->data_length); */
    /* log_info_hexdump(__this->pRxBuffer, __this->data_length); */
    if (__this->data_length > UART_RX_SIZE) {
        log_error("Wired");
    }

    u8 *tmp_buf = NULL;
    tmp_buf = __this->pRxBuffer;
    if (__this->data_length >= 2) {
        unsigned i = 0;
        for (i = 0; i < __this->data_length - 1; ++i) {
            if ((tmp_buf[i] == 0x5A) && (tmp_buf[i + 1] == 0xAA) && (tmp_buf[i + 2] == 0xA5)) {
                break;
            }
        }
        if (i != 0) {
            __this->data_length -= i;
            /* printf("__this->data_length %d i %d\n", __this->data_length, i); */
            if (__this->data_length > 0) {
                memmove(&__this->pRxBuffer[0], &tmp_buf[i], __this->data_length);
            }
        }
    }

    if (__this->data_length <= UART_TOOL_FORMAT_HEAD) {
        return;
    }

    p_newtool = __this->pRxBuffer;

    if ((p_newtool->preamble0 != UART_NEW_TOOL_PREAMBLE0) || (p_newtool->preamble1 != UART_NEW_TOOL_PREAMBLE1)) {
        log_error("preamble err\n");
        log_info_hexdump(__this->pRxBuffer, __this->data_length);
        goto reset_buf;
    }

    if (__this->data_length >= p_newtool->length + 6) {
        crc16 = crc_get_16bit(&p_newtool->length, p_newtool->length + 1);
        /* log_info("CRC16 0x%x / 0x%x", crc16, p_newtool->crc16); */
        if (p_newtool->crc16 != crc16) {
            log_error("crc16 err\n");
            log_info_hexdump(__this->pRxBuffer, __this->data_length);
            goto reset_buf;
        }
        /* log_info_hexdump(p_newtool, p_newtool->length + 6); */
        online_cfg_tool_data_deal(p_newtool, p_newtool->length + 6);
    } else {
        return;
    }

reset_buf:
    __this->data_length = 0;
}

static void ci_uart_isr_cb(void *ut_bus, u32 status)
{
    if (status == UT_TX) {
        return ;
    }
    struct sys_event e;
    e.type = SYS_DEVICE_EVENT;
    e.arg  = (void *)DEVICE_EVENT_FROM_CI_UART;
    e.u.dev.event = 0;
    e.u.dev.value = 0;
    sys_event_notify(&e);
}

static int ci_uart_init()
{
    struct uart_platform_data_t ut = {0};
#if (TCFG_ONLINE_ENABLE || TCFG_SOUNDBOX_TOOL_ENABLE)
#if (TCFG_COMM_TYPE == TCFG_UART_COMM)
    ut.tx_pin = TCFG_TOOL_TX_PORT;
    ut.rx_pin = TCFG_TOOL_RX_PORT;
#endif
#endif
    ut.baud = __this->config.baudrate;
    ut.rx_timeout = 1;
    ut.isr_cbfun = ci_uart_isr_cb;
    ut.rx_cbuf = devBuffer_static;
    ut.rx_cbuf_size = UART_DB_SIZE;
    ut.frame_length = UART_DB_SIZE;
    /* JL_CLOCK->CLK_CON1 |= BIT(11); */
    /* JL_CLOCK->CLK_CON1 &= ~BIT(10); */
    __this->dbuf = devBuffer_static;
    __this->data_length = 0;
    __this->udev = (uart_bus_t *)uart_dev_open(&ut);
    if (__this->udev == NULL) {
        log_error("open uart dev err\n");
        return -1;
    }
    return 0;
}

static void ci_uart_putbyte(char a)
{
    if (__this->udev) {
        __this->udev->putbyte(a);
    }
}

void ci_uart_write(char *buf, u16 len)
{
    if (__this->udev) {
        __this->udev->write(buf, len);
    }
}

static void dummy_handler(const u8 *packet, int size)
{
    log_error("Dummy");
}

static void clock_critical_enter(void)
{

}
static void clock_critical_exit(void)
{
    if (__this->udev) {
        __this->udev->set_baud(__this->config.baudrate);
    }
}
CLOCK_CRITICAL_HANDLE_REG(ci, clock_critical_enter, clock_critical_exit)

static void ci_dev_init(const void *config)
{
#ifdef HAVE_MALLOC
    __this = malloc(sizeof(struct uart_hdl));
    ASSERT(__this, "Fatal error");

    memset(__this, 0x0, sizeof(struct uart_hdl));

    __this->pRxBuffer = malloc(UART_RX_SIZE);
    ASSERT(__this->pRxBuffer, "Fatal error");

    __this->pTxBuffer = malloc(UART_TX_SIZE);
    ASSERT(__this->pTxBuffer, "Fatal error");
#else
    log_info("Static");
    __this->pRxBuffer = pRxBuffer_static;
    __this->pTxBuffer = pTxBuffer_static;
#endif

    __this->packet_handler = dummy_handler;

    ci_transport_config_uart_t *ci_config_uart = (ci_transport_config_uart_t *)config;

    __this->config.baudrate     = ci_config_uart->baudrate_init;
    __this->config.flowcontrol  = ci_config_uart->flowcontrol;
    __this->config.dev_name     = ci_config_uart->device_name;

    log_info("baudrate : %d", __this->config.baudrate);
    log_info("flowcontrol: %d", __this->config.flowcontrol);
}

static int ci_dev_open(void)
{
    ci_uart_init();
    return 0;
}

static int ci_dev_close(void)
{
    return 0;
}

static void ci_dev_register_packet_handler(void (*handler)(const u8 *packet, int size))
{
    __this->packet_handler = handler;
}

static int ci_dev_send_packet(const u8 *packet, int size)
{
    /* dev_stream_out(); */
    int i = 0;
    uart_packet_t *p = (uart_packet_t *)__this->pTxBuffer;

    p->preamble = UART_PREAMBLE;
    p->type     = 0;
    p->length   = size;
    p->crc8     = crc_get_16bit(p, UART_FORMAT_HEAD - 3) & 0xff;
    p->crc16    = crc_get_16bit(packet, size);

    size += UART_FORMAT_HEAD;
    ASSERT(size <= UART_TX_SIZE, "Fatal Error");

    memcpy(p->payload, packet, size);

    /* log_info("Tx : %d", size); */
    /* log_info_hexdump(p, size); */
    if (__this->rx_type == CI_UART) {
#if 0
        while (size--) {
            ci_uart_putbyte(((char *)p)[i++]);
        }
#else
        ci_uart_write(p, size);
#endif
    }

    return 0;
}

static int ci_dev_can_send_packet_now(uint8_t packet_type)
{
    return 0;
}

// get dev api skeletons
static const ci_transport_t ci_transport_uart = {
    /* const char * name; */                                        "CI_UART",
    /* void   (*init) (const void *transport_config); */            &ci_dev_init,
    /* int    (*open)(void); */                                     &ci_dev_open,
    /* int    (*close)(void); */                                    &ci_dev_close,
    /* void   (*register_packet_handler)(void (*handler)(...); */   &ci_dev_register_packet_handler,
    /* int    (*can_send_packet_now)(uint8_t packet_type); */       &ci_dev_can_send_packet_now,
    /* int    (*send_packet)(...); */                               &ci_dev_send_packet,
};

const ci_transport_t *ci_transport_uart_instance(void)
{
    return &ci_transport_uart;
}



#endif

#ifdef  CONFIG_AC608N
//该函数在蓝牙库实现，608没有蓝牙库，在此重定义
u16 crc_get_16bit(const void *src, u32 len)
{
    /* log_info(__func__); */
    u8 *p = (u8 *)src;
    u16 ret;
    OS_SR_ALLOC();
    //  vm_mutex_enter();
    OS_ENTER_CRITICAL();
    JL_CRC->REG = 0 ;

    while (len--) {
        JL_CRC->FIFO = *p++;
    }
    __asm__ volatile("csync");
    ret = JL_CRC->REG;
    OS_EXIT_CRITICAL();
    //  vm_mutex_exit();
    /* printf("CRC16 %02x\r\n", ret); */
    return ret;
}
#endif
