16static const char *
const TAG =
"preferences";
18static constexpr uint32_t ESP_RTC_USER_MEM_START = 0x60001200;
19static constexpr uint32_t ESP_RTC_USER_MEM_SIZE_WORDS = 128;
20static constexpr uint32_t ESP_RTC_USER_MEM_SIZE_BYTES = ESP_RTC_USER_MEM_SIZE_WORDS * 4;
26static constexpr uint32_t RTC_EBOOT_REGION_WORDS = 32;
27static constexpr uint32_t RTC_NORMAL_REGION_WORDS = 78;
28static constexpr uint32_t PREF_TOTAL_WORDS = RTC_EBOOT_REGION_WORDS + RTC_NORMAL_REGION_WORDS;
31static constexpr uint32_t MAX_PREFERENCE_WORDS = 255;
33#define ESP_RTC_USER_MEM ((uint32_t *) ESP_RTC_USER_MEM_START)
39#ifdef USE_ESP8266_PREFERENCES_FLASH
40static constexpr uint32_t ESP8266_FLASH_STORAGE_SIZE = 128;
42static constexpr uint32_t ESP8266_FLASH_STORAGE_SIZE = 64;
46 s_flash_storage[ESP8266_FLASH_STORAGE_SIZE];
47static bool s_prevent_write =
false;
48static bool s_flash_dirty =
false;
51 if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) {
54 *dest = ESP_RTC_USER_MEM[index];
59 if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) {
62 if (index < 32 && s_prevent_write) {
66 auto *ptr = &ESP_RTC_USER_MEM[index];
73static uint32_t get_esp8266_flash_sector() {
79 return (data.uint - 0x40200000) / SPI_FLASH_SEC_SIZE;
81static uint32_t get_esp8266_flash_address() {
return get_esp8266_flash_sector() * SPI_FLASH_SEC_SIZE; }
83static inline size_t bytes_to_words(
size_t bytes) {
return (bytes + 3) / 4; }
87 while (first != last) {
88 crc ^= (*first++ * 2654435769UL) >> 1;
93static bool save_to_flash(
size_t offset,
const uint32_t *data,
size_t len) {
96 if (j >= ESP8266_FLASH_STORAGE_SIZE)
101 s_flash_dirty =
true;
107static bool load_from_flash(
size_t offset,
uint32_t *data,
size_t len) {
108 for (
size_t i = 0; i <
len; i++) {
110 if (j >= ESP8266_FLASH_STORAGE_SIZE)
112 data[i] = s_flash_storage[
j];
117static bool save_to_rtc(
size_t offset,
const uint32_t *data,
size_t len) {
119 if (!esp_rtc_user_mem_write(offset + i, data[i]))
125static bool load_from_rtc(
size_t offset,
uint32_t *data,
size_t len) {
127 if (!esp_rtc_user_mem_read(offset + i, &data[i]))
136static constexpr size_t PREF_MAX_BUFFER_WORDS =
137 ESP8266_FLASH_STORAGE_SIZE > RTC_NORMAL_REGION_WORDS ? ESP8266_FLASH_STORAGE_SIZE : RTC_NORMAL_REGION_WORDS;
142 const size_t buffer_size =
static_cast<size_t>(this->
length_words) + 1;
143 if (buffer_size > PREF_MAX_BUFFER_WORDS)
145 uint32_t buffer[PREF_MAX_BUFFER_WORDS];
146 memset(buffer, 0, buffer_size *
sizeof(
uint32_t));
147 memcpy(buffer, data,
len);
149 return this->
in_flash ? save_to_flash(this->offset, buffer, buffer_size)
150 : save_to_rtc(this->offset, buffer, buffer_size);
156 const size_t buffer_size =
static_cast<size_t>(this->
length_words) + 1;
157 if (buffer_size > PREF_MAX_BUFFER_WORDS)
159 uint32_t buffer[PREF_MAX_BUFFER_WORDS];
160 bool ret = this->
in_flash ? load_from_flash(this->offset, buffer, buffer_size)
161 : load_from_rtc(this->offset, buffer, buffer_size);
166 memcpy(data, buffer,
len);
171 ESP_LOGVV(TAG,
"Loading preferences from flash");
175 spi_flash_read(get_esp8266_flash_address(), s_flash_storage, ESP8266_FLASH_STORAGE_SIZE * 4);
181 if (length_words > MAX_PREFERENCE_WORDS) {
182 ESP_LOGE(TAG,
"Preference too large: %u words",
static_cast<unsigned int>(length_words));
186 const uint32_t total_words = length_words + 1;
196 bool in_normal = start < RTC_NORMAL_REGION_WORDS;
199 if (in_normal && start + total_words > RTC_NORMAL_REGION_WORDS) {
204 if (start + total_words > PREF_TOTAL_WORDS)
207 offset =
static_cast<uint16_t
>(in_normal ? start + RTC_EBOOT_REGION_WORDS : start - RTC_NORMAL_REGION_WORDS);
212 pref->offset = offset;
214 pref->length_words =
static_cast<uint8_t
>(length_words);
215 pref->in_flash = in_flash;
225 ESP_LOGD(TAG,
"Saving");
226 SpiFlashOpResult erase_res, write_res = SPI_FLASH_RESULT_OK;
229 erase_res = spi_flash_erase_sector(get_esp8266_flash_sector());
230 if (erase_res == SPI_FLASH_RESULT_OK) {
231 write_res = spi_flash_write(get_esp8266_flash_address(), s_flash_storage, ESP8266_FLASH_STORAGE_SIZE * 4);
234 if (erase_res != SPI_FLASH_RESULT_OK) {
235 ESP_LOGE(TAG,
"Erasing failed");
238 if (write_res != SPI_FLASH_RESULT_OK) {
239 ESP_LOGE(TAG,
"Writing failed");
243 s_flash_dirty =
false;
248 ESP_LOGD(TAG,
"Erasing storage");
249 SpiFlashOpResult erase_res;
252 erase_res = spi_flash_erase_sector(get_esp8266_flash_sector());
254 if (erase_res != SPI_FLASH_RESULT_OK) {
255 ESP_LOGE(TAG,
"Erasing failed");
260 s_prevent_write =
true;
269 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()
uint32_t calculate_crc(It first, It last, uint32_t type)
const std::vector< uint8_t > & data
Providing packet encoding functions for exchanging data with a remote host.
Preferences ESPPreferences
ESPPreferences * global_preferences