I've been working on an EEPROM utility inspired by this thread.
One of the features I'd like to include is a search function, possibly utilizing the eeprom compare function developed by @ J-M-L. Ideally, the user, after specifying a radix can enter a search term of a (legal) variable size and the sketch will locate same if it exists.
I've put together a small sketch which demonstrates the idea above - comparing only one argument at one address - using hex strings but it seems clunky. Part of the clunkiness stems from having to include three searches, one for each variable type. Perhaps it's unavoidable.
Now comes the part where I'm not sure of the right questions to ask:
I thought to use templates but, since a template would generate code for each type of variable it would in principle basically be the same as what's in my little demo, no? What I want is to select the variable type (byte, unsigned, unsigned long) at runtime and make one call to memcmp_E.
Is this possible? If so, does this have a name I could do some research on?
It's also occurred to me to make up a short function to search the whole EEPROM one byte at a time, feeding it the argument and eeprom addresses. Then, for the two-byte arguments make a function which breaks the argument in two and calls the one-byte function twice. And again, for the four-byte arguments make a function which breaks those in two and calls the two-byte compare function twice. I think this would then obviate the need for memcmp_E and I could revert to EEPROM.read. Is this introducing more clunkiness? Too convoluted?
Any alternatives to simplify the whole thing?
Compare demo:
// Compare hex values in EEPROM vs. RAM
// https://forum.arduino.cc/index.php?topic=455332.msg4350937#new Originating idea
#include <EEPROM.h>
#include "MEMCMP_E.h"
// using eeprom data from j-m-l loader
char str[] = "ef";
char str2[] = "dead";
char str3[] = "deadbeef";
char searchBuffer[9];
unsigned long number;
byte sArgB;
unsigned sArgW;
unsigned long sArgL;
bool found;
void setup() {
Serial.begin(115200);
Serial.println(__FILE__);
for (byte i = 8 ; i < 20; i++)
{ Serial.print(EEPROM.read( i), 16);
Serial.print(" ");
}
Serial.println();
Serial.println(searchBuffer);
// strcpy(searchBuffer,str); // uncomment to test
// strcpy(searchBuffer,str2); // uncomment to test
strcpy(searchBuffer, str3); // uncomment to test
byte argChars = strlen(searchBuffer);
Serial.println(argChars);
// scan target string for non-hex characters
for (byte i = 0; i < argChars; i++) {
if (!isxdigit(searchBuffer[i])) {
Serial.println("string contains non-hex characters");
break;
}
}
if (isxdigit(searchBuffer[0]))
{
number = strtoul (searchBuffer, NULL, 16);
Serial.print("The hexadecimal number '");
Serial.print(searchBuffer);
Serial.print("' = ");
Serial.println(number);
}
if (argChars <= 2) { // 8-bit args
sArgB = number; // receive converted value
if (memcmp_E(&sArgB, 8, 1)) { // if true, was not found
Serial.println("not found");
}
else Serial.println("is found");
}
else if (argChars <= 4) { // 16-bit args
sArgW = number; // receive converted value
if (memcmp_E(&sArgW, 8, 1)) { // if true, was not found
Serial.println("not found");
}
else Serial.println("is found");
}
else if (argChars <= 8) { // 32-bit args
sArgL = number; // receive converted value
Serial.print("received 32-bit value = ");
Serial.println(sArgL);
if (memcmp_E(&sArgL, 8, 1)) { // if true, was not found
Serial.println("not found");
}
else Serial.println("is found");
}
else Serial.println("argument too large");
}
void loop() {
// put your main code here, to run repeatedly:
}
MEMCMP_E.h to do the comparisons
// memcmp_E function
//
// by J-M-L http://forum.arduino.cc/index.php?topic=584108.msg3978283#msg3978283
// -------------------------
// Takes: a pointer to a RAM address, eeprom address, and length.
// Function compares the data at the two addresses for
// len elements and returns true/false status of
// comparison. Since memcmp() is used, if all elements match
// a zero (false) is returned, +- value otherwise.
// Compares:
// char arrays - if (!memcmp_E(ts2, 111, 5))
//
// bytes - if (!memcmp_E(&aByte, EEPROM_addr, 1))
// if (!memcmp_E(aByteArray, 8, nbItemsInaByteArray))
//
// ints -
// longs -
template<typename T>
int memcmp_E(const T* ramStart, int eeprom_start, size_t len )
{
int result = 0; // create and initialize return value
uint8_t sample[sizeof(T)]; // allocate a buffer for EEPROM.get
for (size_t i = 0; i < len * sizeof(T); i += sizeof(T)) {
EEPROM.get( eeprom_start + i, sample); // copy EEPROM data out to RAM
// then use memcmp to do the compare - avoids dealing with endianness
result = memcmp ( ((uint8_t *) ramStart) + i, (uint8_t *) sample, sizeof(T) );
if (result) break; // ie. non-zero
}
return result;
}
J-M-L template loader to preload test values
// by J-M-L http://forum.arduino.cc/index.php?topic=584108.msg3978283#msg3978283
// This sketch preloads values for testing/evaluating the memcmp_E() function.
// string insertion added 11/4/19
#include <EEPROM.h>
void setup() {
const uint32_t v1 = 0xDEADBEEF;
const uint32_t v2 = 0xBADCAFFE;
const uint32_t v3 = 0xFEE4ABED;
// do this once to establish EEPROM values
EEPROM.put(8, v1);
EEPROM.put(12, v2);
EEPROM.put(16, v3);
// Put these strings to start at eeprom addr 100
int stringStart = 100; // Allows varying string lengths, if desired
char ts1[] = "test str 1"; // each is eleven bytes total
char ts2[] = "test str 2";
char ts3[] = "test str 3";
EEPROM.put(stringStart, ts1);
stringStart += sizeof(ts1);
EEPROM.put(111, ts2);
stringStart += sizeof(ts2);
EEPROM.put(122, ts3);
}
void loop() {}