/*
 * @Author: mbw
 * @Date: 2024-12-06 16:52:30
 * @LastEditors: mbw && 1600520629@qq.com
 * @LastEditTime: 2024-12-12 17:30:58
 * @FilePath: \ble_-tyq_-bjq_-ch584-m\bsp\src\bsp_uart.c
 * @Description:
 *
 * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
 */
#include "bsp_uart.h"
#include "lwrb.h"
#include "CH58x_uart.h"
#include "shell_port.h"
#include "CH58xBLE_LIB.h"
#include "bsp_flash.h"
#include "bsp_valve.h"
#include "shell.h"

#undef LOG_ENABLE
#define LOG_ENABLE 1

#include "log.h"

#define UART1_RX_BUFFER_LENGTH 512U
#define UART1_TX_BUFFER_LENGTH 512U

#define UART3_RX_BUFFER_LENGTH 1024U
#define UART3_TX_BUFFER_LENGTH 1024U

lwrb_t uart1_rx_t;
lwrb_t uart1_tx_t;
uint8_t uart1_tx_buf[UART1_TX_BUFFER_LENGTH] = {0};
uint8_t uart1_rx_buf[UART1_RX_BUFFER_LENGTH] = {0};

lwrb_t uart3_rx_t;
lwrb_t uart3_tx_t;
uint8_t uart3_tx_buf[UART3_TX_BUFFER_LENGTH] = {0};
uint8_t uart3_rx_buf[UART3_RX_BUFFER_LENGTH] = {0};

uint8_t BtRxTaskId;

BTFrameData bt_frame = {0};

/**
 * @description: 从帧起始符开始到校验码之前所有字节的和的模256，即各字节不计超过255的溢出值的二进制算术和。
 * @param {uint8_t} *data
 * @param {uint16_t} len
 * @return {*}
 */
uint8_t _CheckSum(const uint8_t *data, size_t len)
{
    uint8_t sum = 0;

    for (size_t i = 0; i < len; i++)
    {
        sum += data[i];
    }
    return sum;
}

// 串口接收
unsigned int BSP_Uart1_Receive_Data(void *buf, unsigned int len)
{
    return lwrb_read(&uart1_rx_t, buf, len);
}

// 串口发送数据
unsigned int BSP_Uart1_Send_Data(const void *buf, unsigned int len)
{
    unsigned int ret;

    ret = lwrb_write(&uart1_tx_t, buf, len);
    UART1_INTCfg(ENABLE, RB_IER_THR_EMPTY);
    return ret;
}

unsigned int BSP_Uart1_Send_String(const void *buf)
{
    return BSP_Uart1_Send_Data(buf, strlen((const char *)buf));
}

// 串口接收
unsigned int BSP_Uart3_Receive_Data(void *buf, unsigned int len)
{
    return lwrb_write(&uart3_rx_t, buf, len);
}

// 串口发送数据
unsigned int BSP_Uart3_Send_Data(const void *buf, unsigned int len)
{
    unsigned int ret;

    ret = lwrb_write(&uart3_tx_t, buf, len);
    UART3_INTCfg(ENABLE, RB_IER_THR_EMPTY);
    return ret;
}

void UART1_FifoInit(void)
{
    lwrb_init(&uart1_tx_t, uart1_tx_buf, sizeof(uart1_tx_buf));
    lwrb_init(&uart1_rx_t, uart1_rx_buf, sizeof(uart1_rx_buf));
}

void UART3_FifoInit(void)
{
    lwrb_init(&uart3_tx_t, uart3_tx_buf, sizeof(uart3_tx_buf));
    lwrb_init(&uart3_rx_t, uart3_rx_buf, sizeof(uart3_rx_buf));
}

