17static const char *
const TAG =
"preferences";
19static constexpr uint32_t ESP_RTC_USER_MEM_START = 0x60001200;
20static constexpr uint32_t ESP_RTC_USER_MEM_SIZE_WORDS = 128;
21static constexpr uint32_t ESP_RTC_USER_MEM_SIZE_BYTES = ESP_RTC_USER_MEM_SIZE_WORDS * 4;
27static constexpr uint32_t RTC_EBOOT_REGION_WORDS = 32;
28static constexpr uint32_t RTC_NORMAL_REGION_WORDS = 78;
29static constexpr uint32_t PREF_TOTAL_WORDS = RTC_EBOOT_REGION_WORDS + RTC_NORMAL_REGION_WORDS;
32static constexpr uint32_t MAX_PREFERENCE_WORDS = 255;
34#define ESP_RTC_USER_MEM ((uint32_t *) ESP_RTC_USER_MEM_START)
40#ifdef USE_ESP8266_PREFERENCES_FLASH
41static constexpr uint32_t ESP8266_FLASH_STORAGE_SIZE = 128;
43static constexpr uint32_t ESP8266_FLASH_STORAGE_SIZE = 64;
47 s_flash_storage[ESP8266_FLASH_STORAGE_SIZE];
48static bool s_prevent_write =
false;
49static bool s_flash_dirty =
false;
52 if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) {
55 *dest = ESP_RTC_USER_MEM[index];
60 if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) {
63 if (index < 32 && s_prevent_write) {
67 auto *ptr = &ESP_RTC_USER_MEM[index];
74static uint32_t get_esp8266_flash_sector() {
80 return (data.uint - 0x40200000) / SPI_FLASH_SEC_SIZE;
82static uint32_t get_esp8266_flash_address() {
return get_esp8266_flash_sector() * SPI_FLASH_SEC_SIZE; }
84static bool save_to_flash(
size_t offset,
const uint32_t *data,
size_t len) {
87 if (j >= ESP8266_FLASH_STORAGE_SIZE)
98static bool load_from_flash(
size_t offset,
uint32_t *data,
size_t len) {
99 for (
size_t i = 0; i <
len; i++) {
101 if (j >= ESP8266_FLASH_STORAGE_SIZE)
103 data[i] = s_flash_storage[
j];
108static bool save_to_rtc(
size_t offset,
const uint32_t *data,
size_t len) {
110 if (!esp_rtc_user_mem_write(offset + i, data[i]))
116static bool load_from_rtc(
size_t offset,
uint32_t *data,
size_t len) {
118 if (!esp_rtc_user_mem_read(offset + i, &data[i]))
127static constexpr size_t PREF_MAX_BUFFER_WORDS =
128 ESP8266_FLASH_STORAGE_SIZE > RTC_NORMAL_REGION_WORDS ? ESP8266_FLASH_STORAGE_SIZE : RTC_NORMAL_REGION_WORDS;
133 const size_t buffer_size =
static_cast<size_t>(this->
length_words) + 1;
134 if (buffer_size > PREF_MAX_BUFFER_WORDS)
136 uint32_t buffer[PREF_MAX_BUFFER_WORDS];
138 return this->
in_flash ? save_to_flash(this->offset, buffer, buffer_size)
139 : save_to_rtc(this->offset, buffer, buffer_size);
145 const size_t buffer_size =
static_cast<size_t>(this->
length_words) + 1;
146 if (buffer_size > PREF_MAX_BUFFER_WORDS)
148 uint32_t buffer[PREF_MAX_BUFFER_WORDS];
149 bool ret = this->
in_flash ? load_from_flash(this->offset, buffer, buffer_size)
150 : load_from_rtc(this->offset, buffer, buffer_size);
157 ESP_LOGVV(TAG,
"Loading preferences from flash");
161 spi_flash_read(get_esp8266_flash_address(), s_flash_storage, ESP8266_FLASH_STORAGE_SIZE * 4);
167 if (length_words > MAX_PREFERENCE_WORDS) {
168 ESP_LOGE(TAG,
"Preference too large: %u words",
static_cast<unsigned int>(length_words));
172 const uint32_t total_words = length_words + 1;
182 bool in_normal = start < RTC_NORMAL_REGION_WORDS;
185 if (in_normal && start + total_words > RTC_NORMAL_REGION_WORDS) {
190 if (start + total_words > PREF_TOTAL_WORDS)
193 offset =
static_cast<uint16_t
>(in_normal ? start + RTC_EBOOT_REGION_WORDS : start - RTC_NORMAL_REGION_WORDS);
198 pref->offset = offset;
200 pref->length_words =
static_cast<uint8_t
>(length_words);
201 pref->in_flash = in_flash;
211 ESP_LOGD(TAG,
"Saving");
212 SpiFlashOpResult erase_res, write_res = SPI_FLASH_RESULT_OK;
215 erase_res = spi_flash_erase_sector(get_esp8266_flash_sector());
216 if (erase_res == SPI_FLASH_RESULT_OK) {
217 write_res = spi_flash_write(get_esp8266_flash_address(), s_flash_storage, ESP8266_FLASH_STORAGE_SIZE * 4);
220 if (erase_res != SPI_FLASH_RESULT_OK) {
221 ESP_LOGE(TAG,
"Erasing failed");
224 if (write_res != SPI_FLASH_RESULT_OK) {
225 ESP_LOGE(TAG,
"Writing failed");
229 s_flash_dirty =
false;
234 ESP_LOGD(TAG,
"Erasing storage");
235 SpiFlashOpResult erase_res;
238 erase_res = spi_flash_erase_sector(get_esp8266_flash_sector());
240 if (erase_res != SPI_FLASH_RESULT_OK) {
241 ESP_LOGE(TAG,
"Erasing failed");
246 s_prevent_write =
true;
255 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)
void preferences_prevent_write(bool prevent)
ESP8266Preferences * get_preferences()
std::span< const uint8_t > data
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).