#ifndef BSP_MODBUS_MB_
#define	BSP_MODBUS_MB_

#ifdef __cplusplus
extern "C" {
#endif

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "bsp_gate.h"

#define MODBUS_MAX_TASK     (300u)
#define MODBUS_MAX_DEV      (32u)
#define MODBUS_GATE_FREE_ADDR  (0xFFFF)

/******************************************
 * Helper Macros
 ******************************************/
#define READ_FC03_F04_BEGIN() \
switch(index) \
{


#define READ_FC03_F04_END() \
        default: \
           data = 0x00; \
           break; \
}

#define READ_FC03_F04_ITEM(INDEX, VARIABLE) \
        case INDEX: \
           data = VARIABLE; \
           break;

#define WRITE_REGISTER_MAP_BEGIN() \
switch(index) \
{

#define WRITE_REGISTER_MAP_END() \
        default: \
           break; \
}

#define WRITE_REGISTER_MAP_ITEM(INDEX, VARIABLE) WRITE_REGISTER_MAP_ITEM_EX(INDEX, VARIABLE, value)

#define WRITE_REGISTER_MAP_ITEM_EX(INDEX, VARIABLE, VALUE) \
        case INDEX: \
             VARIABLE = VALUE; \
             break;

#define WRITE_REGISTER_MAP_STATEMENT(INDEX, STATEMENT) \
        case INDEX: \
             STATEMENT; \
             break;

#define WRITE_REGISTER_MAP_ITEM_CONFIG(INDEX, CONFIG) WRITE_REGISTER_MAP_ITEM_CONFIG_EX(INDEX, CONFIG, value)

#define WRITE_REGISTER_MAP_ITEM_CONFIG_EX(INDEX, CONFIG, VALUE) \
        case INDEX: \
             config_save(CONFIG, VALUE); \
             break;
				



typedef enum
{
	kModbusType_RTU,
	kModbusType_TCP,
	kModbusType_End
}ModbusType;

typedef enum
{
    kModbusFun_0x01 = 0x01,
    kModbusFun_0x02 = 0x02,
	kModbusFun_0x03 = 0x03,
	kModbusFun_0x04 = 0x04,
    kModbusFun_0x05 = 0x05,
	kModbusFun_0x06 = 0x06,
    kModbusFun_0x0F = 0x0F,
    kModbusFun_0x10 = 0x10,
	kModbusFun_End,
}ModbusFun;

typedef enum
{
	kBspMdEx_None = 0,
	kBspMdEx_InvalidFunc,
	kBspMdEx_InvalidAddr,
	kBspMdEx_InvalidRegNum,
	kBspMdEx_SlaveFault,
	kBspMdEx_Acknowledge, //从机确认命令但需要较长时间，需要上位机等待
	kBspMdEx_SlaveBusy,
}BspMdExCode;

struct _ModbusItem;
struct _ModbusTask;

typedef BspMdExCode (*ModbusFunCall)(uint16_t start_addr, uint16_t reg_num, uint8_t *buf, uint16_t *len); 
typedef bool (*ModbusSendCall)(uint8_t comm_dev, uint8_t *buf, int32_t len); 
typedef void (*MB_FUNC_CALL)(struct _ModbusItem * mb_item, uint8_t cmd, uint16_t start_addr, uint8_t *buf, uint16_t len);
typedef void (*HmiRxIntCtrlCall)(uint8_t comm_dev, bool is_en);
typedef void (*MasterCall)(struct _ModbusItem * mb_item, uint32_t base_time);


#define MODBUS_BUF_SIZE		(280u)

typedef struct
{
    uint8_t  slave_addr;
    uint8_t  fun_code;
    uint16_t reg_addr;
    uint16_t reg_num;
    uint16_t time_out;
}ModbusHead;


typedef struct _ModbusTask
{
    uint16_t tick;
    uint16_t buf_addr;
    ModbusHead *head;
}ModbusTask;

typedef struct _ModbusItem
{
	uint8_t  	addr;
    uint8_t     comm_dev;
	ModbusType  type;
    bool        is_master;
    uint16_t    tcp_transaction; //事务元标识符
	uint16_t 	buf_pos;
	uint16_t 	buf_size;
	uint16_t	start_addr;
    uint16_t     gate_write_data_absolute_addr;
	uint32_t 	tick;
	ModbusSendCall  send_call;
    GateItem *gate;
    HmiRxIntCtrlCall ctrl_rx_int_call;
    //MB_FUNC_CALL  func_call;
    ModbusFunCall   fun_call_array[kModbusFun_End];
    MasterCall     master_call;
    
    uint8_t  	buf[MODBUS_BUF_SIZE];
    uint8_t     task_cashe;
    uint8_t     cur_task_idx;
    uint8_t     task_num;//动环任务个数
    
    bool        is_read_write_data;
    uint8_t     gate_write_dev_addr;
    uint8_t     gate_write_try_cnt;
    int16_t     gate_write_data_addr;
    uint16_t    gate_write_data_value;
    uint16_t    gate_write_data_start_addr;
    uint16_t    gate_write_data_end_addr;
    uint16_t    time_out[MODBUS_MAX_DEV];
    ModbusHead *gate_write_data_head;
    ModbusTask  *modbus_task;
    struct _ModbusItem *next_item;
} ModbusItem;

typedef struct
{
    uint8_t    call_idx;
    uint16_t   max_task_num;
    uint16_t   gate_write_data_cnt;
    ModbusItem *head_item;
    ModbusItem *lastest_item;
    
    MasterCall master_call_array[20];
    ModbusTask modbus_task_buf[MODBUS_MAX_TASK];
}ModbusCommData;


//#define MODBUS_STATIC_TASK(_name, _slave_addr, _reg_num, _start_addr, _rcv_buf) \
//    ModbusTask _name =  \
//    {   \
//        (NULL), \
//        (_slave_addr), \
//        (_reg_num), \
//        (_start_addr), \
//        (_rcv_buf), \
//    }


#define MODBUS_STATIC_INIT(_name, _modbus_type, _slave_addr, _comm_dev, _send_call, _ctrl_rx_int_call, _func_call)   \
    ModbusItem _name =   \
    {   \
        (_slave_addr), \
        (_comm_dev), \
		(_modbus_type),\
        (false),\
        0,  \
        0,  \
        MODBUS_BUF_SIZE,  \
		0xFFFF,	\
        MODBUS_GATE_FREE_ADDR,	\
        0,  \
		_send_call, \
		_func_call, \
        _ctrl_rx_int_call, \
    }	

#define MODBUS_RTU_STATIC_INIT(_name, _slave_addr, _comm_dev, _send_call, _ctrl_rx_int_call, _gate)		MODBUS_STATIC_INIT(_name, kModbusType_RTU, _slave_addr, _comm_dev, _send_call, _ctrl_rx_int_call, _gate)
#define MODBUS_TCP_STATIC_INIT(_name, _slave_addr, _comm_dev, _send_call, _ctrl_rx_int_call, _gate)		MODBUS_STATIC_INIT(_name, kModbusType_TCP, _slave_addr, _comm_dev, _send_call, _ctrl_rx_int_call, _gate)

#define MODBUS_STATIC_INIT_CCM(_name, _modbus_type, _slave_addr, _comm_dev, _send_call, _ctrl_rx_int_call, _gate)   \
    ModbusItem _name __attribute__((section (".CCM_RAM"))) = \
    {   \
        (_slave_addr), \
        (_comm_dev), \
		(_modbus_type),\
        (false),\
        0,  \
        0,  \
        MODBUS_BUF_SIZE,  \
		0xFFFF,	\
        MODBUS_GATE_FREE_ADDR,	\
        0,  \
		_send_call, \
		_gate, \
        _ctrl_rx_int_call, \
    }	

#define MODBUS_RTU_STATIC_INIT_CCM(_name, _slave_addr, _comm_dev, _send_call, _ctrl_rx_int_call, _gate)		MODBUS_STATIC_INIT_CCM(_name, kModbusType_RTU, _slave_addr, _comm_dev, _send_call, _ctrl_rx_int_call, _gate)
#define MODBUS_TCP_STATIC_INIT_CCM(_name, _slave_addr, _comm_dev, _send_call, _ctrl_rx_int_call, _gate)		MODBUS_STATIC_INIT_CCM(_name, kModbusType_TCP, _slave_addr, _comm_dev, _send_call, _ctrl_rx_int_call, _gate)


void bsp_modbus_poll(ModbusItem * const item, bool is_enable_call);
void bsp_modbus_pos_send(ModbusItem * const mb_item, uint16_t len);
void bsp_modbus_neg_send(ModbusItem * const mb_item, BspMdExCode ex_code);
void bsp_modbus_register_master_fun(ModbusItem * const item, MasterCall master_call);
void register_modbus_fun(ModbusItem * const mb_item, ModbusFun fun_code, ModbusFunCall register_call);
void bsp_modbus_set_slaver_addr(ModbusItem * const item, uint8_t addr);
void bsp_modbus_push_data(ModbusItem * const mb_item, uint8_t *buf, uint16_t len);
void bsp_modbus_slaver_send_read(ModbusItem * const item, uint8_t dev_addr, uint8_t fun_code, uint8_t *buf, uint16_t len);
void bsp_modbus_master_read(ModbusItem * const item, uint8_t dev_addr, uint8_t fun_code, uint16_t start_addr, uint16_t reg_num);
void bsp_modbus_master_single_write(ModbusItem * const item, uint8_t dev_addr, uint8_t fun_code, uint16_t start_addr, uint16_t value);
void bsp_modbus_master_series_write(ModbusItem * const item, uint8_t dev_addr, uint8_t fun_code, uint16_t start_addr, uint16_t reg_num, uint8_t *buf);    
bool bsp_modbus_register_task(ModbusItem * const item, ModbusHead *head);
uint16_t bsp_modbus_get_time_out(ModbusItem * const item, uint8_t addr);

void bsp_modbus_poll_all(uint32_t base_time);
void bsp_modbus_poll_call(uint32_t base_time);
#ifdef __cplusplus
}
#endif

#endif
