#include "eeprom.h" I2C_eeprom ee(I2C_EE_ADDRESS, EEPROM_SIZE_BYTES); configData_t ConfigData; persistenceData_t PersistenceData; bool eeAvailable = false; bool checkEEPROMavailable(); bool ValidateEEPROM_Version(); bool MigrateEEPROM(uint8_t fromVersion); void InitEEPROM() { ee.begin(); eeAvailable = checkEEPROMavailable(); eeAvailable = ValidateEEPROM_Version(); Serial.printf("Initialized EEPROM at Address 0x%02X\n", I2C_EE_ADDRESS); } void EEPROM_Process() { if (eeAvailable == false) return; switch (globals.requestEEAction) { case EE_CFG_SAVE: StoreConfig_EEPROM(); globals.requestEEAction = EE_IDLE; Serial.println("Stored EEPROM CFG"); break; case EE_CFG_LOAD: GetConfig_EEPROM(); globals.requestEEAction = EE_IDLE; Serial.println("Loaded EEPROM CFG"); break; case EE_CFG_FORMAT: FormatConfig_EEPROM(); globals.requestEEAction = EE_IDLE; globals.systemStatus = sysStat_Shutdown; Serial.println("Formated EEPROM CFG"); break; case EE_PDS_SAVE: StorePersistence_EEPROM(); globals.requestEEAction = EE_IDLE; Serial.println("Stored EEPROM PDS"); break; case EE_PDS_LOAD: GetPersistence_EEPROM(); globals.requestEEAction = EE_IDLE; Serial.println("Loaded EEPROM PDS"); break; case EE_PDS_FORMAT: FormatPersistence_EEPROM(); globals.requestEEAction = EE_IDLE; Serial.println("Formated EEPROM PDS"); break; case EE_FORMAT_ALL: FormatConfig_EEPROM(); FormatPersistence_EEPROM(); globals.requestEEAction = EE_IDLE; Serial.println("Formated EEPROM ALL"); break; case EE_ALL_SAVE: StorePersistence_EEPROM(); StoreConfig_EEPROM(); globals.requestEEAction = EE_IDLE; Serial.println("Stored EEPROM ALL"); break; case EE_IDLE: default: globals.requestEEAction = EE_IDLE; } } void StoreConfig_EEPROM() { if (eeAvailable == false) return; ConfigData.checksum = 0; ConfigData.checksum = Checksum_EEPROM((uint8_t *)&ConfigData, sizeof(ConfigData)); ee.updateBlock(startofConfigData, (uint8_t *)&ConfigData, sizeof(ConfigData)); } void GetConfig_EEPROM() { if (eeAvailable == false) return; ee.readBlock(startofConfigData, (uint8_t *)&ConfigData, sizeof(ConfigData)); uint32_t checksum = ConfigData.checksum; ConfigData.checksum = 0; if (Checksum_EEPROM((uint8_t *)&ConfigData, sizeof(ConfigData)) != checksum) { MaintainDTC(DTC_EEPROM_CFG_BAD, DTC_CRITICAL, true); } ConfigData.checksum = checksum; uint32_t ConfigSanityCheckResult = ConfigSanityCheck(false); if (ConfigSanityCheckResult > 0) { MaintainDTC(DTC_EEPROM_CFG_SANITY, DTC_WARN, true, ConfigSanityCheckResult); globals.requestEEAction = EE_CFG_SAVE; } } void StorePersistence_EEPROM() { if (eeAvailable == false) return; if (PersistenceData.writeCycleCounter >= 0xFFF0) MovePersistencePage_EEPROM(false); else PersistenceData.writeCycleCounter++; PersistenceData.checksum = 0; PersistenceData.checksum = Checksum_EEPROM((uint8_t *)&PersistenceData, sizeof(PersistenceData)); ee.updateBlock(globals.eePersistanceAdress, (uint8_t *)&PersistenceData, sizeof(PersistenceData)); } void GetPersistence_EEPROM() { if (eeAvailable == false) return; ee.readBlock(0, (uint8_t *)&globals.eePersistanceAdress, sizeof(globals.eePersistanceAdress)); // if we got the StartAdress of Persistance and it's out of Range - we Reset it and store defaults // otherwise we Read from eeprom and check if everything is correct if (globals.eePersistanceAdress < startofPersistence || globals.eePersistanceAdress > ee.getDeviceSize()) { MovePersistencePage_EEPROM(true); FormatPersistence_EEPROM(); MaintainDTC(DTC_EEPROM_PDSADRESS_BAD, DTC_CRITICAL, true); } else { ee.readBlock(globals.eePersistanceAdress, (uint8_t *)&PersistenceData, sizeof(PersistenceData)); uint32_t checksum = PersistenceData.checksum; PersistenceData.checksum = 0; if (Checksum_EEPROM((uint8_t *)&PersistenceData, sizeof(PersistenceData)) != checksum) { MaintainDTC(DTC_EEPROM_PDS_BAD, DTC_CRITICAL, true); } PersistenceData.checksum = checksum; } } void FormatConfig_EEPROM() { if (eeAvailable == false) return; Serial.println("Formatting Config-Partition"); ConfigData = ConfigData_defaults; StoreConfig_EEPROM(); GetConfig_EEPROM(); } void FormatPersistence_EEPROM() { if (eeAvailable == false) return; Serial.println("Formatting Persistance-Partition"); PersistenceData = {0}; StorePersistence_EEPROM(); GetPersistence_EEPROM(); } void MovePersistencePage_EEPROM(boolean reset) { if (eeAvailable == false) return; globals.eePersistanceAdress = +sizeof(PersistenceData); PersistenceData.writeCycleCounter = 0; // check if we reached the End of the EEPROM and Startover at the beginning if ((globals.eePersistanceAdress + sizeof(PersistenceData)) > ee.getDeviceSize() || reset) { globals.eePersistanceAdress = startofPersistence; } ee.updateBlock(0, (uint8_t *)&globals.eePersistanceAdress, sizeof(globals.eePersistanceAdress)); } uint32_t Checksum_EEPROM(uint8_t const *data, size_t len) { if (data == NULL) return 0; uint32_t crc, mask; crc = 0xFFFFFFFF; while (len--) { crc ^= *data++; for (uint8_t k = 0; k < 8; k++) { mask = -(crc & 1); crc = (crc >> 1) ^ (0xEDB88320 & mask); } } return ~crc; } void dumpEEPROM(uint16_t memoryAddress, uint16_t length) { #define BLOCK_TO_LENGTH 16 if (eeAvailable == false) return; char ascii_buf[BLOCK_TO_LENGTH + 1]; sprintf(ascii_buf, "%*s", BLOCK_TO_LENGTH, "ASCII"); Serial.print(PSTR("\nAddress ")); for (int x = 0; x < BLOCK_TO_LENGTH; x++) Serial.printf("%3d", x); memoryAddress = memoryAddress / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH; length = (length + BLOCK_TO_LENGTH - 1) / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH; for (unsigned int i = 0; i < length; i++) { int blockpoint = memoryAddress % BLOCK_TO_LENGTH; if (blockpoint == 0) { ascii_buf[BLOCK_TO_LENGTH] = 0; Serial.printf(" %s", ascii_buf); Serial.printf("\n0x%05X:", memoryAddress); } ascii_buf[blockpoint] = ee.readByte(memoryAddress); Serial.printf(" %02X", ascii_buf[blockpoint]); if (ascii_buf[blockpoint] < 0x20 || ascii_buf[blockpoint] > 0x7E) ascii_buf[blockpoint] = '.'; memoryAddress++; } Serial.println(); } bool checkEEPROMavailable() { if (!ee.isConnected()) { MaintainDTC(DTC_NO_EEPROM_FOUND, DTC_CRITICAL, true); return false; } return true; } uint32_t ConfigSanityCheck(bool autocorrect) { uint32_t setting_reset_bits = 0; if ((ConfigData.batteryType != BATTERY_LIPO_2S) || (ConfigData.batteryType != BATTERY_LIPO_3S)) { setting_reset_bits = setting_reset_bits | (1 << 0); if (autocorrect) ConfigData.batteryType = ConfigData_defaults.batteryType; } return setting_reset_bits; } bool ValidateEEPROM_Version() { if (eeAvailable == false) return false; uint8_t EEPROMVersionOnChip = ee.readByte(startofConfigData); if (EEPROMVersionOnChip < ConfigData_defaults.EEPROM_Version) { Serial.printf("EEPROM Image Version is %d, but %d expected - trying to migrate\n", EEPROMVersionOnChip, ConfigData_defaults.EEPROM_Version); if (!MigrateEEPROM(EEPROMVersionOnChip)) { Serial.print("Error\n"); MaintainDTC(DTC_EEPROM_MIGRATE_FAILED, DTC_CRITICAL, true, EEPROMVersionOnChip); return false; } else { Serial.print("Success\n"); } } return true; } bool MigrateEEPROM(uint8_t fromVersion) { uint16_t persistanceMarker_onChip; switch (fromVersion) { // Version 1 EEPROM Layout: startAdress size (byte) // const uint16_t startofConfigData = 16 16 // const uint16_t startofPersistence = 32 24 // // typedef struct // { // uint8_t EEPROM_Version = 1; 16 1 // batteryType_t batteryType = BATTERY_UNDEFINED; 17 4 // bool active_faction_on_reboot = false; 21 1 // uint32_t checksum = 0; 22 4 // } configData_t; // // typedef struct offset // { // uint32_t writeCycleCounter = 0; 0 4 // uint32_t faction_1_timer = 0; 4 4 // uint32_t faction_2_timer = 0; 8 4 // uint32_t faction_3_timer = 0; 12 4 // factions_t activeFaction = NONE; 16 4 // uint32_t checksum = 0; 20 4 // } persistenceData_t; case 1: // Migrate Persistance-Data ee.readBlock(0, (uint8_t *)&persistanceMarker_onChip, sizeof(uint16_t)); if (persistanceMarker_onChip < startofPersistence) { ee.readBlock(persistanceMarker_onChip + 0, (uint8_t *)&PersistenceData.writeCycleCounter, 4); ee.readBlock(persistanceMarker_onChip + 4, (uint8_t *)&PersistenceData.faction_1_timer, 4); ee.readBlock(persistanceMarker_onChip + 8, (uint8_t *)&PersistenceData.faction_2_timer, 4); ee.readBlock(persistanceMarker_onChip + 12, (uint8_t *)&PersistenceData.faction_3_timer, 4); ee.readBlock(persistanceMarker_onChip + 16, (uint8_t *)&PersistenceData.activeFaction, 4); ee.readBlock(persistanceMarker_onChip + 20, (uint8_t *)&PersistenceData.checksum, 4); MovePersistencePage_EEPROM(true); StorePersistence_EEPROM(); } // Migrate Config-Data and set defaults for Values which doesn't exists in this earlier Version ConfigData.EEPROM_Version = ConfigData_defaults.EEPROM_Version; strncpy(ConfigData.Faction_1_Name, ConfigData_defaults.Faction_1_Name, sizeof(ConfigData.Faction_1_Name)); strncpy(ConfigData.Faction_2_Name, ConfigData_defaults.Faction_2_Name, sizeof(ConfigData.Faction_2_Name)); strncpy(ConfigData.Faction_3_Name, ConfigData_defaults.Faction_3_Name, sizeof(ConfigData.Faction_3_Name)); ee.readBlock(17, (uint8_t *)&ConfigData.batteryType, 4); ee.readBlock(21, (uint8_t *)&ConfigData.active_faction_on_reboot, 1); StoreConfig_EEPROM(); return true; break; default: return false; break; } }