Reading an RFID tag using a Wiegand Encoded RFID Reader

No Comments December 3, 2012

A while back I bought a couple of RFID readers from SeeedStudios – it was actually the first (of many) things that I picked up from there.

Right after I got the readers, I hooked one up to my Arduino, downloaded the test library that Seeed provided and got it to read some cards… then put it in a box with the intent of making something work, soon.

It took me a couple of years to get back to it – and the Netduino was my excuse… well, that and thinking about redoing the opener on my Garage door to add a door position monitor, temperature checking and possibly an RFID reader embedded in a secret location to open the door from the outside.

I decided to start with the Reader – since it would likely be the most difficult part. It took me a few hours – but turned out to be a great way for me to learn a bit more about how to develop for the Netduino.

It took some research for me to track down the documentation on the reader. But Seeed was very nice to still have a wiki page with the data for the reader: 125Khz RFID Module – Wiegand

I’m not quite sure what possessed me when I bought it, but instead of getting the serial port version, I got the version with the Wiegand encoded output…. I’m guess it was because the Wiegand format has greater range between the reader and the board... or something like that…

However, it did give me a good challenge to read the codes and learn some of the advance bits of the Netduino.

Very long story shortened quite a bit… Maybe I’ll fill this in more later.

I really need a logic analyzer – it would have made figuring some of this out a lot easier. I started with a poor man’s logic analyzer and hooked up the outputs of the reader to my Netduino:

RFID -> Netduino GPIO
-----------------------------------------------
PORT3 – LED -> D2
PORT1-DATA0 -> D3
PORT1-DATA1 -> D4

+5 & GND

First, I setup some interrupt pins and raised events as the data came in – and was able to pretty quickly make the inputs correspond to the datasheet.

Once I had the interrupt events working, I was able to build out the logic to decode the incoming bits and with some bit manipulation, I was able to get the value for the code printed on the tokens to appear on my Debugger console. (YEA!)

I incorporated all of the logic for the reader into a library that I can use for other stuff – again, good practice for using the Netduino.

There is still some work to do – I’m not checking the parity of the values yet.  But it should be pretty complete for reading and decoding the Wiegand formatted data. (As long as it is the 26 bit variety)

