Last active
March 13, 2022 00:09
-
-
Save linuxgemini/9f089af171d5842eaaa4e0ae39f7d957 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
WiegandNG Extended Demo for HID Readers | |
2021-08-06 linuxgemini | |
Released under GNU LGPL v2.1 (or later) | |
*/ | |
// HID SEOS: FC 54, CC 64004 | |
const unsigned char correctID[] = {0x00, 0x6D, 0xF4, 0x08}; | |
// HID Prox: FC 95, CC 10491 | |
const unsigned long correctHIDidFC = 95; | |
const unsigned long correctHIDidCC = 10491; | |
const unsigned long correctHIDidCN = 0; | |
#include <WiegandNG.h> | |
#define pinD0 2 | |
#define pinD1 3 | |
#define READER_RED 8 | |
#define READER_GRN 9 | |
#define READER_HLD 10 | |
#define READER_BZR 11 | |
#define READER_TMP 12 | |
#define WIEGAND_BITS 50 | |
#define WIEGAND_PACKETGAP 25 | |
const int pins[] = {READER_RED, READER_GRN, READER_HLD, READER_BZR, READER_TMP}; | |
const int pinModes[] = {OUTPUT, OUTPUT, OUTPUT, OUTPUT, INPUT}; | |
const int pinDefaults[] = {HIGH, HIGH, HIGH, HIGH, 0}; | |
WiegandNG wg; | |
unsigned long offMillis = 0; | |
unsigned long nextBuzzerMillis = 0; | |
unsigned long holdEnd = 0; | |
bool buzzerOn = false; | |
int buzzerCount = 0; | |
bool buzzerCont = false; | |
bool tamper = false; | |
bool tamperOpenedPrinted = false; | |
bool tamperClosedPrinted = true; | |
struct HIDcardObject { | |
unsigned long facilityCode; | |
unsigned long cardCode; | |
unsigned long cardNumber; | |
int isProcessed; | |
}; | |
void setup() { | |
Serial.begin(9600); | |
for (int i = 0; i < (sizeof(pins) / sizeof(pins[0])); i++) { | |
Serial.print(F("Setting pin ")); | |
Serial.print(pins[i]); | |
Serial.print(F(" to mode ")); | |
Serial.print(pinModes[i]); | |
Serial.print(F(" with default value ")); | |
Serial.println(pinDefaults[i]); | |
pinMode(pins[i], pinModes[i]); | |
if (pinModes[i] == OUTPUT) digitalWrite(pins[i], pinDefaults[i]); | |
} | |
if (!wg.begin(pinD0, pinD1, WIEGAND_BITS, WIEGAND_PACKETGAP)) { | |
Serial.println(F("Out of memory!")); | |
} | |
Serial.println(F("Ready to read.")); | |
} | |
void PrintBinary(WiegandNG &tempwg) { | |
volatile unsigned char *wgbuffer = tempwg.getRawData(); | |
unsigned int bufferSize = tempwg.getBufferSize(); | |
unsigned int countedBits = tempwg.getBitCounted(); | |
unsigned int countedBytes = (countedBits / 8); | |
if ((countedBits % 8) > 0) countedBytes++; | |
unsigned int regularFirstByteLocator = bufferSize - countedBytes; | |
unsigned char bits[countedBits]; | |
unsigned int intoffset = 0; | |
for (unsigned int i = regularFirstByteLocator; i < bufferSize; i++) { | |
unsigned char bufByte = wgbuffer[i]; | |
for (int x = 0; x < 8; x++) { | |
if ((((bufferSize - i) * 8) - x) <= countedBits) { | |
unsigned char bytebinary = 0; | |
if ((bufByte & 0x80)) { | |
bytebinary = 1; | |
} | |
bits[intoffset] = bytebinary; | |
intoffset++; | |
} | |
bufByte <<= 1; | |
} | |
} | |
for (int i = 0; i < countedBits; i++) { | |
Serial.print(bits[i]); | |
} | |
Serial.println(); | |
} | |
void PrintHex(WiegandNG &tempwg) { | |
volatile unsigned char *wgbuffer = tempwg.getRawData(); | |
unsigned int bufferSize = tempwg.getBufferSize(); | |
unsigned int countedBits = tempwg.getBitCounted(); | |
unsigned int countedBytes = (countedBits / 8); | |
if ((countedBits % 8) > 0) countedBytes++; | |
unsigned int regularFirstByteLocator = bufferSize - countedBytes; | |
unsigned int countedBytesRaw = (countedBits / 8); | |
unsigned int rawFirstByteLocator = bufferSize - countedBytesRaw; | |
Serial.print(F(" Hex: ")); | |
for (unsigned int i = rawFirstByteLocator; i < bufferSize; i++) { | |
unsigned char bufByte = wgbuffer[i]; | |
char tmp[2]; | |
sprintf(tmp, "%.2X", bufByte); | |
Serial.print(tmp); | |
} | |
Serial.println(); | |
Serial.print(F(" Reversed Hex: ")); | |
if (rawFirstByteLocator > 0) { | |
for (unsigned int i = bufferSize - 1; i > rawFirstByteLocator - 1; i--) { | |
unsigned char bufByte = wgbuffer[i]; | |
char tmp[2]; | |
sprintf(tmp, "%.2X", bufByte); | |
Serial.print(tmp); | |
} | |
} else { | |
Serial.print("Failed to print"); | |
} | |
Serial.println(); | |
Serial.print(F(" Even Byte Friendly Hex: ")); | |
for (unsigned int i = regularFirstByteLocator; i < bufferSize; i++) { | |
unsigned char bufByte = wgbuffer[i]; | |
char tmp[2]; | |
sprintf(tmp, "%.2X", bufByte); | |
Serial.print(tmp); | |
} | |
Serial.println(); | |
Serial.print(F(" Even Byte Friendly Reversed Hex: ")); | |
if (regularFirstByteLocator > 0) { | |
for (unsigned int i = bufferSize - 1; i > regularFirstByteLocator - 1; i--) { | |
unsigned char bufByte = wgbuffer[i]; | |
char tmp[2]; | |
sprintf(tmp, "%.2X", bufByte); | |
Serial.print(tmp); | |
} | |
} else { | |
Serial.print("Failed to print"); | |
} | |
Serial.println(); | |
} | |
void PrintHID(HIDcardObject HIDcard, unsigned int bc) { | |
Serial.print(F(" Decoded HID (or AWID) Card: ")); | |
Serial.print(F("Card Type: ")); | |
switch (bc) { | |
case 50: | |
Serial.print(F("AWID RBH50")); | |
break; | |
case 37: | |
if (HIDcard.facilityCode <= 65535 && HIDcard.cardCode <= 524287) { | |
Serial.print(F("H10302 or H10304")); | |
} else { | |
Serial.print(F("H10302")); | |
} | |
break; | |
case 35: | |
Serial.print(F("H5XXXX (HID Corporate 1000)")); | |
break; | |
case 34: | |
Serial.print(F("H10306")); | |
break; | |
case 26: | |
Serial.print(F("H10301")); | |
break; | |
default: | |
Serial.print(F("Unknown")); | |
break; | |
} | |
if ((HIDcard.facilityCode <= 65535 && HIDcard.cardCode <= 524287) || bc == 50) { | |
Serial.print(F(", FC: ")); | |
Serial.print(HIDcard.facilityCode); | |
Serial.print(F(", CC: ")); | |
Serial.print(HIDcard.cardCode); | |
} | |
if (bc == 37) { | |
Serial.print(F(", CN: ")); | |
Serial.print(HIDcard.cardNumber); | |
} | |
Serial.println(); | |
} | |
HIDcardObject Wiegand50ToAWID(unsigned char bits[]) { | |
HIDcardObject HIDcard; | |
unsigned long facilityCode = 0; | |
unsigned long cardCode = 0; | |
// 50 bit AWID RBH50 format | |
// facility code = bits 2 to 16 | |
for (int i = 1; i < 17; i++) { | |
facilityCode <<= 1; | |
facilityCode |= bits[i]; | |
} | |
// card code = bits 17 to 49 | |
for (int i = 16; i < 49; i++) { | |
cardCode <<= 1; | |
cardCode |= bits[i]; | |
} | |
HIDcard.facilityCode = facilityCode; | |
HIDcard.cardCode = cardCode; | |
HIDcard.cardNumber = (unsigned long)0; | |
HIDcard.isProcessed = 1; | |
return HIDcard; | |
} | |
HIDcardObject Wiegand37ToHID(unsigned char bits[]) { | |
HIDcardObject HIDcard; | |
unsigned long facilityCode = 0; | |
unsigned long cardCode = 0; | |
unsigned long cardNumber = 0; // this is for H10302 | |
// 37 bit format (H10302 or H10304) | |
// H10304, FC and CC | |
// FC = bits 2 to 17 | |
for (int i = 1; i < 17; i++) { | |
facilityCode <<= 1; | |
facilityCode |= bits[i]; | |
} | |
// CC = bits 18 to 36 | |
for (int i = 17; i < 36; i++) { | |
cardCode <<= 1; | |
cardCode |= bits[i]; | |
} | |
// H10302, no FC or CC, CN is used | |
// bits 2 to 36 | |
for (int i = 1; i < 36; i++) { | |
cardNumber <<= 1; | |
cardNumber |= bits[i]; | |
} | |
HIDcard.facilityCode = facilityCode; | |
HIDcard.cardCode = cardCode; | |
HIDcard.cardNumber = cardNumber; | |
HIDcard.isProcessed = 1; | |
return HIDcard; | |
} | |
HIDcardObject Wiegand35ToHID(unsigned char bits[]) { | |
HIDcardObject HIDcard; | |
unsigned long facilityCode = 0; | |
unsigned long cardCode = 0; | |
// 35 bit HID Corporate 1000 format (H5XXXX) | |
// facility code = bits 2 to 14 | |
for (int i = 1; i < 14; i++) { | |
facilityCode <<= 1; | |
facilityCode |= bits[i]; | |
} | |
// card code = bits 15 to 34 | |
for (int i = 14; i < 34; i++) { | |
cardCode <<= 1; | |
cardCode |= bits[i]; | |
} | |
HIDcard.facilityCode = facilityCode; | |
HIDcard.cardCode = cardCode; | |
HIDcard.cardNumber = (unsigned long)0; | |
HIDcard.isProcessed = 1; | |
return HIDcard; | |
} | |
HIDcardObject Wiegand34ToHID(unsigned char bits[]) { | |
HIDcardObject HIDcard; | |
unsigned long facilityCode = 0; | |
unsigned long cardCode = 0; | |
// 34 bit format (H10306) | |
// FC = bits 2 to 17 | |
for (int i = 1; i < 17; i++) { | |
facilityCode <<= 1; | |
facilityCode |= bits[i]; | |
} | |
// CC = bits 18 to 33 | |
for (int i = 17; i < 33; i++) { | |
cardCode <<= 1; | |
cardCode |= bits[i]; | |
} | |
HIDcard.facilityCode = facilityCode; | |
HIDcard.cardCode = cardCode; | |
HIDcard.cardNumber = (unsigned long)0; | |
HIDcard.isProcessed = 1; | |
return HIDcard; | |
} | |
HIDcardObject Wiegand26ToHID(unsigned char bits[]) { | |
HIDcardObject HIDcard; | |
unsigned long facilityCode = 0; | |
unsigned long cardCode = 0; | |
// standard 26 bit format (H10301) | |
// facility code = bits 2 to 9 | |
for (int i = 1; i < 9; i++) { | |
facilityCode <<= 1; | |
facilityCode |= bits[i]; | |
} | |
// card code = bits 10 to 25 | |
for (int i = 9; i < 25; i++) { | |
cardCode <<= 1; | |
cardCode |= bits[i]; | |
} | |
HIDcard.facilityCode = facilityCode; | |
HIDcard.cardCode = cardCode; | |
HIDcard.cardNumber = (unsigned long)0; | |
HIDcard.isProcessed = 1; | |
return HIDcard; | |
} | |
HIDcardObject HandleHID(WiegandNG &tempwg) { | |
volatile unsigned char *wgbuffer = tempwg.getRawData(); | |
unsigned int bufferSize = tempwg.getBufferSize(); | |
unsigned int countedBits = tempwg.getBitCounted(); | |
unsigned int countedBytes = (countedBits / 8); | |
if ((countedBits % 8) > 0) countedBytes++; | |
unsigned char bits[countedBits]; | |
unsigned int intoffset = 0; | |
unsigned int regularFirstByteLocator = bufferSize - countedBytes; | |
for (unsigned int i = regularFirstByteLocator; i < bufferSize; i++) { | |
unsigned char bufByte = wgbuffer[i]; | |
for (int x = 0; x < 8; x++) { | |
if ((((bufferSize - i) * 8) - x) <= countedBits) { | |
unsigned char bytebinary = 0; | |
if ((bufByte & 0x80)) { | |
bytebinary = 1; | |
} | |
bits[intoffset] = bytebinary; | |
intoffset++; | |
} | |
bufByte <<= 1; | |
} | |
} | |
HIDcardObject HIDcard; | |
HIDcard.facilityCode = 0; | |
HIDcard.cardCode = 0; | |
HIDcard.cardNumber = 0; | |
HIDcard.isProcessed = 0; | |
if (countedBits == 50) { | |
HIDcard = Wiegand50ToAWID(bits); | |
} else if (countedBits == 37) { | |
HIDcard = Wiegand37ToHID(bits); | |
} else if (countedBits == 35) { | |
HIDcard = Wiegand35ToHID(bits); | |
} else if (countedBits == 34) { | |
HIDcard = Wiegand34ToHID(bits); | |
} else if (countedBits == 26) { | |
HIDcard = Wiegand26ToHID(bits); | |
} | |
return HIDcard; | |
} | |
bool CheckID(WiegandNG &tempwg) { | |
volatile unsigned char *wgbuffer = tempwg.getRawData(); | |
unsigned int bufferSize = tempwg.getBufferSize(); | |
unsigned int countedBits = tempwg.getBitCounted(); | |
unsigned int countedBytes = (countedBits / 8); | |
if ((countedBits % 8) > 0) countedBytes++; | |
unsigned int intoffset = 0; | |
unsigned int regularFirstByteLocator = bufferSize - countedBytes; | |
for (unsigned int i = regularFirstByteLocator; i < bufferSize; i++) { | |
unsigned char bufByte = wgbuffer[i]; | |
if (bufByte != correctID[intoffset]) return false; | |
intoffset++; | |
} | |
return true; | |
} | |
bool CheckHIDid(HIDcardObject HIDcard) { | |
if (!HIDcard.isProcessed) return false; | |
bool ch1 = HIDcard.facilityCode == correctHIDidFC; | |
bool ch2 = HIDcard.cardCode == correctHIDidCC; | |
bool ch3 = HIDcard.cardNumber == correctHIDidCN; | |
return (ch1 && ch2 && ch3); | |
} | |
void SetLED(int ledPin) { | |
if (ledPin > 0) { | |
digitalWrite(ledPin, LOW); | |
offMillis = millis() + 1250; | |
} else { | |
digitalWrite(READER_RED, HIGH); | |
digitalWrite(READER_GRN, HIGH); | |
} | |
} | |
void loop() { | |
if (wg.available() && !tamper) { | |
delay(75); | |
wg.pause(); // pause Wiegand pin interrupts | |
Serial.println(F("Wiegand Data Obtained:")); | |
Serial.print(F(" Bitsize: ")); | |
Serial.println(wg.getBitCounted()); | |
Serial.print(F(" Raw Binary: ")); | |
PrintBinary(wg); | |
PrintHex(wg); | |
HIDcardObject hidres = HandleHID(wg); | |
if (hidres.isProcessed) { | |
PrintHID(hidres, wg.getBitCounted()); | |
} | |
Serial.println(); | |
if (CheckID(wg) || CheckHIDid(hidres)) { | |
Serial.println(F("Card is validated, opening door...")); | |
SetLED(READER_GRN); | |
} else { | |
Serial.println(F("Card is not valid, buzzer is running...")); | |
SetLED(READER_RED); | |
buzzerOn = true; | |
buzzerCount = 0; | |
} | |
holdEnd = millis() + 3000; | |
Serial.println(); | |
wg.clear(); | |
} | |
if (tamper && !tamperOpenedPrinted) { | |
Serial.println(F("TAMPER OPEN, SOMETHING IS UP!")); | |
tamperOpenedPrinted = true; | |
tamperClosedPrinted = false; | |
} else if (!tamper && !tamperClosedPrinted) { | |
Serial.println(F("Tamper closed!")); | |
tamperOpenedPrinted = false; | |
tamperClosedPrinted = true; | |
} | |
if (!digitalRead(READER_TMP)) { | |
buzzerOn = true; | |
buzzerCont = true; | |
tamper = true; | |
SetLED(READER_GRN); | |
SetLED(READER_RED); | |
digitalWrite(READER_HLD, LOW); | |
} else { | |
buzzerCont = false; | |
tamper = false; | |
} | |
if (millis() > offMillis) { | |
SetLED(0); | |
} | |
if (millis() > nextBuzzerMillis && buzzerOn) { | |
if (buzzerCount >= 10 && !buzzerCont) { | |
buzzerOn = false; | |
SetLED(0); | |
} | |
digitalWrite(READER_BZR, buzzerOn ? buzzerCount % 2 : HIGH); | |
buzzerCount++; | |
nextBuzzerMillis = millis() + 90; | |
} | |
if (millis() > holdEnd && !tamper) digitalWrite(READER_HLD, HIGH); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment