Continuing my previous post I will show you how I connected the HID ThinLine II reader and was able to read various RFID cards.
Wiring the Arduino and HID ThinLilne II
Here is how I connected the HID to the Arduino Uno.
- The battery minus is connected to the Arduino GND as well as to the BLACK wire on the HID Reader
- The battery plus is connected to the RED (VCC) of the HID reader
- The GREEN DATA0 wire from the HID is connected to Pin 2 on the Arduino
- The WHITE DATA1 wire from the HID is connected to Pin 3 on the Arduino
Let’s see some code. What I wanted to do is write a reader class that would read the value of the card from the data reader and then return it, so I can write various parsers for the different cards I was experimenting with. I had setup two interrupt handlers (that is how many the Arduino Uno supports) and some timers.
My main application is as follows:
#include <WiegandReader.h>
WiegandReader rfid;
// End code for DATA0 and DATA1
void setup()
{
Serial.begin(57600);
while (!Serial);
delay(10);
}
void loop()
{
if (rfid.IsAvailable())
{
RFIDInfo rInfo;
uint32_t facility = 0, card = 0;
if (rfid.Read(rInfo) && ParseCardValue(facility, card, rInfo))
{
Serial.print("ID: ");
Serial.println(card);
Serial.print("Facility: ");
Serial.println(facility);
}
}
}
In order for data to be «Available» I had postulated that at least 26 bits must have been received and the time since the last received bit is at least ~25ms. Once the data is available, it can be read and parsed.
The two parsers I wrote are for 26-bit (checking the parity) and 32, 35, 37-bit cards (not checking the parity and making assumptions on the card code length).
Here is the 26-bit parser:
bool ParseWiegand26(uint32_t& facility, uint32_t& card, const uint64_t data)
{
uint64_t bitHolder = data;
uint64_t bitHolderParity = data;
uint64_t one = 1;
unsigned int oddParity = bitHolder & 0x1UL;
bitHolder >>= 1; // Skip the parity
card = bitHolder & 0xFFFFUL;
bitHolder >>= 16; // Skip the card code
facility = bitHolder & 0xFFUL;
bitHolder >>= 8; // Skip the facility code
unsigned int evenParity = bitHolder & 0x1UL;
#ifdef _DEBUG
Serial.print("Even Parity: ");
Serial.println(evenParity, BIN);
Serial.print("Facility Code: ");
Serial.println(facility, BIN);
Serial.print("Card Code: ");
Serial.println(card, BIN);
Serial.print("Odd Parity: ");
Serial.println(oddParity, BIN);
#endif // DEBUG
// Check Even Parity
unsigned int oddCount = 0;
for (int cnt = 0; cnt < 13; cnt++)
{
oddCount += bitHolderParity & one;
bitHolderParity >>= 1;
}
unsigned int evenCount = 0;
for (int cnt = 0; cnt < 13; cnt++)
{
evenCount += bitHolderParity & one;
bitHolderParity >>= 1;
}
if (evenCount % 2 != 0)
{
#ifdef _DEBUG
Serial.println("Even Parity Mismatch!");
#endif
return false;
}
if (oddCount % 2 == 0)
{
#ifdef _DEBUG
Serial.println("Odd Parity Mismatch!");
#endif
return false;
}
return true;
}
And here is my reader code from the little library I created:
#include "WiegandReader.h"
volatile unsigned int WiegandReader::currentBitCount = 0; // what is the current bit count
volatile uint64_t WiegandReader::bitHolder = 0; // holds the bits received
volatile unsigned long WiegandReader::lastBitReceived = 0; // the time since the last bit was received
volatile bool WiegandReader::IsInitialized = false;
void WiegandReader::Initialize()
{
// Arduino Uno only has 2 pins for interrupts
Reset();
pinMode(Data0Pin, INPUT);
pinMode(Data1Pin, INPUT);
attachInterrupt(digitalPinToInterrupt(Data0Pin), Data0IntHandler, FALLING); // high to low
attachInterrupt(digitalPinToInterrupt(Data1Pin), Data1IntHandler, FALLING); // high to low
IsInitialized = true;
}
bool WiegandReader::IsAvailable()
{
if (!IsInitialized)
Initialize();
if (currentBitCount >= 26)
{
unsigned long timeDiff = millis() - lastBitReceived;
if (timeDiff > 25)
return true;
}
return false;
}
bool WiegandReader::Read(RFIDInfo& rfid)
{
bool retCode = false;
noInterrupts();
rfid.NumBits = 0;
rfid.Data = 0;
Serial.print("Bit Count: ");
Serial.println(currentBitCount);
if (currentBitCount >= 26)
{
rfid.NumBits = currentBitCount;
rfid.Data = bitHolder;
retCode = true;
}
Reset();
interrupts();
return retCode;
}
void WiegandReader::CheckTimingAndReset()
{
unsigned long timeDiff = millis() - lastBitReceived;
if (timeDiff > 25) // Must be a messed up protocol
{
Reset();
}
}
void WiegandReader::Reset()
{
currentBitCount = 0;
bitHolder = 0;
lastBitReceived = 0;
}
void WiegandReader::Data0IntHandler()
{
CheckTimingAndReset();
currentBitCount++;
if (currentBitCount > 64)
Reset();
bitHolder = bitHolder << 1;
lastBitReceived = millis();
}
void WiegandReader::Data1IntHandler()
{
CheckTimingAndReset();
currentBitCount++;
if (currentBitCount > 64)
Reset();
bitHolder = bitHolder << 1;
bitHolder |= 1;
lastBitReceived = millis();
}
Here is the full source code if interested: https://github.com/bbetov/WiegandReader.git