mirror of https://github.com/arendst/Tasmota.git
fix #11047 Wiegand 26/34 missed some key press
This commit is contained in:
parent
b101657fba
commit
07f641c0b5
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue