/* EEPROM MODULE */ #include "espurna.h" #include EEPROM_Rotate EEPROMr; namespace { bool _eeprom_commit = false; uint32_t _eeprom_commit_count = 0; bool _eeprom_last_commit_result = false; bool _eeprom_ready = false; } // namespace bool eepromReady() { return _eeprom_ready; } void eepromRotate(bool value) { // Enable/disable EEPROM rotation only if we are using more sectors than the // reserved by the memory layout if (EEPROMr.size() > EEPROMr.reserved()) { // Because .rotate(false) marks EEPROM as dirty, this is equivalent to the .backup(0) DEBUG_MSG_P(PSTR("[EEPROM] %s EEPROM rotation\n"), value ? "Enabling" : "Disabling"); EEPROMr.rotate(value); eepromCommit(); } } uint32_t eepromCurrent() { return EEPROMr.current(); } String eepromSectors() { String response; for (uint32_t i = 0; i < EEPROMr.size(); i++) { if (i > 0) response = response + String(", "); response = response + String(EEPROMr.base() - i); } return response; } void eepromSectorsDebug() { DEBUG_MSG_P(PSTR("[MAIN] EEPROM sectors: %s\n"), (char *) eepromSectors().c_str()); DEBUG_MSG_P(PSTR("[MAIN] EEPROM current: %lu\n"), eepromCurrent()); } bool _eepromCommit() { _eeprom_commit_count++; _eeprom_last_commit_result = EEPROMr.commit(); return _eeprom_last_commit_result; } void eepromForceCommit() { _eepromCommit(); } void eepromCommit() { _eeprom_commit = true; } void eepromBackup(uint32_t index){ EEPROMr.backup(index); } #if TERMINAL_SUPPORT void _eepromInitCommands() { terminalRegisterCommand(F("EEPROM"), [](const terminal::CommandContext& ctx) { ctx.output.printf_P(PSTR("Sectors: %s, current: %lu\n"), eepromSectors().c_str(), eepromCurrent()); if (_eeprom_commit_count > 0) { ctx.output.printf_P(PSTR("Commits done: %lu, last: %s\n"), _eeprom_commit_count, _eeprom_last_commit_result ? "OK" : "ERROR"); } terminalOK(ctx); }); terminalRegisterCommand(F("EEPROM.COMMIT"), [](const terminal::CommandContext& ctx) { _eepromCommit(); terminalOK(ctx); }); terminalRegisterCommand(F("EEPROM.DUMP"), [](const terminal::CommandContext& ctx) { EEPROMr.dump(static_cast(ctx.output)); // XXX: only Print interface is used terminalOK(ctx.output); }); terminalRegisterCommand(F("FLASH.DUMP"), [](const terminal::CommandContext& ctx) { if (ctx.argc < 2) { terminalError(F("Wrong arguments")); return; } uint32_t sector = ctx.argv[1].toInt(); uint32_t max = ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE; if (sector >= max) { terminalError(F("Sector out of range")); return; } EEPROMr.dump(static_cast(ctx.output), sector); // XXX: only Print interface is used terminalOK(ctx.output); }); } #endif // ----------------------------------------------------------------------------- void eepromLoop() { if (_eeprom_commit) { _eepromCommit(); _eeprom_commit = false; } } void eepromSetup() { #ifdef EEPROM_ROTATE_SECTORS EEPROMr.size(EEPROM_ROTATE_SECTORS); #else // If the memory layout has more than one sector reserved use those, // otherwise calculate pool size based on memory size. if (EEPROMr.size() == 1) { if (EEPROMr.last() > 1000) { // 4Mb boards EEPROMr.size(4); } else if (EEPROMr.last() > 250) { // 1Mb boards EEPROMr.size(2); } } #endif EEPROMr.offset(EepromRotateOffset); EEPROMr.begin(EepromSize); #if TERMINAL_SUPPORT _eepromInitCommands(); #endif espurnaRegisterLoop(eepromLoop); _eeprom_ready = true; }