Skip to content

Rewrite EEPROM.h to avoid GNU-licensed code #198

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions SampleProjects/TestSomething/test/eeprom.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#include <ArduinoUnitTests.h>
#include <Arduino.h>
#include <Godmode.h>

// Only run EEPROM tests if there is hardware support!
#if defined(EEPROM_SIZE) || (defined(E2END) && E2END)
#if defined(EEPROM_SIZE)
#include <EEPROM.h>

GodmodeState* state = GODMODE();

unittest_setup()
{
state->reset();
Expand All @@ -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);
Expand Down
208 changes: 53 additions & 155 deletions cpp/arduino/EEPROM.h
Original file line number Diff line number Diff line change
@@ -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 <cassert>
#include <inttypes.h>
#include <avr/io.h>

// different EEPROM implementations have different macros that leak out
#if !defined(EEPROM_SIZE) && defined(E2END) && (E2END)
#define EEPROM_SIZE (E2END + 1)
#endif
#include <Godmode.h>

// 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 <typename T> 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 <typename T> 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;
5 changes: 5 additions & 0 deletions cpp/arduino/Godmode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,8 @@ SPIClass SPI = SPIClass(&GODMODE()->spi.dataIn, &GODMODE()->spi.dataOut);

// defined in Wire.h
TwoWire Wire = TwoWire();

#if defined(EEPROM_SIZE)
#include <EEPROM.h>
EEPROMClass EEPROM;
#endif
17 changes: 14 additions & 3 deletions cpp/arduino/Godmode.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <avr/io.h>
#include "WString.h"
#include "PinHistory.h"
#include "EEPROM.h"

// random
void randomSeed(unsigned long seed);
Expand Down Expand Up @@ -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 {
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
}
}

Expand Down