#ifndef _BLV_BUS_PROTOCOL_H
#define _BLV_BUS_PROTOCOL_H

#include "stdint.h"

/************************************************************/
//SRAM设备信息存储地址 - 

/*
设备链表结构 - 
链表起始地址为0x000100 
链表中先存储的是BUS设备信息N个 地址偏移0x000200*N -> SRAM_BUS_Device_List_Addr
在此之后便是存储的轮询设备信息N个 地址偏移0x000200*N -> SRAM_POLL_Device_List_Addr
然后是主动设备信息N个 地址偏移0x000200*N -> SRAM_ACTIVE_Device_List_Addr
最后是普通设备信息N个 

因此在添加设备的时候需要按照设备顺序添加，否则会出错

*****************************************************************************************
|					|			起始地址			|			结束地址				|
|	BUS设备信息		|	SRAM_Device_List_Start_Addr	|	SRAM_BUS_Device_List_Addr		|
|	轮询设备信息	|	SRAM_BUS_Device_List_Addr	|	SRAM_POLL_Device_List_Addr		|
|	主动设备信息	|	SRAM_POLL_Device_List_Addr	|	SRAM_ACTIVE_Device_List_Addr	|
|	普通设备信息	|	SRAM_ACTIVE_Device_List_Addr|	SRAM_Device_List_End_Addr		|
*****************************************************************************************

*/
typedef void (*fun_prt)(uint32_t );	
typedef uint8_t (*fun2_prt)(uint32_t ,uint32_t ,uint16_t );
typedef void (*fun3_prt)(unsigned long);
typedef uint8_t (*fun4_prt)(uint32_t );	

#define Convert_To_Fun_Prt(addr,dev_addr)	{if((addr!=0x00000000) && (addr!=0xFFFFFFFF))	((fun_prt)addr)(dev_addr);}
#define Convert_To_Fun2_Prt(addr,dev_addr,data_addr,len)	{if((addr!=0x00000000) && (addr!=0xFFFFFFFF))	((fun2_prt)addr)(dev_addr,data_addr,len);}

#define RS485OCCUPYTIME    0x01  //485发送函数会占用时间
#define RS485OCCUPYNOTIME  0x00  //485发送函数不占用时间

#define SRAM_Device_List_Size			0x000200	//设备链表存储空间大小 - 设备信息总大小

#define SRAM_BUS_Device_List_Addr			0x000000	//BUS设备链表最后偏移地址 - 4Byte
#define SRAM_POLL_Device_List_Addr			0x000004	//轮询设备链表最后偏移地址
#define SRAM_ACTIVE_Device_List_Addr		0x000008	//主动设备链表最后偏移地址


#define SRAM_Device_List_Start_Addr		0x000100	//设备链表起始地址
#define SRAM_Device_List_End_Addr		0x009FFF	//设备链表结束地址

/*各种设备控制端口号*/
#define Active_Port		0x02	//主动端口
#define Polling_Port	0x01	//轮询端口
#define Bus_port		  0x03	//BUS端口

#define Active_Baud		9600	//主动端口默认波特率
#define Polling_Baud	9600	//轮询端口默认波特率
#define Bus_Baud		115200	//BUS端口默认波特率

