21static const char *
const TAG =
"esp8266.preferences";
23static bool s_prevent_write =
false;
24static uint32_t *s_flash_storage =
nullptr;
25static bool s_flash_dirty =
false;
27static const uint32_t ESP_RTC_USER_MEM_START = 0x60001200;
28#define ESP_RTC_USER_MEM ((uint32_t *) ESP_RTC_USER_MEM_START)
29static const uint32_t ESP_RTC_USER_MEM_SIZE_WORDS = 128;
30static const uint32_t ESP_RTC_USER_MEM_SIZE_BYTES = ESP_RTC_USER_MEM_SIZE_WORDS * 4;
32#ifdef USE_ESP8266_PREFERENCES_FLASH
33static const uint32_t ESP8266_FLASH_STORAGE_SIZE = 128;
35static const uint32_t ESP8266_FLASH_STORAGE_SIZE = 64;
38static inline bool esp_rtc_user_mem_read(uint32_t index, uint32_t *dest) {
39 if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) {
42 *dest = ESP_RTC_USER_MEM[index];
46static inline bool esp_rtc_user_mem_write(uint32_t index, uint32_t value) {
47 if (index >= ESP_RTC_USER_MEM_SIZE_WORDS) {
50 if (index < 32 && s_prevent_write) {
54 auto *ptr = &ESP_RTC_USER_MEM[index];
61static uint32_t get_esp8266_flash_sector() {
67 return (data.uint - 0x40200000) / SPI_FLASH_SEC_SIZE;
69static uint32_t get_esp8266_flash_address() {
return get_esp8266_flash_sector() * SPI_FLASH_SEC_SIZE; }
71static inline size_t bytes_to_words(
size_t bytes) {
return (bytes + 3) / 4; }
75 while (first != last) {
76 crc ^= (*first++ * 2654435769UL) >> 1;
81static bool save_to_flash(
size_t offset,
const uint32_t *data,
size_t len) {
82 for (uint32_t i = 0; i <
len; i++) {
83 uint32_t j = offset + i;
84 if (j >= ESP8266_FLASH_STORAGE_SIZE)
87 uint32_t *ptr = &s_flash_storage[j];
95static bool load_from_flash(
size_t offset, uint32_t *data,
size_t len) {
96 for (
size_t i = 0; i <
len; i++) {
98 if (j >= ESP8266_FLASH_STORAGE_SIZE)
100 data[i] = s_flash_storage[j];
105static bool save_to_rtc(
size_t offset,
const uint32_t *data,
size_t len) {
106 for (uint32_t i = 0; i <
len; i++) {
107 if (!esp_rtc_user_mem_write(offset + i, data[i]))
113static bool load_from_rtc(
size_t offset, uint32_t *data,
size_t len) {
114 for (uint32_t i = 0; i <
len; i++) {
115 if (!esp_rtc_user_mem_read(offset + i, &data[i]))
121class ESP8266PreferenceBackend :
public ESPPreferenceBackend {
125 uint8_t length_words = 0;
126 bool in_flash =
false;
128 bool save(
const uint8_t *data,
size_t len)
override {
129 if (bytes_to_words(
len) != length_words) {
132 size_t buffer_size =
static_cast<size_t>(length_words) + 1;
133 std::unique_ptr<uint32_t[]> buffer(
new uint32_t[buffer_size]());
134 memcpy(buffer.get(), data,
len);
135 buffer[length_words] =
calculate_crc(buffer.get(), buffer.get() + length_words, type);
138 return save_to_flash(offset, buffer.get(), buffer_size);
140 return save_to_rtc(offset, buffer.get(), buffer_size);
142 bool load(uint8_t *data,
size_t len)
override {
143 if (bytes_to_words(
len) != length_words) {
146 size_t buffer_size =
static_cast<size_t>(length_words) + 1;
147 std::unique_ptr<uint32_t[]> buffer(
new uint32_t[buffer_size]());
148 bool ret = in_flash ? load_from_flash(offset, buffer.get(), buffer_size)
149 : load_from_rtc(offset, buffer.get(), buffer_size);
154 if (buffer[length_words] != crc) {
158 memcpy(data, buffer.get(),
len);
163class ESP8266Preferences :
public ESPPreferences {
169 s_flash_storage =
new uint32_t[ESP8266_FLASH_STORAGE_SIZE];
170 ESP_LOGVV(TAG,
"Loading preferences from flash");
174 spi_flash_read(get_esp8266_flash_address(), s_flash_storage, ESP8266_FLASH_STORAGE_SIZE * 4);
178 ESPPreferenceObject make_preference(
size_t length, uint32_t
type,
bool in_flash)
override {
180 if (length_words > 255) {
181 ESP_LOGE(TAG,
"Preference too large: %" PRIu32
" words > 255", length_words);
185 uint32_t start = current_flash_offset;
187 if (
end > ESP8266_FLASH_STORAGE_SIZE)
189 auto *pref =
new ESP8266PreferenceBackend();
190 pref->offset =
static_cast<uint16_t
>(start);
192 pref->length_words =
static_cast<uint8_t
>(length_words);
193 pref->in_flash =
true;
194 current_flash_offset =
end;
200 bool in_normal = start < 96;
203 if (in_normal &&
end > 96) {
205 current_offset = start = 96;
206 end = start + length_words + 1;
215 uint32_t rtc_offset = in_normal ? start + 32 : start - 96;
217 auto *pref =
new ESP8266PreferenceBackend();
218 pref->offset =
static_cast<uint16_t
>(rtc_offset);
220 pref->length_words =
static_cast<uint8_t
>(length_words);
221 pref->in_flash =
false;
222 current_offset += length_words + 1;
226 ESPPreferenceObject make_preference(
size_t length, uint32_t
type)
override {
227#ifdef USE_ESP8266_PREFERENCES_FLASH
234 bool sync()
override {
240 ESP_LOGD(TAG,
"Saving");
241 SpiFlashOpResult erase_res, write_res = SPI_FLASH_RESULT_OK;
244 erase_res = spi_flash_erase_sector(get_esp8266_flash_sector());
245 if (erase_res == SPI_FLASH_RESULT_OK) {
246 write_res = spi_flash_write(get_esp8266_flash_address(), s_flash_storage, ESP8266_FLASH_STORAGE_SIZE * 4);
249 if (erase_res != SPI_FLASH_RESULT_OK) {
250 ESP_LOGE(TAG,
"Erasing failed");
253 if (write_res != SPI_FLASH_RESULT_OK) {
254 ESP_LOGE(TAG,
"Writing failed");
258 s_flash_dirty =
false;
262 bool reset()
override {
263 ESP_LOGD(TAG,
"Erasing storage");
264 SpiFlashOpResult erase_res;
267 erase_res = spi_flash_erase_sector(get_esp8266_flash_sector());
269 if (erase_res != SPI_FLASH_RESULT_OK) {
270 ESP_LOGE(TAG,
"Erasing failed");
275 s_prevent_write =
true;
281 auto *pref =
new ESP8266Preferences();
void preferences_prevent_write(bool prevent)
uint32_t calculate_crc(It first, It last, uint32_t type)
Providing packet encoding functions for exchanging data with a remote host.
ESPPreferences * global_preferences