#ifndef _SOE_H_
#define _SOE_H_

#include "Appconfig.h"

#define SOE_ID_MASK   		0xC5 
#define SOE_ID_ACK_NONE		0xFF 
#define SOE_ID_ACK_OK		0x00 
#ifdef SOE_PARA_ALL_SAVE
#define MAX_EVENT_NUMBER    1024  // 最大事件记录数，带全参数的soe个数不能超过1024
#else
#define MAX_EVENT_NUMBER    1100  // 最大事件记录数，
#endif
#define MAX_VIP_NUMBER  512  //最大关键记录数，由于E2PROM大小限制，不能超过512
#define MAX_OPERATE_NUMBER  512  //最大操作记录数，由于E2PROM大小限制，不能超过512
#ifdef ADD_DEBUG_RECORD_FUN
#define MAX_DEBUG_RECORD_NUMBER  512  //最大关键记录数，由于E2PROM大小限制，不能超过512
#else
#define MAX_DEBUG_RECORD_NUMBER  MAX_VIP_NUMBER
#endif

#ifdef GD_AREA_ECZD_MAOMING
	#define EXT_ARG_NUMBER 15
#else
	#define EXT_ARG_NUMBER 13
#endif

// 事件的类型
enum  
{
	SOE_TYPE_EV=1,	// 事件
	SOE_TYPE_YX,	// 遥信
	SOE_TYPE_DPI,	// 双点，值为双点
	SOE_TYPE_PLC,	// PLC
	SOE_TYPE_LNK,	// 级联，值为双点
	SOE_TYPE_TST,	// 测试点
	SOE_TYPE_OPT,	// 操作
	SOE_TYPE_NUM,	// 类型个数
};

#define SOE_TYPE_ACK SOE_TYPE_TST // 类型小于此的都是需要确认的事件 6

#define SOE_TYPE_MASK 		0x0f // 事件类型屏蔽码
#define SOE_TYPE_VIP 		0x10 //  关键事件 标志  //保存全参数
#define SOE_TYPE_DELAY_FHZ	0X20//等至开关分/合位，延迟保存SOE//#define SOE_TYPE_RSV2 		0x20 // 保留位2
#define SOE_TYPE_RSV3 		0x40 // 保留位3  SOE_TYPE_VIP
#define SOE_TYPE_FAULT 		0x80 // 保留位4

#define SOE_BUF_BITS 		11//9->11 用于雪崩测试缓存不够
#define SOE_BUF_NUMBER 		(1<<SOE_BUF_BITS) // 512

// SOE buffer 索引
typedef struct soe_buf_index
{
	volatile u16 n : SOE_BUF_BITS; 
}sbi_t;


// 由于E2PROM大小限制，此结构大小不允许变动，固定为24字节
typedef struct EVENT_STRUCT
{
	// 事件内容
	u8  ev_type;	// 事件属性
	u8	ev_value;	// 状态,双点用最低两位表示，单点用最低1位表示
	u16	ev_code;	// 事件代码
	s32	ev_arg[3];	// 事件参数
#ifdef SOE_PARA_ALL_SAVE
	s32	allarg[8];	// 全事件记录
#endif
	struct timespec ts; // 事件发生时间
}EVENT_STRUCT;

// 由于E2PROM大小限制，此结构大小不允许变动，固定为28字节
typedef struct EVENT_SAVE
{
	// 事件保存用
	u8	es_flag;	// 事件保存标志
	u8  es_ack;		// 事件后台确认标志
	u16 es_id;		// 事件序列号，事件的唯一性标识，用于文件中定位查找事件，特别是最新事件的位置。

 	EVENT_STRUCT es_ev;        
}EVENT_SAVE;


typedef struct EVENT_EXT_ARG
{
	// 事件保存用
	u16 sw;
	BYTE type[EXT_ARG_NUMBER];
	s32 arg[EXT_ARG_NUMBER];
}EVENT_EXT_ARG;
#ifdef	SOE_RECORD_DELAY
	#define DELAY_SOE_MAX 20
	typedef struct DELAY_SOE_DATA
	{
		//bool soe_delay_flag;
		//bool soe_wait_flag;
		u8 value;
		//u8 waitType;	//等待类型，可等待分位或者合位保存SOE:1-分等待;2-合等待
		u16 code;
		long v1;
		long v2;
		long v3;
		struct timespec ts; // 事件发生时间
	}DELAY_SOE_DATA;
