RFID with Arduino and HID ThinLine II reader – software

· Read in about 4 min · (724 Words)

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

Wiring Diagram

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