#include "main.h"
#include "internal_flash.h"

T_Factory_Prm factory_prm;

static FLASH_EraseInitTypeDef EraseInitStruct;

unsigned int FirstSector = 0, BankNum = FLASH_BANK_1, NbOfSectors = 0;
unsigned int Address = 0, SECTORError = 0, Index = 0;
__IO unsigned int MemoryProgramStatus = 0;
__IO uint64_t data64 = 0;

/**
  * @brief  Gets the sector of a given address
  * @param  Address Address of the FLASH Memory
  * @retval The sector of a given address
  */
unsigned int GetSector(unsigned int Address)
{
  unsigned int sector = 0;
  
  if(((Address < ADDR_FLASH_SECTOR_1_BANK1) && (Address >= ADDR_FLASH_SECTOR_0_BANK1)) || \
     ((Address < ADDR_FLASH_SECTOR_1_BANK2) && (Address >= ADDR_FLASH_SECTOR_0_BANK2)))    
  {
    sector = FLASH_SECTOR_0;  
  }
  else if(((Address < ADDR_FLASH_SECTOR_2_BANK1) && (Address >= ADDR_FLASH_SECTOR_1_BANK1)) || \
          ((Address < ADDR_FLASH_SECTOR_2_BANK2) && (Address >= ADDR_FLASH_SECTOR_1_BANK2)))    
  {
    sector = FLASH_SECTOR_1;  
  }
  else if(((Address < ADDR_FLASH_SECTOR_3_BANK1) && (Address >= ADDR_FLASH_SECTOR_2_BANK1)) || \
          ((Address < ADDR_FLASH_SECTOR_3_BANK2) && (Address >= ADDR_FLASH_SECTOR_2_BANK2)))    
  {
    sector = FLASH_SECTOR_2;  
  }
  else if(((Address < ADDR_FLASH_SECTOR_4_BANK1) && (Address >= ADDR_FLASH_SECTOR_3_BANK1)) || \
          ((Address < ADDR_FLASH_SECTOR_4_BANK2) && (Address >= ADDR_FLASH_SECTOR_3_BANK2)))    
  {
    sector = FLASH_SECTOR_3;  
  }
  else if(((Address < ADDR_FLASH_SECTOR_5_BANK1) && (Address >= ADDR_FLASH_SECTOR_4_BANK1)) || \
          ((Address < ADDR_FLASH_SECTOR_5_BANK2) && (Address >= ADDR_FLASH_SECTOR_4_BANK2)))    
  {
    sector = FLASH_SECTOR_4;  
  }
  else if(((Address < ADDR_FLASH_SECTOR_6_BANK1) && (Address >= ADDR_FLASH_SECTOR_5_BANK1)) || \
          ((Address < ADDR_FLASH_SECTOR_6_BANK2) && (Address >= ADDR_FLASH_SECTOR_5_BANK2)))    
  {
    sector = FLASH_SECTOR_5;  
  }
  else if(((Address < ADDR_FLASH_SECTOR_7_BANK1) && (Address >= ADDR_FLASH_SECTOR_6_BANK1)) || \
          ((Address < ADDR_FLASH_SECTOR_7_BANK2) && (Address >= ADDR_FLASH_SECTOR_6_BANK2)))    
  {
    sector = FLASH_SECTOR_6;  
  }
  else if(((Address < ADDR_FLASH_SECTOR_0_BANK2) && (Address >= ADDR_FLASH_SECTOR_7_BANK1)) || \
          ((Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_7_BANK2)))
  {
     sector = FLASH_SECTOR_7;  
  }
  else
  {
    sector = FLASH_SECTOR_7;
  }

  return sector;
}

unsigned int GetBank(unsigned int Address)
{
  unsigned int bank = 0;
  
  if(IS_FLASH_PROGRAM_ADDRESS_BANK1(Address))
  {
    bank = FLASH_BANK_1;
  }
  else
  {
    bank = FLASH_BANK_2;    
  }

  return bank;
}

void erase_internal_one_sector(unsigned int Address)
{
	HAL_FLASH_Unlock();

  /* -3- Erase the user Flash area
    (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/

  /* Get the 1st sector to erase */
  FirstSector = GetSector(Address);
  /* Get the number of sector to erase from 1st sector*/
  NbOfSectors = 1;

	BankNum = GetBank(Address);
	
  /* Fill EraseInit structure*/
  EraseInitStruct.TypeErase     = FLASH_TYPEERASE_SECTORS;
  EraseInitStruct.VoltageRange  = FLASH_VOLTAGE_RANGE_3;
  EraseInitStruct.Banks         = BankNum;
  EraseInitStruct.Sector        = FirstSector;
  EraseInitStruct.NbSectors     = NbOfSectors;
  
  if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK)
  {
    /*
      Error occurred while sector erase.
      User can add here some code to deal with this error.
      SECTORError will contain the faulty sector and then to know the code error on this sector,
      user can call function 'HAL_FLASH_GetError()'
    */
    /* Infinite loop */
    while (1)
    {
      __nop();
    }
  }
	HAL_FLASH_Lock();
}

void write_internal_flash(unsigned int Address,	unsigned int val_addr)//Address 32uint, write 32byte
{
	uint64_t val_check;
	
	//HAL_FLASH_Unlock();
	
	if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, Address, (uint64_t)val_addr) == HAL_OK)
	{
		__nop();
	}
	else
	{
		/* Error occurred while writing data in Flash memory.
			 User can add here some code to deal with this error */
		while (1)
		{
			__nop();
		}
	}
	//HAL_FLASH_Lock();
}

void read_internal_flash(unsigned int start_address,	unsigned int * val_addr, unsigned int num)//num 8byte multiple
{
	unsigned int i = 0;
	unsigned int * p_val_addr;
	p_val_addr = val_addr;
	
	for(i=0;i<num;i++)
  {
		*(uint64_t*)p_val_addr = *(uint64_t*)start_address;
		__DSB();
		p_val_addr +=8;
		start_address +=8;
  }
}

void reset_factory_prm(void)
{
	unsigned int load_falsh_addr;
	load_falsh_addr = FLASH_USER_FACTORY_PRM;
	
	erase_internal_one_sector(load_falsh_addr);
	
	factory_prm.open_password_isenable = 1;
	factory_prm.auth_function_isenable = 0;
	
	write_factory_prm();
}

void write_factory_prm(void)
{
	unsigned int load_falsh_addr;
	load_falsh_addr = FLASH_USER_FACTORY_PRM;
	
	erase_internal_one_sector(load_falsh_addr);
	HAL_FLASH_Unlock();
	write_internal_flash(load_falsh_addr, &factory_prm);
	HAL_FLASH_Lock();
}

void read_factory_prm(void)
{
	unsigned int falsh_addr;
	unsigned int pid_temp;
	
	falsh_addr = FLASH_USER_FACTORY_PRM;
	
	factory_prm.open_password_isenable = *(__IO uint32_t *)falsh_addr;
	factory_prm.rsv1 = *(__IO uint32_t *)(falsh_addr+4);
	factory_prm.auth_function_isenable = *(__IO uint32_t *)(falsh_addr+8);
	
	if(((0 == (*(__IO uint32_t *)(falsh_addr + 12)))&&(0 == (*(__IO uint32_t *)(falsh_addr + 16)))) ||\
		((0xFFFFFFFF == (*(__IO uint32_t *)(falsh_addr + 12)))&&(0xFFFFFFFF == (*(__IO uint32_t *)(falsh_addr + 16))))){
		factory_prm.pid[0] = 1;
		factory_prm.pid[1] = 2;
		factory_prm.pid[2] = 3;
		factory_prm.pid[3] = 4;
		factory_prm.pid[4] = 5;
		factory_prm.pid[5] = 6;
		factory_prm.pid[6] = 7;
		factory_prm.pid[7] = 8;
	}else{
		pid_temp = *(__IO uint32_t *)(falsh_addr + 12);
		factory_prm.pid[0] = pid_temp & 0xFF;
		factory_prm.pid[1] = (pid_temp>>8) & 0xFF;
		factory_prm.pid[2] = (pid_temp>>16) & 0xFF;
		factory_prm.pid[3] = (pid_temp>>24) & 0xFF;
		
		pid_temp = *(__IO uint32_t *)(falsh_addr + 16);
		factory_prm.pid[4] = pid_temp & 0xFF;
		factory_prm.pid[5] = (pid_temp>>8) & 0xFF;
		factory_prm.pid[6] = (pid_temp>>16) & 0xFF;
		factory_prm.pid[7] = (pid_temp>>24) & 0xFF;
		
		pid_temp = *(__IO uint32_t *)(falsh_addr + 20);
		factory_prm.pid[8] = pid_temp & 0xFF;
		factory_prm.pid[9] = (pid_temp>>8) & 0xFF;
		factory_prm.pid[10] = (pid_temp>>16) & 0xFF;
		factory_prm.pid[11] = (pid_temp>>24) & 0xFF;
	}
	
	factory_prm.ctl_type = (*(__IO uint32_t *)(falsh_addr + 24))&0xFF;
	if((0 == factory_prm.ctl_type)||(0xFF == factory_prm.ctl_type))factory_prm.ctl_type = 1;
	
	if(factory_prm.open_password_isenable > 1)factory_prm.open_password_isenable = 1;
	if(factory_prm.auth_function_isenable > 1)factory_prm.auth_function_isenable = 0;
	factory_prm.open_password_isenable = 0;
}
