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

View File

@ -36,22 +36,27 @@
* *
* Rule: * Rule:
* on wiegand#uid=4302741608 do publish cmnd/ailight/power 2 endon * 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 **** #warning **** Wiegand interface enabled ****
#define XSNS_82 82 #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 // 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
// DEV_WIEGAND_TEST_MODE 2 : testing with hardware correctly connected. // DEV_WIEGAND_TEST_MODE 2 : testing with hardware correctly connected.
#define DEV_WIEGAND_TEST_MODE 0 #define DEV_WIEGAND_TEST_MODE 0
#ifdef DEV_WIEGAND_TEST_MODE #ifdef DEV_WIEGAND_TEST_MODE
#if (DEV_WIEGAND_TEST_MODE==0) #if (DEV_WIEGAND_TEST_MODE==0)
#elif (DEV_WIEGAND_TEST_MODE==1) #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) #elif (DEV_WIEGAND_TEST_MODE==2)
#warning "Wiegand Interface compiled with 'DEV_WIEGAND_TEST_MODE' 2 (Hardware connected)" #warning "Wiegand Interface compiled with 'DEV_WIEGAND_TEST_MODE' 2 (Hardware connected)"
#else #else
@ -59,6 +64,8 @@
#endif #endif
#endif #endif
typedef struct rfid_store { uint64_t RFID; uint16_t bitCount; } RFID_store;
class Wiegand { class Wiegand {
public: public:
@ -70,17 +77,17 @@ class Wiegand {
#endif // USE_WEBSERVER #endif // USE_WEBSERVER
bool isInit = false; bool isInit = false;
uint8_t scanDelay;
private: private:
uint64_t HexStringToDec(uint64_t); uint64_t HexStringToDec(uint64_t);
uint64_t CheckAndConvertRfid(uint64_t,uint16_t); uint64_t CheckAndConvertRfid(uint64_t,uint16_t);
char translateEnterEscapeKeyPress(char); char translateEnterEscapeKeyPress(char);
uint8_t CalculateParities(uint64_t, int); uint8_t CalculateParities(uint64_t, int);
bool WiegandConversion (void); //bool WiegandConversion (void);
bool WiegandConversion (uint64_t , uint16_t );
static void handleD0Interrupt(void); static void handleD0Interrupt(void);
static void handleD1Interrupt(void); static void handleD1Interrupt(void);
static void handleDxInterrupt(int in); // fix #11047
uint64_t rfid; uint64_t rfid;
uint8_t tagSize; uint8_t tagSize;
@ -88,11 +95,14 @@ class Wiegand {
static volatile uint64_t rfidBuffer; static volatile uint64_t rfidBuffer;
static volatile uint16_t bitCount; static volatile uint16_t bitCount;
static volatile uint32_t lastFoundTime; static volatile uint32_t lastFoundTime;
static volatile uint8_t timeOut; // fix #11047
static volatile uint32_t bitTime;
#if (DEV_WIEGAND_TEST_MODE)==1 static volatile uint32_t FirstBitTimeStamp;
uint64_t GetRandomRfid(uint8_t); static volatile uint32_t CodeGapTime;
#endif // DEV_WIEGAND_TEST_MODE==1 static volatile bool CodeComplete;
static volatile RFID_store rfid_found[];
static volatile int currentFoundRFIDcount;
}; };
Wiegand* oWiegand = new Wiegand(); Wiegand* oWiegand = new Wiegand();
@ -100,7 +110,13 @@ Wiegand* oWiegand = new Wiegand();
volatile uint64_t Wiegand::rfidBuffer; volatile uint64_t Wiegand::rfidBuffer;
volatile uint16_t Wiegand::bitCount; volatile uint16_t Wiegand::bitCount;
volatile uint32_t Wiegand::lastFoundTime; 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() { Wiegand::Wiegand() {
rfid = 0; rfid = 0;
@ -108,73 +124,68 @@ Wiegand::Wiegand() {
tagSize = 0; tagSize = 0;
rfidBuffer = 0; rfidBuffer = 0;
bitCount = 0 ; bitCount = 0 ;
timeOut = 0;
isInit = false; isInit = false;
scanDelay = 1; // fix #11047
} bitTime = WIEGAND_BIT_TIME_DEFAULT;
FirstBitTimeStamp = 0;
#if (DEV_WIEGAND_TEST_MODE)==1 CodeGapTime = WIEGAND_CODE_GAP_FACTOR * bitTime;
uint64_t Wiegand::GetRandomRfid(uint8_t tag_size=34) { CodeComplete = false;
// Todo add support for 4 and 8 bit keyboard "tags" currentFoundRFIDcount=0;
uint64_t result = (uint32_t)HwRandom(); for (int i=0; i < WIEGAND_RFID_ARRAY_SIZE; i++ )
uint8_t parities = 0; {
bitCount = tag_size; rfid_found[i].RFID=0;
timeOut = millis() - WIEGAND_BIT_TIMEOUT; rfid_found[i].bitCount=0;
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;
} }
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) void ICACHE_RAM_ATTR Wiegand::handleD1Interrupt() { // Receive a 1 bit. (D0=high & D1=low)
rfidBuffer = (rfidBuffer << 1) | 1; // Leftshift + 1 bit handleDxInterrupt(1);
bitCount++; // Increment the counter
lastFoundTime = millis(); // Last time bit found
} }
void ICACHE_RAM_ATTR Wiegand::handleD0Interrupt() { // Receive a 0 bit. (D0=low & D1=high) 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 handleDxInterrupt(0);
bitCount++; // Increment the counter }
lastFoundTime = millis(); // Last time bit found
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() { void Wiegand::Init() {
@ -201,11 +212,11 @@ void Wiegand::Init() {
#endif // DEV_WIEGAND_TEST_MODE>0 #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 evenParityBit = 0;
uint8_t oddParityBit = (uint8_t) (rfidIn & 0x1); // Last bit = odd parity uint8_t oddParityBit = (uint8_t) (rfidIn & 0x1); // Last bit = odd parity
uint8_t calcParity = 0; uint8_t calcParity = 0;
switch (bitcount) { switch (bitCount) {
case 24: case 24:
evenParityBit = (rfidIn & 0x800000) ? 0x80 : 0; evenParityBit = (rfidIn & 0x800000) ? 0x80 : 0;
rfidIn = (rfidIn & 0x7FFFFE) >>1; 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; bool bRet = false;
unsigned long nowTick = millis(); // unsigned long nowTick = micros();
// Add a maximum wait time for new bits // Add a maximum wait time for new bits
unsigned long diffTicks = nowTick - lastFoundTime; // unsigned long diffTicks = nowTick - lastFoundTime;
if ((diffTicks > WIEGAND_BIT_TIMEOUT) && (diffTicks >= 5000 )) { // Max. 5 secs between 2 bits comming in // unsigned long inter_code_gap = WIEGAND_CODE_GAP_FACTOR * bitTime;
bitCount = 0; // if ((diffTicks > inter_code_gap) && (diffTicks >= 1000000 )) { // Max. 4-8 secs between 2 bits comming in. depends on micros() resolution
rfidBuffer = 0;
lastFoundTime = nowTick;
return bRet;
}
if (diffTicks > WIEGAND_BIT_TIMEOUT) { // Last bit found is WIEGAND_BIT_TIMEOUT ms ago
#if (DEV_WIEGAND_TEST_MODE)>0 #if (DEV_WIEGAND_TEST_MODE)>0
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Raw tag %llu, Bit count %u"), rfidBuffer, bitCount); AddLog(LOG_LEVEL_INFO, PSTR("WIE: Raw tag %llu, Bit count %u"), rfidBuffer, bitCount);
#endif // DEV_WIEGAND_TEST_MODE>0 #endif // DEV_WIEGAND_TEST_MODE>0
@ -319,20 +326,15 @@ bool Wiegand::WiegandConversion () {
rfid = (int)translateEnterEscapeKeyPress(lowNibble); rfid = (int)translateEnterEscapeKeyPress(lowNibble);
bRet = true; bRet = true;
} else { } else {
lastFoundTime = nowTick; // lastFoundTime = nowTick;
bRet = false; bRet = false;
} }
tagSize = bitCount; tagSize = bitCount;
} else { } else {
// Time reached but unknown bitCount, clear and start again // Time reached but unknown bitCount, clear and start again
lastFoundTime = nowTick; // lastFoundTime = nowTick;
bRet = false; bRet = false;
} }
bitCount = 0;
rfidBuffer = 0;
} else {
bRet = false; // Watching time not finished
}
#if (DEV_WIEGAND_TEST_MODE)>0 #if (DEV_WIEGAND_TEST_MODE)>0
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag out %llu, tag size %u "), rfid, tagSize); AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag out %llu, tag size %u "), rfid, tagSize);
#endif // DEV_WIEGAND_TEST_MODE>0 #endif // DEV_WIEGAND_TEST_MODE>0
@ -340,43 +342,42 @@ bool Wiegand::WiegandConversion () {
} }
void Wiegand::ScanForTag() { void Wiegand::ScanForTag() {
#if (DEV_WIEGAND_TEST_MODE)>0 unsigned long startTime = micros();
AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag().")); handleDxInterrupt(3);
#if (DEV_WIEGAND_TEST_MODE==1) if (currentFoundRFIDcount > 0) {
switch (millis() %4) { unsigned int lastFoundRFIDcount = currentFoundRFIDcount;
case 0: #if (DEV_WIEGAND_TEST_MODE)>0
rfidBuffer = GetRandomRfid(24); AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag(). bitTime: %0lu lastFoundTime: %0lu RFIDS in buffer: %lu"), bitTime, lastFoundTime, currentFoundRFIDcount);
break; #endif
case 1: for (int i= 0; i < WIEGAND_RFID_ARRAY_SIZE; i++)
rfidBuffer = GetRandomRfid(26); {
break; if (rfid_found[i].RFID != 0) {
case 2: uint64_t oldTag = rfid;
rfidBuffer = GetRandomRfid(32); bool validKey = WiegandConversion(rfid_found[i].RFID, rfid_found[i].bitCount);
break; #if (DEV_WIEGAND_TEST_MODE)>0
case 3: AddLog(LOG_LEVEL_INFO, PSTR("WIE: Previous tag %llu"), oldTag);
rfidBuffer = GetRandomRfid(34); #endif // DEV_WIEGAND_TEST_MODE>0
break; if (validKey) { // Only in case of valid key do action. Issue#10585
default: if (oldTag == rfid) {
rfidBuffer = GetRandomRfid(34); AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: Old tag"));
break; }
} ResponseTime_P(PSTR(",\"Wiegand\":{\"UID\":%0llu,\"" D_JSON_SIZE "\":%u}}"), rfid,tagSize);
AddLog(LOG_LEVEL_INFO, PSTR("WIE: Raw generated %lX"), rfidBuffer); // For tests without reader attaiched MqttPublishTeleSensor();
#endif // DEV_WIEGAND_TEST_MODE==1 }
#endif // DEV_WIEGAND_TEST_MODE>0 rfid_found[i].RFID=0;
if (bitCount > 0) { rfid_found[i].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"));
} }
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 #ifdef USE_WEBSERVER
@ -400,18 +401,8 @@ bool Xsns82(byte function) {
} }
else if (oWiegand->isInit) { else if (oWiegand->isInit) {
switch (function) { switch (function) {
case FUNC_EVERY_250_MSECOND: // Some tags need more time, don't try shorter period case FUNC_EVERY_100_MSECOND: // fix for #11047 Wiegand 26/34 missed some key press
#if (DEV_WIEGAND_TEST_MODE)==1 oWiegand->ScanForTag();
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++;
}
break; break;
#ifdef USE_WEBSERVER #ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR: case FUNC_WEB_SENSOR: