From 6b22fe60f5df4a4b077b7b418e0f6c7575ab70df Mon Sep 17 00:00:00 2001 From: James Foster Date: Fri, 2 Oct 2020 17:28:56 -0700 Subject: [PATCH 01/14] Introduce EEPROM support (#166) --- SampleProjects/TestSomething/test/eeprom.cpp | 10 ++ cpp/arduino/EEPROM.h | 155 +++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 SampleProjects/TestSomething/test/eeprom.cpp create mode 100644 cpp/arduino/EEPROM.h diff --git a/SampleProjects/TestSomething/test/eeprom.cpp b/SampleProjects/TestSomething/test/eeprom.cpp new file mode 100644 index 00000000..ead3e371 --- /dev/null +++ b/SampleProjects/TestSomething/test/eeprom.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +unittest(length) +{ + assertEqual(EEPROM_SIZE, EEPROM.length()); +} + +unittest_main() diff --git a/cpp/arduino/EEPROM.h b/cpp/arduino/EEPROM.h new file mode 100644 index 00000000..75df36c6 --- /dev/null +++ b/cpp/arduino/EEPROM.h @@ -0,0 +1,155 @@ +/* + EEPROM.h - EEPROM library + Original Copyright (c) 2006 David A. Mellis. All right reserved. + New version by Christopher Andrews 2015. + + Copy of https://github.com/arduino/ArduinoCore-megaavr/blob/c8a1dd996c783777ec46167cfd8ad3fd2e6df185/libraries/EEPROM/src/EEPROM.h + modified by James Foster 2020 to work with Arduino CI. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef EEPROM_h +#define EEPROM_h + +#include +#include + +// I see EEPROM_SIZE defined in various arv/io*.h files; why isn't it defined here? +#define EEPROM_SIZE (4096) +// Is this all the custom code required? +static uint8_t eeprom[EEPROM_SIZE]; +inline uint8_t eeprom_read_byte( uint8_t* index ) { return eeprom[(unsigned long) index % EEPROM_SIZE]; } +inline void eeprom_write_byte( uint8_t* index, uint8_t value ) { eeprom[(unsigned long) index % EEPROM_SIZE] = value; } + +/*** + EERef class. + + This object references an EEPROM cell. + Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM. + This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell. +***/ + +struct EERef{ + + EERef( const int index ) + : index( index ) {} + + //Access/read members. + uint8_t operator*() const { return eeprom_read_byte( (uint8_t*) index ); } + operator uint8_t() const { return **this; } + + //Assignment/write members. + EERef &operator=( const EERef &ref ) { return *this = *ref; } + EERef &operator=( uint8_t in ) { return eeprom_write_byte( (uint8_t*) index, in ), *this; } + EERef &operator +=( uint8_t in ) { return *this = **this + in; } + EERef &operator -=( uint8_t in ) { return *this = **this - in; } + EERef &operator *=( uint8_t in ) { return *this = **this * in; } + EERef &operator /=( uint8_t in ) { return *this = **this / in; } + EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; } + EERef &operator %=( uint8_t in ) { return *this = **this % in; } + EERef &operator &=( uint8_t in ) { return *this = **this & in; } + EERef &operator |=( uint8_t in ) { return *this = **this | in; } + EERef &operator <<=( uint8_t in ) { return *this = **this << in; } + EERef &operator >>=( uint8_t in ) { return *this = **this >> in; } + + EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; } + + /** Prefix increment/decrement **/ + EERef& operator++() { return *this += 1; } + EERef& operator--() { return *this -= 1; } + + /** Postfix increment/decrement **/ + uint8_t operator++ (int){ + uint8_t ret = **this; + return ++(*this), ret; + } + + uint8_t operator-- (int){ + uint8_t ret = **this; + return --(*this), ret; + } + + int index; //Index of current EEPROM cell. +}; + +/*** + EEPtr class. + + This object is a bidirectional pointer to EEPROM cells represented by EERef objects. + Just like a normal pointer type, this can be dereferenced and repositioned using + increment/decrement operators. +***/ + +struct EEPtr{ + + EEPtr( const int index ) + : index( index ) {} + + operator int() const { return index; } + EEPtr &operator=( int in ) { return index = in, *this; } + + //Iterator functionality. + bool operator!=( const EEPtr &ptr ) { return index != ptr.index; } + EERef operator*() { return index; } + + /** Prefix & Postfix increment/decrement **/ + EEPtr& operator++() { return ++index, *this; } + EEPtr& operator--() { return --index, *this; } + EEPtr operator++ (int) { return index++; } + EEPtr operator-- (int) { return index--; } + + int index; //Index of current EEPROM cell. +}; + +/*** + EEPROMClass class. + + This object represents the entire EEPROM space. + It wraps the functionality of EEPtr and EERef into a basic interface. + This class is also 100% backwards compatible with earlier Arduino core releases. +***/ + +struct EEPROMClass{ + + //Basic user access methods. + EERef operator[]( const int idx ) { return idx; } + uint8_t read( int idx ) { return EERef( idx ); } + void write( int idx, uint8_t val ) { (EERef( idx )) = val; } + void update( int idx, uint8_t val ) { EERef( idx ).update( val ); } + + //STL and C++11 iteration capability. + EEPtr begin() { return 0x00; } + EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid. + uint16_t length() { return EEPROM_SIZE; } + + //Functionality to 'get' and 'put' objects to and from EEPROM. + template< typename T > T &get( int idx, T &t ){ + EEPtr e = idx; + uint8_t *ptr = (uint8_t*) &t; + for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e; + return t; + } + + template< typename T > const T &put( int idx, const T &t ){ + EEPtr e = idx; + const uint8_t *ptr = (const uint8_t*) &t; + for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ ); + return t; + } +}; + +static EEPROMClass EEPROM; +#endif \ No newline at end of file From 1011dc492ba38ba84c9675f9d628061718be9c67 Mon Sep 17 00:00:00 2001 From: James Foster Date: Mon, 5 Oct 2020 11:33:20 -0700 Subject: [PATCH 02/14] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68cc609c..83607321 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added +- Support for EEPROM ### Changed - Move repository from https://github.com/ianfixes/arduino_ci to https://github.com/Arduino-CI/arduino_ci From c512f287d430858a6fc39913d305ab3e791ca195 Mon Sep 17 00:00:00 2001 From: James Foster Date: Mon, 5 Oct 2020 12:22:22 -0700 Subject: [PATCH 03/14] Only include EEPROM if board supports it. --- CHANGELOG.md | 2 +- SampleProjects/TestSomething/.arduino-ci.yml | 1 + SampleProjects/TestSomething/test/eeprom.cpp | 11 +++++++++++ cpp/arduino/EEPROM.h | 7 ++++--- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83607321..d2e5d9cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added -- Support for EEPROM +- Support for mock EEPROM (but only if board supports it; added mega2560 to TestSomething config) ### Changed - Move repository from https://github.com/ianfixes/arduino_ci to https://github.com/Arduino-CI/arduino_ci diff --git a/SampleProjects/TestSomething/.arduino-ci.yml b/SampleProjects/TestSomething/.arduino-ci.yml index c418bdbe..16298baf 100644 --- a/SampleProjects/TestSomething/.arduino-ci.yml +++ b/SampleProjects/TestSomething/.arduino-ci.yml @@ -4,6 +4,7 @@ unittest: platforms: - uno - due + - mega2560 compile: platforms: diff --git a/SampleProjects/TestSomething/test/eeprom.cpp b/SampleProjects/TestSomething/test/eeprom.cpp index ead3e371..0068a8e9 100644 --- a/SampleProjects/TestSomething/test/eeprom.cpp +++ b/SampleProjects/TestSomething/test/eeprom.cpp @@ -2,9 +2,20 @@ #include #include +#ifdef EEPROM_SIZE + unittest(length) { assertEqual(EEPROM_SIZE, EEPROM.length()); } +#else + +unittest(eeprom) +{ + assertTrue(true); +} + +#endif + unittest_main() diff --git a/cpp/arduino/EEPROM.h b/cpp/arduino/EEPROM.h index 75df36c6..a3c40f39 100644 --- a/cpp/arduino/EEPROM.h +++ b/cpp/arduino/EEPROM.h @@ -27,8 +27,8 @@ #include #include -// I see EEPROM_SIZE defined in various arv/io*.h files; why isn't it defined here? -#define EEPROM_SIZE (4096) +#ifdef EEPROM_SIZE + // Is this all the custom code required? static uint8_t eeprom[EEPROM_SIZE]; inline uint8_t eeprom_read_byte( uint8_t* index ) { return eeprom[(unsigned long) index % EEPROM_SIZE]; } @@ -152,4 +152,5 @@ struct EEPROMClass{ }; static EEPROMClass EEPROM; -#endif \ No newline at end of file +#endif +#endif From 524d35284027cd71118209bda2dbca41534bb4c0 Mon Sep 17 00:00:00 2001 From: James Foster Date: Mon, 5 Oct 2020 17:11:51 -0700 Subject: [PATCH 04/14] Add EEPROM_SIZE to mega boards. --- SampleProjects/TestSomething/test/eeprom.cpp | 7 ------- cpp/arduino/avr/iomxx0_1.h | 11 +++++++++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/SampleProjects/TestSomething/test/eeprom.cpp b/SampleProjects/TestSomething/test/eeprom.cpp index 0068a8e9..f773a046 100644 --- a/SampleProjects/TestSomething/test/eeprom.cpp +++ b/SampleProjects/TestSomething/test/eeprom.cpp @@ -9,13 +9,6 @@ unittest(length) assertEqual(EEPROM_SIZE, EEPROM.length()); } -#else - -unittest(eeprom) -{ - assertTrue(true); -} - #endif unittest_main() diff --git a/cpp/arduino/avr/iomxx0_1.h b/cpp/arduino/avr/iomxx0_1.h index 374c5f40..553d46d6 100644 --- a/cpp/arduino/avr/iomxx0_1.h +++ b/cpp/arduino/avr/iomxx0_1.h @@ -351,6 +351,17 @@ Last two letters: EEAR address. */ #define __EEPROM_REG_LOCATIONS__ 1F2021 +/* According to https://ww1.microchip.com/downloads/en/devicedoc/atmel-2549-8-bit-avr-microcontroller-atmega640-1280-1281-2560-2561_datasheet.pdf, + * the Atmel ATmega640/V-1280/V-1281/V-2560/V-2561/V microcontrollers each have + * 4Kbytes of EEPROM and since this file is included from things that seem + * to match that description, it would be helpful to know that EEPROM is + * available and know its size. This macro is defined for many other models, + * so we will add it here. + * + * See https://github.com/Arduino-CI/arduino_ci/issues/166#issuecomment-703904394. + */ +#define EEPROM_SIZE (4096) + #define GTCCR _SFR_IO8(0x23) #define TSM 7 #define PSRASY 1 From 8ed2732c5904c1aa0689068093ccd4b7d64ed906 Mon Sep 17 00:00:00 2001 From: James Foster Date: Mon, 5 Oct 2020 18:21:05 -0700 Subject: [PATCH 05/14] Move `EEPROM_SIZE` macro to `misc/default.yml`. --- cpp/arduino/avr/iomxx0_1.h | 11 ----------- misc/default.yml | 1 + 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/cpp/arduino/avr/iomxx0_1.h b/cpp/arduino/avr/iomxx0_1.h index 553d46d6..374c5f40 100644 --- a/cpp/arduino/avr/iomxx0_1.h +++ b/cpp/arduino/avr/iomxx0_1.h @@ -351,17 +351,6 @@ Last two letters: EEAR address. */ #define __EEPROM_REG_LOCATIONS__ 1F2021 -/* According to https://ww1.microchip.com/downloads/en/devicedoc/atmel-2549-8-bit-avr-microcontroller-atmega640-1280-1281-2560-2561_datasheet.pdf, - * the Atmel ATmega640/V-1280/V-1281/V-2560/V-2561/V microcontrollers each have - * 4Kbytes of EEPROM and since this file is included from things that seem - * to match that description, it would be helpful to know that EEPROM is - * available and know its size. This macro is defined for many other models, - * so we will add it here. - * - * See https://github.com/Arduino-CI/arduino_ci/issues/166#issuecomment-703904394. - */ -#define EEPROM_SIZE (4096) - #define GTCCR _SFR_IO8(0x23) #define TSM 7 #define PSRASY 1 diff --git a/misc/default.yml b/misc/default.yml index 67d7f87f..1d2629de 100644 --- a/misc/default.yml +++ b/misc/default.yml @@ -100,6 +100,7 @@ platforms: features: defines: - __AVR_ATmega2560__ + - EEPROM_SIZE=(4096) warnings: flags: cplayClassic: From fadc74334bb16088d862cf7bc7bfea3d800c2f83 Mon Sep 17 00:00:00 2001 From: James Foster Date: Mon, 5 Oct 2020 21:42:28 -0700 Subject: [PATCH 06/14] Use E2END to calculate EEPROM_SIZE. --- cpp/arduino/EEPROM.h | 3 +++ misc/default.yml | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/arduino/EEPROM.h b/cpp/arduino/EEPROM.h index a3c40f39..7eef18b3 100644 --- a/cpp/arduino/EEPROM.h +++ b/cpp/arduino/EEPROM.h @@ -27,6 +27,9 @@ #include #include +#if !defined(EEPROM_SIZE) && defined(E2END) && (E2END) +#define EEPROM_SIZE (E2END + 1) +#endif #ifdef EEPROM_SIZE // Is this all the custom code required? diff --git a/misc/default.yml b/misc/default.yml index 1d2629de..67d7f87f 100644 --- a/misc/default.yml +++ b/misc/default.yml @@ -100,7 +100,6 @@ platforms: features: defines: - __AVR_ATmega2560__ - - EEPROM_SIZE=(4096) warnings: flags: cplayClassic: From 0ee51702bd76681dc4967eb66215b6ba0dec1531 Mon Sep 17 00:00:00 2001 From: James Foster Date: Mon, 5 Oct 2020 21:51:34 -0700 Subject: [PATCH 07/14] EEPROM is tested by uno and due so we don't need to add mega2560 (one less file changed). --- SampleProjects/TestSomething/.arduino-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/SampleProjects/TestSomething/.arduino-ci.yml b/SampleProjects/TestSomething/.arduino-ci.yml index 16298baf..c418bdbe 100644 --- a/SampleProjects/TestSomething/.arduino-ci.yml +++ b/SampleProjects/TestSomething/.arduino-ci.yml @@ -4,7 +4,6 @@ unittest: platforms: - uno - due - - mega2560 compile: platforms: From 4605207bc2ac30b8475b13b1a1b4ff41713f81a2 Mon Sep 17 00:00:00 2001 From: James Foster Date: Tue, 6 Oct 2020 22:23:27 -0700 Subject: [PATCH 08/14] Simplify reference to EEPROM library. --- CHANGELOG.md | 2 +- SampleProjects/TestSomething/test/eeprom.cpp | 5 +++-- cpp/arduino/EEPROM.h | 15 +++++++++++---- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3101da3..68f6f0d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added -- Support for mock EEPROM (but only if board supports it; added mega2560 to TestSomething config) +- Support for mock EEPROM (but only if board supports it) ### Changed - Move repository from https://github.com/ianfixes/arduino_ci to https://github.com/Arduino-CI/arduino_ci diff --git a/SampleProjects/TestSomething/test/eeprom.cpp b/SampleProjects/TestSomething/test/eeprom.cpp index f773a046..440d6f1c 100644 --- a/SampleProjects/TestSomething/test/eeprom.cpp +++ b/SampleProjects/TestSomething/test/eeprom.cpp @@ -1,8 +1,9 @@ #include #include -#include -#ifdef EEPROM_SIZE +// Only run EEPROM tests if there is hardware support! +#if defined(EEPROM_SIZE) || (defined(E2END) && E2END) +#include unittest(length) { diff --git a/cpp/arduino/EEPROM.h b/cpp/arduino/EEPROM.h index 7eef18b3..39fa91f8 100644 --- a/cpp/arduino/EEPROM.h +++ b/cpp/arduino/EEPROM.h @@ -4,7 +4,7 @@ New version by Christopher Andrews 2015. Copy of https://github.com/arduino/ArduinoCore-megaavr/blob/c8a1dd996c783777ec46167cfd8ad3fd2e6df185/libraries/EEPROM/src/EEPROM.h - modified by James Foster 2020 to work with Arduino CI. + modified by James Foster in 2020 to work with Arduino CI. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -27,16 +27,24 @@ #include #include +// different EEPROM implementations have different macros that leak out #if !defined(EEPROM_SIZE) && defined(E2END) && (E2END) #define EEPROM_SIZE (E2END + 1) #endif -#ifdef EEPROM_SIZE -// Is this all the custom code required? +// Does the current board have EEPROM? +#ifndef EEPROM_SIZE +// In lieu of an "EEPROM.h not found" error for unsupported boards +#error "EEPROM library not available for your board" +#endif + +// On a real device this would be in hardware, but we have a mock board! static uint8_t eeprom[EEPROM_SIZE]; inline uint8_t eeprom_read_byte( uint8_t* index ) { return eeprom[(unsigned long) index % EEPROM_SIZE]; } inline void eeprom_write_byte( uint8_t* index, uint8_t value ) { eeprom[(unsigned long) index % EEPROM_SIZE] = value; } +// Everything following is from the original (referenced above) + /*** EERef class. @@ -156,4 +164,3 @@ struct EEPROMClass{ static EEPROMClass EEPROM; #endif -#endif From 2ad01315aeaa9087a8a030c1a43e7ba501edd05b Mon Sep 17 00:00:00 2001 From: Elizabeth Ventura Date: Sun, 11 Oct 2020 15:07:59 -0700 Subject: [PATCH 09/14] adding tests for EEPROM --- SampleProjects/TestSomething/test/eeprom.cpp | 49 ++++++++++++++++++++ cpp/arduino/Godmode.h | 8 ++++ 2 files changed, 57 insertions(+) diff --git a/SampleProjects/TestSomething/test/eeprom.cpp b/SampleProjects/TestSomething/test/eeprom.cpp index 440d6f1c..f2f9faed 100644 --- a/SampleProjects/TestSomething/test/eeprom.cpp +++ b/SampleProjects/TestSomething/test/eeprom.cpp @@ -10,6 +10,55 @@ unittest(length) assertEqual(EEPROM_SIZE, EEPROM.length()); } +unittest(firstRead) +{ + uint8_t a = EEPROM.read(0); + assertEqual(255, a); +} + +unittest(writeRead) +{ + EEPROM.write(0, 24); + uint8_t a = EEPROM.read(0); + assertEqual(24, a); + + EEPROM.write(0, 128); + uint8_t b = EEPROM.read(0); + assertEqual(128, b); + +// this will fail since it is out of bound (0 - 255) + EEPROM.write(0, 256); + uint8_t c = EEPROM.read(0); + assertEqual(256, c); + +} + +unittest(updateWrite) +{ + EEPROM.write(1, 14); + EEPROM.update(1, 22); + uint8_t a = EEPROM.read(1); + assertEqual(22, a); +} + +unittest(putGet) +{ + const float f1 = 0.025f; + float f2 = 0.0f; + EEPROM.put(5, f1); + assertEqual(0.0f, f2); + EEPROM.get(5, f2); + assertEqual(0.025f, f2); +} + +unittest(array) +{ + int val = 10; + EEPROM[2] = val; + uint8_t a = EEPROM.read(2); + assertEqual(10, a); +} + #endif unittest_main() diff --git a/cpp/arduino/Godmode.h b/cpp/arduino/Godmode.h index 12fa1b51..0cc16514 100644 --- a/cpp/arduino/Godmode.h +++ b/cpp/arduino/Godmode.h @@ -3,6 +3,7 @@ #include #include "WString.h" #include "PinHistory.h" +#include "EEPROM.h" // random void randomSeed(unsigned long seed); @@ -87,12 +88,19 @@ class GodmodeState { spi.readDelayMicros = 0; } + void resetEEPROM() { + for(int i = 0; i < EEPROM.length(); ++i){ + EEPROM.update(i, 255); + } + } + void reset() { resetClock(); resetPins(); resetInterrupts(); resetPorts(); resetSPI(); + resetEEPROM(); seed = 1; } From 5c26abdae24dad53c8552f415546bb7231d183b0 Mon Sep 17 00:00:00 2001 From: Elizabeth Ventura Date: Sun, 11 Oct 2020 18:34:28 -0700 Subject: [PATCH 10/14] test high memory and array read. --- SampleProjects/TestSomething/test/eeprom.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/SampleProjects/TestSomething/test/eeprom.cpp b/SampleProjects/TestSomething/test/eeprom.cpp index f2f9faed..7abed1cc 100644 --- a/SampleProjects/TestSomething/test/eeprom.cpp +++ b/SampleProjects/TestSomething/test/eeprom.cpp @@ -23,14 +23,22 @@ unittest(writeRead) assertEqual(24, a); EEPROM.write(0, 128); - uint8_t b = EEPROM.read(0); - assertEqual(128, b); + a = EEPROM.read(0); + assertEqual(128, a); -// this will fail since it is out of bound (0 - 255) EEPROM.write(0, 256); - uint8_t c = EEPROM.read(0); - assertEqual(256, c); + a = EEPROM.read(0); + assertEqual(0, a); + int addr = EEPROM_SIZE / 2; + EEPROM.write(addr, 63); + a = EEPROM.read(addr); + assertEqual(63, a); + + addr = EEPROM_SIZE - 1; + EEPROM.write(addr, 188); + a = EEPROM.read(addr); + assertEqual(188, a); } unittest(updateWrite) @@ -55,7 +63,7 @@ unittest(array) { int val = 10; EEPROM[2] = val; - uint8_t a = EEPROM.read(2); + uint8_t a = EEPROM[2]; assertEqual(10, a); } From f923a7fbbdbce3d67c7dc9d13fd77299cd603f0e Mon Sep 17 00:00:00 2001 From: Elizabeth Ventura Date: Mon, 12 Oct 2020 09:22:07 -0700 Subject: [PATCH 11/14] add setup to reset memory before each test --- SampleProjects/TestSomething/test/eeprom.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/SampleProjects/TestSomething/test/eeprom.cpp b/SampleProjects/TestSomething/test/eeprom.cpp index 7abed1cc..5e2e7a6e 100644 --- a/SampleProjects/TestSomething/test/eeprom.cpp +++ b/SampleProjects/TestSomething/test/eeprom.cpp @@ -5,6 +5,12 @@ #if defined(EEPROM_SIZE) || (defined(E2END) && E2END) #include +GodmodeState* state = GODMODE(); +unittest_setup() +{ + state->reset(); +} + unittest(length) { assertEqual(EEPROM_SIZE, EEPROM.length()); From 9c74e43980ec678e5fe20cb64b32a942078b4304 Mon Sep 17 00:00:00 2001 From: James Foster Date: Mon, 26 Oct 2020 22:27:07 -0700 Subject: [PATCH 12/14] Add documentation of EEPROM (fix #190). --- REFERENCE.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/REFERENCE.md b/REFERENCE.md index da04de88..5ad63979 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -581,3 +581,40 @@ unittest(spi) { assertEqual("LMNOe", String(inBuf)); } ``` + +### EEPROM + +`EEPROM` is a global with a simple API to read and write bytes to persistent memory (like a tiny hard disk) given an `int` location. Since the Arduino core already provides this as a global, and the core API is sufficient for basic testing (read/write), there is no direct tie to the `GODMODE` API. (If you need more, such as a log of intermediate values, enter a feature request.) + +```C++ +unittest(eeprom) +{ + uint8_t a; + // size + assertEqual(EEPROM_SIZE, EEPROM.length()); + // initial values + a = EEPROM.read(0); + assertEqual(255, a); + // write and read + EEPROM.write(0, 24); + a = EEPROM.read(0); + assertEqual(24, a); + // update + EEPROM.write(1, 14); + EEPROM.update(1, 22); + a = EEPROM.read(1); + assertEqual(22, a); + // put and get + const float f1 = 0.025f; + float f2 = 0.0f; + EEPROM.put(5, f1); + assertEqual(0.0f, f2); + EEPROM.get(5, f2); + assertEqual(0.025f, f2); + // array access + int val = 10; + EEPROM[2] = val; + a = EEPROM[2]; + assertEqual(10, a); +} +``` From d7e7653dc49ece9bdff75b052a8c2819aa5c12b9 Mon Sep 17 00:00:00 2001 From: James Foster Date: Sat, 7 Nov 2020 21:08:04 -0800 Subject: [PATCH 13/14] Rewrite EEPROM.h to avoid GNU-licensed code. --- SampleProjects/TestSomething/test/eeprom.cpp | 8 +- cpp/arduino/EEPROM.h | 208 +++++-------------- cpp/arduino/Godmode.cpp | 3 + cpp/arduino/Godmode.h | 17 +- 4 files changed, 75 insertions(+), 161 deletions(-) diff --git a/SampleProjects/TestSomething/test/eeprom.cpp b/SampleProjects/TestSomething/test/eeprom.cpp index 5e2e7a6e..8a844249 100644 --- a/SampleProjects/TestSomething/test/eeprom.cpp +++ b/SampleProjects/TestSomething/test/eeprom.cpp @@ -1,11 +1,13 @@ #include #include +#include // Only run EEPROM tests if there is hardware support! -#if defined(EEPROM_SIZE) || (defined(E2END) && E2END) +#if defined(EEPROM_SIZE) #include GodmodeState* state = GODMODE(); + unittest_setup() { state->reset(); @@ -32,9 +34,9 @@ unittest(writeRead) a = EEPROM.read(0); assertEqual(128, a); - EEPROM.write(0, 256); + EEPROM.write(0, 255); a = EEPROM.read(0); - assertEqual(0, a); + assertEqual(255, a); int addr = EEPROM_SIZE / 2; EEPROM.write(addr, 63); diff --git a/cpp/arduino/EEPROM.h b/cpp/arduino/EEPROM.h index 39fa91f8..05b3daa5 100644 --- a/cpp/arduino/EEPROM.h +++ b/cpp/arduino/EEPROM.h @@ -1,166 +1,64 @@ -/* - EEPROM.h - EEPROM library - Original Copyright (c) 2006 David A. Mellis. All right reserved. - New version by Christopher Andrews 2015. - - Copy of https://github.com/arduino/ArduinoCore-megaavr/blob/c8a1dd996c783777ec46167cfd8ad3fd2e6df185/libraries/EEPROM/src/EEPROM.h - modified by James Foster in 2020 to work with Arduino CI. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef EEPROM_h -#define EEPROM_h +#pragma once +#include #include -#include - -// different EEPROM implementations have different macros that leak out -#if !defined(EEPROM_SIZE) && defined(E2END) && (E2END) -#define EEPROM_SIZE (E2END + 1) -#endif +#include // Does the current board have EEPROM? #ifndef EEPROM_SIZE -// In lieu of an "EEPROM.h not found" error for unsupported boards -#error "EEPROM library not available for your board" + // In lieu of an "EEPROM.h not found" error for unsupported boards + #error "EEPROM library not available for your board" #endif -// On a real device this would be in hardware, but we have a mock board! -static uint8_t eeprom[EEPROM_SIZE]; -inline uint8_t eeprom_read_byte( uint8_t* index ) { return eeprom[(unsigned long) index % EEPROM_SIZE]; } -inline void eeprom_write_byte( uint8_t* index, uint8_t value ) { eeprom[(unsigned long) index % EEPROM_SIZE] = value; } - -// Everything following is from the original (referenced above) - -/*** - EERef class. - - This object references an EEPROM cell. - Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM. - This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell. -***/ - -struct EERef{ - - EERef( const int index ) - : index( index ) {} - - //Access/read members. - uint8_t operator*() const { return eeprom_read_byte( (uint8_t*) index ); } - operator uint8_t() const { return **this; } - - //Assignment/write members. - EERef &operator=( const EERef &ref ) { return *this = *ref; } - EERef &operator=( uint8_t in ) { return eeprom_write_byte( (uint8_t*) index, in ), *this; } - EERef &operator +=( uint8_t in ) { return *this = **this + in; } - EERef &operator -=( uint8_t in ) { return *this = **this - in; } - EERef &operator *=( uint8_t in ) { return *this = **this * in; } - EERef &operator /=( uint8_t in ) { return *this = **this / in; } - EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; } - EERef &operator %=( uint8_t in ) { return *this = **this % in; } - EERef &operator &=( uint8_t in ) { return *this = **this & in; } - EERef &operator |=( uint8_t in ) { return *this = **this | in; } - EERef &operator <<=( uint8_t in ) { return *this = **this << in; } - EERef &operator >>=( uint8_t in ) { return *this = **this >> in; } - - EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; } - - /** Prefix increment/decrement **/ - EERef& operator++() { return *this += 1; } - EERef& operator--() { return *this -= 1; } - - /** Postfix increment/decrement **/ - uint8_t operator++ (int){ - uint8_t ret = **this; - return ++(*this), ret; +class EEPROMClass { +private: + GodmodeState* state; +public: + // constructor + EEPROMClass() { + state = GODMODE(); + } + // array subscript operator + uint8_t &operator[](const int index) { + assert(index < EEPROM_SIZE); + return state->eeprom[index]; + } + + uint8_t read(const int index) { + assert(index < EEPROM_SIZE); + return state->eeprom[index]; + } + + void write(const int index, const uint8_t value) { + assert(index < EEPROM_SIZE); + state->eeprom[index] = value; + } + + void update(const int index, const uint8_t value) { + assert(index < EEPROM_SIZE); + state->eeprom[index] = value; + } + + uint16_t length() { return EEPROM_SIZE; } + + // read any object + template T &get(const int index, T &object) { + uint8_t *ptr = (uint8_t *)&object; + for (int i = 0; i < sizeof(T); ++i) { + *ptr++ = read(index + i); } - - uint8_t operator-- (int){ - uint8_t ret = **this; - return --(*this), ret; + return object; + } + + // write any object + template const T &put(const int index, T &object) { + const uint8_t *ptr = (const uint8_t *)&object; + for (int i = 0; i < sizeof(T); ++i) { + write(index + i, *ptr++); } - - int index; //Index of current EEPROM cell. + return object; + } }; -/*** - EEPtr class. - - This object is a bidirectional pointer to EEPROM cells represented by EERef objects. - Just like a normal pointer type, this can be dereferenced and repositioned using - increment/decrement operators. -***/ - -struct EEPtr{ - - EEPtr( const int index ) - : index( index ) {} - - operator int() const { return index; } - EEPtr &operator=( int in ) { return index = in, *this; } - - //Iterator functionality. - bool operator!=( const EEPtr &ptr ) { return index != ptr.index; } - EERef operator*() { return index; } - - /** Prefix & Postfix increment/decrement **/ - EEPtr& operator++() { return ++index, *this; } - EEPtr& operator--() { return --index, *this; } - EEPtr operator++ (int) { return index++; } - EEPtr operator-- (int) { return index--; } - - int index; //Index of current EEPROM cell. -}; - -/*** - EEPROMClass class. - - This object represents the entire EEPROM space. - It wraps the functionality of EEPtr and EERef into a basic interface. - This class is also 100% backwards compatible with earlier Arduino core releases. -***/ - -struct EEPROMClass{ - - //Basic user access methods. - EERef operator[]( const int idx ) { return idx; } - uint8_t read( int idx ) { return EERef( idx ); } - void write( int idx, uint8_t val ) { (EERef( idx )) = val; } - void update( int idx, uint8_t val ) { EERef( idx ).update( val ); } - - //STL and C++11 iteration capability. - EEPtr begin() { return 0x00; } - EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid. - uint16_t length() { return EEPROM_SIZE; } - - //Functionality to 'get' and 'put' objects to and from EEPROM. - template< typename T > T &get( int idx, T &t ){ - EEPtr e = idx; - uint8_t *ptr = (uint8_t*) &t; - for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e; - return t; - } - - template< typename T > const T &put( int idx, const T &t ){ - EEPtr e = idx; - const uint8_t *ptr = (const uint8_t*) &t; - for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ ); - return t; - } -}; - -static EEPROMClass EEPROM; -#endif +// global available in Godmode.cpp +extern EEPROMClass EEPROM; diff --git a/cpp/arduino/Godmode.cpp b/cpp/arduino/Godmode.cpp index 102afca6..0c7afbf3 100644 --- a/cpp/arduino/Godmode.cpp +++ b/cpp/arduino/Godmode.cpp @@ -113,3 +113,6 @@ SPIClass SPI = SPIClass(&GODMODE()->spi.dataIn, &GODMODE()->spi.dataOut); // defined in Wire.h TwoWire Wire = TwoWire(); + +#include +EEPROMClass EEPROM; diff --git a/cpp/arduino/Godmode.h b/cpp/arduino/Godmode.h index 0cc16514..67e637b1 100644 --- a/cpp/arduino/Godmode.h +++ b/cpp/arduino/Godmode.h @@ -3,7 +3,6 @@ #include #include "WString.h" #include "PinHistory.h" -#include "EEPROM.h" // random void randomSeed(unsigned long seed); @@ -31,6 +30,17 @@ unsigned long micros(); #define NUM_SERIAL_PORTS 0 #endif +// different EEPROM implementations have different macros that leak out +#if !defined(EEPROM_SIZE) && defined(E2END) && (E2END) + // public value indicates that feature is available + #define EEPROM_SIZE (E2END + 1) + // local array size + #define _EEPROM_SIZE EEPROM_SIZE +#else + // feature is not available but we want to have the array so other code compiles + #define _EEPROM_SIZE (0) +#endif + class GodmodeState { private: struct PortDef { @@ -55,6 +65,7 @@ class GodmodeState { struct PortDef serialPort[NUM_SERIAL_PORTS]; struct InterruptDef interrupt[MOCK_PINS_COUNT]; // not sure how to get actual number struct PortDef spi; + uint8_t eeprom[_EEPROM_SIZE]; void resetPins() { for (int i = 0; i < MOCK_PINS_COUNT; ++i) { @@ -89,8 +100,8 @@ class GodmodeState { } void resetEEPROM() { - for(int i = 0; i < EEPROM.length(); ++i){ - EEPROM.update(i, 255); + for(int i = 0; i < EEPROM_SIZE; ++i){ + eeprom[i] = 255; } } From 03e4168415d7938dbfbc0d9c3cd50dbe2e1591e1 Mon Sep 17 00:00:00 2001 From: James Foster Date: Sun, 8 Nov 2020 23:10:57 -0800 Subject: [PATCH 14/14] Conditionalize inclusion of EEPROM. --- cpp/arduino/Godmode.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cpp/arduino/Godmode.cpp b/cpp/arduino/Godmode.cpp index 0c7afbf3..f68867e4 100644 --- a/cpp/arduino/Godmode.cpp +++ b/cpp/arduino/Godmode.cpp @@ -114,5 +114,7 @@ SPIClass SPI = SPIClass(&GODMODE()->spi.dataIn, &GODMODE()->spi.dataOut); // defined in Wire.h TwoWire Wire = TwoWire(); -#include -EEPROMClass EEPROM; +#if defined(EEPROM_SIZE) + #include + EEPROMClass EEPROM; +#endif