/******************************************************************************
版权所有：	
文件名称：	pw_quality.c
文件版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-04
功能说明：	DTU电能质量处理函数
其它说明：
修改记录：
*/
/*------------------------------- 头文件 --------------------------------------
*/
#include "head.h"
 

/*------------------------------- 宏定义 --------------------------------------
*/
#define FILE_VERSION	0X01010101	//文件版本

enum
{
	ENERGY_FILE,		//电度文件
	EXTREMA_FILE,		//极值记录文件
	MEARCD_FILE,		//定点遥测记录文件
	CAP_FILE,			//电容器管理文件
	UDCRCD_FILE,			//电池电压记录文件
	FILE_NUM
};

enum
{
	YEAR=1,
	MONTH,
	DAY,
};
/*------------------------------ 全局变量 -------------------------------------
*/
struct pw_quality_file
{
	s8 *			name;
	int				offset;
	struct file * 	handle;
};

struct pw_quality_file g_pw_quality_file[] = 
{
	{"/app/data/energy.bin",		0,0},
	{"/app/data/extrema.bin",		0,0},
	{"/app/data/mearcd.bin",		0,0},
	{"/app/data/cap.bin",			0,0},
	{"/app/data/udcrcd.bin",			0,0},
};

struct pw_quality 		g_energy;
struct pw_quality 		g_extrema;
struct pw_quality 		g_mearcd;
struct pw_quality		g_capmanage;
struct pw_quality		g_udcrcd;

struct energy_rcd		g_energy_rcd[2];
struct extrema_rcd 		g_extrema_rcd[2];
struct mea_rcd			g_mea_rcd[2];
struct cap_rcd			g_cap_rcd[2]; 
struct udc_rcd			g_udc_rcd[2];

int g_pw_init;
/*------------------------------ 函数声明 -------------------------------------
*/
int energy_create_file(void);
int extrema_create_file(void);
int mearcd_create_file(void);
int capmanage_create_file(void);
int udcrcd_create_file(void);

int pw_quality_file_init(u8 file_no);
int pw_quality_file_rcd(u8 file_no, u32 index, u32 rcd_num, u32 len, u32 size, char *new_rcd, char *nul_rcd );

static int _index_check(u32 num,  u32 len, u8 *buf);
static void _get_ac_name(u16 owner,u16 index,char *name);
/*------------------------------ 外部函数 -------------------------------------
外部函数供其它实体文件引用，必须仔细检查传入参数的合法性.
*/
/******************************************************************************
函数名称：energy_init
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：电度初始化
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int energy_init(void)
{
	int i;

	g_energy.change_set = 0;
	for(i=0;i<g_sw_num;i++)
	{
		if(g_ui[PUB_AC_NUM+SW_AC_IA+i*SW_AC_NUM].chn_index == CFG_ADC_CHANNEL_ZERO)
		{
			g_energy.sw_num = i;
			break;
		}
	}
	g_energy.len = FILE_ADDR_ALGIN(8 + g_energy.sw_num * 16);
	g_energy.mea_num = g_energy.sw_num;
	if (pRunSet->wDDRL)
	{
		g_energy.rcd_num = ((pRunSet->wDDRL * 24 * 60) / pRunSet->wDDJG) + 1;//7天，5~60分钟间隔
	}
	g_energy.delay_s = pRunSet->wDDJG * 60;

	memset(g_energy_rcd, 0, sizeof(g_energy_rcd));
	memset(&g_energy_rcd[0], 0xFF, sizeof(struct energy_rcd));
	
	i = pw_quality_file_init(ENERGY_FILE);
	if (i<0 && pRunSet->wDDRL)
	{
		rt_printf("iret1 = %d\r\n", i);
		i = energy_create_file();
		rt_file_del("/tmp/energy.csv");
		rt_printf("初始化电度文件, ret = %d\r\n", i);
	}

	//当开关数量、时间间隔定值有变动时，需重新创建文件
	return 0;
}

/******************************************************************************
函数名称：energy_create_file
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：创建电度记录文件
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int energy_create_file(void)
{
	unsigned int addr,file_length;
	char *p;
	loff_t pos;
	struct energy_file_head_data	energy_file;
		
	// 写文件头
	memset(&energy_file,0,sizeof(energy_file));
	energy_file.cfh.signature = SIG_ENERGY_FILE;
	energy_file.cfh.version = FILE_VERSION;
	
	energy_file.interval = g_energy.delay_s;
	energy_file.size = pRunSet->wDDRL;	//默认存储7天
	energy_file.swnum = g_energy.mea_num;
	
	energy_file.addr = FILE_ADDR_ALGIN(sizeof(energy_file));
	energy_file.num = g_energy.rcd_num;

	// 得到文件长度
	addr = energy_file.addr + energy_file.num * g_energy.len;
	file_length = FILE_ADDR_ALGIN(addr);

	// 分配并初始化空间
	p = rt_malloc(file_length); 
	if(!p)
	{
		return -1;
	}
	memset(p,0,file_length);
	
	// 写入文件头
	memcpy(p, (char *)&energy_file, sizeof(energy_file));
	
	// 写电度记录
	memset(p+energy_file.addr, 0xFF, g_energy.len);//无效记录为全1

	// 创建数据文件
	g_pw_quality_file[ENERGY_FILE].handle = rt_file_open(g_pw_quality_file[ENERGY_FILE].name,O_CREAT|O_RDWR,0);
	if(IS_ERR(g_pw_quality_file[ENERGY_FILE].handle))
	{
		g_pw_quality_file[ENERGY_FILE].handle = 0;
		rt_printf("%s open error!\r\n",g_pw_quality_file[ENERGY_FILE].name);
		rt_free(p);
		return -2;
	}
	
	pos = 0;
	rt_file_write(g_pw_quality_file[ENERGY_FILE].handle,p,file_length,&pos);

	g_energy.index = 0;

	rt_free(p);
	
	return 0;
}

/******************************************************************************
函数名称：energy_calc
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：电度值计算
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int energy_calc(void)
{
	int i=0;
	float data_p, data_q;

	//算法
	for (i=0; i<g_energy.sw_num; i++)
	{
		data_p = (float)g_sw[i].ac_in[SW_AC_IN_P] / Q16_BASE;
		data_q = (float)g_sw[i].ac_in[SW_AC_IN_Q] / Q16_BASE;

		//计算时不断累加，满足间隔后取值清0
		if (data_p > 0)
		{
			g_energy_rcd[1].mea[i].energy_p_p += data_p;
		}
		else
		{
			g_energy_rcd[1].mea[i].energy_p_n += data_p;
		}
		if (data_q > 0)
		{
			g_energy_rcd[1].mea[i].energy_q_p += data_q;
		}
		else
		{
			g_energy_rcd[1].mea[i].energy_q_n += data_q;
		}
	}
	return 0;
}

/******************************************************************************
函数名称：energy_record
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：电度值记录
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int energy_record(void)
{
	int i=0;
	struct timespec ts;
	u32 index_new;

		//获取当前时间
	clk_time_get(&ts);
	timespec_to_rtc(ts,&g_energy_rcd[1].timemark,1);

	//索引存储位置
	index_new = g_energy.index;
	g_energy.index++;
	if (g_energy.index >= g_energy.rcd_num)
	{
		g_energy.index=0;
	}	

	//更新记录
	i = pw_quality_file_rcd (ENERGY_FILE,						
						g_energy.len, 
						sizeof(struct energy_file_head_data), 
						index_new, 
						g_energy.index, 
						(char*)&g_energy_rcd[1], 
						(char*)&g_energy_rcd[0]);
	
	/*rt_printf("当前时间: %04d-%02d-%02d %02d:%02d:%02d:%09d!\r\n",
				g_energy_rcd[1].timemark.year + 2000,
				g_energy_rcd[1].timemark.month,
				g_energy_rcd[1].timemark.day,
				g_energy_rcd[1].timemark.hour,
				g_energy_rcd[1].timemark.min,
				g_energy_rcd[1].timemark.ms/1000,
				ts.tv_nsec
				);
	rt_printf("ret = %d, energy_index = %d\r\n\r\n\r\n", i, g_energy.index);*/

	memset(&g_energy_rcd[1], 0, sizeof(struct energy_rcd));
	return 0;
}

/******************************************************************************
函数名称：energy_create_csv
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：电度值记录转换为CSV文件
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
struct energy_rcd en_rcd;
int energy_create_csv(void)
{
	unsigned int addr, len1=0;
	int i, j,loop;
	char *buf;
	struct energy_rcd *rcd;

	char p[512];
	loff_t pos;
	struct file * pfile;

	// 分配并初始化空间
	len1 = g_energy.len*g_energy.rcd_num;
	buf = rt_malloc(len1); 
	if(!buf)
	{
		return -1;
	}
	memset(buf,0,len1);
	addr = sizeof(struct energy_file_head_data);
	pos = addr;

	if(rt_file_read(g_pw_quality_file[ENERGY_FILE].handle,buf,len1,&pos) != len1)
	{
		rt_free(buf);
		return -2;
	}
		
	//需考虑打印文件时，同步存储记录的问题
	// 创建数据文件
	pos = 0;
	pfile = rt_file_open("/tmp/energy.csv",O_CREAT|O_RDWR,0);
	if(IS_ERR(pfile))
	{
		rt_free(buf);
		return -3;
	}	

	//打印抬头
	sprintf(p, "%s,电度记录文件,\r\n", EQUIP_TYPE_STRING);
	rt_file_write(pfile,p,strlen(p),&pos);
	
	//打印表格标题
	sprintf(p, "记录时间,"); 	
	rt_file_write(pfile,p,strlen(p),&pos);
	for(i=1; i<g_energy.sw_num+1; i++)  // 遥测
	{
		sprintf(p,"Ep正_%d,Ep负_%d,Eq正_%d,Eq负_%d,", i, i, i, i);
		rt_file_write(pfile,p,strlen(p),&pos);
	}
	sprintf(p, "\r\n"); 	
	rt_file_write(pfile,p,strlen(p),&pos);

	//打印极值记录
	rcd = &en_rcd;
	for(loop=g_energy.rcd_num,i=g_energy.index+1;loop>0; loop--,i++)
	{
		if(i>= g_energy.rcd_num)
		{
			i=0;
		}
		
		//找出标示行下的最老记录行
		memcpy(&en_rcd,buf+i* g_energy.len,g_energy.len);
		if (rcd->timemark.month < 1|| rcd->timemark.month >12)	//如果月份为0，非1~12之间，判定该条记录非法
		{
			continue;
		}
		
		sprintf(p, "%04d-%02d-%02d_%02d:%02d:%02d-%03d,", 
			rcd->timemark.year+2000, 
			rcd->timemark.month,
			rcd->timemark.day,
			rcd->timemark.hour,
			rcd->timemark.min,
			rcd->timemark.ms/1000,
			rcd->timemark.ms%1000);
		rt_file_write(pfile,p,strlen(p),&pos);
		for (j=0; j<g_energy.sw_num; j++)
		{
			sprintf(p, "%4.3f,%4.3f,%4.3f,%4.3f,", 
					rcd->mea[j].energy_p_p, 
					rcd->mea[j].energy_p_n, 
					rcd->mea[j].energy_q_p, 
					rcd->mea[j].energy_q_n);
			rt_file_write(pfile,p,strlen(p),&pos);
		}

		sprintf(p, "\r\n");
		rt_file_write(pfile,p,strlen(p),&pos);
	}	
	
	// 关闭文件
	rt_file_close(pfile,0);

	rt_free(buf);
	
	rt_printf("电度文件生成成功\r\n");

	return 0;
}
/******************************************************************************
函数名称：energy_init
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：电度初始化
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int extrema_init(void)
{
	int i;
	struct timespec ts;
	struct rtc_time_t	time;	//时标

	g_extrema.change_set = 0;

	g_extrema.len = FILE_ADDR_ALGIN(8 + g_table_head->ac_num * 24);

	g_extrema.rcd_num = pRunSet->wJZRL+1;//30天日极值
	g_extrema.mea_num = g_table_head->ac_num;

	memset(g_extrema_rcd, 0, sizeof(g_extrema_rcd));
	memset(&g_extrema_rcd[0], 0xFF, sizeof(struct extrema_rcd));
	
	i = pw_quality_file_init(EXTREMA_FILE);
	
	if (i<0 && pRunSet->wJZRL)
	{
		rt_printf("iret2 = %d\r\n", i);
		i = extrema_create_file();
		rt_file_del("/tmp/extrema.csv");
		rt_printf("初始化极值记录文件, ret=%d\r\n", i);

		//获取当前时间
		clk_time_get(&ts);
		timespec_to_rtc(ts,&time,1);
		g_extrema_rcd[1].timemark = time;
		for (i=0; i<g_table_head->ac_num; i++)
		{
			g_extrema_rcd[1].extrema_mea[i].timemark_h = time;
			g_extrema_rcd[1].extrema_mea[i].timemark_l = time;
		}
	}
	return 0;
}

/******************************************************************************
函数名称：energy_create_file
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：创建极值记录文件
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int extrema_create_file(void)
{
	unsigned int addr,file_length, i;
	char *p;
	loff_t pos;
	struct extrema_file_head_data	extrema_file;
	struct rsc			*extrema_rsc;
	
	// 写文件头
	memset(&extrema_file,0,sizeof(extrema_file));
	extrema_file.cfh.signature = SIG_EXTREMA_FILE;
	extrema_file.cfh.version = FILE_VERSION;
	
	extrema_file.interval = DAY;
	extrema_file.size = pRunSet->wJZRL;	//默认存储30天
	extrema_file.mea_num = g_extrema.mea_num;

	extrema_file.addr_desc = FILE_ADDR_ALGIN(sizeof(extrema_file));
	extrema_file.num_desc = g_extrema.mea_num;
	
	extrema_file.addr = FILE_ADDR_ALGIN(sizeof(extrema_file) + g_table_head->ac_num*sizeof(struct rsc));
	extrema_file.num = g_extrema.rcd_num;//刚创建时仅存储一条无效电度记录

	extrema_file.rsc_crc = g_crc_rectable;

	// 得到文件长度
	addr = extrema_file.addr + extrema_file.num * g_extrema.len;
	file_length = FILE_ADDR_ALGIN(addr);

	// 分配并初始化空间
	p = rt_malloc(file_length); 
	if(!p)
	{
		return -1;
	}
	memset(p,0,file_length);
	
	// 写入文件头
	memcpy(p, (char *)&extrema_file, sizeof(extrema_file));
	extrema_rsc = (struct rsc *)(p+sizeof(extrema_file));

	//写点表描述
	for(i=0;i<g_table_head->ac_num;i++)
	{
		memcpy (&extrema_rsc[i], &g_ac_table[i], 5);
		extrema_rsc[i].normal = g_ac_table[i].normal;
		_get_ac_name(g_ac_table[i].owner, g_ac_table[i].indexno, extrema_rsc[i].name);
	}
	
	// 写极值记录
	memset(p+extrema_file.addr, 0xFF, g_extrema.len);//无效记录为全1

	// 创建数据文件
	g_pw_quality_file[EXTREMA_FILE].handle = rt_file_open(g_pw_quality_file[EXTREMA_FILE].name,O_CREAT|O_RDWR,0);
	if(IS_ERR(g_pw_quality_file[EXTREMA_FILE].handle))
	{
		g_pw_quality_file[EXTREMA_FILE].handle = 0;
		rt_printf("%s open error!\r\n",g_pw_quality_file[EXTREMA_FILE].name);
		rt_free(p);
		return -2;
	}
	
	pos = 0;
	rt_file_write(g_pw_quality_file[EXTREMA_FILE].handle,p,file_length,&pos);

	g_extrema.index = 0;

	rt_free(p);
	
	return 0;
}

/******************************************************************************
函数名称：extrema_calc
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：极值计算
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int extrema_calc(void)
{
	static int first = 1;
	
	int i,time_changed=0;
	struct timespec ts;
	struct rtc_time_t	time;	//时标

	u32 index_data;

	//获取当前时间
	clk_time_get(&ts);
	timespec_to_rtc(ts,&time,1);

	//日期不对应时，保存旧值
	if(first ==1)
	{
		g_extrema_rcd[1].timemark = time;
		time_changed = 1;
		first = 0;
	}
	else if (time.day != g_extrema_rcd[1].timemark.day)
	{
		//更新存储位置
		index_data = g_extrema.index;
		g_extrema.index++;
		if (g_extrema.index >= g_extrema.rcd_num)
		{
			g_extrema.index=0;
		}	
		
		//保存旧记录入文件
		pw_quality_file_rcd (EXTREMA_FILE,						
				g_extrema.len, 
				sizeof(struct extrema_file_head_data)+g_table_head->ac_num*sizeof(struct rsc), 
				index_data, 
				g_extrema.index, 
				(char *)&g_extrema_rcd[1], 
				(char *)&g_extrema_rcd[0]);
		/*rt_printf("当前时间2: %04d-%02d-%02d %02d:%02d:%02d:%09d!\r\n",
					g_extrema_rcd[1].timemark.year + 2000,
					g_extrema_rcd[1].timemark.month,
					g_extrema_rcd[1].timemark.day,
					g_extrema_rcd[1].timemark.hour,
					g_extrema_rcd[1].timemark.min,
					g_extrema_rcd[1].timemark.ms/1000,
					ts.tv_nsec
					);*/

		// 更新时间
		g_extrema_rcd[1].timemark = time;
		time_changed = 1;
		//rt_printf("extrema_index = %d\r\n\r\n\r\n", g_extrema.index);
 	}


	//更新极大值、极小值
	for (i=0; i<g_table_head->ac_num; i++)
	{
		u8 no=g_ac_table[i].indexno;			
		if(no>0)
		{		
			float data;
			long lmeaval;
			float f_65536=65536.0;
			if(g_ac_table[i].normal==0)f_65536=1.0;		
			
			no-=1;
			lmeaval=GetRmtMeaVal(g_ac_table[i].owner,no,NULL);
			data =((float)lmeaval)/f_65536; //转为浮点数
			//日期不对应时，重新初始化记录
			if (time_changed)
			{
				g_extrema_rcd[1].extrema_mea[i].extrema_h = data;
				g_extrema_rcd[1].extrema_mea[i].extrema_l = data;
				g_extrema_rcd[1].extrema_mea[i].timemark_h = time;
				g_extrema_rcd[1].extrema_mea[i].timemark_l = time;

				g_extrema_rcd[1].timemark = time;
			}
			else
			{
				//极大值
				if (data > g_extrema_rcd[1].extrema_mea[i].extrema_h)
				{
					g_extrema_rcd[1].extrema_mea[i].extrema_h = data;
					g_extrema_rcd[1].extrema_mea[i].timemark_h = time;
				}
				//极小值
				if (data < g_extrema_rcd[1].extrema_mea[i].extrema_l)
				{
					g_extrema_rcd[1].extrema_mea[i].extrema_l = data;
					g_extrema_rcd[1].extrema_mea[i].timemark_l = time;
				}
			}
		}
		else		//备用点号，数值上送0
		{
			g_extrema_rcd[1].extrema_mea[i].extrema_h = 0;
			g_extrema_rcd[1].extrema_mea[i].extrema_l = 0;
			memset (&g_extrema_rcd[1].extrema_mea[i].timemark_h, 0, sizeof(struct rtc_time_t));
			memset (&g_extrema_rcd[1].extrema_mea[i].timemark_l, 0, sizeof(struct rtc_time_t));

		}
	}
 
	return 0;
}

/******************************************************************************
函数名称：extrema_create_csv
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：极值记录转换为CSV文件
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
struct extrema_rcd ex_rcd;
int extrema_create_csv(void)
{
	unsigned int addr, len1=0;
	int i, j,loop;
	char *buf;
	struct extrema_rcd *rcd;

	char p[512];
	loff_t pos;
	struct file * pfile;

	// 分配并初始化空间
	len1 = g_extrema.len*g_extrema.rcd_num;
	buf = rt_malloc(len1); 
	if(!buf)
	{
		return -1;
	}
	memset(buf,0,len1);
	addr = sizeof(struct extrema_file_head_data) + g_extrema.mea_num*sizeof(struct rsc);
	pos = addr;

	if(rt_file_read(g_pw_quality_file[EXTREMA_FILE].handle,buf,len1,&pos) != len1)
	{
		rt_free(buf);
		return -2;
	}
		
	//需考虑打印文件时，同步存储记录的问题
	// 创建数据文件
	pos = 0;
	pfile = rt_file_open("/tmp/extrema.csv",O_CREAT|O_RDWR,0);
	if(IS_ERR(pfile))
	{
		rt_free(buf);
		return -3;
	}
	

	//打印抬头
	sprintf(p, "%s,极值记录文件,\r\n", EQUIP_TYPE_STRING);
	rt_file_write(pfile,p,strlen(p),&pos);
	
	//打印表格标题
	sprintf(p, "记录时间,"); 	
	rt_file_write(pfile,p,strlen(p),&pos);
	for(i=0; i<g_table_head->ac_num; i++)  // 遥测
	{
		if(g_ac_table[i].indexno!=0)
		{
			_get_ac_name(g_ac_table[i].owner,g_ac_table[i].indexno,p);
		}
		else
		{
			sprintf(p,"备用");
		}
		sprintf(p+strlen(p), ",,"); 	
		rt_file_write(pfile,p,strlen(p),&pos);
	}
	sprintf(p, "\r\n"); 	
	rt_file_write(pfile,p,strlen(p),&pos);

	//打印极值记录
	rcd = &ex_rcd;
	for(loop =g_extrema.rcd_num,i=g_extrema.index+1;loop>0; loop--,i++)
	{
		//
		if(i>= g_extrema.rcd_num)
		{
			i=0;
		}
		
		//找出标示行下的最老记录行
		//rcd = (struct extrema_rcd *) (buf+i* g_extrema.len);
		memcpy(&ex_rcd,buf+i* g_extrema.len,g_extrema.len);
		if (rcd->timemark.month < 1|| rcd->timemark.month >12)	//如果月份为0，非1~12之间，判定该条记录非法
		{
			continue;
		}
		
		sprintf(p, "%04d-%02d-%02d,", 
			rcd->timemark.year+2000, 
			rcd->timemark.month,
			rcd->timemark.day);
		rt_file_write(pfile,p,strlen(p),&pos);
		for (j=0; j<g_table_head->ac_num; j++)
		{
			sprintf(p, "%4.3f,", rcd->extrema_mea[j].extrema_h);
			rt_file_write(pfile,p,strlen(p),&pos);
			sprintf(p, "%02d:%02d:%02d-%03d,", 
			rcd->extrema_mea[j].timemark_h.hour,
			rcd->extrema_mea[j].timemark_h.min,
			rcd->extrema_mea[j].timemark_h.ms/1000,
			rcd->extrema_mea[j].timemark_h.ms%1000);
			rt_file_write(pfile,p,strlen(p),&pos);
		}

		sprintf(p, "\r\n,");
		rt_file_write(pfile,p,strlen(p),&pos);

		for (j=0; j<g_table_head->ac_num; j++)
		{
			sprintf(p, "%4.3f,", rcd->extrema_mea[j].extrema_l);
			rt_file_write(pfile,p,strlen(p),&pos);
			sprintf(p, "%02d:%02d:%02d-%03d,", 
			rcd->extrema_mea[j].timemark_l.hour,
			rcd->extrema_mea[j].timemark_l.min,
			rcd->extrema_mea[j].timemark_l.ms/1000,
			rcd->extrema_mea[j].timemark_l.ms%1000);
			rt_file_write(pfile,p,strlen(p),&pos);
		}
		sprintf(p, "\r\n");
		rt_file_write(pfile,p,strlen(p),&pos);

	}	
	
	// 关闭文件
	rt_file_close(pfile,0);

	rt_free(buf);
	
	rt_printf("极值文件生成成功\r\n");

	return 0;
}

/******************************************************************************
函数名称：mea_rcd_init
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：定点遥测初始化
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int mearcd_init(void)
{
	int i;
	g_mearcd.change_set = 0;

	g_mearcd.len = FILE_ADDR_ALGIN(8 + g_table_head->ac_num * 4);

	if (pRunSet->wZDRL)
	{
		g_mearcd.rcd_num = ((pRunSet->wZDRL * 24 * 60) / pRunSet->wZDJG) + 1;//7天，5~60分钟间隔
	}
	g_mearcd.delay_s = pRunSet->wZDJG * 60;//5~60分钟间隔
	g_mearcd.mea_num = g_table_head->ac_num;
	memset(g_mea_rcd, 0, sizeof(g_mea_rcd));
	memset(&g_mea_rcd[0], 0xFF, sizeof(struct mea_rcd));
	
	i = pw_quality_file_init(MEARCD_FILE);
	if (i<0 && pRunSet->wZDRL)
	{
		rt_printf("iret3 = %d\r\n", i);
		i = mearcd_create_file();
		rt_file_del("/tmp/mearcd.csv");
		rt_printf("初始化定点遥测记录文件, ret=%d\r\n", i);
	}
	return 0;
}

/******************************************************************************
函数名称：mearcd_create_file
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：创建定点遥测记录文件
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int mearcd_create_file(void)
{
	unsigned int addr,file_length, i;
	char *p;
	loff_t pos;
	struct mearcd_file_head_data	mearcd_file;
	struct rsc			*mearcd_rsc;
		
	// 写文件头
	memset(&mearcd_file,0,sizeof(mearcd_file));
	mearcd_file.cfh.signature = SIG_MEARCD_FILE;
	mearcd_file.cfh.version = FILE_VERSION;
	
	mearcd_file.interval = g_mearcd.delay_s;
	mearcd_file.size = pRunSet->wZDRL;	//默认存储30天
	mearcd_file.mea_num = g_mearcd.mea_num;

	mearcd_file.addr_desc = FILE_ADDR_ALGIN(sizeof(mearcd_file));
	mearcd_file.num_desc = g_mearcd.mea_num;
	
	mearcd_file.addr = FILE_ADDR_ALGIN(sizeof(mearcd_file) + g_table_head->ac_num*sizeof(struct rsc));
	mearcd_file.num = g_mearcd.rcd_num;//刚创建时仅存储一条无效电度记录

	mearcd_file.rsc_crc = g_crc_rectable;

	// 得到文件长度
	addr = mearcd_file.addr + mearcd_file.num * g_mearcd.len;
	file_length = FILE_ADDR_ALGIN(addr);

	// 分配并初始化空间
	p = rt_malloc(file_length); 
	if(!p)
	{
		return -1;
	}
	memset(p,0,file_length);
	
	// 写入文件头
	memcpy(p, (char *)&mearcd_file, sizeof(mearcd_file));
	mearcd_rsc = (struct rsc *)(p+sizeof(mearcd_file));

	//写点表描述
	for(i=0;i<g_table_head->ac_num;i++)
	{
		memcpy (&mearcd_rsc[i], &g_ac_table[i], 5);
		mearcd_rsc[i].normal = g_ac_table[i].normal;
		_get_ac_name(g_ac_table[i].owner, g_ac_table[i].indexno, mearcd_rsc[i].name);
	}
	
	// 写极值记录
	memset(p+mearcd_file.addr, 0xFF, g_mearcd.len);//无效记录为全1

	// 创建数据文件
	g_pw_quality_file[MEARCD_FILE].handle = rt_file_open(g_pw_quality_file[MEARCD_FILE].name,O_CREAT|O_RDWR,0);
	if(IS_ERR(g_pw_quality_file[MEARCD_FILE].handle))
	{
		g_pw_quality_file[MEARCD_FILE].handle = 0;
		rt_printf("%s open error!\r\n",g_pw_quality_file[MEARCD_FILE].name);
		rt_free(p);
		return -2;
	}
	
	pos = 0;
	rt_file_write(g_pw_quality_file[MEARCD_FILE].handle,p,file_length,&pos);

	g_mearcd.index = 0;

	rt_free(p);
	
	return 0;
}

/******************************************************************************
函数名称：extrema_calc
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：极值计算
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int mearcd_record(void)
{
	int i;
	struct timespec ts;
	struct rtc_time_t	time;	//时标

	u32 index_data;

	//获取当前时间
	clk_time_get(&ts);
	timespec_to_rtc(ts,&time,1);

	g_mea_rcd[1].timemark = time;
	//更新值
	for (i=0; i<g_table_head->ac_num; i++)
	{
		u8 no=g_ac_table[i].indexno;			
		if(no>0)
		{		
			float data;
			long lmeaval;
			float f_65536=65536.0;
			if(g_ac_table[i].normal==0)f_65536=1.0;					
			no-=1;
			lmeaval=GetRmtMeaVal(g_ac_table[i].owner,no,NULL);
			data =((float)lmeaval)/f_65536; //转为浮点数

			g_mea_rcd[1].data[i] = data;
		}
		else		//备用点号，数值上送0
		{
			g_mea_rcd[1].data[i] = 0;
			memset (&g_mea_rcd[1].timemark, 0, sizeof(struct rtc_time_t));
		}
	}
	
	//更新存储位置
	index_data = g_mearcd.index;
	g_mearcd.index++;
	if (g_mearcd.index >= g_mearcd.rcd_num)
	{
		g_mearcd.index=0;
	}	
		
	//保存旧记录入文件
	pw_quality_file_rcd (MEARCD_FILE,						
						g_mearcd.len, 
						sizeof(struct mearcd_file_head_data)+g_table_head->ac_num*sizeof(struct rsc), 
						index_data, 
						g_mearcd.index, 
						(char *)&g_mea_rcd[1], 
						(char *)&g_mea_rcd[0]);
	/*rt_printf("当前时间2: %04d-%02d-%02d %02d:%02d:%02d:%09d!\r\n",
				g_mea_rcd[1].timemark.year + 2000,
				g_mea_rcd[1].timemark.month,
				g_mea_rcd[1].timemark.day,
				g_mea_rcd[1].timemark.hour,
				g_mea_rcd[1].timemark.min,
				g_mea_rcd[1].timemark.ms/1000,
				ts.tv_nsec
				);

	rt_printf("mearcd_index = %d\r\n\r\n\r\n", g_mearcd.index);*/
	return 0;
}

/******************************************************************************
函数名称：mearcd_create_csv
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：定点遥测记录转换为CSV文件
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
struct mea_rcd mearcd;
int mearcd_create_csv(void)
{
	unsigned int addr, len1=0;
	int i, j,loop;
	char *buf;
	struct mea_rcd *rcd;

	char p[512];
	loff_t pos;
	struct file * pfile;

	// 分配并初始化空间
	len1 = g_mearcd.len * g_mearcd.rcd_num;
	buf = rt_malloc(len1); 
	if(!buf)
	{
		return -1;
	}
	memset(buf,0,len1);
	addr = sizeof(struct mearcd_file_head_data) + g_mearcd.mea_num*sizeof(struct rsc);
	pos = addr;

	if(rt_file_read(g_pw_quality_file[MEARCD_FILE].handle,buf,len1,&pos) != len1)
	{
		rt_free(buf);
		return -2;
	}
		
	//需考虑打印文件时，同步存储记录的问题
	// 创建数据文件
	pos = 0;
	pfile = rt_file_open("/tmp/mearcd.csv",O_CREAT|O_RDWR,0);
	if(IS_ERR(pfile))
	{
		rt_free(buf);
		return -3;
	}	

	//打印抬头
	sprintf(p, "%s,定点遥测文件,\r\n", EQUIP_TYPE_STRING);
	rt_file_write(pfile,p,strlen(p),&pos);
	
	//打印表格标题
	sprintf(p, "记录时间,"); 	
	rt_file_write(pfile,p,strlen(p),&pos);
	for(i=0; i<g_table_head->ac_num; i++)  // 遥测
	{
		if(g_ac_table[i].indexno!=0)
		{
			_get_ac_name(g_ac_table[i].owner,g_ac_table[i].indexno,p);
		}
		else
		{
			sprintf(p,"备用");
		}
		sprintf(p+strlen(p), ","); 	
		rt_file_write(pfile,p,strlen(p),&pos);
	}
	sprintf(p, "\r\n"); 	
	rt_file_write(pfile,p,strlen(p),&pos);

	//打印极值记录
	rcd = &mearcd;
	for(loop=g_mearcd.rcd_num,i=g_mearcd.index+1;loop>0; loop--,i++)
	{
		//
		if(i >= g_mearcd.rcd_num)
		{
			i=0;
		}
		
		//找出标示行下的最老记录行
		memcpy(&mearcd, buf+i*g_mearcd.len, g_mearcd.len);
		if (rcd->timemark.month < 1|| rcd->timemark.month >12)	//如果月份为0，非1~12之间，判定该条记录非法
		{
			continue;
		}
		
		sprintf(p, "%04d-%02d-%02d_%02d:%02d:%02d-%03d,", 
			rcd->timemark.year+2000, 
			rcd->timemark.month,
			rcd->timemark.day,
			rcd->timemark.hour,
			rcd->timemark.min,
			rcd->timemark.ms/1000,
			rcd->timemark.ms%1000);
		rt_file_write(pfile,p,strlen(p),&pos);
		for (j=0; j<g_table_head->ac_num; j++)
		{
			sprintf(p, "%4.3f,", rcd->data[j]);
			rt_file_write(pfile,p,strlen(p),&pos);
		}

		sprintf(p, "\r\n");
		rt_file_write(pfile,p,strlen(p),&pos);

	}	
	
	// 关闭文件
	rt_file_close(pfile,0);

	rt_free(buf);
	
	rt_printf("定点遥测文件生成成功\r\n");

	return 0;
}

/******************************************************************************
函数名称：capmanage_init
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：电容器管理初始化
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int capmanage_init(void)
{
	int i;

	g_capmanage.change_set = 0;

	for(i=0;i<g_sw_num;i++)
	{
		if(g_ui[PUB_AC_NUM+SW_AC_IA+i*SW_AC_NUM].chn_index == CFG_ADC_CHANNEL_ZERO)
		{
			g_capmanage.sw_num = i;
			break;
		}
	}
	
	g_capmanage.len = FILE_ADDR_ALGIN(8 + g_capmanage.sw_num*2*8 + 6*8);

	g_capmanage.rcd_num = pRunSet->wCAPRL + 1;//30条
	g_capmanage.delay_s = pRunSet->wCAPJG;//1~300秒钟间隔
	g_capmanage.mea_num = g_capmanage.sw_num*2+6;//两组线电压，开关倍数的Q、COS
	
	memset(g_cap_rcd, 0, sizeof(g_cap_rcd));
	memset(&g_cap_rcd[0], 0xFF, sizeof(struct cap_rcd));
	
	i = pw_quality_file_init(CAP_FILE);
	if (i<0 && pRunSet->wCAPRL)
	{
		rt_printf("iret4 = %d\r\n", i);
		i = capmanage_create_file();
		rt_file_del("/tmp/cap_manage.csv");
		rt_printf("初始化电容器管理文件, ret=%d\r\n", i);
	}
	return 0;
}

/******************************************************************************
函数名称：capmanage_create_file
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：创建电容器管理文件
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int capmanage_create_file(void)
{
	unsigned int addr,file_length, i, j=0;
	char *p;
	loff_t pos;
	struct capmanage_file_head_data	caprcd_file;
	struct rsc			*caprcd_rsc;
		
	// 写文件头
	memset(&caprcd_file,0,sizeof(caprcd_file));
	caprcd_file.cfh.signature = SIG_CAPRCD_FILE;
	caprcd_file.cfh.version = FILE_VERSION;
	
	caprcd_file.size = pRunSet->wCAPRL;	//默认存储30条
	caprcd_file.meanum = g_capmanage.mea_num;

	caprcd_file.addr_desc = FILE_ADDR_ALGIN(sizeof(caprcd_file));
	caprcd_file.num_desc = g_capmanage.mea_num;
	
	caprcd_file.addr = FILE_ADDR_ALGIN(caprcd_file.addr_desc + caprcd_file.num_desc *sizeof(struct rsc));
	caprcd_file.num = g_capmanage.rcd_num;

	caprcd_file.rsc_crc = g_crc_rectable;

	// 得到文件长度
	addr = caprcd_file.addr + caprcd_file.num * g_capmanage.len;
	file_length = FILE_ADDR_ALGIN(addr);

	// 分配并初始化空间
	p = rt_malloc(file_length); 
	if(!p)
	{
		return -1;
	}
	memset(p,0,file_length);
	
	// 写入文件头
	memcpy(p, (char *)&caprcd_file, sizeof(caprcd_file));
	caprcd_rsc = (struct rsc *)(p+sizeof(caprcd_file));

	//写点表描述
	for(i=0; i<g_table_head->ac_num; i++)
	{
		if (g_ac_table[i].owner == 0)
		{
			if (((g_ac_table[i].indexno-1)>=PUB_AC_UAB1 && (g_ac_table[i].indexno-1)<=PUB_AC_UCA1)
				|| ((g_ac_table[i].indexno-1)>=PUB_AC_UAB2 && (g_ac_table[i].indexno-1)<=PUB_AC_UCA2))
			{
				memcpy (&caprcd_rsc[j], &g_ac_table[i], 5);
				caprcd_rsc[j].normal = g_ac_table[i].normal;
				strcpy(caprcd_rsc[j].name, g_pub_ac_desc[g_ac_table[i].indexno-1].name);
				j++;
			}
		}
		else
		{
			if ((g_ac_table[i].indexno-1)==(SW_AC_IN_Q) || (g_ac_table[i].indexno-1)==(SW_AC_IN_COS))
			{
				memcpy (&caprcd_rsc[j], &g_ac_table[i], 5);
				caprcd_rsc[j].normal = g_ac_table[i].normal;
				sprintf(caprcd_rsc[j].name,"%s_%d", g_sw_ac_desc[g_ac_table[i].indexno-1].name, g_ac_table[i].owner);
				j++;
			}
		}
	}
	
	// 写极值记录
	memset(p+caprcd_file.addr, 0xFF, g_capmanage.len);//无效记录为全1

	// 创建数据文件
	g_pw_quality_file[CAP_FILE].handle = rt_file_open(g_pw_quality_file[CAP_FILE].name,O_CREAT|O_RDWR,0);
	if(IS_ERR(g_pw_quality_file[CAP_FILE].handle))
	{
		g_pw_quality_file[CAP_FILE].handle = 0;
		rt_printf("%s open error!\r\n",g_pw_quality_file[CAP_FILE].name);
		rt_free(p);
		return -2;
	}
	
	pos = 0;
	rt_file_write(g_pw_quality_file[CAP_FILE].handle,p,file_length,&pos);

	g_capmanage.index = 0;

	rt_free(p);
	
	return 0;
}

/******************************************************************************
函数名称：capmanage_calc
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：电容器管理取值
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int capmanage_calc(void)
{
	int i, j=0, capdata_rcd = 0;

	float data;
	long lmeaval;

	
	//更新值
	for (i=0; i<g_table_head->ac_num; i++)
	{
		u8 no=g_ac_table[i].indexno;

		if (g_ac_table[i].owner == 0)
		{
			if (((g_ac_table[i].indexno-1)>=PUB_AC_UAB1 && (g_ac_table[i].indexno-1)<=PUB_AC_UCA1)
				|| ((g_ac_table[i].indexno-1)>=PUB_AC_UAB2 && (g_ac_table[i].indexno-1)<=PUB_AC_UCA2))
			{
				capdata_rcd = 1;
			}
		}
		else
		{
			if ((g_ac_table[i].indexno-1)==(SW_AC_IN_Q) || (g_ac_table[i].indexno-1)==(SW_AC_IN_COS))
			{
				capdata_rcd = 1;
			}
		}
		if (capdata_rcd)
		{				

			float f_65536=65536.0;
			if(g_ac_table[i].normal==0)f_65536=1.0;		
			no-=1;
			lmeaval=GetRmtMeaVal(g_ac_table[i].owner,no,NULL);
			data =((float)lmeaval)/f_65536; //转为浮点数
			g_cap_rcd[1].data[j].old_data = g_cap_rcd[1].data[j].new_data;
			g_cap_rcd[1].data[j].new_data = data;
			capdata_rcd = 0;
			j++;
		}
	}
	return 0;
}

int capmanage_record(void)
{
	u32 index_data;

	struct timespec ts;
	struct rtc_time_t	time;	//时标

	//获取当前时间
	clk_time_get(&ts);
	timespec_to_rtc(ts,&time,1);

	g_cap_rcd[1].action_timemark = time;

	//更新存储位置
	index_data = g_capmanage.index;
	g_capmanage.index++;
	if (g_capmanage.index >= g_capmanage.rcd_num)
	{
		g_capmanage.index=0;
	}	
		
	//保存旧记录入文件
	pw_quality_file_rcd (CAP_FILE,						
						g_capmanage.len, 
						sizeof(struct capmanage_file_head_data)+g_capmanage.mea_num*sizeof(struct rsc), 
						index_data, 
						g_capmanage.index, 
						(char *)&g_cap_rcd[1], 
						(char *)&g_cap_rcd[0]);
	/*rt_printf("当前时间2: %04d-%02d-%02d %02d:%02d:%02d:%09d!\r\n",
				g_cap_rcd[1].action_timemark.year + 2000,
				g_cap_rcd[1].action_timemark.month,
				g_cap_rcd[1].action_timemark.day,
				g_cap_rcd[1].action_timemark.hour,
				g_cap_rcd[1].action_timemark.min,
				g_cap_rcd[1].action_timemark.ms/1000,
				ts.tv_nsec
				);

	rt_printf("capmanage_index = %d\r\n\r\n\r\n", g_capmanage.index);*/
	return 0;
}

/******************************************************************************
函数名称：mearcd_create_csv
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：定点遥测记录转换为CSV文件
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
struct cap_rcd caprcd;
int capmanage_create_csv(void)
{
	unsigned int addr, len1=0;
	int i, j,loop;
	char *buf;
	struct cap_rcd *rcd;

	char p[512];
	loff_t pos;
	struct file * pfile;

	// 分配并初始化空间
	len1 = g_capmanage.len * g_capmanage.rcd_num;
	buf = rt_malloc(len1); 
	if(!buf)
	{
		return -1;
	}
	memset(buf,0,len1);
	addr = sizeof(struct capmanage_file_head_data) + g_capmanage.mea_num*sizeof(struct rsc);
	pos = addr;

	if(rt_file_read(g_pw_quality_file[CAP_FILE].handle,buf,len1,&pos) != len1)
	{
		rt_free(buf);
		return -2;
	}
		
	//需考虑打印文件时，同步存储记录的问题
	// 创建数据文件
	pos = 0;
	pfile = rt_file_open("/tmp/cap_manage.csv",O_CREAT|O_RDWR,0);
	if(IS_ERR(pfile))
	{
		rt_free(buf);
		return -3;
	}	

	//打印抬头
	sprintf(p, "%s,电容器管理文件,\r\n", EQUIP_TYPE_STRING);
	rt_file_write(pfile,p,strlen(p),&pos);
	
	//打印表格标题
	sprintf(p, "记录时间,"); 	
	rt_file_write(pfile,p,strlen(p),&pos);
	for(i=0; i<g_table_head->ac_num; i++)  // 遥测
	{
		if (g_ac_table[i].owner == 0)
		{
			if (((g_ac_table[i].indexno-1)>=PUB_AC_UAB1 && (g_ac_table[i].indexno-1)<=PUB_AC_UCA1)
				|| ((g_ac_table[i].indexno-1)>=PUB_AC_UAB2 && (g_ac_table[i].indexno-1)<=PUB_AC_UCA2))
			{
				strcpy(p, g_pub_ac_desc[g_ac_table[i].indexno-1].name);			
				sprintf(p+strlen(p), ","); 	
				rt_file_write(pfile,p,strlen(p),&pos);
			}
		}
		else
		{
			if ((g_ac_table[i].indexno-1)==(SW_AC_IN_Q) || (g_ac_table[i].indexno-1)==(SW_AC_IN_COS))
			{
				sprintf(p,"%s_%d", g_sw_ac_desc[g_ac_table[i].indexno-1].name, g_ac_table[i].owner);
				sprintf(p+strlen(p), ","); 	
				rt_file_write(pfile,p,strlen(p),&pos);
			}
		}
	}
	sprintf(p, "\r\n"); 	
	rt_file_write(pfile,p,strlen(p),&pos);

	//打印极值记录
	rcd = &caprcd;
	for(loop=g_capmanage.rcd_num,i=g_capmanage.index+1;loop>0; loop--,i++)
	{
		//
		if(i >= g_capmanage.rcd_num)
		{
			i=0;
		}
		
		//找出标示行下的最老记录行
		memcpy(&caprcd, buf+i*g_capmanage.len, g_capmanage.len);
		if (rcd->action_timemark.month < 1|| rcd->action_timemark.month >12)	//如果月份为0，非1~12之间，判定该条记录非法
		{
			continue;
		}
		
		sprintf(p, "%04d-%02d-%02d_%02d:%02d:%02d-%03d,", 
			rcd->action_timemark.year+2000, 
			rcd->action_timemark.month,
			rcd->action_timemark.day,
			rcd->action_timemark.hour,
			rcd->action_timemark.min,
			rcd->action_timemark.ms/1000,
			rcd->action_timemark.ms%1000);
		rt_file_write(pfile,p,strlen(p),&pos);
		for (j=0; j<g_capmanage.mea_num; j++)
		{
			sprintf(p, "%4.3f,", rcd->data[j].old_data);
			rt_file_write(pfile,p,strlen(p),&pos);
		}

		sprintf(p, "\r\n,");
		rt_file_write(pfile,p,strlen(p),&pos);

		for (j=0; j<g_capmanage.mea_num; j++)
		{
			sprintf(p, "%4.3f,", rcd->data[j].new_data);
			rt_file_write(pfile,p,strlen(p),&pos);
		}

		sprintf(p, "\r\n");
		rt_file_write(pfile,p,strlen(p),&pos);

	}	
	
	// 关闭文件
	rt_file_close(pfile,0);

	rt_free(buf);
	
	rt_printf("电容器管理文件生成成功\r\n");

	return 0;
}

/******************************************************************************
函数名称：udcrcd_init
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：电池电压初始化
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int udcrcd_init(void)
{
	int i;

	g_udcrcd.change_set = 0;
	g_udcrcd.len = FILE_ADDR_ALGIN(sizeof(struct udc_rcd));
	if (pRunSet->wUDCRL)
	{
		g_udcrcd.rcd_num = pRunSet->wUDCRL + 1;//30天
	}
	g_udcrcd.delay_s = 1;
	g_udcrcd.no = 30;

	memset(g_udc_rcd, 0, sizeof(g_udc_rcd));
	memset(&g_udc_rcd[0], 0xFF, sizeof(struct udc_rcd));
	
	i = pw_quality_file_init(UDCRCD_FILE);
	if (i<0 && pRunSet->wUDCRL)
	{
		rt_printf("iret1 = %d\r\n", i);
		i = udcrcd_create_file();
		rt_file_del("/tmp/udcrcd.csv");
		rt_printf("初始化电池电压记录文件, ret = %d\r\n", i);
	}
	return 0;
}

/******************************************************************************
函数名称：udcrcd_create_file
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：创建电池电压记录文件
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int udcrcd_create_file(void)
{
	unsigned int addr,file_length;
	char *p;
	loff_t pos;
	struct udcrcd_file_head_data	udcrcd_file;
		
	// 写文件头
	memset(&udcrcd_file,0,sizeof(udcrcd_file));
	udcrcd_file.cfh.signature = SIG_UDCRCD_FILE;
	udcrcd_file.cfh.version = FILE_VERSION;
	
	udcrcd_file.size = pRunSet->wUDCRL;	
	
	udcrcd_file.addr = FILE_ADDR_ALGIN(sizeof(udcrcd_file));
	udcrcd_file.num = g_udcrcd.rcd_num;

	// 得到文件长度
	addr = udcrcd_file.addr + udcrcd_file.num * g_udcrcd.len;
	file_length = FILE_ADDR_ALGIN(addr);

	// 分配并初始化空间
	p = rt_malloc(file_length); 
	if(!p)
	{
		return -1;
	}
	memset(p,0,file_length);
	
	// 写入文件头
	memcpy(p, (char *)&udcrcd_file, sizeof(udcrcd_file));
	
	// 写电度记录
	memset(p+udcrcd_file.addr, 0xFF, g_udcrcd.len);//无效记录为全1

	// 创建数据文件
	g_pw_quality_file[UDCRCD_FILE].handle = rt_file_open(g_pw_quality_file[UDCRCD_FILE].name,O_CREAT|O_RDWR,0);
	if(IS_ERR(g_pw_quality_file[UDCRCD_FILE].handle))
	{
		g_pw_quality_file[UDCRCD_FILE].handle = 0;
		rt_printf("%s open error!\r\n",g_pw_quality_file[UDCRCD_FILE].name);
		rt_free(p);
		return -2;
	}
	
	pos = 0;
	rt_file_write(g_pw_quality_file[UDCRCD_FILE].handle,p,file_length,&pos);

	g_udcrcd.index = 0;

	rt_free(p);
	
	return 0;
}

/******************************************************************************
函数名称：dcrcd_record
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：电池电压记录
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int udcrcd_record(u32 no)
{
	int i=0;
	struct timespec ts;
	static u32 index_new;

	//获取当前时间
	if (no == 0)
	{
		clk_time_get(&ts);
		timespec_to_rtc(ts,&g_udc_rcd[1].timemark,1);
		//索引存储位置
		index_new = g_udcrcd.index;
		g_udcrcd.index++;
		if (g_udcrcd.index >= g_udcrcd.rcd_num)
		{
			g_udcrcd.index=0;
		}	
	}	

	g_udc_rcd[1].data[no] =  rt_round((float)g_sw_pub.ac_in[PUB_AC_IN_UDC]/Q16_BASE);

	if (no < (g_udcrcd.no-1))
	{
		return 0;
	}
	
	//更新记录
	i = pw_quality_file_rcd (UDCRCD_FILE,						
						g_udcrcd.len, 
						sizeof(struct udcrcd_file_head_data), 
						index_new, 
						g_udcrcd.index, 
						(char*)&g_udc_rcd[1], 
						(char*)&g_udc_rcd[0]);
	
	/*rt_printf("当前时间: %04d-%02d-%02d %02d:%02d:%02d:%09d!\r\n",
				g_udc_rcd[1].timemark.year + 2000,
				g_udc_rcd[1].timemark.month,
				g_udc_rcd[1].timemark.day,
				g_udc_rcd[1].timemark.hour,
				g_udc_rcd[1].timemark.min,
				g_udc_rcd[1].timemark.ms/1000,
				g_udc_rcd[1].timemark.ms%1000
				);
	rt_printf("ret = %d, udcrcd_index = %d\r\n\r\n\r\n", i, g_udcrcd.index);*/

	memset(&g_udc_rcd[1], 0, sizeof(struct udc_rcd));
	return 0;
}

/******************************************************************************
函数名称：udcrcd_create_csv
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：电池电压记录转换为CSV文件
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
struct udc_rcd udcrcd;
int udcrcd_create_csv(void)
{
	unsigned int addr, len1=0;
	int i, j,loop;
	char *buf;
	struct udc_rcd *rcd;

	char p[512];
	loff_t pos;
	struct file * pfile;

	// 分配并初始化空间
	len1 = g_udcrcd.len * g_udcrcd.rcd_num;
	buf = rt_malloc(len1); 
	if(!buf)
	{
		return -1;
	}
	memset(buf,0,len1);
	addr = sizeof(struct udcrcd_file_head_data);
	pos = addr;

	if(rt_file_read(g_pw_quality_file[UDCRCD_FILE].handle,buf,len1,&pos) != len1)
	{
		rt_free(buf);
		return -2;
	}
		
	//需考虑打印文件时，同步存储记录的问题
	// 创建数据文件
	pos = 0;
	pfile = rt_file_open("/tmp/udcrcd.csv",O_CREAT|O_RDWR,0);
	if(IS_ERR(pfile))
	{
		rt_free(buf);
		return -3;
	}	

	//打印抬头
	sprintf(p, "%s,电池电压记录文件,\r\n", EQUIP_TYPE_STRING);
	rt_file_write(pfile,p,strlen(p),&pos);
	
	//打印表格标题
	sprintf(p, "记录时间,"); 	
	rt_file_write(pfile,p,strlen(p),&pos);
	for(i=0; i<g_udcrcd.no; i++)  
	{
		sprintf(p,"%ds,", i);
		rt_file_write(pfile,p,strlen(p),&pos);
	}
	sprintf(p, "\r\n"); 	
	rt_file_write(pfile,p,strlen(p),&pos);

	//打印记录
	rcd = &udcrcd;
	for(loop=g_udcrcd.rcd_num,i=g_udcrcd.index+1;loop>0; loop--,i++)
	{
		if(i >= g_udcrcd.rcd_num)
		{
			i=0;
		}
		
		//找出标示行下的最老记录行
		memcpy(&udcrcd,buf+i* g_udcrcd.len,g_udcrcd.len);
		if (rcd->timemark.month < 1|| rcd->timemark.month >12)	//如果月份为0，非1~12之间，判定该条记录非法
		{
			continue;
		}
		
		sprintf(p, "%04d-%02d-%02d_%02d:%02d:%02d-%03d,", 
			rcd->timemark.year+2000, 
			rcd->timemark.month,
			rcd->timemark.day,
			rcd->timemark.hour,
			rcd->timemark.min,
			rcd->timemark.ms/1000,
			rcd->timemark.ms%1000);
		rt_file_write(pfile,p,strlen(p),&pos);
		for (j=0; j<g_udcrcd.no; j++)
		{
			sprintf(p, "%2.3f,",rcd->data[j]);
			rt_file_write(pfile,p,strlen(p),&pos);
		}

		sprintf(p, "\r\n");
		rt_file_write(pfile,p,strlen(p),&pos);
	}	
	
	// 关闭文件
	rt_file_close(pfile,0);

	rt_free(buf);
	
	rt_printf("电池电压文件生成成功\r\n");

	return 0;
}
/******************************************************************************
函数名称：pw_quality_init
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：电能质量初始化
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int pw_quality_init(void)
{
	g_pw_init = 1;
	return 0;
}

//退出函数
int pw_quality_exit(void)
{
	int i;

	//循环关闭文件
	for(i = 0; i< FILE_NUM; i++)
	{
		if(g_pw_quality_file[i].handle != 0)
		{
			rt_file_close(g_pw_quality_file[i].handle,0);
			g_pw_quality_file[i].handle = 0;
		}
	}
	return 0;
}

/******************************************************************************
函数名称：	pw_quality_file_init
函数版本：	01.01
创建作者：  xxxxxx
创建日期：	2013-08-08
函数说明：初始化记录文件
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
int pw_quality_file_init(u8 file_no)
{
	u32 len;
	int i,j=0, iret=0;
	u8 *buf;
	u8 *tmp;

	loff_t pos;

	// 打开文件
	g_pw_quality_file[file_no].handle = rt_file_open(g_pw_quality_file[file_no].name,O_RDWR ,0);
	if(IS_ERR(g_pw_quality_file[file_no].handle))
	{
		return -1;
	}

	// 得到文件长度
	rt_file_llseek(g_pw_quality_file[file_no].handle,0,SEEK_END);
	len = g_pw_quality_file[file_no].handle->f_pos;
	rt_file_llseek(g_pw_quality_file[file_no].handle,0,SEEK_SET);
	
	// 分配内存
	buf = rt_malloc(len);
	if((buf) == NULL)
	{
		rt_file_close(g_pw_quality_file[file_no].handle,0);
		return -2; 	
	}
	//保存原指针,便于以后释放内存
	tmp = buf;
	// 读出内容
	pos = 0;
	if(rt_file_read(g_pw_quality_file[file_no].handle,buf,len,&pos) != len)
	{
		rt_file_close(g_pw_quality_file[file_no].handle,0);
		rt_free(buf);
		return -3;
	}

	switch(file_no)
	{
		case ENERGY_FILE:
		{
			struct energy_file_head_data *brh;

			// 检查文件签名
			brh = (struct energy_file_head_data*)buf;
			if(brh->cfh.signature != SIG_ENERGY_FILE)
			{
				rt_free(buf);
				return -4;
			}

			// 检查文件长度
			if(len < sizeof(*brh)  + brh->num*g_energy.len)
			{
				rt_free(buf);
				return -5; 	
			}
			if (pRunSet->wDDRL == 0)
			{
				rt_file_del(g_pw_quality_file[file_no].name);
				rt_file_del("/tmp/energy.csv");
				rt_printf("删除电度记录文件\r\n");
				rt_free(buf);
				return 1;
			}
			if ((brh->interval != g_energy.delay_s) 
				|| (brh->size != pRunSet->wDDRL)
				|| (brh->swnum != g_energy.mea_num))
			{
				rt_free(buf);
				return -6;
			}

			buf += brh->addr;
			g_energy.index = _index_check(brh->num, g_energy.len, buf);	
		}
		break;

		case EXTREMA_FILE:
		{
			struct extrema_file_head_data *brh;
			struct rsc			*extrema_rsc;
			
			// 检查文件签名
			brh = (struct extrema_file_head_data*)buf;
			if(brh->cfh.signature != SIG_EXTREMA_FILE)
			{
				rt_free(buf);
				return -7;
			}

			// 检查文件长度
			if(len < sizeof(*brh) + g_table_head->ac_num*sizeof(struct rsc) + brh->num*g_extrema.len)
			{
				rt_free(buf);
				return -8; 	
			}

			if (pRunSet->wJZRL == 0)
			{
				rt_file_del(g_pw_quality_file[file_no].name);
				rt_file_del("/tmp/extrema.csv");
				rt_printf("删除极值记录文件\r\n");
				rt_free(buf);
				return 2;
			}
			if ((brh->size != pRunSet->wJZRL)
				|| (brh->mea_num != g_extrema.mea_num))
			{
				rt_free(buf);
				return -9;
			}
			//检查点表CRC和内容
			if (brh->rsc_crc != g_crc_rectable)
			{
				extrema_rsc = (struct rsc *)(buf+brh->addr_desc);
				for (i=0; i<g_extrema.mea_num; i++)
				{
					iret = memcmp(&extrema_rsc[i], &g_ac_table[i], 5);
					if (iret != 0)
					{
						rt_free(buf);
						return -10;
					}
				}				
			}

			//检索无效记录的索引号
			buf += brh->addr;
			g_extrema.index = _index_check(brh->num, g_extrema.len, buf);	
		}
		break;

		case MEARCD_FILE:
		{
			struct mearcd_file_head_data *brh;
			struct rsc			*mec_rsc;
			
			// 检查文件签名
			brh = (struct mearcd_file_head_data*)buf;
			if(brh->cfh.signature != SIG_MEARCD_FILE)
			{
				rt_free(buf);
				return -11;
			}

			// 检查文件长度
			if(len < sizeof(*brh) + g_table_head->ac_num*sizeof(struct rsc) + brh->num*g_mearcd.len)
			{
				rt_free(buf);
				return -12; 	
			}

			if (pRunSet->wZDRL == 0)
			{
				rt_file_del(g_pw_quality_file[file_no].name);
				rt_file_del("/tmp/mearcd.csv");
				rt_printf("删除定点遥测记录文件\r\n");
				rt_free(buf);
				return 3;
			}
			if ((brh->interval != g_mearcd.delay_s) 
				|| (brh->size != pRunSet->wZDRL)
				|| (brh->mea_num != g_mearcd.mea_num))
			{
				rt_free(buf);
				return -13;
			}
			//检查点表CRC和内容
			if (brh->rsc_crc != g_crc_rectable)
			{
				mec_rsc = (struct rsc *)(buf+brh->addr_desc);
				for (i=0; i<g_mearcd.mea_num; i++)
				{
					iret = memcmp(&mec_rsc[i], &g_ac_table[i], 5);
					if (iret != 0)
					{
						rt_free(buf);
						return -14;
					}
				}				
			}

			//检索无效记录的索引号
			buf += brh->addr;
			g_mearcd.index = _index_check(brh->num, g_mearcd.len, buf);	
		}			
		break;

		case CAP_FILE:
		{
			struct capmanage_file_head_data *brh;
			struct rsc			*cap_rsc;
			
			// 检查文件签名
			brh = (struct capmanage_file_head_data*)buf;
			if(brh->cfh.signature != SIG_CAPRCD_FILE)
			{
				rt_free(buf);
				return -15;
			}

			// 检查文件长度
			if(len < sizeof(*brh) + g_capmanage.mea_num*sizeof(struct rsc) + brh->num*g_capmanage.len)
			{
				rt_free(buf);
				return -16; 	
			}

			if (pRunSet->wCAPRL == 0)
			{
				rt_file_del(g_pw_quality_file[file_no].name);
				rt_file_del("/tmp/cap_manage.csv");
				rt_printf("删除电容器管理文件\r\n");
				rt_free(buf);
				return 4;
			}
			if ((brh->size != pRunSet->wCAPRL)
				|| (brh->meanum != g_capmanage.mea_num))
			{
				rt_free(buf);
				return -17;
			}
			//检查点表CRC和内容
			if (brh->rsc_crc != g_crc_rectable)
			{
				cap_rsc = (struct rsc *)(buf+brh->addr_desc);
				for (i=0; i<g_mearcd.mea_num; i++)
				{
					if (g_ac_table[i].owner == 0)
					{
						if (((g_ac_table[i].indexno-1)>=PUB_AC_UAB1 && (g_ac_table[i].indexno-1)<=PUB_AC_UCA1)
							|| ((g_ac_table[i].indexno-1)>=PUB_AC_UAB2 && (g_ac_table[i].indexno-1)<=PUB_AC_UCA2))
						{
							iret = memcmp(&cap_rsc[j], &g_ac_table[j], 5);
							j++;
						}
					}
					else
					{
						if ((g_ac_table[i].indexno-1)==(SW_AC_IN_Q) || (g_ac_table[i].indexno-1)==(SW_AC_IN_COS))
						{
							iret = memcmp(&cap_rsc[j], &g_ac_table[j], 5);
							j++;
						}
					}

					if (iret != 0)
					{
						rt_free(buf);
						return -18;
					}
				}				
			}

			//检索无效记录的索引号
			buf += brh->addr;
			g_capmanage.index = _index_check(brh->num, g_capmanage.len, buf);			
		}
		break;


		case UDCRCD_FILE:
		{
			struct udcrcd_file_head_data *brh;

			// 检查文件签名
			brh = (struct udcrcd_file_head_data*)buf;
			if(brh->cfh.signature != SIG_UDCRCD_FILE)
			{
				rt_free(buf);
				return -4;
			}

			// 检查文件长度
			if(len < sizeof(*brh) + brh->num*g_udcrcd.len)
			{
				rt_free(buf);
				return -5; 	
			}
			if (pRunSet->wUDCRL == 0)
			{
				rt_file_del(g_pw_quality_file[file_no].name);
				rt_file_del("/tmp/udcrcd.csv");
				rt_printf("删除电池电压记录文件\r\n");
				rt_free(buf);
				return 1;
			}
			if (brh->size != pRunSet->wUDCRL)
			{
				rt_free(buf);
				return -6;
			}

			buf += brh->addr;
			g_udcrcd.index = _index_check(brh->num, g_udcrcd.len, buf);	
		}
		break;

	}

	buf = tmp;
	//释放内存
	rt_free(buf);

	return 0;

}

/******************************************************************************
函数名称：pw_quality_file_rcd
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：更新记录
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/

int pw_quality_file_rcd(u8 file_no, u32 len, u32 size, u32 index_new, u32 index_null, char *new_rcd, char *nul_rcd )
{
	loff_t pos;

	if (g_pw_quality_file[file_no].handle == 0
		|| new_rcd == 0 || nul_rcd == 0)
	{
		return -1;
	}

	// 写无效记录
	pos = size + index_null * len;
	//rt_printf("index_null = %d, pos1 = %d\r\n", index_null, (int)pos);
	if(rt_file_write(g_pw_quality_file[file_no].handle, nul_rcd, len, &pos) != len)		
	{
		return -3;
	}	

	// 写新记录
	pos = size + index_new * len;
	//rt_printf("index_new = %d, pos2 = %d\r\n", index_new, (int)pos);
	if(rt_file_write(g_pw_quality_file[file_no].handle,new_rcd, len, &pos) != len)		
	{
		return -4;			
	}

	return 0;
}

/******************************************************************************
函数名称：pw_quality_app
函数版本：	01.01
创建作者：xxxxxx
创建日期：	2014-09-05
函数说明：电能质量应用程序
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/

static u32 extrema_delay=0;
static u32 time100us=0;
static u32 energy_p_delay=0;
static u32 energy_p_rcddelay=0;
static u32 mearcd_delay=0;
static u32 cap_delay=0;
static u32 caprcd_flag = 0;
static u32 udcrcd_delay = 0;
static u32 udcrcd_no=0;
static u32 init_count = 5*10;
int pw_quality_app(void)
{
	u32 us0;
	
	if((g_pw_init == 0) || (!pRunSet->bTT_Pwquality))
	{
		return 0;
	}

	while(init_count)
	{
		energy_p_delay = ustimer_get_origin();
		init_count--;
		return 0;
	}	
	
	time100us++;

	us0 = ustimer_get_origin();
	if ((int)(us0 - energy_p_delay) >= 0)
	{
		if (pRunSet->wDDRL)
		{
			energy_calc();
		}
		
		energy_p_delay += USTIMER_SEC;
		energy_p_rcddelay++;
		extrema_delay++;
		mearcd_delay++;
		cap_delay++;
		udcrcd_delay++;
	}

	if (energy_p_rcddelay >= g_energy.delay_s)
	{
		if (pRunSet->wDDRL)
		{	
			energy_record();
		}
		energy_p_rcddelay = 0;
	}

	if (extrema_delay >= 1)
	{
		if (pRunSet->wJZRL)
		{
			extrema_calc();
		}
		extrema_delay = 0;
	}

	if (mearcd_delay >= g_mearcd.delay_s)
	{
		if (pRunSet->wZDRL)
		{
			mearcd_record();
		}
		mearcd_delay = 0;
	}

	if (GetRmtYxVal(0,PUB_DI_CAP+1) == SW_DI_TYPE_ON)
	{
		caprcd_flag = 1;
	}
 	
	if (!caprcd_flag)
	{
		capmanage_calc();
		cap_delay = 0;
	}

	if (caprcd_flag && (cap_delay >= g_capmanage.delay_s))
	{
		if (pRunSet->wCAPRL)
		{
			capmanage_calc();
			capmanage_record();
			caprcd_flag = 0;
		}
		cap_delay = 0;
	}

	if (udcrcd_delay >= g_udcrcd.delay_s)
	{
		if (g_udcrcd.begin)
		{
			udcrcd_record(udcrcd_no);
			udcrcd_no++;
			if (udcrcd_no == g_udcrcd.no)
			{
				g_udcrcd.begin = 0;
				udcrcd_no = 0;
			}
		}
		udcrcd_delay = 0;
	}
	return 0;
}
 
/*------------------------------ 内部函数 -------------------------------------
内部函数以下划线‘_’开头，不需要检查参数的合法性.
*/
static int _index_check(u32 num,  u32 len, u8 *buf)
{
	int i, index;

	for (i=0; i<num; i++)
	{
		struct rtc_time_t *time;
		time = (struct rtc_time_t *)buf;
		if (time->month < 1|| time->month >12)	//做一个判断日期非法的通用函数，
		{
			index = i;
			break;
		}
		else
		{
			buf += len;
		}
	}

	return index;
}

static void _get_ac_name(u16 owner,u16 index,char *name)
{

	if(owner==0)
	{
		strcpy(name, g_pub_ac_desc[index-1].name);
	}
	else
	{
		sprintf(name,"%s_%d", g_sw_ac_desc[index-1].name, owner);
	}
}

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


