AskSin++
Storage.h
1 //- -----------------------------------------------------------------------------------------------------------------------
2 // AskSin++
3 // 2016-10-31 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
4 //- -----------------------------------------------------------------------------------------------------------------------
5 
6 #ifndef __STORAGE_H__
7 #define __STORAGE_H__
8 
9 #include "Debug.h"
10 
11 #ifdef ARDUINO_ARCH_STM32F1
12  #include "flash_stm32.h"
13 #endif
14 
15 namespace as {
16 
18 
19 #ifdef ARDUINO_ARCH_STM32F1
20  #if MCU_STM32F103CB
21  #define FlashPageSize 0x400
22  #define FlashStartAddress 0x0801fc00 // Page127
23  #elif defined(MCU_STM32F103C8)
24  #define FlashPageSize 0x400
25  #define FlashStartAddress 0x0800fc00 // Page63
26  #else
27  #error Unknown CPU type
28  #endif
29 
30  // we mirror 1 Flash Page into RAM
31  uint8_t data[FlashPageSize];
32 
33  void eeprom_read_block(void* buf,const void* addr,size_t size) {
34  uintptr_t offset = (uintptr_t)addr;
35  if( offset + size < sizeof(data) ) {
36  memcpy(buf,&data[offset],size);
37  }
38  }
39  void eeprom_write_block(const void* buf,void* addr,size_t size) {
40  uintptr_t offset = (uintptr_t)addr;
41  if( offset + size < sizeof(data) ) {
42  memcpy(&data[offset],buf,size);
43  }
44  }
45 #endif
46 
47 #ifndef ARDUINO
48  // we mirror 1 Flash Page into RAM
49  uint8_t data[1024];
50 
51  inline void memcpy(void* dest,const void* src,size_t size) {
52  uint8_t* d = (uint8_t*)dest;
53  const uint8_t* s = (const uint8_t*)src;
54  for( size_t i=0; i<size; ++i ) {
55  *d++ = *s++;
56  }
57  }
58 
59  void eeprom_read_block(void* buf,const void* addr,size_t size) {
60  uintptr_t offset = (uintptr_t)addr;
61  if( offset + size < sizeof(data) ) {
62  memcpy(buf,&data[offset],size);
63  }
64  }
65  void eeprom_write_block(const void* buf,void* addr,size_t size) {
66  uintptr_t offset = (uintptr_t)addr;
67  if( offset + size < sizeof(data) ) {
68  memcpy(&data[offset],buf,size);
69  }
70  }
71 #endif
72 
73 public:
74  InternalEprom () {
75 #ifdef ARDUINO_ARCH_STM32F1
76  // copy data from FLASH into RAM
77  uint16_t* towrite = (uint16_t*)data;
78  uint16_t *toread = (uint16_t*)(uintptr_t)FlashStartAddress;
79  for( size_t i=0; i<sizeof(data)/2; ++i ) {
80  *(towrite + i) = *(toread + i);
81  }
82 #endif
83  }
84 
85  bool present () {
86  return true;
87  }
88 
89  uint16_t size () {
90 #ifdef ARDUINO_ARCH_STM32F1
91  return 1024;
92 #else
93  return E2END + 1; // last EEPROM address + 1
94 #endif
95  }
96 
97  void store () {
98 #ifdef ARDUINO_ARCH_STM32F1
99  // copy data from RAM to FLASH
100  FLASH_Unlock(); //unlock flash writing
101  FLASH_ErasePage(FlashStartAddress);
102  uint16_t* toread = (uint16_t*)data;
103  for( size_t i=0; i<sizeof(data)/2; ++i ) {
104  FLASH_ProgramHalfWord(FlashStartAddress+i+i,*(toread+i));
105  }
106  FLASH_Lock();
107 #endif
108  }
109 
110  uint8_t getByte (uint16_t addr) {
111  uint8_t b = 0;
112  eeprom_read_block(&b,(void*)(uintptr_t)addr,1);
113  return b;
114  }
115 
116  bool setByte (uint16_t addr, uint8_t d) {
117  uint8_t b = d;
118  eeprom_write_block(&b,(void*)(uintptr_t)addr,1);
119  return true;
120  }
121 
122  bool setData (uint16_t addr,uint8_t* buf,uint16_t size) {
123  eeprom_write_block(buf,(void*)(uintptr_t)addr,size);
124  return true;
125  }
126 
127  bool getData (uint16_t addr,uint8_t* buf,uint16_t size) {
128  eeprom_read_block(buf,(const void*)(uintptr_t)addr,size);
129  return true;
130  }
131 
132  bool clearData (uint16_t addr, uint16_t size) {
133  for( uint16_t i=0; i<size; ++i) {
134  setByte(addr+i,0);
135  }
136  return true;
137  }
138 };
139 
140 
141 #if defined(TwoWire_h) || defined(_WIRE_H_) || defined(_TWOWIRE_H_) || defined(_WIREBASE_H_)
142 
143 #ifndef BUFFER_LENGTH
144  #ifdef TWI_BUFFER_SIZE // MightyCore
145  #define BUFFER_LENGTH TWI_BUFFER_SIZE
146  #else // fall back to default value
147  #define BUFFER_LENGTH 32
148  #endif
149 #endif
150 
151 // with help of https://github.com/JChristensen/extEEPROM
152 
153 template <uint8 ID,uint16_t PAGES,uint8_t PAGESIZE>
154 class at24cX {
155 public:
156  at24cX () {}
157 
158  bool present () {
159  Wire.beginTransmission(ID);
160  Wire.write(0); //high addr byte
161  Wire.write(0); //low addr byte
162  return Wire.endTransmission() == 0;
163  }
164 
165  uint16_t size () {
166  return PAGES * PAGESIZE;
167  }
168 
169  void store () {}
170 
171  uint8 getByte (uint16_t addr) {
172  uint8 b = 0;
173  Wire.beginTransmission(ID);
174  Wire.write(addr >> 8);
175  Wire.write(addr & 0xff);
176  if( Wire.endTransmission() == 0 ) {
177  Wire.requestFrom(ID,(uint8_t)1);
178  b = Wire.read();
179  }
180  return b;
181  }
182 
183  bool setByte (uint16_t addr, uint8 d) {
184  bool success = true;
185  Wire.beginTransmission(ID);
186  Wire.write(addr >> 8);
187  Wire.write(addr & 0xff);
188  Wire.write(d);
189  success = Wire.endTransmission() == 0;
190  // wait for write operation finished
191  if( success == true ) {
192  success = waitComplete();
193  }
194  return success;
195  }
196 
197  uint16_t calcBlockSize(uint16_t addr, uint16_t size) {
198  uint16_t block = PAGESIZE - (addr % PAGESIZE);
199  // BUFFER_LENGTH from Wire.h - 2 byte address
200  block = (BUFFER_LENGTH - 2) < block ? BUFFER_LENGTH - 2 : block;
201  return (size < block) ? size : block;
202  }
203 
204 
205  bool setData (uint16_t addr,uint8* buf,uint16_t size) {
206  // DPRINT("setData: ");DHEX(addr);DPRINT(" ");DDECLN(size);
207  bool success = true;
208  while( success == true && size > 0 ) {
209  uint16_t towrite = calcBlockSize(addr, size);
210  // DPRINT(" write: ");DHEX(addr);DPRINT(" ");DDECLN(towrite);
211  Wire.beginTransmission(ID);
212  Wire.write(addr >> 8);
213  Wire.write(addr & 0xff);
214  uint8_t done = 0;
215  while( done < towrite ) {
216  done++;
217  Wire.write(*buf++);
218  }
219  success = Wire.endTransmission() == 0;
220  // wait for write operation finished
221  if( success == true ) {
222  success = waitComplete();
223  }
224  else {
225  DPRINTLN(F("ERROR EEPROM WRITE"));
226  }
227  size -= towrite;
228  addr += towrite;
229  }
230  return success;
231  }
232 
233  bool getData (uint16_t addr,uint8* buf,uint16_t size) {
234  bool success = true;
235  while( success == true && size > 0 ) {
236  uint16_t toread = calcBlockSize(addr, size);
237  //DPRINT("Read: ");DHEX(addr);DPRINT(" ");DHEXLN(toread);
238  Wire.beginTransmission(ID);
239  Wire.write(addr >> 8);
240  Wire.write(addr & 0xff);
241  success = Wire.endTransmission() == 0;
242  if( success == true ) {
243  Wire.requestFrom(ID,(uint8_t)toread);
244  uint8_t done = 0;
245  while( done < toread ) {
246  done++;
247  *buf++ = (uint8_t)Wire.read();
248  }
249  }
250  size -= toread;
251  addr += toread;
252  }
253  return success;
254  }
255 
256  bool clearData (uint16_t addr, uint16_t size) {
257  // DPRINT("clearData: ");DHEX(addr);DPRINT(" ");DDECLN(size);
258  bool success = true;
259  while( success == true && size > 0 ) {
260  uint16_t towrite = calcBlockSize(addr, size);
261  // DPRINT(" clear: ");DHEX(addr);DPRINT(" ");DDECLN(towrite);
262  Wire.beginTransmission(ID);
263  Wire.write(addr >> 8);
264  Wire.write(addr & 0xff);
265  uint8_t done = 0;
266  while( done < towrite ) {
267  done++;
268  Wire.write(0);
269  }
270  success = Wire.endTransmission() == 0;
271  // wait for write operation finished
272  if( success == true ) {
273  success = waitComplete();
274  }
275  else {
276  DPRINTLN(F("ERROR EEPROM CLEAR"));
277  }
278  size -= towrite;
279  addr += towrite;
280  }
281 // DPRINTLN("clearData done");
282  return success;
283  }
284 
285  bool waitComplete () {
286  //wait up to 50ms for the write to complete
287  for (uint8_t i=25; i; --i) {
288  _delay_ms(2); //no point in waiting too fast
289  if( present() == true ) {
290  return true;
291  }
292  }
293  DPRINTLN(F("ERROR EEPROM WAIT"));
294  return false;
295  }
296 
297 };
298 
299 template <uint8_t ID,uint16_t PAGES,uint8_t PAGESIZE>
300 class CachedAt24cX : public at24cX<ID,PAGES,PAGESIZE> {
301  uint8_t pagecache[PAGESIZE];
302  uint16_t pageaddr;
303  bool dirty;
304 public:
306  CachedAt24cX () : pageaddr(0xffff), dirty(false) {}
307 
308  void store () {
309  writecache();
310  }
311 
312 protected:
313  void writecache () {
314  if( pageaddr != 0xffff && dirty == true ) {
315  // DPRINT("WRITECACHE "); DHEXLN(pageaddr);
316  Base::setData(pageaddr, pagecache, PAGESIZE);
317  dirty = false;
318  }
319  }
320 
321  uint8_t* fillcache(uint16_t addr) {
322  uint16_t paddr = addr & ~(PAGESIZE-1);
323  if( pageaddr != paddr ) {
324  writecache();
325  pageaddr = paddr;
326  // DPRINT("FILLCACHE "); DHEXLN(pageaddr);
327  Base::getData(pageaddr,pagecache,PAGESIZE);
328  dirty = false;
329  }
330  return pagecache;
331  }
332 
333  void clearcache () {
334  writecache();
335  // DPRINT("CLEARCACHE\n");
336  pageaddr = 0xffff;
337  }
338 
339 public:
340  uint8_t getByte (uint16_t addr) {
341  fillcache(addr);
342  return pagecache[addr - pageaddr];
343  }
344 
345  bool setByte (uint16_t addr, uint8_t d) {
346  fillcache(addr);
347  pagecache[addr - pageaddr] = d;
348  dirty = true;
349  return true;
350  }
351 
352  bool getData (uint16_t addr,uint8_t* buf,uint16_t size) {
353  writecache();
354  return Base::getData(addr, buf, size);
355  }
356 
357  bool setData (uint16_t addr,uint8_t* buf,uint16_t size) {
358  clearcache();
359  return Base::setData(addr, buf, size);
360  }
361 
362  bool clearData (uint16_t addr, uint16_t size) {
363  clearcache();
364  return Base::clearData(addr, size);
365  }
366 
367 };
368 
369 // define some known EEPROM types
372 
373 #endif
374 
375 
376 template <class DRIVER=InternalEprom>
377 class StorageWrapper : public DRIVER {
378 
379 public:
380  StorageWrapper () {}
381 
382  bool setup (uint16_t checksum=0) {
383  bool firststart = false;
384  uint32_t mem;
385  DRIVER::getData(0x0,(uint8_t*)&mem,4);
386  uint32_t magic = 0xCAFE0000 | checksum;
387  if(magic != mem) {
388  DHEXLN(mem);
389  DPRINT(F("Init Storage: "));
390  DHEXLN(magic);
391  // init eeprom
392  DRIVER::setData(0x0,(uint8_t*)&magic,4);
393  firststart = true;
394  }
395  return firststart;
396  }
397 
398  bool setBits (uint16_t addr, uint8_t bits) {
399  DRIVER::setByte(addr,DRIVER::getByte(addr) | bits);
400  return true;
401  }
402 
403  bool clearBits (uint16_t addr, uint8_t bits) {
404  DRIVER::setByte(addr,DRIVER::getByte(addr) & ~bits);
405  return true;
406  }
407 
408  bool setData (uint16_t addr,uint8_t* buf,uint16_t size) {
409  return DRIVER::setData(addr,buf,size);
410  }
411 
412  template <class T>
413  bool setData (uint16_t addr,const T& obj) {
414  return DRIVER::setData(addr,(uint8_t*)&obj,sizeof(T));
415  }
416 
417  bool getData (uint16_t addr,uint8_t* buf,uint16_t size) {
418  return DRIVER::getData(addr,buf,size);
419  }
420 
421  template <class T>
422  bool getData (uint16_t addr,T* obj) {
423  return DRIVER::getData(addr,(uint8_t*)obj,sizeof(T));
424  }
425 
426  bool clearData (uint16_t addr, uint16_t size) {
427  return DRIVER::clearData(addr,size);
428  }
429 
430  void reset () {
431  // clear magic
432  clearData(0x0,4);
433  }
434 
435  void dump (uint16_t start, uint16_t num) {
436  for( uint16_t i=0; i<num; ++i, ++start ) {
437  DHEX(DRIVER::getByte(start));
438  DPRINT(F(" "));
439  }
440  DPRINT(F("\n"));
441  }
442 
443 };
444 
445 #ifndef STORAGEDRIVER
446 #define STORAGEDRIVER InternalEprom
447 #endif
448 
449 extern void* __gb_store;
450 
451 class Storage : public StorageWrapper<STORAGEDRIVER > {
452 public:
453  Storage () {
454  __gb_store = this;
455  }
456 };
457 
458 
459 static inline Storage& storage () {
460  return *((Storage*)__gb_store);
461 }
462 
463 #define STORAGE_CFG_START 0x04
465  uint8_t size;
466 public:
467  StorageConfig (uint8_t s) : size(s) {}
468 
469  uint8_t checksum () const {
470  uint8_t sum = 0x5e;
471  for( uint8_t i=0; i<size-1; ++i ) {
472  sum ^= getByte(i);
473  }
474  return sum;
475  }
476 
477  void validate () {
478  setByte(size-1,checksum());
479  }
480 
481  bool valid () const {
482  return getByte(size-1) == checksum();
483  }
484 
485  void clear () {
486  storage().clearData(STORAGE_CFG_START, size);
487  }
488 
489  uint8_t getSize () const {
490  return size-1;
491  }
492 
493  uint8_t getByte (uint8_t offset) const {
494  return storage().getByte(STORAGE_CFG_START+offset);
495  }
496 
497  void setByte(uint8_t offset,uint8_t data) {
498  storage().setByte(STORAGE_CFG_START+offset,data);
499  }
500 };
501 
505 class UserStorage {
506  uint16_t start;
507 public:
508  UserStorage (uint16_t s) : start(s) {}
509 
510  uint16_t getAddress () const {
511  return start;
512  }
513 
514  uint16_t getSize () const {
515  return storage().size() - getAddress();
516  }
517 
518  void clear () {
519  storage().clearData(getAddress(),getSize());
520  }
521 
522  uint8_t getByte (uint16_t offset) const {
523  return storage().getByte(getAddress()+offset);
524  }
525 
526  void setByte(uint16_t offset,uint8_t data) {
527  storage().setByte(getAddress()+offset,data);
528  }
529 
530  void setData (uint16_t offset,uint8_t* buf,uint16_t size) {
531  storage().setData(getAddress()+offset,buf,size);
532  }
533 
534  void getData (uint16_t offset,uint8_t* buf,uint16_t size) {
535  storage().getData(getAddress()+offset,buf,size);
536  }
537 
538  template <class T>
539  void setData (uint16_t offset,const T& obj) {
540  setData(offset,(uint8_t*)&obj,sizeof(T));
541  }
542 
543  template <class T>
544  void getData (uint16_t offset,T* obj) {
545  getData(offset,(uint8_t*)obj,sizeof(T));
546  }
547 
548 };
549 
550 }
551 
552 #endif
as::UserStorage
Definition: Storage.h:505
as::at24cX
Definition: Storage.h:154
as::StorageConfig
Definition: Storage.h:464
as::CachedAt24cX
Definition: Storage.h:300
as::InternalEprom
Definition: Storage.h:17
as::Storage
Definition: Storage.h:451
as::StorageWrapper
Definition: Storage.h:377