Browse over 10,000 Electronics Projects

OpenAccess eeprom functions

OpenAccess eeprom functions

I defined a lot of commands about how to store and retrieve stuff from the onboard eeprom.  Here they are with hopefully enough explanation.

//EEPROM stuff
//if I have time I should figure out why it errors out reading over 512 entries (should get 2048)
int entry_size = 64;
byte hash[32];
//store card id (currently a long, might not need to be)
char name[31];
byte priv;
byte command[64]; //add time zone

Initialization stuff, and questions about my sanity.  I defined 64 bytes of ‘command’ data, but never got around to using it (I could have made the define byte command[entry_size]).  The length is because that’s the same amount of space I use for a given user (and I can just index +1 to get that index user) .  You can see that the hash is 32 bits, and I have one priv byte which leaves an arbitrary 31 bytes to store the human readable name while keeping a nice round 64 byte per entry number.  The intent was to use this space for nonvolatile things (which could be stored in the 2560’s eeprom, but I decided to make it so the micro-controller board is fungible.  The only part of that intent that remains is the comment that references a time zone.  It would be easy to add the ability to peek and poke that byte (er… signed whatever-the-hell it would have to be to be a time zone) and have the date retrieval function use that offset.

// dumps the command area of the EEPROM
void SCmd_read_CMD()//debug, dumps command memory
{
read_EE_command();//updates working memory from EEPROM
for (int i = 0; i < 64; i++)
{
Serial.print(command[i], HEX);
}
Serial.println();
}

The command area of the eeprom stores nonvolatile things, but I never defined what.  This function reads it all out into working memory and prints it out for the benefit of the person or script that requested it (this function is triggered by a serial command).

void read_EE_command()//populate working memory from EEPROM
{
//for(int i = 0;i<64;i++)
//{
// command[i] = 0;
//}
for(int i = 0;i<64;i++)
{
command[i] = EEPROM1024.read(i);
}
}

This is the function that actually reads the command section of the eeprom and puts it into working memory.  There is a commented out section that blanks the working memory first, I don’t think that needs to still be there.

void write_EE_cmd()//populate EEPROM from working memory
{
for(int i = 0;i<64;i++)
{
EEPROM1024.write(i,command[i]);
}
}

This writes the volatile command memory to long term storage, doing the opposite of the above function.

void blank_EE_cmd()//debug

{
for(int i = 0;i<64;i++)
{
command[i] = 0;
EEPROM1024.write(i,0);
}
}

When testing code I end up filling the eeprom and need to blank parts of it to test other code, this function probably need not live in a running system.  I would recommend putting in a bunch of debug stuff, but marking it as such so it can be removed later.

void read_EE_name(int index)
{
for(int i = 0;i<31;i++)
{
name[i] = 0;
}
for (int i = 0; i < 31; i++)
{
name[i] = EEPROM1024.read(i+((index+1) * entry_size));//keeps command byte unwritten
}
return;
}

This code reads the name at a given index to working memory.  This is a common part of this code, I move stuff to and from working memory in order to check on it, change it, and then put it back.  This keeps reads and writes to the memory to a minimum and there’s less of a chance that the memory will be saved in an undesirable state.

void read_EE_hash(int index)
{
//for(int i = 0;i<64;i++)
//{
// EEPROM1024.write(i,command[i]);
//}
index +=1;//keeps command byte unwritten
int start_address = (index) * entry_size;
int end_address = start_address + entry_size;

for (int i = 0; i < 32; i++)
{
hash[i] = EEPROM1024.read(((start_address) + 32)+i);
}
return;
}

This code reads a hash at a given index to working memory.  This code is framed a bit differently than the function above, but it accomplishes the same task.  This looks older and more complicated, and should probably be condensed to look like the name retrieval function.

void dump_EE(int start_address, int end_address)//debug
{
//byte data[64];
for (int address = start_address; address < end_address; address++)
{
char data;
data = EEPROM1024.read(address);
Serial.print(address);
Serial.print(” :”);
Serial.print(data, HEX);
Serial.print(” :”);
Serial.println(data);
}
//Serial.println(“DONE”);
return;
}

This is another debug statement to dump eeprom data.  I mostly store my data as ascii so it prints the hex and ascii.  This is how I checked up on the memory during development, and if the intent is to run this board as a dumb I/O terminal it could be useful to leave in or as a method of backing up all the raw data.  If there is a problem this could be helped in debugging it since it does not try to be smart and just gives you all the addresses you ask for.  As always there’s some cruft left from previous formatting of the data, I’d remove the first one but leave the second one as it would be nice to be able to uncomment that later if something starts locking up.

void serial_user_print(int index)//debug? if in final make serial prints logging
{
read_EE_name(index);
read_EE_priv(index);
read_EE_hash(index);
Serial.print(index,DEC);
Serial.print(“;”);
for (int j = 0; j < (sizeof(name)/sizeof(name[0])); j++)
{
if(name[j] != 0)
Serial.print(name[j]);
}
Serial.print(“;”);
Serial.print(priv,HEX);
Serial.print(“;”);
for (int j = 0; j < (sizeof(hash)/sizeof(hash[0])); j++)
{
Serial.print((char)hash[j]);
}
Serial.println();
}

This prints out all the information about a user at a given address.  A more verbose version could be written to decode the priv bits as well.  This is a smarter version of the dump function which gives one index’s user data in a concise format.  It is only sent to the serial port, not to the printer (as pointed out by the comment).

// removes the user with <hash>
//format: RMV_USRH;<hash>
void SCmd_remove_user_hash()
{
char *arg;
arg = SCmd.next();
remove_user_hash(arg);
Serial.println(“user removed”);
}
void remove_user_hash(char hashd[32])////////////////////////////////////////////////////////////////////////////////////////////////untested
{
for(int i = 0;i<num_users;i++)
{
boolean succeed = 1;
read_EE_hash(i);
for (int j = 0; j < (sizeof(hash)/sizeof(hash[0])); j++)
{
if(hash[j] != hashd[j])
{
succeed == 0;
j+=((sizeof(hash)/sizeof(hash[0])));//break
}
}
if(succeed)
{
remove_user(i);
Serial.println(“user removed”);
i+=num_users;//break
}
}
}



Advertisement1


This is supposed to be a serial wrapper and the associated function to remove a user with a given hash.  It would search out a perfect match for a given hash then blow away the first user with that hash.  It looks like it actually prints “user removed” twice, once from each function which should be corrected (remove the first instance, leave the one in the internal function and make it log that to the printer as well as the serial port).  There is no output if the hash isn’t found (this should be corrected).  Notice how I break the loop? Classic me. Use at your own peril.

// removes the user with <name>
//format: RMV_USRN;<name>
void SCmd_remove_user_name()
{
char *arg;
arg = SCmd.next();
remove_user_name(arg);
Serial.println(“user removed”);
}
void remove_user_name(char named[31])///////////////////////////////////////////////////////////////////////////////////////////////untested
{
for(int i = 0;i<num_users;i++)
{
boolean succeed = 1;
read_EE_name(i);
for (int j = 0; j < (sizeof(name)/sizeof(name[0])); j++)
{
if((name[j] != 0 || named[j] != 0) && name[j] != named[j])
{
succeed == 0;
j+=((sizeof(name)/sizeof(name[0])));//break
}
}
if(succeed)
{
remove_user(i);
Serial.println(“user removed”);
i+=num_users;//break
}
}
}

This is supposed to be a serial wrapper and the associated function to remove a user with a given human readable name.  It would search out a perfect match for a given name, then blow away the first user with that hash.  It looks like it actually prints “user removed” twice, once from each function which should be corrected (remove the first instance, leave the one in the internal function and make it log that to the printer as well as the serial port).  There is no output if the hash isn’t found (this should be corrected).  Notice how I break the loop? Classic me. Use at your own peril.

// removes the user at <index>
//format: RMV_USR;<index>
void SCmd_remove_user()
{
char *arg;
arg = SCmd.next();
remove_user(atoi(arg));
Serial.println(“user removed”);
}
void remove_user(int i)
{
logging(logDate());
logging(” – “);
loggingln(“removing user”);
serial_user_print(i);
String name = “Free”;
byte priv= 0;
//gonna need to add a blank cardid ince that gets implemented
String hash = “00000000000000000000000000000000”;
write_EE(i, name, priv, hash);
logging(logDate());
logging(” – “);
loggingln(“user removed”);
}

This will remove a user at a given index, log it properly, blanking the hash, priv byte, and changing the name to ‘Free’.  This is the way I think it should be done, finding the user you want to delete by reading through the entries and deciding to eliminate it by index, the above functions were an attempt to automate that (which are a bit unfinished).  This sorta creates a sacred cow with that name, but I’m not worried about it.  I could also use “-1” but “Free” reads better when you dump the data.  Also, there’s no spellchecker in my IDE, so that comment typo was only found here in wordpress.

void populate_blank_users()//debug
{
for (int i = 0;i<num_users;i++)
remove_user(i);
}

Want to remove everyone? Probably do if you’re debugging a bunch.  This just loops through everyone and does that.

// adds a user at a given index
//format: ADD_USR;<index>;<name>;<priv byte>;<hash>
void SCmd_add_user()//rename to SCmd_add_user_index() once above function is done
{
char *arg;
arg = SCmd.next();
int index = atoi(arg);
arg = SCmd.next();
String name = arg;
arg = SCmd.next();
byte priv= atoi(arg);
arg = SCmd.next();
String hash = arg;
write_EE(index, name, priv, hash);
}

This adds a user to a given index, be warned you need the desired name, precalculated hash and priv byte to use this.  It’s mostly useful for restoring after a backup, although I could create a standalone tool to calculate those based on the card ID, PIN, and asking what privileges the user should have.  I already have those functions, they just need to be tweaked to reply to some user input.

//create a function like SCmd_add_user that adds a user at the first free index

I could have sworn I did this but I guess it’s left as an exercise for the reader.  It’s like the ‘search and destroy’ commands, but it’s a ‘search and implant’ which uses the functionality already in the user add functionality if you use they keypad to add the user.

// reads the user at <index>
//format: READ_USR;<index>
void SCmd_read_user()
{
char *arg;
arg = SCmd.next();
serial_user_print(atoi(arg));
//Serial.println(“DONE”);
}

This reads a user at a given index, this is a serial wrapper for a function already made modular for other reasons.

// dumps all users present
//format: DUMP_USR
void SCmd_dump_users()
{
for (int i=0;i<num_users;i++)
{
if(user_present(i))
{
Serial.println(i);
serial_user_print(i);
}
}
//Serial.println(“DONE”);
}

This dumps all present users (use the raw read if you want all the data).  This uses the user_present function, I thought that used the name being ‘Free’ but I just checked and it uses priv byte not equal to zero.  Whatever gets the job done, this actually returns whether the user can open the door and that effectively limits the other functions because I use the door open timer to allow for the triggering of the other functions.

void dump_all_EE() //debug stuff
{
for (int address = 0; address < 131072; address++)
{
char data;
data = EEPROM1024.read(address);
Serial.print(address);
Serial.print(” :”);
Serial.println(data, HEX);
Serial.print(address);
Serial.print(” :”);
Serial.println((char)data);
//Serial.print(” :”);
//Serial.println(data);
}
//Serial.println(“DONE”);
}

Dump all the eeprom!  Hardcoded endstop, don’t remember why but there it is.

void write_EE(int index, String name, byte priv, String hash)
{
index +=1;
char data[64] = {
};
for(int i = 0;i<31;i++)
{
if(name[i] == 0)
{
i+=31;//break
}
else
{
data[i] = name[i];
}
}
data[31] = priv;
for(int i = 0;i<32;i++)
{
data[i+32] = hash[i];
}

int start_address = (index) * entry_size;
int end_address = start_address + entry_size;

//Serial.println(“Writing data”);
for (int address = start_address; address < end_address; address++)
{
EEPROM1024.write(address, data[address % entry_size]);
}
//Serial.println();
}

Here is how I write the eeprom for a user index.  This is used when I dump working memory back to a user slot.  I have the serial wrapper for it, or it is called after adding a user.

This may seem like a lot, and you may not need much of it but I think it’s nice to have.  This is part of the OpenAccess project.

 

 


Top