// // Created by MightyPork on 2017/07/09. // #include "persist.h" #include #include "wifimgr.h" #include "screen.h" PersistBlock persist; #define PERSIST_SECTOR_ID 0x3D //region Persist and restore individual modules static void ICACHE_FLASH_ATTR apply_live_settings(void) { persist_dbg("[Persist] Applying live settings..."); persist_dbg("[Persist] > system"); sysconf_apply_settings(); persist_dbg("[Persist] > wifi"); wifimgr_apply_settings(); persist_dbg("[Persist] > terminal"); terminal_apply_settings(); persist_dbg("[Persist] Live settings applied."); // ... } static void ICACHE_FLASH_ATTR restore_live_settings_to_hard_defaults(void) { persist_dbg("[Persist] Restore to hard defaults..."); persist_dbg("[Persist] > system"); sysconf_restore_defaults(); persist_dbg("[Persist] > wifi"); wifimgr_restore_defaults(); persist_dbg("[Persist] > terminal"); terminal_restore_defaults(); persist_dbg("[Persist] Restored to hard defaults."); // ... } //endregion const u32 wconf_at = (u32)&persist.defaults.wificonf - (u32)&persist.defaults; const u32 tconf_at = (u32)&persist.defaults.termconf - (u32)&persist.defaults; const u32 sconf_at = (u32)&persist.defaults.sysconf - (u32)&persist.defaults; const u32 cksum_at = (u32)&persist.defaults.checksum - (u32)&persist.defaults; /** * Compute CRC32. Adapted from https://github.com/esp8266/Arduino * @param data * @param length * @return crc32 */ static uint32_t ICACHE_FLASH_ATTR calculateCRC32(const uint8_t *data, size_t length) { // the salt here should ensure settings are wiped when the structure changes // CHECKSUM_SALT can be adjusted manually to force a reset. uint32_t crc = 0xffffffff + CHECKSUM_SALT + ((wconf_at << 16) ^ (tconf_at << 10) ^ (sconf_at << 5)); while (length--) { uint8_t c = *data++; for (uint32_t i = 0x80; i > 0; i >>= 1) { bool bit = (bool) (crc & 0x80000000UL); if (c & i) { bit = !bit; } crc <<= 1; if (bit) { crc ^= 0x04c11db7UL; } } } return crc; } /** * Compute a persist bundle checksum * * @param bundle * @return */ static uint32_t ICACHE_FLASH_ATTR compute_checksum(AppConfigBundle *bundle) { // this should be the bundle without the checksum return calculateCRC32((uint8_t *) bundle, sizeof(AppConfigBundle) - 4); } static void ICACHE_FLASH_ATTR set_admin_block_defaults(void) { persist_info("[Persist] Initing admin config block"); strcpy(persist.admin.pw, DEFAULT_ADMIN_PW); persist.admin.version = ADMINCONF_VERSION; } /** * Load, verify and apply persistent config */ void ICACHE_FLASH_ATTR persist_load(void) { persist_info("[Persist] Loading settings from FLASH..."); persist_dbg("Persist memory map:"); persist_dbg("> wifi at %4d (error %2d)", wconf_at, wconf_at - 0); persist_dbg("> sys at %4d (error %2d)", sconf_at, sconf_at - WIFICONF_SIZE); persist_dbg("> term at %4d (error %2d)", tconf_at, tconf_at - WIFICONF_SIZE - SYSCONF_SIZE); persist_dbg("> cksum at %4d (error %2d)", cksum_at, cksum_at - (APPCONF_SIZE - 4)); persist_dbg("> Total size = %d bytes (error %d)", sizeof(AppConfigBundle), APPCONF_SIZE - sizeof(AppConfigBundle)); bool hard_reset = false; // Try to load hard_reset |= !system_param_load(PERSIST_SECTOR_ID, 0, &persist, sizeof(PersistBlock)); // Verify checksums if (hard_reset || (compute_checksum(&persist.defaults) != persist.defaults.checksum) || (compute_checksum(&persist.current) != persist.current.checksum) || (persist.admin.version != 0 && (calculateCRC32((uint8_t *) &persist.admin, sizeof(AdminConfigBlock) - 4) != persist.admin.checksum))) { error("[Persist] Checksum verification: FAILED"); hard_reset = true; } else { persist_info("[Persist] Checksum verification: PASSED"); } if (hard_reset) { // Zero all out memset(&persist, 0, sizeof(PersistBlock)); persist_load_hard_default(); // write them also as defaults memcpy(&persist.defaults, &persist.current, sizeof(AppConfigBundle)); // reset admin pw set_admin_block_defaults(); persist_store(); // this also stores them to flash and applies to modules } else { if (persist.admin.version == 0) { set_admin_block_defaults(); persist_store(); } apply_live_settings(); } persist_info("[Persist] All settings loaded and applied."); } void ICACHE_FLASH_ATTR persist_store(void) { persist_info("[Persist] Storing all settings to FLASH..."); // Update checksums before write persist.current.checksum = compute_checksum(&persist.current); persist.defaults.checksum = compute_checksum(&persist.defaults); persist.admin.checksum = calculateCRC32((uint8_t *) &persist.admin, sizeof(AdminConfigBlock) - 4); if (!system_param_save_with_protect(PERSIST_SECTOR_ID, &persist, sizeof(PersistBlock))) { error("[Persist] Store to flash failed!"); } persist_info("[Persist] All settings persisted."); } /** * Restore to built-in defaults */ void ICACHE_FLASH_ATTR persist_load_hard_default(void) { persist_info("[Persist] Restoring live settings to hard defaults..."); // Set live config to default values restore_live_settings_to_hard_defaults(); persist_store(); persist_info("[Persist] Settings restored to hard defaults."); apply_live_settings(); // apply } /** * Restore default settings & apply. also persists. */ void ICACHE_FLASH_ATTR persist_restore_default(void) { persist_info("[Persist] Restoring live settings to stored defaults..."); memcpy(&persist.current, &persist.defaults, sizeof(AppConfigBundle)); apply_live_settings(); persist_store(); persist_info("[Persist] Settings restored to stored defaults."); } /** * Store current settings as defaults & write to flash */ void ICACHE_FLASH_ATTR persist_set_as_default(void) { persist_info("[Persist] Storing live settings as defaults.."); // current -> defaults memcpy(&persist.defaults, &persist.current, sizeof(AppConfigBundle)); persist_store(); persist_info("[Persist] Default settings updated."); }