Wednesday, May 12, 2010

RFID Project (The Code)

I found some already written code doing exactly what I wanted it to.  It did have a bug in it that I had to get some help figuring out.  ( If your RFID started with a 00 it had some issues )  Here is the code.





#include // Needed to write to EEPROM storage

#define powerPin    10
#define failPin     11
#define passPin     12
#define doorPin     13


boolean programMode = false;
boolean match = false;

byte storedCard[6];  // Stores an ID read from EEPROM
byte readCard[6];    // Sotres an ID read from the RFID reader
byte checksum = 0;   // Stores the checksum to verify the ID

void setup()
{
  // for (int i = 0; i < 512; i++) // Uncoment to wipe the EEPROM
   // EEPROM.write(i, 0);
  pinMode(powerPin, OUTPUT);      // Connected to Blue on tri-color LED to indicate reader is ready
  pinMode(passPin, OUTPUT);       // Connected to Green on tri-color LED to indicate user is valid
  pinMode(failPin, OUTPUT);       // Connected to Green on tri-color LED to indicate user is NOT valid or read failed
  pinMode(doorPin, OUTPUT);       // Connected to relay to activate the door lock
  Serial.begin(9600);             // Connect to the serial port
 }

void loop ()
{
 
  
  byte val = 0;       // Temp variable to hold the current byte

  normalModeOn();     // Normal mode, blue Power LED is on, all others are off
 
  if ( programMode)   // Program mode to add a new ID card
  {
    programModeOn();  // Program Mode cycles through RGB waiting to read a new card
  
    if(Serial.available() > 0)  // Waits for something to come on the serial line
    {
      if((val = Serial.read()) == 2)  // First Byte should be 2, STX byte
      {
        getID();                      // Get the ID, sets readCard = to the read ID
        if ( !isMaster(readCard) )    // Check to see if it is the master programing card
        {
          writeID(readCard);          // If not, write the card to the EEPROM sotrage
          programMode = false;        // Turn off programing mode
          checksum = 0;               // Make sure the checksum is empty
        }
      }
    }
  }
  // Normal Operation...
  else
  {
    if(Serial.available() > 0)          // If the serial port is available and sending data...
    {
      if((val = Serial.read()) == 2)    // First Byte should be 2, STX byte
      {                
        getID();                        // Get the ID, sets readCard = to the read ID
        byte bytesread = 0;
      
        for ( int i = 0; i < 5; i++ )         // Loop 5 times
        {
          if  ( readCard[i] < 16 )              // Print out 0 if < 16 to prepend output
            Serial.print("0");
          
          Serial.print(readCard[i], HEX);     // Print out the hex value read in
          Serial.print(" ");
        }
        Serial.println();
        Serial.print("Checksum: ");
        Serial.print(readCard[5], HEX);       // Checksum read from the card
      
        if ( readCard[5] == checksum )        // See if the 5th BYTE (the checksum) read in from the reader
        {                                     // matches the checksum caculated
          checksum = 0;          // If so, we can empty the variable storing the calculated checksum
          Serial.println();
          Serial.println("Checksum correct");
          Serial.println();
          if ( isMaster( readCard ) )         // Check to see if the card is the master programing card
          {
            programMode = true;               // If so, enable programing mode
          }
          else
          {
            if ( findID(readCard) )           // If not, see if the card is in the EEPROM
            {
              openDoor(5);                // If it is, open the door lock
              Serial.println();
              Serial.print("It's stored");
              Serial.println();
            }
            else
            {
              failed();                       // If not, show that the ID was not valid
              Serial.println();
              Serial.print("It's NOT stored");
              Serial.println();
            }
          }
        }
        else                                  // If the checksum failed
        {                                     // Print out the checksum
      
          Serial.println("Checksum error");
          Serial.println();
          Serial.print("[");
          Serial.print(readCard[5], HEX);
          Serial.print("] != [");
          Serial.print(checksum, HEX);
          Serial.print("] ");
        
        }
      }
    }
  }
}

