fix #11047 Wiegand 26/34 missed some key press

This commit is contained in:
sle 2021-03-10 12:42:30 +01:00
parent b101657fba
commit 07f641c0b5
1 changed files with 128 additions and 137 deletions

View File

@ -36,22 +36,27 @@
*
* Rule:
* on wiegand#uid=4302741608 do publish cmnd/ailight/power 2 endon
*
* contains:
* - fix for #11047 Wiegand 26/34 missed some key press if they are press at normal speed
* - removed testing code for tests without attached hardware
\*********************************************************************************************/
#warning **** Wiegand interface enabled ****
#define XSNS_82 82
#define WIEGAND_BIT_TIMEOUT 25 // Time in mSec to be wait after last bit detected.
#define WIEGAND_CODE_GAP_FACTOR 3 // Gap between 2 complete RFID codes send by the device. (WIEGAND_CODE_GAP_FACTOR * bitTime) to detect the end of a code
#define WIEGAND_BIT_TIME_DEFAULT 1250 // period time of one bit (impluse + impulse_gap time) 1250µs measured by oscilloscope on my RFID Reader
#define WIEGAND_RFID_ARRAY_SIZE 5 // storage of rfids found between 2 calls of FUNC_EVERY_100_MSECOND
// Use only a randomly generate RFID for testing. using #define will save some space in the final code
// DEV_WIEGAND_TEST_MODE 1 : testing with random rfid without hardware connected, but GPIOs set correctly
// using #define will save some space in the final code
// DEV_WIEGAND_TEST_MODE 2 : testing with hardware correctly connected.
#define DEV_WIEGAND_TEST_MODE 0
#ifdef DEV_WIEGAND_TEST_MODE
#if (DEV_WIEGAND_TEST_MODE==0)
#elif (DEV_WIEGAND_TEST_MODE==1)
#warning "Wiegand Interface compiled with 'DEV_WIEGAND_TEST_MODE' 1 (Random RFID)"
#warning "(no longer available) Wiegand Interface compiled with 'DEV_WIEGAND_TEST_MODE' 1 (Random RFID)"
#elif (DEV_WIEGAND_TEST_MODE==2)
#warning "Wiegand Interface compiled with 'DEV_WIEGAND_TEST_MODE' 2 (Hardware connected)"
#else
@ -59,6 +64,8 @@
#endif
#endif
typedef struct rfid_store { uint64_t RFID; uint16_t bitCount; } RFID_store;
class Wiegand {
public:
@ -70,17 +77,17 @@ class Wiegand {
#endif // USE_WEBSERVER
bool isInit = false;
uint8_t scanDelay;
private:
uint64_t HexStringToDec(uint64_t);
uint64_t CheckAndConvertRfid(uint64_t,uint16_t);
char translateEnterEscapeKeyPress(char);
uint8_t CalculateParities(uint64_t, int);
bool WiegandConversion (void);
//bool WiegandConversion (void);
bool WiegandConversion (uint64_t , uint16_t );
static void handleD0Interrupt(void);
static void handleD1Interrupt(void);
static void handleDxInterrupt(int in); // fix #11047
uint64_t rfid;
uint8_t tagSize;
@ -88,11 +95,14 @@ class Wiegand {
static volatile uint64_t rfidBuffer;
static volatile uint16_t bitCount;
static volatile uint32_t lastFoundTime;
static volatile uint8_t timeOut;
#if (DEV_WIEGAND_TEST_MODE)==1
uint64_t GetRandomRfid(uint8_t);
#endif // DEV_WIEGAND_TEST_MODE==1
// fix #11047
static volatile uint32_t bitTime;
static volatile uint32_t FirstBitTimeStamp;
static volatile uint32_t CodeGapTime;
static volatile bool CodeComplete;
static volatile RFID_store rfid_found[];
static volatile int currentFoundRFIDcount;
};
Wiegand* oWiegand = new Wiegand();
@ -100,7 +110,13 @@ Wiegand* oWiegand = new Wiegand();
volatile uint64_t Wiegand::rfidBuffer;
volatile uint16_t Wiegand::bitCount;
volatile uint32_t Wiegand::lastFoundTime;
volatile uint8_t Wiegand::timeOut;
// fix for #11047
volatile uint32_t Wiegand::bitTime;
volatile uint32_t Wiegand::FirstBitTimeStamp;
volatile uint32_t Wiegand::CodeGapTime;
volatile bool Wiegand::CodeComplete;
volatile RFID_store Wiegand::rfid_found[WIEGAND_RFID_ARRAY_SIZE];
volatile int Wiegand::currentFoundRFIDcount;
Wiegand::Wiegand() {
rfid = 0;
@ -108,73 +124,68 @@ Wiegand::Wiegand() {
tagSize = 0;
rfidBuffer = 0;
bitCount = 0 ;
timeOut = 0;
isInit = false;
scanDelay = 1;
}
#if (DEV_WIEGAND_TEST_MODE)==1
uint64_t Wiegand::GetRandomRfid(uint8_t tag_size=34) {
// Todo add support for 4 and 8 bit keyboard "tags"
uint64_t result = (uint32_t)HwRandom();
uint8_t parities = 0;
bitCount = tag_size;
timeOut = millis() - WIEGAND_BIT_TIMEOUT;
result = result << 32;
result += HwRandom();
switch (tag_size){
case 24:
result = (result & 0x7FFFFE) >>1;
break;
case 26:
result = (result & 0x1FFFFFE) >>1;
break;
case 32:
result = (result & 0x7FFFFFFE) >>1;
break;
case 34:
result = (result & 0x3FFFFFFFE) >>1;
break;
default:
break;
// fix #11047
bitTime = WIEGAND_BIT_TIME_DEFAULT;
FirstBitTimeStamp = 0;
CodeGapTime = WIEGAND_CODE_GAP_FACTOR * bitTime;
CodeComplete = false;
currentFoundRFIDcount=0;
for (int i=0; i < WIEGAND_RFID_ARRAY_SIZE; i++ )
{
rfid_found[i].RFID=0;
rfid_found[i].bitCount=0;
}
parities = CalculateParities(result, tag_size);
result = (result << 1) | (parities & 0x01); // Set LSB parity
if (parities & 0x80) { // MSB parity is 1
switch (tag_size) {
case 24:
result |= 0x800000;
break;
case 26:
result |= 0x2000000;
break;
case 32:
result |= 0x80000000;
break;
case 34:
result |= 0x400000000;
break;
default:
break;
}
}
return result;
}
#endif // DEV_WIEGAND_TEST_MODE==1
void ICACHE_RAM_ATTR Wiegand::handleD1Interrupt() { // Receive a 1 bit. (D0=high & D1=low)
rfidBuffer = (rfidBuffer << 1) | 1; // Leftshift + 1 bit
bitCount++; // Increment the counter
lastFoundTime = millis(); // Last time bit found
handleDxInterrupt(1);
}
void ICACHE_RAM_ATTR Wiegand::handleD0Interrupt() { // Receive a 0 bit. (D0=low & D1=high)
rfidBuffer = rfidBuffer << 1; // Leftshift the 0 bit is now at the end of rfidBuffer
bitCount++; // Increment the counter
lastFoundTime = millis(); // Last time bit found
handleDxInterrupt(0);
}
void ICACHE_RAM_ATTR Wiegand::handleDxInterrupt(int in) {
unsigned long curTime = micros(); // to be sure I will use micros() instead of millis() overflow is handle by using the minus operator to compare
unsigned long diffTime= curTime - lastFoundTime;
if (diffTime > 3000000 ) { //cancel noisy bits in buffer and start a new tag
rfidBuffer = 0;
bitCount = 0;
FirstBitTimeStamp = 0;
}
if ( (diffTime > CodeGapTime) && (bitCount > 0)) {
// previous RFID tag (key pad numer)is complete. Will be detected by the code ending gap
// one bit will take the time of impulse_time + impulse_gap_time. it (bitTime) will be recalculated each time an impulse is detected
// the devices will add some inter_code_gap_time to separate codes this will be much longer than the bit_time. (WIEGAND_CODE_GAP_FACTOR)
// unfortunately there's no timing defined for Wiegang. On my test reader the impulse time = 125 µs impulse gap time = 950 µs.
if (currentFoundRFIDcount < WIEGAND_RFID_ARRAY_SIZE) { // when reaching the end of rfid buffer we will overwrite the last one.
currentFoundRFIDcount++;
}
// start a new tag
rfidBuffer = 0;
bitCount = 0;
FirstBitTimeStamp = 0;
}
if (in ==3) {// called by ScanForTag to get the last tag, because the interrupt handler is no longer called after receiving the last bit
return;
}
if (in == 0) { rfidBuffer = rfidBuffer << 1; } // Receive a 0 bit. (D0=low & D1=high): Leftshift the 0 bit is now at the end of rfidBuffer
else {rfidBuffer = (rfidBuffer << 1) | 1; } // Receive a 1 bit. (D0=high & D1=low): Leftshift + 1 bit
bitCount++;
if (bitCount == 1) { // first bit was detected
FirstBitTimeStamp = (curTime != 0) ? curTime : 1; // accept 1µs differenct to avoid a miss the first timestamp if curTime is 0.
}
else if (bitCount == 2) { // only calculate once per RFID tag
bitTime = diffTime; //calc maximum current length of one bit
CodeGapTime = WIEGAND_CODE_GAP_FACTOR * bitTime;
}
//save current rfid in array otherwise we will never see the last found tag
rfid_found[currentFoundRFIDcount].RFID=rfidBuffer;
rfid_found[currentFoundRFIDcount].bitCount= bitCount;
lastFoundTime = curTime; // Last time a bit was detected
}
void Wiegand::Init() {
@ -201,11 +212,11 @@ void Wiegand::Init() {
#endif // DEV_WIEGAND_TEST_MODE>0
}
uint64_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitcount) {
uint64_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitCount) {
uint8_t evenParityBit = 0;
uint8_t oddParityBit = (uint8_t) (rfidIn & 0x1); // Last bit = odd parity
uint8_t calcParity = 0;
switch (bitcount) {
switch (bitCount) {
case 24:
evenParityBit = (rfidIn & 0x800000) ? 0x80 : 0;
rfidIn = (rfidIn & 0x7FFFFE) >>1;
@ -282,18 +293,14 @@ char Wiegand::translateEnterEscapeKeyPress(char oKeyPressed) {
}
}
bool Wiegand::WiegandConversion () {
bool Wiegand::WiegandConversion (uint64_t rfidBuffer, uint16_t bitCount) {
bool bRet = false;
unsigned long nowTick = millis();
// unsigned long nowTick = micros();
// Add a maximum wait time for new bits
unsigned long diffTicks = nowTick - lastFoundTime;
if ((diffTicks > WIEGAND_BIT_TIMEOUT) && (diffTicks >= 5000 )) { // Max. 5 secs between 2 bits comming in
bitCount = 0;
rfidBuffer = 0;
lastFoundTime = nowTick;
return bRet;
}
if (diffTicks > WIEGAND_BIT_TIMEOUT) { // Last bit found is WIEGAND_BIT_TIMEOUT ms ago
// unsigned long diffTicks = nowTick - lastFoundTime;
// unsigned long inter_code_gap = WIEGAND_CODE_GAP_FACTOR * bitTime;
// if ((diffTicks > inter_code_gap) && (diffTicks >= 1000000 )) { // Max. 4-8 secs between 2 bits comming in. depends on micros() resolution
#if (DEV_WIEGAND_TEST_MODE)>0
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Raw tag %llu, Bit count %u"), rfidBuffer, bitCount);
#endif // DEV_WIEGAND_TEST_MODE>0
@ -319,20 +326,15 @@ bool Wiegand::WiegandConversion () {
rfid = (int)translateEnterEscapeKeyPress(lowNibble);
bRet = true;
} else {
lastFoundTime = nowTick;
// lastFoundTime = nowTick;
bRet = false;
}
tagSize = bitCount;
} else {
// Time reached but unknown bitCount, clear and start again
lastFoundTime = nowTick;
// lastFoundTime = nowTick;
bRet = false;
}
bitCount = 0;
rfidBuffer = 0;
} else {
bRet = false; // Watching time not finished
}
#if (DEV_WIEGAND_TEST_MODE)>0
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag out %llu, tag size %u "), rfid, tagSize);
#endif // DEV_WIEGAND_TEST_MODE>0
@ -340,43 +342,42 @@ bool Wiegand::WiegandConversion () {
}
void Wiegand::ScanForTag() {
#if (DEV_WIEGAND_TEST_MODE)>0
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag()."));
#if (DEV_WIEGAND_TEST_MODE==1)
switch (millis() %4) {
case 0:
rfidBuffer = GetRandomRfid(24);
break;
case 1:
rfidBuffer = GetRandomRfid(26);
break;
case 2:
rfidBuffer = GetRandomRfid(32);
break;
case 3:
rfidBuffer = GetRandomRfid(34);
break;
default:
rfidBuffer = GetRandomRfid(34);
break;
}
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Raw generated %lX"), rfidBuffer); // For tests without reader attaiched
#endif // DEV_WIEGAND_TEST_MODE==1
#endif // DEV_WIEGAND_TEST_MODE>0
if (bitCount > 0) {
uint64_t oldTag = rfid;
bool validKey = WiegandConversion();
#if (DEV_WIEGAND_TEST_MODE)>0
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Previous tag %llu"), oldTag);
#endif // DEV_WIEGAND_TEST_MODE>0
if (validKey) { // Only in case of valid key do action. Issue#10585
if (oldTag == rfid) {
AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: Old tag"));
unsigned long startTime = micros();
handleDxInterrupt(3);
if (currentFoundRFIDcount > 0) {
unsigned int lastFoundRFIDcount = currentFoundRFIDcount;
#if (DEV_WIEGAND_TEST_MODE)>0
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag(). bitTime: %0lu lastFoundTime: %0lu RFIDS in buffer: %lu"), bitTime, lastFoundTime, currentFoundRFIDcount);
#endif
for (int i= 0; i < WIEGAND_RFID_ARRAY_SIZE; i++)
{
if (rfid_found[i].RFID != 0) {
uint64_t oldTag = rfid;
bool validKey = WiegandConversion(rfid_found[i].RFID, rfid_found[i].bitCount);
#if (DEV_WIEGAND_TEST_MODE)>0
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Previous tag %llu"), oldTag);
#endif // DEV_WIEGAND_TEST_MODE>0
if (validKey) { // Only in case of valid key do action. Issue#10585
if (oldTag == rfid) {
AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: Old tag"));
}
ResponseTime_P(PSTR(",\"Wiegand\":{\"UID\":%0llu,\"" D_JSON_SIZE "\":%u}}"), rfid,tagSize);
MqttPublishTeleSensor();
}
rfid_found[i].RFID=0;
rfid_found[i].bitCount=0;
}
ResponseTime_P(PSTR(",\"Wiegand\":{\"UID\":%0llu,\"" D_JSON_SIZE "\":%u}}"), rfid, tagSize);
MqttPublishTeleSensor();
}
if (currentFoundRFIDcount > lastFoundRFIDcount) {
// if that happens: we need to move the id found during the loop to top of the array
// and correct the currentFoundRFIDcount
}
currentFoundRFIDcount=0; //reset array
#if (DEV_WIEGAND_TEST_MODE)>0
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() time elapsed %lu"), (micros() - startTime));
#endif
}
}
#ifdef USE_WEBSERVER
@ -400,18 +401,8 @@ bool Xsns82(byte function) {
}
else if (oWiegand->isInit) {
switch (function) {
case FUNC_EVERY_250_MSECOND: // Some tags need more time, don't try shorter period
#if (DEV_WIEGAND_TEST_MODE)==1
if (oWiegand->scanDelay >= 4) // Give a second because of the log entries to be send.
#else
if (oWiegand->scanDelay >= 2) // Only run every (delay * 250 ms) (every 250ms is too fast for some tags)
#endif
{
oWiegand->ScanForTag();
oWiegand->scanDelay = 1;
} else {
oWiegand->scanDelay++;
}
case FUNC_EVERY_100_MSECOND: // fix for #11047 Wiegand 26/34 missed some key press
oWiegand->ScanForTag();
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR: