#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"
#include "drv_w5500.h"
#define APP_HMI_BUF_SIZE    (1024 * 4)

/************************************************ETH接口***************************************************/
static void w5500_rcv_call(uint8_t socket, uint8_t *buf, uint16_t len);

ModbusItem w5500_modbus_tcp_array[W5500_MODBUS_NUM] __attribute__((section (".ccmram")));
W5500_STATIC_INIT(w5500, kSpiDev_3, kGpioType_W5500Cs, w5500_rcv_call);

uint8_t canID_devNumber = 0;

static void eth_ctrl_rx_int(uint8_t comm_dev, bool is_en)
{
    
}


static bool w5500_tcp_send(uint8_t comm_dev, uint8_t *buf, int32_t len)
{
    uint32_t cnt;
    bool res = false;
    uint16_t addr, tmp;
    uint8_t rcv_buf[2], socket_reg;

    if(comm_dev < 8)
    {
        tmp = cnt = 0;
        socket_reg = W5500_CREAT_SOCKET_REG(comm_dev);
        while(cnt++ < 10)
        {
            drv_w5500_read_socket_reg(&w5500, socket_reg, Sn_TX_FSR_0x20, rcv_buf, 2);
            tmp = READ_BT_INT16U_BY_CONST_POS(rcv_buf, 0);
            if(len < tmp)
            {
                drv_w5500_read_socket_reg(&w5500, socket_reg, Sn_TX_WR_0x24, rcv_buf, 2);
                addr = READ_BT_INT16U_BY_CONST_POS(rcv_buf, 0);

                drv_w5500_dma_write_socket_reg(&w5500, W5500_CREAT_SOCKET_WRITE_BUF(comm_dev), addr, buf, len);
                addr += len;
                WRITE_BT_INT16U_BY_CONST_POS(rcv_buf, 0, addr);
                drv_w5500_write_socket_reg(&w5500, socket_reg, Sn_TX_WR_0x24, rcv_buf, 2);
                
                rcv_buf[0] = SOCKET_CMD_SEND;
                drv_w5500_write_socket_reg(&w5500, socket_reg, Sn_CR_0x01, rcv_buf, 1);
                res = true;
                break;
            }
            kit_time_dly_ms(1);
        }
    }
    return res;
}

bool w5500_tcp_close(uint8_t socket)
{
    bool res = false;
    if(socket < W5500_MODBUS_NUM)
    {
        res = drv_w5500_close_socket(&w5500, socket);
    }
    return res;
}

void w5500_tcp_close_call(uint8_t socket)
{
    if(socket < W5500_MODBUS_NUM)
    {
        
    }
}



void w5500_rcv_call(uint8_t socket, uint8_t *buf, uint16_t len)
{
    bsp_modbus_push_data(&w5500_modbus_tcp_array[socket], buf, len);
}

void bms_poll_w5500(void)
{
    drv_w5500_poll(&w5500);
}

#define STM32_ID_ADDR   0x1FFF7A10

void bms_w5500_net_protocol(void)
{
    uint8_t mac_buf[6];
    uint16_t port, *port_array;
    uint32_t ip, len, addr, net_mask, gateway_ip;

    ip = 2831155300;//get_eeprom_data(kEEData_Eth1IPAddr2_1, kEepromDataType_Double);
    net_mask = 4294967040;//get_eeprom_data(kEEData_Eth1Mask2_1, kEepromDataType_Double);
    gateway_ip = 2831155201;//= get_eeprom_data(kEEData_Eth1Gate1Addr2_1, kEepromDataType_Double);
    drv_w5500_init(&w5500, ip, port_array, gateway_ip, net_mask, (uint8_t *)(STM32_ID_ADDR + 4), 40000); 
}



