20static constexpr uint32_t ESP_RTC_USER_MEM_START = 0x60001200;
21static constexpr uint32_t ESP_RTC_USER_MEM_SIZE_WORDS = RTC_USER_MEM_WORDS;
22static constexpr uint32_t ESP_RTC_USER_MEM_SIZE_BYTES = ESP_RTC_USER_MEM_SIZE_WORDS * 4;
28static constexpr uint32_t RTC_EBOOT_REGION_WORDS = ESP8266_PREFERENCES_RTC_EBOOT_WORDS;
29static constexpr uint32_t RTC_NORMAL_REGION_WORDS = ESP8266_PREFERENCES_RTC_NORMAL_WORDS;
30static constexpr uint32_t PREF_TOTAL_WORDS = RTC_EBOOT_REGION_WORDS + RTC_NORMAL_REGION_WORDS;
31static_assert(PREF_TOTAL_WORDS <= RTC_CRASH_BASE - RTC_SYSTEM_USER_BASE,
32 "preference regions overlap the crash handler's RTC words");
35static constexpr uint32_t MAX_PREFERENCE_WORDS = 255;
37#define ESP_RTC_USER_MEM ((uint32_t *) ESP_RTC_USER_MEM_START)
40static constexpr uint32_t ESP8266_FLASH_STORAGE_SIZE = ESP8266_PREFERENCES_FLASH_WORDS;
43 s_flash_storage[ESP8266_FLASH_STORAGE_SIZE];
44static bool s_prevent_write =
false;
45static bool s_flash_dirty =
false;
48 if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) {
52 *dest = ESP_RTC_USER_MEM[index];
57 if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) {
60 if (index < RTC_EBOOT_REGION_WORDS && s_prevent_write) {
64 auto *
ptr = &ESP_RTC_USER_MEM[index];
72static uint32_t get_esp8266_flash_sector() {
78 return (data.uint - 0x40200000) / SPI_FLASH_SEC_SIZE;
80static uint32_t get_esp8266_flash_address() {
return get_esp8266_flash_sector() * SPI_FLASH_SEC_SIZE; }
82static bool save_to_flash(
size_t offset,
const uint32_t *data,
size_t len) {
85 if (j >= ESP8266_FLASH_STORAGE_SIZE)
96static bool load_from_flash(
size_t offset,
uint32_t *data,
size_t len) {
97 for (
size_t i = 0; i <
len; i++) {
99 if (j >= ESP8266_FLASH_STORAGE_SIZE)
101 data[i] = s_flash_storage[
j];
106static bool save_to_rtc(
size_t offset,
const uint32_t *data,
size_t len) {
108 if (!esp_rtc_user_mem_write(offset + i, data[i]))
114static bool load_from_rtc(
size_t offset,
uint32_t *data,
size_t len) {
116 if (!esp_rtc_user_mem_read(offset + i, &data[i]))
125static constexpr size_t PREF_MAX_BUFFER_WORDS =
126 ESP8266_FLASH_STORAGE_SIZE > RTC_NORMAL_REGION_WORDS ? ESP8266_FLASH_STORAGE_SIZE : RTC_NORMAL_REGION_WORDS;
131 const size_t buffer_size =
static_cast<size_t>(this->
length_words) + 1;
132 if (buffer_size > PREF_MAX_BUFFER_WORDS)
136 return this->
in_flash ? save_to_flash(this->offset,
buffer, buffer_size)
137 : save_to_rtc(this->offset,
buffer, buffer_size);
143 const size_t buffer_size =
static_cast<size_t>(this->
length_words) + 1;
144 if (buffer_size > PREF_MAX_BUFFER_WORDS)
148 : load_from_rtc(this->offset,
buffer, buffer_size);
155 ESP_LOGVV(TAG,
"Loading preferences from flash");
159 spi_flash_read(get_esp8266_flash_address(), s_flash_storage, ESP8266_FLASH_STORAGE_SIZE * 4);
165 if (length_words > MAX_PREFERENCE_WORDS) {
166 ESP_LOGE(TAG,
"Preference too large: %u words",
static_cast<unsigned int>(length_words));
170 const uint32_t total_words = length_words + 1;
180 bool in_normal = start < RTC_NORMAL_REGION_WORDS;
183 if (in_normal && start + total_words > RTC_NORMAL_REGION_WORDS) {
188 if (start + total_words > PREF_TOTAL_WORDS)
191 offset =
static_cast<uint16_t
>(in_normal ? start + RTC_EBOOT_REGION_WORDS : start - RTC_NORMAL_REGION_WORDS);
196 pref->offset = offset;
198 pref->length_words =
static_cast<uint8_t
>(length_words);
199 pref->in_flash = in_flash;
209 ESP_LOGD(TAG,
"Saving");
210 SpiFlashOpResult erase_res, write_res = SPI_FLASH_RESULT_OK;
213 erase_res = spi_flash_erase_sector(get_esp8266_flash_sector());
214 if (erase_res == SPI_FLASH_RESULT_OK) {
215 write_res = spi_flash_write(get_esp8266_flash_address(), s_flash_storage, ESP8266_FLASH_STORAGE_SIZE * 4);
218 if (erase_res != SPI_FLASH_RESULT_OK) {
219 ESP_LOGE(TAG,
"Erasing failed");
222 if (write_res != SPI_FLASH_RESULT_OK) {
223 ESP_LOGE(TAG,
"Writing failed");
227 s_flash_dirty =
false;
232 ESP_LOGD(TAG,
"Erasing storage");
233 SpiFlashOpResult erase_res;
236 erase_res = spi_flash_erase_sector(get_esp8266_flash_sector());
238 if (erase_res != SPI_FLASH_RESULT_OK) {
239 ESP_LOGE(TAG,
"Erasing failed");
244 s_prevent_write =
true;
253 s_preferences.
setup();
Helper class to disable interrupts.
bool save(const uint8_t *data, size_t len)
bool load(uint8_t *data, size_t len)
uint32_t current_flash_offset
ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)
static void int int int int const uint8_t * ptr
ESPHOME_LOG_TAG(TAG, "esp8266")
void preferences_prevent_write(bool prevent)
ESP8266Preferences * get_preferences()
std::span< const uint8_t > data
value[LAYOUT.day_index()]
Preferences ESPPreferences
size_t rtc_pref_bytes_to_words(size_t bytes)
Round a byte count up to whole 32-bit words.
bool rtc_pref_decode(const uint32_t *buffer, uint32_t type, uint8_t length_words, uint8_t *data, size_t len)
Verify the checksum of a record held in buffer (length_words data words + 1 checksum word) and,...
ESPPreferences * global_preferences
void rtc_pref_encode(uint32_t *buffer, uint32_t type, uint8_t length_words, const uint8_t *data, size_t len)
Encode len data bytes into buffer (length_words data words + 1 trailing checksum word).