Sunday, 29 September 2013

Using Implantable RFID Tags to identify trains

I think I'd like to be able to identify which train is which on my layout without having to type in numbers and so forth. I've decided to put a single RFID reader on the track somewhere and run all trains past it at the start of my sessions so the computers can work out what is where automagically.

I bought these nifty and tiny RFID tags from LittleBird.



And this RFID reader with a nice TTL UART for serial transmission.

Here's the extremely simple test circuit I built using an Arduino Nano to control it all...

The antenna is the red wiring loop on the top right. The Arduino is the blue board bottom left.

Sample code is below.



//
// This code implements a state machine to read a serial stream from pin 3
// for s simple 125KHz RFID reader:
//    http://www.seeedstudio.com/wiki/index.php?title=125Khz_RFID_module_-_UART
//
//  
//

#include <SoftwareSerial.h>

typedef enum RFIDProtStateType { initialising,
                            waiting_good, 
                            waiting_error, 
                            started, 
                            reading_digits, 
                            reading_cksum, 
                            waiting_finish, 
                            finished };
// a global representing the current command state
RFIDProtStateType  RFIDProtState;

boolean  GotRFID;

char  RFIDTag[10];
char  Checksum[2];

int  index;

#define  RFIDProtRxPin       3
#define  RFIDProtTxPin       2

SoftwareSerial RFIDProtSerial =  SoftwareSerial(RFIDProtRxPin, RFIDProtTxPin);


void
setup()
{
  Serial.begin(9600);

  RFIDProtSerial.begin(9600);

  index = 0;
  
  RFIDProtState = waiting_good;
  GotRFID = false;
}

//
// Convert a string containing 2 bytes representing a number in HEX into a hex byte
// ...so a string containin "A1" will be returned as 0xA1
//
byte
StringHexToByte(char *in)
{
  byte  result;
  int  j;
  
  result = 0;
  
  for(j = 0; j < 2 ; j ++)
  {
    if( in[j] >= 'A')
    {
      result |= (in[j] - 'A' + 10) << 4*(1-j);
    }
    else
    {
      result |= (in[j] - '0') << 4*(1-j);
    }
  }
  
  return result;
}


//
//
// Handle Char will process a message coming in of the form:
//
//     <0x02><10 hex digit ID tag><2 digit xor checksum><0x03>
//
// errors show up on pin 13 (with LED)
//
void
HandleCharacter(char c)
{
      int  i,j;
      byte  cksum = 0x00;
      byte  digit;
         
      switch(RFIDProtState)
      {
       case waiting_error:
       case waiting_good:
          if(c == 0x02)
          {
            // we now have the start character
            RFIDProtState = started;
            index = 0;
          }
          else
          {
            RFIDProtState = waiting_error;
          }         
          break;
          
        case started:
        case reading_digits:
          if(c >= '0')
          {
            RFIDProtState = reading_digits;
            RFIDTag[index++] = c;
            if(index == 10)
            {
              RFIDProtState = reading_cksum;
              index = 0;
            }  
          }
          else
          {
            RFIDProtState = waiting_error;
          }
          break;
          
        case reading_cksum:
          Checksum[index++] = c;
          
          if( index == 2)
          {
            // we now have the 2 bytes of checksum read in
            index = 0;
            cksum = 0;
             
            // calculate the checksum from the string of digits
            for(i=0; i< 5;i++)
            {
              digit = StringHexToByte(&RFIDTag[i*2]);
              cksum ^= digit;           
            }
                    
            if (cksum != StringHexToByte(Checksum))
              RFIDProtState = waiting_error;
            else
              RFIDProtState = waiting_finish;
          }  
          break;
          
        case waiting_finish:
          if(c == 0x03)
          {
            RFIDProtState = finished;
          }
          else
          {
            RFIDProtState = waiting_error;
            index = 0;
          }
          //break;
          // Note no break here - fall through and handle finishing
        case finished:
          index = 0;
          
          GotRFID = true;
          
          RFIDProtState = waiting_good;
          
          break;
      }

}

void
GetCommand()
{
  char  c;
  
    if(RFIDProtSerial.available())
    {
      c = RFIDProtSerial.read();
      HandleCharacter(c);
    }
    if (RFIDProtState == waiting_error)  
      digitalWrite(13, HIGH);
    else
      digitalWrite(13, LOW);
}


void
loop()
{
  
  GetCommand();
  
  if(GotRFID)
  {
    int  i;
    
    for(i = 0; i < 10; i++)
      Serial.print(RFIDTag[i]);
      
    Serial.println();
    
    GotRFID = false;
  }
  

}