#endif
typedef struct SOE_QUEUE //SOE队列
{
	// 事件队列指针
	sbi_t head;
	
	sbi_t tail_eep;						// 保存尾指针
	sbi_t tail_send[COMM_CHANNEL_NUM]; 	// 发送尾指针
	sbi_t tail_ack [COMM_CHANNEL_NUM];	// 确认尾指针

	// 统计
	u32	stat_eep_over;						// 保存溢出计数
	u32	stat_send_over[COMM_CHANNEL_NUM];	// 发送溢出计数
	u32	stat_ack_over[COMM_CHANNEL_NUM];	// 确认溢出计数
	u32 stat_cnt_type[SOE_TYPE_NUM];		// 按类型统计事件计数

	// 事件队列
	EVENT_SAVE soe[SOE_BUF_NUMBER];  //记录缓冲区
	EVENT_EXT_ARG tExtArg[SOE_BUF_NUMBER];

#ifdef SOE_RELINK_DISCOS
	bool bSoeRelink[COMM_CHANNEL_NUM];	
	sbi_t relink_tail_bak[COMM_CHANNEL_NUM]; 	// 发送尾指针
#endif

#ifdef	SOE_RECORD_DELAY
	bool fzsoe_delay_flag; //fz转录启动标志
	bool fzsoe_wait_flag; //fzSOE QUEUE非空
	bool hzsoe_delay_flag; //fz转录启动标志
	bool hzsoe_wait_flag; //hzSOE QUEUE非空
	/*u8 value;
	u16 code;
	long v1;
	long v2;
	long v3;
	struct timespec ts; // 事件发生时间
	*/
	u8 delay_fzsoe_count;
	u8 delay_hzsoe_count;
	DELAY_SOE_DATA delay_fzsoe_tab[DELAY_SOE_MAX];
	DELAY_SOE_DATA delay_hzsoe_tab[DELAY_SOE_MAX];
#endif
}SOE_QUEUE;

typedef struct SOE_INF  // 事件记录保存信息，上电时统计
{
	// 事件记录
	u16 wEvNumber;  // 事件记录数目
	u16 wEvIndex;   // 事件记录保存位置
	u16 wEvID;
	u16 wEvAck; // 上电重新载入事件数

	// 操作记录
	u16 wOpNumber; //操作记录数目
	u16 wOpIndex;   //操作记录保存位置
	u16 wOpID;

	// 关键记录
	u16 wVipNumber; //关键记录数目
	u16 wVipIndex;   //关键记录保存位置
	u16 wVipID;

	// 事件显示
	u16 	wDpAutoShow;
	bool  	bDpNew;
	#ifdef GD_AREA_FOS_2020
	bool    bDpType;  //操作记录标志
	#endif
    //#ifdef ADD_DEBUG_RECORD_FUN	
	u16 wDebugNumber; //调试记录数目
	u16 wDebugIndex;   //调试记录保存位置
	u16 wDebugID;
    //#endif
}SOE_INF;


extern SOE_QUEUE g_soe_queue;
extern SOE_INF g_soe_info;
extern u32 g_ev_words[];
extern u16 dwFaultAll;  // 事故总
extern DWORD dsWarnAll;   //告警总


static inline int soe_ev_is_on(EVENT_STRUCT *ev)
{
	if(ev->ev_type == SOE_TYPE_DPI || ev->ev_type == SOE_TYPE_LNK )
	{
		return (ev->ev_value == SW_DI_TYPE_ON);
	}

	return ev->ev_value;
}

void soe_init(void);

int soe_ev_set(u16 code,u8 v);

int soe_yx2lp(u16 ev_code);
u16 soe_lp2cp(u8 ev_type,u16 ev_code,s32 is_mix);

void soe_record_ev (u16 code,u8 value,long v1,long v2,long v3 );
void soe_record_yx (u16 code,u8 value,struct timespec * ts);
void soe_record_lnk(u16 code,u8 value,struct timespec * ts,s32 v1,bool bmix,u32 cp_s);
void soe_record_dpi(u16 code,u8 value,struct timespec * ts);
void soe_record_plc(u16 code,u8 value, u32 flag);
void soe_record_tst(u16 code,u8 value);
void soe_record_opt(u16 code,long v1);
#ifdef FUN_SET_CHANGE_SOE
void soe_record_opt3(u16 code,long v1,long v2,long v3);
#endif
int soe_get(u8 ch,EVENT_STRUCT *ev);
void soe_ack(u8 chnl,u16 ack);

void soe_save(void);
bool soe_check(u32 code);
void soe_clear_ev(void);
void soe_clear_opt(void);

#endif

