/******************************************************************************
版权所有：	
文件名称：	battery.c
文件版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-12
功能说明：	电池管理处理
其它说明：
修改记录：
*/
/*------------------------------- 头文件 --------------------------------------
*/
#include "head.h"
 
/*------------------------------- 宏定义 --------------------------------------
*/
// 电池活化管理状态
enum
{
	BAT_IDLE=0,	// 空闲态
	BAT_HHRD,	// 活化准备
	BAT_CK_AH,	// 检测容量
	BAT_NCK_AH,	// 不检测容量
	BAT_END_HH,	// 终止活化
	BAT_ST_NUM,	
};

enum
{
	HH_NORMAL=1,	// 正常活化
	HH_VOLLESS,		// 欠量活化
	HH_BREAK,		// 中断活化
	HH_QUIT,		// 退出活化
};

enum
{
	HH_BEGIN,		// 活化启动
	HH_END,			// 活化退出
};


#define BATHH_RCD_NUM	100			// 电池活化记录为100条

#define FILE_VERSION	0X01010101	//文件版本

/*------------------------------ 类型结构 -------------------------------------
*/
//自动活化管理结构体
struct bat
{
	struct timespec ts_bg_set;	// 电池活化启动时间 定值
	struct timespec ts_bg;		// 当前进行的活化启动时间
	struct timespec ts;			// 当前时间
	u8 begin_flag;
};

// 活化记录结构体
struct bathh_rcd
{
	struct rtc_time_t	timemark;	// 时标
	u8		stu[8];					// 状态：电池活化，电源失电，电源故障，电池欠压，开关控制，电池充满
	float	hh[2];					// U、I
	u8		reserved[8];
}; // 16*2

// 活化数据
struct bathh_data
{	
	struct bathh_rcd hhrcd[2];// 活化开始、结束时的记录
	float	bat_ah_cur;		// 当前活化容量
	u8		hhtype;			// 活化类型：正常活化，欠量活化，中断活化	
	u8		reserved[11];
};// 16*5

//电池活化文件头，16bytes
struct bathh_file_head
{
	u32	signature;	//资源表文件签名
	u32	version;	//资源表文件版本
	u32	reserved0;	//保留0
	u32	reserved1;	//保留1
};

struct bat_file_head_data
{
	// 资源表文件头
	struct bathh_file_head cfh;	
	
	// 装置类型
	u8 	equ_sw_num;
	u8 	equ_brd_num;
	char equ_name[14];

	// 电池活化管理描述	
	u32	addr;
	u32 num;

	// 历史最近2次容量
	float bat_ah_old[2];

	u32 Reserved[4];
 };

/*------------------------------ 全局变量 -------------------------------------
*/
struct bat g_bat;		
struct BATT_MANA g_batt_mana;
int g_switch_do = 0;//有开出执行标志1:有开出操作0:无开出操作

struct file * 	bat_handle;			// 电池活化bin文件句柄
struct bat_file_head_data bat_brh;	// 电池活化bin文件头，用于更新近两次活化容量
struct bathh_data	g_bathh_data[2];// 电池活化当前记录
struct bathh_data bat_rcd;			// 临时使用
/*------------------------------ 函数声明 -------------------------------------
*/
static float _bat_get_vol(void);
static void _bat_active_auto(void);
static int _bat_file_init(void);
static int _bat_create_file(void);
static int _bat_begin_end(int hh_type, int stu);
static int _bat_rcd_save(void);
static int _bat_gj(void);
static int _index_check(u32 num,  u32 len, u8 *buf);

/*------------------------------ 外部函数 -------------------------------------
外部函数供其它实体文件引用，必须仔细检查传入参数的合法性.
*/
/******************************************************************************
函数名称：	bat_init
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-12
函数说明：	电池管理初始化.						
参数说明：	无
返回值：  	成功返回0，失败返回负数。
修改记录：	
*/
int bat_init(void)
{
	int i;
	memset(&g_batt_mana, 0, sizeof(g_batt_mana));

	//初始化电池管理结构体
	clk_time_get(&(g_batt_mana.powerontime));

	g_batt_mana.bat_ok = 1;
		
	g_batt_mana.len = FILE_ADDR_ALGIN(sizeof(struct bathh_data));
	g_batt_mana.rcd_num = BATHH_RCD_NUM + 1;//100条

	memset(g_bathh_data, 0, sizeof(g_bathh_data));
	memset(&g_bathh_data[0], 0xFF, sizeof(struct bathh_data));
	
	i = _bat_file_init();
	if (i != 0)
	{
		rt_printf("iret = %d\r\n", i);
		i = _bat_create_file();
		rt_file_del("/tmp/bathh_rcd.csv");
		rt_printf("初始化电池活化记录文件, ret = %d\r\n", i);
	}

	return i;	
}

//退出函数
int bat_exit(void)
{
	if(bat_handle != 0)
	{
		rt_file_close(bat_handle,0);
		bat_handle = 0;
	}
	
	return 0;
}

/******************************************************************************
函数名称：	bat_proc
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-12
函数说明：	电池管理任务。
参数说明：	无
返回值：  	成功返回0，失败返回负数。
修改记录：	
*/
int bat_proc(void)
{
	int stu = g_batt_mana.stu;

	// 检查自动活化需求
	_bat_active_auto();

	// 充电电压检查
	g_batt_mana.hattvol = _bat_get_vol();

	// 获取电源模块状态和开关控制状态
	g_batt_mana.poweroff = g_run_stu.dcjlsd;
	g_batt_mana.powerabn = g_run_stu.dcdygz;
	g_batt_mana.voltless = g_run_stu.dcqy;
	g_batt_mana.hhstatus = g_run_stu.dchh;
	g_batt_mana.switchstatus = bat_get_sw_status();

	// 使用系统tick秒计时
	g_batt_mana.chargeoktime = (u32)60*60*pRunSet->bat_chargeok_time;

	switch(stu)
	{
		case BAT_IDLE:
		{			
			// 若有电源失电、有开出控制或电源故障
			if (g_batt_mana.poweroff || g_batt_mana.switchstatus || g_batt_mana.powerabn)
			{
				g_batt_mana.stu = BAT_END_HH;
				break;
			}

			// 将电池充满
			// 上电充电时间计算
			clk_time_get(&g_batt_mana.poweron);
			g_batt_mana.poweronhour = ((float)(g_batt_mana.poweron.tv_sec-g_batt_mana.powerontime.tv_sec))/3600;
			
			if (g_batt_mana.batvolold < g_batt_mana.hattvol*0.98)
			{
				g_batt_mana.batvolold = g_batt_mana.hattvol;
				g_batt_mana.chargeokdly = g_tick_secs;
				g_batt_mana.chargeok = 0;
			}			
			// 保证电池充满
			else if ((g_batt_mana.batvolold >= g_batt_mana.hattvol*0.98) && (!g_batt_mana.chargeok))
			{				
				g_batt_mana.batvolold = g_batt_mana.hattvol;
				//连续维持充满电压30分钟以上,确认电池充满
				if((g_tick_secs - g_batt_mana.chargeokdly) >= g_batt_mana.chargeoktime)
				{				
					//检查充电OK标志
					if(!g_batt_mana.chargeok)
					{
						//设置电池充满标志
						g_batt_mana.chargeok = 1;
						rt_printf("电池充满\r\n");
					}
				}
			}

			// 电压充满后，需继续监测电压
			if (g_batt_mana.chargeok)
			{
				g_batt_mana.batvolold = g_batt_mana.hattvol;
			}

			// 电池首次上电充电时间要持续24小时, 或者电池电压达到要求
			if (!g_batt_mana.poweron_flag)
			{
				if ((g_batt_mana.poweronhour <= 24.0) && (!g_batt_mana.chargeok))
				{			
				//	rt_printf("电池充电时间不够(%2.2f)小时\r\n", g_batt_mana.poweronhour);
					break;
				}		
				else
				{
					g_batt_mana.poweron_flag = 1;
				}
			}

			// 检测到活化信号
			if (g_batt_mana.hhstatus)
			{
				// 非装置启动活化，判定为电源模块人工启动，清除近两次活化容量，此动作可取消电池告警
				if (g_batt_mana.hhstart_from != FROM_DEVICE)
				{
					bat_brh.bat_ah_old[0] = 0;
					bat_brh.bat_ah_old[1] = 0;
					g_batt_mana.hhstart_from = 0;
				}

				// 电池是否充满，判断正常活化还是欠量活化
				if(g_batt_mana.chargeok)
				{
					g_batt_mana.hhtype = HH_NORMAL;
				}
				else
				{
					g_batt_mana.hhtype = HH_VOLLESS;
				}

				// 活化启动记录
				_bat_begin_end(g_batt_mana.hhtype, HH_BEGIN);
				g_batt_mana.batvolold = 0;
				
				g_batt_mana.stu = BAT_HHRD;				
			}	
		}
		break;

		case BAT_HHRD:
		{
			static int flag=TRUE;			
			// 检查电池是否欠压
			if (g_batt_mana.voltless)
			{
				if (flag)
				{
					g_batt_mana.voltlessdly = ustimer_get_origin();
					flag = FALSE;
				}
							
				// 欠压持续时间检查
				// 持续5秒钟则清除,返回流程时间和充电电压检查
				if(ustimer_get_duration(g_batt_mana.voltlessdly) >= USTIMER_SEC*5)
				{
					//清除电池充电OK标志
					g_batt_mana.chargeok = 0;
					flag = TRUE;
					rt_printf("电池欠压\r\n");

					g_batt_mana.stu = BAT_IDLE;
				}
			}

			if (g_batt_mana.chargeok)
			{
				g_batt_mana.stu = BAT_CK_AH;
			}
			else
			{
				rt_printf("欠量活化\r\n");
				g_batt_mana.stu = BAT_NCK_AH;				
			}
		}
		break;

		case BAT_CK_AH:
		{
			// 若有电源失电、有开出控制或电源故障
			if (g_batt_mana.poweroff || g_batt_mana.switchstatus || g_batt_mana.powerabn)
			{
				g_batt_mana.stu = BAT_END_HH;
				break;
			}
			
			// 正在活化
			if (g_batt_mana.hhstatus)
			{
				// 检查活化进行标志
				if(!g_batt_mana.hhon)
				{
					// 设置活化进行标志
					g_batt_mana.hhon = 1;
					rt_printf("正常活化开始\r\n");

					// 记录活化开始时间
					clk_time_get(&(g_batt_mana.hqtime));
				}
				else
				{
					// 活化进行中,计算当前活化消耗容量
					clk_time_get(&g_batt_mana.hhexitts);
					//将活化持续时间转化为浮点数的小时为单位
					g_batt_mana.hhhour = ((float)(g_batt_mana.hhexitts.tv_sec - g_batt_mana.hqtime.tv_sec))/3600;
				}
			}
			// 活化结束
			else	
			{
				// 有启动过活化操作
				if (g_batt_mana.hhon)
				{
					// 装置发出活化退出命令，活化过程中断，清除近两次活化容量，此动作可取消电池告警
					if (g_batt_mana.hhquit_from == FROM_DEVICE)
					{
						bat_brh.bat_ah_old[0] = 0;
						bat_brh.bat_ah_old[1] = 0;
						g_batt_mana.hhtype = HH_QUIT;
						g_batt_mana.hhquit_from = 0;
					}
					_bat_begin_end(g_batt_mana.hhtype, HH_END);
					
					rt_printf("本次活化总消耗时间:%2.2fh\r\n", g_batt_mana.hhhour);

					g_batt_mana.hhon = 0;
					g_batt_mana.chargeok = 0;
					rt_printf("正常活化完成\r\n");

					g_batt_mana.stu = BAT_IDLE;
				}
			}
		}
		break;

		case BAT_NCK_AH:
		{
			//若有电源失电、有开出控制或电源故障
			if(g_batt_mana.poweroff || g_batt_mana.switchstatus || g_batt_mana.powerabn)
			{
				g_batt_mana.stu = BAT_END_HH;
				break;
			}	

			// 正在活化
			if (g_batt_mana.hhstatus)	
			{
				// 检查活化进行标志
				if(!g_batt_mana.hhon)
				{
					// 设置活化进行标志
					g_batt_mana.hhon = 1;
					rt_printf("欠量活化开始\r\n");

					// 记录活化开始时间
					clk_time_get(&(g_batt_mana.hqtime));
				}
				else
				{
					// 活化进行中,计算当前活化消耗容量
					clk_time_get(&g_batt_mana.hhexitts);
					//将活化持续时间转化为浮点数的小时为单位
					g_batt_mana.hhhour = ((float)(g_batt_mana.hhexitts.tv_sec - g_batt_mana.hqtime.tv_sec))/3600;
				}
			}
			// 活化结束
			else	
			{
				// 有启动过活化操作
				if (g_batt_mana.hhon)
				{
					// 装置发出活化退出命令，活化过程中断，清除近两次活化容量，此动作可取消电池告警
					if (g_batt_mana.hhquit_from == FROM_DEVICE)
					{
						bat_brh.bat_ah_old[0] = 0;
						bat_brh.bat_ah_old[1] = 0;
						g_batt_mana.hhtype = HH_QUIT;
						g_batt_mana.hhquit_from = 0;
					}
					_bat_begin_end(g_batt_mana.hhtype, HH_END);
					
					// 计算活化消耗电池容量
					rt_printf("本次活化总消耗时间:%2.2fh\r\n", g_batt_mana.hhhour);

					g_batt_mana.hhon = 0;
					g_batt_mana.chargeok = 0;
					rt_printf("欠量活化完成\r\n");

					g_batt_mana.stu = BAT_IDLE;
				}
			}
		}
		break;
		
		case BAT_END_HH:
		{
			int ret;
			//活化状态检查
			if(g_batt_mana.hhstatus)
			{
				//若处于活化状态，则禁止活化处理
				ret = bat_act_off(1);
				_bat_begin_end(HH_BREAK, HH_END);
				//rt_printf("活化终止\r\n");
				
				if(ret != -1)
				{
					g_batt_mana.hhon = 0;
					g_batt_mana.chargeok = 0;

					//清除活化开始时间
					memset(&(g_batt_mana.hqtime), 0, sizeof(g_batt_mana.hqtime));
				}
			}	

			// 电源恢复上电、开关控制结束、电源故障排除
			if(!(g_batt_mana.poweroff || g_batt_mana.switchstatus || g_batt_mana.powerabn))
			{
				g_batt_mana.stu = BAT_IDLE;
			}
		}
		break;		
	}

	_bat_gj();
	return 0;
}

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

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

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

	if(rt_file_read(bat_handle,buf,len1,&pos) != len1)
	{
		rt_free(buf);
		return -2;
	}
		
	//需考虑打印文件时，同步存储记录的问题
	// 创建数据文件
	pos = 0;
	pfile = rt_file_open("/tmp/bathh.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, "上次有效容量,本次有效容量,电池是否正常\r\n");
	rt_file_write(pfile,p,strlen(p),&pos);

	sprintf(p, "%4.3f,%4.3f,", bat_brh.bat_ah_old[1], bat_brh.bat_ah_old[0]);
	rt_file_write(pfile,p,strlen(p),&pos);

	if (g_batt_mana.bat_ok)
	{
		sprintf(p,"正常,");			
	}
	else
	{
		sprintf(p,"异常,");			
	}	
	rt_file_write(pfile,p,strlen(p),&pos);

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

	//打印表格标题
	sprintf(p,	"活化类型,"
				"活化起始时间,电池活化,电源失电,电源故障,电池欠压,开关控制,电池充满,起始电压,起始电流,"
				"活化结束时间,电池活化,电源失电,电源故障,电池欠压,开关控制,电池充满,结束电压,结束电流,"
				"告警阀值,活化时长");
	rt_file_write(pfile,p,strlen(p),&pos);
	
	sprintf(p, "\r\n"); 	
	rt_file_write(pfile,p,strlen(p),&pos);

	//打印记录
	rcd = &bat_rcd;
	for(loop=g_batt_mana.rcd_num,i=g_batt_mana.index+1; loop>0; loop--,i++)
	{
		if(i>= g_batt_mana.rcd_num)
		{
			i=0;
		}
		
		//找出标示行下的最老记录行
		memcpy(&bat_rcd, buf+i*g_batt_mana.len, g_batt_mana.len);

		if (rcd->hhtype == HH_NORMAL)
		{
			sprintf(p,"正常活化,");			
		}
		else if (rcd->hhtype == HH_VOLLESS)
		{
			sprintf(p,"欠量活化,");			
		}
		else if (rcd->hhtype == HH_BREAK)
		{
			sprintf(p,"中断活化,");			
		}
		else if (rcd->hhtype == HH_QUIT)
		{
			sprintf(p,"退出活化,");			
		}
		else	//判定该条记录非法
		{
			continue;					
		}
		rt_file_write(pfile,p,strlen(p),&pos);

		for (k=0; k<2; k++)
		{
			sprintf(p, "%04d-%02d-%02d_%02d:%02d:%02d-%03d,", 
				rcd->hhrcd[k].timemark.year+2000, 
				rcd->hhrcd[k].timemark.month,
				rcd->hhrcd[k].timemark.day,
				rcd->hhrcd[k].timemark.hour,
				rcd->hhrcd[k].timemark.min,
				rcd->hhrcd[k].timemark.ms/1000,
				rcd->hhrcd[k].timemark.ms%1000);
			rt_file_write(pfile,p,strlen(p),&pos);

			// 4个开入
			for (j=0; j<4; j++)
			{
				if (rcd->hhrcd[k].stu[j])
				{
					sprintf(p,"合,");				
				}
				else
				{
					sprintf(p,"分,");
				}
				rt_file_write(pfile,p,strlen(p),&pos);
			}

			// 开关控制
			if (rcd->hhrcd[k].stu[4])
			{
				sprintf(p,"有,");				
			}
			else
			{
				sprintf(p,"无,");
			}
			rt_file_write(pfile,p,strlen(p),&pos);

			// 电池充满
			if (rcd->hhrcd[k].stu[5])
			{
				sprintf(p,"已充满,");				
			}
			else
			{
				sprintf(p,"未充满,");
			}
			rt_file_write(pfile,p,strlen(p),&pos);

			sprintf(p, "%4.3f,%4.3f,", 
					rcd->hhrcd[k].hh[0], 
					rcd->hhrcd[k].hh[1]);
			rt_file_write(pfile,p,strlen(p),&pos);
		}	

		// 告警阀值
 		sprintf(p, "%4.3f,", tRunPara.bat_alarm);
		rt_file_write(pfile,p,strlen(p),&pos);

		// 本次活化消耗时间
 		sprintf(p, "%4.3f,", rcd->bat_ah_cur);
		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;
}
/******************************************************************************
函数名称：	bat_set_sw_status
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-12
函数说明：	设置开关状态。
参数说明：value: true:有开出false:无开出
返回值：  	无
修改记录：	
*/
void bat_set_sw_status(bool value)
{
	g_switch_do = value;	
}

/******************************************************************************
函数名称：	get_switch_status
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-12
函数说明：	获取开关状态。
参数说明：无
返回值：  	返回开关状态值1 或0，1:有开出控制0:无开出控制
修改记录：	
*/
int bat_get_sw_status(void)
{
	return g_switch_do;
}

/******************************************************************************
函数名称：	bat_begin_time
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-12-16
函数说明：	电池活化关闭
参数说明：	buf
返回值：  	成功返回0.
修改记录：	
*/
int bat_begin_time(void)
{
	memset (&g_bat, 0, sizeof(g_bat));
	
	g_bat.ts_bg_set.tv_sec = (long)tRunPara.dTBatBegin;
	g_bat.begin_flag = 0;

	return 0;
}

/******************************************************************************
函数名称：	bat_active
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-12-16
函数说明：	电池活化启动
参数说明：	buf
返回值：  	成功返回0.
修改记录：	
*/
int bat_active(int value)
{
#ifdef BATTERY_WITH_COMM
	int i;
	bool b_bat_comm=false;
	#ifdef FUNC_SEL_BAT_MODULE
		bool b_bat_comm_pwrm=false;
	#endif
	
	for(i=0;i<CFG_UART_NUM_MAX;i++)
	{
		if(tRunPara.tUartPara[i].wProtocol == PROTOCOL_POWER_MOD)
		{
			b_bat_comm = true;
		}
	#ifdef FUNC_SEL_BAT_MODULE
		else if(tRunPara.tUartPara[i].wProtocol == PROTOCOL_PWRM)
		{
			b_bat_comm_pwrm = true;
		}
	#endif
	}

	if(b_bat_comm)
	{
		StartBattAct();
	}
	#ifdef FUNC_SEL_BAT_MODULE
	else if(b_bat_comm_pwrm)
	{
		set_ykhh_all_flag();
	}
	#endif
	else
#endif
	{
		if(sw_do_pub(PUB_DO_DCHH,SW_DO_TYPE_ON)!=0)
		{
			rt_printf("电池活化启动失败\r\n");
			return -1;
		}
		
		soe_record_opt(EV_BAT_HANDACTIVE, 1);	

		g_batt_mana.hhstart_from = FROM_DEVICE;
	}

	return 0;
}

/******************************************************************************
函数名称：	bat_active
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-12-16
函数说明：	电池活化关闭
参数说明：	buf
返回值：  	成功返回0.
修改记录：	
*/
int bat_act_off(int value)
{
	/* 不主动发活化退出命令，避免干扰测试
	if(sw_do_pub(PUB_DO_HHTC,SW_DO_TYPE_ON)!=0)
	{
		rt_printf("电池活化退出失败\r\n");
		return -1;
	}
	*/
	
	//soe_record_opt(EV_BAT_HANDACTOFF, 1);

#ifdef BATTERY_WITH_COMM
	int i;
	bool b_bat_comm=false;
	#ifdef FUNC_SEL_BAT_MODULE
		bool b_bat_comm_pwrm=false;
	#endif
	
	for(i=0;i<CFG_UART_NUM_MAX;i++)
	{
		if(tRunPara.tUartPara[i].wProtocol == PROTOCOL_POWER_MOD)
		{
			b_bat_comm = true;
		}
	#ifdef FUNC_SEL_BAT_MODULE
		else if(tRunPara.tUartPara[i].wProtocol == PROTOCOL_PWRM)
		{
			b_bat_comm_pwrm = true;
		}
	#endif
	}

	if(b_bat_comm)
	{
		StopBattAct();
	}
	#ifdef FUNC_SEL_BAT_MODULE
	else if(b_bat_comm_pwrm)
	{
		set_ykstop_all_flag();
	}
	#endif
#endif

	sw_do_pub(PUB_DO_HHTC,SW_DO_TYPE_ON);

	g_batt_mana.hhquit_from = FROM_DEVICE;
	return 0;
}

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

/******************************************************************************
函数名称：	_bat_get_vol
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2015-05-12
函数说明：	获取电池电压。
参数说明：无
返回值：     
修改记录：	
*/
static float _bat_get_vol(void)
{
	float vol;
	vol = rt_round((float)g_sw_pub.ac_in[PUB_AC_IN_UDC]/Q16_BASE);
	
	return vol;	
}

/******************************************************************************
函数名称：	_bat_active_auto
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-12-16
函数说明：	电池自动活化处理
参数说明：	无
返回值：  	无
修改记录：	
*/
static void _bat_active_auto(void)
{
	long interval;

#ifdef BATTERY_WITH_COMM
	int i;
	bool b_bat_comm=false;
	for(i=0;i<CFG_UART_NUM_MAX;i++)
	{
		if(tRunPara.tUartPara[i].wProtocol == PROTOCOL_POWER_MOD)
		{
			b_bat_comm = true;
		}
	}
#endif

	interval = (long)tRunPara.dTBatInterval;

	// 取当前时间
	clk_time_get(&g_bat.ts);

	// 活化间隔大于0，自动活化投入
	if(tRunPara.dTBatInterval>0)
	{
		if (!g_bat.begin_flag)
		{
		
			// 如果上电时启动时间未设置,
			// 如果上电时当前时间比启动时间小2倍活化间隔
			// 则认为当前时间有误,从当前时间开始判定间隔
			#if 0
			if ((tRunPara.dTBatBegin == 0)
			 	|| (g_bat.ts.tv_sec+interval*2) < g_bat.ts_bg_set.tv_sec)
			{
				// 暂存启动时间，启动活化间隔对比
				clk_time_get(&g_bat.ts_bg);
				g_bat.begin_flag = 1;
			}
			#endif
			// 如果上电时当前时间略小于启动时间,返回不处理
			if (g_bat.ts.tv_sec < g_bat.ts_bg_set.tv_sec)
			{
				return;
			}
			// 如果上电时当前时间大于启动时间, 且未开始第一次活化
			else if ((g_bat.ts.tv_sec - g_bat.ts_bg_set.tv_sec) / interval < 1)
			{
				// 暂存启动时，启动活化间隔对比
				g_bat.ts_bg.tv_sec = g_bat.ts_bg_set.tv_sec - interval;
				g_bat.begin_flag = 1;
			}
			// 如果上电时当前时间大于启动时间，且已多次活化
			else if ((g_bat.ts.tv_sec - g_bat.ts_bg_set.tv_sec) / interval >= 1)
			{
				long sec;

				// 取出本次活化的累积时间
				sec = (g_bat.ts.tv_sec - g_bat.ts_bg_set.tv_sec) % interval;
				// 暂存启动时间，启动活化间隔对比
				g_bat.ts_bg.tv_sec = g_bat.ts.tv_sec - sec;
				g_bat.begin_flag = 1;
			}
		}
		else
		{
			// 当前时间与启动时间比对，是否大于间隔
			if ((g_bat.ts.tv_sec-g_bat.ts_bg.tv_sec) >= interval)
			{
				// 启动活化
			#ifdef BATTERY_WITH_COMM
				if(b_bat_comm)
				{
					StartBattAct();
					soe_record_opt(EV_BAT_AUTOACTIVE, 1);
				}
				else
			#endif
				{
					if(sw_do_pub(PUB_DO_DCHH,SW_DO_TYPE_ON)==0)
					{
						soe_record_opt(EV_BAT_AUTOACTIVE, 1);	
					}
				}
				g_batt_mana.hhstart_from = FROM_DEVICE;

				// 更新启动时间
				clk_time_get(&g_bat.ts_bg);
			}
		}
	}
	else
	{
		g_bat.begin_flag = 0;
	}
}

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

	loff_t pos;
	struct bat_file_head_data *brh;

	// 打开文件
	bat_handle = rt_file_open("/app/data/bathh_rcd.bin",O_RDWR,0);
	if(IS_ERR(bat_handle))
	{
		return -1;
	}

	// 得到文件长度
	len = rt_file_getfile_size(bat_handle);
	if(len <= 0)
	{
		rt_file_close(bat_handle,0);
		return -11;
	}
	
	// 分配内存
	buf = rt_malloc(len);
	if((buf) == NULL)
	{
		rt_file_close(bat_handle,0);
		return -2; 	
	}
	//保存原指针,便于以后释放内存
	tmp = buf;
	// 读出内容
	pos = 0;
	if(rt_file_read(bat_handle,buf,len,&pos) != len)
	{
		rt_file_close(bat_handle,0);
		rt_free(buf);
		return -3;
	}

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

	// 检查文件长度
	if(len < sizeof(*brh) + brh->num*g_batt_mana.len)
	{
		rt_free(buf);
		return -5; 	
	}

	memcpy(&bat_brh, buf, sizeof(bat_brh));
	
	buf += brh->addr;
	g_batt_mana.index = _index_check(brh->num, g_batt_mana.len, buf);	

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

	return 0;

}

/******************************************************************************
函数名称：_bat_create_file
函数版本：01.01
创建作者：xxxxxx
创建日期：2014-09-05
函数说明：创建电池活化记录文件
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
static int _bat_create_file(void)
{
	unsigned int addr,file_length;
	char *p;
	loff_t pos;
	struct bat_file_head_data	bat_file;
		
	// 写文件头
	memset(&bat_file,0,sizeof(bat_file));
	bat_file.cfh.signature = SIG_BATHH_FILE;
	bat_file.cfh.version = FILE_VERSION;
		
	bat_file.addr = FILE_ADDR_ALGIN(sizeof(bat_file));
	bat_file.num = g_batt_mana.rcd_num;

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

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

	// 创建数据文件
	bat_handle = rt_file_open("/app/data/bathh_rcd.bin",O_CREAT|O_RDWR,0);
	if(IS_ERR(bat_handle))
	{
		bat_handle = 0;
		rt_printf("%s open error!\r\n","/app/data/bathh_rcd.bin");
		rt_free(p);
		return -2;
	}
	
	pos = 0;
	rt_file_write(bat_handle,p,file_length,&pos);

	g_batt_mana.index = 0;

	rt_free(p);
	
	return 0;
}

/******************************************************************************
函数名称：_bat_rcd
函数版本：01.01
创建作者：xxxxxx
创建日期：2014-09-05
函数说明：电池活化起始和结束记录
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
static int _bat_begin_end(int hh_type, int stu)
{
	struct timespec ts;

	switch(stu)
	{
		case HH_BEGIN:
		{
			// 活化类型
			g_bathh_data[1].hhtype = hh_type;

			// 起始活化时间
			clk_time_get(&ts);
			timespec_to_rtc(ts,&g_bathh_data[1].hhrcd[0].timemark, 1);

			// 起始活化各状态
			g_bathh_data[1].hhrcd[0].stu[0] = g_batt_mana.hhstatus;
			g_bathh_data[1].hhrcd[0].stu[1] = g_batt_mana.poweroff;
			g_bathh_data[1].hhrcd[0].stu[2] = g_batt_mana.powerabn;
			g_bathh_data[1].hhrcd[0].stu[3] = g_batt_mana.voltless;
			g_bathh_data[1].hhrcd[0].stu[4] = g_batt_mana.switchstatus;
			g_bathh_data[1].hhrcd[0].stu[5] = g_batt_mana.chargeok;

			// 起始活化电压、电流
			g_bathh_data[1].hhrcd[0].hh[0] = g_batt_mana.hattvol;
		}
		break;

		case HH_END:
		{
			// 活化类型
			if (hh_type != g_bathh_data[1].hhtype)
			{
				g_bathh_data[1].hhtype = hh_type;
			}
			
			// 结束活化时间
			clk_time_get(&ts);
			timespec_to_rtc(ts,&g_bathh_data[1].hhrcd[1].timemark, 1);

			// 结束活化各状态
			g_bathh_data[1].hhrcd[1].stu[0] = g_batt_mana.hhstatus;
			g_bathh_data[1].hhrcd[1].stu[1] = g_batt_mana.poweroff;
			g_bathh_data[1].hhrcd[1].stu[2] = g_batt_mana.powerabn;
			g_bathh_data[1].hhrcd[1].stu[3] = g_batt_mana.voltless;
			g_bathh_data[1].hhrcd[1].stu[4] = g_batt_mana.switchstatus;
			g_bathh_data[1].hhrcd[1].stu[5] = g_batt_mana.chargeok;
			
			// 结束活化电压、电流
			g_bathh_data[1].hhrcd[1].hh[0] = g_batt_mana.hattvol;

			// 本次活化容量
			g_bathh_data[1].bat_ah_cur = g_batt_mana.hhhour;

			// 更新近两次有效活化容量
			if (g_bathh_data[1].hhtype == HH_NORMAL)
			{
				bat_brh.bat_ah_old[1] = bat_brh.bat_ah_old[0];
				bat_brh.bat_ah_old[0] = g_batt_mana.hhhour;			
			}

			// 存储记录
			_bat_rcd_save();
		}
		break;
	}
	return 0;
}
/******************************************************************************
函数名称：_bat_rcd_save
函数版本：01.01
创建作者：xxxxxx
创建日期：2014-09-05
函数说明：电池活化记录
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
static int _bat_rcd_save(void)
{
	u32 index_new;
	loff_t pos;
	u32 size;

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

	//更新记录
	if (bat_handle == 0	|| (char*)&g_bathh_data[0] == 0 || (char*)&g_bathh_data[0] == 0)
	{
		return -1;
	}

	size = sizeof(struct bat_file_head_data);

	// 写无效记录
	pos = size + g_batt_mana.index * g_batt_mana.len;
	if(rt_file_write(bat_handle, (char*)&g_bathh_data[0], g_batt_mana.len, &pos) != g_batt_mana.len)		
	{
		return -3;
	}	

	// 写新记录
	pos = size + index_new * g_batt_mana.len;
	if(rt_file_write(bat_handle, (char*)&g_bathh_data[1], g_batt_mana.len, &pos) != g_batt_mana.len)		
	{
		return -4;			
	}

	// 更新近两次容量
	pos = 0;
	if(rt_file_write(bat_handle, (char*)&bat_brh, size, &pos) != size)	
	{
		return -5;
	}	

	memset(&g_bathh_data[1], 0, sizeof(struct bathh_data));
	return 0;
}

/******************************************************************************
函数名称：	_bat_gj
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-12-16
函数说明：	电池异常告警
参数说明：	无
返回值：  	无
修改记录：	
*/
static int _bat_gj(void)
{
	struct timespec ts;
	struct rtc_time_t	time[2];	

	// 当连续两次正常活化，容量都小于阀值，发出电池异常告警
	if (((bat_brh.bat_ah_old[0] > 0) && (bat_brh.bat_ah_old[0] < tRunPara.bat_alarm))
		&& ((bat_brh.bat_ah_old[1] > 0) && (bat_brh.bat_ah_old[1] < tRunPara.bat_alarm)))
	{
		//if(!soe_check(EV_BATERR))
		{			
			long dz[2];

			dz[0] = (long)(bat_brh.bat_ah_old[0]*Q16_BASE);
			dz[1] = (long)(bat_brh.bat_ah_old[1]*Q16_BASE);
			
			//soe_record_ev(EV_BATERR, 1, dz[0], dz[1], 0);
		}
		g_batt_mana.bat_ok = 0;
	}
	else
	{
		//if(soe_check(EV_BATERR))
		//{
		//	soe_record_ev(EV_BATERR, 0, 0,0,0 ); 
		//}
		g_batt_mana.bat_ok = 1;
	}

	// 当只有最新一次容量小于阀值时，主动启动第二次活化
	if (((bat_brh.bat_ah_old[0] > 0) && (bat_brh.bat_ah_old[0] < tRunPara.bat_alarm))
		&& (bat_brh.bat_ah_old[1] >= tRunPara.bat_alarm))
	{
		// 有自动活化时
		if(tRunPara.dTBatInterval>0)
		{
			clk_time_get(&ts);
			timespec_to_rtc(ts, &time[0], 1);
			timespec_to_rtc(g_bat.ts_bg_set, &time[1], 1);

			if ((time[0].hour == time[1].hour)
				||(time[0].min == time[1].min)
				||(time[0].ms == time[1].ms))
			{
				// 启动活化
				if(sw_do_pub(PUB_DO_DCHH,SW_DO_TYPE_ON)==0)
				{
					soe_record_opt(EV_BAT_AUTOACTIVE, 1);	
				}
				g_batt_mana.hhstart_from = FROM_DEVICE;
			}
		}
		else//无自动活化，主动活化
		{
			// 启动活化
			if(sw_do_pub(PUB_DO_DCHH,SW_DO_TYPE_ON)==0)
			{
				soe_record_opt(EV_BAT_AUTOACTIVE, 1);	
			}
			g_batt_mana.hhstart_from = FROM_DEVICE;
		}
	}
	
	return 0;
}
/******************************************************************************
函数名称：	_index_check
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2014-12-16
函数说明：	索引出无效记录位置，即新记录填写位置
参数说明：	无
返回值：  	无
修改记录：	
*/
static int _index_check(u32 num,  u32 len, u8 *buf)
{
	int i, index=0;

	for (i=0; i<num; i++)
	{
		struct bathh_data *bat;
		bat = (struct bathh_data *)buf;
		
		if (bat->hhtype == 0xFF)	// 非法记录为0xFF
		{
			index = i;
			break;
		}
		else
		{
			buf += len;
		}
	}

	return index;
}

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


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