Here is the library for reading and decoding the value:

   1: using System;
   2: using Microsoft.SPOT;
   3: using Microsoft.SPOT.Hardware;
   4:  
   5: namespace CraigTuckerLibs.Hardware
   6: {
   7:  
   8:     /// --------------------------------------------------------------------
   9:     /// <summary>
  10:     /// Encapsulates the RFID Reader logic
  11:     /// </summary>
  12:     /// --------------------------------------------------------------------
  13:     public class RFIDReader
  14:     {
  15:         public event NativeEventHandler OnCodeRead;
  16:         
  17:         protected static byte BufferBitCount = 0;
  18:         protected static int CardValue = 0;
  19:  
  20:         /// --------------------------------------------------------------------
  21:         /// <summary>
  22:         /// Setup the RFIDReader for use
  23:         /// </summary>
  24:         /// --------------------------------------------------------------------
  25:         public RFIDReader(Cpu.Pin CardReadPin, Cpu.Pin Data0Pin, Cpu.Pin Data1Pin)
  26:         {
  27:             // the card read flag is triggered for each bit that is sent across to be read.
  28:             InterruptPort cardRead = new InterruptPort(CardReadPin, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
  29:             
  30:             cardRead.OnInterrupt += new NativeEventHandler(cardRead_OnInterrupt);
  31:             
  32:             // setup input bit ports
  33:             InterruptPort Data0 = new InterruptPort(Data0Pin, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeHigh);
  34:             InterruptPort Data1 = new InterruptPort(Data1Pin, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeHigh);
  35:             
  36:             Data0.OnInterrupt += new NativeEventHandler(Data0_OnInterrupt);
  37:             Data1.OnInterrupt += new NativeEventHandler(Data1_OnInterrupt);
  38:         }
  39:  
  40:  
  41:         /// --------------------------------------------------------------------
  42:         /// <summary>
  43:         /// Handles the Data1 pin event
  44:         /// </summary>
  45:         /// --------------------------------------------------------------------
  46:         protected void Data1_OnInterrupt(uint data1, uint data2, DateTime time)
  47:         {
  48:             // adds a '1' to the end of the current buffer
  49:             AddBit(true);
  50:         }
  51:  
  52:         /// --------------------------------------------------------------------
  53:         /// <summary>
  54:         /// Handles the Data0 pin event
  55:         /// </summary>
  56:         /// --------------------------------------------------------------------
  57:         protected void Data0_OnInterrupt(uint data1, uint data2, DateTime time)
  58:         {
  59:             // adds a '0' to the end of the current buffer
  60:             AddBit(false);
  61:         }
  62:  
  63:  
  64:  
  65:         /// --------------------------------------------------------------------
  66:         /// <summary>
  67:         /// Adds the next bit to the currently read code.
  68:         /// </summary>
  69:         /// --------------------------------------------------------------------
  70:         private void AddBit(bool flag)
  71:         {
  72:             //00 - start bit
  73:             //01 - data bit
  74:             //... - ...
  75:             //24 - data bit
  76:             //25 stop bit
  77:                         
  78:             // Read in the bit and process it
  79:             // ========================================
  80:             
  81:             // shift the card value up one position
  82:             CardValue = CardValue << 1;
  83:  
  84:             // append the specified bit to the end
  85:             if (flag)
  86:             {
  87:                 CardValue += 1;
  88:             }
  89:  
  90:             // increment the counter we are using to keep track of the the buffer position
  91:             BufferBitCount++;
  92:             
  93:             // this is the stop bit - need to process and verify what has been read
  94:             if (BufferBitCount == 26)
  95:             {
  96:                 // for later use, pull off the upper and lower parity values
  97:                 bool lowerParity = (CardValue & 0x1) > 0;
  98:                 bool upperParity = (CardValue & 0x4000000) > 0;
  99:  
 100:                 //TODO: Read the upper and lower bytes and verify the parity is correct:
 101:                 // BASIC BREAKDOWN  : First 12 bits are checked against first Even Parity bit (Position 0)
 102:                 //                    Second 12 bits are checked agains the last Odd Parity bit (Position 25)
 103:                 /*
 104:                 bit    0    1    2    3    4    5    6    7    8    9    10    11    12    13    14    15    16    17    18    19    20    21    22    23    24    25
 105:                  -    P-EVEN                                                                                              P-ODD
 106:                  -  P   E   E   E   E   E   E   E   E   E   E   E   E   O   O   O   O   O   O   O   O   O   O   O   O   P
 107:                  */
 108:  
 109:                 // finally, shift off the last parity bit then masks out the remainder to get the actual serial # value
 110:                 UInt32 serialNumber = (UInt32)((CardValue >> 1) & 0xFFFFFF); 
 111:  
 112:                 // reset the buffer values, just in case the CardRead event doesn't fire as expected
 113:                 BufferBitCount = 0;
 114:                 CardValue = 0;
 115:  
 116:                 // raise the Code Read event - we can assume we have a successful read.
 117:                 InvokeOnCodeRead(0, serialNumber, DateTime.Now);
 118:             }
 119:         }
 120:  
 121:  
 122:         /// --------------------------------------------------------------------
 123:         /// <summary>
 124:         /// Handles the Card Read Event
 125:         /// </summary>
 126:         /// --------------------------------------------------------------------
 127:         static void cardRead_OnInterrupt(uint data1, uint data2, DateTime time)
 128:         {
 129:             // assume that if this happens, we are starting a new read, reset any existing
 130:             // processing that is going on.
 131:             BufferBitCount = 0;
 132:             CardValue = 0;
 133:         }
 134:  
 135:  
 136:  
 137:         /// --------------------------------------------------------------------
 138:         /// <summary>
 139:         /// Raises the event when a new code has been read.  Data2 will contain
 140:         /// the value that was found by the reader
 141:         /// </summary>
 142:         /// --------------------------------------------------------------------
 143:         private void InvokeOnCodeRead(uint data1, uint data2, DateTime time)
 144:         {
 145:             if (OnCodeRead != null)
 146:             {
 147:                 OnCodeRead(data1, data2, time);
 148:             }
 149:         }
 150:  
 151:     }
 152: }

And this is the sample code that will use the library to display the serial number of the tag in the debugger:

   1: using System;
   2: using System.Net;
   3: using System.Net.Sockets;
   4: using System.Threading;
   5: using Microsoft.SPOT;
   6: using Microsoft.SPOT.Hardware;
   7: using SecretLabs.NETMF.Hardware;
   8: using SecretLabs.NETMF.Hardware.Netduino;
   9: using System.IO.Ports;
  10: using CraigTuckerLibs.Hardware;
  11:  
  12: namespace RFIDTest
  13: {
  14:     public class Program
  15:     {
  16:         /// --------------------------------------------------------------------
  17:         /// <summary>
  18:         /// Handles the Main Event
  19:         /// </summary>
  20:         /// --------------------------------------------------------------------
  21:         public static void Main()
  22:         {
  23:             RFIDReader RFID = new RFIDReader(Pins.GPIO_PIN_D2, Pins.GPIO_PIN_D3, Pins.GPIO_PIN_D4);
  24:             RFID.OnCodeRead += new NativeEventHandler(RFID_OnCodeRead);
  25:            
  26:                         
  27:             // hang out and run the app:
  28:             Thread.Sleep(Timeout.Infinite);
  29:         }
  30:  
  31:         /// --------------------------------------------------------------------
  32:         /// <summary>
  33:         /// Code was sent from RFID Reader
  34:         /// </summary>
  35:         /// --------------------------------------------------------------------
  36:         static void RFID_OnCodeRead(uint data1, uint data2, DateTime time)
  37:         {
  38:             Debug.Print("SerialNumber: " + data2.ToString());
  39:         }
  40:     }
  41: }

 


No Comments