From 4566aaee05b1750e47601dd457fd777f90b306f5 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 15 Feb 2022 17:52:45 +0100 Subject: [PATCH] Refactor wiegand to 32-bit Refactor wiegand from 64-bit to 32-bit while keeping full 34-bit support --- tasmota/xsns_82_wiegand.ino | 184 ++++++++++++++++-------------------- 1 file changed, 84 insertions(+), 100 deletions(-) diff --git a/tasmota/xsns_82_wiegand.ino b/tasmota/xsns_82_wiegand.ino index 5aaa22d4f..9908e7a55 100644 --- a/tasmota/xsns_82_wiegand.ino +++ b/tasmota/xsns_82_wiegand.ino @@ -40,6 +40,8 @@ * 20220215 * - fix 34-bit size parity chk * - fix 64-bit representation after removal of %llu support (Tasmota does not support 64-bit decimal output specifier (%llu) saving 60k code) + * - change internal rfid size from uint64_t to uint32_t + * - limited max amount of kaypad presses to a 32-bit number (at least 999999999) * --- * 20201101 * - fix for #11047 Wiegand 26/34 missed some key press if they are press at normal speed @@ -106,23 +108,21 @@ class Wiegand { #if (DEV_WIEGAND_TEST_MODE!=1) private: #endif //(DEV_WIEGAND_TEST_MODE==1) - uint64_t CheckAndConvertRfid(uint64_t,uint16_t); + uint32_t CheckAndConvertRfid(uint64_t,uint16_t); uint8_t CalculateParities(uint64_t, int); bool WiegandConversion (uint64_t , uint16_t ); - void setOutputFormat(void); // fix output HEX format void HandleKeyPad(void); //handle one tag for multi key strokes - static void handleD0Interrupt(void); static void handleD1Interrupt(void); static void handleDxInterrupt(int in); // fix #11047 static void ClearRFIDBuffer(int); - uint64_t rfid; + uint32_t rfid; uint32_t tagSize; const char* outFormat; - uint64_t mqttRFIDKeypadBuffer; - uint64_t webRFIDKeypadBuffer; + uint32_t mqttRFIDKeypadBuffer; + uint32_t webRFIDKeypadBuffer; static volatile uint64_t rfidBuffer; static volatile uint16_t bitCount; @@ -149,15 +149,14 @@ volatile bool Wiegand::CodeComplete; volatile RFID_store Wiegand::rfid_found[WIEGAND_RFID_ARRAY_SIZE]; volatile int Wiegand::currentFoundRFIDcount; - - void IRAM_ATTR Wiegand::ClearRFIDBuffer(int endIndex = WIEGAND_RFID_ARRAY_SIZE) { - currentFoundRFIDcount=WIEGAND_RFID_ARRAY_SIZE-endIndex; // clear all buffers - for (int i= 0; i < endIndex; i++) { - rfid_found[i].RFID=0; - rfid_found[i].bitCount=0; - } + currentFoundRFIDcount = WIEGAND_RFID_ARRAY_SIZE - endIndex; // clear all buffers + for (uint32_t i = 0; i < endIndex; i++) { + rfid_found[i].RFID=0; + rfid_found[i].bitCount=0; + } } + void IRAM_ATTR Wiegand::handleD1Interrupt() { // Receive a 1 bit. (D0=high & D1=low) handleDxInterrupt(1); } @@ -167,9 +166,9 @@ void IRAM_ATTR Wiegand::handleD0Interrupt() { // Receive a 0 bit. (D0=low & D1= } void IRAM_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 > CodeGapTime) && (bitCount > 0)) { + uint32_t curTime = micros(); // to be sure I will use micros() instead of millis() overflow is handle by using the minus operator to compare + uint32_t diffTime = curTime - lastFoundTime; + 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) @@ -192,7 +191,7 @@ void IRAM_ATTR Wiegand::handleDxInterrupt(int in) { 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, but restrict to values, which are in within a plausible range - bitTime = ((diffTime > (WIEGAND_BIT_TIME_DEFAULT/4)) && (diffTime < (4*WIEGAND_BIT_TIME_DEFAULT))) ? diffTime : WIEGAND_BIT_TIME_DEFAULT; + bitTime = ((diffTime > (WIEGAND_BIT_TIME_DEFAULT / 4)) && (diffTime < (4 * WIEGAND_BIT_TIME_DEFAULT))) ? diffTime : WIEGAND_BIT_TIME_DEFAULT; CodeGapTime = WIEGAND_CODE_GAP_FACTOR * bitTime; } //save current rfid in array otherwise we will never see the last found tag @@ -247,7 +246,7 @@ void Wiegand::Init() { #endif // DEV_WIEGAND_TEST_MODE>0 } -uint64_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitCount) { +uint32_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; @@ -277,8 +276,8 @@ uint64_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitCount) { } calcParity = CalculateParities(rfidIn, bitCount); // Check result on http://www.ccdesignworks.com/wiegand_calc.htm with raw tag as input if (calcParity != (evenParityBit | oddParityBit)) { // Parity bit is wrong + AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: %_X parity error"), &rfidIn); // Print up to uint64_t rfidIn=0; - AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: %_X parity error"), &rfidIn); } #if (DEV_WIEGAND_TEST_MODE)>0 AddLog(LOG_LEVEL_INFO, PSTR("WIE: even (left) parity: %u "), (evenParityBit>>7)); @@ -286,10 +285,10 @@ uint64_t Wiegand::CheckAndConvertRfid(uint64_t rfidIn, uint16_t bitCount) { AddLog(LOG_LEVEL_INFO, PSTR("WIE: odd (right) parity: %u "), oddParityBit); AddLog(LOG_LEVEL_INFO, PSTR("WIE: odd (calc) parity: %u "), (calcParity & 0x01)); #endif // DEV_WIEGAND_TEST_MODE>0 - return rfidIn; + return (uint32_t)rfidIn; } -uint8_t Wiegand::CalculateParities(uint64_t tagWithoutParities, int tag_size=26) { +uint8_t Wiegand::CalculateParities(uint64_t tagWithoutParities, int tag_size = 26) { // tag_size is the size of the final tag including the 2 parity bits // So length if the tagWithoutParities should be (tag_size-2) !! That will be not profed and // lead to wrong results if the input value is larger! @@ -299,7 +298,7 @@ uint8_t Wiegand::CalculateParities(uint64_t tagWithoutParities, int tag_size=26) tag_size -= 2; if (tag_size <= 0) { return retValue; } // Prohibit div zero exception and other wrong inputs uint8_t parity = 1; // Check for odd parity on LSB - for (uint8_t i = 0; i < (tag_size / 2); i++) { + for (uint32_t i = 0; i < (tag_size / 2); i++) { parity ^= (tagWithoutParities & 1); tagWithoutParities >>= 1; } @@ -318,53 +317,47 @@ uint8_t Wiegand::CalculateParities(uint64_t tagWithoutParities, int tag_size=26) bool Wiegand::WiegandConversion (uint64_t rfidBuffer, uint16_t bitCount) { bool bRet = false; #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 %_X, Bit count %u"), &rfidBuffer, bitCount); // Print up to uint64_t #endif // DEV_WIEGAND_TEST_MODE>0 - if ((24 == bitCount) || (26 == bitCount) || (32 == bitCount) || (34 == bitCount)) { - // 24, 26, 32, 34-bit Wiegand codes - rfid = CheckAndConvertRfid(rfidBuffer, bitCount); - tagSize = bitCount; + if ((24 == bitCount) || (26 == bitCount) || (32 == bitCount) || (34 == bitCount)) { + // 24, 26, 32, 34-bit Wiegand codes + rfid = CheckAndConvertRfid(rfidBuffer, bitCount); + tagSize = bitCount; + bRet = true; + } + else if (4 == bitCount) { + // 4-bit Wiegand codes for keypads + rfid = (uint32_t)(rfidBuffer & 0x0000000F); + tagSize = bitCount; + bRet = true; + } + else if (8 == bitCount) { + // 8-bit Wiegand codes for keypads 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 = (rfidBuffer & 0xf0) >>4; + char lowNibble = (rfidBuffer & 0x0f); + if (lowNibble == (~highNibble & 0x0f)) { // Check if low nibble matches the "NOT" of high nibble. + rfid = (uint32_t)(lowNibble); bRet = true; - } - else if (4 == bitCount) { - // 4-bit Wiegand codes for keypads - rfid = (int)(rfidBuffer & 0x0000000F); - tagSize = bitCount; - bRet = true; - } - else if (8 == bitCount) { - // 8-bit Wiegand codes for keypads 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 = (rfidBuffer & 0xf0) >>4; - char lowNibble = (rfidBuffer & 0x0f); - if (lowNibble == (~highNibble & 0x0f)) { // Check if low nibble matches the "NOT" of high nibble. - rfid = (int)(lowNibble); - bRet = true; - } else { - bRet = false; - } - tagSize = bitCount; } else { - // Time reached but unknown bitCount, clear and start again - tagSize = 0; bRet = false; } + tagSize = bitCount; + } else { + // Time reached but unknown bitCount, clear and start again + tagSize = 0; + bRet = false; + } #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 %u, tag size %u "), rfid, tagSize); #endif // DEV_WIEGAND_TEST_MODE>0 return bRet; } -void Wiegand::setOutputFormat(void) -{ - if (GetOption(WIEGAND_OPTION_HEX) == 0) { outFormat = "u"; } - else { outFormat = "X" WIEGAND_OPTION_HEX_POSTFIX ; } -} - void Wiegand::HandleKeyPad(void) { // will be called if a valid key pad input was recognized - if (GetOption(WIEGAND_OPTION_KEYPAD_TO_TAG) == 0) { // handle all key pad inputs as ONE Tag until # is recognized - if ( (tagSize == 4) || (tagSize == 8) ) { + if (GetOption(WIEGAND_OPTION_KEYPAD_TO_TAG) == 0) { // handle all key pad inputs as ONE Tag until # is recognized + if ((tagSize == 4) || (tagSize == 8)) { //only handle Keypad strokes if it is requested if (rfid >= 0x0a) { // # * as end of input detected -> all key values which are larger than 9 rfid = mqttRFIDKeypadBuffer; // original tagsize of 4 or 8 will be kept. @@ -372,7 +365,7 @@ void Wiegand::HandleKeyPad(void) { // will be called if a valid key pad input wa mqttRFIDKeypadBuffer = 0; } else { - mqttRFIDKeypadBuffer = (mqttRFIDKeypadBuffer*10)+rfid; //left shift + new key + mqttRFIDKeypadBuffer = (mqttRFIDKeypadBuffer * 10) + rfid; //left shift + new key webRFIDKeypadBuffer = mqttRFIDKeypadBuffer; // visualising the current typed keys rfid = 0; tagSize = 0; @@ -386,38 +379,33 @@ void Wiegand::HandleKeyPad(void) { // will be called if a valid key pad input wa } void Wiegand::ScanForTag() { - unsigned long startTime = micros(); + uint32_t 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 - // format MQTT output -// setOutputFormat(); -// char sFormat[50]; -// snprintf( sFormat, 50, PSTR(",\"Wiegand\":{\"UID\":%%0ll%s,\"" D_JSON_SIZE "\":%%%s}}"), outFormat, outFormat); - for (int i= 0; i < WIEGAND_RFID_ARRAY_SIZE; i++) - { - if (rfid_found[i].RFID != 0 || (rfid_found[i].RFID == 0 && i == 0)) { - uint64_t oldTag = rfid; + if (currentFoundRFIDcount > 0) { + uint32_t lastFoundRFIDcount = currentFoundRFIDcount; +#if (DEV_WIEGAND_TEST_MODE)>0 + AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag(). bitTime: %u lastFoundTime: %u RFIDS in buffer: %u"), bitTime, lastFoundTime, currentFoundRFIDcount); +#endif + for (uint32_t i = 0; i < WIEGAND_RFID_ARRAY_SIZE; i++) { + if (rfid_found[i].RFID != 0 || (rfid_found[i].RFID == 0 && i == 0)) { + uint32_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: ValidKey: %d Previous tag %llu"), validKey, oldTag); - #endif // DEV_WIEGAND_TEST_MODE>0 +#if (DEV_WIEGAND_TEST_MODE)>0 + AddLog(LOG_LEVEL_INFO, PSTR("WIE: ValidKey %d, Previous tag %u"), validKey, oldTag); +#endif // DEV_WIEGAND_TEST_MODE>0 if (validKey) { // Only in case of valid key do action. Issue#10585 HandleKeyPad(); //support one tag for multi key input - if (tagSize>0) { //do output only for rfids which are complete + if (tagSize > 0) { //do output only for rfids which are complete if (oldTag == rfid) { AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: Old tag")); } -// ResponseTime_P(sFormat, rfid, tagSize); -// Tasmota does not support 64-bit decimal output specifier (%llu) saving 60k code + ResponseTime_P(PSTR(",\"Wiegand\":{\"UID\":")); if (GetOption(WIEGAND_OPTION_HEX) == 0) { - ResponseTime_P(PSTR(",\"Wiegand\":{\"UID\":%lu,\"" D_JSON_SIZE "\":%d}}"), (uint32_t)rfid, tagSize); + ResponseAppend_P(PSTR("%u"), rfid); } else { - ResponseTime_P(PSTR(",\"Wiegand\":{\"UID\":\"%1_X" WIEGAND_OPTION_HEX_POSTFIX "\",\"" D_JSON_SIZE "\":%d}}"), &rfid, tagSize); + ResponseAppend_P(PSTR("\"%X" WIEGAND_OPTION_HEX_POSTFIX "\""), rfid); } + ResponseAppend_P(PSTR(",\"" D_JSON_SIZE "\":%d}}"), tagSize); MqttPublishTeleSensor(); } } @@ -426,33 +414,29 @@ void Wiegand::ScanForTag() { 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 - AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() %lu tags added while working on buffer"), (currentFoundRFIDcount-lastFoundRFIDcount)); + AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() %u tags added while working on buffer"), (currentFoundRFIDcount - lastFoundRFIDcount)); } ClearRFIDBuffer(); //reset array - #if (DEV_WIEGAND_TEST_MODE)>0 - AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() time elapsed %lu"), (micros() - startTime)); - #endif +#if (DEV_WIEGAND_TEST_MODE)>0 + AddLog(LOG_LEVEL_INFO, PSTR("WIE: ScanForTag() time elapsed %u"), (micros() - startTime)); +#endif } - } #ifdef USE_WEBSERVER void Wiegand::Show(void) { -// setOutputFormat(); -// char sFormat [30]; -// snprintf( sFormat, 30,PSTR("{s}Wiegand UID{m}%%ll%s {e}"), outFormat); -// if (tagSize>0) { WSContentSend_PD(sFormat, rfid); } -// else { WSContentSend_PD(sFormat, webRFIDKeypadBuffer); } -// Tasmota does not support 64-bit decimal output specifier (%llu) saving 60k code - if (GetOption(WIEGAND_OPTION_HEX) == 0) { - WSContentSend_P(PSTR("{s}Wiegand UID{m}%lu{e}"), (tagSize>0) ? (uint32_t)rfid : (uint32_t)webRFIDKeypadBuffer); - } else { - WSContentSend_P(PSTR("{s}Wiegand UID{m}%1_X" WIEGAND_OPTION_HEX_POSTFIX "{e}"), (tagSize>0) ? &rfid : &webRFIDKeypadBuffer); - } - #if (DEV_WIEGAND_TEST_MODE)>0 - AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag %llu, Bits %u"), rfid, bitCount); - #endif // DEV_WIEGAND_TEST_MODE>0 + WSContentSend_P(PSTR("{s}Wiegand UID{m}")); + if (GetOption(WIEGAND_OPTION_HEX) == 0) { + WSContentSend_P(PSTR("%u"), (tagSize > 0) ? rfid : webRFIDKeypadBuffer); + } else { + WSContentSend_P(PSTR("%X" WIEGAND_OPTION_HEX_POSTFIX), (tagSize > 0) ? rfid : webRFIDKeypadBuffer); + } + WSContentSend_P(PSTR("{e}")); + +#if (DEV_WIEGAND_TEST_MODE)>0 + AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag %u, Bits %u"), rfid, bitCount); +#endif // DEV_WIEGAND_TEST_MODE>0 } #endif // USE_WEBSERVER