/********************************************************************************
Copyright (C), Sinowealth Electronic. Ltd.
Author: 	Sino
Version: 	V0.0
Date: 		2020/04/26
History:
	V2.0	2020/04/26		 Preliminary
********************************************************************************/
#include "Main.h"

BOOL bE2PProcessFlg;                                            //EEPROM处理标志
BOOL bE2PBKDsgEnd;                                              //放电结束标志，需要备份信息到外挂EEPROM
BOOL bE2PBKDsgEndValid;
BOOL bE2PBKChgStop;                                             //充电结束标志，需要备份信息到外挂EEPROM
BOOL bE2PBKChgStart;                                            //充电开始标志，需要备份信息到外挂EEPROM
BOOL bE2PBKRtc;                                                 //RTC定时备份标志，需要备份信息到外挂EEPROM
BOOL bE2PErase;                                                 //擦除外挂EEPROM标志
U8 xdata bUart0E2PRdData;                                                //读取外挂EEPROM标志
U8 xdata bUart1E2PRdData;                                                //读取外挂EEPROM标志
U8 xdata bUart2E2PRdData;                                                //读取外挂EEPROM标志
BOOL bE2PRErr;
BOOL bE2PTwiRWErrFlg;
U8 xdata bUart0RTCRdTime;                                                //读取RTC时间标志
U8 xdata bUart1RTCRdTime;                                                //读取RTC时间标志
U8 xdata bUart2RTCRdTime;                                                //读取RTC时间标志
BOOL bDsgToChgFlg;                                              //放电转换为充电，需要备份数据
BOOL bChgToDsgFlg;                                              //充电转换为放电，需要备份数据
U16	xdata uiE2PDataAddr;
U8	xdata ucE2PTwiRWErrDelayCnt;
U8	xdata ucRTCBKTime1;
U16	xdata uiRTCBKTime2;
U8	idata ucUpDataLimitTime;
U16	xdata uiCHGValidTime;
U8	xdata ucRTCBuf[7];


/*************************************************************************************************
* 函数名: AFEI2CCheck
* 参  数: 无
* 返回值: 无
* 描  述: 连续5S检测到AFE的I2C通讯错误，则置位bAfeErr=1
*************************************************************************************************/
void E2PRomTwiCheck(void)
{
	if(bEnEEPRomBK)
	{
		if(bE2PTwiRWErrFlg)
		{
			if(++ucE2PTwiRWErrDelayCnt >= TIME_1S_5S)
			{
				bE2PRErr = 1;
				ucE2PTwiRWErrDelayCnt = TIME_1S_5S;
			}
		}
		else
		{
			ucE2PTwiRWErrDelayCnt = 0;
		}
	}
}


/*************************************************************************************************
* 函数名: E2PRomWrite
* 参  数: Addr：地址；Length：长度；WrBuf：写入存放的Buf
* 返回值: 无
* 描  述: 写入EEPROm
*************************************************************************************************/
BOOL E2PRomWrite(U16 WrAddr, U8 Length, U8 xdata *WrBuf)
{
	BOOL Result = 0;
    U8 i;
    
	if(!bE2PRErr)
	{
		for(i=0; i<5; i++)
		{
			#ifdef TWI_Hardware_Module
			if(TwiWrite(E2PROM_ID, WrAddr, TWI_ADDR_2B, Length, TWI_CRC_NO, WrBuf))
			{
				Result = 1;
				break;
			}                
			#else
			if(TwiWrite(E2PROM_ID, WrAddr, Length, WrBuf))
			{
				Result = 1;
				break;
			}	
			#endif
			Delay1ms(1);
		}
	}
	bE2PTwiRWErrFlg = !Result;                                  //标记通讯是否正常
	
	return Result;
}


/*************************************************************************************************
* 函数名: E2PRomRead
* 参  数: Addr：地址；Length：长度；RdBuf：读取存放的Buf
* 返回值: 无
* 描  述: 读取EEPROm
*************************************************************************************************/
BOOL E2PRomRead(U16 RdAddr, U8 Length, U8 xdata *RdBuf)
{
	BOOL Result = 0;
    U8 i;
    
	if(!bE2PRErr)
	{
		for(i=0; i<5; i++)
		{
			#ifdef TWI_Hardware_Module
			if(TwiRead(E2PROM_ID, RdAddr, TWI_ADDR_2B, Length, TWI_CRC_NO, RdBuf))
			{
				Result = 1;
				break;
			}                
			#else
			if(TwiRead(E2PROM_ID, RdAddr, Length, RdBuf))
			{
				Result = 1;
				break;
			}	
			#endif
			Delay1ms(1);
		}
	}
	bE2PTwiRWErrFlg = !Result;                                  //标记通讯是否正常
	
	return Result;
}



/*************************************************************************************************
* 函数名: E2PRomErase
* 参  数: 无
* 返回值: 无
* 描  述: 擦除EEPROM
*************************************************************************************************/
void E2PRomErase(void)
{
	U16 i;
	U8 xdata WrBuf[8];
	
	MemorySet(WrBuf, 0, 8);                                     //clr Info.uiVCell[]
	
	for(i=0; i<(E2PROM_SIZE/32-1); i++)
	{
		McuWDTClear();
		E2PRomWrite(i*32+31, 1, WrBuf);
	}
	
	E2PRomWrite(E2PROM_BOOT_ADDR, 8, WrBuf);
	uiE2PDataAddr = 0;
}


/*************************************************************************************************
* 函数名: InitE2PRom
* 参  数: 无
* 返回值: 无
* 描  述: 初始化EEPROM的地址
*************************************************************************************************/
BOOL E2PRomInit(void)
{
	BOOL Result = 0;
	
	U8 xdata RdBuf[8];

	Result = E2PRomRead(E2PROM_BOOT_ADDR, 8, RdBuf);

	RdBuf[2] = RdBuf[0]+RdBuf[1];
	RdBuf[6] = RdBuf[4]+RdBuf[5];	

	if(RdBuf[2] == RdBuf[3])
	{
		uiE2PDataAddr = ((U16)RdBuf[0]<<8) + RdBuf[1];
	}
	else if(RdBuf[6] == RdBuf[7])
	{
		uiE2PDataAddr = ((U16)RdBuf[4]<<8) + RdBuf[5];
	}
	else
	{
		uiE2PDataAddr = 0;
	}
	
	return Result;
}


/*************************************************************************************************
* 函数名: E2PRomBKRTC
* 参  数: 无
* 返回值: 无
* 描  述: 备份RTC
*************************************************************************************************/
void E2PRomBKRTC(void)
{
 	U8 xdata WrBuf[9];
	U8 i, checksum = 0;
	
	RTCReadTime(&RTC);
	MemoryCopy((U8 xdata *)&(RTC.Second), WrBuf, 7);
	for(i=0; i<7; i++)
	{
		checksum += WrBuf[i];
	}
	WrBuf[7] = checksum;
	WrBuf[8] = 0x5A;
	
	E2PRomWrite(E2PROM_RTC_ADDR, 9, WrBuf);
}


/*************************************************************************************************
* 函数名: E2PRomBKBoot
* 参  数: 无
* 返回值: 无
* 描  述: 备份EEPROM的Boot区
*************************************************************************************************/
void E2PRomBKBoot(void)
{
 	U8 xdata WrBuf[8];

	WrBuf[0] = (uiE2PDataAddr>>8);
	WrBuf[1] = uiE2PDataAddr;
	WrBuf[3] = WrBuf[0]+WrBuf[1];                               //Calculate checksum

	WrBuf[4] = WrBuf[0];
	WrBuf[5] = WrBuf[1];
	WrBuf[7] = WrBuf[3];
	
	E2PRomWrite(E2PROM_BOOT_ADDR, 8, WrBuf);
} 


/*************************************************************************************************
* 函数名: E2PRomBKData
* 参  数: BKType：备份类型
* 返回值: 无
* 描  述: 读取外挂EEPROM
*************************************************************************************************/
void E2PRomBKData(U8 BKType)
{
	U8 xdata WrBuf[32];	

    if(BKType == E2PROM_BKTYPE_CHG_START)                       //充电开始
    {
        MemoryCopy((U8 xdata *)&ucRTCBuf[0], WrBuf, 3);
		MemoryCopy((U8 xdata *)&ucRTCBuf[4], WrBuf + 3, 3);
    }
    else
    {
    	RTCReadTime(&RTC);
		MemoryCopy((U8 xdata *)&(RTC.Second), WrBuf, 3);
 		MemoryCopy((U8 xdata *)&(RTC.Date), WrBuf + 3, 3);
    }
	
	WrBuf[6] = (Info.uiPackStatus>>8);
	WrBuf[7] = Info.uiPackStatus;
	WrBuf[8] = (Info.uiBatStatus>>8);
	WrBuf[9] = Info.uiBatStatus;
	WrBuf[10] = (Info.ulFCC>>24);
	WrBuf[11] = (Info.ulFCC>>16);
	WrBuf[12] = (Info.ulFCC>>8);
	WrBuf[13] = Info.ulFCC;
	WrBuf[14] = (Info.ulRC>>24);
	WrBuf[15] = (Info.ulRC>>16);
	WrBuf[16] = (Info.ulRC>>8);
	WrBuf[17] = Info.ulRC;
	WrBuf[18] = (Info.ulVoltage>>24);
	WrBuf[19] = (Info.ulVoltage>>16);
	WrBuf[20] = (Info.ulVoltage>>8);
	WrBuf[21] = Info.ulVoltage;
	WrBuf[22] = (Info.slCurr>>24);
	WrBuf[23] = (Info.slCurr>>16);
	WrBuf[24] = (Info.slCurr>>8);
	WrBuf[25] = Info.slCurr;
	WrBuf[26] = (Info.uiTS[0]>>8);
	WrBuf[27] = Info.uiTS[0];
	WrBuf[28] = (Info.uiCycleCount>>8);
	WrBuf[29] = Info.uiCycleCount;
	WrBuf[30] = BKType;
	WrBuf[31] = 0x5A;

	E2PRomWrite(uiE2PDataAddr, 32, WrBuf);
	
	uiE2PDataAddr += 32;
	if(uiE2PDataAddr >= E2PROM_BOOT_ADDR)
	{
		uiE2PDataAddr = 0;
	}

	E2PRomBKBoot();
}


/*************************************************************************************************
* 函数名: Uart0RdE2PRom
* 参  数: 无
* 返回值: 无
* 描  述: 读取外挂EEPROM
*************************************************************************************************/
void Uart0RdE2PRom(void)
{	
	U16 RdAddr;
    
    RdAddr = ((U16)ucUart0Buf[UART_CMD_NO]-CMD_RD_EEPROM)*128+((U16)ucSubClassID-0x80)*4096;
	E2PRomRead(RdAddr, ucUart0Buf[UART_LENGTH], &ucUart0Buf[UART_DATA]);
    
    ucUart0Buf[UART_DATA+ucUart0Buf[UART_LENGTH]] = CRC8cal(&ucUart0Buf,ucUart0Buf[UART_LENGTH]+UART_DATA);
	Uart0SendData();                                             //Start Send Data; Set UART REG
}

/*************************************************************************************************
* 函数名: Uart1RdE2PRom
* 参  数: 无
* 返回值: 无
* 描  述: 读取外挂EEPROM
*************************************************************************************************/
void Uart1RdE2PRom(void)
{	
	U16 RdAddr;
    
    RdAddr = ((U16)ucUart1Buf[UART_CMD_NO]-CMD_RD_EEPROM)*128+((U16)ucSubClassID-0x80)*4096;
	E2PRomRead(RdAddr, ucUart1Buf[UART_LENGTH], &ucUart1Buf[UART_DATA]);
    
    ucUart1Buf[UART_DATA+ucUart1Buf[UART_LENGTH]] = CRC8cal(&ucUart1Buf,ucUart1Buf[UART_LENGTH]+UART_DATA);
	Uart1SendData();                                             //Start Send Data; Set UART REG
}

/*************************************************************************************************
* 函数名: Uart2RdE2PRom
* 参  数: 无
* 返回值: 无
* 描  述: 读取外挂EEPROM
*************************************************************************************************/
void Uart2RdE2PRom(void)
{	
	U16 RdAddr;
    
    RdAddr = ((U16)ucUart2Buf[UART_CMD_NO]-CMD_RD_EEPROM)*128+((U16)ucSubClassID-0x80)*4096;
	E2PRomRead(RdAddr, ucUart2Buf[UART_LENGTH], &ucUart2Buf[UART_DATA]);
    
    ucUart2Buf[UART_DATA+ucUart2Buf[UART_LENGTH]] = CRC8cal(&ucUart2Buf,ucUart2Buf[UART_LENGTH]+UART_DATA);
	Uart2SendData();                                             //Start Send Data; Set UART REG
}


/*************************************************************************************************
* 函数名: UartRdRTC
* 参  数: 无
* 返回值: 无
* 描  述: 读取RTC时间：秒、分、时、日、月、年，并返回给UART
*************************************************************************************************/
void Uart0RdRTC(void)
{
	RTCReadTime(&RTC);
	MemoryCopy((U8 xdata *)&(RTC.Second), &ucUart0Buf[UART_DATA], 7);
	
	ucUart0Buf[UART_DATA+ucUart0Buf[UART_LENGTH]] = CRC8cal(&ucUart0Buf,ucUart0Buf[UART_LENGTH]+UART_DATA);
	Uart0SendData();                                             //Start Send Data; Set UART REG
}


/*************************************************************************************************
* 函数名: Uart1RdRTC
* 参  数: 无
* 返回值: 无
* 描  述: 读取RTC时间：秒、分、时、日、月、年，并返回给UART
*************************************************************************************************/
void Uart1RdRTC(void)
{
	RTCReadTime(&RTC);
	MemoryCopy((U8 xdata *)&(RTC.Second), &ucUart1Buf[UART_DATA], 7);
	
	ucUart1Buf[UART_DATA+ucUart1Buf[UART_LENGTH]] = CRC8cal(&ucUart1Buf,ucUart1Buf[UART_LENGTH]+UART_DATA);
	Uart1SendData();                                             //Start Send Data; Set UART REG
}

/*************************************************************************************************
* 函数名: Uart2RdRTC
* 参  数: 无
* 返回值: 无
* 描  述: 读取RTC时间：秒、分、时、日、月、年，并返回给UART
*************************************************************************************************/
void Uart2RdRTC(void)
{
	RTCReadTime(&RTC);
	MemoryCopy((U8 xdata *)&(RTC.Second), &ucUart2Buf[UART_DATA], 7);
	
	ucUart2Buf[UART_DATA+ucUart2Buf[UART_LENGTH]] = CRC8cal(&ucUart2Buf,ucUart2Buf[UART_LENGTH]+UART_DATA);
	Uart2SendData();                                             //Start Send Data; Set UART REG
}

/*************************************************************************************************
* 函数名: E2PRomBKProcess
* 参  数: 无
* 返回值: 无
* 描  述: 对外挂EEPROM进行相应处理
*************************************************************************************************/
void E2PRomBKProcess(void)
{
	U8 BKType;
	
	if(bEnEEPRomBK && bE2PProcessFlg)
	{
		bE2PProcessFlg = 0;
//		E2PRomInit();    
//		RTCInitTime(&RTC);
		
		if(bE2PErase)
		{
			bE2PErase = 0;
			E2PRomErase();
		}
		
		if(bUart0E2PRdData||bUart1E2PRdData||bUart2E2PRdData)
		{
			if(bUart0E2PRdData )
			{
				bUart0E2PRdData = 0;
				Uart0RdE2PRom();
			}
			if(bUart1E2PRdData)
			{
				bUart1E2PRdData = 0;
				Uart2RdE2PRom();
			}
			if(bUart2E2PRdData)
			{
				bUart2E2PRdData = 0;
				Uart2RdE2PRom();
			}
			
		}
		
		if(bUart0RTCRdTime||bUart1RTCRdTime||bUart2RTCRdTime)
		{
			if(bUart0RTCRdTime)
			{
				bUart0RTCRdTime = 0;
				Uart0RdRTC();
			}
			if(bUart1RTCRdTime)
			{
				bUart1RTCRdTime = 0;
				Uart1RdRTC();
			}
			if(bUart2RTCRdTime)
			{
				bUart2RTCRdTime = 0;
				Uart2RdRTC();
			}
		}
		
		if(bE2PBKRtc)
		{
			bE2PBKRtc = 0;
			E2PRomBKRTC();
		}
		
		if(bE2PBKChgStart)
		{
			bE2PBKChgStart = 0;
			BKType = E2PROM_BKTYPE_CHG_START;
			E2PRomBKData(BKType);
		}
		
		if(bE2PBKChgStop)
		{
			bE2PBKChgStop = 0;
			BKType = E2PROM_BKTYPE_CHG_END;
			E2PRomBKData(BKType);
		}
		
		if(bE2PBKDsgEnd)
		{
			bE2PBKDsgEnd = 0;
			BKType = E2PROM_BKTYPE_DSG_END;
			E2PRomBKData(BKType);
		}
	}
}


/*************************************************************************************************
* 函数名: E2PRomBKCheck
* 参  数: 无
* 返回值: 无
* 描  述: 每1s检测是否需要备份RTC及EEPROM数据
*************************************************************************************************/
void E2PRomBKCheck(void)
{
	if(bEnEEPRomBK)
	{
//		E2PRomInit();    
//		RTCInitTime(&RTC);
		
		if(++ucRTCBKTime1 >= E2ucRTCBKDelay)
		{
			ucRTCBKTime1 = 0;
			RTCReadTime(&RTC);
		}
		
		if(++uiRTCBKTime2 >= 3600)                              //1h
		{
			uiRTCBKTime2 = 0;
			bE2PProcessFlg = 1;
			bE2PBKRtc = 1;
		}

		if(!bCHGING)											
		{
			bDsgToChgFlg = 1;
			if(bChgToDsgFlg)
			{
				bChgToDsgFlg = 0;
				bE2PProcessFlg = 1;
				bE2PBKChgStop = 1;			
			}			
			if(bUV && bE2PBKDsgEndValid)
			{
				bE2PBKDsgEndValid = 0;
				bE2PProcessFlg = 1;
				bE2PBKDsgEnd = 1;
			}
			else if(!bUV)
			{
				bE2PBKDsgEndValid = 1;
			}			
		}

		if((bDsgToChgFlg && Info.slCurr>=E2siChgBKCur))
		{
			if(!uiCHGValidTime)
			{
				RTCReadTime(&RTC);
				MemoryCopy((U8 xdata *)&RTC, ucRTCBuf, 7);    
			}

			if(++uiCHGValidTime > ((U16)E2ucChgBKDelay*60))     //1分钟
			{
				uiCHGValidTime = 0;
				bChgToDsgFlg = 1;
				bDsgToChgFlg = 0;
				bE2PProcessFlg = 1;
				bE2PBKChgStart = 1;
			}
		}
		else
		{
			uiCHGValidTime = 0;
		}
	}
}