/*设备属性信息存储结构*/
typedef enum{
	Dev_Type = 0x00,				//设备类型 - 1Byte
	Dev_Addr,						//设备地址 - 1Byte
	Dev_port,						//设备端口 - 1Byte
	Dev_baud,						//设备波特率 - 4Byte
	Dev_baud_8,
	Dev_baud_16,
	Dev_baud_24,
	Dev_Check,						//设备数据校验 - 1Byte
	Dev_DataLen,					//设备数据长度 - 2Byte	
	Dev_DataLen_H,					//设备数据长度
	Dev_Retrynum,					//设备重发次数 - 1Byte
	Dev_WaitTime,					//设备发送等待时间 - 2Byte
	Dev_WaitTime_8,	
	Dev_Protocol,         //设备协议	
	Dev_Coord,            //设备下标
	Dev_Coord_8,
	Dev_ActionCoord,      //动作下标
  Dev_ActionCoord_8,    	
	Dev_Polling_CF,					//设备轮询数据发送回调函数	- 4Byte
	Dev_Polling_CF_8,
	Dev_Polling_CF_16,
	Dev_Polling_CF_24,
	Dev_Processing_CF,				//设备数据处理回调函数	- 4Byte
	Dev_Processing_CF_8,
	Dev_Processing_CF_16,
	Dev_Processing_CF_24,
	Dev_Data_Process_0,				//设备数据处理回调函数	- 4Byte  也是函数指针的起始地址
	Dev_Data_Process_8,
	Dev_Data_Process_16,
	Dev_Data_Process_24,
	Dev_Input_Type_Get_0,				//设备输入得到回调函数	- 4Byte
	Dev_Input_Type_Get_8,
	Dev_Input_Type_Get_16,
	Dev_Input_Type_Get_24,
	Dev_Output_Ctrl_0,				//设备输出控制回调函数	- 4Byte
	Dev_Output_Ctrl_8,
	Dev_Output_Ctrl_16,
	Dev_Output_Ctrl_24,
	Dev_Output_Loop_State_Get_0,				//设备输出状态得到回调函数	- 4Byte
	Dev_Output_Loop_State_Get_8,
	Dev_Output_Loop_State_Get_16,
	Dev_Output_Loop_State_Get_24,	
	Dev_Output_Group_Ctrl_0,				//设备输出群控制得到回调函数	- 4Byte
	Dev_Output_Group_Ctrl_8,
	Dev_Output_Group_Ctrl_16,
	Dev_Output_Group_Ctrl_24,	
	Dev_Output_Loop_Group_State_Get_0,				//设备输出群状态得到回调函数	- 4Byte
	Dev_Output_Loop_Group_State_Get_8,
	Dev_Output_Loop_Group_State_Get_16,
	Dev_Output_Loop_Group_State_Get_24,		
	Dev_Privately,			//设备私有变量 -- 根据设备类型定义设备数据长度
}Device_Attribute_E;
/************************************************************/

/*2022.12.26 林开锐修改开始*/
/*故障类型开始*/
#define In_ErrFun_LineState				0x01  //离线在线状态
#define In_ErrFun_ELEPercent			0x02  //电池电量
#define In_ErrFun_CurValue				0x03  //电流值  
#define In_ErrFun_ResetTime				0x04  //1901重启次数
#define In_ErrFun_LoopState			    0x05  //设备回路状态
/*故障类型结束*/ 
/*2022.12.26 林开锐修改结束*/

/*485设备状态定义开始*/
#define DEV_IS_ONLINE               0x00    //设备在线
#define DEV_IS_OFFLINE              0x01    //设备离线
#define DEV_IS_LINEUNINIT           0x02    //设备在线离线未初始化或者未确定

#define Port_Normal_Mode		0x01	//正常模式
#define Port_Passthrough_mode	0x02	//透传模式
#define Port_Monitoring_mode	0x03	//监控模式

#define Passthrough_DataLen_Max		0x01E0		//透传数据最长为480Byte

#define BLV_BUS485_WaitLdle_Time	20		//单位:ms
#define BUS_Retry_Flag				0x40	//重发标志
#define BLV_BUS485_ChangeBaudWaitTime	10		//单位：ms
#define BLV_BUS485_ChangeBaudSendWaitTime	20		//单位：ms
#define BLV_POLL485_ChangeBaudWaitTime	10		//单位：ms
/* BLV_BUS 485总线控制协议格式
□ PKT_ADD_FM：己方（发送者）地址																				
□ PKT_TYPE：接收者类型，可以使单个地址，也可以是群发																				
	□ bit 7 ：表示本包所指定的地址是单机地址还是群组编号。																			
		bit 7 = 0 ： 单发地址																		
		bit 7 = 1 ： 群组地址																		
	□ bit 6 ：表示本包是首发数据还是重发数据。																			
		bit 6 = 0 ： 本包属首发数据包																		
		bit 6 = 1 ： 本包属重发数据包																		
	□ bit 3：0 ：序列号。																			
		序列号范围由0~15循环累加，每成功发送一次加1。	
□ PKT_DevType：设备类型
□ PKT_ADD_TO：对方地址（或群组编号）																				
	当接收者类型为群组时，群组编号0对应所有设备，此时发布的信息即为全员广播信息。																			
□ PKT_LEN：包长，整包长度，最大50。																				
□ PKT_CHKSUM：校验和，1Byte，整包数据除PKT_CHKSUM字节外求和取余。																				
□ PKT_CMD：命令类型，固定长度 1Byte 																				
□ PKT_PARA：命令参数，根据PKT_CMD，长度不固定																				
*/
typedef enum{
	PKT_ADD_FM,
	PKT_TYPE,
	PKT_DevType,
	PKT_ADD_TO,
	PKT_LEN,
	PKT_CHKSUM,
	PKT_CMD,
	PKT_PARA,
}BLV_BUS_PKT_E;

