├── .gitignore ├── README.md ├── examples └── WiegandTest │ └── WiegandTest.ino ├── keywords.txt ├── library.properties └── src ├── Wiegand.cpp └── Wiegand.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.bak -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wiegand 4 bit, 8 bit, 24 bit, 26 bit, 32 bit and 34 bit library for Arduino 2 | 3 | The Wiegand interface is a de facto standard commonly used to connect a card reader or keypad to an electronic entry system. Wiegand interface has the ability to transmit signal over long distance with a simple 3 wires connection. This library uses interrupt pins from Arduino to read the pulses from Wiegand interface and return the code and type of the Wiegand. 4 | 5 | # Different Wiegand libraries comparison 6 | 7 | | Library | Description | 8 | | ---| --- | 9 | | [Wiegand library](https://github.com/monkeyboard/Wiegand-Protocol-Library-for-Arduino) | This is the easiest and cleanest library to use when only a single wiegand reader is needed. I strongly suggest to use this version if you only need one reader support | 10 | | [Wiegand NG library](https://github.com/jpliew/Wiegand-NG-Multi-Bit-Wiegand-Library-for-Arduino) | This is another single reader library, however it uses dynamic memory to store the raw wiegand thus allowing unlimited bit length to be stored as long as your Arduino board has the memory to store it. I won't recommend to use this library unless you are facing a non-standard wiegand reader that sends out data that will not be decoded by the original Wiegand library. | 11 | | [Multi Wiegand library](https://github.com/jpliew/Multi-Reader-Wiegand-Protocol-Library-for-Arduino) | This library uses pin change interrupt this allowing all the pin change interrupt supported pin to be used. With this, multiple readers can also be supported. Due to a workaround (hack) used to overcome the limitation with `attachInterrupt` not being able to be attached to class method directly, the initialisation of the sketch is more ugly and complicated. | 12 | 13 | ## Requirements 14 | 15 | The following are needed 16 | 17 | * [Arduino](http://www.arduino.cc) - Any ATMEGA328 compatible board should work. 18 | * [Wiegand RFID Reader](http://www.monkeyboard.org/products/85-developmentboard/84-rfid-wiegand-protocol-development-kit) - The code was written for this reader however customers reported working with [HID](http://www.hidglobal.com/products/cards-and-credentials) compatible readers. 19 | * DATA0 of Wiegand connects to Arduino PIN 2 and DATA1 of Wiegand connects to Arduino PIN 3 20 | 21 | ## Installation 22 | 23 | Create a folder named Wiegand in Arduino's libraries folder. You will have the following folder structure: 24 | 25 | cd arduino/libraries 26 | git clone https://github.com/monkeyboard/Wiegand-Protocol-Library-for-Arduino.git Wiegand 27 | 28 | ## Arduino Sketch 29 | 30 | ![alt text](http://www.monkeyboard.org/images/tutorials/wiegand/wiegand_arduino.png "RFID Reader to Arduino connection diagram") 31 | 32 | 33 | Execute Arduino IDE, select Example-->Wiegand-->WiegandTest 34 | 35 | ### Example 36 |

