|
|
@@ -0,0 +1,221 @@
|
|
|
+#include "wiegand.h"
|
|
|
+#include <furi.h>
|
|
|
+#include <api-hal.h>
|
|
|
+
|
|
|
+volatile unsigned long WIEGAND::_cardTempHigh = 0;
|
|
|
+volatile unsigned long WIEGAND::_cardTemp = 0;
|
|
|
+volatile unsigned long WIEGAND::_lastWiegand = 0;
|
|
|
+unsigned long WIEGAND::_code = 0;
|
|
|
+unsigned long WIEGAND::_codeHigh = 0;
|
|
|
+volatile int WIEGAND::_bitCount = 0;
|
|
|
+int WIEGAND::_wiegandType = 0;
|
|
|
+
|
|
|
+constexpr uint32_t clocks_in_ms = 64 * 1000;
|
|
|
+
|
|
|
+WIEGAND::WIEGAND() {
|
|
|
+}
|
|
|
+
|
|
|
+unsigned long WIEGAND::getCode() {
|
|
|
+ return _code;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned long WIEGAND::getCodeHigh() {
|
|
|
+ return _codeHigh;
|
|
|
+}
|
|
|
+
|
|
|
+int WIEGAND::getWiegandType() {
|
|
|
+ return _wiegandType;
|
|
|
+}
|
|
|
+
|
|
|
+bool WIEGAND::available() {
|
|
|
+ bool ret;
|
|
|
+ __disable_irq();
|
|
|
+ ret = DoWiegandConversion();
|
|
|
+ __enable_irq();
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+void input_isr(void* _pin, void* _ctx) {
|
|
|
+ // interrupt manager get us pin constant, so...
|
|
|
+ uint32_t pin = (uint32_t)_pin;
|
|
|
+ WIEGAND* _this = static_cast<WIEGAND*>(_ctx);
|
|
|
+
|
|
|
+ if(pin == ext_pa6_gpio.pin) {
|
|
|
+ _this->ReadD0();
|
|
|
+ }
|
|
|
+
|
|
|
+ if(pin == ext_pa7_gpio.pin) {
|
|
|
+ _this->ReadD1();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void WIEGAND::begin() {
|
|
|
+ _lastWiegand = 0;
|
|
|
+ _cardTempHigh = 0;
|
|
|
+ _cardTemp = 0;
|
|
|
+ _code = 0;
|
|
|
+ _wiegandType = 0;
|
|
|
+ _bitCount = 0;
|
|
|
+
|
|
|
+ const GpioPin* pinD0 = &ext_pa6_gpio;
|
|
|
+ const GpioPin* pinD1 = &ext_pa7_gpio;
|
|
|
+
|
|
|
+ gpio_init(pinD0, GpioModeInterruptFall); // Set D0 pin as input
|
|
|
+ gpio_init(pinD1, GpioModeInterruptFall); // Set D1 pin as input
|
|
|
+
|
|
|
+ api_interrupt_add(
|
|
|
+ input_isr, InterruptTypeExternalInterrupt, this); // Hardware interrupt - high to low pulse
|
|
|
+}
|
|
|
+
|
|
|
+void WIEGAND::ReadD0() {
|
|
|
+ _bitCount++; // Increament bit count for Interrupt connected to D0
|
|
|
+ if(_bitCount > 31) // If bit count more than 31, process high bits
|
|
|
+ {
|
|
|
+ _cardTempHigh |= ((0x80000000 & _cardTemp) >> 31); // shift value to high bits
|
|
|
+ _cardTempHigh <<= 1;
|
|
|
+ _cardTemp <<= 1;
|
|
|
+ } else {
|
|
|
+ _cardTemp <<= 1; // D0 represent binary 0, so just left shift card data
|
|
|
+ }
|
|
|
+ _lastWiegand = DWT->CYCCNT; // Keep track of last wiegand bit received
|
|
|
+}
|
|
|
+
|
|
|
+void WIEGAND::ReadD1() {
|
|
|
+ _bitCount++; // Increment bit count for Interrupt connected to D1
|
|
|
+ if(_bitCount > 31) // If bit count more than 31, process high bits
|
|
|
+ {
|
|
|
+ _cardTempHigh |= ((0x80000000 & _cardTemp) >> 31); // shift value to high bits
|
|
|
+ _cardTempHigh <<= 1;
|
|
|
+ _cardTemp |= 1;
|
|
|
+ _cardTemp <<= 1;
|
|
|
+ } else {
|
|
|
+ _cardTemp |= 1; // D1 represent binary 1, so OR card data with 1 then
|
|
|
+ _cardTemp <<= 1; // left shift card data
|
|
|
+ }
|
|
|
+ _lastWiegand = DWT->CYCCNT; // Keep track of last wiegand bit received
|
|
|
+}
|
|
|
+
|
|
|
+unsigned long WIEGAND::GetCardId(
|
|
|
+ volatile unsigned long* codehigh,
|
|
|
+ volatile unsigned long* codelow,
|
|
|
+ char bitlength) {
|
|
|
+ if(bitlength == 26) // EM tag
|
|
|
+ return (*codelow & 0x1FFFFFE) >> 1;
|
|
|
+
|
|
|
+ if(bitlength == 24) return (*codelow & 0x7FFFFE) >> 1;
|
|
|
+
|
|
|
+ if(bitlength == 34) // Mifare
|
|
|
+ {
|
|
|
+ *codehigh = *codehigh & 0x03; // only need the 2 LSB of the codehigh
|
|
|
+ *codehigh <<= 30; // shift 2 LSB to MSB
|
|
|
+ *codelow >>= 1;
|
|
|
+ return *codehigh | *codelow;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(bitlength == 32) {
|
|
|
+ return (*codelow & 0x7FFFFFFE) >> 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return *codelow; // EM tag or Mifare without parity bits
|
|
|
+}
|
|
|
+
|
|
|
+char translateEnterEscapeKeyPress(char originalKeyPress) {
|
|
|
+ switch(originalKeyPress) {
|
|
|
+ case 0x0b: // 11 or * key
|
|
|
+ return 0x0d; // 13 or ASCII ENTER
|
|
|
+
|
|
|
+ case 0x0a: // 10 or # key
|
|
|
+ return 0x1b; // 27 or ASCII ESCAPE
|
|
|
+
|
|
|
+ default:
|
|
|
+ return originalKeyPress;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool WIEGAND::DoWiegandConversion() {
|
|
|
+ unsigned long cardID;
|
|
|
+ unsigned long sysTick = DWT->CYCCNT;
|
|
|
+
|
|
|
+ if((sysTick - _lastWiegand) >
|
|
|
+ (25 * clocks_in_ms)) // if no more signal coming through after 25ms
|
|
|
+ {
|
|
|
+ if((_bitCount == 24) || (_bitCount == 26) || (_bitCount == 32) || (_bitCount == 34) ||
|
|
|
+ (_bitCount == 37) || (_bitCount == 40) || (_bitCount == 8) ||
|
|
|
+ (_bitCount ==
|
|
|
+ 4)) // bitCount for keypress=4 or 8, Wiegand 26=24 or 26, Wiegand 34=32 or 34
|
|
|
+ {
|
|
|
+ _codeHigh = 0;
|
|
|
+ // shift right 1 bit to get back the real value - interrupt done 1 left shift in advance
|
|
|
+ _cardTemp >>= 1;
|
|
|
+ // bit count more than 32 bits, shift high bits right to make adjustment
|
|
|
+ if(_bitCount > 32) _cardTempHigh >>= 1;
|
|
|
+
|
|
|
+ if(_bitCount == 8) // keypress wiegand with integrity
|
|
|
+ {
|
|
|
+ // 8-bit Wiegand keyboard data, high nibble is the "NOT" of low nibble
|
|
|
+ // eg if key 1 pressed, data=E1 in binary 11100001 , high nibble=1110 , low nibble = 0001
|
|
|
+ char highNibble = (_cardTemp & 0xf0) >> 4;
|
|
|
+ char lowNibble = (_cardTemp & 0x0f);
|
|
|
+ _wiegandType = _bitCount;
|
|
|
+ _bitCount = 0;
|
|
|
+ _cardTemp = 0;
|
|
|
+ _cardTempHigh = 0;
|
|
|
+
|
|
|
+ if(lowNibble ==
|
|
|
+ (~highNibble & 0x0f)) // check if low nibble matches the "NOT" of high nibble.
|
|
|
+ {
|
|
|
+ _code = (int)translateEnterEscapeKeyPress(lowNibble);
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ _lastWiegand = sysTick;
|
|
|
+ _bitCount = 0;
|
|
|
+ _cardTemp = 0;
|
|
|
+ _cardTempHigh = 0;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO: Handle validation failure case!
|
|
|
+ } else if(4 == _bitCount) {
|
|
|
+ // 4-bit Wiegand codes have no data integrity check so we just
|
|
|
+ // read the LOW nibble.
|
|
|
+ _code = (int)translateEnterEscapeKeyPress(_cardTemp & 0x0000000F);
|
|
|
+
|
|
|
+ _wiegandType = _bitCount;
|
|
|
+ _bitCount = 0;
|
|
|
+ _cardTemp = 0;
|
|
|
+ _cardTempHigh = 0;
|
|
|
+
|
|
|
+ return true;
|
|
|
+ } else if(40 == _bitCount) {
|
|
|
+ _cardTempHigh >>= 1;
|
|
|
+
|
|
|
+ _code = _cardTemp;
|
|
|
+ _codeHigh = _cardTempHigh;
|
|
|
+
|
|
|
+ _wiegandType = _bitCount;
|
|
|
+ _bitCount = 0;
|
|
|
+ _cardTemp = 0;
|
|
|
+ _cardTempHigh = 0;
|
|
|
+
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ // wiegand 26 or wiegand 34
|
|
|
+ cardID = GetCardId(&_cardTempHigh, &_cardTemp, _bitCount);
|
|
|
+ _wiegandType = _bitCount;
|
|
|
+ _bitCount = 0;
|
|
|
+ _cardTemp = 0;
|
|
|
+ _cardTempHigh = 0;
|
|
|
+ _code = cardID;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // well time over 25 ms and bitCount !=8 , !=26, !=34 , must be noise or nothing then.
|
|
|
+ _lastWiegand = sysTick;
|
|
|
+ _bitCount = 0;
|
|
|
+ _cardTemp = 0;
|
|
|
+ _cardTempHigh = 0;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else
|
|
|
+ return false;
|
|
|
+}
|