PRFID trying to make a logging system with 100+ items

Currently I am trying to accomplish a project for a woodshop-like class. The project is this, each of our tools will be tagged with a small RFID tag, and every person will have an RFID tag embedded into their name tags. Using these tags, users can check in and out tools. This helps to keep track of who has a tool checked out, and if a person lost a tool. I have an alpha stage version of the program, and it works! Problem is, I'm already using a third of my storage, and this is a test with only 10 tools, while I need to tag 100+! I am a beginner at programing and would apreciate any help. Right now, I'm trying to make a tool() function so when a tag is read, the code is put into the function, and it's logged. My current code follows. I added a few comments, and hope the info in the Serial.print() is enough to explain the rest. Current setup: Arduino Uno connected to RFID reader (Parrallax) connected to Serial.port for a simple response for scans and logging.

(I'm limited by charecters, see my following post for code)

The very messy code PART 1

String name, tool, nameverify; //the basic logging Strings
String Steve, Bob, Tom, Joe;
String scan, scanverif;
String buffer;
int login;
int fail;
int timeout;
int cache;
int logcache;
int tools;
int refresh;
int startup = 1;
char codecompare[10] = "000000000";
String hammer1,wrench1,wrench2,mesuretape1,mesuretape2,mesuretape3,hammer2,screwphillips,vicegrip1,boardstrech; //tools

String date, time;
//String code1, code2, code3, code4, code5, code6, code7, code8, code9, code10; //each code digit
String code1;
int testing;

int val = 0;
char code[11];
int bytesread = 0;

long session;
long sessioncheck; //some varriables such as these are not used

int toolfresh;
  
void setup() {
  session = 0;
  Serial.begin(2400);
  time = String("set time"); 
  name = String("0");
  tool = String("0");
  nameverify = String("0");
  Serial.println(" ");
  Serial.println("Please scan name card");
  Serial.println(" ");
  fail = 1;
  login = 0;
  logcache = 0;
  cache = 0;
  //refresh = 1;
  pinMode(2,OUTPUT);
  digitalWrite(2,LOW);
  
  scan = "000000000";
  
  String buffer = "000000000";
  
  login = 0;
  toolfresh = 0;

}

void loop() {
    if(Serial.available() > 0) {          // if data available from reader 
    if((val = Serial.read()) == 10) {   // check for header 
      bytesread = 0; 
      while(bytesread<10) {              // read 10 digit code 
        if(Serial.available() > 0) { 
          val = Serial.read(); 
          if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading 
            break;                       // stop reading 
          } 
          code[bytesread] = val;         // add the digit           
          bytesread++;                   // ready to read next digit  
        } 
      } 
      if(bytesread == 10) {
        if (code[9] != 000000000) {
          buffer = String(code);    //old way thought to work
          code1 = String(code[0]);
          //code1 = String(code[0]);
          //code2 = String(code[1]);
          //code3 = String(code[2]);
          //code4 = String(code[3]);
          //code5 = String(code[4]);
          //code6 = String(code[5]);
          //code7 = String(code[6]);
          //code8 = String(code[7]);
          //code9 = String(code[8]);
          //code10 = String(code[9]);
          //buffer = code1+code2+code3+code4+code5+code6+code7+code8+code9+code10;
        }
        //Serial.print("TAG code is: ");   // possibly a good TAG  //REMOVE COMMENT TO ENABLE RFID READ MODE
        //Serial.println(buffer);         // print the TAG code 
        if (scanverif != buffer) {
        scan = buffer;
        scanverif = scan;
        buffer = "000000000";
        } else {
          buffer = "000000000";
        }
      }
      bytesread = 0; 
      digitalWrite(2, HIGH);                  // deactivate the RFID reader for a moment so it will not flood
           delay(1500);                       // wait for a bit 
           digitalWrite(2, LOW);           // Activate the RFID reader
    } 
  } //END RFID READ ING CODE
  //if (buffer == "000000000") {           //debug sequence testing buffer and scan
    //Serial.print("hi: ");
    //Serial.print(buffer);
    //Serial.print(", ");
    //Serial.println(scan);
    //delay(1000);
  //}
  //if (buffer != "000000000") {             //testing sequence that says hello to a buffer code
    //Serial.print("hello");
    //Serial.println(buffer);
    //Serial.println(scan);
    //scan = buffer;
    //Serial.println(scan);
  //}
  name = "0";
    if (1 == 1) {      //A certain range of codes is for Names
      if (scan == "00009F9898") {     //matches code with name
        name = "Steve";
      }
      if (scan == "03003C3EFF") {
        name = "Bob";
      }
      if (scan == "03003C4E3B") {
        name = "Tom";
      }
      //if (scan == "00009F98B1") {
        //name = "Joe";
      //}
      if (scan == "03003C2FE7") {                             //SEE ADMIN SECTION
        name = "Joe";
      }
      if ((name != "0") && (login > 0) && (name != nameverify)) {
        Serial.println(" ");
        Serial.println("~~~~~~~The person above forgot to log out!~~~~~~~");
        Serial.println(" ");
        Serial.println(" ");
        login = 0;
        scan = "000000000";
      }
      if ((name != "0") && (login > 0) && (name == nameverify)) {
        name = "0";
        nameverify = "0";
        login = 0;
        Serial.println("~~~~~~~You have sucessfully been logged out!~~~~~~~");
        Serial.println(" ");
        Serial.println(" ");
        Serial.println(" ");
        Serial.println(" ");
        refresh = 1;
        scan = "000000000";
        toolfresh = 1;
        tools = 0;
      }
      if ((name != "0") && (login == 0) && (refresh == 0)) {
        Serial.print("~~~~~~~Welcome, "); //welcomes user, asks for tool scan
        Serial.print(name);
        Serial.println("~~~~~~~");
        Serial.println("Please scan your first tool");
        login ++;
        nameverify = name;
        scan = "000000000";
        session++;
      }
    }
  if (login == 0 && fail == 0) {
    delay(500);
    Serial.print("Scan not recognized, please try again");
    fail = 1;
    scan = "000000000";
  }
  if (login == 1) {
      timeout ++;
      delay(100);
  }
  if (timeout == 600) {
        Serial.println("Session will be logged out soon");
      }
  if (timeout == 1200) {
    Serial.println("~~~~~~~You have been automatically logged out, scan card to log in again~~~~~~~");
    login = 0;
    timeout = 0;
    tools = 0;
    name = "0";
    nameverify = "0";
  }

END OF PART 1

PART 2

  if (login == 1) {
    if (code1 == "8") {
      //String date =
      //String time =
            if (scan == "8400337767" && hammer1 == nameverify && refresh == 0) {
        hammer1 = "1";
        Serial.println("Tool Checked In!");
        refresh = 1;
      }
      if (scan == "8400336FC1" && wrench1 == nameverify && refresh == 0) {
        wrench1 = "1";
        Serial.println("Tool Checked In!");
        refresh = 1;
      }
      if (scan == "8400337B88" && wrench2 == nameverify && refresh == 0) {
        wrench2 = "1";
        Serial.println("Tool Checked In!");
        refresh = 1;
      }
      if (scan == "8400337F75" && mesuretape1 == nameverify && refresh == 0) {
        mesuretape1 = "1";
        Serial.println("Tool Checked In!");
        refresh = 1;
      }
      if (scan == "8400336BD4" && mesuretape3 == nameverify && refresh == 0) {
        mesuretape3 = "1";
        Serial.println("Tool Checked In!");
        refresh = 1;
      }
      if (scan == "8400336A6F" && hammer2 == nameverify && refresh == 0) {
        hammer2 = "1";
        Serial.println("Tool Checked In!");
        refresh = 1;
      }
      if (scan == "8400336ECE" && screwphillips == nameverify && refresh == 0) {
        screwphillips = "1";
        Serial.println("Tool Checked In!");
        refresh = 1;
      }
      if (scan == "840033833D" && vicegrip1 == nameverify && refresh == 0) {
        vicegrip1 = "1";
        Serial.println("Tool Checked In!");
        refresh = 1;
      }
      if (scan == "84003373F1" && boardstrech == nameverify && refresh == 0) {
        boardstrech = "1";
        Serial.println("Tool Checked In!");
        refresh = 1;
      } 
      
      if (scan == "8400337767" && hammer1 == "") {
        tool = "Hammer 1";
        hammer1 = nameverify;
      } 
      
      if (scan == "8400336FC1" && wrench1 == "") {
        tool = "Wrench 1";
        wrench1 = nameverify;
      }
      
      if (scan == "8400337B88" && wrench2 == "") { //DEFECTIVE
        tool = "Wrench 2";
      }
      
      if (scan == "8400337F75" && mesuretape1 == "") { 
        tool = "Mesuring Tape 1";
        mesuretape1 = nameverify;
      }
      
      if (scan == "840033780F" && mesuretape2 == "") {  //DEFECTIVE
        tool = "Mesuring Tape 2";      
      }
      if (scan == "8400337767" && mesuretape2 == nameverify && refresh == 0) {
        mesuretape2 = "1";
        Serial.println("Tool Checked In!");
        refresh = 1;
      }
      if (scan == "8400336BD4" && mesuretape3 == "") {  
        tool = "Mesuring Tape 3";
        mesuretape3 = nameverify;
      }
      
      if (scan == "8400336A6F" && hammer2 == "") {
        tool = "Hammer 2";
        hammer2 = nameverify;     
      }
      
      if (scan == "8400336ECE" && screwphillips == "") {
        tool = "Screw Driver Phillips";
        screwphillips = nameverify;      
      }
      
      if (scan == "840033833D" && vicegrip1 == "") {
        tool = "Vice Grips 1";
        vicegrip1 = nameverify;       
      }
      
      if (scan == "84003373F1" && boardstrech == "") {
        tool = "Board Strecher";       //it is real!!!
        boardstrech = nameverify;
      }
      
      //String hammer1,wrench1,wrench2,mesuretape1,mesuretape2,mesuretape3,hammer2,screwphillips,vicegrip1,boardstrech
      cache = 1;
      scan = 0;
    }
    if (cache == 0) {
      //Serial.println("No Tool Checked");
    }
    if (cache == 1 && tool != "0") {
      Serial.print("You just scanned a ");
      Serial.println(tool);
      delay(1000);
      cache = 0;
      Serial.println("Tool has been logged");
      tools++;
      Serial.print("You have checked out ");
      Serial.print(tools);
      Serial.println(" tool(s) so far. Scan another tool, or scan name card to end session");
      Serial.println(" ");
      tool = "0";
    }
  }
  if (toolfresh == 1) {
    if (boardstrech == "1") {
        boardstrech = "";
      }
    if (vicegrip1 == "1") {
        vicegrip1 = "";
      }
    if (screwphillips == "1") {
        screwphillips = "";
      }
    if (hammer2 == "1") {
        hammer2 = "";
      }
    if (mesuretape3 == "1") {
        mesuretape3 = "";
      }
    if (mesuretape2 == "1") {
        mesuretape2 = "";
      }
    if (mesuretape1 == "1") {
        mesuretape1 = "";
      }
    if (wrench2 == "1") {
        wrench2 = "";
      }
    if (wrench1 == "1") {
        wrench1 = "";
      }
    if (hammer1 == "1") {
        hammer1 = "";
      }
      toolfresh = 0;
  }
  if (scan == "00009F98B1") {
    Serial.println("~~~~~~~Initiating System Check~~~~~~~");
    Serial.println("Following tools are checked out by people (tool:person)");
    //String hammer1,wrench1,wrench2,mesuretape1,mesuretape2,mesuretape3,hammer2,screwphillips,vicegrip1,boardstrech
    if (hammer1 != "") {
        Serial.print("Hammer 1: ");
        Serial.println(hammer1);
    }
    if (wrench1 != "") {
        Serial.print("Wrench 1: ");
        Serial.println(wrench1);
    }
    if (wrench2 != "") {
        Serial.print("Wrench 2: ");
        Serial.println(wrench2);
    }
    if (mesuretape1 != "") {
        Serial.print("Mesureing Tape 1: ");
        Serial.println(mesuretape1);
    }
    if (mesuretape2 != "") {
        Serial.print("Mesureing Tape 2: ");
        Serial.println(mesuretape2);
    }
    if (mesuretape3 != "") {
        Serial.print("Mesureing Tape 3: ");
        Serial.println(mesuretape3);
    }
    if (hammer2 != "") {
        Serial.print("Hammer 2: ");
        Serial.println(hammer2);
    }
    if (screwphillips != "") {
        Serial.print("Screw Driver Phillips: ");
        Serial.println(screwphillips);
    }
    if (boardstrech != "") {
        Serial.print("Board Strecher: ");
        Serial.println(boardstrech);
    }
    }
  refresh = 0;
  scan = "000000000";
}