/*BUS总线控制协议2 - 长度改为uint16_t类型*/
typedef enum{
	PKT2_ADD_FM,
	PKT2_TYPE,
	PKT2_DevType,
	PKT2_ADD_TO,
	PKT2_LEN,
	PKT2_LEN_8,
	PKT2_CHKSUM,
	PKT2_CMD,
	PKT2_PARA,
}BLV_BUS_PKT2_E;

typedef enum{
	B_IDLE,			//空闲
	B_Polling,		//设备轮询数据发送
	B_Send,			//设备数据发送
	Change_Dev,		//切换设备
	Read_Dev,		//读当前设备信息
	B_Retry,		//数据重发
	Wait_Reply,		//等待回复
	B_Wait,			//BUS总线等待
	Baud_Wait,		//切换波特率等待
	Baud_Comm,		//切换波特率后先发送一包询问数据，在进行正常通讯
	Baud_SendWait,	//切换波特率后发送等待
}G_BLV_BUS;

/*函数指针类型定义开始*/
typedef void (*Dev_Dev_Data_Process_ptr)(uint32_t CfgDevAdd);     //设备数据处理函数 输出控制函数，或者输入检测函数
typedef uint8_t (*Dev_Dev_Input_Type_Get_ptr)(uint32_t CfgDevAddIn, uint16_t DevInputLoop, uint16_t DevInputType);															//设备输入检测函数，传入设备回路地址，返回输入类型
typedef void (*Dev_Output_Ctrl_ptr)(uint32_t CfgDevAddIn, uint16_t DevInputAddr, uint32_t CfgDevAddOut, uint16_t DevOutputLoop, uint16_t DevOutputType);		  	//设备输出控制函数，传入设备类型，输出回路地址，输出类型，即可控制设备
typedef uint16_t (*Dev_Output_Loop_State_Get_ptr)(uint32_t CfgDevAddOut, uint16_t DevOutputLoop);										//设备输出回路状态得到。比如此时LED灯指定回路亮度为50， 那么应该返回50

typedef void (*Dev_Output_Group_Ctrl_ptr)(uint32_t CfgDevAddIn, uint16_t DevInputAddr,uint32_t devaddr, uint32_t CtrlFlag, uint8_t CtrlNum,uint16_t *start);
typedef uint16_t (*Dev_Output_Loop_Group_State_Get_ptr)(uint32_t devaddr, uint8_t SceneType, uint32_t ReadFlag, uint8_t ReadNum,uint16_t *start);

/*函数指针类型定义结束*/
#define Dev_Fun_Ptr_Len    sizeof(Struct_Dev_Fun_Info)    //目前每个设备四个函数指针 一共16个字节

typedef struct 
{
	Dev_Dev_Data_Process_ptr       Dev_Data_Process;           //数据处理
	Dev_Dev_Input_Type_Get_ptr     Dev_Input_Type_Get;         //输入检测
	Dev_Output_Ctrl_ptr            Dev_Output_Ctrl;            //输出控制
	Dev_Output_Loop_State_Get_ptr  Dev_Output_Loop_State_Get;  //输出状态得到
	Dev_Output_Group_Ctrl_ptr      Dev_Output_Group_Ctrl;            //输出群控制
	Dev_Output_Loop_Group_State_Get_ptr  Dev_Output_Loop_Group_State_Get_ptr;  //输出群状态得到
	
}__attribute__ ((__packed__))Struct_Dev_Fun_Info;  					   //设备信息结构体，相同的设备类型拥有相同的函数，只是传的参数不一样


/*通讯记录相关定义*/
#define BLV_COMM_RecordNum			30		
#define BLV_CONTINUE_FAIL_MAX		20			//连续失败最大次数
#define BLV_COMM_Fail_Precent_Max	30			//失败最大百分比
#define BLV_COMM_Precent_Num		100			//通讯百分比开始记录数
#define BLV_BUS_BAUD_ADJUST_SIZE	1000		//每次增加115200*1% 
#define BLV_BUS_BAUD_ADJUST_MIN		103200	
#define BLV_BUS_BAUD_ADJUST_MAX		126200
//#define BLV_BUS_BAUD_ADJUST_MAX		135000

typedef struct{
	uint8_t 	record[BLV_COMM_RecordNum];		//通讯记录BUFF
	uint8_t 	num;							//当前写入下标
	uint8_t		continue_fail_num;				//连续失败计数
	uint8_t 	comm_percent;					//通讯百分比
	uint8_t 	full_flag;						//记录已满标志位
	uint8_t 	remian1;
	uint8_t 	remian2;
}__attribute__ ((packed)) BLV_COMM_RECORD_G;


typedef struct{
	uint8_t 	type;
	uint8_t 	addr;
	uint8_t 	port;
	uint32_t 	baud;
	uint8_t 	check;
	uint16_t 	data_len;
	uint8_t 	retry_num;
	uint16_t 	wait_time;
	uint8_t   Protocol;        //协议
	uint16_t  DevCoord;        //设备存在下标
	uint16_t  ActionCoord;     //对应动作存在下标
/*函数指针申明开始*/
	uint32_t 	polling_cf;                 //发送函数
	uint32_t 	processing_cf;              //接收处理函数
	
	Struct_Dev_Fun_Info DevFunInfo;        //函数指针结构体
	

/*函数指针申明结束*/
}__attribute__ ((packed)) Device_Public_Information_G;

typedef struct{
	uint8_t 	port_mode;				//端口模式 - 0x01:正常模式 0x02:透传模式 0x03:监控模式
	uint8_t 	pass_state;				//透传状态机
	uint32_t 	mode_tick;				//模式当前时间戳
	uint32_t 	mode_outtime;			//模式超时时间
	uint32_t 	pass_tick;				//透传当前时间戳
	uint32_t 	pass_outtime;			//透传超时时间
	uint32_t    baud;					//当前波特率
	fun_prt		BaudRateCfg;			//波特率切换函数
	
	uint8_t 	BUS_Start;				//BUS状态机
	uint8_t 	device_num;				//设备总数
	uint32_t 	n_list_read_addr;		//当前读取的设备链表地址
	uint32_t    Last_list_addr;			//下一个设备链表地址
	uint32_t 	send_wait;				//发送等待时间
	uint8_t		Process_Flag;			//处理标志
	uint8_t 	Retry_Flag;				//重发标记：发送之前置数,收到回复标记后标记清零，
	uint32_t 	change_tick;			//切换波特率时间
	
	uint8_t 	n_dev_type;				//当前设备类型
	uint8_t		n_dev_addr;				//当前设备地址
	uint16_t 	n_dev_datalen;			//当前设备数据长度
	uint32_t	n_dev_waittime;			//当前设备发送等待时间
	uint8_t 	n_retry_num;			//当前设备重发数
	uint32_t 	n_polling_cf;			//当前设备轮询发送回调函数指针
	uint32_t 	n_processing_cf;		//当前设备数据回调函数指针

}__attribute__ ((packed)) BLV_BUS_Manage_G;

typedef struct{
	uint8_t 	port_mode;				//端口模式 - 0x01:正常模式 0x02:透传模式 0x03:监控模式
	uint8_t 	pass_state;				//透传状态机
	uint32_t 	mode_tick;				//模式当前时间戳
	uint32_t 	mode_outtime;			//模式超时时间
	uint32_t 	pass_tick;				//透传当前时间戳
	uint32_t 	pass_outtime;			//透传超时时间
	uint32_t    baud;					//当前波特率
	fun_prt		BaudRateCfg;			//波特率切换函数
	
	uint8_t 	POLL_Start;				//POLL状态机
	uint8_t 	device_num;				//设备总数
	uint32_t 	n_list_read_addr;		//当前读取的设备链表地址
	uint32_t    Last_list_addr;			//下一个设备链表地址
	uint32_t 	send_wait;				//发送等待时间
	uint8_t		Process_Flag;			//处理标志
	uint8_t 	Retry_Flag;				//重发标记：发送之前置数,收到回复标记后标记清零，
	uint32_t 	change_tick;			//切换波特率时间
	
	uint8_t 	n_dev_type;				//当前设备类型
	uint8_t		n_dev_addr;				//当前设备地址
	uint16_t 	n_dev_datalen;			//当前设备数据长度
	uint32_t	n_dev_waittime;			//当前设备发送等待时间
	uint8_t 	n_retry_num;			//当前设备重发数
	uint32_t 	n_polling_cf;			//当前设备轮询发送回调函数指针
	uint32_t 	n_processing_cf;		//当前设备数据回调函数指针

}__attribute__ ((packed)) BLV_POLL_Manage_G;


