ESPHome 2026.5.0-dev
Loading...
Searching...
No Matches
preferences.cpp
Go to the documentation of this file.
1#ifdef USE_RP2040
2
3#include <Arduino.h>
4
5#include <hardware/flash.h>
6#include <hardware/sync.h>
7
8#include "preferences.h"
9
10#include <cstring>
11
13#include "esphome/core/log.h"
14
15namespace esphome::rp2040 {
16
17static const char *const TAG = "preferences";
18
19static constexpr uint32_t RP2040_FLASH_STORAGE_SIZE = 512;
20
21static bool s_prevent_write = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
22static uint8_t
23 s_flash_storage[RP2040_FLASH_STORAGE_SIZE]; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
24static bool s_flash_dirty = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
25
26// No preference can exceed the total flash storage, so stack buffer covers all cases.
27static constexpr size_t PREF_MAX_BUFFER_SIZE = RP2040_FLASH_STORAGE_SIZE;
28
29extern "C" uint8_t _EEPROM_start;
30
31template<class It> uint8_t calculate_crc(It first, It last, uint32_t type) {
32 std::array<uint8_t, 4> type_array = decode_value(type);
33 uint8_t crc = type_array[0] ^ type_array[1] ^ type_array[2] ^ type_array[3];
34 while (first != last) {
35 crc ^= (*first++);
36 }
37 return crc;
38}
39
40bool RP2040PreferenceBackend::save(const uint8_t *data, size_t len) {
41 const size_t buffer_size = len + 1;
42 if (buffer_size > PREF_MAX_BUFFER_SIZE)
43 return false;
44 uint8_t buffer[PREF_MAX_BUFFER_SIZE];
45 memcpy(buffer, data, len);
46 buffer[len] = calculate_crc(buffer, buffer + len, this->type);
47
48 for (size_t i = 0; i < buffer_size; i++) {
49 uint32_t j = this->offset + i;
50 if (j >= RP2040_FLASH_STORAGE_SIZE)
51 return false;
52 uint8_t v = buffer[i];
53 uint8_t *ptr = &s_flash_storage[j];
54 if (*ptr != v)
55 s_flash_dirty = true;
56 *ptr = v;
57 }
58 return true;
59}
60
61bool RP2040PreferenceBackend::load(uint8_t *data, size_t len) {
62 const size_t buffer_size = len + 1;
63 if (buffer_size > PREF_MAX_BUFFER_SIZE)
64 return false;
65 uint8_t buffer[PREF_MAX_BUFFER_SIZE];
66
67 for (size_t i = 0; i < buffer_size; i++) {
68 uint32_t j = this->offset + i;
69 if (j >= RP2040_FLASH_STORAGE_SIZE)
70 return false;
71 buffer[i] = s_flash_storage[j];
72 }
73
74 uint8_t crc = calculate_crc(buffer, buffer + len, this->type);
75 if (buffer[len] != crc) {
76 return false;
77 }
78
79 memcpy(data, buffer, len);
80 return true;
81}
82
84
86 ESP_LOGVV(TAG, "Loading preferences from flash");
87 memcpy(s_flash_storage, this->eeprom_sector_, RP2040_FLASH_STORAGE_SIZE);
88}
89
91 uint32_t start = this->current_flash_offset;
92 uint32_t end = start + length + 1;
93 if (end > RP2040_FLASH_STORAGE_SIZE) {
94 return {};
95 }
96 auto *pref = new RP2040PreferenceBackend(); // NOLINT(cppcoreguidelines-owning-memory)
97 pref->offset = start;
98 pref->type = type;
100 return ESPPreferenceObject(pref);
101}
102
104 if (!s_flash_dirty)
105 return true;
106 if (s_prevent_write)
107 return false;
108
109 ESP_LOGD(TAG, "Saving");
110
111 {
112 InterruptLock lock;
113 ::rp2040.idleOtherCore();
114 flash_range_erase((intptr_t) this->eeprom_sector_ - (intptr_t) XIP_BASE, 4096);
115 flash_range_program((intptr_t) this->eeprom_sector_ - (intptr_t) XIP_BASE, s_flash_storage,
116 RP2040_FLASH_STORAGE_SIZE);
117 ::rp2040.resumeOtherCore();
118 }
119
120 s_flash_dirty = false;
121 return true;
122}
123
125 ESP_LOGD(TAG, "Erasing storage");
126 {
127 InterruptLock lock;
128 ::rp2040.idleOtherCore();
129 flash_range_erase((intptr_t) this->eeprom_sector_ - (intptr_t) XIP_BASE, 4096);
130 ::rp2040.resumeOtherCore();
131 }
132 s_prevent_write = true;
133 return true;
134}
135
136static RP2040Preferences s_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
137
138RP2040Preferences *get_preferences() { return &s_preferences; }
139
141 s_preferences.setup();
142 global_preferences = &s_preferences;
143}
144void preferences_prevent_write(bool prevent) { s_prevent_write = prevent; }
145
146} // namespace esphome::rp2040
147
148namespace esphome {
149ESPPreferences *global_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
150} // namespace esphome
151
152#endif // USE_RP2040
Helper class to disable interrupts.
Definition helpers.h:2104
bool save(const uint8_t *data, size_t len)
bool load(uint8_t *data, size_t len)
ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash)
Definition preferences.h:13
uint16_t type
RP2040Preferences * get_preferences()
void preferences_prevent_write(bool prevent)
uint8_t _EEPROM_start
uint8_t calculate_crc(It first, It last, uint32_t type)
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
Preferences ESPPreferences
Definition preferences.h:42
std::string size_t len
Definition helpers.h:1045
ESPPreferences * global_preferences
constexpr std::array< uint8_t, sizeof(T)> decode_value(T val)
Decode a value into its constituent bytes (from most to least significant).
Definition helpers.h:910
static void uint32_t
uint8_t end[39]
Definition sun_gtil2.cpp:17
uint16_t length
Definition tt21100.cpp:0