#include "ucos_ii.h"
#include "drv_uart.h"

#include "bsp_can.h"
#include "bsp_task.h"
#include "bsp_queue.h"

#include "version_manager.h"
#include "gpio_manager.h"
#include "comm_manager.h"
#include "flash_manager.h"
#include "eeprom_manager.h"

#include "kit_data.h"
#include "kit_debug.h"
#include "bsp_hmi.h"

#define APP_HMI_BUF_SIZE    (1024 * 4)
uint8_t hmi_buf[4][APP_HMI_BUF_SIZE] __attribute__((section (".CCM_RAM")));

QUEUE_STATIC_INIT_CCM(inter_can_queue, 50, sizeof(CanMsg));
QUEUE_STATIC_INIT_CCM(exter_can_queue, 150, sizeof(CanMsg));
/**************************************************CAN接口**************************************************/
static void can_ctrl_rx_int(uint8_t comm_dev, bool is_en)
{
    drv_can_ctrl_interrupt((can_dev_e)comm_dev, kcan_interrupt_e_Rx, is_en);
}


static void inter_can_tx_it_call(kit_ret_e res, void *data)
{
    OS_TRACE_ISR_ENTER();
    bsp_can_async_poll(INTER_CAN_PORT);
    OS_TRACE_ISR_EXIT();
}

static void exter_can_tx_it_call(kit_ret_e res, void *data)
{
    OS_TRACE_ISR_ENTER();
    bsp_can_async_poll(EXTER_CAN_PORT);
    OS_TRACE_ISR_EXIT();
}

/************************************************UART接口***************************************************/
//const GpioType rs485_tx_en_map[3] = {kGpioType_RS485_Ch1_Tx_En, kGpioType_RS485_Ch2_Tx_En, kGpioType_Rs485_Ch2_TxEn2};
const GpioType rs485_tx_en_map[3] = {kGpioType_RS485_Ch1_Tx_En, kGpioType_RS485_Ch2_Tx_En};
static void uart_ctrl_rx_int(uint8_t comm_dev, bool is_en)
{
    drv_uart_ctrl_interrupt((UartDev)comm_dev, kUartInterrupt_Rx, is_en);
}

static bool uart_async_send(uint8_t comm_dev, uint8_t *buf, int32_t len)
{
    bool res = false;
    if((comm_dev < 3) && ((len < APP_HMI_BUF_SIZE)))
    {
        drv_gpio_set_pin_status(rs485_tx_en_map[comm_dev], kGpioStatus_Low);
        drv_uart_int_async_send((UartDev)comm_dev, buf, len);
    }
    return res;
}

/*********************************************MODBUS实例***************************************************/
QUEUE_STATIC_INIT_CCM(bmu_can_queue, 150, sizeof(CanMsg));
static void inter_can_rx_it_call(kit_ret_e res, void *data)
{
    OS_TRACE_ISR_ENTER();
    bsp_queue_push_instance(&inter_can_queue, data);
    OS_TRACE_ISR_EXIT();
}

static void exter_can_rx_it_call(kit_ret_e res, void *data)
{
    OS_TRACE_ISR_ENTER();
    bsp_queue_push_instance(&exter_can_queue, data);
    OS_TRACE_ISR_EXIT();
}
/*********************************************MODBUS实例***************************************************/
extern EEpromItem eeprom_item;
GATE_STATIC_INIT2_CCM(modbus_gate, 200, (kEep_GateDataEnd - kEep_GateDataStart));
//参数配置和设置中断条件
MODBUS_RTU_STATIC_INIT_CCM(inter_uart_modbus,  0x01, INTER_UART_PORT, uart_async_send,  uart_ctrl_rx_int, &modbus_gate);
MODBUS_RTU_STATIC_INIT_CCM(exter_uart1_modbus, 0x01, EXTER_UART1_PORT, uart_async_send, uart_ctrl_rx_int, &modbus_gate);

ModbusItem *modbus_rtu_array[kModbusIdx_End] = {&inter_uart_modbus, &exter_uart1_modbus};

uint16_t bms_get_gate_read_data_idx(void)
{    
    return modbus_gate.read_buf_idx;
}

uint16_t bms_get_gate_write_data_idx(void)
{    
    return modbus_gate.write_buf_idx;
}

uint16_t bms_get_gate_read_data(uint16_t addr)
{    
    return modbus_gate.read_buf[addr];
}


uint16_t bms_set_gate_write_data(uint16_t addr, uint16_t value)
{
    uint32_t cnt;
    if(bsp_gate_set_data(&modbus_gate, addr, value) == true)
    {
        cnt = 0;
        while((bsp_gate_has_data_change(&modbus_gate, addr) == true) && (cnt++ < 300))
        {
            bsp_task_delay_ms(10);
        }     
    }
    value = bsp_gate_get_write_data(&modbus_gate, addr);
    return value;

}

uint32_t bms_fill_gate_read_data(uint8_t *buf)
{
    kit_copy_buf(buf, modbus_gate.read_buf, modbus_gate.read_buf_idx << 1);
    
    return modbus_gate.read_buf_idx << 1;
}

uint32_t bms_fill_gate_write_data(uint8_t *buf)
{
    kit_copy_buf(buf, modbus_gate.write_buf, modbus_gate.write_buf_idx << 1);
    
    return modbus_gate.write_buf_idx << 1;
}

//中断回调函数
static void inter_uart_rx_it_call(kit_ret_e res, void *data)
{
    OS_TRACE_ISR_ENTER();
    
    bsp_modbus_push_data(&inter_uart_modbus, data, 1);
    OS_TRACE_ISR_EXIT();
}

static void exter_uart1_rx_it_call(kit_ret_e res, void *data)
{
    OS_TRACE_ISR_ENTER();

    bsp_modbus_push_data(&exter_uart1_modbus, data, 1);
    OS_TRACE_ISR_EXIT();
}


static void uart_tx_it_call(kit_ret_e res, void *data)
{
    uint8_t dev = *(uint8_t *)data;
    OS_TRACE_ISR_ENTER();
    if(dev < 3)
    {
		{
			drv_gpio_set_pin_status(rs485_tx_en_map[dev], kGpioStatus_High);
		}
    }        
    OS_TRACE_ISR_EXIT();
}

typedef enum
{
    kUartParity_None,
    kUartParity_Odd,
    kUartParity_Even,
    kUartParity_End,
}UartParity;


const uint16_t uart_parity[kUartParity_End] = {0x0000, 0x0007, 0x0005};
const uint32_t uart_baudrate[kR485BaudRateEnd] = {4800, 9600, 19200, 38400, 115200};
void bms_init_comm(void)
{
    uint32_t i, tmp, prop;
    
    tmp = bms_get_tag_data(kTagData_DevAddr);
    modbus_gate.is_write_check = true;
    modbus_gate.write_buf = &eeprom_item.data_buf[kEep_GateDataStart];

    bsp_eeprom_set_data(kEep_Inter485Parity_Baudrate,1,kEepromDataType_Low);
    bsp_eeprom_set_data(kEep_Exter485_2Parity_Baudrate,1,kEepromDataType_Low);
    
    for(i = 0; i < BMS_485_CHANNEL; i++)
    {
        tmp = get_eeprom_data(kEep_Inter485Parity_Baudrate + i, kEepromDataType_Low);
        if(tmp >= kR485BaudRateEnd)
        {
            tmp = 0;
        }
        
        prop = get_eeprom_data(kEep_Inter485Parity_Baudrate + i, kEepromDataType_High);
        prop = (prop < kUartParity_End) ? uart_parity[prop] : 0;
        
        drv_uart_init((UartDev)modbus_rtu_array[i]->comm_dev, uart_baudrate[tmp], prop | UART_CFG_STOP_BIT_1, kGpioType_Rs485_Ch1_Tx + (i << 1), kGpioType_Rs485_Ch1_Rx + (i << 1));
        drv_uart_set_interrupt((UartDev)modbus_rtu_array[i]->comm_dev, kUartInterrupt_Tx, APP_CFG_INT_PRIO_UART2_RX, uart_tx_it_call);//设置中断回调
    }
	
    drv_uart_set_interrupt(INTER_UART_PORT,  kUartInterrupt_Rx, APP_CFG_INT_PRIO_UART2_RX, inter_uart_rx_it_call);
    drv_uart_set_interrupt(EXTER_UART1_PORT, kUartInterrupt_Rx, APP_CFG_INT_PRIO_UART2_RX, exter_uart1_rx_it_call);
       
	drv_can_init(INTER_CAN_PORT, 250, kGpioType_Can_Ch1_Rx, kGpioType_Can_Ch1_Tx);
    drv_can_set_interrupt(INTER_CAN_PORT, kcan_interrupt_e_Rx, APP_CFG_INT_PRIO_CAN2_RX, inter_can_rx_it_call);
    drv_can_set_interrupt(INTER_CAN_PORT, kcan_interrupt_e_Tx, APP_CFG_INT_PRIO_CAN2_TX, inter_can_tx_it_call);
	
	drv_can_init(EXTER_CAN_PORT, 250, kGpioType_Can_Ch2_Rx, kGpioType_Can_Ch2_Tx);
    drv_can_set_interrupt(EXTER_CAN_PORT, kcan_interrupt_e_Rx, APP_CFG_INT_PRIO_CAN2_RX, exter_can_rx_it_call);
    drv_can_set_interrupt(EXTER_CAN_PORT, kcan_interrupt_e_Tx, APP_CFG_INT_PRIO_CAN2_TX, exter_can_tx_it_call);
}