/*bt接收数据处理*/
int BSP_Bt_Process(uint8_t *data, uint16_t len)
{
    int ret              = 0;
    uint16_t index       = 0;
    uint8_t data_buf[64] = {0};
    // 解析接收到的数据帧，先寻找AA开头，然后再找AA下一个字节，其代表了数据长度，然后找到代表长度的值的长度的下一位，其为校验码，校验码后为结束码0x55，
    // 如果数据正确，则提取数据，不正确，则不处理
    if (len < 4)
    { // 至少需要 4 个字节：起始码、长度、校验码、结束码
        logError("BT 数据帧长度不足");
        logHexDumpAll(data, len);
        return 1;
    }

    while (index < len && data[index] != 0xAA) // 寻找起始码 0xAA
    {
        index++;
    }
    if (index >= len - 3) // 不够空间容纳长度、校验码和结束码
    {
        logError("BT 数据帧起始码错误");
        logHexDumpAll(data, len);
        return 2;
    }

    uint16_t datalength = data[index + 1]; // 读取数据长度
    if (index + 2 + datalength + 1 >= len) // 检查数据长度是否合理 数据长度 + 校验码 + 结束码
    {
        logError("BT 数据帧长度错误");
        logHexDumpAll(data, len);
        return 3; //
    }

    uint8_t rx_sum         = data[index + 2 + datalength];        // 读取校验码
    uint8_t calculated_sum = _CheckSum(&data[0], datalength + 2); // 计算校验码
    if (rx_sum != calculated_sum)
    {

        logError("BT 数据帧校验码错误 rx_sum = %02X, calculated_sum = %02X", rx_sum, calculated_sum);
        logHexDumpAll(data, len);
        return 4;
    }

    if (data[index + 2 + datalength + 1] != 0x55) // 检查结束码
    {
        logError("BT 数据帧结束码错误");
        logHexDumpAll(data, len);
        return 5;
    }
    // 当程序走到这里时，就说明接收到了正确的数据帧，开始解析命令
    tmos_memcpy(data_buf, &data[index + 3], datalength);
    switch (data[index + 2])
    {
        case kValveCmdCtr:
            ret = BSP_Bt_Valve_Ctr(&data_buf[0], datalength);
            logDebug("recv cmd: 0x01, 执行的动作是关闭阀门");
            break;
        case kValveCmdReg:
            ret = BSP_Bt_Register_Valve(&data_buf[0], datalength);
            logDebug("recv cmd: 0x02, 执行的动作是注册阀门");
            break;
        case kValveCmdRem:
            ret = BSP_Bt_Remove_Valve(&data_buf[0], datalength);
            logDebug("recv cmd: 0x03, 执行的动作是移除阀门");
            break;
        case kValveCmdRep:
            ret = BSP_Bt_Replace_Valve(&data_buf[0], datalength);
            logDebug("recv cmd: 0x04, 执行的动作是更换阀门");
            break;
        default:
            logError("unknow cmd: %02X", data[index + 2]);
            break;
    }

    return ret;
}

/*发送数据帧处理*/
uint8_t BT_GenerateRawFrame(BTFrameData *pRawData, const uint8_t *p_src, uint8_t src_len)
{
    pRawData->len = src_len + 4;

    tmos_memset(pRawData->buf, 0, sizeof(pRawData->buf));

    pRawData->buf[0] = 0XAA;
    pRawData->buf[1] = src_len;

    tmos_memcpy(&pRawData->buf[2], p_src, src_len);

    // 从帧起始符开始到校验码之前所有字节的和的模256
    // ，即各字节不计超过255的溢出值的二进制算术和。
    pRawData->buf[pRawData->len - 2] = _CheckSum(&pRawData->buf[0], pRawData->len - 2);
    pRawData->buf[pRawData->len - 1] = 0X55;

    logHexDumpAll(&pRawData->buf[0], pRawData->len);

    return 0;
}

/**
 * @brief  向报警器发送数据
 * @param  {uint8_t} task_id
 * @param  {uint16_t} events
 * @return {*}
 */
uint16_t BSP_Send_Process(uint8_t *pdata, uint16_t len)
{
    int8_t ret                                   = 0;
    __attribute__((aligned(4))) uint8_t buf[128] = {0};
    ret                                          = BSP_Bt_Process(buf, len);
    if (ret != 0)
    {
        logError("BT 操作失败[%d]", ret);
    }
}

uint16_t BT_ProcessEvent(uint8_t task_id, uint16_t events)
{
    int8_t ret = 0;
    if (events & SYS_EVENT_MSG)
    {
        uint8_t *pMsg;
        uint8_t master_buf[64] = {0};
        if ((pMsg = tmos_msg_receive(BtRxTaskId)) != NULL)
        {
            PRINT("revice data:");
            // for (uint8_t i = 0; i < 5; i++)
            // {
            //     PRINT("%02x ", pMsg[i]);
            // }
            tmos_memcpy(master_buf, pMsg, sizeof(master_buf));
            PRINT("\r\n");
            // Release the TMOS message
            tmos_msg_deallocate(pMsg);
        }
    }
    else if (events & BT_START_EVT)
    {
        lwrb_reset(&uart1_rx_t);
        tmos_start_task(task_id, BT_REC_EVT, 20);
        tmos_start_task(task_id, BT_INFO_UPDATA_EVT, 1000);
        return (events ^ BT_START_EVT);
    }
    else if (events & BT_REC_EVT)
    {
        int len = lwrb_get_full(&uart1_rx_t);
        if (len > 0)
        {
            __attribute__((aligned(4))) uint8_t buf[256] = {0};
            lwrb_read(&uart1_rx_t, buf, len);
            ret = BSP_Bt_Process(buf, len);
            if (ret != 0)
            {
                logError("BT 操作失败[%d]", ret);
            }
        }
        tmos_start_task(task_id, BT_REC_EVT, 20);
        return (events ^ BT_REC_EVT);
    }
    else if (events & BT_SEND_EVT)
    {
        // BSP_Uart1_Send_String("\r\n");//报警器端接收是以回车换行结尾，所以这里也加上换行
        tmos_start_task(task_id, BT_SEND_EVT, 1000);
        return (events ^ BT_SEND_EVT);
    }
    else if (events & BT_INFO_UPDATA_EVT) // 更新蓝牙连接信息
    {
        BSP_Bt_Valve_Updata();
        return (events ^ BT_INFO_UPDATA_EVT);
    }
    return 0;
}