37 | #include <Wiegand.h>
38 | 
39 | WIEGAND wg;
40 | 
41 | void setup() {
42 | 	Serial.begin(9600);  
43 | 	
44 | 	// default Wiegand Pin 2 and Pin 3 see image on README.md
45 | 	// for non UNO board, use wg.begin(pinD0, pinD1) where pinD0 and pinD1 
46 | 	// are the pins connected to D0 and D1 of wiegand reader respectively.
47 | 	wg.begin();
48 | }
49 | 
50 | void loop() {
51 | 	if(wg.available())
52 | 	{
53 | 		Serial.print("Wiegand HEX = ");
54 | 		Serial.print(wg.getCode(),HEX);
55 | 		Serial.print(", DECIMAL = ");
56 | 		Serial.print(wg.getCode());
57 | 		Serial.print(", Type W");
58 | 		Serial.println(wg.getWiegandType());    
59 | 	}
60 | }
61 | 
62 | 63 | 64 | ## Contributors 65 | 66 | [softwarefoundry](https://github.com/softwarefoundry) added library.properties 67 | 68 | [Francesco Uggetti (ugge75)](https://github.com/ugge75) improved this version of library to support multiple readers for ATMEGA2560. Please check out [his version of multiple wiegand readers library here](https://github.com/ugge75/Wiegand-Protocol-Library-for-Arduino-MEGA-2560) 69 | 70 | [Apollon77](https://github.com/Apollon77) improved interrupt safety and removed sysTick from global 71 | 72 | [paulfurley](https://github.com/paulfurley) added 4 bit code 73 | 74 | [PaulStoffregen](https://github.com/PaulStoffregen) added Use digitalPinToInterrupt on newer Arduino software, if present 75 | 76 | [tholum](https://github.com/tholum) Simpler Instructions 77 | 78 | [zanhecht](https://github.com/zanhecht) Recognize 24- and 32-bit 79 | 80 | [luckymallari](https://github.com/luckymallari) Simplified begin(D0, D1) for ESP(8266/32) devices. 81 | 82 | Written by [JP Liew](http://jpliew.com) 83 | 84 | Project home: http://www.monkeyboard.org/tutorials/82-protocol/24-wiegand-converter 85 | 86 | *This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.* 87 | 88 | *This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.* 89 | -------------------------------------------------------------------------------- /examples/WiegandTest/WiegandTest.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | WIEGAND wg; 4 | 5 | void setup() { 6 | Serial.begin(9600); 7 | 8 | // default Wiegand Pin 2 and Pin 3 see image on README.md 9 | // for non UNO board, use wg.begin(pinD0, pinD1) where pinD0 and pinD1 10 | // are the pins connected to D0 and D1 of wiegand reader respectively. 11 | wg.begin(); 12 | } 13 | 14 | void loop() { 15 | if(wg.available()) 16 | { 17 | Serial.print("Wiegand HEX = "); 18 | Serial.print(wg.getCode(),HEX); 19 | Serial.print(", DECIMAL = "); 20 | Serial.print(wg.getCode()); 21 | Serial.print(", Type W"); 22 | Serial.println(wg.getWiegandType()); 23 | } 24 | } -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Wiegand Library 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | WIEGAND KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | getCode KEYWORD2 16 | getWiegandType KEYWORD2 17 | available KEYWORD2 18 | 19 | ####################################### 20 | # Constants (LITERAL1) 21 | ####################################### 22 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Wiegand Protocol Library for Arduino 2 | version=1.0.20 3 | author=JP Liew 4 | maintainer=https://github.com/monkeyboard 5 | sentence=Wiegand 26 and Wiegand 34 Protocol Library for Arduino 6 | paragraph=The Wiegand interface is a de facto standard commonly used to connect a card reader or keypad to an electronic entry system. Wiegand interface has the ability to transmit signal over long distance with a simple 3 wires connection. This library uses interrupt pins from Arduino to read the pulses from Wiegand interface and return the code and type of the Wiegand. 7 | category=Communication 8 | url=https://github.com/monkeyboard/Wiegand-Protocol-Library-for-Arduino.git 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/Wiegand.cpp: -------------------------------------------------------------------------------- 1 | #include "Wiegand.h" 2 | 3 | #if defined(ESP8266) 4 | #define INTERRUPT_ATTR ICACHE_RAM_ATTR 5 | #elif defined(ESP32) 6 | #define INTERRUPT_ATTR IRAM_ATTR 7 | #else 8 | #define INTERRUPT_ATTR 9 | #endif 10 | 11 | volatile unsigned long WIEGAND::_cardTempHigh=0; 12 | volatile unsigned long WIEGAND::_cardTemp=0; 13 | volatile unsigned long WIEGAND::_lastWiegand=0; 14 | unsigned long WIEGAND::_code=0; 15 | volatile int WIEGAND::_bitCount=0; 16 | int WIEGAND::_wiegandType=0; 17 | 18 | WIEGAND::WIEGAND() 19 | { 20 | } 21 | 22 | unsigned long WIEGAND::getCode() 23 | { 24 | return _code; 25 | } 26 | 27 | int WIEGAND::getWiegandType() 28 | { 29 | return _wiegandType; 30 | } 31 | 32 | bool WIEGAND::available() 33 | { 34 | bool ret; 35 | noInterrupts(); 36 | ret=DoWiegandConversion(); 37 | interrupts(); 38 | return ret; 39 | } 40 | 41 | void WIEGAND::begin() 42 | { 43 | begin(2,3); 44 | } 45 | 46 | void WIEGAND::begin(int pinD0, int pinD1) 47 | { 48 | _lastWiegand = 0; 49 | _cardTempHigh = 0; 50 | _cardTemp = 0; 51 | _code = 0; 52 | _wiegandType = 0; 53 | _bitCount = 0; 54 | pinMode(pinD0, INPUT); // Set D0 pin as input 55 | pinMode(pinD1, INPUT); // Set D1 pin as input 56 | 57 | attachInterrupt(digitalPinToInterrupt(pinD0), ReadD0, FALLING); // Hardware interrupt - high to low pulse 58 | attachInterrupt(digitalPinToInterrupt(pinD1), ReadD1, FALLING); // Hardware interrupt - high to low pulse 59 | } 60 | 61 | INTERRUPT_ATTR void WIEGAND::ReadD0 () 62 | { 63 | _bitCount++; // Increament bit count for Interrupt connected to D0 64 | if (_bitCount>31) // If bit count more than 31, process high bits 65 | { 66 | _cardTempHigh |= ((0x80000000 & _cardTemp)>>31); // shift value to high bits 67 | _cardTempHigh <<= 1; 68 | _cardTemp <<=1; 69 | } 70 | else 71 | { 72 | _cardTemp <<= 1; // D0 represent binary 0, so just left shift card data 73 | } 74 | _lastWiegand = millis(); // Keep track of last wiegand bit received 75 | } 76 | 77 | INTERRUPT_ATTR void WIEGAND::ReadD1() 78 | { 79 | _bitCount ++; // Increment bit count for Interrupt connected to D1 80 | if (_bitCount>31) // If bit count more than 31, process high bits 81 | { 82 | _cardTempHigh |= ((0x80000000 & _cardTemp)>>31); // shift value to high bits 83 | _cardTempHigh <<= 1; 84 | _cardTemp |= 1; 85 | _cardTemp <<=1; 86 | } 87 | else 88 | { 89 | _cardTemp |= 1; // D1 represent binary 1, so OR card data with 1 then 90 | _cardTemp <<= 1; // left shift card data 91 | } 92 | _lastWiegand = millis(); // Keep track of last wiegand bit received 93 | } 94 | 95 | unsigned long WIEGAND::GetCardId (volatile unsigned long *codehigh, volatile unsigned long *codelow, char bitlength) 96 | { 97 | if (bitlength==26) // EM tag 98 | return (*codelow & 0x1FFFFFE) >>1; 99 | 100 | if (bitlength==24) 101 | return (*codelow & 0x7FFFFE) >>1; 102 | 103 | if (bitlength==34) // Mifare 104 | { 105 | *codehigh = *codehigh & 0x03; // only need the 2 LSB of the codehigh 106 | *codehigh <<= 30; // shift 2 LSB to MSB 107 | *codelow >>=1; 108 | return *codehigh | *codelow; 109 | } 110 | 111 | if (bitlength==32) { 112 | return (*codelow & 0x7FFFFFFE ) >>1; 113 | } 114 | 115 | return *codelow; // EM tag or Mifare without parity bits 116 | } 117 | 118 | char translateEnterEscapeKeyPress(char originalKeyPress) { 119 | switch(originalKeyPress) { 120 | case 0x0b: // 11 or * key 121 | return 0x0d; // 13 or ASCII ENTER 122 | 123 | case 0x0a: // 10 or # key 124 | return 0x1b; // 27 or ASCII ESCAPE 125 | 126 | default: 127 | return originalKeyPress; 128 | } 129 | } 130 | 131 | bool WIEGAND::DoWiegandConversion () 132 | { 133 | unsigned long cardID; 134 | unsigned long sysTick = millis(); 135 | 136 | if ((sysTick - _lastWiegand) > 25) // if no more signal coming through after 25ms 137 | { 138 | if ((_bitCount==24) || (_bitCount==26) || (_bitCount==32) || (_bitCount==34) || (_bitCount==8) || (_bitCount==4)) // bitCount for keypress=4 or 8, Wiegand 26=24 or 26, Wiegand 34=32 or 34 139 | { 140 | _cardTemp >>= 1; // shift right 1 bit to get back the real value - interrupt done 1 left shift in advance 141 | if (_bitCount>32) // bit count more than 32 bits, shift high bits right to make adjustment 142 | _cardTempHigh >>= 1; 143 | 144 | if (_bitCount==8) // keypress wiegand with integrity 145 | { 146 | // 8-bit Wiegand keyboard data, high nibble is the "NOT" of low nibble 147 | // eg if key 1 pressed, data=E1 in binary 11100001 , high nibble=1110 , low nibble = 0001 148 | char highNibble = (_cardTemp & 0xf0) >>4; 149 | char lowNibble = (_cardTemp & 0x0f); 150 | _wiegandType=_bitCount; 151 | _bitCount=0; 152 | _cardTemp=0; 153 | _cardTempHigh=0; 154 | 155 | if (lowNibble == (~highNibble & 0x0f)) // check if low nibble matches the "NOT" of high nibble. 156 | { 157 | _code = (int)translateEnterEscapeKeyPress(lowNibble); 158 | return true; 159 | } 160 | else { 161 | _lastWiegand=sysTick; 162 | _bitCount=0; 163 | _cardTemp=0; 164 | _cardTempHigh=0; 165 | return false; 166 | } 167 | 168 | // TODO: Handle validation failure case! 169 | } 170 | else if (4 == _bitCount) { 171 | // 4-bit Wiegand codes have no data integrity check so we just 172 | // read the LOW nibble. 173 | _code = (int)translateEnterEscapeKeyPress(_cardTemp & 0x0000000F); 174 | 175 | _wiegandType = _bitCount; 176 | _bitCount = 0; 177 | _cardTemp = 0; 178 | _cardTempHigh = 0; 179 | 180 | return true; 181 | } 182 | else // wiegand 26 or wiegand 34 183 | { 184 | cardID = GetCardId (&_cardTempHigh, &_cardTemp, _bitCount); 185 | _wiegandType=_bitCount; 186 | _bitCount=0; 187 | _cardTemp=0; 188 | _cardTempHigh=0; 189 | _code=cardID; 190 | return true; 191 | } 192 | } 193 | else 194 | { 195 | // well time over 25 ms and bitCount !=8 , !=26, !=34 , must be noise or nothing then. 196 | _lastWiegand=sysTick; 197 | _bitCount=0; 198 | _cardTemp=0; 199 | _cardTempHigh=0; 200 | return false; 201 | } 202 | } 203 | else 204 | return false; 205 | } 206 | -------------------------------------------------------------------------------- /src/Wiegand.h: -------------------------------------------------------------------------------- 1 | #ifndef _WIEGAND_H 2 | #define _WIEGAND_H 3 | 4 | #if defined(ARDUINO) && ARDUINO >= 100 5 | #include "Arduino.h" 6 | #else 7 | #include "WProgram.h" 8 | #endif 9 | 10 | class WIEGAND { 11 | 12 | public: 13 | WIEGAND(); 14 | void begin(); 15 | void begin(int pinD0, int pinD1); 16 | void begin(int pinD0, int pinIntD0, int pinD1, int pinIntD1); 17 | bool available(); 18 | unsigned long getCode(); 19 | int getWiegandType(); 20 | 21 | private: 22 | static void ReadD0(); 23 | static void ReadD1(); 24 | static bool DoWiegandConversion (); 25 | static unsigned long GetCardId (volatile unsigned long *codehigh, volatile unsigned long *codelow, char bitlength); 26 | 27 | static volatile unsigned long _cardTempHigh; 28 | static volatile unsigned long _cardTemp; 29 | static volatile unsigned long _lastWiegand; 30 | static volatile int _bitCount; 31 | static int _wiegandType; 32 | static unsigned long _code; 33 | }; 34 | 35 | #endif 36 | --------------------------------------------------------------------------------