#include <assert.h>

#include "eeprom.h"
#include "stdio.h"

#define CONCAT(a, b) CONCAT_INNER(a, b)											// These three macros
#define CONCAT_INNER(a, b) a ## b												// generate unique variables
#define UNIQUE_NAME(base) CONCAT(base, __COUNTER__)								// according to template "baseX", like "base1", "base2" and etc

/********************************************************/

// Eeprom state related defines

/*****************EEPROM_EMULATOR************************/

typedef struct
{
  // Schnittstellenparameter
  uint32_t	  baudrate;
  uint16_t	  parityMode;
  uint16_t	  stopBits;
  uint16_t	  slave_adress;
  uint16_t	  ibn_day;
  uint16_t	  ibn_month;
  uint16_t	  ibn_year;
  uint16_t	  user_id;

  // Offset und Gain
  int16_t	  batteryCurrentOffsetRefTemperatureShunt;
  int16_t	  batteryCurrentOffsetRefTemperatureChip;
  int16_t	  batteryCurrentGainRefTempShunt;
  int16_t	  batteryCurrentGainRefTempChip;
  int16_t	  batteryCurrentOffsetTemperatureCalibrationTemperature;
  int16_t	  batteryCurrentGainTemperatureCalibrationShuntTemperature;
  int16_t	  batteryCurrentGainTemperatureCalibrationChipTemperature;
  int32_t	  batteryCurrentOffsetRefshuntVoltage;
  int32_t	  batteryCurrentOffsetCommonModeCalibrationVoltage;
  int32_t	  batteryCurrentOffsetCommonModeCompensationFactor;
  int32_t	  batteryCurrentOffsetTemperatureCompensationFactor;
  int32_t	  batteryCurrentGainRefCurrent;
  int32_t	  batteryCurrentGainTemperatureCompensationShuntFactor;
  int32_t	  batteryCurrentGainTemperatureCompensationChipFactor;

  int32_t	  currentOffset;
  uint32_t	  currentGain;

  int64_t	  mAsCounter;
  int32_t	  detectedCapacity;
  int32_t	  detectedEnergy;
  int64_t	  mAs_AutoMode;								// 160-163	Helps to restore current SoC after Reset or Shutdown
  int64_t	  mWs_AutoMode;								// 164-167	Helps to restore current SoC after Reset or Shutdown

  // battery parameter
  uint16_t	  cef;
  uint16_t	  peukert;
  uint32_t	  cellCapacity;
  uint32_t	  cellEnergy;
  uint16_t	  iBatFull;
  uint16_t	  tBatFull;
  uint16_t	  uBatFull;
  uint16_t	  uBatEmpty;
  uint8_t	  socCalcMode;
  uint16_t	  cellRatedDischargeTime;

  // Schaltausgänge
  uint16_t	  lvpStart;									// Spannung ab der die LOW Voltage Protection aktiv wird in mV
  uint16_t	  lvpStop;									// Spannung ab der die LOW Voltage Protection wieder inaktiv wird
  uint16_t	  ovpStart;									// Spannung ab der die OVER Voltage Protection aktiv wird in mV
  uint16_t	  ovpStop;									// Spannung ab der die OVER Voltage Protection wieder inaktiv wird
  int16_t	  loadCurrentLimit;							// maximaler Laststrom in A wenn der Strom größer ist als der eingestelle Wert dann wird die Laststrom Protection aktiv
  int16_t	  chargeCurrentLimit;						// maximaler Ladestrom in A wenn der Strom größer ist als der eingestelle Wert dann wird die Ladestrom Protection aktiv
  int16_t	  chargeStopHighTemperatureStart;			// Abschalttemperatur Ladung wegen zu hoher Temperatur
  int16_t	  chargeStopHighTemperatureStop;			// Wiedereinschalttemperatur
  int16_t	  chargeStopLowTemperatureStart;			// Abschalttemperatur Ladung wegen zu niedriger Temperatur
  int16_t	  chargeStopLowTemperatureStop;				// Wiedereinschalttemperatur
  int16_t	  dischargeStopHighTemperatureStart;		// Abschalttemperatur Entladung wegen zu hoher Temperatur
  int16_t	  dischargeStopHighTemperatureStop;			// Wiedereinschalttemperatur
  int16_t	  dischargeStopLowTemperatureStart;			// Abschalttemperatur EntLadung wegen zu niedriger Temperatur
  int16_t	  dischargeStopLowTemperatureStop;			// Wiedereinschalttemperatur

  int16_t	  uBatEmptyCompStartTemp;					// We start calculating uBatEmpty compensations only when cell temperature is lower than this value
  int16_t	  uBatEmptyCompStopTemp;					// We stop calculating uBatEmpty compensations when cell temperature is lower than this value
  uint16_t	  uBatEmptyCompStopVolt;					// uBatEmpty Voltage at temperatures lower than lvpCompStopTemp

  int16_t	  extraDischargeStrom_mA;					// For example, current that consumes LiPro itself
  uint32_t	  dischargeTotalAh;
  uint32_t	  chargeTotalAh;
  uint32_t	  dischargeTotalWh;							// 154-155	[mAs]
  uint32_t	  chargeTotalWh;							// 156-157	[mAs]

  uint16_t	  cefW;
  uint32_t	  onTime;

} eeprom_data_t;

typedef struct
{
  // Schnittstellenparameter
  uint32_t	  baudrate;
  uint16_t	  parityMode;
  uint16_t	  stopBits;
  uint16_t	  slave_adress;
  uint16_t	  ibn_day;
  uint16_t	  ibn_month;
  uint16_t	  ibn_year;
  uint16_t	  user_id;

  // Offset und Gain
  int16_t	  batteryCurrentOffsetRefTemperatureShunt;
  int16_t	  batteryCurrentOffsetRefTemperatureChip;
  int16_t	  batteryCurrentGainRefTempShunt;
  int16_t	  batteryCurrentGainRefTempChip;
  int16_t	  batteryCurrentOffsetTemperatureCalibrationTemperature;
  int16_t	  batteryCurrentGainTemperatureCalibrationShuntTemperature;
  int16_t	  batteryCurrentGainTemperatureCalibrationChipTemperature;
  int32_t	  batteryCurrentOffsetRefshuntVoltage;
  int32_t	  batteryCurrentOffsetCommonModeCalibrationVoltage;
  int32_t	  batteryCurrentOffsetCommonModeCompensationFactor;
  int32_t	  batteryCurrentOffsetTemperatureCompensationFactor;
  int32_t	  batteryCurrentGainRefCurrent;
  int32_t	  batteryCurrentGainTemperatureCompensationShuntFactor;
  int32_t	  batteryCurrentGainTemperatureCompensationChipFactor;

  int32_t	  currentOffset;
  uint32_t	  currentGain;

  int64_t	  mAsCounter;
  int32_t	  detectedCapacity;
  int32_t	  detectedEnergy;
  int32_t	  mAh_AutoMode;
  int32_t	  mWh_AutoMode;

  // battery parameter
  uint16_t	  cef;
  uint16_t	  peukert;
  uint32_t	  cellCapacity;
  uint32_t	  cellEnergy;
  uint16_t	  iBatFull;
  uint16_t	  tBatFull;
  uint16_t	  uBatFull;
  uint16_t	  uBatEmpty;
  uint8_t	  socCalcMode;
  uint16_t	  cellRatedDischargeTime;

  // Schaltausgänge
  uint16_t	  lvpStart;									// Spannung ab der die LOW Voltage Protection aktiv wird in mV
  uint16_t	  lvpStop;									// Spannung ab der die LOW Voltage Protection wieder inaktiv wird
  uint16_t	  ovpStart;									// Spannung ab der die OVER Voltage Protection aktiv wird in mV
  uint16_t	  ovpStop;									// Spannung ab der die OVER Voltage Protection wieder inaktiv wird
  int16_t	  loadCurrentLimit;							// maximaler Laststrom in A wenn der Strom größer ist als der eingestelle Wert dann wird die Laststrom Protection aktiv
  int16_t	  chargeCurrentLimit;						// maximaler Ladestrom in A wenn der Strom größer ist als der eingestelle Wert dann wird die Ladestrom Protection aktiv
  int16_t	  chargeStopHighTemperatureStart;			// Abschalttemperatur Ladung wegen zu hoher Temperatur
  int16_t	  chargeStopHighTemperatureStop;			// Wiedereinschalttemperatur
  int16_t	  chargeStopLowTemperatureStart;			// Abschalttemperatur Ladung wegen zu niedriger Temperatur
  int16_t	  chargeStopLowTemperatureStop;				// Wiedereinschalttemperatur
  int16_t	  dischargeStopHighTemperatureStart;		// Abschalttemperatur Entladung wegen zu hoher Temperatur
  int16_t	  dischargeStopHighTemperatureStop;			// Wiedereinschalttemperatur
  int16_t	  dischargeStopLowTemperatureStart;			// Abschalttemperatur EntLadung wegen zu niedriger Temperatur
  int16_t	  dischargeStopLowTemperatureStop;			// Wiedereinschalttemperatur

  int16_t	  uBatEmptyCompStartTemp;					// We start calculating uBatEmpty compensations only when cell temperature is lower than this value
  int16_t	  uBatEmptyCompStopTemp;					// We stop calculating uBatEmpty compensations when cell temperature is lower than this value
  uint16_t	  uBatEmptyCompStopVolt;					// uBatEmpty Voltage at temperatures lower than lvpCompStopTemp

  int16_t	  extraDischargeStrom_mA;					// For example, current that consumes LiPro itself
  uint32_t	  dischargeTotalAh;
  uint32_t	  chargeTotalAh;
  uint32_t	  dischargeTotalWh;							// 154-155	[mAs]
  uint32_t	  chargeTotalWh;							// 156-157	[mAs]

  uint16_t	  cefW;
  uint32_t	  onTime;

}eeprom_old_data_t;

// Substitute for #if sizeof(some_type) == sizeof(another_type) functionality
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

typedef struct
{
  // Geräteinformation
  uint32_t    SN;
  uint8_t     deviceInfoWritten;
  uint8_t     UNIQUE_NAME(reserved)[3];
}device_info_t;

typedef struct
{
  // Eeprom Status Infos
   uint8_t     firstStartId;
   uint8_t     UNIQUE_NAME(reserved)[3];
  uint16_t     structureSize;
  uint16_t     revisionInfo;
  uint32_t     writeCounter;
}eeprom_state_t;

// fasse zu einer Struktur zusammen um nachher einfach darauf zugreifen zu können
typedef struct
{
  eeprom_state_t eepromState;
  device_info_t  deviceInfo;
  eeprom_data_t  changedData;
}eeprom_stored_data_t;

typedef struct
{
  eeprom_state_t eepromState;
  device_info_t  deviceInfo;
  eeprom_old_data_t changedData;
}eeprom_stored_old_data_t;


// Flash related defines
#define USER_FLASH_BASE_ADRESS                    FLASH_BASE								  // 0x08000000
#define USER_FLASH_SIZE                           FLASH_SIZE								  // 0x00020000	- 128 kB
#define USER_FLASH_END                            (USER_FLASH_BASE_ADRESS + USER_FLASH_SIZE)  // 0x08020000
#define USER_FLASH_PAGE_SIZE                      (0x800)                                                                 //- 2 kB

// Eeprom emulator related defines
#define NUMBER_OF_PAGES                           (1U)
#define USER_EEPROM_BASE_ADRESS                   (USER_FLASH_END - (USER_FLASH_PAGE_SIZE * NUMBER_OF_PAGES))		  // 0x0801F800 - EEPROM start address (CONFIG_ID location)

// Data to store reated defines
//#define SIZEOF_DEFAULT_EEPROM_DATA                (sizeof(eeprom_new_data_t))
#define SIZEOF_CHANGED_EEPROM_DATA                (sizeof(eeprom_data_t))
#define SIZEOF_CHANGED_EEPROM_OLD_DATA            (sizeof(eeprom_old_data_t))
#define SIZEOF_DEVICE_INFO                        (sizeof(device_info_t))
#define SIZEOF_EEPROM_STATE                       (sizeof(eeprom_state_t))

#define SIZE_OF_DATA_TO_STORE                     (SIZEOF_CHANGED_EEPROM_DATA + SIZEOF_DEVICE_INFO + SIZEOF_EEPROM_STATE)
#define SIZE_OF_OLD_DATA_TO_STORE                 (SIZEOF_CHANGED_EEPROM_OLD_DATA + SIZEOF_DEVICE_INFO + SIZEOF_EEPROM_STATE)

// Adress related defines
#define EEPROM_ADRESS_FIRST_START_ID              (USER_EEPROM_BASE_ADRESS)// - 1 + SIZE_OF_DATA_TO_STORE - 1 - SIZEOF_DEVICE_INFO - 1 - 1)
#define FIRST_START_ID                            (0xFF)
#define CONFIG_ID								  (57)	  // Increment by 1 to make compartible update, more than 1 - incompartible
#if CONFIG_ID == FIRST_START_ID
#error "CONFIG_ID must not be equal to FIRST_START_ID!!! Calibration data will be erased!!!"
#endif

static uint32_t GetPage(uint32_t Address);
static HAL_StatusTypeDef getEEPROMData(uint32_t address, uint8_t * data, uint32_t len);

// muss modulo 8 noch hinzufügen wg 8 byte alignement
static uint64_t eepromData[(SIZE_OF_DATA_TO_STORE / 8) + 1];
static uint64_t eepromOldData[(SIZE_OF_OLD_DATA_TO_STORE / 8) + 1];

static FLASH_EraseInitTypeDef EraseInitStruct = {0};

static const eeprom_data_t defaultEepromData =
{
	// Schnittstellenparameter

	/* baudrate		*/														19200,			// uint32_t   baudrate;
	/* parityMode	*/														0,				// uint16_t   parityMode;
	/* stopBits		*/														1,				// uint16_t   stopBits;
	/* slave_adress	*/														1,				// uint16_t   slave_adress;
	/* ibn_day		*/														0,				// ibm_day
	/* ibn_month	*/														0,				// ibm_month
	/* ibn_year		*/														0,				// ibm_year
	/* user_id		*/														0,				// user id

	// Offset und Gain

	/* batteryCurrentOffsetRefTemperatureShunt					*/			0,				// int16_t   batteryCurrentOffsetRefTemperatureShunt;
	/* batteryCurrentOffsetRefTemperatureChip					*/			0,				// int16_t   batteryCurrentOffsetRefTemperatureChip
	/* batteryCurrentGainRefTempShunt							*/			0,				// int16_t   batteryCurrentGainRefTempShunt;
	/* batteryCurrentGainRefTempChip							*/			0,				// int16_t   batteryCurrentGainRefTempShip
	/* batteryCurrentOffsetTemperatureCalibrationTemperature	*/			0,				// int16_t   batteryCurrentOffsetTemperatureCalibrationTemperature;
	/* batteryCurrentGainTemperatureCalibrationShuntTemperature	*/			0,				// int16_t   batteryCurrentGainTemperatureCalibrationShuntTemperature;
	/* batteryCurrentGainTemperatureCalibrationChipTemperature	*/			0,				// int16_t   batteryCurrentGainTemperatureCalibrationChipTemperature;
	/* batteryCurrentOffsetRefshuntVoltage						*/			0,				// int32_t   batteryCurrentOffsetRefshuntVoltage;
	/* batteryCurrentOffsetCommonModeCalibrationVoltage			*/			0,				// int32_t   batteryCurrentOffsetCommonModeCalibrationVoltage;
	/* batteryCurrentOffsetTemperatureCompensationFactor		*/			0,				// int32_t   batteryCurrentOffsetTemperatureCompensationFactor;
	/* batteryCurrentOffsetCommonModeCompensationFactor			*/			0,				// int32_t   batteryCurrentOffsetCommonModeCompensationFactor;
	/* batteryCurrentGainRefCurrent								*/			250000,			// int32_t   batteryCurrentGainRefCurrent;
	/* batteryCurrentGainTemperatureCompensationShuntFactor		*/			0,				// int32_t   batteryCurrentGainTemperatureCompensationShuntFactor;
	/* batteryCurrentGainTemperatureCompensationChipFactor		*/			0,				// int32_t   batteryCurrentGainTemperatureCompensationChipFactor;

	/* currentOffset  */													0,				//int32_t   currentOffset;
	/* currentGain	  */													1000000,		//uint32_t  currentGain;

	/* mAsCounter		*/													0,				// mAsCounter
	/* detectedCapacity	*/													-1,				// detectedCapacity
	/* detectedEnergy	*/													-1,				// detectedEnergy
	/* mAs_AutoMode		*/													(-100000LL*3600LL),	// mAs_AutoMode = cellCapacity*3600,
	/* mWs_AutoMode		*/													(-2640000LL*3600LL),// mWs_AutoMode = cellEnergy*3600,

	// battery parameter

	/* cef						*/											99,				// cef
	/* peukert					*/											105,			// peukert
	/* cellCapacity				*/											100000,			// cell Capacity in mAh
	/* cellEnergy				*/											2640000,		// cell energy in mWh
	/* iBatFull					*/											10,				// I-batt full 4% 4A bei 100Ah akku
	/* tBatFull					*/											2,				// t-batt full 2 Sekunden
	/* uBatFull					*/											14000,			// 14Volt Ubatt full
	/* uBatEmpty				*/											12500,			// 11,312V Ubatt Empty
	/* socCalcMode				*/											1,				// SoC calculation mode: 0(default)
	/* cellRatedDischargeTime	*/											2,				// cell rated current discharge time [C/x]. For example, if 40Ah cell is rated as 0.5c, then rated discharge time is 2

	/* lvpStart	*/															12000,			// uint16_t lvpStart; Spannung ab der die LOW Voltage Protection aktiv wird in mV
	/* lvpStop	*/															12500,			// uint16_t lvpStop; Spannung ab der die LOW Voltage Protection wieder inaktiv wird
	/* ovpStart	*/															15000,			// uint16_t  ovpStart; Spannung ab der die OVER Voltage Protection aktiv wird in mV
	/* ovpStop	*/															14000,			// uint16_t  ovpStop; Spannung ab der die OVER Voltage Protection wieder inaktiv wird

#if (DEVICETYPE == 500)
	/* loadCurrentLimit	  */												-500,			// uint16_t loadCurrentLimit; maximaler Laststrom in A wenn der Strom größer ist als der eingestelle Wert dann wird die Laststrom Protection aktiv
	/* chargeCurrentLimit */												500,			// uint16_t chargeCurrentLimit;	maximaler Ladestrom in A wenn der Strom größer ist als der eingestelle Wert dann wird die Ladestrom Protection aktiv
#elif (DEVICETYPE == 250)
	/* loadCurrentLimit	  */												-250,			// uint16_t loadCurrentLimit; maximaler Laststrom in A wenn der Strom größer ist als der eingestelle Wert dann wird die Laststrom Protection aktiv
	/* chargeCurrentLimit */												250,			// uint16_t chargeCurrentLimit maximaler Ladestrom in A wenn der Strom größer ist als der eingestelle Wert dann wird die Ladestrom Protection aktiv
#elif (DEVICETYPE == 125)
	/* loadCurrentLimit	  */												-125,			// uint16_t loadCurrentLimit; maximaler Laststrom in A wenn der Strom größer ist als der eingestelle Wert dann wird die Laststrom Protection aktiv
	/* chargeCurrentLimit */												125,			// uint16_t chargeCurrentLimit; maximaler Ladestrom in A wenn der Strom größer ist als der eingestelle Wert dann wird die Ladestrom Protection aktiv
#else
#error No valid device type
#endif
	/* chargeStopHighTemperatureStart	*/									7500,			// 80°C int16_t chargeStopHighTemperatureStart;	Abschalttemperatur Ladung wegen zu hoher Temperatur
	/* chargeStopHighTemperatureStop	*/									7000,			// 75°C int16_t chargeStopHighTemperatureStop;	Wiedereinschalttemperatur
	/* chargeStopLowTemperatureStart	*/									-3500,			// -35°C int16_t chargeStopLowTemperatureStart;	Abschalttemperatur Ladung wegen zu niedriger Temperatur
	/* chargeStopLowTemperatureStop		*/									-3000,			// -30°C int16_t chargeStopLowTemperatureStop; Wiedereinschalttemperatur
	/* dischargeStopHighTemperatureStart*/									7500,			// 80°C int16_t dischargeStopHighTemperatureStart; Abschalttemperatur Entladung wegen zu hoher Temperatur
	/* dischargeStopHighTemperatureStop	*/									7000,			// 75°C int16_t dischargeStopHighTemperatureStop; Wiedereinschalttemperatur
	/* dischargeStopLowTemperatureStart	*/									-3500,			// -35°C int16_t dischargeStopLowTemperatureStart; Abschalttemperatur EntLadung wegen zu niedriger Temperatur
	/* dischargeStopLowTemperatureStop	*/									-3000,			// -30°C int16_t dischargeStopLowTemperatureStop; Wiedereinschalttemperatur

	/* uBatEmptyCompStartTemp	*/											50,				// 5°C We start calculating uBatEmpty compensations only when cell temperature is lower than this value
	/* uBatEmptyCompStopTemp	*/											-200,			// -20°C We stop calculating uBatEmpty compensations when cell temperature is lower than this value
	/* uBatEmptyCompStopVolt	*/											10000,			// 10V uBatEmpty voltage at temperatures lower than -20°C

	/* extraDischargeStrom_mA	*/											7,				// mA, current that LiPro consumes itself
	/* dischargeTotalAh			*/											0,				// Ah for negative current counter
	/* chargeTotalAh			*/											0,				// Ah for total charge counter
	/* dischargeTotalWh			*/											0,
	/* chargeTotalWh			*/											0,

	/* cefW		*/															90,				// 90% cef for Wh calculations
	/* onTime	*/															0

};

/**
  * @brief  Gets the page of a given address
  * @param  Addr: Address of the FLASH Memory
  * @retval The page of a given address
  */
static uint32_t GetPage(uint32_t Addr)
{
  return (Addr - FLASH_BASE) / FLASH_PAGE_SIZE;
}

//------------------------------------------------------------------------------

static HAL_StatusTypeDef getEEPROMData(uint32_t address, uint8_t* data, uint32_t len)
{
    uint8_t daten;

    if ((address + len) > USER_FLASH_END) return HAL_ERROR;

    for (size_t i = 0; i < len; ++i) data[i] = *((uint8_t *)(address + i));

    return HAL_OK;
}

//------------------------------------------------------------------------------

startType_t EEPROM_isFirstStart(uint8_t* fsID)
{
  // sizeof eeprom_new_data_t must not be equal to size of eeprom_old_data_t
  BUILD_BUG_ON(sizeof(eeprom_data_t) == sizeof(eeprom_old_data_t));

  uint8_t firstStartCatcher;

  if (getEEPROMData(EEPROM_ADRESS_FIRST_START_ID, &firstStartCatcher, 1) != HAL_OK) return FIRST_START_ERROR;

  if (fsID != NULL) *fsID = firstStartCatcher;

  if (firstStartCatcher == FIRST_START_ID)
  {
	  printf ("First start detected!\n");
	  return FIRST_START_AFTER_ERASE;
  }
  else if (firstStartCatcher == CONFIG_ID)
  {
	  printf ("Normal start without EEPROM changes detected\n");
	  return FIRST_START_AFTER_COMPARTIBLE_UPDATE;
  }
  else if (firstStartCatcher == CONFIG_ID - 1)
  {
	  printf ("EEPROM was changed! We need to preserve calibration and settings data!\n");
	  return FIRST_START_AFTER_INCOMPARTIBLE_UPDATE;
  }
  else return FIRST_START_ERROR;
}

//------------------------------------------------------------------------------

HAL_StatusTypeDef EEPROM_fullRestore(sys_data_t* data)
{
  eeprom_stored_data_t* dataToStore;
  uint32_t PageError;
  uint32_t Address;
  uint32_t x;

  printf("EEPROM FULL RESTORE!\n");

  /**************** LESE_DEFAULT_WERTE ************************/

  dataToStore = (eeprom_stored_data_t*) eepromData;

  // Schnittstellenparameter
  dataToStore->changedData.baudrate													= defaultEepromData.baudrate;
  dataToStore->changedData.parityMode												= defaultEepromData.parityMode;
  dataToStore->changedData.stopBits													= defaultEepromData.stopBits;
  dataToStore->changedData.slave_adress												= defaultEepromData.slave_adress;

  // Offset und Gain
  dataToStore->changedData.batteryCurrentOffsetRefTemperatureShunt					= defaultEepromData.batteryCurrentOffsetRefTemperatureShunt;
  dataToStore->changedData.batteryCurrentOffsetRefTemperatureChip					= defaultEepromData.batteryCurrentOffsetRefTemperatureChip;
  dataToStore->changedData.batteryCurrentGainRefTempShunt							= defaultEepromData.batteryCurrentGainRefTempShunt;
  dataToStore->changedData.batteryCurrentGainRefTempChip							= defaultEepromData.batteryCurrentGainRefTempChip;
  dataToStore->changedData.batteryCurrentOffsetTemperatureCalibrationTemperature	= defaultEepromData.batteryCurrentOffsetTemperatureCalibrationTemperature;
  dataToStore->changedData.batteryCurrentGainTemperatureCalibrationShuntTemperature	= defaultEepromData.batteryCurrentGainTemperatureCalibrationShuntTemperature;
  dataToStore->changedData.batteryCurrentGainTemperatureCalibrationChipTemperature	= defaultEepromData.batteryCurrentGainTemperatureCalibrationChipTemperature;
  dataToStore->changedData.batteryCurrentOffsetRefshuntVoltage						= defaultEepromData.batteryCurrentOffsetRefshuntVoltage;
  dataToStore->changedData.batteryCurrentOffsetCommonModeCalibrationVoltage			= defaultEepromData.batteryCurrentOffsetCommonModeCalibrationVoltage;
  dataToStore->changedData.batteryCurrentOffsetCommonModeCompensationFactor			= defaultEepromData.batteryCurrentOffsetCommonModeCompensationFactor;
  dataToStore->changedData.batteryCurrentOffsetTemperatureCompensationFactor		= defaultEepromData.batteryCurrentOffsetTemperatureCompensationFactor;
  dataToStore->changedData.batteryCurrentGainRefCurrent								= defaultEepromData.batteryCurrentGainRefCurrent;
  dataToStore->changedData.batteryCurrentGainTemperatureCompensationShuntFactor		= defaultEepromData.batteryCurrentGainTemperatureCompensationShuntFactor;
  dataToStore->changedData.batteryCurrentGainTemperatureCompensationChipFactor		= defaultEepromData.batteryCurrentGainTemperatureCompensationChipFactor;

  dataToStore->changedData.currentOffset											= defaultEepromData.currentOffset;
  dataToStore->changedData.currentGain												= defaultEepromData.currentGain;

  // AH Counter Parameter
  dataToStore->changedData.cef														= defaultEepromData.cef;
  dataToStore->changedData.peukert													= defaultEepromData.peukert;
  dataToStore->changedData.cellCapacity												= defaultEepromData.cellCapacity;
  dataToStore->changedData.cellEnergy												= defaultEepromData.cellEnergy;
  dataToStore->changedData.iBatFull													= defaultEepromData.iBatFull;
  dataToStore->changedData.tBatFull													= defaultEepromData.tBatFull;
  dataToStore->changedData.uBatFull													= defaultEepromData.uBatFull;
  dataToStore->changedData.uBatEmpty												= defaultEepromData.uBatEmpty;
  dataToStore->changedData.socCalcMode												= defaultEepromData.socCalcMode;
  dataToStore->changedData.cellRatedDischargeTime									= defaultEepromData.cellRatedDischargeTime;

  // Schaltausgänge
  dataToStore->changedData.lvpStart													= defaultEepromData.lvpStart;
  dataToStore->changedData.lvpStop													= defaultEepromData.lvpStop;
  dataToStore->changedData.ovpStart													= defaultEepromData.ovpStart;
  dataToStore->changedData.ovpStop													= defaultEepromData.ovpStop;
  dataToStore->changedData.loadCurrentLimit											= defaultEepromData.loadCurrentLimit;
  dataToStore->changedData.chargeCurrentLimit										= defaultEepromData.chargeCurrentLimit;
  dataToStore->changedData.chargeStopHighTemperatureStart							= defaultEepromData.chargeStopHighTemperatureStart;
  dataToStore->changedData.chargeStopHighTemperatureStop							= defaultEepromData.chargeStopHighTemperatureStop;
  dataToStore->changedData.chargeStopLowTemperatureStart							= defaultEepromData.chargeStopLowTemperatureStart;
  dataToStore->changedData.chargeStopLowTemperatureStop								= defaultEepromData.chargeStopLowTemperatureStop;
  dataToStore->changedData.dischargeStopHighTemperatureStart						= defaultEepromData.dischargeStopHighTemperatureStart;
  dataToStore->changedData.dischargeStopHighTemperatureStop							= defaultEepromData.dischargeStopHighTemperatureStop;
  dataToStore->changedData.dischargeStopLowTemperatureStart							= defaultEepromData.dischargeStopLowTemperatureStart;
  dataToStore->changedData.dischargeStopLowTemperatureStop							= defaultEepromData.dischargeStopLowTemperatureStop;

  dataToStore->changedData.uBatEmptyCompStartTemp									= defaultEepromData.uBatEmptyCompStartTemp;
  dataToStore->changedData.uBatEmptyCompStopTemp									= defaultEepromData.uBatEmptyCompStopTemp;
  dataToStore->changedData.uBatEmptyCompStopVolt									= defaultEepromData.uBatEmptyCompStopVolt;

  dataToStore->changedData.extraDischargeStrom_mA									= defaultEepromData.extraDischargeStrom_mA;
  dataToStore->changedData.dischargeTotalAh											= defaultEepromData.dischargeTotalAh;
  dataToStore->changedData.chargeTotalAh											= defaultEepromData.chargeTotalAh;
  dataToStore->changedData.dischargeTotalWh											= defaultEepromData.dischargeTotalWh;
  dataToStore->changedData.chargeTotalWh											= defaultEepromData.chargeTotalWh;
  dataToStore->changedData.cefW														= defaultEepromData.cefW;
  dataToStore->changedData.onTime													= defaultEepromData.onTime;

  dataToStore->changedData.mAsCounter												= defaultEepromData.mAsCounter;
  dataToStore->changedData.detectedCapacity											= defaultEepromData.detectedCapacity;
  dataToStore->changedData.detectedEnergy											= defaultEepromData.detectedEnergy;
  dataToStore->changedData.mAs_AutoMode												= defaultEepromData.mAs_AutoMode;
  dataToStore->changedData.mWs_AutoMode												= defaultEepromData.mWs_AutoMode;

  // Eeprom Status Infos
  dataToStore->eepromState.writeCounter++;
  dataToStore->eepromState.structureSize = sizeof(eeprom_stored_data_t);
  dataToStore->eepromState.revisionInfo = 0;
  dataToStore->eepromState.firstStartId = CONFIG_ID;

  /****************PAGE_LÖSCHEN********************/
  HAL_FLASH_Unlock();

  // check for PG bit set if so clear bit
  FLASH_WaitForLastOperation(1000);
  if(READ_BIT(FLASH->CR, FLASH_CR_PG))
  {
    CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
  }

  /* Fill EraseInit structure*/
  EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
  EraseInitStruct.Page        = FLASH_PAGE_NB - 1; //GetPage(USER_EEPROM_BASE_ADRESS);
  EraseInitStruct.NbPages     = 1;

  /* erase Sektoren daten d+rfen nicht im instuction cache liegen  */
  if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
  {
    while (1)
    {
      // ERROR HAL_FLASH_GetError() kann info geben
    }
  }

  /****************IM_FLASH_SPEICHERN********************/

  /* programmiere uint64_t */
  Address = USER_EEPROM_BASE_ADRESS;
  x = 0;
  while (Address < (USER_EEPROM_BASE_ADRESS + SIZE_OF_DATA_TO_STORE))
  {
    if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, eepromData[x]) == HAL_OK)
    {
      Address = Address + 8;
      x ++;
    }
   else
    {
      /* Error occurred while writing data in Flash memory.
         User can add here some code to deal with this error */
      while (1)
      {
        // ERROR
      }
    }
  }

  /* Lock the Flash */
  HAL_FLASH_Lock();

  /**************** AUSLESEN_UND_PRÜFEN ********************/

  return EEPROM_readConfig(data);

  //  Die Geräteinformation wird nicht geändert:
  /*
  dataToStore->deviceInfo.SN1;
  dataToStore->deviceInfo.SN1;
  dataToStore->deviceInfo.SN1;
  dataToStore->deviceInfo.deviceInfoWritten;
  */
}

HAL_StatusTypeDef EEPROM_factoryRestore(sys_data_t* data, int resetToDefault)
{
  printf("EEPROM FACTORY RESTORE/UPDATE!\n");

  // Reading from FLASH old calibration and parameters data
  if (getEEPROMData(USER_EEPROM_BASE_ADRESS, (uint8_t*)eepromOldData, sizeof(eepromOldData)) != HAL_OK) return HAL_ERROR;
  // Interpreting these data as it were in last version of the program
  eeprom_stored_old_data_t* oldDataToStore = (eeprom_stored_old_data_t*)eepromOldData;
  // Allocating free space for calibration and parameters data for new version of the program
  eeprom_stored_data_t* dataToStore = (eeprom_stored_data_t*)eepromData;

  //EEPROM_readConfig(data);														// Restoring calibration data

  // Offset und Gain
  dataToStore->changedData.currentOffset											= oldDataToStore->changedData.currentOffset;
  dataToStore->changedData.batteryCurrentOffsetRefTemperatureShunt					= oldDataToStore->changedData.batteryCurrentOffsetRefTemperatureShunt;
  dataToStore->changedData.batteryCurrentOffsetRefTemperatureChip					= oldDataToStore->changedData.batteryCurrentOffsetRefTemperatureChip;
  dataToStore->changedData.batteryCurrentOffsetRefshuntVoltage						= oldDataToStore->changedData.batteryCurrentOffsetRefshuntVoltage;
  dataToStore->changedData.batteryCurrentOffsetCommonModeCalibrationVoltage			= oldDataToStore->changedData.batteryCurrentOffsetCommonModeCalibrationVoltage;
  dataToStore->changedData.batteryCurrentOffsetCommonModeCompensationFactor			= oldDataToStore->changedData.batteryCurrentOffsetCommonModeCompensationFactor;
  dataToStore->changedData.batteryCurrentOffsetTemperatureCalibrationTemperature	= oldDataToStore->changedData.batteryCurrentOffsetTemperatureCalibrationTemperature;
  dataToStore->changedData.batteryCurrentOffsetTemperatureCompensationFactor		= oldDataToStore->changedData.batteryCurrentOffsetTemperatureCompensationFactor;
  dataToStore->changedData.currentGain												= oldDataToStore->changedData.currentGain;
  dataToStore->changedData.batteryCurrentGainRefTempShunt							= oldDataToStore->changedData.batteryCurrentGainRefTempShunt;
  dataToStore->changedData.batteryCurrentGainRefTempChip							= oldDataToStore->changedData.batteryCurrentGainRefTempChip;
  dataToStore->changedData.batteryCurrentGainRefCurrent								= oldDataToStore->changedData.batteryCurrentGainRefCurrent;
  dataToStore->changedData.batteryCurrentGainTemperatureCalibrationShuntTemperature	= oldDataToStore->changedData.batteryCurrentGainTemperatureCalibrationShuntTemperature;
  dataToStore->changedData.batteryCurrentGainTemperatureCompensationShuntFactor		= oldDataToStore->changedData.batteryCurrentGainTemperatureCompensationShuntFactor;
  dataToStore->changedData.batteryCurrentGainTemperatureCalibrationChipTemperature	= oldDataToStore->changedData.batteryCurrentGainTemperatureCalibrationChipTemperature;
  dataToStore->changedData.batteryCurrentGainTemperatureCompensationChipFactor		= oldDataToStore->changedData.batteryCurrentGainTemperatureCompensationChipFactor;

  // Schnittstellenparameter
  dataToStore->changedData.baudrate													= resetToDefault == 1 ? defaultEepromData.baudrate		: oldDataToStore->changedData.baudrate;
  dataToStore->changedData.parityMode												= resetToDefault == 1 ? defaultEepromData.parityMode	: oldDataToStore->changedData.parityMode;
  dataToStore->changedData.stopBits													= resetToDefault == 1 ? defaultEepromData.stopBits		: oldDataToStore->changedData.stopBits;
  dataToStore->changedData.slave_adress												= resetToDefault == 1 ? defaultEepromData.slave_adress	: oldDataToStore->changedData.slave_adress;
  dataToStore->changedData.ibn_day													= resetToDefault == 1 ? defaultEepromData.ibn_day		: oldDataToStore->changedData.ibn_day;
  dataToStore->changedData.ibn_month												= resetToDefault == 1 ? defaultEepromData.ibn_month		: oldDataToStore->changedData.ibn_month;
  dataToStore->changedData.ibn_year													= resetToDefault == 1 ? defaultEepromData.ibn_year		: oldDataToStore->changedData.ibn_year;
  dataToStore->changedData.user_id													= resetToDefault == 1 ? defaultEepromData.user_id		: oldDataToStore->changedData.user_id;

  //Ah counter
  dataToStore->changedData.cef														= resetToDefault == 1 ? defaultEepromData.cef					  : oldDataToStore->changedData.cef;
  dataToStore->changedData.cellCapacity												= resetToDefault == 1 ? defaultEepromData.cellCapacity			  : oldDataToStore->changedData.cellCapacity;
  dataToStore->changedData.cellEnergy												= resetToDefault == 1 ? defaultEepromData.cellEnergy			  : oldDataToStore->changedData.cellEnergy;
  dataToStore->changedData.iBatFull													= resetToDefault == 1 ? defaultEepromData.iBatFull				  : oldDataToStore->changedData.iBatFull;
  dataToStore->changedData.peukert													= resetToDefault == 1 ? defaultEepromData.peukert				  : oldDataToStore->changedData.peukert;
  dataToStore->changedData.tBatFull													= resetToDefault == 1 ? defaultEepromData.tBatFull				  : oldDataToStore->changedData.tBatFull;
  dataToStore->changedData.uBatFull													= resetToDefault == 1 ? defaultEepromData.uBatFull				  : oldDataToStore->changedData.uBatFull;
  dataToStore->changedData.uBatEmpty												= resetToDefault == 1 ? defaultEepromData.uBatEmpty				  : oldDataToStore->changedData.uBatEmpty;
  dataToStore->changedData.socCalcMode												= resetToDefault == 1 ? defaultEepromData.socCalcMode			  : oldDataToStore->changedData.socCalcMode;
  dataToStore->changedData.cellRatedDischargeTime									= resetToDefault == 1 ? defaultEepromData.cellRatedDischargeTime  : oldDataToStore->changedData.cellRatedDischargeTime;

  // Schaltausgänge
  dataToStore->changedData.lvpStart													= resetToDefault == 1 ? defaultEepromData.lvpStart							: oldDataToStore->changedData.lvpStart;
  dataToStore->changedData.lvpStop													= resetToDefault == 1 ? defaultEepromData.lvpStop							: oldDataToStore->changedData.lvpStop;
  dataToStore->changedData.ovpStart													= resetToDefault == 1 ? defaultEepromData.ovpStart							: oldDataToStore->changedData.ovpStart;
  dataToStore->changedData.ovpStop													= resetToDefault == 1 ? defaultEepromData.ovpStop							: oldDataToStore->changedData.ovpStop;
  dataToStore->changedData.loadCurrentLimit											= resetToDefault == 1 ? defaultEepromData.loadCurrentLimit					: oldDataToStore->changedData.loadCurrentLimit;
  dataToStore->changedData.chargeCurrentLimit										= resetToDefault == 1 ? defaultEepromData.chargeCurrentLimit				: oldDataToStore->changedData.chargeCurrentLimit;
  dataToStore->changedData.chargeStopHighTemperatureStart							= resetToDefault == 1 ? defaultEepromData.chargeStopHighTemperatureStart	: oldDataToStore->changedData.chargeStopHighTemperatureStart;
  dataToStore->changedData.chargeStopHighTemperatureStop							= resetToDefault == 1 ? defaultEepromData.chargeStopHighTemperatureStop		: oldDataToStore->changedData.chargeStopHighTemperatureStop;
  dataToStore->changedData.chargeStopLowTemperatureStart							= resetToDefault == 1 ? defaultEepromData.chargeStopLowTemperatureStart		: oldDataToStore->changedData.chargeStopHighTemperatureStop;
  dataToStore->changedData.chargeStopLowTemperatureStop								= resetToDefault == 1 ? defaultEepromData.chargeStopLowTemperatureStop		: oldDataToStore->changedData.chargeStopLowTemperatureStop;
  dataToStore->changedData.dischargeStopHighTemperatureStart						= resetToDefault == 1 ? defaultEepromData.dischargeStopHighTemperatureStart	: oldDataToStore->changedData.dischargeStopHighTemperatureStart;
  dataToStore->changedData.dischargeStopHighTemperatureStop							= resetToDefault == 1 ? defaultEepromData.dischargeStopHighTemperatureStop	: oldDataToStore->changedData.dischargeStopHighTemperatureStop;
  dataToStore->changedData.dischargeStopLowTemperatureStart							= resetToDefault == 1 ? defaultEepromData.dischargeStopLowTemperatureStart	: oldDataToStore->changedData.dischargeStopLowTemperatureStart;
  dataToStore->changedData.dischargeStopLowTemperatureStop							= resetToDefault == 1 ? defaultEepromData.dischargeStopLowTemperatureStop	: oldDataToStore->changedData.dischargeStopLowTemperatureStop;

  dataToStore->changedData.uBatEmptyCompStartTemp									= resetToDefault == 1 ? defaultEepromData.uBatEmptyCompStartTemp  : oldDataToStore->changedData.uBatEmptyCompStartTemp;
  dataToStore->changedData.uBatEmptyCompStopTemp									= resetToDefault == 1 ? defaultEepromData.uBatEmptyCompStopTemp	  : oldDataToStore->changedData.uBatEmptyCompStopTemp;
  dataToStore->changedData.uBatEmptyCompStopVolt									= resetToDefault == 1 ? defaultEepromData.uBatEmptyCompStopVolt	  : oldDataToStore->changedData.uBatEmptyCompStopVolt;

  dataToStore->changedData.extraDischargeStrom_mA									= resetToDefault == 1 ? defaultEepromData.extraDischargeStrom_mA  : oldDataToStore->changedData.extraDischargeStrom_mA;
  dataToStore->changedData.dischargeTotalAh											= resetToDefault == 1 ? defaultEepromData.dischargeTotalAh		  : oldDataToStore->changedData.dischargeTotalAh;
  dataToStore->changedData.chargeTotalAh											= resetToDefault == 1 ? defaultEepromData.chargeTotalAh			  : oldDataToStore->changedData.chargeTotalAh;
  dataToStore->changedData.cefW														= resetToDefault == 1 ? defaultEepromData.cefW					  : oldDataToStore->changedData.cefW;
  dataToStore->changedData.onTime													= resetToDefault == 1 ? defaultEepromData.onTime				  : oldDataToStore->changedData.onTime;

  // These fields are new
  dataToStore->changedData.mAsCounter												= defaultEepromData.mAsCounter;
  dataToStore->changedData.detectedCapacity											= defaultEepromData.detectedCapacity;
  dataToStore->changedData.detectedEnergy											= defaultEepromData.detectedEnergy;
  dataToStore->changedData.mAs_AutoMode												= defaultEepromData.mAs_AutoMode;
  dataToStore->changedData.mWs_AutoMode												= defaultEepromData.mWs_AutoMode;
  dataToStore->changedData.dischargeTotalWh											= defaultEepromData.dischargeTotalWh;
  dataToStore->changedData.chargeTotalWh											= defaultEepromData.chargeTotalWh;


  dataToStore->eepromState.writeCounter	  = ++oldDataToStore->eepromState.writeCounter;
  dataToStore->eepromState.structureSize  = sizeof(eeprom_stored_data_t);
  dataToStore->eepromState.revisionInfo	  = 0;
  dataToStore->eepromState.firstStartId = CONFIG_ID;

  dataToStore->deviceInfo.deviceInfoWritten	= resetToDefault == 1 ? 0 : oldDataToStore->deviceInfo.deviceInfoWritten;
  dataToStore->deviceInfo.SN				= resetToDefault == 1 ? 0 : oldDataToStore->deviceInfo.SN;

  /**************** PAGE_LÖSCHEN ********************/
  HAL_FLASH_Unlock();

  // check for PG bit set if so clear bit
  FLASH_WaitForLastOperation(1000);
  if(READ_BIT(FLASH->CR, FLASH_CR_PG)) CLEAR_BIT(FLASH->CR, FLASH_CR_PG);

  /* Fill EraseInit structure*/
  EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
  EraseInitStruct.Page        = FLASH_PAGE_NB - 1; //GetPage(USER_EEPROM_BASE_ADRESS);
  EraseInitStruct.NbPages     = 1;

  /* erase Sektoren daten dürfen nicht im instruction cache liegen  */
  uint32_t PageError;
  if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
  {
    while (1)
    {
      // ERROR HAL_FLASH_GetError() kann info geben
    }
  }

  /**************** IM_FLASH_SPEICHERN ********************/
  uint32_t Address;
  uint32_t x;

  /* programmiere uint64_t */
  Address = USER_EEPROM_BASE_ADRESS;
  x = 0;
  while (Address < (USER_EEPROM_BASE_ADRESS + SIZE_OF_DATA_TO_STORE))
  {
    if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, eepromData[x]) == HAL_OK)
    {
      Address += 8;
      x++;
    }
   else
    {
      /* Error occurred while writing data in Flash memory.
         User can add here some code to deal with this error */
      while (1)
      {
        // ERROR
      }
    }
  }

  /* Lock the Flash */
  HAL_FLASH_Lock();

  /****************AUSLESEN_UND_PRÜFEN********************/

  return EEPROM_readConfig(data);
}

HAL_StatusTypeDef EEPROM_storeConfig(sys_data_t* data, uint8_t withSN)
{
  eeprom_stored_data_t* dataToStore;
  uint32_t PageError;
  uint32_t Address;
  uint32_t x;
  /****************LESE_WERTE_AUS_SYSDATA*********************/
  printf("EEPROM STORE CONFIG!\n");
  dataToStore = (eeprom_stored_data_t*) eepromData;

  // Schnittstellenparameter
  dataToStore->changedData.baudrate = data->s.parameter.baudrate;
  dataToStore->changedData.parityMode =	data->s.parameter.parityMode;
  dataToStore->changedData.stopBits = data->s.parameter.stopBit;
  dataToStore->changedData.slave_adress = data->s.parameter.slave_address;
  dataToStore->changedData.ibn_day = data->s.parameter.ibn_day;
  dataToStore->changedData.ibn_month = data->s.parameter.ibn_month;
  dataToStore->changedData.ibn_year = data->s.parameter.ibn_year;
  dataToStore->changedData.user_id = data->s.parameter.user_id;

  // Offset und Gain
  dataToStore->changedData.batteryCurrentOffsetRefTemperatureChip = data->s.parameter.batteryCurrentOffsetRefTemperatureChip;
  dataToStore->changedData.batteryCurrentOffsetRefTemperatureShunt = data->s.parameter.batteryCurrentOffsetRefTemperatureShunt;

  dataToStore->changedData.batteryCurrentGainRefTempShunt = data->s.parameter.batteryCurrentGainRefTempShunt;
  dataToStore->changedData.batteryCurrentGainRefTempChip = data->s.parameter.batteryCurrentGainRefTempChip;
  dataToStore->changedData.batteryCurrentOffsetTemperatureCalibrationTemperature = data->s.parameter.batteryCurrentOffsetTemperatureCalibrationTemperature;
  dataToStore->changedData.batteryCurrentGainTemperatureCalibrationShuntTemperature = data->s.parameter.batteryCurrentGainTemperatureCalibrationShuntTemperature;
  dataToStore->changedData.batteryCurrentGainTemperatureCalibrationChipTemperature = data->s.parameter.batteryCurrentGainTemperatureCalibrationChipTemperature;
  dataToStore->changedData.batteryCurrentOffsetRefshuntVoltage = data->s.parameter.batteryCurrentOffsetRefshuntVoltage;

  dataToStore->changedData.batteryCurrentOffsetCommonModeCalibrationVoltage = data->s.parameter.batteryCurrentOffsetCommonModeCalibrationVoltage;
  dataToStore->changedData.batteryCurrentOffsetCommonModeCompensationFactor = data->s.parameter.batteryCurrentOffsetCommonModeCompensationFactor;
  dataToStore->changedData.batteryCurrentOffsetTemperatureCompensationFactor = data->s.parameter.batteryCurrentOffsetTemperatureCompensationFactor;
  dataToStore->changedData.batteryCurrentGainRefCurrent = data->s.parameter.batteryCurrentGainRefCurrent;
  dataToStore->changedData.batteryCurrentGainTemperatureCompensationShuntFactor = data->s.parameter.batteryCurrentGainTemperatureCompensationShuntFactor;
  dataToStore->changedData.batteryCurrentGainTemperatureCompensationChipFactor = data->s.parameter.batteryCurrentGainTemperatureCompensationChipFactor;

  dataToStore->changedData.currentOffset = data->s.parameter.batteryCurrentOffset;
  dataToStore->changedData.currentGain = data->s.parameter.batteryCurrentGainCorrectionFaktor;

  // AH COUNTER Einstellungen
  dataToStore->changedData.cef = data->s.parameter.cef;
  dataToStore->changedData.peukert = data->s.parameter.peukert;
  dataToStore->changedData.cellCapacity = data->s.parameter.cellCapacity;
  dataToStore->changedData.cellEnergy =	data->s.parameter.battEnergy;
  dataToStore->changedData.iBatFull = data->s.parameter.iBatFull;
  dataToStore->changedData.tBatFull = data->s.parameter.tBatFull;
  dataToStore->changedData.uBatFull = data->s.parameter.uBatFull;
  dataToStore->changedData.uBatEmpty = data->s.parameter.uBatEmpty;
  dataToStore->changedData.socCalcMode = data->s.parameter.socCalcMode;

  dataToStore->changedData.cellRatedDischargeTime = data->s.parameter.cellRatedDischargeTime;
  // Schaltausgänge
  dataToStore->changedData.lvpStart = data->s.parameter.lvpStart;
  dataToStore->changedData.lvpStop = data->s.parameter.lvpStop;
  dataToStore->changedData.ovpStart = data->s.parameter.ovpStart;
  dataToStore->changedData.ovpStop = data->s.parameter.ovpStop;
  dataToStore->changedData.loadCurrentLimit = data->s.parameter.loadCurrentLimit;
  dataToStore->changedData.chargeCurrentLimit =	data->s.parameter.chargeCurrentLimit;
  dataToStore->changedData.chargeStopHighTemperatureStart = data->s.parameter.chargeStopHighTemperatureStart;
  dataToStore->changedData.chargeStopHighTemperatureStop = data->s.parameter.chargeStopHighTemperatureStop;
  dataToStore->changedData.chargeStopLowTemperatureStart = data->s.parameter.chargeStopLowTemperatureStart;
  dataToStore->changedData.chargeStopLowTemperatureStop = data->s.parameter.chargeStopLowTemperatureStop;
  dataToStore->changedData.dischargeStopHighTemperatureStart = data->s.parameter.dischargeStopHighTemperatureStart;
  dataToStore->changedData.dischargeStopHighTemperatureStop = data->s.parameter.dischargeStopHighTemperatureStop;
  dataToStore->changedData.dischargeStopLowTemperatureStart = data->s.parameter.dischargeStopLowTemperatureStart;
  dataToStore->changedData.dischargeStopLowTemperatureStop = data->s.parameter.dischargeStopLowTemperatureStop;

  // Neue Parameter für SOC
  dataToStore->changedData.uBatEmptyCompStartTemp = data->s.parameter.uBatEmptyCompStartTemp;
  dataToStore->changedData.uBatEmptyCompStopTemp = data->s.parameter.uBatEmptyCompStopTemp;
  dataToStore->changedData.uBatEmptyCompStopVolt = data->s.parameter.uBatEmptyCompStopVolt;

  dataToStore->changedData.extraDischargeStrom_mA = data->s.parameter.extraDischargeStrom_mA;
  dataToStore->changedData.dischargeTotalAh = data->s.values.dischargeTotalAh;
  dataToStore->changedData.chargeTotalAh = data->s.values.chargeTotalAh;
  dataToStore->changedData.dischargeTotalWh = data->s.values.dischargeTotalWh;
  dataToStore->changedData.chargeTotalWh = data->s.values.chargeTotalWh;
  dataToStore->changedData.cefW = data->s.parameter.cefW;
  dataToStore->changedData.onTime = data->s.values.onTime;

  dataToStore->changedData.mAsCounter = data->s.values.mAsCounter;
  dataToStore->changedData.detectedCapacity = data->s.values.detectedCapacity;
  dataToStore->changedData.detectedEnergy = data->s.values.detectedEnergy;
  dataToStore->changedData.mAs_AutoMode = data->s.values.mAs_AutoMode;
  dataToStore->changedData.mWs_AutoMode = data->s.values.mWs_AutoMode;

  // Eeprom Status Infos
  dataToStore->eepromState.writeCounter++;
  dataToStore->eepromState.structureSize = sizeof(eeprom_stored_data_t);
  dataToStore->eepromState.revisionInfo = 0;
  dataToStore->eepromState.firstStartId = CONFIG_ID;

  if (withSN)
  {
    printf("Writing SN!\n");
    dataToStore->deviceInfo.SN = data->s.parameter.sn;
  }

  /****************PAGE_LÖSCHEN********************/
  HAL_FLASH_Unlock();

  // check for PG bit set if so clear bit
  FLASH_WaitForLastOperation(1000);
  if(READ_BIT(FLASH->CR, FLASH_CR_PG))
  {
    CLEAR_BIT(FLASH->CR, FLASH_CR_PG);
  }

  /* Fill EraseInit structure*/
  EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
  EraseInitStruct.Page        = FLASH_PAGE_NB - 1; //GetPage(USER_EEPROM_BASE_ADRESS);
  EraseInitStruct.NbPages     = 1;

  /* erase Sektoren daten dürfen nicht im instuction cache liegen  */
  if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
  {
    while (1)
    {
      // ERROR HAL_FLASH_GetError() kann info geben
    }
  }

  /****************IM_FLASH_SPEICHERN********************/

  /* programmiere uint64_t */
  Address = USER_EEPROM_BASE_ADRESS;
  x = 0;
  while (Address < (USER_EEPROM_BASE_ADRESS + SIZE_OF_DATA_TO_STORE))
  {
    if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, eepromData[x]) == HAL_OK)
    {
      Address += 8;
      x++;
    }
   else
    {
      /* Error occurred while writing data in Flash memory.
         User can add here some code to deal with this error */
      while (1)
      {
        // ERROR
      }
    }
  }

  /* Lock the Flash */
  HAL_FLASH_Lock();

  /****************AUSLESEN_UND_PRÜFEN********************/

  return EEPROM_readConfig(data);
}

//------------------------------------------------------------------------------

HAL_StatusTypeDef EEPROM_readConfig(sys_data_t* data)
{
  eeprom_stored_data_t* dataToStore;

  /****************WERTE_AUS_FLASH_LESEN********************/

  if (getEEPROMData(USER_EEPROM_BASE_ADRESS, (uint8_t*)eepromData, sizeof(eepromData)) != HAL_OK) return HAL_ERROR;

  dataToStore = (eeprom_stored_data_t*)eepromData;

  // Schnittstellenparameter
  data->s.parameter.baudrate													= dataToStore->changedData.baudrate;
  data->s.parameter.parityMode													= dataToStore->changedData.parityMode;
  data->s.parameter.stopBit														= dataToStore->changedData.stopBits;
  data->s.parameter.slave_address												= dataToStore->changedData.slave_adress;
  data->s.parameter.ibn_day														= dataToStore->changedData.ibn_day;
  data->s.parameter.ibn_month													= dataToStore->changedData.ibn_month;
  data->s.parameter.ibn_year													= dataToStore->changedData.ibn_year;
  data->s.parameter.user_id														= dataToStore->changedData.user_id;

  // Offset und Gain
  data->s.parameter.batteryCurrentOffsetRefTemperatureShunt						= dataToStore->changedData.batteryCurrentOffsetRefTemperatureShunt;
  data->s.parameter.batteryCurrentOffsetRefTemperatureChip						= dataToStore->changedData.batteryCurrentOffsetRefTemperatureChip;
  data->s.parameter.batteryCurrentGainRefTempShunt								= dataToStore->changedData.batteryCurrentGainRefTempShunt;
  data->s.parameter.batteryCurrentGainRefTempChip								= dataToStore->changedData.batteryCurrentGainRefTempChip;
  data->s.parameter.batteryCurrentOffsetTemperatureCalibrationTemperature		= dataToStore->changedData.batteryCurrentOffsetTemperatureCalibrationTemperature;
  data->s.parameter.batteryCurrentGainTemperatureCalibrationShuntTemperature	= dataToStore->changedData.batteryCurrentGainTemperatureCalibrationShuntTemperature;
  data->s.parameter.batteryCurrentGainTemperatureCalibrationChipTemperature		= dataToStore->changedData.batteryCurrentGainTemperatureCalibrationChipTemperature;
  data->s.parameter.batteryCurrentOffsetRefshuntVoltage							= dataToStore ->changedData.batteryCurrentOffsetRefshuntVoltage;
  data->s.parameter.batteryCurrentOffsetCommonModeCalibrationVoltage			= dataToStore->changedData.batteryCurrentOffsetCommonModeCalibrationVoltage;
  data->s.parameter.batteryCurrentOffsetCommonModeCompensationFactor			= dataToStore->changedData.batteryCurrentOffsetCommonModeCompensationFactor;
  data->s.parameter.batteryCurrentOffsetTemperatureCompensationFactor			= dataToStore->changedData.batteryCurrentOffsetTemperatureCompensationFactor;
  data->s.parameter.batteryCurrentGainRefCurrent								= dataToStore->changedData.batteryCurrentGainRefCurrent;
  data->s.parameter.batteryCurrentGainTemperatureCompensationShuntFactor		= dataToStore->changedData.batteryCurrentGainTemperatureCompensationShuntFactor;
  data->s.parameter.batteryCurrentGainTemperatureCompensationChipFactor			= dataToStore->changedData.batteryCurrentGainTemperatureCompensationChipFactor;
  data->s.parameter.batteryCurrentOffset										= dataToStore->changedData.currentOffset;
  data->s.parameter.batteryCurrentGainCorrectionFaktor							= dataToStore->changedData.currentGain;

  //Einstellungenm für AH counter
  data->s.parameter.cef															= dataToStore ->changedData.cef;
  data->s.parameter.peukert														= dataToStore ->changedData.peukert;
  data->s.parameter.cellCapacity												= dataToStore ->changedData.cellCapacity;
  data->s.parameter.battEnergy													= dataToStore ->changedData.cellEnergy;
  data->s.parameter.iBatFull													= dataToStore ->changedData.iBatFull;
  data->s.parameter.tBatFull													= dataToStore->changedData.tBatFull;
  data->s.parameter.uBatFull													= dataToStore->changedData.uBatFull;
  data->s.parameter.uBatEmpty													= dataToStore->changedData.uBatEmpty;
  data->s.parameter.socCalcMode													= dataToStore->changedData.socCalcMode;
  data->s.parameter.cellRatedDischargeTime										= dataToStore->changedData.cellRatedDischargeTime;

  // New EU directive says that cell Energy in Wh must be somwhere on the
  // visible part of the cell as well as capacity in Ah


  // Schaltausgänge
  data->s.parameter.lvpStart													= dataToStore->changedData.lvpStart;
  data->s.parameter.lvpStop														= dataToStore->changedData.lvpStop;
  data->s.parameter.ovpStart													= dataToStore->changedData.ovpStart;
  data->s.parameter.ovpStop														= dataToStore->changedData.ovpStop;
  data->s.parameter.loadCurrentLimit											= dataToStore->changedData.loadCurrentLimit;
  data->s.parameter.chargeCurrentLimit											= dataToStore->changedData.chargeCurrentLimit;
  data->s.parameter.chargeStopHighTemperatureStart								= dataToStore->changedData.chargeStopHighTemperatureStart;
  data->s.parameter.chargeStopHighTemperatureStop								= dataToStore->changedData.chargeStopHighTemperatureStop;
  data->s.parameter.chargeStopLowTemperatureStart								= dataToStore->changedData.chargeStopLowTemperatureStart;
  data->s.parameter.chargeStopLowTemperatureStop								= dataToStore->changedData.chargeStopLowTemperatureStop;
  data->s.parameter.dischargeStopHighTemperatureStart							= dataToStore->changedData.dischargeStopHighTemperatureStart;
  data->s.parameter.dischargeStopHighTemperatureStop							= dataToStore->changedData.dischargeStopHighTemperatureStop;
  data->s.parameter.dischargeStopLowTemperatureStart							= dataToStore->changedData.dischargeStopLowTemperatureStart;
  data->s.parameter.dischargeStopLowTemperatureStop								= dataToStore->changedData.dischargeStopLowTemperatureStop;

  data->s.parameter.uBatEmptyCompStartTemp										= dataToStore->changedData.uBatEmptyCompStartTemp;
  data->s.parameter.uBatEmptyCompStopTemp										= dataToStore->changedData.uBatEmptyCompStopTemp;
  data->s.parameter.uBatEmptyCompStopVolt										= dataToStore->changedData.uBatEmptyCompStopVolt;

  data->s.parameter.extraDischargeStrom_mA										= dataToStore->changedData.extraDischargeStrom_mA;
  data->s.values.dischargeTotalAh												= dataToStore->changedData.dischargeTotalAh;
  data->s.values.chargeTotalAh													= dataToStore->changedData.chargeTotalAh;
  data->s.values.dischargeTotalWh												= dataToStore->changedData.dischargeTotalWh;
  data->s.values.chargeTotalWh													= dataToStore->changedData.chargeTotalWh;
  data->s.parameter.cefW														= dataToStore ->changedData.cefW;
  data->s.values.onTime															= dataToStore->changedData.onTime;

  data->s.values.mAsCounter														= dataToStore->changedData.mAsCounter;
  data->s.values.detectedCapacity												= dataToStore->changedData.detectedCapacity;
  data->s.values.detectedEnergy													= dataToStore->changedData.detectedEnergy;
  data->s.values.mAs_AutoMode													= dataToStore->changedData.mAs_AutoMode;
  data->s.values.mWs_AutoMode													= dataToStore->changedData.mWs_AutoMode;

  //  Geräteinformation
  data->s.parameter.sn															= dataToStore->deviceInfo.SN;

  // prüfe Eeprom Status Infos
  //dataToStore->eepromState.writeCounter ++ ;
  if (dataToStore->eepromState.structureSize != sizeof(eeprom_stored_data_t)) return HAL_ERROR;
  if (dataToStore->eepromState.revisionInfo != 0) return HAL_ERROR;
  if (dataToStore->eepromState.firstStartId != CONFIG_ID) return HAL_ERROR;

  return HAL_OK;
}