// If the serial port is ready and we received the STX BYTE (2) then this function is called
// to get the 4 BYTE ID + 1 BYTE checksum. The ID+checksum is stored in readCard[6]
// Bytes 0-4 are the 5 ID bytes, byte 5 is the checksum
void getID()
{
  byte bytesread = 0;
  byte i = 0;
  byte val = 0;
  byte tempbyte = 0;
 
  // 5 HEX Byte code is actually 10 ASCII Bytes.
  while ( bytesread < 12 ) // Read 10 digit code + 2 digit checksum
  {                      
    if( Serial.available() > 0)   // Check to make sure data is coming on the serial line
    {
      val = Serial.read();        // Store the current ASCII byte in val
                                
      if((val == 0x0D)||(val == 0x0A)||(val == 0x03)||(val == 0x02))
      {                           // If header or stop bytes before the 10 digit reading
        break;                    // Stop reading                                
      }
    
      if ( (val >= '0' ) && ( val <= '9' ) )    // Do Ascii/Hex conversion
      {
        val = val - '0';
      }
      else if ( ( val >= 'A' ) && ( val <= 'F' ) )
      {
        val = 10 + val - 'A';
      }

      if ( bytesread & 1 == 1 )      // Every two ASCII charactors = 1 BYTE in HEX format
      {
                                     // Make some space for this hex-digit by
                                     // shifting the previous hex-digit with 4 bits to the left:
        readCard[bytesread >> 1] = (val | (tempbyte << 4));
  
        if ( bytesread >> 1 != 5 )                // If we're at the checksum byte,
        {
          checksum ^= readCard[bytesread >> 1];   // Calculate the checksum using XOR
        };
      }
      else                                        // If it is the first HEX charactor
      {
        tempbyte = val;                           // Store the HEX in a temp variable
      };
      bytesread++;                                // Increment the counter to keep track
    }
  }
  bytesread = 0;
}


// Read an ID from EEPROM and save it to the storedCard[6] array
void readID( int number )  // Number = position in EEPROM to get the 5 Bytes from
{
   int start = (number * 5 ) - 4;  // Figure out starting position
   //Serial.print("Start: ");
   //Serial.print(start);
   //Serial.print("\n\n");
  
   for ( int i = 0; i < 5; i++ )  // Loop 5 times to get the 5 Bytes
   {
     storedCard[i] = EEPROM.read(start+i);  // Assign values read from EEPROM to array
     /*
     Serial.print("Read [");
     Serial.print(start+i);
     Serial.print("] [");
     Serial.print(storedCard[i], HEX);
     Serial.print("] \n");
     */
   }
}

// Write an array to the EEPROM in the next available slot
void writeID( byte a[] )
{
  if ( !findID( a ) )          // Before we write to the EEPROM, check to see if we have seen this card before!
  {
    int num = EEPROM.read(0);  // Get the numer of used spaces, position 0 stores the number of ID cards
    /*
    Serial.print("Num: ");
    Serial.print(num);
    Serial.print(" \n");
    */
    int start = ( num * 5 ) + 1;   // Figure out where the next slot starts
 
    num++;                         // Increment the counter by one
    EEPROM.write( 0, num );        // Write the new count to the counter
  
    for ( int j = 0; j < 5; j++ )  // Loop 5 times
    {
      EEPROM.write( start+j, a[j] );  // Write the array values to EEPROM in the right position
      /*
      Serial.print("W[");
      Serial.print(start+j);
      Serial.print("] Value [");
      Serial.print(a[j], HEX);
      Serial.print("] \n");
      */
    }
    successWrite();
  }
  else
  {
    failedWrite();
  }
}

// Check two arrays of bytes to see if they are exact matches
boolean checkTwo ( 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
    {
    Serial.print("[");
    Serial.print("Does not match");
    Serial.print("] ReadCard [");
    Serial.print(a[k], HEX);
    Serial.print("] StoredCard [");
    Serial.print(b[k], HEX);
    Serial.print("] \n");
     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
  }
}

// Looks in the EEPROM to try to match any of the EEPROM ID's with the passed ID
boolean findID( byte find[] )
{
  int count = EEPROM.read(0);             // Read the first Byte of EEPROM that
  Serial.print("Count: ");                // stores the number of ID's in EEPROM
  Serial.print(count);
  Serial.print("\n");
  for ( int i = 1; i <= count; i++ )      // Loop once for each EEPROM entry
  {
    readID(i);                            // Read an ID from EEPROM, it is stored in storedCard[6]
    if( checkTwo( find, storedCard ) )    // Check to see if the storedCard read from EEPROM
    {                                     // is the same as the find[] ID card passed
      Serial.print("We have a matched card!!! \n");
      return true;
      break;                              // Stop looking we found it
    }
    else                                  // If not, return false
    {
      Serial.print("No Match here.... \n");
    }
  
  }
  return false;
}

// Opens door and turns on the green LED for setDelay seconds
void openDoor( int setDelay )
{
  setDelay *= 1000; // Sets delay in seconds
 
  digitalWrite(powerPin, LOW);  // Turn off blue LED
  digitalWrite(failPin, LOW);   // Turn off red LED
  digitalWrite(passPin, HIGH);  // Turn on green LED
  digitalWrite(doorPin, HIGH);  // Unlock door!
 
  delay(setDelay); // Hold door lock open for 5 seconds
 
  digitalWrite(doorPin, LOW); // Relock door
  digitalWrite(passPin, LOW); // Turn off green LED
}