END PART 2, END OF CODE

Use codes not string names for tools, you are very limited on RAM, strings eat lots of memory. The Arduino isn't going to be able to store records, a desktop PC will be needed for that or a SDcard. Use processing routines to send to a computer and to query the computer. One could relate each item status to a bit location in a byte array. 13 bytes of memory could hold the state of 104 items if each bit was 1 for checked in and 0 for checked out. The gagle of if statements could be reduced to a single function taking parameters and returning a value.

Consider this code snip of yours...

      if (scan == "8400336FC1" && wrench1 == "") {
        tool = "Wrench 1";
        wrench1 = nameverify;
      }

"Wrench 1" needs to be a pnemonic, a number that is referred to in the code view as a name but in reality a unique number. The RFID should be stored as a number as well not a string. I see that the first 3 bytes of your tags are all the same, so define them as a site code, and the last 2 bytes as tag number. When testing a card read, first test for a valid site code and discard transaction if the sitecode fails, this also has the benefit of you assigning different site codes to different departments so you can keep another department's tools from getting checked in elsewhere.

I see what you mean, but later in the code you see that I use Serial.print(wrench1); This is a UI feature to tell the user that they checked out Wrench 1. Also, do you know of a way to make all the repeated code into functions?

Slight mispelling on my part....Mnemonic....lol. How are you with databases?

no experience with them, but i have a basic knowledge

What I’d do for that is define a struct to hold the details for a person i.e. their RFID and their name. Put an array of these in progmem that defines the people able to use your system. When your scanner picks up an RFID in the right range to be a person, search through the array looking for a matching RFID and put the corresponding struct into a variable that records who is currently logged in. Also note the time that the person logged in.

Define a struct that holds the details for a tool i.e. the RFID, name, and anything else that matters to you. Put an array of these in progmem and treat them the same as above i.e. when you scan an RFID in the right range to be a tool, search the array of tools for a matching RFID and record the matching entry in a variable. If there is a person logged in (i.e. the last login was not too long ago and the person has not logged out again) then process this as an attempt to check a tool in or out.

To do that you need to know whether a given tool is checked out. I’d define a struct that records the status of each tool i.e. the id of the tool and the person who has it checked out (if any) and the time they checked it out. You could store these wherever you want, but for a standalone system I’d put it in EEPROM.

So, the logic would be check whether the tool is already checked out to the person: if it is, then treat this as a check-in (update the tool status record to show it isn’t checked out any more); if it isn’t then treat this as a checkout and update the tool status to show this person checked it out at this time.

You’d need to enter the person and tool definitions into your sketch and reload it again each time these change. Presumably you’d also need a way to list the current status of all tools or selected tools, and have a command to change these directly for admin purposes.

As an enhancement, rather than storing your people and tool definitions in progmem you can move them to flash and have commands to add / change / remove entries. For a productin system you’d need this in order to be usable. But for a proof of concept you can avoid all that and just hard-code that configuration data within the sketch.

Some thoughts:

You handle your RFID tags as string as in fact they are a (hexadecimal) number. As they all seem to start with 840033 you could ignore these digits as they add no value. probably the last 4 digits (2 bytes) are enough to be unique.

you could create a struct to represent one tool

struct tool
{
  char[12] toolname;   // max 11 chars + \0 e.g.Hammer10 or Wrench07
  uint16_t RFID;         // 16bits RFID;  only uses the last 2 bytes [84.00.33].6F.C1
}

Needs 16bytes to represent one tool, as these are all fixed data they can be in flash (stated before).

Only the state which changes should be in RAM. For this we can define an array of structs which holds only the lent items. Assuming students have also an RFID

struct checkedout { uint16_t Tool; uint16_t Person; //rfid of student } 4 bytes per item checked out, so 200 checked out items can be in 800 bytes of RAM. If an item is checked out it is added to this list, and when checked in again it can be removed from the list.

Thank You for all the help! I will create a new version of the code and post it when I'm done.

Ok, I'm trying to work with structs, but I'm a bit confused.

struct {
  int anInt;
  byte *anArray;
} withArrays;

This is an example I found. How do I properly accsess this, or a certain value from it, and what is the proper form to store data in a struct?

How do I properly accsess this, or a certain value from it, and what is the proper form to store data in a struct?

First, you need to create an instance of the struct:

withArrays anInst;

Then, you can use:

anInst.anInt = 42;
anInst.anArray = strdup("The answer to life, the universe, and everything");

What is "anInst"? Also, to accses data, can I just simply do

someVar = anInst.anInt

What is "anInst"?

An instance of the structure.

Also, to accses data, can I just simply do

Yes.

Thanks! Do you know of any good references for things not on the Arduino reference?

Reducing the RFID tags to 16-bit message digests will let you conserve a nice amount of space and at runtime the comparisons will be numeric. Just an idea.

bigluc: Thanks! Do you know of any good references for things not on the Arduino reference?

Check your post about struct rage...

Do you know of any good references for things not on the Arduino reference?

Google.

I would be careful about ignoring those first 3 bytes. That is fine with the batch of RFID tags you have but what happens in 6 months when you add new tools and you have to get a new batch of RFID tags that come from a different lot? It is a very real possibility that you get the last 2 bytes duplicated. I grant you it is slim but it could happen. RFID codes are 5 bytes for a reason.

Also, don't dismiss the SD card option mentioned above. If you want to operate independant of a PC then this is the best option for storing data easily without having to worry about that PC interface.

Ok so I'm working with structs, and I'm wondering if it's possible to create a funtion with them

typedef struct {
   int tag;
   char* checked;
} tool;

tool Wrench01 = {01234567, "Bob"};



void setup() {
  Serial.begin(9600);
  //tool Wrench01 = {01234567, "Bob"};
  //Wrench01.tag = 01234567;
  //Wrench01.checked = "Bob";
}

void loop() {
  Serial.print("Tag Number: ");
  Serial.println(Wrench01.tag);
  Serial.print("Checked out too: ");
  Serial.println(Wrench01.checked);
  delay(1000);
  
}

I want to be able to tell the board to find the .tag that matches the code scanned, and want to be able to create a universal function that will print .checked as well as the name of the person (haven't coded that yet).