/******************************************************************************
版权所有：	
文件名称：	rt_error.c
文件版本：	01.01
创建作者：	sunxi
创建日期：	2020-06-18
功能说明：	错误代码管理。
其它说明：
修改记录：
*/
/*------------------------------- 头文件 --------------------------------------
*/
#include "rt.h"
#include "my_rtc.h"
#include <stdatomic.h>
#include "debug_print.h"

/*------------------------------- 宏定义 --------------------------------------
*/
#define ERR_FLAGS_ARG_INDEX		0X0001	// 错误带参数
#define ERR_FLAGS_SW			0X0002	// 软件错误


// sunxi 20200817 added start
// 64位架构上long为8字节会导致上位机获取故障信息错位此处改为int
#define BYTES_PER_INT		sizeof(int)
#define BITS_PER_INT		(BYTES_PER_INT*8)
#define BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_INT))
#define BIT_WORD(nr)		((nr) / BITS_PER_INT)

#define DIV_ROUND_UP(n, d) 		(((n) + (d) - 1) / (d))
#define BITS_TO_INTS(nr)	DIV_ROUND_UP(nr, 8 * sizeof(int))

static inline int test_and_set_bit(int nr, uint32_t *addr)
{
	uint32_t mask = BIT_MASK(nr);
	uint32_t *p = ((uint32_t *)addr) + BIT_WORD(nr);
	uint32_t old = *p;

	*p = old | mask;
	return (old & mask) != 0;
}

static inline int test_and_clear_bit(int nr, uint32_t *addr)
{
	uint32_t mask = BIT_MASK(nr);
	uint32_t *p = ((uint32_t *)addr) + BIT_WORD(nr);
	uint32_t old = *p;

	*p = old & ~mask;
	return (old & mask) != 0;
}

static inline int test_bit(int nr, const volatile uint32_t *addr)
{
	return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_INT-1)));
}
// sunxi 20200817 added end

/*------------------------------ 类型结构 -------------------------------------
*/
struct err_msg
{
	u16 err_code;
	u16 err_flags;
	int err_arg;
	struct timespec ts;
};

struct err_msg_q
{
	u8 head;
	u8 tail;
	
	struct err_msg msg[256];
};

struct err_t
{
	u32 	flags;
	char * 	txt;
};

/*------------------------------ 全局变量 -------------------------------------
*/
struct err_t g_err_txt[] = 
{
	{0,"OK"},
	{ERR_FLAGS_SW,"FLASH CRC错误"},
	{ERR_FLAGS_SW,"RAM CRC错误"},
	{0,"GPS对时错误"},
	{0,"开出自检错误"},
	{0,"报文发送错误"},
	{0,"报文接收错误"},
	{ERR_FLAGS_SW,"程序更新错误"},
	
	{ERR_FLAGS_ARG_INDEX,"子板通讯异常"},
	{ERR_FLAGS_ARG_INDEX,"子板故障"},
	
	{ERR_FLAGS_ARG_INDEX,"ADC初始化错误"},
	{0,"FPGA初始化错误"},
	{0,"E2PROM初始化错误"},
	{0,"FLASH初始化错误"},
	{0,"实时时钟错误"},
	
	{ERR_FLAGS_SW | ERR_FLAGS_ARG_INDEX,"交流系数错误"},
	{ERR_FLAGS_SW ,"直流系数错误"},
	{ERR_FLAGS_SW ,"SWTICH初始化错误"},
	{ERR_FLAGS_SW ,"录波初始化错误"},
	{ERR_FLAGS_SW ,"软件初始化错误"},
	{0,"未知错误"},
	
	{0,"装置错误"},
	{ERR_FLAGS_SW ,"板卡资源文件错误"},
	{ERR_FLAGS_SW ,"装置配置文件错误"},
	{ERR_FLAGS_SW ,"装置参数错误"},
	
	{ERR_FLAGS_SW ,"定值无效"},
	{ERR_FLAGS_SW ,"内部定值无效"},
	{ERR_FLAGS_SW ,"公共定值无效"},
	{ERR_FLAGS_SW ,"定值描述文件错误"},
	{ERR_FLAGS_SW ,"定值数据文件错误"},
	{ERR_FLAGS_SW ,"状态板定值错误"},
	
	{ERR_FLAGS_SW ,"创建资源表错误"},
	{ERR_FLAGS_SW ,"转发表错误"},
	{ERR_FLAGS_SW ,"可编程逻辑错误"},

	{ERR_FLAGS_SW ,"日志文件错误"},

