RFID Tag Compare

Hello,

I have this dilemma with comparing two RFID Tag numbers using the ID-12 Reader and an Arduino Uno, one from a card, and the other in an array. I'd like to print to Serial: "Card is a Match", then do something. Im manipulating the example from this site:Arduino Playground - ID12

The tag Im trying to compare to:

byte target_tag[TAG_LEN] = {0x4F, 0x00, 0x88, 0xB3, 0x4F};

I cant make up my mind which of these sets of code is the right one to use, as Ive seen them both work in other people's programs, but they wont work for me:

if (bytesread == 12) {                          // if 12 digit read is complete
        Serial.print("5-byte master: ");
        for (i=0; i<5; i++) {
          if (master[i] < 16) Serial.print("0");
          byte master1 = master[i];
          Serial.print(master[i], HEX);
          Serial.print(" "); 
          //Serial.println();
        }
	    if(memcmp(master, target_tag[i], TAG_LEN) == 0 )
	    {
               Serial.print("This Card is a Match!");
	    }
    }
        Serial.println();

        Serial.print("Checksum: ");
        Serial.print(master[5], HEX);
        Serial.println(master[5] == checksum ? " -- passed." : " -- error.");
        Serial.println();

Or this one:

if (bytesread == 12) {                          // if 12 digit read is complete
        Serial.print("5-byte master: ");
        for (i=0; i<5; i++) {
          if (master[i] < 16) Serial.print("0");
          byte master1 = master[i];
          Serial.print(master[i], HEX);
          Serial.print(" "); 
          //Serial.println();
        }
	   for(int i = 0; i < ARR_LEN; i++)
        {
          if (CheckTwoBytes(target_tag[i], master))
          {
            Serial.print("This Card is a Match!");
          }
      }
    }
        Serial.println();

        Serial.print("Checksum: ");
        Serial.print(master[5], HEX);
        Serial.println(master[5] == checksum ? " -- passed." : " -- error.");
        Serial.println();
}

boolean CheckTwoBytes ( byte a[], byte b[] )
{
if ( a[0] != NULL ) // Make sure there is something in the array first
match = true; // Assume they match at first

for ( int k = 0; k < 5; k++ ) // Loop 5 times
{
/*
Serial.print("[");
Serial.print(k);
Serial.print("] ReadCard [");
Serial.print(a[k], HEX);
Serial.print("] StoredCard [");
Serial.print(b[k], HEX);
Serial.print("] \n");
*/
if ( a[k] != b[k] ) // IF a != b then set match = false, one fails, all fail
match = false;
}
if ( match ) // Check to see if if match is still true
{
//Serial.print("Strings Match! \n"); 
return true; // Return true
}
else {
//Serial.print("Strings do not match \n"); 
return false; // Return false
}
}

Im trying to write the code myself, and learn how it works as Im writing it. I dont feel comfortable just copying and pasting other people's code just to get it to work.

I've searched around the web, and found a variety of help pages, examples and tutorials, but nothing as detailed in explanation as Im looking for.

Any help is greatly appreciated.

where you write

if(memcmp(master, target_tag[i], TAG_LEN) == 0 )

is PROBABLY wrong

try

if(memcmp(master, target_tag, TAG_LEN) == 0 )

frank26080115:

if(memcmp(master, target_tag, TAG_LEN) == 0 )

Hmm, for some reason it was throwing an error before: cannot compare byte* & byte...it works now, but only for one of my RFID cards. The other one wont validate.

This is my array for all my tags that Ive got saved in the Arduino:

byte target_tag[ARR_LEN][TAG_LEN]={{0x4F, 0x00, 0x88, 0xB3, 0x4F},{*My Other Tag*}}

Maybe this tutorial can help you futher,
http://www.tigoe.net/pcomp/code/PHP/347/
I did build my code around this and works great.

teding:
Maybe this tutorial can help you futher,
http://www.tigoe.net/pcomp/code/PHP/347/
I did build my code around this and works great.

I appreciate the link, but Tom approaches this a little differently since he is reading and writing to EEPROM.

However, I figured it out this morning by adding one extra loop to check my other Tag ID's. Now it works.

Here is the code for the loop:

