/*
 * H_Common_STM32F4_FLASH.c
 *
 *  Created on: 2024/11/18
 *      Author: egaono-electronics
 */

#include "H_Common_STM32F4_FLASH.h"



#define def_SizeDataFLASH  64


uint32_t GLB_uint32_ErrorCode = HAL_FLASH_ERROR_NONE;


uint32_t GLB_uint32_aDataFLASH[def_SizeDataFLASH];



//----------------------------------------------------------
// 指定Addressから属するsectorを割り出す。
//----------------------------------------------------------
// 引数;
// uint32_t uint32_Address : 指定Address


// 戻り値; 指定Addressが属するsector
//----------------------------------------------------------
uint32_t GetSector(uint32_t uint32_Address)
{
  uint32_t uint32_Sector = 0;


  if((uint32_Address < def_ADDR_FLASH_SECTOR_1)
      && (uint32_Address >= def_ADDR_FLASH_SECTOR_0))
  {
    uint32_Sector = FLASH_SECTOR_0;
  }
  else if((uint32_Address < def_ADDR_FLASH_SECTOR_2)
      && (uint32_Address >= def_ADDR_FLASH_SECTOR_1))
  {
    uint32_Sector = FLASH_SECTOR_1;
  }
  else if((uint32_Address < def_ADDR_FLASH_SECTOR_3)
      && (uint32_Address >= def_ADDR_FLASH_SECTOR_2))
  {
    uint32_Sector = FLASH_SECTOR_2;
  }
  else if((uint32_Address < def_ADDR_FLASH_SECTOR_4)
      && (uint32_Address >= def_ADDR_FLASH_SECTOR_3))
  {
    uint32_Sector = FLASH_SECTOR_3;
  }
  else if((uint32_Address < def_ADDR_FLASH_SECTOR_5)
      && (uint32_Address >= def_ADDR_FLASH_SECTOR_4))
  {
    uint32_Sector = FLASH_SECTOR_4;
  }
  else if((uint32_Address < def_ADDR_FLASH_SECTOR_6)
      && (uint32_Address >= def_ADDR_FLASH_SECTOR_5))
  {
    uint32_Sector = FLASH_SECTOR_5;
  }
  else if((uint32_Address < def_ADDR_FLASH_SECTOR_7)
      && (uint32_Address >= def_ADDR_FLASH_SECTOR_6))
  {
    uint32_Sector = FLASH_SECTOR_6;
  }
  else if((uint32_Address < def_ADDR_FLASH_SECTOR_8)
      && (uint32_Address >= def_ADDR_FLASH_SECTOR_7))
  {
    uint32_Sector = FLASH_SECTOR_7;
  }
#ifdef def_USE_FLASH_1M
  else if((uint32_Address < def_ADDR_FLASH_SECTOR_9)
      && (uint32_Address >= def_ADDR_FLASH_SECTOR_8))
  {
    uint32_Sector = FLASH_SECTOR_8;
  }
  else if((uint32_Address < def_ADDR_FLASH_SECTOR_10)
      && (uint32_Address >= def_ADDR_FLASH_SECTOR_9))
  {
    uint32_Sector = FLASH_SECTOR_9;
  }
  else if((uint32_Address < def_ADDR_FLASH_SECTOR_11)
      && (uint32_Address >= def_ADDR_FLASH_SECTOR_10))
  {
    uint32_Sector = FLASH_SECTOR_10;
  }
  else if((uint32_Address <= def_ADDR_FLASH_END)
      && (uint32_Address >= def_ADDR_FLASH_SECTOR_11))
  {
    uint32_Sector = FLASH_SECTOR_11;
  }
#endif  // def_USE_FLASH_1M
  else{
    // NG
#ifndef def_USE_FLASH_1M
      uint32_Sector = FLASH_SECTOR_7 + 1;
#else  // def_USE_FLASH_1M
      uint32_Sector = FLASH_SECTOR_11 + 1;
#endif  // def_USE_FLASH_1M
  }

  return(uint32_Sector);
}



//----------------------------------------------------------
// Erase FLASH
//----------------------------------------------------------
// 引数;
// uint32_t uint32_StartAddress : Erase開始Address
// uint32_t uint32_EndAddress : Erase終了Address


// 戻り値;
//    0 : OK
//    1 : NG
//----------------------------------------------------------
int16_t EraseFLASH(uint32_t uint32_StartAddress,
                   uint32_t uint32_EndAddress)
{
  FLASH_EraseInitTypeDef EraseInitStruct;

  uint32_t uint32_SectorError = 0;

  uint32_t uint32_StartSector = 0;
  uint32_t uint32_EndSector = 0;
  uint32_t uint32_Num_Sectors = 0;


  // Unlock the Flash to enable
  //                the flash control register access
  HAL_FLASH_Unlock();


  // Get the number of the start and end sectors
  uint32_StartSector = GetSector(uint32_StartAddress);
  uint32_EndSector = GetSector(uint32_EndAddress);
  uint32_Num_Sectors
            = uint32_EndSector - uint32_StartSector + 1;

  // Fill EraseInit structure
  EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
  EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
  EraseInitStruct.Sector = uint32_StartSector;
  EraseInitStruct.NbSectors = uint32_Num_Sectors;

  if(HAL_FLASHEx_Erase(&EraseInitStruct, &uint32_SectorError)
                                                    != HAL_OK)
  {
    // Retry
    if(HAL_FLASHEx_Erase(&EraseInitStruct, &uint32_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()'
      */
    GLB_uint32_ErrorCode = HAL_FLASH_GetError();

    return(1);  // NG
    }
  }


  __HAL_FLASH_DATA_CACHE_DISABLE();
  __HAL_FLASH_INSTRUCTION_CACHE_DISABLE();

  __HAL_FLASH_DATA_CACHE_RESET();
  __HAL_FLASH_INSTRUCTION_CACHE_RESET();

  __HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
  __HAL_FLASH_DATA_CACHE_ENABLE();


  // Locks the FLASH control register access
  HAL_FLASH_Lock();

  return(0);  // OK
}



//----------------------------------------------------------
// Write Data to Flash Memory
//----------------------------------------------------------
// 引数;
// uint32_t uint32_StartAddress(4の倍数) :
//                                  書き込み開始Address
// uint32_t uint32_Length : 書き込みデータ数
// uint32_t *puint32_aData(4byte単位) :
//              書き込みデータが格納されたBufferのポインタ


// 戻り値;
//    0 : OK
//    1 : NG
//----------------------------------------------------------
int16_t WriteFLASH(uint32_t uint32_StartAddress,
                   uint32_t uint32_Length,
                   uint32_t *puint32_aData)
{
  HAL_StatusTypeDef hal_Status;

  uint32_t uint32_Address = 0;
  uint32_t uint32_I;


  // Unlocks the FLASH control register access
  HAL_FLASH_Unlock();


  // Program Flash
  uint32_Address = uint32_StartAddress;

  //------------------------------------------------------------
  // Program the user Flash area word by word
  // (area defined by FLASH_USER_START_ADDR
  //                                and FLASH_USER_END_ADDR)
  //------------------------------------------------------------
  for(uint32_I = 0; uint32_I < uint32_Length; uint32_I++){
    hal_Status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
              uint32_Address, puint32_aData[uint32_I]);
    if(hal_Status != HAL_OK){
      // Retry
      hal_Status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
                uint32_Address, puint32_aData[uint32_I]);
      if(hal_Status != HAL_OK){
        GLB_uint32_ErrorCode = HAL_FLASH_GetError();
        return(1);  // NG
      }
    }

    uint32_Address += 4;
  }
  //------------------------------------------------------------

  // Locks the FLASH control register access
  HAL_FLASH_Lock();


  // Check the correctness of written data
  uint32_Address = uint32_StartAddress;

  //------------------------------------------------------------
  for(uint32_I = 0; uint32_I < uint32_Length; uint32_I++){
    if((*(volatile uint32_t *)uint32_Address)
                                != puint32_aData[uint32_I])
    {
      return(1);  // NG
    }
    uint32_Address += 4;
  }
  //------------------------------------------------------------

  return(0);  // OK
}



//----------------------------------------------------------
// Set Data and Write Flash Memory
//----------------------------------------------------------
// 引数;
// uint32_t uint32_StartAddress : 書き込み開始アドレス
// int16_t int16_Length : 書き込みbyte数
// uint8_t *puint8_aData :
//              書き込みデータが格納されたBufferのポインタ


// 戻り値;
//    0 : OK
//    1以上 : NG
//----------------------------------------------------------
int16_t SetDataAndWriteFLASH(uint32_t uint32_StartAddress,
                             int16_t int16_Length,
                             uint8_t *puint8_aData)
{
  int16_t int16_I;
  int16_t int16_Number;

  int16_t int16_SizeMAX;  // 書き込み最大byte数
  int16_t int16_WriteSize;

  int16_t int16_ReadPoint = 0;
  int16_t int16_Result = 0;


  // Flash Memoryには uint32_t(4byte)単位で書き込む。
  // def_SizeDataFLASH は
  //    書き込み用ワーク GLB_uint32_aDataFLASH の配列のサイズ
  int16_SizeMAX = (int16_t)def_SizeDataFLASH * 4;

  do{
    if(int16_Length > int16_SizeMAX){
      int16_WriteSize = int16_SizeMAX;
    }
    else{
      int16_WriteSize = int16_Length;
    }

    for(int16_I = 0;
            int16_I < (int16_t)def_SizeDataFLASH; int16_I++){
      GLB_uint32_aDataFLASH[int16_I] = 0;
    }

    int16_Number = 0;

    for(int16_I = 0; int16_I < int16_WriteSize; int16_I++){
      if((int16_I & 0x0003) == 0){
        GLB_uint32_aDataFLASH[int16_Number]
            = (uint32_t)puint8_aData[int16_ReadPoint + int16_I];
      }
      else if((int16_I & 0x0003) == 1){
        GLB_uint32_aDataFLASH[int16_Number]
        |= ((uint32_t)puint8_aData[int16_ReadPoint + int16_I])
                                                        << 8;
      }
      else if((int16_I & 0x0003) == 2){
        GLB_uint32_aDataFLASH[int16_Number]
        |= ((uint32_t)puint8_aData[int16_ReadPoint + int16_I])
                                                        << 16;
      }
      else{
        GLB_uint32_aDataFLASH[int16_Number]
        |= ((uint32_t)puint8_aData[int16_ReadPoint + int16_I])
                                                        << 24;
        int16_Number++;
      }
    }

    if(int16_WriteSize % 4 != 0){
      int16_Number++;
    }


    // Write Data to FLASH
    int16_Result = WriteFLASH(uint32_StartAddress,
                              (uint32_t)int16_Number,
                              GLB_uint32_aDataFLASH);
    if(int16_Result != 0){
      // Retry
      int16_Result = WriteFLASH(uint32_StartAddress,
                                (uint32_t)int16_Number,
                                GLB_uint32_aDataFLASH);
      if(int16_Result != 0){
        return(1);  // NG
      }
    }

    int16_Length -= int16_SizeMAX;
    uint32_StartAddress += (uint32_t)int16_SizeMAX;
    int16_ReadPoint += int16_SizeMAX;
  }while(int16_Length > 0);

  return(0);  // OK
  //--------------------------------------------------------
}