	{ERR_FLAGS_SW ,"版本文件错误"},
	
	{0,"装置失电"},
	{ERR_FLAGS_SW ,"上电合闸文件错误"},
	{ERR_FLAGS_SW ,"汉字库文件错误"},	
	{ERR_FLAGS_SW ,"电池活化文件错误"},
	{ERR_FLAGS_SW ,"装置授权错误"},
	{0 ,"加密芯片错误"},
};	


struct err_t g_err_entxt[] =
{
	{0,"OK"},
	{ERR_FLAGS_SW,"FLASH CRC error"},
	{ERR_FLAGS_SW,"RAM CRC error"},
	{0,"GPS set time error"},
	{0,"Self-checking error"},
	{0,"The message send error"},
	{0,"Message receiving error"},
	{ERR_FLAGS_SW,"Program update error"},
	
	{ERR_FLAGS_ARG_INDEX,"Subboard communication exceptions"},
	{ERR_FLAGS_ARG_INDEX,"Subboard failure"},
	
	{ERR_FLAGS_ARG_INDEX,"ADC Initialization error"},
	{0,"FPGA Initialization error"},
	{0,"E2PROM Initialization error"},
	{0,"FLASH Initialization error"},
	{0,"Real-time clock error"},
	
	{ERR_FLAGS_SW | ERR_FLAGS_ARG_INDEX,"AC Coefficient error"},
	{ERR_FLAGS_SW ,"DC Coefficient error"},
	{ERR_FLAGS_SW ,"SWTICH Initialization error"},
	{ERR_FLAGS_SW ,"Record wave initialization error"},
	{ERR_FLAGS_SW ,"Software initialization error"},
	{0,"Unknown error"},
	
	{0,"Device error"},
	{ERR_FLAGS_SW ,"Board resource file error"},
	{ERR_FLAGS_SW ,"Device configuration file error"},
	{ERR_FLAGS_SW ,"Device parameter error"},
	
	{ERR_FLAGS_SW ,"The set fixed value is invalid"},
	{ERR_FLAGS_SW ,"The internal fixed value is invalid"},
	{ERR_FLAGS_SW ,"The public fixed value is invalid"},
	{ERR_FLAGS_SW ,"The file of setting value describes error"},
	{ERR_FLAGS_SW ,"The file of setting value data  error"},
	{ERR_FLAGS_SW ,"Error of state board fixed value"},
	
	{ERR_FLAGS_SW ,"Create a resource table error"},
	{ERR_FLAGS_SW ,"Iectable error"},
	{ERR_FLAGS_SW ,"PLC error"},

	{ERR_FLAGS_SW ,"LOG file error "},

	{ERR_FLAGS_SW ,"Version file error"},
	
	{0,"Device power-lossing"},
	{ERR_FLAGS_SW ,"Load power file error"},
	{ERR_FLAGS_SW ,"Chinese character library file error"},	
	{ERR_FLAGS_SW ,"Incorrect battery activation file"},
	{ERR_FLAGS_SW ,"Device authorization error"},
	{0 ,"Encryption chip error"},
};


atomic_uint g_err_cnt_hw; // 硬件错误计数
atomic_uint g_err_cnt_sw; // 软件错误计数

uint32_t  g_err_bit[BITS_TO_INTS(ERR_CODE_NUM)];

#if 0 // sunxi 20180730 类型不正确
int g_err_arg[ERR_CODE_NUM];
#else
uint32_t g_err_arg[ERR_CODE_NUM];
#endif

struct err_msg_q g_err_queue;

/*------------------------------ 函数声明 -------------------------------------
*/


/*------------------------------ 外部函数 -------------------------------------
外部函数供其它实体文件引用，必须仔细检查传入参数的合法性.
*/

int rt_err_init(void)
{
	int num;

	num = sizeof(g_err_txt)/sizeof(g_err_txt[0]);
	if(num != ERR_CODE_NUM)
    {
        dp_err_n_c_rt("rt_err_init error(ERR_CODE_NUM=%d,num=%d).\r\n", ERR_CODE_NUM, num);
        return -1;
    }
    atomic_init(&g_err_cnt_hw, 0);
	atomic_init(&g_err_cnt_sw, 0);
	
	return 0;
}


int rt_err_exit(void)
{

	return 0;
}


int rt_err_set(u32 err_code,u32 err_arg)
{
	struct err_msg * em;
	int is_msg_log=0;

	// 检查错误代码是否越限
	if(err_code >= ERR_CODE_NUM)
	{
		return -1;
	}

	// 处理错误参数
	if(g_err_txt[err_code].flags&ERR_FLAGS_ARG_INDEX)
	{
		// 检查参数索引
		if(err_arg >= 32)
		{
			dp_err_n_c_rt("rt_err_set err:err_code=%lu, err_arg=%lu", err_code,err_arg);
			return -2;
		}
		
		// 处理索引参数
		if(test_and_set_bit(err_arg,&g_err_arg[err_code]) == 0)
		{
			is_msg_log = 1;
		}
	} 
	else
	{
		g_err_arg[err_code] = err_arg;
	}

	// 处理错误代码
	if(test_and_set_bit(err_code,g_err_bit) == 0)
	{
		if(g_err_txt[err_code].flags&ERR_FLAGS_SW)
		{
			// atomic_inc(&g_err_cnt_sw);
			atomic_fetch_add(&g_err_cnt_sw, 1);
		}
		else
		{
			// atomic_inc(&g_err_cnt_hw);
			atomic_fetch_add(&g_err_cnt_hw, 1);
		}
		is_msg_log = 2;
	}

	// 如果需要，将错误信息放入队列。
	if(is_msg_log)
	{
		if((u8)(g_err_queue.tail - g_err_queue.head) != 1)
		{
			em = &g_err_queue.msg[g_err_queue.head];
			em->err_code = err_code;
			em->err_arg = err_arg;
			em->err_flags = 1;
			clk_time_get(&em->ts);
			g_err_queue.head++;
		}
		else
		{
			rt_printf("rt_err_clr g_err_queue full!\r\n");
		}
	
		dp_err_n_c_rt("%s产生[错误参数:%lu]!\r\n",g_err_txt[err_code].txt,err_arg);
	}

	return 0;
}


int rt_err_clr(u32 err_code,int err_arg)
{
	struct err_msg * em;
	int is_msg_log=0;
	
	// 检查错误代码是否越限
	if(err_code >= ERR_CODE_NUM)
	{
		return -1;
	}
	
	// 处理错误参数
	if(g_err_txt[err_code].flags & ERR_FLAGS_ARG_INDEX)
	{
		// 检查参数索引
		if(err_arg >= 32)
		{
			return -2;
		}

		// 处理索引参数
		if(test_and_clear_bit(err_arg,&g_err_arg[err_code]) != 0)
		{
			is_msg_log = 1;
		}
		
		// 处理错误代码
		if(g_err_arg[err_code] == 0)
		{
			if(test_and_clear_bit(err_code,g_err_bit) != 0)
			{
				if(g_err_txt[err_code].flags&ERR_FLAGS_SW)
				{
					// atomic_dec(&g_err_cnt_sw);
					atomic_fetch_sub(&g_err_cnt_sw, 1);
				}
				else
				{
					// atomic_dec(&g_err_cnt_hw);
					atomic_fetch_sub(&g_err_cnt_hw, 1);
				}
				is_msg_log = 2;
			}
		}

	}
	else 
	{
		// 处理错误代码
		if(test_and_clear_bit(err_code,g_err_bit) != 0)
		{
			if(g_err_txt[err_code].flags&ERR_FLAGS_SW)
			{
				// atomic_dec(&g_err_cnt_sw);
				atomic_fetch_sub(&g_err_cnt_sw, 1);
			}
			else
			{
				// atomic_dec(&g_err_cnt_hw);
				atomic_fetch_sub(&g_err_cnt_hw, 1);
			}
			is_msg_log = 2;
		}
	}
	
	// 如果需要，将错误信息放入队列。
	if(is_msg_log)
	{
		if((u8)(g_err_queue.tail - g_err_queue.head) != 1)
		{
			em = &g_err_queue.msg[g_err_queue.head];
			em->err_code = err_code;
			em->err_arg = err_arg;
			em->err_flags = 0;
			clk_time_get(&em->ts);
			g_err_queue.head++;
		}
		else
		{
			rt_printf("rt_err_clr g_err_queue full!\r\n");
		}
		
		dp_err_n_c_rt("%s消失[错误参数:%d]!\r\n",g_err_txt[err_code].txt,err_arg);
	}

	return 0;
}

int rt_err_test(u32 err_code)
{
	if(err_code >= ERR_CODE_NUM)
	{
		return -1;
	}

	return test_bit(err_code,g_err_bit);

} 

int rt_err_count_hw(void)
{
	return g_err_cnt_hw;
}
int rt_err_count_sw(void)
{
	return g_err_cnt_sw;
}

