#include "flash.h"
#include "stm32f0xx_it.h"

//#include "gizwits_protocol.h"

volatile uint32_t flashWriteOffset = SYS_APP_BAK_SAVE_ADDR_BASE;
volatile uint32_t flashReadOffset = SYS_APP_BAK_SAVE_ADDR_BASE;

/* MCU OTA */
/*擦除指定的Flash页*/
void flash_erase_page(uint8_t flashPage , uint32_t addr_base)
{

		HAL_FLASH_Unlock();

    FLASH_EraseInitTypeDef f;
    f.TypeErase = FLASH_TYPEERASE_PAGES;
    f.PageAddress = addr_base+flashPage*FLASH_PAGE_SIZE;
    f.NbPages = 1;
	
    uint32_t PageError = 0;
    HAL_FLASHEx_Erase(&f, &PageError);
		HAL_FLASH_Lock();
}
void flash_erase(uint32_t size , uint32_t addr_base)
{
    uint32_t flashPageSum;
		uint32_t i;
    /*如果小于1024做处理*/
    if(size < FLASH_PAGE_SIZE)
        size = FLASH_PAGE_SIZE;												//
    /* 计算需要擦写的Flash页 */
    if((size % FLASH_PAGE_SIZE) == 0)
    {
        flashPageSum = size / FLASH_PAGE_SIZE;				//小于一页擦除一页
    }
    else
    {
        flashPageSum = (size / FLASH_PAGE_SIZE) + 1;	//大于一页擦除n+1页
    }
    for(i = 0;i<flashPageSum;i++)
    {
			flash_erase_page(i,addr_base);								//基址累加擦除flash
    }
}

void writeFlash(uint16_t * buf_to_save , uint16_t len , uint32_t wFlashAddr)
{
    uint16_t count=0;
    if(wFlashAddr >= 0x08020000)
    {
#ifdef DEBUG
        printf("Waring:Flash Write Addr Error\r\n");
#endif
        flashWriteOffset = SYS_APP_BAK_SAVE_ADDR_BASE;
        return;
    }
	HAL_FLASH_Unlock();

		while(count < len)
		{
				HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,(wFlashAddr + count*2),buf_to_save[count]);//写flash函数
				count ++;     
		}
		HAL_FLASH_Lock();
}

void readFlash(uint16_t * buf_to_get,uint16_t len , uint32_t readFlashAddr)
{
	uint16_t count=0;
	while(count<len)
	{
	 	buf_to_get[count]=*(uint16_t *)(readFlashAddr + count*2);
		count++;
	}
}
/*写Flash,控制写长度,Flash地址偏移*/
void wFlashData(uint8_t * buf_to_save , uint16_t len , uint32_t wFlashAddr)
{
    uint8_t WriteFlashTempBuf[PIECE_MAX_LEN];//写Flash临时缓冲区
    uint16_t WriteFlashTempLen = 0;//写Flash长度
    memset(WriteFlashTempBuf,0xEE,sizeof(WriteFlashTempBuf));//写Flash临时缓冲区首先全部填充0xEE
    memcpy(WriteFlashTempBuf,buf_to_save,len);//临时缓冲区
    WriteFlashTempLen = len;
    if(len%2 != 0)
        WriteFlashTempLen += 1;//因为Flash只能写半字
    writeFlash((uint16_t *)&WriteFlashTempBuf ,  WriteFlashTempLen/2 , wFlashAddr);
}
void rFlashData(uint8_t * buf_to_get , uint16_t len , uint32_t rFlashAddr)
{
    uint8_t ReadFlashTempBuf[PIECE_MAX_LEN];//读Flash临时缓冲区
    uint16_t ReadFlashTempLen = 0;//读Flash长度
    if(len%2 == 0)
    {
        ReadFlashTempLen = len;
        readFlash((uint16_t *)&ReadFlashTempBuf,ReadFlashTempLen/2 , rFlashAddr);
        memcpy(buf_to_get,ReadFlashTempBuf,len);
    }
    else
    {
        ReadFlashTempLen = len + 1;//因为Flash只能读半字
        readFlash((uint16_t *)&ReadFlashTempBuf,ReadFlashTempLen/2 , rFlashAddr);
        memcpy(buf_to_get,ReadFlashTempBuf,len);
    }
}
/****IAP*****/
typedef  void (*iapfun)(void);				//֨ӥһٶگ˽`эքӎ˽.
iapfun jump2app; 
u16 iapbuf[1024];   

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 

//设置栈顶指针
//__asm void MSR_MSP(u32 addr) 
//{
//    MSR MSP, r0 			//set Main Stack value
//    BX r14
//}
//void iap_load_app(u32 appxaddr)
//{
//	if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)	//ݬөջַ֥֘ˇرۏר.
//	{ 
//		printf("Stack Success!\r\n");
//		jump2app=(iapfun)*(vu32*)(appxaddr+4);		//ԃۧպëȸ֚׾ٶؖΪԌѲߪʼַ֘(شλַ֘)		
//		MSR_MSP(*(vu32*)appxaddr);					//ԵʼۯAPPבջָ֫(ԃۧպëȸք֚һٶؖԃԚզ؅ջַ֥֘)
//		jump2app();									//͸תսAPP.
//	}
//	else
//	{
//		printf("Stack Failed!\r\n");
//	}
//}


//                      代写入的值    地址
void FLASH_EEPROM_Write(uint32_t n,uint32_t add)
{
    HAL_FLASH_Unlock();     //解锁
    uint32_t PageError = 0;
	  FLASH_EraseInitTypeDef f;
    f.TypeErase = FLASH_TYPEERASE_PAGES;
//    f.PageAddress = addr_base+flashPage*FLASH_PAGE_SIZE;
    f.NbPages = 1;
    if (HAL_FLASHEx_Erase(&f,&PageError) == HAL_OK) //如果结构体中的起始地址0x0801FC00，这一页的数据擦除成功，返回OK
    {
        printf("擦除 成功\r\n");
			  __nop();
    }
    uint32_t writeFlashData = n;        //代写入的值
    uint32_t addr = add;                  //写入的地址
    HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,addr, writeFlashData); //向FLASH中写入
    printf("at address:0x%x, read value:%d\r\n", addr, *(__IO uint32_t*)addr);
    HAL_FLASH_Lock();
    while(1);
}


uint32_t FLASH_EEPROM_Read(uint32_t add)
{
	  int t;
    HAL_FLASH_Unlock();
    uint32_t Page = 0;
    uint32_t addr = add;                  //写入的地址
    t=*(__IO uint32_t*)addr;
	  return t;
//    return Page;
}

////读取指定地址的字(32位数据) 
////faddr:读地址 
////返回值:对应数据.
//u32 STMFLASH_ReadWord(u32 faddr)
//{
//	return *(vu32*)faddr; 
//}

////WriteAddr:起始地址
////WriteData:要写入的数据
//void Test_Write(u32 WriteAddr,u32 WriteData)   	
//{
//	STMFLASH_Write(WriteAddr,&WriteData,1);//写入一个字 
//}



////从指定地址开始写入指定长度的数据
////特别注意:因为STM32F4的扇区实在太大,没办法本地保存扇区数据,所以本函数
////         写地址如果非0XFF,那么会先擦除整个扇区且不保存扇区数据.所以
////         写非0XFF的地址,将导致整个扇区数据丢失.建议写之前确保扇区里
////         没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写. 
////该函数对OTP区域也有效!可以用来写OTP区!
////OTP区域地址范围:0X1FFF7800~0X1FFF7A0F(注意：最后16字节，用于OTP数据块锁定，别乱写！！)
////WriteAddr:起始地址(此地址必须为4的倍数!!)
////pBuffer:数据指针
////NumToWrite:字(32位)数(就是要写入的32位数据的个数.) 
//void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)	
//{ 
//	FLASH_EraseInitTypeDef FlashEraseInit;
//	HAL_StatusTypeDef FlashStatus=HAL_OK;
//	u32 SectorError=0;
//	u32 addrx=0;
//	u32 endaddr=0;	
//	if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;	//非法地址
//    
//	HAL_FLASH_Unlock();             //解锁	
//	addrx=WriteAddr;				//写入的起始地址
//	endaddr=WriteAddr+NumToWrite*4;	//写入的结束地址
//    
//	if(addrx<0X1FFF0000)
//	{
//		while(addrx<endaddr)		//扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
//		{
//			 if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
//			{   
////				FlashEraseInit.TypeErase=FLASH_TYPEERASE_SECTORS;       //擦除类型，扇区擦除 
//				FlashEraseInit.Sector=STMFLASH_GetFlashSector(addrx);   //要擦除的扇区
//				FlashEraseInit.NbSectors=1;                             //一次只擦除一个扇区
////				FlashEraseInit.VoltageRange=FLASH_VOLTAGE_RANGE_3;      //电压范围，VCC=2.7~3.6V之间!!
//				if(HAL_FLASHEx_Erase(&FlashEraseInit,&SectorError)!=HAL_OK) 
//				{
//					break;//发生错误了	
//				}
//				}else addrx+=4;
//				FLASH_WaitForLastOperation(FLASH_WAITETIME);                //等待上次操作完成
//		}
//	}
//	FlashStatus=FLASH_WaitForLastOperation(FLASH_WAITETIME);            //等待上次操作完成
//	if(FlashStatus==HAL_OK)
//	{
//		 while(WriteAddr<endaddr)//写数据
//		 {
//			if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,WriteAddr,*pBuffer)!=HAL_OK)//写入数据
//			{ 
//				break;	//写入异常
//			}
//			WriteAddr+=4;
//			pBuffer++;
//		}  
//	}
//	HAL_FLASH_Lock();           //上锁
//}










