AceUtils  0.6.0
Useful Arduino utilties which are too small as separate libraries, but complex enough to be shared among multiple projects, and often have external dependencies to other libraries.
CrcEeprom.h
1 /*
2  * MIT License
3  * Copyright (c) 2018 Brian T. Park
4  */
5 
6 #ifndef ACE_UTILS_CRC_EEPROM_CRC_EEPROM_H
7 #define ACE_UTILS_CRC_EEPROM_CRC_EEPROM_H
8 
9 #include <AceCRC.h> // crc32_nibble
10 #include "EepromInterface.h" // EepromInterface
11 
12 namespace ace_utils {
13 namespace crc_eeprom {
14 
27 constexpr uint32_t toContextId(char a, char b, char c, char d) {
28  return ((uint32_t) d << 24)
29  | ((uint32_t) c << 16)
30  | ((uint32_t) b << 8)
31  | a;
32 }
33 
34 
41 constexpr size_t toSavedSize(size_t dataSize) {
42  return dataSize + 8;
43 }
44 
54 typedef uint32_t (*Crc32Calculator)(const void* data, size_t dataSize);
55 
85 template <
86  template <typename> class T_EI,
87  typename T_E
88 >
89 class CrcEeprom {
90  public:
116  explicit CrcEeprom(
117  T_E& eeprom,
118  uint32_t contextId = 0,
119  #if defined(ESP8266)
120  Crc32Calculator crcCalc = ace_crc::crc32_nibblem::crc_calculate
121  #else
122  Crc32Calculator crcCalc = ace_crc::crc32_nibble::crc_calculate
123  #endif
124  ) :
125  mEeprom(eeprom),
126  mContextId(contextId),
127  mCrc32Calculator(crcCalc)
128  {}
129 
137  template <typename T>
138  size_t writeWithCrc(size_t address, const T& data) {
139  return writeDataWithCrc(address, &data, sizeof(T));
140  }
141 
149  template <typename T>
150  bool readWithCrc(size_t address, T& data) const {
151  return readDataWithCrc(address, &data, sizeof(T));
152  }
153 
158  size_t writeDataWithCrc(size_t address, const void* data, size_t dataSize) {
159  const size_t address0 = address;
160 
161  // write the contextId
162  writeData(address, (const uint8_t*) &mContextId, sizeof(mContextId));
163  address += sizeof(mContextId);
164 
165  // write data block
166  writeData(address, (const uint8_t*) data, dataSize);
167  address += dataSize;
168 
169  // write CRC at the end of the data block
170  uint32_t crc = (*mCrc32Calculator)(data, dataSize);
171  writeData(address, (const uint8_t*) &crc, sizeof(crc));
172  address += sizeof(crc);
173 
174  bool success = commit();
175  return (success) ? address - address0: 0;
176  }
177 
183  bool readDataWithCrc(size_t address, void* data, size_t dataSize) const {
184  // read contextId
185  uint32_t retrievedContextId;
186  readData(address, (uint8_t*) &retrievedContextId,
187  sizeof(retrievedContextId));
188  if (retrievedContextId != mContextId) return false;
189  address += sizeof(retrievedContextId);
190 
191  // read data block
192  readData(address, (uint8_t*) data, dataSize);
193  address += dataSize;
194 
195  // read the CRC
196  uint32_t retrievedCrc;
197  readData(address, (uint8_t*) &retrievedCrc, sizeof(retrievedCrc));
198  address += sizeof(retrievedCrc);
199 
200  // Verify CRC
201  uint32_t expectedCrc = (*mCrc32Calculator)(data, dataSize);
202  return expectedCrc == retrievedCrc;
203  }
204 
205  private:
206  void write(size_t address, uint8_t val) {
207  mEeprom.write(address, val);
208  }
209 
210  uint8_t read(size_t address) const { return mEeprom.read(address); }
211 
212  bool commit() { return mEeprom.commit(); }
213 
214  void writeData(size_t address, const uint8_t* data, size_t size) {
215  while (size--) {
216  write(address++, *data++);
217  }
218  }
219 
220  void readData(size_t address, uint8_t* data, size_t size) const {
221  while (size--) {
222  *data++ = read(address++);
223  }
224  }
225 
226  private:
227  T_EI<T_E> mEeprom;
228  uint32_t const mContextId;
229  Crc32Calculator const mCrc32Calculator;
230 };
231 
233 template <typename T_E>
234 class CrcEepromEsp : public CrcEeprom<EspStyleEeprom, T_E> {
235  public:
236  explicit CrcEepromEsp(
237  T_E& eeprom,
238  uint32_t contextId = 0,
239  #if defined(ESP8266)
240  Crc32Calculator crcCalc = ace_crc::crc32_nibblem::crc_calculate
241  #else
242  Crc32Calculator crcCalc = ace_crc::crc32_nibble::crc_calculate
243  #endif
244  ) :
245  CrcEeprom<EspStyleEeprom, T_E>(eeprom, contextId, crcCalc)
246  {}
247 
248 };
249 
251 template <typename T_E>
252 class CrcEepromAvr : public CrcEeprom<AvrStyleEeprom, T_E> {
253  public:
254  explicit CrcEepromAvr(
255  T_E& eeprom,
256  uint32_t contextId = 0,
257  #if defined(ESP8266)
258  Crc32Calculator crcCalc = ace_crc::crc32_nibblem::crc_calculate
259  #else
260  Crc32Calculator crcCalc = ace_crc::crc32_nibble::crc_calculate
261  #endif
262  ) :
263  CrcEeprom<AvrStyleEeprom, T_E>(eeprom, contextId, crcCalc)
264  {}
265 };
266 
267 } // crc_eeprom
268 } // ace_utils
269 
270 #endif // defined(ACE_UTILS_CRC_EEPROM_CRC_EEPROM_H)
Version of CrcEeprom specialized for an AvrStyleEeprom.
Definition: CrcEeprom.h:252
Version of CrcEeprom specialized for an EspStyleEeprom.
Definition: CrcEeprom.h:234
Thin wrapper around the EEPROM object (from the the built-in EEPROM library) to read and write a give...
Definition: CrcEeprom.h:89
size_t writeWithCrc(size_t address, const T &data)
Convenience method that writes the given data of type T at given address.
Definition: CrcEeprom.h:138
bool readDataWithCrc(size_t address, void *data, size_t dataSize) const
Read the data from EEPROM along with its CRC and contextId.
Definition: CrcEeprom.h:183
size_t writeDataWithCrc(size_t address, const void *data, size_t dataSize)
Write the data with its CRC and its contextId.
Definition: CrcEeprom.h:158
CrcEeprom(T_E &eeprom, uint32_t contextId=0, Crc32Calculator crcCalc=ace_crc::crc32_nibblem::crc_calculate)
Constructor with an optional contextId identifier and an optional Crc32Calculator crcCalc function po...
Definition: CrcEeprom.h:116
bool readWithCrc(size_t address, T &data) const
Convenience function that reads the given data of type T at given address.
Definition: CrcEeprom.h:150