12 #include "preferences.h" 20 static const char *
const TAG =
"esp8266.preferences";
22 static bool s_prevent_write =
false;
23 static uint32_t *s_flash_storage =
nullptr;
24 static bool s_flash_dirty =
false;
26 static const uint32_t ESP_RTC_USER_MEM_START = 0x60001200;
27 #define ESP_RTC_USER_MEM ((uint32_t *) ESP_RTC_USER_MEM_START) 28 static const uint32_t ESP_RTC_USER_MEM_SIZE_WORDS = 128;
29 static const uint32_t ESP_RTC_USER_MEM_SIZE_BYTES = ESP_RTC_USER_MEM_SIZE_WORDS * 4;
31 #ifdef USE_ESP8266_PREFERENCES_FLASH 32 static const uint32_t ESP8266_FLASH_STORAGE_SIZE = 128;
34 static const uint32_t ESP8266_FLASH_STORAGE_SIZE = 64;
37 static inline bool esp_rtc_user_mem_read(uint32_t index, uint32_t *dest) {
38 if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) {
41 *dest = ESP_RTC_USER_MEM[index];
45 static inline bool esp_rtc_user_mem_write(uint32_t index, uint32_t value) {
46 if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) {
49 if (index < 32 && s_prevent_write) {
53 auto *ptr = &ESP_RTC_USER_MEM[index];
60 static uint32_t get_esp8266_flash_sector() {
66 return (data.uint - 0x40200000) / SPI_FLASH_SEC_SIZE;
68 static uint32_t get_esp8266_flash_address() {
return get_esp8266_flash_sector() * SPI_FLASH_SEC_SIZE; }
72 while (first != last) {
73 crc ^= (*first++ * 2654435769UL) >> 1;
78 static bool save_to_flash(
size_t offset,
const uint32_t *data,
size_t len) {
79 for (uint32_t i = 0; i <
len; i++) {
80 uint32_t j = offset + i;
81 if (j >= ESP8266_FLASH_STORAGE_SIZE)
84 uint32_t *ptr = &s_flash_storage[j];
92 static bool load_from_flash(
size_t offset, uint32_t *data,
size_t len) {
93 for (
size_t i = 0; i <
len; i++) {
94 uint32_t j = offset + i;
95 if (j >= ESP8266_FLASH_STORAGE_SIZE)
97 data[i] = s_flash_storage[j];
102 static bool save_to_rtc(
size_t offset,
const uint32_t *data,
size_t len) {
103 for (uint32_t i = 0; i <
len; i++) {
104 if (!esp_rtc_user_mem_write(offset + i, data[i]))
110 static bool load_from_rtc(
size_t offset, uint32_t *data,
size_t len) {
111 for (uint32_t i = 0; i <
len; i++) {
112 if (!esp_rtc_user_mem_read(offset + i, &data[i]))
122 bool in_flash =
false;
123 size_t length_words = 0;
125 bool save(
const uint8_t *data,
size_t len)
override {
126 if ((len + 3) / 4 != length_words) {
129 std::vector<uint32_t> buffer;
130 buffer.resize(length_words + 1);
131 memcpy(buffer.data(), data,
len);
132 buffer[buffer.size() - 1] =
calculate_crc(buffer.begin(), buffer.end() - 1,
type);
135 return save_to_flash(offset, buffer.data(), buffer.size());
137 return save_to_rtc(offset, buffer.data(), buffer.size());
140 bool load(uint8_t *data,
size_t len)
override {
141 if ((len + 3) / 4 != length_words) {
144 std::vector<uint32_t> buffer;
145 buffer.resize(length_words + 1);
148 ret = load_from_flash(offset, buffer.data(), buffer.size());
150 ret = load_from_rtc(offset, buffer.data(), buffer.size());
156 if (buffer[buffer.size() - 1] !=
crc) {
160 memcpy(data, buffer.data(),
len);
167 uint32_t current_offset = 0;
168 uint32_t current_flash_offset = 0;
171 s_flash_storage =
new uint32_t[ESP8266_FLASH_STORAGE_SIZE];
172 ESP_LOGVV(TAG,
"Loading preferences from flash...");
176 spi_flash_read(get_esp8266_flash_address(), s_flash_storage, ESP8266_FLASH_STORAGE_SIZE * 4);
181 uint32_t length_words = (length + 3) / 4;
183 uint32_t start = current_flash_offset;
184 uint32_t
end = start + length_words + 1;
185 if (end > ESP8266_FLASH_STORAGE_SIZE)
187 auto *pref =
new ESP8266PreferenceBackend();
188 pref->offset = start;
190 pref->length_words = length_words;
191 pref->in_flash =
true;
192 current_flash_offset =
end;
196 uint32_t start = current_offset;
197 uint32_t
end = start + length_words + 1;
198 bool in_normal = start < 96;
201 if (in_normal && end > 96) {
203 current_offset = start = 96;
204 end = start + length_words + 1;
213 uint32_t rtc_offset = in_normal ? start + 32 : start - 96;
215 auto *pref =
new ESP8266PreferenceBackend();
216 pref->offset = rtc_offset;
218 pref->length_words = length_words;
219 pref->in_flash =
false;
220 current_offset += length_words + 1;
225 #ifdef USE_ESP8266_PREFERENCES_FLASH 226 return make_preference(length, type,
true);
228 return make_preference(length, type,
false);
232 bool sync()
override {
238 ESP_LOGD(TAG,
"Saving preferences to flash...");
239 SpiFlashOpResult erase_res, write_res = SPI_FLASH_RESULT_OK;
242 erase_res = spi_flash_erase_sector(get_esp8266_flash_sector());
243 if (erase_res == SPI_FLASH_RESULT_OK) {
244 write_res = spi_flash_write(get_esp8266_flash_address(), s_flash_storage, ESP8266_FLASH_STORAGE_SIZE * 4);
247 if (erase_res != SPI_FLASH_RESULT_OK) {
248 ESP_LOGE(TAG,
"Erase ESP8266 flash failed!");
251 if (write_res != SPI_FLASH_RESULT_OK) {
252 ESP_LOGE(TAG,
"Write ESP8266 flash failed!");
256 s_flash_dirty =
false;
260 bool reset()
override {
261 ESP_LOGD(TAG,
"Cleaning up preferences in flash...");
262 SpiFlashOpResult erase_res;
265 erase_res = spi_flash_erase_sector(get_esp8266_flash_sector());
267 if (erase_res != SPI_FLASH_RESULT_OK) {
268 ESP_LOGE(TAG,
"Erase ESP8266 flash failed!");
273 s_prevent_write =
true;
279 auto *pref =
new ESP8266Preferences();
291 #endif // USE_ESP8266
uint32_t calculate_crc(It first, It last, uint32_t type)
ESPPreferences * global_preferences
Helper class to disable interrupts.
void preferences_prevent_write(bool prevent)
Implementation of SPI Controller mode.