unleashed-firmware/applications/accessor/helpers/wiegand.cpp
SG 46bc515c6a
Low frequency RFID app [Read stage] (#385)
* App Lfrfid: init
* HAL-resources: add external gpios
* HAL-pwm: fix frequency calculation
* App LFRFID: generic manchester decoder
* App LFRFID: em-marine decoder
* App iButton: fix dwt timing acquire
* App LFRFID: rfid reader
* App LFRFID: temporary read keys on read scene
* App LFRFID: remove atomic bool init.
* App LFRFID: add *.c to build
* App LFRFID: unstable HID decoder
* App LFRFID: HID-26 reading
* HAL OS: disable sleep
* App LFRFID: HID-26 reader: remove debug
* App LFRFID: static data decoder-analyzer
* App LFRFID: very raw Indala decoder
* App LFRFID: multiprotocol reader
* App LFRFID: more reliable HID decoder
* App LFRFID: syntax fix
* App LFRFID: simple read scene
* Gui: force redraw on screen stream connect
* HAL-OS: allow sleep
* App LFRFID: notify api, tune view, tune scene
* App LFRFID: simple rfid emulator
* App LFRFID: more scenes, more reliable EM decoder.
* App LFRFID: format fix
* App LFRFID: warning fix
* Api-hal-resources: add rfid pins, rename external pins
* App LFRFID: remove unused emulator
* App LFRFID: use new gpio hal api
* App accessor: use new ext gpio name
* App LFRFID: remove unused emulator
* App LFRFID: remove debug gpio
* Api-hal-resources: alternate functions init
* Api-hal-rfid: new api
* Api-hal-ibutton: new api
* Api-hal: new headers
* App LFRFID: use new api in reader subroutines
* App LFRFID: use new api in emulator subroutines
* App LFRFID: remove old app
* App LFRFID, App iButton: fix memleak
* Api-hal-rfid: comments
* App LFRFID: pulse joiner helper, it combines pulses of different polarity into one pulse suitable for a timer
* App LFRFID: pulse joiner, now can accept only ne pulse
* App LFRFID: pulse joiner, fixes
* App LFRFID: EM encoder and emulation
* App LFRFID: format fixes
* App LFRFID: emmarine encoder cleanup
* App LFRFID: HID Encoder blank
* App LFRFID: Indala Encoder blank
2021-05-04 16:21:16 +03:00

221 lines
6.7 KiB
C++

#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 == gpio_ext_pa6.pin) {
_this->ReadD0();
}
if(pin == gpio_ext_pa7.pin) {
_this->ReadD1();
}
}
void WIEGAND::begin() {
_lastWiegand = 0;
_cardTempHigh = 0;
_cardTemp = 0;
_code = 0;
_wiegandType = 0;
_bitCount = 0;
const GpioPin* pinD0 = &gpio_ext_pa6;
const GpioPin* pinD1 = &gpio_ext_pa7;
hal_gpio_init(pinD0, GpioModeInterruptFall, GpioPullNo, GpioSpeedLow); // Set D0 pin as input
hal_gpio_init(pinD1, GpioModeInterruptFall, GpioPullNo, GpioSpeedLow); // 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;
}