ESPHome 2025.5.0
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#include <vector>
12
14#include "esphome/core/log.h"
16
17namespace esphome {
18namespace rp2040 {
19
20static const char *const TAG = "rp2040.preferences";
21
22static bool s_prevent_write = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
23static uint8_t *s_flash_storage = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
24static bool s_flash_dirty = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
25
26static const uint32_t RP2040_FLASH_STORAGE_SIZE = 512;
27
28extern "C" uint8_t _EEPROM_start;
29
30template<class It> uint8_t calculate_crc(It first, It last, uint32_t type) {
31 std::array<uint8_t, 4> type_array = decode_value(type);
32 uint8_t crc = type_array[0] ^ type_array[1] ^ type_array[2] ^ type_array[3];
33 while (first != last) {
34 crc ^= (*first++);
35 }
36 return crc;
37}
38
39class RP2040PreferenceBackend : public ESPPreferenceBackend {
40 public:
41 size_t offset = 0;
42 uint32_t type = 0;
43
44 bool save(const uint8_t *data, size_t len) override {
45 std::vector<uint8_t> buffer;
46 buffer.resize(len + 1);
47 memcpy(buffer.data(), data, len);
48 buffer[buffer.size() - 1] = calculate_crc(buffer.begin(), buffer.end() - 1, type);
49
50 for (uint32_t i = 0; i < len + 1; i++) {
51 uint32_t j = offset + i;
52 if (j >= RP2040_FLASH_STORAGE_SIZE)
53 return false;
54 uint8_t v = buffer[i];
55 uint8_t *ptr = &s_flash_storage[j];
56 if (*ptr != v)
57 s_flash_dirty = true;
58 *ptr = v;
59 }
60 return true;
61 }
62 bool load(uint8_t *data, size_t len) override {
63 std::vector<uint8_t> buffer;
64 buffer.resize(len + 1);
65
66 for (size_t i = 0; i < len + 1; i++) {
67 uint32_t j = offset + i;
68 if (j >= RP2040_FLASH_STORAGE_SIZE)
69 return false;
70 buffer[i] = s_flash_storage[j];
71 }
72
73 uint8_t crc = calculate_crc(buffer.begin(), buffer.end() - 1, type);
74 if (buffer[buffer.size() - 1] != crc) {
75 return false;
76 }
77
78 memcpy(data, buffer.data(), len);
79 return true;
80 }
81};
82
83class RP2040Preferences : public ESPPreferences {
84 public:
85 uint32_t current_flash_offset = 0;
86
87 RP2040Preferences() : eeprom_sector_(&_EEPROM_start) {}
88 void setup() {
89 s_flash_storage = new uint8_t[RP2040_FLASH_STORAGE_SIZE]; // NOLINT
90 ESP_LOGVV(TAG, "Loading preferences from flash...");
91 memcpy(s_flash_storage, this->eeprom_sector_, RP2040_FLASH_STORAGE_SIZE);
92 }
93
94 ESPPreferenceObject make_preference(size_t length, uint32_t type, bool in_flash) override {
95 return make_preference(length, type);
96 }
97
98 ESPPreferenceObject make_preference(size_t length, uint32_t type) override {
99 uint32_t start = this->current_flash_offset;
100 uint32_t end = start + length + 1;
101 if (end > RP2040_FLASH_STORAGE_SIZE) {
102 return {};
103 }
104 auto *pref = new RP2040PreferenceBackend(); // NOLINT(cppcoreguidelines-owning-memory)
105 pref->offset = start;
106 pref->type = type;
107 current_flash_offset = end;
108 return {pref};
109 }
110
111 bool sync() override {
112 if (!s_flash_dirty)
113 return true;
114 if (s_prevent_write)
115 return false;
116
117 ESP_LOGD(TAG, "Saving preferences to flash...");
118
119 {
120 InterruptLock lock;
121 ::rp2040.idleOtherCore();
122 flash_range_erase((intptr_t) eeprom_sector_ - (intptr_t) XIP_BASE, 4096);
123 flash_range_program((intptr_t) eeprom_sector_ - (intptr_t) XIP_BASE, s_flash_storage, RP2040_FLASH_STORAGE_SIZE);
124 ::rp2040.resumeOtherCore();
125 }
126
127 s_flash_dirty = false;
128 return true;
129 }
130
131 bool reset() override {
132 ESP_LOGD(TAG, "Cleaning up preferences in flash...");
133 {
134 InterruptLock lock;
135 ::rp2040.idleOtherCore();
136 flash_range_erase((intptr_t) eeprom_sector_ - (intptr_t) XIP_BASE, 4096);
137 ::rp2040.resumeOtherCore();
138 }
139 s_prevent_write = true;
140 return true;
141 }
142
143 protected:
144 uint8_t *eeprom_sector_;
145};
146
148 auto *prefs = new RP2040Preferences(); // NOLINT(cppcoreguidelines-owning-memory)
149 prefs->setup();
150 global_preferences = prefs;
151}
152void preferences_prevent_write(bool prevent) { s_prevent_write = prevent; }
153
154} // namespace rp2040
155
156ESPPreferences *global_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
157
158} // namespace esphome
159
160#endif // USE_RP2040
uint8_t type
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
std::string size_t len
Definition helpers.h:301
ESPPreferences * global_preferences
constexpr14 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:221
uint8_t end[39]
Definition sun_gtil2.cpp:17
uint16_t length
Definition tt21100.cpp:0