/**
 * @file Drv_IAP.c
 * @author 吳星萍(iris@e-besthealth.com)
 * @brief  IAP調用接口
 * @version 0.1
 * @date 2020-06-18
 *
 * @copyright BEST HEALTH ELECTRONIC INC (c) 2019
 *
 * Compiler Ver. : V3.57
 * IDE3000  Ver. : V8.03
 * MCU/CFG  Ver. : BH67F5362/1.1
 */
#include "common.h"

const unsigned int __attribute__((at(IAPWRSTARTADDRESS))) DebufInfo[IAPWRLENGHT]=
{
	0x5500,0x5501,0x5502,0x5503,0x5504,0x5505,0x5506,0x5507,0x5508,0x5509,0x550A,0x550B,0x550C,0x550D,0x550E,0x550F,
	0x5510,0x5511,0x5512,0x5513,0x5514,0x5515,0x5516,0x5517,0x5518,0x5519,0x551A,0x551B,0x551C,0x551D,0x551E,0x551F,
	0xAA00,0xAA01,0xAA02,0xAA03,0xAA04,0xAA05,0xAA06,0xAA07,0xAA08,0xAA09,0xAA0A,0xAA0B,0xAA0C,0xAA0D,0xAA0E,0xAA0F,
	0xAA10,0xAA11,0xAA12,0xAA13,0xAA14,0xAA15,0xAA16,0xAA17,0xAA18,0xAA19,0xAA1A,0xAA1B,0xAA1C,0xAA1D,0xAA1E,0xAA1F,
};

/********************************************************************
Function: Flash存儲器寫使能
INPUT	: None
OUTPUT	: IAPEnableIsOk,1 Enable Ok,0 Enable Fail
NOTE	:
********************************************************************/
unsigned char Drv_Enable_FWEN(void)
{
	unsigned char EMIStatus,IAPEnableIsOk;
	IAPEnableIsOk = 1;
	EMIStatus = _emi;
	_emi = 0;
	GCC_CLRWDT();
	_fc0 = ENABLE_FWEN_MODE; // 寫功能使能模式,start a 300us counter
	_fd1l = 0x00;			 // 按順序將固定模式數據序列寫入對應的暫存器
	_fd1h = 0x04;
	_fd2l = 0x0D;
	_fd2h = 0x09;
	_fd3l = 0xC3;
	_fd3h = 0x40;
	_emi = EMIStatus;
	while(_fwpen);			// 寫使能成功后此位硬件自動清零
	if(!_cfwen)	
	{
		IAPEnableIsOk = 0x00;	// 讀CFWEN 確認狀態
	}
	return IAPEnableIsOk;
}
/********************************************************************
Function: 擦除Flash存儲器目標地址頁
INPUT	: Flash_Addr
OUTPUT	: ErasePageIsOk,1 ErasePage Ok, 0 ErasePage Fail
NOTE	:
*********************************************************************/
unsigned char Drv_Erase_Page(unsigned int EPage_Addr,unsigned char EPage_Length)
{
	unsigned char ErasePageIsOk,i;
	unsigned int  Check_Buff;
	ErasePageIsOk = 1;
	_emi = 0;
	GCC_CLRWDT();
	if(!Drv_Enable_FWEN())
	{
		ErasePageIsOk = 0x00;
	}
	
	_fc0 = PAGE_ERASE_MODE;			// 頁擦除模式
	_clwb = 1;		
	_farl = (unsigned char)(EPage_Addr&0xff);
	_farh = (unsigned char)(EPage_Addr>>8);	
	
	for(i=0;i<EPage_Length;i++)
	{
		_fd0h=0x00;				//標記地址
	}
	_fwt=1;						// 激活一個寫週期
	while(_fwt)					// 等待 Flash ROM 擦除完成
	{
		GCC_CLRWDT();
	}						
	for(i=0;i<EPage_Length;i++)
	{
		Check_Buff=Drv_ReadFlashRom(EPage_Addr);
		EPage_Addr++;
		if(Check_Buff!=0x00)		//確認是否擦除成功
		{
			ErasePageIsOk=0;
		}	
	}
	_cfwen = 0;					// Flash ROM 写除能
	_emi=1;					
	return ErasePageIsOk;
}
/********************************************************************
Function: 寫目標地址FLASH ROM 數據
INPUT	: FlashAddr,FlashLength
OUTPUT	: WriteFlashIsOk,1 WriteFlash Ok, 0 WriteFlash Fail
NOTE	:
*********************************************************************/
unsigned char Drv_WriteFlashRom(unsigned int FlashAddr,unsigned char FlashLength)
{
	if(!Drv_Erase_Page(IAPWRSTARTADDRESS,FlashLength))
	{
		Drv_Erase_Page(IAPWRSTARTADDRESS,FlashLength); // 未擦除成功,處理
	}
	unsigned char WriteFlashIsOk;
	unsigned int  Check_Buff;
	WriteFlashIsOk = 1;
	GCC_CLRWDT();
	if(!Drv_Enable_FWEN())
	{
		WriteFlashIsOk = 0x00;
	}
	_clwb = 1;					// write Initiate clear write buffer process
	while(_clwb);

	_fc0 = WRITE_FLASH_MODE;	//寫入模式

	_farl = (unsigned char)(FlashAddr&0xff);
	_farh = (unsigned char)(FlashAddr>>8) ;
	unsigned char i;
	for ( i = 0; i < FlashLength; i++)
	{
		_fd0l = (unsigned char)(Flash_WR_Buff[i] & 0xff);
		_fd0h = (unsigned char)((Flash_WR_Buff[i] >> 8)&0xff);
	}
	_fwt = 1;					// 啟動寫入
	while(_fwt);
	
	for(i=0;i<FlashLength;i++)
	{
		Check_Buff=Drv_ReadFlashRom(FlashAddr+i);
		if(Check_Buff!=Flash_WR_Buff[i])		//確認是否寫入成功
		{
			WriteFlashIsOk=0;
		}	
	}
	_cfwen = 0;					// 結束寫入，關閉寫使能
	return WriteFlashIsOk;
}
/********************************************************************
Function: 讀取目標地址FLASH ROM 數據
INPUT	: None
OUTPUT	: None
NOTE	:
*********************************************************************/
unsigned int Drv_ReadFlashRom(unsigned int RPage_Addr)
{
	
	volatile unsigned int   Read_Data=0xff;
	_emi = 0;
	GCC_CLRWDT();
	_fc0 = READ_FLASH_MODE;	
	_farl = (unsigned char)(RPage_Addr&0xff);
	_farh = (unsigned char)(RPage_Addr>>8);
	_frd=1;					// 啟動讀入
	while(_frd);
	Read_Data = (unsigned int)((Read_Data&_fd0h)<<8);
	Read_Data = (unsigned int)(Read_Data|_fd0l);
	_frden=0;
	_emi=1;
	return Read_Data;
}
