EepromSecureData
CRC-controlled EEPROM memory storage
Loading...
Searching...
No Matches
EepromSecureData.h
1/*
2 Copyright (C) 2023 epsilonrt <epsilonrt@gmail.com>
3 SPDX-License-Identifier: LGPL-2.1-or-later
4*/
5#include <EEPROM.h>
6#include <assert.h>
7#include <stdio.h>
8#if defined(ESP32) && __has_include(<Preferences.h>)
9#include <Preferences.h>
10#endif
11#include "CrcIButton.h"
12#include "EepromBase.h"
13#pragma once
14
15enum class EepromSecureBackend : uint8_t {
16 Auto,
17 EEPROM,
18 Preferences
19};
20
26template <class T>
28
29 public:
35 EepromSecureData (EepromSecureBackend backend = EepromSecureBackend::Auto, bool crcEnabled = true) :
36 m_backend (resolveBackend (backend)), m_crcEnabled (crcEnabled), m_eem (EepromBase::counter) {
37 EepromBase::counter += size();
38 // assert (EepromBase::counter < EEPROM.length());
39 }
40
46 EepromSecureData (const T &data, EepromSecureBackend backend = EepromSecureBackend::Auto, bool crcEnabled = true) :
48 m_data = data;
49 }
50
57 save();
58 }
59
65 bool save() {
66
67 updateCrc();
68 if (m_backend == EepromSecureBackend::Preferences) {
69
70 #if defined(ESP32) && __has_include(<Preferences.h>)
71 return saveToPreferences();
72 #else
73 return false;
74 #endif
75 }
76 return saveToEeprom();
77 }
78
86 bool load (const T &defaultData = T()) {
87
88 bool loaded = false;
89 uint8_t crc = 0;
90
91 if (m_backend == EepromSecureBackend::Preferences) {
92
93 #if defined(ESP32) && __has_include(<Preferences.h>)
94 loaded = loadFromPreferences (crc);
95 #endif
96 }
97 else {
98
99 loaded = loadFromEeprom (crc);
100 }
101
102 if (!loaded) {
103 m_data = defaultData;
104 updateCrc();
105 save();
106 return false;
107 }
108 updateCrc();
109
110 if (m_crcEnabled && (m_crc.value () != crc)) {
111 m_data = defaultData;
112 updateCrc();
113 save();
114 return false;
115 }
116 return true;
117 }
118
124 void setCrcEnabled (bool enabled) {
125 m_crcEnabled = enabled;
126 }
127
133 bool crcEnabled() const {
134 return m_crcEnabled;
135 }
136
142 EepromSecureBackend backend() const {
143 return m_backend;
144 }
145
149 inline uint16_t size() const {
150 return sizeof (T) + sizeof (m_crc);
151 }
152
156 T &data() {
157 return m_data;
158 }
159
163 const T &data() const {
164 return m_data;
165 }
166
172 operator T &() {
173 return m_data;
174 }
175
181 operator const T &() const {
182 return m_data;
183 }
184
191 return & m_data;
192 }
193
199 const T *operator&() const {
200 return & m_data;
201 }
202
206 T &operator= (const T &t) {
207 m_data = t;
208 updateCrc();
209 return m_data;
210 }
211
216 m_data = rhs.m_data;
217 return *this;
218 }
219
223 bool operator == (const EepromSecureData &rhs) const {
224 return m_data == rhs.m_data;
225 }
226
230 bool operator != (const EepromSecureData &rhs) const {
231 return ! (*this == rhs);
232 }
233
234 protected:
235 bool saveToEeprom () {
236 EEPROM.put (m_eem, m_data);
237 EEPROM.write (m_eem + sizeof (T), storedCrcValue());
238 #if defined(ESP32) || defined(ESP8266)
239 return EEPROM.commit();
240 #else
241 return true;
242 #endif
243 }
244
245 bool loadFromEeprom (uint8_t &crc) {
246 EEPROM.get (m_eem, m_data);
247 crc = EEPROM.read (m_eem + sizeof (T));
248 return true;
249 }
250
251 #if defined(ESP32) && __has_include(<Preferences.h>)
252 bool saveToPreferences () {
253 Preferences prefs;
254 if (!prefs.begin (kNamespace, false)) {
255 return false;
256 }
257
258 char dataKey[16];
259 char crcKey[16];
260 makeKeys (dataKey, crcKey, sizeof (dataKey), sizeof (crcKey));
261
262 size_t bytes = prefs.putBytes (dataKey, &m_data, sizeof (T));
263 size_t crcBytes = prefs.putUChar (crcKey, storedCrcValue());
264 prefs.end();
265 return (bytes == sizeof (T)) && (crcBytes == 1);
266 }
267
268 bool loadFromPreferences (uint8_t &crc) {
269 Preferences prefs;
270 if (!prefs.begin (kNamespace, true)) {
271 return false;
272 }
273
274 char dataKey[16];
275 char crcKey[16];
276 makeKeys (dataKey, crcKey, sizeof (dataKey), sizeof (crcKey));
277
278 size_t expected = sizeof (T);
279 size_t storedLen = prefs.getBytesLength (dataKey);
280 if (storedLen != expected) {
281 prefs.end();
282 return false;
283 }
284
285 size_t bytes = prefs.getBytes (dataKey, &m_data, sizeof (T));
286 crc = prefs.getUChar (crcKey, kMissingCrcValue);
287 prefs.end();
288 if (bytes != sizeof (T)) {
289 return false;
290 }
291 if (!m_crcEnabled) {
292 return true;
293 }
294 return crc != kMissingCrcValue;
295 }
296
297 void makeKeys (char *dataKey, char *crcKey, size_t dataKeySize, size_t crcKeySize) const {
298 snprintf (dataKey, dataKeySize, "d%u", static_cast<unsigned> (m_eem));
299 snprintf (crcKey, crcKeySize, "c%u", static_cast<unsigned> (m_eem));
300 }
301 #endif
302
303 static EepromSecureBackend resolveBackend (EepromSecureBackend backend) {
304 if (backend == EepromSecureBackend::Auto) {
305 #if defined(ESP32) && __has_include(<Preferences.h>)
306 return EepromSecureBackend::Preferences;
307 #else
308 return EepromSecureBackend::EEPROM;
309 #endif
310 }
311
312 #if defined(ESP32) && __has_include(<Preferences.h>)
313 return backend;
314 #else
315 if (backend == EepromSecureBackend::Preferences) {
316 return EepromSecureBackend::EEPROM;
317 }
318 return backend;
319 #endif
320 }
321
322 uint8_t storedCrcValue () const {
323 if (!m_crcEnabled) {
324 return kCrcDisabledValue;
325 }
326 return m_crc.value();
327 }
328
329 // update CRC
330 void updateCrc () {
331 m_crc.reset ();
332 m_crc.update (m_data);
333 }
334
335 protected:
336 static constexpr const char *kNamespace = "EepSecData";
337 static constexpr uint8_t kMissingCrcValue = 0xFF;
338 static constexpr uint8_t kCrcDisabledValue = 0xA5;
339 EepromSecureBackend m_backend;
340 bool m_crcEnabled;
341 uint16_t m_eem; // EEPROM memory address of the object
342 T m_data; // data object itself (RAM)
343 CrcIButton <T> m_crc; // CRC object
344};
EEPROM memory storage management class.
Definition EepromBase.h:21
CRC-controlled EEPROM memory storage template class.
T & data()
Get the data object.
T & operator=(const T &t)
Overloaded assignment operator from T.
const T * operator&() const
Overloaded cast operator to const T.
uint16_t size() const
Get the size of the object with CRC.
bool load(const T &defaultData=T())
Load data from EEPROM memory with CRC check.
~EepromSecureData()
Destroy the Eeprom Secure Data object.
EepromSecureData(EepromSecureBackend backend=EepromSecureBackend::Auto, bool crcEnabled=true)
Construct a new Eeprom Secure Data object.
const T & data() const
Get the data object as const.
void setCrcEnabled(bool enabled)
Enable or disable CRC checks on save/load.
EepromSecureBackend backend() const
Get resolved storage backend used by this instance.
bool save()
Save data to EEPROM memory with CRC.
bool operator==(const EepromSecureData &rhs) const
Overloaded equality operator.
EepromSecureData(const T &data, EepromSecureBackend backend=EepromSecureBackend::Auto, bool crcEnabled=true)
Construct a new Eeprom Secure Data object with initial data.
bool operator!=(const EepromSecureData &rhs) const
Overloaded not-equality operator.
T * operator&()
Overloaded cast operator to T *.
bool crcEnabled() const
Check whether CRC checks are enabled.