int rt_err_count(void)
{
	return g_err_cnt_hw + g_err_cnt_sw;
}

char * rt_err_msg(u32 err_code)
{
	if(err_code >= ERR_CODE_NUM)
	{
		return 0;
	}

	return (char *)g_err_txt[err_code].txt;
}


int rt_err_app(void)
{
	static char log[512];
	char hs_log[128]={0};
	char *buf;
	
	
	struct rtc_time_t tm;
	struct err_msg * em;

	while(g_err_queue.head != g_err_queue.tail)
	{
		em = &g_err_queue.msg[g_err_queue.tail++];
		buf = log;

		
		timespec_to_rtc(em->ts,&tm,0);
		sprintf(buf,"20%02hu-%02hu-%02hu %02hu:%02hu:%02hu.%06lu ",tm.year,tm.month,tm.day,tm.hour,tm.min,tm.ms/1000,em->ts.tv_nsec/1000);
		buf += strlen(buf);
		
		if(em->err_flags)
		{
			sprintf(buf,"%s产生[错误参数:%d]",g_err_txt[em->err_code].txt,em->err_arg);
			sprintf(hs_log,"%s occurs",g_err_entxt[em->err_code].txt);
		}
		else
		{
			sprintf(buf,"%s消失[错误参数:%d]",g_err_txt[em->err_code].txt,em->err_arg);
			sprintf(hs_log,"%s disappear",g_err_entxt[em->err_code].txt);
		}
		log_str(LOG_ERR,log);

		if((em->err_code == ERR_CODE_CRC_FLASH)
			||(em->err_code == ERR_CODE_CRC_RAM)
			||(em->err_code == ERR_CODE_GPS)
			||(em->err_code == ERR_CODE_DO_CHECK)
			||(em->err_code == ERR_CODE_CRC_RAM)
			||(em->err_code == ERR_CODE_INIT_ADC)
			||(em->err_code == ERR_CODE_INIT_FPGA)
			||(em->err_code == ERR_CODE_INIT_E2PROM)
			||(em->err_code == ERR_CODE_INIT_SPI_FLASH)
			||(em->err_code == ERR_CODE_RTC)
			||(em->err_code == ERR_CODE_ESAM)
			||(em->err_code == ERR_CODE_SB_COMM))
		{
			if(em->err_flags)
			{
				// sunxi 20200817 app 那边定义的函数 load_hs_log_rcd(TYPE_HW_ERR,false,&tm,hs_log,1);
			}
			else
			{
				// sunxi 20200817 app 那边定义的函数 load_hs_log_rcd(TYPE_HW_ERR,false,&tm,hs_log,0);
			}
		}

		if((em->err_code == ERR_CODE_EQU)
			||(em->err_code == ERR_CODE_EQU_RESOURCE)
			||(em->err_code == ERR_CODE_EQU_CONFIG)
			||(em->err_code == ERR_CODE_RESOURCE_TABLE)
			||(em->err_code == ERR_CODE_IEC_TABLE)
			||(em->err_code == ERR_CODE_HZK))
		{
			if(em->err_flags)
			{
				// sunxi 20200817 app 那边定义的函数 load_hs_log_rcd(TYPE_SW_ERR,false,&tm,hs_log,1);
			}
			else
			{
				// sunxi 20200817 app 那边定义的函数 load_hs_log_rcd(TYPE_SW_ERR,false,&tm,hs_log,0);
			}
		}
		
	}

	return 0;
}

/*------------------------------ 内部函数 -------------------------------------
内部函数以下划线‘_’开头，不需要检查参数的合法性.
*/

/*------------------------------ 测试函数 -------------------------------------
一个实体文件必须带一个本模块的测试函数来进行单元测试，如果的确不方便在本模块中
进行单元测试，必须在此注明实际的测试位置（例如在哪个实体文件中使用哪个测试函数）.
*/

int rt_err_printf(void)
{
	int i,err_cnt;

	rt_printf("\r\n系统错误信息:\r\n");
	
	err_cnt = 0;
	for(i=0;i<ERR_CODE_NUM;i++)
	{
		if(test_bit(i,g_err_bit))
		{
			rt_printf("系统错误(%03d):%s!\r\n",i,g_err_txt[i].txt);
			err_cnt++;
		}
	}

	rt_printf("总计%d个错误(g_err_cnt_hw=%d,g_err_cnt_sw=%d).\r\n",err_cnt,g_err_cnt_hw, g_err_cnt_sw);

	return 0;
}


/*------------------------------ 文件结束 -------------------------------------
*/

