/**
  ************************************* Copyright ****************************** 
  *
  *                 Copyright (C), 2012-2016, Radioway Tech. Co., Ltd.
  *                            All Rights Reserved
  *
  *    
  * FileName   : flash.c
  * Version    : v1.0
  * Author     : Heb
  * Date       : 2024-07-11
  * Description: 
  * Function List: 
  	1. ....
          <version>: 
     <modify staff>: 
             <data>: 
      <description>: 
  	2. ...
  ******************************************************************************
 */
#include <string.h>
#include "HAL_conf.h"
#include "board.h"
#include "flash.h"

void flash_init(void)
{
    uint32_t secpos = 0;	   //扇区地址
//    
    flash_read(FLASH_BACKUP_FLAG_ADDR ,(uint8_t *)&secpos, sizeof(secpos));
    
    if ((secpos >= FLASH_DATA_BASE_SECTOR) && (secpos < (FLASH_DATA_BASE_SECTOR+FLASH_DATA_SECTOR_SIZE)))
    {
        uint8_t  temp_buf[FLASH_SECTOR_SIZE] = {0};
        FLASH_Unlock();
        flash_read(FLASH_BACKUP_ADDR, temp_buf, FLASH_SECTOR_SIZE);
        
        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
        FLASH_ErasePage(secpos*FLASH_SECTOR_SIZE+FLASH_BASE_ADDR);
        flash_write_no_check(secpos*FLASH_SECTOR_SIZE+FLASH_BASE_ADDR, (uint32_t *)temp_buf, FLASH_SECTOR_SIZE/4 );
        
        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
        FLASH_ErasePage(FLASH_BACKUP_FLAG_ADDR);
        FLASH_Lock();
    }
    
}

void flash_erase(uint32_t address)
{
    uint32_t secpos  = 0;	   //扇区地址
    uint32_t offaddr = 0;      //去掉0X08000000后的地址
    
    BOARD_CRITICAL_BEGIN( );
    FLASH_Unlock();
    
    offaddr   = address-FLASH_BASE_ADDR;        //实际偏移地址.
    secpos    = offaddr/FLASH_SECTOR_SIZE;	    //扇区地址  0~64
    
	FLASH->SR = FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR;
	FLASH_ErasePage(secpos*FLASH_SECTOR_SIZE+FLASH_BASE_ADDR);	

	FLASH_Lock();
    BOARD_CRITICAL_END( );
}

void flash_write_no_check(uint32_t address, uint32_t *buffer, uint32_t size )
{	
    FLASH_Status state = FLASH_COMPLETE;
    
    for (uint32_t i=0;i<size;i++)
	{
        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
        state = FLASH_ProgramWord(address, buffer[i]);
        address+=4; //地址增加4.
	}

}



void flash_read(uint32_t address, uint8_t *buffer, uint32_t size)
{
    if ((buffer == NULL) || (size == 0))
    {
        return;
    }

    for (uint32_t i=0;i<size;i++) 
	{
		buffer[i] = *(uint8_t*) address;
		address ++;
	}

}


void flash_write(uint32_t address, uint8_t *buffer, uint32_t size )
{
    uint8_t  temp_buf[FLASH_SECTOR_SIZE] = {0};
    uint32_t i = 0;
    uint32_t secpos = 0;	   //扇区地址
	uint32_t secoff = 0;	   //扇区内偏移地址(16位字计算)
	uint32_t secremain = 0;    //扇区内剩余地址(16位字计算)	
    uint32_t offaddr = 0;      //后的地址

    if ((buffer == NULL) || (size == 0))
    {
        return;
    }
    
    BOARD_CRITICAL_BEGIN( );
    FLASH_Unlock();
    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
    
    offaddr   = address-FLASH_BASE_ADDR;        //实际偏移地址.
    secpos    = offaddr/FLASH_SECTOR_SIZE;	    //扇区地址
    secoff    = offaddr%FLASH_SECTOR_SIZE;	//在扇区内的偏移(1个字节为基本单位.)
    secremain = FLASH_SECTOR_SIZE-secoff;		//扇区剩余空间大小 
    
    if (size<=secremain)  //不大于该扇区范围
        secremain=size;
    
    while (1) 
    {
        flash_read(secpos*FLASH_SECTOR_SIZE+FLASH_BASE_ADDR ,temp_buf, FLASH_SECTOR_SIZE);
        
        for(i=0;i<secremain;i++)//复制
        {
            temp_buf[i+secoff]=buffer[i];
        }
        
        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
        FLASH_ErasePage(FLASH_BACKUP_ADDR);
        flash_write_no_check(FLASH_BACKUP_ADDR, (uint32_t *)temp_buf, FLASH_SECTOR_SIZE/4 );
        
        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
        FLASH_ErasePage(FLASH_BACKUP_FLAG_ADDR);
        flash_write_no_check(FLASH_BACKUP_FLAG_ADDR, (uint32_t *)&secpos, 1 );

        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
        FLASH_ErasePage(secpos*FLASH_SECTOR_SIZE+FLASH_BASE_ADDR);
        flash_write_no_check(secpos*FLASH_SECTOR_SIZE+FLASH_BASE_ADDR, (uint32_t *)temp_buf, FLASH_SECTOR_SIZE/4 );
        
        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
        FLASH_ErasePage(FLASH_BACKUP_FLAG_ADDR);
        
        if (size != secremain)
        {
            secpos ++;				//扇区地址增1
			secoff = 0;				//偏移位置为0 	 
		   	buffer += secremain;  	//指针偏移
			address += secremain;	//写地址偏移	   
		   	size -= secremain;	//字节(16位)数递减
            if (size>FLASH_SECTOR_SIZE)
            {
                secremain = FLASH_SECTOR_SIZE;//下一个扇区还是写不完
            }
			else 
            {
                secremain= size;//下一个扇区可以写完了
            }
        }
        else
        {
            break;//写入结束了
        }
    }
    
    FLASH_Lock();
    BOARD_CRITICAL_END( );
}



void flash_fill(uint32_t address, uint8_t data, uint32_t size )
{
    uint8_t  temp_buf[FLASH_SECTOR_SIZE] = {0};
    uint32_t i = 0;
    uint32_t secpos = 0;	   //扇区地址
	uint32_t secoff = 0;	   //扇区内偏移地址(16位字计算)
	uint32_t secremain = 0;    //扇区内剩余地址(16位字计算)	
    uint32_t offaddr = 0;      //后的地址

    if (size == 0)
    {
        return;
    }
    
    BOARD_CRITICAL_BEGIN( );
    FLASH_Unlock();
    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
    
    offaddr   = address-FLASH_BASE_ADDR;        //实际偏移地址.
    secpos    = offaddr/FLASH_SECTOR_SIZE;	    //扇区地址
    secoff    = offaddr%FLASH_SECTOR_SIZE;	//在扇区内的偏移(1个字节为基本单位.)
    secremain = FLASH_SECTOR_SIZE-secoff;		//扇区剩余空间大小 
    
    if (size<=secremain)  //不大于该扇区范围
        secremain=size;
    
    while (1) 
    {
        flash_read(secpos*FLASH_SECTOR_SIZE+FLASH_BASE_ADDR ,temp_buf, FLASH_SECTOR_SIZE);
        
        for(i=0;i<secremain;i++)//复制
        {
            temp_buf[i+secoff]=data;
        }
        
        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
        FLASH_ErasePage(FLASH_BACKUP_ADDR);
        flash_write_no_check(FLASH_BACKUP_ADDR, (uint32_t *)temp_buf, FLASH_SECTOR_SIZE/4 );
        
        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
        FLASH_ErasePage(FLASH_BACKUP_FLAG_ADDR);
        flash_write_no_check(FLASH_BACKUP_FLAG_ADDR, (uint32_t *)&secpos, 1 );

        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
        FLASH_ErasePage(secpos*FLASH_SECTOR_SIZE+FLASH_BASE_ADDR);
        flash_write_no_check(secpos*FLASH_SECTOR_SIZE+FLASH_BASE_ADDR, (uint32_t *)temp_buf, FLASH_SECTOR_SIZE/4 );
        
        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
        FLASH_ErasePage(FLASH_BACKUP_FLAG_ADDR);
        
        if (size != secremain)
        {
            secpos ++;				//扇区地址增1
			secoff = 0;				//偏移位置为0 	 
//		   	buffer += secremain;  	//指针偏移
			address += secremain;	//写地址偏移	   
		   	size -= secremain;	//字节(16位)数递减
            if (size>FLASH_SECTOR_SIZE)
            {
                secremain = FLASH_SECTOR_SIZE;//下一个扇区还是写不完
            }
			else 
            {
                secremain= size;//下一个扇区可以写完了
            }
        }
        else
        {
            break;//写入结束了
        }
    }
    
    FLASH_Lock();
    BOARD_CRITICAL_END( );
}






















