/********************************************************************************
Copyright (C), Sinowealth Electronic. Ltd.
Author: 	Sino
Version: 	V0.0
Date: 		2020/04/26
History:
	V2.0	2020/04/26		 Preliminary
********************************************************************************/
#include "MCURegister.h"
#include "C51_TYPE.H"
#include "Flash.h"
#include <intrins.h>
#include <ABSACC.H>

U8 ucMcuFlashWrValid;


/*************************************************************************************************
* 函数名: McuFlashEraseSector
* 参  数: McuFlashAddr：起始地址；McuType：擦除CODE区或者EEPROM
* 返回值: 无
* 描  述: 擦除Sector
*************************************************************************************************/
void McuFlashEraseSector(U32 xdata McuFlashAddr, U8 xdata McuType)
{
    FLASHCON = McuType;
    XPAGE = McuFlashAddr>>8;
	
        IB_CON1	 = 0xE6;
	if(!EA)		//防止误写
	{
        IB_CON2	 = 0x05;
		if(FLASHCON == McuType)		//防止误写
		{
        IB_CON3	 = 0x0A;
			if(ucMcuFlashWrValid == 0x55)		//防止误写
			{
        IB_CON4	 = 0x09;
		if(XPAGE == (McuFlashAddr>>8))	//防止误写
		{
			IB_CON5	 = 0x06;
			_nop_();
			_nop_();
			_nop_();
			_nop_();
		}
    }
		}
}

    FLASHCON = MCU_TYPE_CODE;
}


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


/*************************************************************************************************
* 函数名: McuFlashWrOneByte
* 参  数: McuFlashAddr：起始地址；WrData：写入的注释
* 返回值: 无
* 描  述: 写1个字节
*************************************************************************************************/
void McuFlashWrOneByte(U32 xdata McuFlashAddr, U8 xdata WrData, U8 xdata McuType)
{
    FLASHCON = McuType;
    XPAGE = McuFlashAddr>>8;
    IB_OFFSET = McuFlashAddr % 256;
    
    IB_DATA	 = WrData;
        IB_CON1	 = 0x6E;
	if(!EA)		//防止误写
	{
        IB_CON2	 = 0x05;
		if(FLASHCON == McuType)		//防止误写
		{
        IB_CON3	 = 0x0A;
			if(ucMcuFlashWrValid == 0x55)		//防止误写
			{
        IB_CON4	 = 0x09;
		if(XPAGE == (McuFlashAddr>>8))	//防止误写
		{
			IB_CON5	 = 0x06;
			_nop_();
			_nop_();
			_nop_();
			_nop_();
					_nop_();
				}
			}
		}
    }
	
    FLASHCON = MCU_TYPE_CODE;
}


/*************************************************************************************************
* 函数名: McuFlashRdOneByte
* 参  数: McuFlashAddr：读取CODE区的地址
* 返回值: 返回当前Code字节
* 描  述: 读1个字节
*************************************************************************************************/
U8 McuFlashRdOneByte(U32 xdata McuFlashAddr, U8 xdata McuType)
{
    U8 GetData = 0;
    
    FLASHCON = McuType;
	GetData = CBYTE[McuFlashAddr];
    FLASHCON = MCU_TYPE_CODE;
    return GetData;
}				


/*************************************************************************************************
* 函数名: BootProgram
* 参  数: 无
* 返回值: 无
* 描  述: Boot区进行升级代码操作：Erase->Program->Verify
          每擦除1个Sector，即刻写入数据，校验数据
*************************************************************************************************/
U8 BootProgram(void)
{
    U8  i, McuCode, McuFlashType;
	U16 j;
	U32 McuFlashAddr;
	
	for(i=0; i<IAP_BK_CODE_SIZE/MCU_CODE_SECTOR_SIZE; i++)                      //擦除应用程序区，以Sector为单位
	{
        BootMcuWdtClear();
		if(i < IAP_CODE_SIZE/MCU_CODE_SECTOR_SIZE)                              //当前更新CODE区29K
		{
			McuFlashType = MCU_TYPE_CODE;                                       //IAP更新CODE区
			McuFlashAddr = IAP_CODE_START_ADDR + (U16)i*MCU_CODE_SECTOR_SIZE;   //从第5K开始
		}
		else
		{
			McuFlashType = MCU_TYPE_E2P;                                        //IAP更新EEPROM区
			McuFlashAddr = (U16)i*MCU_CODE_SECTOR_SIZE - IAP_CODE_SIZE;
		}
		ucMcuFlashWrValid = 0x55;
		McuFlashEraseSector(McuFlashAddr, McuFlashType);                        //以字节为单位
		if(McuFlashBlankCheck(McuFlashAddr, McuFlashType))                      //擦除结束后，需要查空
		{
			for(j=0; j<MCU_CODE_SECTOR_SIZE; j++)                               //将数据搬入APP对应地址
			{
				McuCode = McuFlashRdOneByte(IAP_BK_CODE_START_ADDR+j+(U16)i*MCU_CODE_SECTOR_SIZE, MCU_TYPE_CODE);	//yangweilei 此处固化为从flash取数据，从APP备份区读取CODE(1字节)
				McuFlashWrOneByte(McuFlashAddr+j, McuCode, McuFlashType);		//将CODE写入APP执行区
				if(McuCode != McuFlashRdOneByte(McuFlashAddr+j, McuFlashType))	//校验写入的代码
				{
					return (BOOT_PGR_WR_ERR);
				}
			}
		}
		else
		{
			return (BOOT_PGR_ERASE_ERR);
		}
	}
	
	return (BOOT_PGR_OK);
}


/*************************************************************************************************
* 函数名: BootUpgradeCode
* 参  数: 无
* 返回值: 无
* 描  述: Boot区进行升级代码操作：Erase->Program->Verify
*************************************************************************************************/
BOOL BootUpgradeCode(void)
{
	BOOL Result = 1;
		
	if(BootProgram() == BOOT_PGR_OK)
	{
		McuFlashEraseSector(BOOT_FLG_START_ADDR, MCU_TYPE_CODE);                //写入成功，擦除远程升级标志位
		Result = McuFlashBlankCheck(BOOT_FLG_START_ADDR, MCU_TYPE_CODE);        //擦除结束后，需要查空
	}
	else
	{
		Result = 0;
	}
    
	return Result;
}