for (int n=0; n<ARR_LEN; n++){
if(memcmp(master, target_tag[n], TAG_LEN) == 0 )  //Compares two bytes of TAG_LEN, if they are a match, the argument will be 0, thus 0 == 0
	  {
            Serial.println("This Card is a Match!");             
	  }
       }

Thanks.

Here is the code for the loop:

You could, of course, print in the body of the if statement the value of n, so you know WHICH tag the scanned one matched, if that was important.

I have another question, similarly relating to this.

I want the program to print out when the card validates, and also when the card doesnt validate. Ive tried this:

if(memcmp(master, target_tag[n], TAG_LEN) == 0 )  //Compares two bytes of TAG_LEN, if they are a match, the argument will be 0, thus 0 == 0
	  {
            Serial.println("This Card is a Match!");
	  }
        else if(memcmp(master, target_tag[n], TAG_LEN) != 0)
            {     
              Serial.println("This Card is NOT a Match!");
            }

If it validates, it outputs once. If it doesnt validate, it outputs twice- for each tag it reads in.

What I want it to do is compare vs both tags, and then if it validates, great, output once - like its already doing. If not, output ONCE as well. Any suggestions of how to get that to work?

it's hard to diagnose the problem without the entire code

if(memcmp(master, target_tag[n], TAG_LEN) == 0 )  //Compares two bytes of TAG_LEN, if they are a match, the argument will be 0, thus 0 == 0
	  {
            Serial.println("This Card is a Match!");
	  }
        else if(memcmp(master, target_tag[n], TAG_LEN) != 0)

If the value returned be memcmp() is not 0, how can it be anything but not zero? The second if test is redundant.

Most likely what is happening is that you are learning that one of the tags is not tag 0 and is not tag 1, when you read tag 2. If you were to include n in the output message, I think you'd see that the messages are NOT identical. But, without seeing the whole code, who knows for sure.

PaulS:
If the value returned be memcmp() is not 0, how can it be anything but not zero? The second if test is redundant.

Most likely what is happening is that you are learning that one of the tags is not tag 0 and is not tag 1, when you read tag 2. If you were to include n in the output message, I think you'd see that the messages are NOT identical. But, without seeing the whole code, who knows for sure.

I was trying to do an IF/ELSE statement, and I wasnt getting anywhere, so I figured to try the opposite of my IF statement to see if that worked. It did exactly the same as the ELSE statement. So yes, its redundant. However, since you guys are most insistent about seeing the whole code to analyze the problem, here you go:

#include <NewSoftSerial.h>
NewSoftSerial mySerial(2, 3); //rx, tx

#define TAG_LEN 5
#define ARR_LEN 2

byte target_tag[ARR_LEN][TAG_LEN] = 					//This array of TAG ID's will later be in a database on the BB
{{0x4F, 0x00, 0x88, 0xB3, 0x4F}, //Card 1 Tag ID
{TAG_ID_2}}; //Card 2 Tag ID

boolean match = false; // initialize card match to false

void setup() {
Serial.begin(9600);// connect to the serial port
mySerial.begin(9600);
Serial.println("Bring an RFID tag near the reader...");
}

