/*
 * ****************************************************
 * @file    : flash.c
 * @brief   : Flash Program Body
 * @author  : HSW / WESPION
 * @data    : 2025. 05. 06
 * ****************************************************
 */

#include "flash.h"


EEPROM Data_Form Origin_Data={
    {HW_MODEL,HW_VER},              //uint8_t model[2];
    VER_MAJER,
    VER_MINER,

    VER_YEAR,
    VER_MONTH,
    VER_DATE,

    MOTOR_PARA_POLE,                //uint8_t
    VER_SUB,                        //uint8_t   ///somebp 2024.02.07
    MOTOR_ANG_ENCPULSE,             //uint16_t

    MOTOR_PARA_Ld,
    MOTOR_PARA_Lq,
    MOTOR_PARA_Rs,
    MOTOR_PARA_PhaiF,

    MOTOR_GAINCURD_Kp,
    MOTOR_GAINCURD_Ki,
    MOTOR_GAINCURD_Kaw,
    MOTOR_GAINCURQ_Kp,
    MOTOR_GAINCURQ_Ki,
    MOTOR_GAINCURQ_Kaw,

    MOTOR_GAINSPD_Kp,
    MOTOR_GAINSPD_Ki,
    MOTOR_GAINSPD_Kaw,

    MOTOR_GAINFWEAK_Kp,
    MOTOR_GAINFWEAK_Ki,

    MOTOR_ANG_ANGLESCALE,
    MOTOR_ANG_SPEEDSCALE,
    MOTOR1_ANG_ANGLEELCOFFSET,
    MOTOR2_ANG_ANGLEELCOFFSET,

    MOTOR_ANG_MR_MAX_SIN,           //uint16_t
    MOTOR_ANG_MR_MAX_COS,           //uint16_t
    MOTOR_ANG_MR_MIN_SIN,           //uint16_t
    MOTOR_ANG_MR_MIN_COS,           //uint16_t
    MOTOR_ANG_MR_MID_SIN,           //uint16_t
    MOTOR_ANG_MR_MID_COS,           //uint16_t
    MOTOR_ANG_MR_GAIN_SIN,
    MOTOR_ANG_MR_GAIN_COS,

    INV_PARA_HWADCSCALE,
    INV_PARA_HWVDCSCALE,
    INV_PARA_HWISCALE,

    INV_PARA_TSAMP,

    INV_PARA_PWM_MAX,
    INV_PARA_PWM_MID,
    INV_PARA_VDCMARGIN,

    LPFVDC_FC,
    LPFVDC_FS,

    LPFCUR_FC,
    LPFCUR_FS,

    LPFSPD_FC,
    LPFSPD_FS,

    ERRREF_ISENSOROPEN,
    ERRREF_ISENSORSHORT,
    ERRREF_OVERCURRENT,
    ERRREF_OVERSPEED,
    ERRREF_OVERVOLTAGE,
    ERRREF_UNDERVOLTAGE,
    ERRREF_ISENSOROFFSETMAX,
    ERRREF_ISENSOROFFSETMIN,

    INV_CTRL_VDCLIMFWEAK,
    INV_CTRL_ILIMFWEAK,

    MOTOR_ANG_RPMLIM,
    MOTOR_ANG_SPDCTRLOUTLIM,

    MACHINE_SENSOR_GEAR_RATIO,
    MACHINE_SPOOL_DIAMETER,
    MACHINE_MAX_WEIGHT,
    MACHINE_CABLE_MAX_LENGTH,
    MACHINE_SCALE_WEIGHT2CURRENT,
    MACHINE_SOFT_WINDING_HEIGHT,

    MACHINE_DEFAULT_WEIGHT,
    MACHINE_FRICTION_WEIGHT,
    MACHINE_FRICTION_SPEED_PLUS,
    MACHINE_FRICTION_SPEED_MINUS,

    DFU_Status,     // Flash 초기상태를 의도한 값이므로 따로 지정하진 않음.

    FLASH_VALID_CODE,//uint32_t check
};

BACKUP Data_Form Backup_Data={
    {HW_MODEL,HW_VER},              //uint8_t model[2];
    VER_MAJER,
    VER_MINER,

    VER_YEAR,
    VER_MONTH,
    VER_DATE,

    MOTOR_PARA_POLE,                //uint8_t
    VER_SUB,                        //uint8_t   ///somebp 2024.02.07
    MOTOR_ANG_ENCPULSE,             //uint16_t

    MOTOR_PARA_Ld,
    MOTOR_PARA_Lq,
    MOTOR_PARA_Rs,
    MOTOR_PARA_PhaiF,

    MOTOR_GAINCURD_Kp,
    MOTOR_GAINCURD_Ki,
    MOTOR_GAINCURD_Kaw,
    MOTOR_GAINCURQ_Kp,
    MOTOR_GAINCURQ_Ki,
    MOTOR_GAINCURQ_Kaw,

    MOTOR_GAINSPD_Kp,
    MOTOR_GAINSPD_Ki,
    MOTOR_GAINSPD_Kaw,

    MOTOR_GAINFWEAK_Kp,
    MOTOR_GAINFWEAK_Ki,

    MOTOR_ANG_ANGLESCALE,
    MOTOR_ANG_SPEEDSCALE,
    MOTOR1_ANG_ANGLEELCOFFSET,
    MOTOR2_ANG_ANGLEELCOFFSET,

    MOTOR_ANG_MR_MAX_SIN,           //uint16_t
    MOTOR_ANG_MR_MAX_COS,           //uint16_t
    MOTOR_ANG_MR_MIN_SIN,           //uint16_t
    MOTOR_ANG_MR_MIN_COS,           //uint16_t
    MOTOR_ANG_MR_MID_SIN,           //uint16_t
    MOTOR_ANG_MR_MID_COS,           //uint16_t
    MOTOR_ANG_MR_GAIN_SIN,
    MOTOR_ANG_MR_GAIN_COS,

    INV_PARA_HWADCSCALE,
    INV_PARA_HWVDCSCALE,
    INV_PARA_HWISCALE,

    INV_PARA_TSAMP,

    INV_PARA_PWM_MAX,
    INV_PARA_PWM_MID,
    INV_PARA_VDCMARGIN,

    LPFVDC_FC,
    LPFVDC_FS,

    LPFCUR_FC,
    LPFCUR_FS,

    LPFSPD_FC,
    LPFSPD_FS,

    ERRREF_ISENSOROPEN,
    ERRREF_ISENSORSHORT,
    ERRREF_OVERCURRENT,
    ERRREF_OVERSPEED,
    ERRREF_OVERVOLTAGE,
    ERRREF_UNDERVOLTAGE,
    ERRREF_ISENSOROFFSETMAX,
    ERRREF_ISENSOROFFSETMIN,

    INV_CTRL_VDCLIMFWEAK,
    INV_CTRL_ILIMFWEAK,

    MOTOR_ANG_RPMLIM,
    MOTOR_ANG_SPDCTRLOUTLIM,

    MACHINE_SENSOR_GEAR_RATIO,
    MACHINE_SPOOL_DIAMETER,
    MACHINE_MAX_WEIGHT,
    MACHINE_CABLE_MAX_LENGTH,
    MACHINE_SCALE_WEIGHT2CURRENT,
    MACHINE_SOFT_WINDING_HEIGHT,

    MACHINE_DEFAULT_WEIGHT,
    MACHINE_FRICTION_WEIGHT,
    MACHINE_FRICTION_SPEED_PLUS,
    MACHINE_FRICTION_SPEED_MINUS,

    DFU_Status,     // Flash 초기상태를 의도한 값이므로 따로 지정하진 않음.

    FLASH_VALID_CODE,//uint32_t check
};

//__attribute__((section(".FlashData")))      //  (25.05.03) RDP 적용을 위해 FlashData를 bin으로 추출하기 위함
const Data_Form_RAM Defualt_RAM_Data={
    {HW_MODEL,HW_VER},              //uint8_t model[2];
    VER_MAJER,
    VER_MINER,

    VER_YEAR,
    VER_MONTH,
    VER_DATE,

    MOTOR_PARA_POLE,                //uint8_t
    VER_SUB,                        //uint8_t   ///somebp 2024.02.07
    MOTOR_ANG_ENCPULSE,             //uint16_t

    MOTOR_PARA_Ld,
    MOTOR_PARA_Lq,
    MOTOR_PARA_Rs,
    MOTOR_PARA_PhaiF,

    MOTOR_GAINCURD_Kp,
    MOTOR_GAINCURD_Ki,
    MOTOR_GAINCURD_Kaw,
    MOTOR_GAINCURQ_Kp,
    MOTOR_GAINCURQ_Ki,
    MOTOR_GAINCURQ_Kaw,

    MOTOR_GAINSPD_Kp,
    MOTOR_GAINSPD_Ki,
    MOTOR_GAINSPD_Kaw,

    MOTOR_GAINFWEAK_Kp,
    MOTOR_GAINFWEAK_Ki,

    MOTOR_ANG_ANGLESCALE,
    MOTOR_ANG_SPEEDSCALE,
    MOTOR1_ANG_ANGLEELCOFFSET,
    MOTOR2_ANG_ANGLEELCOFFSET,

    MOTOR_ANG_MR_MAX_SIN,           //uint16_t
    MOTOR_ANG_MR_MAX_COS,           //uint16_t
    MOTOR_ANG_MR_MIN_SIN,           //uint16_t
    MOTOR_ANG_MR_MIN_COS,           //uint16_t
    MOTOR_ANG_MR_MID_SIN,           //uint16_t
    MOTOR_ANG_MR_MID_COS,           //uint16_t
    MOTOR_ANG_MR_GAIN_SIN,
    MOTOR_ANG_MR_GAIN_COS,

    INV_PARA_HWADCSCALE,
    INV_PARA_HWVDCSCALE,
    INV_PARA_HWISCALE,

    INV_PARA_TSAMP,

    INV_PARA_PWM_MAX,
    INV_PARA_PWM_MID,
    INV_PARA_VDCMARGIN,

    LPFVDC_FC,
    LPFVDC_FS,

    LPFCUR_FC,
    LPFCUR_FS,

    LPFSPD_FC,
    LPFSPD_FS,

    ERRREF_ISENSOROPEN,
    ERRREF_ISENSORSHORT,
    ERRREF_OVERCURRENT,
    ERRREF_OVERSPEED,
    ERRREF_OVERVOLTAGE,
    ERRREF_UNDERVOLTAGE,
    ERRREF_ISENSOROFFSETMAX,
    ERRREF_ISENSOROFFSETMIN,

    INV_CTRL_VDCLIMFWEAK,
    INV_CTRL_ILIMFWEAK,

    MOTOR_ANG_RPMLIM,
    MOTOR_ANG_SPDCTRLOUTLIM,

    MACHINE_SENSOR_GEAR_RATIO,
    MACHINE_SPOOL_DIAMETER,
    MACHINE_MAX_WEIGHT,
    MACHINE_CABLE_MAX_LENGTH,
    MACHINE_SCALE_WEIGHT2CURRENT,
    MACHINE_SOFT_WINDING_HEIGHT,

    MACHINE_DEFAULT_WEIGHT,
    MACHINE_FRICTION_WEIGHT,
    MACHINE_FRICTION_SPEED_PLUS,
    MACHINE_FRICTION_SPEED_MINUS,

    DFU_Status,     // Flash 초기상태를 의도한 값이므로 따로 지정하진 않음.

    FLASH_VALID_CODE,//uint32_t check
};

Data_Form_RAM RAM_Data;


void Flash_Init(void)
{
  uint8_t i;
  uint32_t *ram_data,*source_data;

  ram_data=(uint32_t*)&RAM_Data;

  if(Origin_Data.check==FLASH_VALID_CODE) {
    source_data=(uint32_t*)&Origin_Data;
    for(i=0; i<sizeof(RAM_Data)/4;i++ ) {
      *ram_data++=*source_data++;
    }
    //write backup
    Flash_Write(FLASH_BACKUP_SECTOR);
    Flash_Write(FLASH_BACKUP_SECTOR);
  }
  else if(Backup_Data.check==FLASH_VALID_CODE) {
    source_data=(uint32_t*)&Backup_Data;
    for(i=0; i<sizeof(RAM_Data)/4;i++) {
      *ram_data++=*source_data++;
    }
    //write origin
    Flash_Write(FLASH_ORIGIN_SECTOR);
    Flash_Write(FLASH_ORIGIN_SECTOR);
  }
  else {                       //Factory Reset
    source_data=(uint32_t*)&Defualt_RAM_Data;
    for(i=0; i<sizeof(RAM_Data)/4;i++) {
      *ram_data++=*source_data++;
    }
    //write origin
    Flash_Write(FLASH_ORIGIN_SECTOR);
    Flash_Write(FLASH_ORIGIN_SECTOR);
  }
}

HAL_StatusTypeDef Flash_Erase(uint32_t sector)
{
  uint32_t SectorError=0;

  HAL_FLASH_Unlock();

  FLASH_EraseInitTypeDef  EraseInitStruct;

  EraseInitStruct.TypeErase=FLASH_TYPEERASE_SECTORS;
  EraseInitStruct.Sector=sector;
  EraseInitStruct.NbSectors=1;
  EraseInitStruct.VoltageRange=FLASH_VOLTAGE_RANGE_3;

  if(HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError)!=HAL_OK){
    return HAL_ERROR;
  }
  HAL_FLASH_Lock();
  Delay_msec(10);
  return HAL_OK;

}

/**
  * @brief  Set the specified data holding register value for DAC channel.
  * @param  Sector  Target Sector Number
  *          This parameter can be one of the following values:
  *            @arg FLASH_ORIGIN_SECTOR
  *            @arg FLASH_BACKUP_SECTOR
  * @retval HAL status
  */
HAL_StatusTypeDef Flash_Write(uint8_t sector)
{
  uint8_t i;
  const uint32_t t=sizeof(Data_Form_RAM)/4;
  uint32_t *ram_data,*flash_data;

  ram_data=(uint32_t*)&RAM_Data;
  if(sector==FLASH_ORIGIN_SECTOR){//origin
    flash_data=(uint32_t*)&Origin_Data;

    for(i=0; i<t; i++) {
      if(*ram_data++!=*flash_data++)    break;
    }
    if(i==t)                            return HAL_OK;

    ram_data=(uint32_t*)&RAM_Data;
    flash_data=(uint32_t*)&Origin_Data;   //target

    //Erase
    HAL_FLASH_Unlock();
    Flash_Erase(FLASH_ORIGIN_SECTOR);
    HAL_FLASH_Lock();
    Delay_msec(10);

    //Write
    HAL_FLASH_Unlock();
    for(i=0; i<t; i++) {
      if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (uint32_t)flash_data++, *ram_data++)!=HAL_OK) {
        return HAL_ERROR;
      }
    }
    Delay_msec(10);
    HAL_FLASH_Lock();
  }
  if(sector==FLASH_BACKUP_SECTOR){//backup
    flash_data=(uint32_t*)&Backup_Data;

    for(i=0; i<t; i++) {
      if(*ram_data++!=*flash_data++)    break;
    }
    if(i==t)                            return HAL_OK;

    ram_data=(uint32_t*)&RAM_Data;
    flash_data=(uint32_t*)&Backup_Data;   //target

    //Erase
    HAL_FLASH_Unlock();
    Flash_Erase(FLASH_BACKUP_SECTOR);
    HAL_FLASH_Lock();
    Delay_msec(10);

    //Write
    HAL_FLASH_Unlock();
    for(i=0; i<t; i++) {
      if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (uint32_t)flash_data++, *ram_data++)!=HAL_OK) {
        return HAL_ERROR;
      }
    }
    Delay_msec(10);
    HAL_FLASH_Lock();
  }
  return HAL_OK;
}