// Flashes Red LED if failed login
void failed()
{
  digitalWrite(passPin, LOW);   // Make sure green LED is off
  digitalWrite(powerPin, LOW);  // Make sure blue LED is off
    
  // Blink red fail LED 3 times to indicate failed key
  digitalWrite(failPin, HIGH);  // Turn on red LED
  delay(500);
  digitalWrite(failPin, LOW);   // Turn off red LED
    
  digitalWrite(failPin, HIGH);  // Turn on red LED
  delay(500);
  digitalWrite(failPin, LOW);   // Turn off red LED
    
  digitalWrite(failPin, HIGH);  // Turn on red LED
  delay(500);
  digitalWrite(failPin, LOW);   // Turn off red LED
}

// Check to see if the ID passed is the master programing card
boolean isMaster( byte test[] )
{
  byte bytesread = 0;
  byte i = 0;                // Example card, replace with one of yours you want to be the master
  byte val[10] = {'2','6','0','3','A','V','D','3','6','9' };
  byte master[6];
  byte checksum = 0;
  byte tempbyte = 0;
  bytesread = 0;
 
  for ( i = 0; i < 10; i++ )  // First we need to convert the array above into a 5 HEX BYTE array
  {
    if ( (val[i] >= '0' ) && ( val[i] <= '9' ) )   // Convert one char to HEX
    {
      val[i] = val[i] - '0';
    }
    else if ( (val[i] >= 'A' ) && ( val[i] <= 'F' ) )
    {
      val[i] = 10 + val[i] - 'A';
    }
    
    if (bytesread & 1 == 1) // Every two hex-digits, add byte to code:
    {
        // make some space for this hex-digit by
        // shifting the previous hex-digit with 4 bits to the left:
      master[bytesread >> 1] = (val[i] | (tempbyte << 4));
  
      if (bytesread >> 1 != 5)                 // If we're at the checksum byte,
      {
        checksum ^= master[bytesread >> 1];      // Calculate the checksum... (XOR)
      };
    }
    else
    {
      tempbyte = val[i];                       // Store the first hex digit first...
    };
    bytesread++;        
  }

  if ( checkTwo( test, master ) )                // Check to see if the master = the test ID
    return true;
  else
    return false;
}

// Controls LED's for Normal mode, Blue on, all others off
void normalModeOn()
{
  digitalWrite(powerPin, HIGH);    // Power pin ON and ready to read card
  digitalWrite(passPin, LOW);      // Make sure Green LED is off
  digitalWrite(failPin, LOW);      // Make sure Red LED is off
  digitalWrite(doorPin, LOW);      // Make sure Door is Locked
}
  
// Controls LED's for program mode, cycles through RGB
void programModeOn()
{
  digitalWrite(powerPin, LOW);  // Make sure blue LED is off
  digitalWrite(failPin, LOW);   // Make sure blue LED is off
  digitalWrite(passPin, HIGH);  // Make sure green LED is on
  delay(200);
  digitalWrite(powerPin, LOW);  // Make sure blue LED is off
  digitalWrite(failPin, HIGH);  // Make sure blue LED is on
  digitalWrite(passPin, LOW);   // Make sure green LED is off
  delay(200);
  digitalWrite(powerPin, HIGH); // Make sure blue LED is on
  digitalWrite(failPin, LOW);   // Make sure blue LED is off
  digitalWrite(passPin, LOW);   // Make sure green LED is off
  delay(200);
}

// Flashes the green LED 3 times to indicate a successful write to EEPROM
void successWrite()
{
  digitalWrite(powerPin, LOW); // Make sure blue LED is off
  digitalWrite(failPin, LOW);  // Make sure blue LED is off
  digitalWrite(passPin, HIGH); // Make sure green LED is on
  delay(200);
  digitalWrite(passPin, LOW);  // Make sure green LED is off
  delay(200);
  digitalWrite(passPin, HIGH); // Make sure green LED is on
  delay(200);
  digitalWrite(passPin, LOW);  // Make sure green LED is off
  delay(200);
  digitalWrite(passPin, HIGH); // Make sure green LED is on
  delay(200);
}

// Flashes the red LED 3 times to indicate a failed write to EEPROM
void failedWrite()
{
  digitalWrite(powerPin, LOW); // Make sure blue LED is off
  digitalWrite(failPin, HIGH); // Make sure red LED is on
  digitalWrite(passPin, LOW);  // Make sure green LED is off
  delay(200);
  digitalWrite(failPin, LOW);  // Make sure red LED is off
  delay(200);
  digitalWrite(failPin, HIGH); // Make sure red LED is on
  delay(200);
  digitalWrite(failPin, LOW);  // Make sure red LED is off
  delay(200);
  digitalWrite(failPin, HIGH); // Make sure red LED is on
  delay(200);
}

No comments:

Post a Comment