void loop () {
  byte i = 0;
  byte val = 0;
  byte master[6];
  byte checksum = 0;
  byte bytesread = 0;
  byte tempbyte = 0;

  if(mySerial.available() > 0) {
    if((val = mySerial.read()) == 2) {                  // check for header 
      bytesread = 0; 
      while (bytesread < 12) {                        // read 10 digit master + 2 digit checksum
        if( mySerial.available() > 0) { 
          val = mySerial.read();
          if((val == 0x0D)||(val == 0x0A)||(val == 0x03)||(val == 0x02)) { // if header or stop bytes before the 10 digit reading 
            break;                                    // stop reading
          }

          // Do Ascii/Hex conversion:
          if ((val >= '0') && (val <= '9')) {
            val = val - '0';
          } else if ((val >= 'A') && (val <= 'F')) {
            val = 10 + val - 'A';
          }

          // Every two hex-digits, add byte to master:
          if (bytesread & 1 == 1) {
            // make some space for this hex-digit by
            // shifting the previous hex-digit with 4 bits to the left:
            master[bytesread >> 1] = (val | (tempbyte << 4));

            if (bytesread >> 1 != 5) {                // If we're at the checksum byte,
              checksum ^= master[bytesread >> 1];       // Calculate the checksum... (XOR)
            };
          } else {
            tempbyte = val;                           // Store the first hex digit first...
          };

          bytesread++;                                // ready to read next digit
        } 
      } 
      //do something else perhaps wait for other data.
      
      if (bytesread == 12) {                          // if 12 digit read is complete
        Serial.println();
        Serial.print("5-byte master: ");
       
        for (i=0; i<5; i++) {
          if (master[i] < 16) 
            Serial.print("0");
          byte master1 = master[i];
          Serial.print(master[i], HEX);              //Prints the Tag of the Card read
          Serial.print(" "); 
        }
        for (int n=0; n<ARR_LEN; n++){               //Checks each ID Tag in the Array
        
	if(memcmp(master, target_tag[n], TAG_LEN) == 0 )  //Compares two bytes of TAG_LEN, if they are a match, the argument will be 0, thus 0 == 0
	  {
            Serial.println();
            Serial.println("This Card is a Match!");
            Serial.println();
	  }
        else 
            {     
              Serial.println("This Card is NOT a Match!");
            }
       } 
    }
      bytesread = 0;
      Serial.flush();
    }
  }
}

};

Hope this helps in deciphering the two-time repetition of the "This Card is NOT a Match!" statement.

Hope this helps in deciphering the two-time repetition of the "This Card is NOT a Match!" statement.

No, not really.

Putting each { on a new line, and using Tools + Auto Format would help.

So would including the value of n in the output:

              Serial.print("Card ");
              Serial.print(n);
              Serial.println(" is NOT a Match!");

This way, if you see:
Card 0 is NOT a Match!
Card 1 is NOT a Match!
then we know one thing.

If you see
Card 0 is NOT a Match!
Card 0 is NOT a Match!
or
Card 1 is NOT a Match!
Card 1 is NOT a Match!
then we know something else.

UNTEngineer:
If it validates, it outputs once. If it doesnt validate, it outputs twice- for each tag it reads in.

From code inspection, I predict slightly different behaviour.

What it should do is compare the received RFID against each of your two hardcoded values in turn. For each comparison it prints either "This Card is a Match!" or "This Card is NOT a Match!".

If you want to clean this up I suggest you extract the comparison into a function that returns something to indicate whether the value is a match. If you want to know which one it matched, you could return the 0-based index into the target_tag array (and a negative value to indicate no match). Or if you don't care which one it matched, just return a boolean.

Then, based on the return value print out the appropriate trace message.

By the way, that's far from the worst code I've seen but in order to convince myself the logic was sound I reformatted it to put each { and } on a separate line with matching pairs indented by the same amount; I suggest you adopt that code style. I also suggest that you get into the habit of putting { and } after any if/else statement. Sure, it might work without it now when you only have one statement, but you've no idea how many times I've seen people tack an extra statement on the end - or inadvertently use a macro that expanded to more than one statement - and introduce a subtle bug. Use { and } to make the control structure as clear and robust as possible.

PeterH:
By the way, that's far from the worst code I've seen but in order to convince myself the logic was sound I reformatted it to put each { and } on a separate line with matching pairs indented by the same amount; I suggest you adopt that code style. I also suggest that you get into the habit of putting { and } after any if/else statement. Sure, it might work without it now when you only have one statement, but you've no idea how many times I've seen people tack an extra statement on the end - or inadvertently use a macro that expanded to more than one statement - and introduce a subtle bug. Use { and } to make the control structure as clear and robust as possible.

Well this is practically the example given on the Arduino website for use with the ID-12. I just manipulated it for my purpose.

PaulS:
Putting each { on a new line, and using Tools + Auto Format would help.

So would including the value of n in the output:

              Serial.print("Card ");

Serial.print(n);
              Serial.println(" is NOT a Match!");

I am using Auto-format. I'll implement the Card (n) into the code and see what happens.

UNTEngineer:
Well this is practically the example given on the Arduino website for use with the ID-12. I just manipulated it for my purpose.

Well, I'm not saying that the people who coded that example are wrong, but they are not using the coding style which, in my opinion, is the one which makes the control structures in your code clearest. I recommend that you follow the style I outlined, even though you will routinely encounter code that follows other styles.