/********************************************************************************
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	bMcuFlashWrWaitFlg;
BOOL	bMcuFlashWrFlg;
BOOL	bMcuFlashErr;
U8	xdata	ucMcuFlashWrValid;
U8	xdata	bMcuFlashWrWaitCnt;

/*************************************************************************************************
* 函数名: McuFlashWrOneByte
* 参  数: McuFlashAddr：起始地址；WrData：写入的注释
* 返回值: 无
* 描  述: 写1个字节
*************************************************************************************************/
void McuFlashWrOneByte(U16 McuFlashAddr, U8 WrData)
{
    IrqDis();
	McuFlashEn();
	
    XPAGE = McuFlashAddr>>8;
    IB_OFFSET = McuFlashAddr % 256;
    IB_DATA = WrData;

    IB_CON1 = 0x6E;	
    IB_CON2 = 0x05;
    IB_CON3 = 0x0A;
    IB_CON4 = 0x09;
	if(XPAGE == (McuFlashAddr>>8))
	{
		IB_CON5 = 0x06;
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
	}
	
    McuFlashDis();
	IrqEn();
}


/*************************************************************************************************
* 函数名: McuFlashBlankCheck
* 参  数: McuFlashAddr：起始地址
* 返回值: 0：非全0，Erase失败；1：全0，Erase成功
* 描  述: 当Erase完1个Sector，需检查是否全为0
*************************************************************************************************/
BOOL McuFlashBlankCheck(U16 McuFlashAddr)
{
	BOOL Result = 1;
    U16 i;
    
    for(i=0; i<MCUFLASH_SECTOR_SIZE; i++)
    {
        if(CBYTE[McuFlashAddr+i] != 0x00)
        {
            Result = 0;
			break;
        }
    }
    
    return Result;
}


/*************************************************************************************************
* 函数名: McuFlashDataCheck
* 参  数: McuFlashAddr：起始地址
* 返回值: 0：校验错误；1：校验正确
* 描  述: 校验被写的Sector数据是否和XRAM区一致
*************************************************************************************************/
BOOL McuFlashDataCheck(U16 McuFlashAddr, U16 XramAddr)
{
	BOOL Result = 1;
    U8 xdata *ptr = (U8 xdata *)XramAddr;                   //强制将变量的值作为地址赋值给指针变量
    U16 i;
    
    for(i=0; i<MCUFLASH_SECTOR_SIZE; i++)
    {
        if(CBYTE[McuFlashAddr+i] != *(ptr+i))
        {
            Result = 0;
			break;
        }
    }
	
    return Result;
}


/*************************************************************************************************
* 函数名: McuFlashWrSector
* 参  数: 无
* 返回值: 无
* 描  述: 写1个Sector的数据
*************************************************************************************************/
BOOL McuFlashWrSector(U16 McuFlashAddr, U16 XramAddr)
{
    BOOL Result = 0;
    U16 i;
    U8 xdata *ptr = (U8 xdata *)XramAddr;                   //强制将变量的值作为地址赋值给指针变量
    
    for(i=0; i<MCUFLASH_SECTOR_SIZE; i++)
    {
        IB_OFFSET = McuFlashAddr+i;
        XPAGE = (McuFlashAddr+i)>>8;
        IB_DATA = *(ptr+i);
		IB_CON1 = 0x6E;
		if(!EA)
		{
			IB_CON2 = 0x05;
			if(FLASHCON)
			{
				IB_CON3 = 0x0A;
				if(ucMcuFlashWrValid == 0x55)
				{
					IB_CON4 = 0x09;
					if(XPAGE == ((McuFlashAddr+i)>>8))
					{
						IB_CON5 = 0x06;
						_nop_();
						_nop_();
						_nop_();
						_nop_();
						_nop_();
						Result = 1;
					}
					else
					{
						Result = 0;
						break;
					}
				}
				else
				{
					Result = 0;
					break;
				}
			}
			else
			{
				Result = 0;
				break;
			}
		}
		else
		{
			Result = 0;
			break;
		}
    }
	
    return Result;
}


/*************************************************************************************************
* 函数名: McuFlashWrite
* 参  数: McuFlashAddr：写入的地址，长度固定为1个Sector
* 返回值: 0：写入失败；1：写入成功
* 描  述: 写MCU Flash的1个Sector:
          1.Erase Sector
          2.检查当前Sector是否全为0
          3.将XRAM数据写入
          4.校验XRAM和MCU Flash区数据是否一致
*************************************************************************************************/
BOOL McuFlashWrite(U16 McuFlashAddr, U16 XramAddr)
{
    BOOL Result = 0;
	
	McuWDTClear();                      //清看门狗
	IrqDis();                           //关闭中断源
	McuFlashEn();
	
	XPAGE = McuFlashAddr >> 8;
	IB_CON1 = 0xE6;
	if(!EA)
	{
		IB_CON2 = 0x05;
		if(FLASHCON)
		{
			IB_CON3 = 0x0A;
			if(ucMcuFlashWrValid == 0x55)
			{
				IB_CON4 = 0x09;
				if(XPAGE == (McuFlashAddr >> 8))
				{
					IB_CON5 = 0x06;
					_nop_();
					_nop_();
					_nop_();
					_nop_();
					_nop_();

					if(McuFlashBlankCheck(McuFlashAddr))					//查空
					{
						if(McuFlashWrSector(McuFlashAddr, XramAddr))		//写入
						{
							if(McuFlashDataCheck(McuFlashAddr, XramAddr))	//校验
							{
								Result = 1;
							}
						}
					}
				}
			}
		}
	}

    IB_CON1 = 0;
    IB_CON2 = 0;
    IB_CON3 = 0;
    IB_CON4 = 0;
    IB_CON5 = 0;
    
    McuFlashDis();
    XPAGE = 0x00;
    IrqEn();
    
    return Result;
}






/*************************************************************************************************
* 函数名: McuFlashProcess
* 参  数: 无
* 返回值: 无
* 描  述: 写MCU Flash，同时更新备份1区和2区
*************************************************************************************************/
void McuFlashProcess(void)
{
	BOOL McuFlashBk1WrFailFlg = 0, McuFlashBk2WrFailFlg = 0;
	U16 VoltageMin;
	
	if(bMcuFlashWrFlg)
	{
		bMcuFlashWrFlg = 0;
		
		ucMcuFlashWrValid = 0x55;                           //防误写检验标志
		if(ucCellNum > 5)                                   //6~10串应用，需要总电压超过10V
		{
			VoltageMin = 10000;
		}
		else                                                //3~5串应用，需要总电压超过5V
		{
			VoltageMin = 5000;
		}
		
		if((Info.ulVoltage>=VoltageMin) && (E2uiCheckFlag==0x5AA5))
		{
			if(!McuFlashWrite(MCUFLASH_BK1_ADDR, XRAM_MAP_ADDR))    //连续写两次，如果都错误则置位错误标志
			{
				if(!McuFlashWrite(MCUFLASH_BK1_ADDR, XRAM_MAP_ADDR))
				{
					McuFlashBk1WrFailFlg = 1;
					E2uiCheckFlag = 0xFFFF;
					McuFlashWrOneByte(MCUFLASH_BK1_ADDR+510,0xFF);
					McuFlashWrOneByte(MCUFLASH_BK1_ADDR+511,0xFF);
				}
			}

			if(!McuFlashWrite(MCUFLASH_BK2_ADDR, XRAM_MAP_ADDR))
			{
				if(!McuFlashWrite(MCUFLASH_BK2_ADDR, XRAM_MAP_ADDR))
				{
					McuFlashBk2WrFailFlg = 1;
					E2uiCheckFlag = 0xFFFF;
					McuFlashWrOneByte(MCUFLASH_BK2_ADDR+510,0xFF);
					McuFlashWrOneByte(MCUFLASH_BK2_ADDR+511,0xFF);
				}	
			}
		}
		else
		{
			McuFlashBk1WrFailFlg = 1;
			McuFlashBk2WrFailFlg = 1;
		}
		ucMcuFlashWrValid = 0x00;
		
		if(McuFlashBk1WrFailFlg && McuFlashBk2WrFailFlg)	//如果Flash两个区都操作错误，则置位Flash错误标志
		{
			bMcuFlashErr = 1;
		}
	}
}


/*************************************************************************************************
* 函数名: McuFlashRead
* 参  数: SourceAddr：源地址；TargetAddr：目标地址；Length：数据长度
* 返回值: 0：数据正确；1：数据错误
* 描  述: 判断MCU Flash参数区的最后一个字节是否为0x5AA5，检查数据区是否被破坏
*************************************************************************************************/
BOOL McuFlashRead(U16 SourceAddr, U8 xdata *TargetAddr, U16 Length)
{
	U16 i;
    BOOL Result = 1;
    U8 xdata *data TargetAddr1 = TargetAddr;                //*后面的data关键字的作用，是把指针TargetAddr1定义在data区中

	IrqDis();
	McuFlashEn();
    McuWDTClear();
    for(i=0; i<Length; i++)
	{
		*TargetAddr1 = CBYTE[SourceAddr+i];
		TargetAddr1++;
	}
	McuFlashDis();
	IrqEn();
	
    return Result;
}


/*************************************************************************************************
* 函数名: McuFlashWrWaitCheck
* 参  数: 无
* 返回值: 无
* 描  述: 当需要写MCU Flash参数时，部分模块需要延时2S执行写操作（上位机修改参数），部分模块立即写
*************************************************************************************************/
void McuFlashWrWaitCheck(void)
{
	if(bMcuFlashWrWaitFlg)
	{
	 	if(++bMcuFlashWrWaitCnt >= MCU_FLASH_WATI_DELAY)
		{
			bMcuFlashWrWaitFlg = 0;
		 	bMcuFlashWrWaitCnt = 0;
			bMcuFlashWrFlg = 1;
		}
	}
}


/*************************************************************************************************
* 函数名: McuFlashCheckFlg
* 参  数: McuFlashAddr：MCU Flash区的地址
* 返回值: 0：数据正确；1：数据错误
* 描  述: 判断MCU Flash参数区的最后一个字节是否为0x5AA5，检查数据区是否被破坏
*************************************************************************************************/
BOOL McuFlashCheckFlg(U16 McuFlashAddr)
{
	BOOL Result = 0;
	
	McuFlashEn();
	if(CWORD[McuFlashAddr/2] == 0x5AA5)
	{
		Result = 1;
	}
	McuFlashDis();
	
	return Result;
}