/**************************************************CAN接口**************************************************/
QUEUE_STATIC_INIT_CCM(inter_can_queue, 50, sizeof(CanMsg));
QUEUE_STATIC_INIT_CCM(exter_can_queue, 150, sizeof(CanMsg));

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,kGpioType_RS485_Ch3_Tx_En};
const GpioType rs485_tx_en_map[4] = {kGpioType_RS485_Ch1_Tx_En,kGpioType_RS485_Ch2_Tx_En,kGpioType_RS485_Ch2_Tx_En,kGpioType_RS485_Ch3_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 < 4) && ((len < APP_HMI_BUF_SIZE)))
    {
        drv_gpio_set_pin_status(rs485_tx_en_map[comm_dev], kGpioStatus_High);
        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);
MODBUS_RTU_STATIC_INIT_CCM(exter_uart2_modbus, 0x01, EXTER_UART2_PORT, uart_async_send, uart_ctrl_rx_int, &modbus_gate);

ModbusItem *modbus_rtu_array[kModbusIdx_End] = {&inter_uart_modbus, &exter_uart1_modbus,&exter_uart2_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 uint8_t buff[8] = {0};
static uint8_t pos = 0;
//中断回调函数
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 exter_uart2_rx_it_call(kit_ret_e res, void *data)
{
    OS_TRACE_ISR_ENTER();
    bsp_modbus_push_data(&exter_uart2_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 < 4)
    {
		drv_gpio_set_pin_status(rs485_tx_en_map[dev], kGpioStatus_Low);
    }        
    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};
const uint32_t can_baudrate[kCanBaudRateEnd] = {125, 250, 500, 1000};
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);
	
		canID_devNumber = get_eeprom_data(kEep_ExterRS485_1SlaveID_Protocol, kEepromDataType_High);
    
    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;
        uint32_t tmpBaud = uart_baudrate[prop];
        drv_uart_init((UartDev)modbus_rtu_array[i]->comm_dev, 115200, 0 | 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);//设置中断回调
    }
	
		uint32_t tmpIndex = get_eeprom_data(kEep_InterCanProtocol_Baudrate + i, kEepromDataType_Low);
		uint32_t tmpCanBaud = can_baudrate[tmpIndex];
    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_uart_set_interrupt(EXTER_UART2_PORT, kUartInterrupt_Rx, APP_CFG_INT_PRIO_UART2_RX, exter_uart2_rx_it_call);
       
		drv_can_init(INTER_CAN_PORT, 500, kGpioType_Can_Ch1_Rx, kGpioType_Can_Ch1_Tx);
    drv_can_set_interrupt(INTER_CAN_PORT, kcan_interrupt_e_Rx, APP_CFG_INT_PRIO_CAN1_RX, inter_can_rx_it_call);
    drv_can_set_interrupt(INTER_CAN_PORT, kcan_interrupt_e_Tx, APP_CFG_INT_PRIO_CAN1_TX, inter_can_tx_it_call);
	
		drv_can_init(EXTER_CAN_PORT, 500, 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);
	
    for(i = 0; i < W5500_MODBUS_NUM; i++)
    {
        w5500_modbus_tcp_array[i].type = kModbusType_TCP;
        w5500_modbus_tcp_array[i].comm_dev = i;
        w5500_modbus_tcp_array[i].start_addr = 0xFFFF;
        w5500_modbus_tcp_array[i].send_call = w5500_tcp_send;
        w5500_modbus_tcp_array[i].buf_size = MODBUS_BUF_SIZE;
        w5500_modbus_tcp_array[i].ctrl_rx_int_call = eth_ctrl_rx_int;
    }
	
    drv_w5500_set_close_call(&w5500, w5500_tcp_close_call);
    drv_spi_init(kSpiDev_3, kSpiFreq_Div2, kSpiMode_C0E0, SpiFrame_MSBFirst, kGpioType_W5500Clk, kGpioType_W5500Miso, kGpioType_W5500Mosi);
    //drv_spi_set_dma(kSpiDev_3, true, true);
    
	drv_gpio_set_pin_status(kGpioType_W5500Rst, kGpioStatus_Low);
    kit_time_dly_ms(500);
    drv_gpio_set_pin_status(kGpioType_W5500Rst, kGpioStatus_High);
    kit_time_dly_ms(1500);
}