typedef struct{
	uint8_t 	port_mode;				//端口模式 - 0x01:正常模式 0x02:透传模式 0x03:监控模式
	uint8_t 	pass_state;				//透传状态机
	uint32_t 	mode_tick;				//模式当前时间戳
	uint32_t 	mode_outtime;			//模式超时时间
	uint32_t 	pass_tick;				//透传当前时间戳
	uint32_t 	pass_outtime;			//透传超时时间
	uint32_t    baud;					//当前波特率
	fun_prt		BaudRateCfg;			//波特率切换函数	
	
	uint8_t 	Act_Start;				//Active状态机
	uint8_t 	device_num;				//主动设备总数
	uint8_t		process_num;			//数据处理计数
	
	uint32_t  list_read_addr;			//处理地址
	uint32_t 	n_list_read_addr;		//当前读取的设备链表地址
	uint32_t    Last_list_addr;			//下一个设备链表地址
	uint32_t 	send_wait;				//发送等待时间
	uint8_t		Process_Flag;			//处理标志
	uint8_t 	Send_Flag;				//发送标记
	uint8_t 	Retry_Flag;				//重发标记：发送之前置数,收到回复标记后标记清零，
	
	uint32_t	n_dev_waittime;			//当前设备发送等待时间
	uint8_t 	n_retry_num;			//当前设备重发数
	uint32_t 	n_polling_cf;			//当前设备轮询发送回调函数指针
	uint32_t 	n_processing_cf;		//当前设备数据回调函数指针
	
}__attribute__ ((packed)) BLV_ACTIVE_Manage_G;



void Add_BUS_Device_To_List(uint8_t type,uint8_t addr,uint8_t *dev_data,uint16_t data_len,void (*polling_cf)(uint32_t ),uint8_t (*processing_cf)(uint32_t ,uint32_t ,uint16_t ));
void Add_BUS_Device_To_List2(Device_Public_Information_G *dev_info,uint8_t *dev_data,uint16_t data_len);
void Add_POLL_Device_To_List2(Device_Public_Information_G *dev_info,uint8_t *dev_data,uint16_t data_len);
void Add_ACT_Device_To_List2(Device_Public_Information_G *dev_info,uint8_t *dev_data,uint16_t data_len);

void BLV_BUS_Polling_Task2(void);
void BLV_PollPort_Task(void);
void BLV_BUS_Processing_Task(void);
void BLV_ActivePort_Task(void);
void BLV_ActivePort_ModeTask(void);

uint8_t BLV_Active_Dev_Scan(uint32_t dev_addr);
void BLV_Active_Set_List_Addr(uint32_t addr);
uint32_t Find_Device_List_Information(uint8_t dev_type,uint8_t addr);
uint8_t Find_The_Number_Of_Device_In_The_List(void);
uint8_t Gets_the_state_of_all_devices(uint8_t *data_buff,uint8_t num);

/*2022.12.26 林开锐修改开始*/
void Write_Device_Fault_State(uint8_t device_type,uint8_t device_addr,uint8_t fault_type,uint8_t fault_state);	//写设备故障状态到SRAM

/*2022.12.26 林开锐修改结束*/

void Act485Port_Passthrough_Task(void);
void BLV_PollPort_ModeTask(void);
void BLV_BUS485Port_ModeTask(void);

void BLV_Communication_Record(BLV_COMM_RECORD_G *dev_record,uint8_t option,uint8_t state);
uint8_t BLV_Communication_Baud_Adjust(BLV_COMM_RECORD_G *dev_record,uint32_t baud_addr);
uint8_t BLV_Communication_Baud_Adjust2(BLV_COMM_RECORD_G *dev_record,Device_Public_Information_G *dev_info);
uint16_t Get_BLV_Communication_Fail_Rate(BLV_COMM_RECORD_G *dev_record);

extern BLV_BUS_Manage_G BUS485_Info;
extern BLV_ACTIVE_Manage_G Act485_Info;
extern BLV_POLL_Manage_G Poll485_Info;

void Write_Device_Loop_Fault_State(uint8_t device_type,uint8_t device_addr,uint8_t fault_type,uint8_t fault_state,uint16_t loop);

#endif
