As I mentioned in a previous post, I have written code to read a ProxPoint Plus 6800 RFID Reader (Clock & Data output model) from HID. This is going to be a very long post, so click through to read it all.

Here is the Arduino sketch code to read the data from an HID RFID Card. FYI: I know it looks stupid to use an array of bytes to read binary data, but since the boolean type is a byte in size (according to the arduino.cc reference site) it made more sense to use bytes and not have to switch from ‘true/false’ to ‘1/0’ when trying to print to a debugging console or to do math with.

// Test code for HID Prox reader with clock/data output
// Code by Paul Lariviere – Jan 2011
//
// Card Present should be wired to pin 13
// Clock should be wired to pin 2
// Data should be wired to pin 12

int cardPresentPin = 13;
int clockPin = 2;
int dataPin = 12;
volatile int count = 0;
volatile byte data[200];

void setup()
{
pinMode(cardPresentPin, INPUT);
pinMode(dataPin, INPUT);
pinMode(clockPin, INPUT);
attachInterrupt(0, readBit, RISING);
Serial.begin(9600);
for (int a = 0; a < 200; a++)
{
data[a] = 0;
}
}

void loop()
{
if (digitalRead(cardPresentPin) == LOW)
{
//Serial.println("interrupts enabled");
interrupts();
}
else
{
noInterrupts();
if (count != 0)
{
Serial.println("READ COMPLETE!");
for (int a = 0; a <200; a++)
{
Serial.print(data[a]);
}
count = 0;
}
}
}

void readBit()
{
//Serial.println("reading bit");
if (digitalRead(dataPin) == HIGH)
{
data[count] = 0;
}
else
{
data[count] = 1;
}
count++;
}

The code works by attaching an interrupt to the Clock line that will trigger the readBit function, which will read a bit from the data line and store the result in an array at each time interval. If you want to see why this works, you can check out the HID Reader documentation to see a protocol timing chart and it becomes immediately obvious what is going on.

Once a card is placed in range of the reader, the reader changes the state of the Card Present pin. This code will enable interrupts as soon as this signal is detected. Once interrupts are enabled, a clock signal triggers a bit-read event until the card is read.

So this code will read the first 200 bits from the data line. You can check HID’s documentation to see exactly how many bits it spits out, but it’s more than 200, I simply stopped reading early. IIRC the final output is the same format as track2 data on a magstripe, so if you want to read the whole thing you can check the HID documentation to see how many bits the entire read ends up being.

Once we have the data, we then need to convert the raw data to a final card number. This part was particularly bothersome to figure out because I had a really hard time with HID’s documentation of the procedure. It’s probably just because I’m slow, but it took me quite a few tries and several reads of the documentation to decode the card data. I will post the detailled procedure I used in case anybody else find the HID docs to be a bit confusing.

Here is a sample of output that I received when reading an unused test card:

0000000000000000000000000
1101000001000010000100001
0000100001000010110110101
0000101000100001100101101
0000101101111111110000000
0000000000000000000000000
0000000000000000000000000
0000000000000000000000000

The output is laid out as 25 bits per line. The protocol specification says that the reader sends 25 leading 0’s and a whole bunch of trailing 0’s after the actual useful card data. Here is the above output with the additional rows of 0s removed:

1101000001000010000100001
0000100001000010110110101
0000101000100001100101101
0000101101111111110000000

Here is the info given from the card (# printed along the edge of the HID card):
card #: 35779 = HEX: 8BC3 = BIN: 1000 1011 1100 0011
This binary pattern is what we’re ultimately looking for in our end result

This is the raw data decoded assuming 5-bit chunks with format: MSB X X LSB PARITY
stripping off the parity and converting to hex we get:
B0000000650213606F
or in binary with parity bits removed:
B – 0000 0000 0000 0000 0000 0000 0000 0110 1010 0000 0100 1000 1100 0110 0000 0110 – F

B and F are the start/end sentinels so we don’t need them

Here’s the tricky part. 1: the bits are reversed (msb..lsb) and 2: it looks like 4bit hex but it’s actually 3bit octal with an extra 0 for padding on the right hand side (so the true format is MSB X LSB PAD). Inverting the bits and dropping the 0 pad we are left with:

110 101 000 010 001 011 110 000 110

Now, we start from the right and take 26 bits (results in simply dropping the leading 1 in this case) and we’re left with:
10 101 000 010 001 011 110 000 110
p……………………………………………..p

The first and last bits of this 26bit remainder are parity bits. Toss them. Result:
0 101 000 010 001 011 110 000 11

Re-arrange this result into 4bit chunks and covert to hex:

…5……0………8……B……C…..3
0101 0000 1000 1011 1100 0011
| facility # |…….card number…….|

The card number portion matches exactly our “known” card number from above. For a complete implementation these mathematical operations just need to be converted to code. I never ended up finishing this project b/c we decided to use a Rabbit micro. for our access control application due to the performance and price ($32 ~ the same price as an Arduino but with built-in Ethernet + web server, etc.)

When implementing the decoding into an Arduino sketch it would be a good idea to perform parity checks instead of just tossing the parity bits away as I described above. If anybody ends up implementing some Arduino code to finish the functionality and sends me a msg I will post a link to it here.

Happy Making!

Edit: Original code had a mistake that used interrupt 1 with pin2 instead of interrupt 0. This was brought to my attention in comments below but I didn’t have time to confirm / correct at that time. Since this project seems to still be getting attention I confirmed the mistake using the Arduino.cc documentation and fixed the code.