#include "drv_uart.h"

#include "bsp_flash.h"
#include "bsp_queue.h"

#include "db_config.h"

#include "version_manager.h"
#include "gpio_manager.h"
#include "comm_manager.h"
#include "flash_manager.h"
#include "eeprom_manager.h"
#include "bmu_manager.h"
#include "kit_data.h"
#include "protocol_comm.h"

typedef enum
{
    kModbusProtocal_None,
	kModbusProtocal_BlueSun,
    kModbusProtocal_End,
}ModbusProtocal;

typedef enum
{
    kCanProtocal_None,   //使用CAN并机的时候需要将外can协议设置为闲置
	kCanProtocal_Bcu,
	kCanProtocal_Bcu_invt,  //英威腾协议
    kCanProtocal_End,
}CanProtocal;

typedef struct
{
    CanCommSend send;
    CanCommPoll poll;
    CanCommReceive receive;
}ProtocalCanItem;

extern QueueItem inter_can_queue;
extern QueueItem exter_can_queue;
extern ModbusItem w5500_modbus_tcp_array[W5500_MODBUS_NUM];
extern const UintArgFunCall tcp_server_poll[W5500_MODBUS_NUM];

QueueItem *queue_can[kcan_dev_e_End] = 
{
    &exter_can_queue,
    &inter_can_queue,
};


/************************************************CAN*****************************************************/
ProtocalCanItem protocal_can[kcan_dev_e_End];

void protocol_can_none_init(can_dev_e can)
{
    protocol_can_set_call(can, NULL, NULL, NULL);
}

typedef void (*CanProtocalCall)(can_dev_e can);
CanProtocalCall protocol_can_init_array[kCanProtocal_End] = 
{
	protocol_can_none_init,
	protocol_can_bcu_init,
};

/************************************************modbus*****************************************************/
void protocal_modbus_none_init(ModbusItem * const mb_item, uint8_t addr)
{
    register_modbus_fun(mb_item, kModbusFun_0x01, NULL);
    register_modbus_fun(mb_item, kModbusFun_0x02, NULL);
    register_modbus_fun(mb_item, kModbusFun_0x03, NULL);
    register_modbus_fun(mb_item, kModbusFun_0x04, NULL);
    register_modbus_fun(mb_item, kModbusFun_0x06, NULL);
    register_modbus_fun(mb_item, kModbusFun_0x10, NULL);
}

/************************************************Model*****************************************************/
typedef void (*UniteProtocalInit)(void * const item, uint16_t addr);
typedef enum
{
    UniteProtocalType_Hmi,
    UniteProtocalType_Modbus,
    UniteProtocalType_Iec104,
    UniteProtocalType_End,
}UniteProtocalType;


typedef struct
{
    bool is_used_model;
    UniteProtocalType type;
    UniteProtocalInit init;
}UniteProtocol;


UniteProtocol unite_protocol_init_array[kModbusProtocal_End] = 
{
    false,      UniteProtocalType_Modbus,   protocol_modbus_bcu_init
	//false,      UniteProtocalType_Modbus,   protocol_modbus_blusun_init
};

/************************************************Init*****************************************************/
void protocol_comm_init(void)
{
    uint16_t protocol, addr;
    uint32_t i, j;
    
    bms_analyse_model_data();

    //485通讯协议
    for(j = 0; j < kModbusIdx_End; j++)
    {
        addr = get_eeprom_data(kEep_InterRS485_SlaveID_Protocol + j, kEepromDataType_High);
        protocol = get_eeprom_data(kEep_InterRS485_SlaveID_Protocol + j, kEepromDataType_Low);
        if((protocol < kModbusProtocal_End))// && (unite_protocol_init_array[protocol].type == UniteProtocalType_Modbus)
        {
            if((bms_get_modbus_model_task_num(j) > 0) && (unite_protocol_init_array[protocol].is_used_model == true))
            {
                modbus_rtu_array[j]->is_read_write_data = true;
                bms_set_tag_data(kTagData_GateIdx, protocol);
                for(i = 0; i < bms_get_modbus_model_task_num(j); i++)
                {
                    bsp_modbus_register_task(modbus_rtu_array[j], bms_get_modbus_model_head_addr(j, i));
                }
            }
            if(unite_protocol_init_array[protocol].init != NULL)
            {
                if(unite_protocol_init_array[protocol].type == UniteProtocalType_Hmi)
                {
									;//上位机预留
                }
                else
                {
                    unite_protocol_init_array[protocol].init(modbus_rtu_array[j], addr);
                }
            }
        }
    }
    
	for(i = 0; i < kcan_dev_e_End;i++)
	{
		protocol = get_eeprom_data(kEep_InterCanProtocol_Baudrate + i, kEepromDataType_High);
		//测试
		protocol = 1;
		if((protocol < kCanProtocal_End) && (protocol_can_init_array[protocol] != NULL))
		{
			protocol_can_init_array[protocol](i);
		}
	}
}


void protocol_can_set_call(can_dev_e can, CanCommReceive rx, CanCommSend tx, CanCommPoll poll)
{
    if(can < kcan_dev_e_End)
    {
        protocal_can[can].send = tx;
        protocal_can[can].poll = poll;
        protocal_can[can].receive = rx;
    }
}


void protocol_can_poll(uint32_t base_time, can_dev_e can)
{
	CanMsg msg;
	uint32_t cnt = 0;

    if(can < kcan_dev_e_End)
    {
        if(protocal_can[can].receive != NULL)
        {
            while ((bsp_queue_pop_instance(queue_can[can], (uint8_t *)&msg) == kKit_Ret_Ok) && (++cnt < 100))
            {
                protocal_can[can].receive(&msg, can);
            }
        }
            
        if(protocal_can[can].send != NULL)
        {
            protocal_can[can].send(base_time, can);
        }
        
        if(protocal_can[can].poll != NULL)
        {
            protocal_can[can].poll(base_time, can);
        }
    }
}

static uint32_t inter_modbus_count = 0,inter2_modbus_count = 0,inter3_modbus_count = 0;
void modbus_rtu_inter_handler(uint32_t base_time)
{
	inter_modbus_count++;
    bsp_modbus_poll(modbus_rtu_array[kModbusIdx_Inter], true);
}


void modbus_rtu_extern_handler(uint32_t base_time)
{
	inter2_modbus_count++;
    bsp_modbus_poll(modbus_rtu_array[kModbusIdx_Exter1], true);
}


void modbus_rtu_externII_handler(uint32_t base_time)
{
	inter3_modbus_count++;
    bsp_modbus_poll(modbus_rtu_array[kModbusIdx_Exter2], true);
}

typedef void (* UintArgCall) (uint32_t arg);
#if W5500_MODBUS_NUM > 0
void protocol_w5500_modbus_tcp_server1_poll(uint32_t base_time)
{
    //bsp_iec104_poll(&w5500_iec104_array[0]);
    bsp_modbus_poll(&w5500_modbus_tcp_array[0], true);
}
#endif
#if W5500_MODBUS_NUM > 1
void protocol_w5500_modbus_tcp_server2_poll(uint32_t base_time)
{
    //bsp_iec104_poll(&w5500_iec104_array[1]);
    bsp_modbus_poll(&w5500_modbus_tcp_array[1], true);
}
#endif
#if W5500_MODBUS_NUM > 2
void protocol_w5500_modbus_tcp_server3_poll(uint32_t base_time)
{
    //bsp_iec104_poll(&w5500_iec104_array[2]);
    bsp_modbus_poll(&w5500_modbus_tcp_array[2], true);
}
#endif
#if W5500_MODBUS_NUM > 3
void protocol_w5500_modbus_tcp_server4_poll(uint32_t base_time)
{
    //bsp_iec104_poll(&w5500_iec104_array[3]);
    bsp_modbus_poll(&w5500_modbus_tcp_array[3], true);
}
#endif
#if W5500_MODBUS_NUM > 4
void protocol_w5500_modbus_tcp_server5_poll(uint32_t base_time)
{
    //bsp_iec104_poll(&w5500_iec104_array[4]);
    bsp_modbus_poll(&w5500_modbus_tcp_array[4], true);
}
#endif
#if W5500_MODBUS_NUM > 5
void protocol_w5500_modbus_tcp_server6_poll(uint32_t base_time)
{
    //bsp_iec104_poll(&w5500_iec104_array[5]);
    bsp_modbus_poll(&w5500_modbus_tcp_array[5], true);
}
#endif
#if W5500_MODBUS_NUM > 6
void protocol_w5500_modbus_tcp_server7_poll(uint32_t base_time)
{
    //bsp_iec104_poll(&w5500_iec104_array[6]);
    bsp_modbus_poll(&w5500_modbus_tcp_array[6], true);
}
#endif
#if W5500_MODBUS_NUM > 7
void protocol_w5500_modbus_tcp_server8_poll(uint32_t base_time)
{
    //bsp_iec104_poll(&w5500_iec104_array[7]);
    bsp_modbus_poll(&w5500_modbus_tcp_array[7], true);
}
#endif

const UintArgCall tcp_server_poll[W5500_MODBUS_NUM] = 
{
    protocol_w5500_modbus_tcp_server1_poll,
    protocol_w5500_modbus_tcp_server2_poll,
    protocol_w5500_modbus_tcp_server3_poll,
    protocol_w5500_modbus_tcp_server4_poll,
    protocol_w5500_modbus_tcp_server5_poll,
    protocol_w5500_modbus_tcp_server6_poll,
    protocol_w5500_modbus_tcp_server7_poll,
    protocol_w5500_modbus_tcp_server8_poll,
};