EEPROM comparing

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() {}

Hi - thanks for the mention, I had totally forgotten this piece of code

You could use stringStart instead of hard coded addresses 111 and 122 (isn’t it why you computed them in the first place anyway?)

  int stringStart = 100; // Allows varying string lengths, if desired
...
  EEPROM.put(stringStart, ts1);
  stringStart += sizeof(ts1); // that’s 111, as sizeof() will account for the trailing NULL char
  EEPROM.put(111, ts2);
  stringStart += sizeof(ts2); // that’s 122
  EEPROM.put(122, ts3);

J-M-L:
You could use stringStart instead of hard coded addresses 111 and 122 (isn’t it why you computed them in the first place anyway?)

  int stringStart = 100; // Allows varying string lengths, if desired

??? Now I’m confused. The compare demo has these lines:

if (memcmp_E(&sArgB, 8, 1)) { // if true, was not found
and
if (memcmp_E(&sArgW, 8, 1)) { // if true, was not found
and
if (memcmp_E(&sArgL, 8, 1)) { // if true, was not found

My understanding is the compiler creates three functions, one to handle each of the three types.

Is it possible to code a function like:

if (memcmp_E(&, 8, 1)) { // if true, was not found

that could be called from several places, with different argument types, and yet have only one instance of it after compilation?

Apologies if I am not seeing the obvious. It happens all too often :^(

No, a function template by itself is not a type, or a function, or any other entity, it’s just a template, a model.

No code is generated from a source file that contains only template definitions. In order for any code to appear, a template must be instantiated: the template arguments must be determined so that the compiler can generate an actual function (or different functions with different signatures)

J-M-L:
No, a function template by itself is not a type, or a function, or any other entity, it’s just a template, a model.

No code is generated from a source file that contains only template definitions. In order for any code to appear, a template must be instantiated: the template arguments must be determined so that the compiler can generate an actual function (or different functions with different signatures)

So my reading has shown me.

I'm not locked in on templates, I'm just seeking some particular arrangement of code which can accept, at runtime, any of the three types (one byte, two byte, four byte) and return a t/f found result. Something like passing an argument to a function.

Thanks for the replies.

You could use void* as the type for your data pointer or cast it as (uint8_t*) (one byte, two byte, four byte), pass in the number of bytes to compare and compare byte by byte