/*BT与报警器主机接口*/
void BSP_UART1_Init(void)
{
    // GPIOPinRemap(ENABLE, RB_PIN_UART1);

    /* 配置串口1：先配置IO口模式，再配置串口 */
    GPIOB_SetBits(BT_UART_RX_PIN);
    GPIOB_ModeCfg(BT_UART_RX_PIN, GPIO_ModeIN_PU);      // RXD-配置上拉输入
    GPIOB_ModeCfg(BT_UART_TX_PIN, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出，注意先让IO口输出高电平
    UART1_DefInit();
    UART1_ByteTrigCfg(UART_1BYTE_TRIG);
    // 中断方式接收数据
    UART1_INTCfg(ENABLE, RB_IER_LINE_STAT | RB_IER_RECV_RDY | RB_IER_THR_EMPTY);
    PFIC_EnableIRQ(UART1_IRQn);
    UART1_FifoInit();
    BtRxTaskId = TMOS_ProcessEventRegister(BT_ProcessEvent);
    tmos_set_event(BtRxTaskId, BT_START_EVT);
}

/*调试接口*/
void BSP_UART3_Init(void)
{
    GPIOPinRemap(ENABLE, RB_PIN_UART3);
    /* 配置串口3：先配置IO口模式，再配置串口 */
    GPIOB_SetBits(UART3_TX_PIN);
    GPIOB_ModeCfg(UART3_RX_PIN, GPIO_ModeIN_PU);      // RXD-配置上拉输入
    GPIOB_ModeCfg(UART3_TX_PIN, GPIO_ModeOut_PP_5mA); // TXD-配置推挽输出，注意先让IO口输出高电平
    UART3_DefInit();
    UART3_BaudRateCfg(460800);
    UART3_ByteTrigCfg(UART_1BYTE_TRIG);
    // 中断方式接收数据
    UART3_INTCfg(ENABLE, RB_IER_LINE_STAT | RB_IER_RECV_RDY | RB_IER_THR_EMPTY);
    PFIC_EnableIRQ(UART3_IRQn);

    UART3_FifoInit();
    userShellInit();
}

/*********************************************************************
 * @fn      UART1_IRQHandler
 *
 * @brief   UART1中断函数
 *
 * @return  none
 */
__INTERRUPT
__HIGH_CODE
void UART1_IRQHandler(void)
{
    uint8_t data;
    switch (UART1_GetITFlag())
    {
        case UART_II_LINE_STAT: // 线路状态错误
        {
            //            UART1_GetLinSTA();
            break;
        }
        case UART_II_RECV_RDY:
        case UART_II_RECV_TOUT: // 接收数据
            while (R8_UART1_RFC)
            {
                data = R8_UART1_RBR;
                lwrb_write(&uart1_rx_t, &data, 1);
            }
            break;

        case UART_II_THR_EMPTY: // 发送缓存区空，可继续发送
            if (lwrb_read(&uart1_tx_t, &data, 1))
            {
                UART1_SendByte(data);
            }
            else
            {
                UART1_INTCfg(DISABLE, RB_IER_THR_EMPTY);
            }

            break;

        case UART_II_MODEM_CHG: // 只支持串口0
            break;

        default:
            break;
    }
}

/*********************************************************************
 * @fn      UART3_IRQHandler
 *
 * @brief   UART1中断函数
 *
 * @return  none
 */
__INTERRUPT
__HIGH_CODE
void UART3_IRQHandler(void)
{
    uint8_t data;
    switch (UART3_GetITFlag())
    {
        case UART_II_LINE_STAT: // 线路状态错误
        {
            //            UART1_GetLinSTA();
            break;
        }
        case UART_II_RECV_RDY:
        case UART_II_RECV_TOUT: // 接收超时
            while (R8_UART3_RFC)
            {
                shellHandler(&shell, R8_UART3_RBR);
            }
            break;
        case UART_II_THR_EMPTY: // 发送缓存区空，可继续发送
            if (lwrb_get_full(&uart3_tx_t))
            {
                lwrb_read(&uart3_tx_t, &data, 1);
                UART3_SendByte(data);
            }
            else
            {
                UART3_INTCfg(DISABLE, RB_IER_THR_EMPTY);
            }

            break;

        case UART_II_MODEM_CHG: // 只支持串口0
            break;

        default:
            break;
    }
}

int reboot(void)
{
    PFIC_SystemReset();
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
                 reboot, reboot, "reboot");
