diff --git a/CHANGELOG.md b/CHANGELOG.md index 79e41be9e..743b0fcaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file. - Support for up to 4 I2C SEESAW_SOIL Capacitance & Temperature sensors by Peter Franck (#10481) - ESP8266 Support for 2MB and up linker files with 1MB and up LittleFS - ESP32 support for TLS MQTT using BearSSL (same as ESP8266) +- Support for 24/26/32/34 bit RFID Wiegand interface (D0/D1) by Sigurd Leuther (#3647) ### Breaking Changed - ESP32 switch from default SPIFFS to default LittleFS file system loosing current (zigbee) files diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b3f8e38a0..136d679f3 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -78,6 +78,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota - Support for disabling 38kHz IR modulation using ``#define IR_SEND_USE_MODULATION false`` [#10301](https://github.com/arendst/Tasmota/issues/10301) - Support for SPI display driver for ST7789 TFT by Gerhard Mutz [#9037](https://github.com/arendst/Tasmota/issues/9037) - Support for time proportioned (``#define USE_TIMEPROP``) and optional PID (``#define USE_PID``) relay control [#10412](https://github.com/arendst/Tasmota/issues/10412) +- Support for 24/26/32/34 bit RFID Wiegand interface (D0/D1) by Sigurd Leuther [#3647](https://github.com/arendst/Tasmota/issues/3647) - Support rotary encoder on Shelly Dimmer [#10407](https://github.com/arendst/Tasmota/issues/10407#issuecomment-756240920) - Support character `#` to be replaced by `space`-character in command ``Publish`` topic [#10258](https://github.com/arendst/Tasmota/issues/10258) - Basic support for ESP32 Odroid Go 16MB binary tasmota32-odroidgo.bin [#8630](https://github.com/arendst/Tasmota/issues/8630) diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h index f6fb4a662..b13396097 100644 --- a/tasmota/language/af_AF.h +++ b/tasmota/language/af_AF.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index f00b30d2c..b69e1b81c 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -781,6 +781,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index d529a4e16..6ed6b3b63 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index 071bfaaa0..635318b54 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index 9f1342b0b..718ee89d8 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 11acc25fb..9d0a73354 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index bb9bdd4d0..b35de9d0b 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index 709788ecc..5dfc7c5ba 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -778,6 +778,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "CarteSD CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index 1ed935184..b36412ac1 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index b8d4d5347..62f2131ce 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index 6791d768a..391f166a7 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 - CS" #define D_SENSOR_SSD1331_DC "SSD1331 - DC" #define D_SENSOR_SDCARD_CS "Scheda SD - CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index a51333856..7593261df 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index 185e3a0c0..0eea3bb75 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 9da13e702..2d614d037 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index f48328e4c..ecb4a8afc 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index f7893127c..6f7a11f01 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index b4641fca8..270b251d7 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index 9d19762a4..e37ed4e8f 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "А" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 5c46b4b89..2eebf1331 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index a6e6aa1f6..ed97b84e8 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 21ac79065..659dcf15b 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index b32761e2e..a350cef9b 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "А" diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index e5d7d6c35..86eb6eb2e 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index 2041c1483..d0a29c3c1 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "安" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 46814ce24..02d898d5a 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -782,6 +782,8 @@ #define D_SENSOR_SSD1331_CS "SSD1331 CS" #define D_SENSOR_SSD1331_DC "SSD1331 DC" #define D_SENSOR_SDCARD_CS "SDCard CS" +#define D_SENSOR_WIEGAND_D0 "Wiegand D0" +#define D_SENSOR_WIEGAND_D1 "Wiegand D1" // Units #define D_UNIT_AMPERE "安培" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 12f47d073..f62d2a6b7 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -710,6 +710,7 @@ #define MAX31865_REF_RES 430 // Reference resistor (Usually 430Ω for a PT100, 4300Ω for a PT1000) #define MAX31865_PTD_BIAS 0 // To calibrate your not-so-good PTD //#define USE_LMT01 // Add support for TI LMT01 temperature sensor, count pulses on single GPIO (+0k5 code) +//#define USE_WIEGAND // Add support for 24/26/32/34 bit RFID Wiegand interface (D0/D1) (+1k7 code) // -- IR Remote features - all protocols from IRremoteESP8266 -------------------------- // IR Full Protocols mode is activated through platform.io only. @@ -767,8 +768,6 @@ #define USE_ZIGBEE_MAXTIME_SENSOR 60*60 // 1h #define USE_ZIGBEE_MAXTIME_LIGHT 60*60 // 1h - - // -- Other sensors/drivers ----------------------- //#define USE_TM1638 // Add support for TM1638 switches copying Switch1 .. Switch8 (+1k code) diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index 3a3597f2a..49c158653 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -704,7 +704,9 @@ void ResponseAppendFeatures(void) #ifdef USE_SEESAW_SOIL feature7 |= 0x02000000; // xsns_81_seesaw_soil.ino #endif -// feature7 |= 0x04000000; +#ifdef USE_WIEGAND + feature7 |= 0x04000000; // xsns_82_wiegand.ino +#endif // feature7 |= 0x08000000; // feature7 |= 0x10000000; diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index f2dbae6c4..40e90cccd 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -146,6 +146,7 @@ enum UserSelectablePins { GPIO_ROT1A_NP, GPIO_ROT1B_NP, // Rotary switch GPIO_ADC_PH, // Analog PH Sensor GPIO_BS814_CLK, GPIO_BS814_DAT, // Holtek BS814A2 touch ctrlr + GPIO_WIEGAND_D0, GPIO_WIEGAND_D1, // Wiegand Data lines GPIO_SENSOR_END }; enum ProgramSelectablePins { @@ -312,6 +313,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_ROTARY " A_n|" D_SENSOR_ROTARY " B_n|" D_SENSOR_ADC_PH "|" D_SENSOR_BS814_CLK "|" D_SENSOR_BS814_DAT "|" + D_SENSOR_WIEGAND_D0 "|" D_SENSOR_WIEGAND_D1 "|" ; const char kSensorNamesFixed[] PROGMEM = @@ -735,6 +737,10 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_MIEL_HVAC_TX), // Mitsubishi Electric HVAC TX pin AGPIO(GPIO_MIEL_HVAC_RX), // Mitsubishi Electric HVAC RX pin #endif +#ifdef USE_WIEGAND + AGPIO(GPIO_WIEGAND_D0), // Date line D0 of Wiegand devices + AGPIO(GPIO_WIEGAND_D1), // Date line D1 of Wiegand devices +#endif /*-------------------------------------------------------------------------------------------*\ * ESP32 specifics diff --git a/tasmota/xsns_82_wiegand.ino b/tasmota/xsns_82_wiegand.ino new file mode 100644 index 000000000..57ebfba2a --- /dev/null +++ b/tasmota/xsns_82_wiegand.ino @@ -0,0 +1,429 @@ +/* + xsns_82_wiegand.ino - Support for Wiegand Interface 125kHz NFC Tag Reader for Tasmota + + Copyright (C) 2021 Sigurd Leuther and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_WIEGAND +/*********************************************************************************************\ + MQTT: + %prefix%/%topic%/SENSOR = {"Time":"2021-01-13T12:30:38","Wiegand":{"UID":"rfid tag"}} + + Domoticz: + The nvalue will be always 0 and the svalue will contain the tag UID as string. +\*********************************************************************************************/ +#warning **** Wiegand interface enabled **** + +#define XSNS_82 82 + +#define WIEGAND_BIT_TIMEOUT 25 //time to be wait after last bit detected. +// 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 +// DEV_WIEGAND_TEST_MODE 2 : testing with hardware corretly 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)" + #elif (DEV_WIEGAND_TEST_MODE==2) + #warning "Wiegand Interface compiled with 'DEV_WIEGAND_TEST_MODE' 2 (Hardware connected)" + #else + #warning "Wiegand Interface compiled with unknown mode" + #endif +#endif + +class Wiegand { + public: + + Wiegand(void); + void Init(void); + void ScanForTag(void); +#ifdef USE_WEBSERVER + void Show(void); +#endif + + 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); + static void handleD0Interrupt(void); + static void handleD1Interrupt(void); + + uint64_t rfid; + uint8_t tagSize; + + static volatile uint64_t rfidBuffer; + static volatile uint16_t bitCount; + static volatile uint32_t lastFoundTime; + static volatile uint8_t timeOut; + bool isInit = false; + +#if (DEV_WIEGAND_TEST_MODE)==1 + uint64_t GetRandomRfid(uint8_t); +#endif +}; + +Wiegand* oWiegand = new Wiegand(); +uint8_t scanDelay; + +volatile uint64_t Wiegand::rfidBuffer; +volatile uint16_t Wiegand::bitCount; +volatile uint32_t Wiegand::lastFoundTime; +volatile uint8_t Wiegand::timeOut; + +Wiegand::Wiegand() { + rfid = 0; + lastFoundTime = 0; + tagSize = 0; + rfidBuffer = 0; + bitCount = 0 ; + timeOut = 0; + isInit= false; +} + +#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; + } + 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 + +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 +} + +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 +} + +void Wiegand::Init() { + isInit = false; + if (PinUsed(GPIO_WIEGAND_D0) && PinUsed(GPIO_WIEGAND_D1)) { //only start, if the Wiegang pins are + #if (DEV_WIEGAND_TEST_MODE)>0 + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: Init()")); + #endif + pinMode(Pin(GPIO_WIEGAND_D0), INPUT_PULLUP); + pinMode(Pin(GPIO_WIEGAND_D1), INPUT_PULLUP); + attachInterrupt(Pin(GPIO_WIEGAND_D0), handleD0Interrupt, FALLING); + attachInterrupt(Pin(GPIO_WIEGAND_D1), handleD1Interrupt, FALLING); + isInit = true; // helps to run only if correctly setup + #if (DEV_WIEGAND_TEST_MODE)>0 + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: Testmode")); // for tests without reader attaiched + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: D0:%u"),Pin(GPIO_WIEGAND_D0)); + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: D1:%u"),Pin(GPIO_WIEGAND_D1)); + #else + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: D0=%u, D1=%u"),Pin(GPIO_WIEGAND_D0), Pin(GPIO_WIEGAND_D1)); + #endif + } + #if (DEV_WIEGAND_TEST_MODE)>0 + else { + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: no GPIOs.")); + } + #endif +} + +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) { + case 24: + evenParityBit = (rfidIn & 0x800000) ? 0x80 : 0; + rfidIn = (rfidIn & 0x7FFFFE) >>1; + break; + + case 26: + evenParityBit = (rfidIn & 0x2000000) ? 0x80 : 0; + rfidIn = (rfidIn & 0x1FFFFFE) >>1; + break; + + case 32: + evenParityBit = (rfidIn & 0x80000000) ? 0x80 : 0; + rfidIn = (rfidIn & 0x7FFFFFFE) >>1; + break; + + case 34: + evenParityBit = (rfidIn & 0x400000000) ? 0x80 : 0; + rfidIn = (rfidIn & 0x3FFFFFFFE) >>1; + break; + + default: + break; + } + calcParity = CalculateParities(rfidIn, bitCount); //ckeck result on http://www.ccdesignworks.com/wiegand_calc.htm with raw tag as input + if (calcParity != (evenParityBit | oddParityBit)) { // Paritybit is wrong + rfidIn=0; + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: %llu parity error"), rfidIn); + } + #if (DEV_WIEGAND_TEST_MODE)>0 + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: even (left) parity: %u "), (evenParityBit>>7)); + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: even (calc) parity: %u "), (calcParity & 0x80)>>7); + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: odd (right) parity: %u "), oddParityBit); + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: odd (calc) parity: %u "), (calcParity & 0x01)); + #endif + return rfidIn; +} + +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! + //calculated start parity (even) will be returned as bit 8 + //calculated end parity (odd) will be returned as bit 1 + uint8_t retValue=0; + 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++) { + parity^=(tagWithoutParities & 1); + tagWithoutParities>>=1; + } + retValue |= parity; + + parity=0; //check for even parity on MSB + while (tagWithoutParities) { + parity^=(tagWithoutParities & 1); + tagWithoutParities>>=1; + } + retValue |= (parity<<7); + + return retValue; +} + +char Wiegand::translateEnterEscapeKeyPress(char oKeyPressed) { + switch(oKeyPressed) { + case 0x0b: // 11 or * key + return 0x0d; // 13 or ASCII ENTER + + case 0x0a: // 10 or # key + return 0x1b; // 27 or ASCII ESCAPE + + default: + return oKeyPressed; + } +} + +bool Wiegand::WiegandConversion () +{ + bool bRet = false; + unsigned long nowTick = millis(); + if ((nowTick - lastFoundTime) > WIEGAND_BIT_TIMEOUT) //last bit found is WIEGAND_BIT_TIMEOUT ms ago + { + #if (DEV_WIEGAND_TEST_MODE)>0 + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: raw tag: %llu "), rfidBuffer); + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: bit count: %u "), bitCount); + #endif + if ((bitCount==4)||(bitCount==8)||(bitCount==24)||(bitCount==26)||(bitCount==32)||(bitCount==34)) { + if ((bitCount==24)||(bitCount==26)||(bitCount==32)||(bitCount==34)) { + // 24,26,32,34-bit Wiegand codes + rfid = CheckAndConvertRfid( rfidBuffer, bitCount); + tagSize=bitCount; + bitCount=0; + rfidBuffer=0; + bRet=true; + } + if (bitCount==4) { + // 4-bit Wiegand codes for keypads + rfid = (int)translateEnterEscapeKeyPress(rfidBuffer & 0x0000000F); + tagSize = bitCount; + bitCount = 0; + rfidBuffer = 0; + bRet=true; + } + if (bitCount==8){ + // 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)translateEnterEscapeKeyPress(lowNibble); + bRet=true; + } + else { + lastFoundTime=nowTick; + bRet=false; + } + tagSize=bitCount; + bitCount=0; + rfidBuffer=0; + } + } + else { + // time reached but unknown bitCount, clear and start again + lastFoundTime=nowTick; + bitCount=0; + rfidBuffer=0; + bRet=false; + } + } + else{ + bRet=false; // watching time not finished + } + #if (DEV_WIEGAND_TEST_MODE)>0 + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: tag out: %llu "), rfid); + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: tag size: %u"), tagSize); + #endif + return bRet; +} + +void Wiegand::ScanForTag() { + + if (!isInit) { return;} + #if (DEV_WIEGAND_TEST_MODE)>0 + AddLog_P(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_P(LOG_LEVEL_INFO, PSTR("WIE: raw generated: %lX"), rfidBuffer); // for tests without reader attaiched + #endif + #endif + if (bitCount > 0) { + uint64_t oldTag = rfid; + bool newKey = WiegandConversion(); + #if (DEV_WIEGAND_TEST_MODE)>0 + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: previous tag: %llu"), oldTag); + #endif + if(newKey && (oldTag != rfid)) { + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: new= %llu"), rfid); + } + else + { AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: prev= %llu"), rfid);} + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: bits= %u"), tagSize); + ResponseTime_P(PSTR(",\"Wiegand\":{\"UID\":\"%0llu\"}}"), rfid); + MqttPublishTeleSensor(); + } +} + +#ifdef USE_WEBSERVER +void Wiegand::Show(void) { + if (!isInit) { return; } + WSContentSend_PD(PSTR("{s}Wiegand UID{m}%llu {e}"), rfid); + #if (DEV_WIEGAND_TEST_MODE)>0 + AddLog_P(LOG_LEVEL_INFO,PSTR("WIE: Tag: %llu"), rfid); + AddLog_P(LOG_LEVEL_INFO, PSTR("WIE: %u bits"), bitCount); + #endif +} +#endif // USE_WEBSERVER + + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns82(byte function) { + bool result = false; + + switch (function) { + case FUNC_INIT: + oWiegand->Init(); + scanDelay = 1; + break; + + case FUNC_EVERY_250_MSECOND: // some tags need more time, don't try shorter period + #if (DEV_WIEGAND_TEST_MODE)==1 + if (scanDelay>=4) // give a second because of the log entries to be send. + #else + if (scanDelay>=2) // only run every (delay * 250 ms) (every 250ms is too fast for some tags) + #endif + { + oWiegand->ScanForTag(); + scanDelay = 1; + } + else { + scanDelay++; + } + break; + + #ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + oWiegand->Show(); + break; + #endif // USE_WEBSERVER + } + return result; +} +#endif // USE_WIEGAND \ No newline at end of file diff --git a/tools/decode-status.py b/tools/decode-status.py index 8d8bfc7ba..f6b6f923d 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -244,7 +244,7 @@ a_features = [[ "USE_SHELLY_DIMMER","USE_RC522","USE_FTC532","USE_DISPLAY_EPAPER_42", "USE_DISPLAY_ILI9488","USE_DISPLAY_SSD1351","USE_DISPLAY_RA8876","USE_DISPLAY_ST7789", "USE_DISPLAY_SSD1331","USE_UFILESYS","USE_TIMEPROP","USE_PID", - "USE_BS814A2","USE_SEESAW_SOIL","","", + "USE_BS814A2","USE_SEESAW_SOIL","USE_WIEGAND","", "","","","" ]] @@ -273,7 +273,7 @@ else: obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v20210111 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v20210116 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj))