From 74a2f920ddcec83d1968991623061a976aeaae2e Mon Sep 17 00:00:00 2001 From: TD-er Date: Thu, 26 Jun 2025 21:03:44 +0200 Subject: [PATCH] [MFRC522] Speed-up detecting cards + make error recovery more stable --- lib/MFRC522/MFRC522.cpp | 45 +++++++++------- lib/MFRC522/MFRC522.h | 28 ++++++++-- platformio_esp32_envs.ini | 2 +- src/_P111_RC522_RFID.ino | 27 +++++++++- src/src/PluginStructs/P111_data_struct.cpp | 60 ++++++++++++++++++++-- src/src/PluginStructs/P111_data_struct.h | 2 + 6 files changed, 135 insertions(+), 29 deletions(-) diff --git a/lib/MFRC522/MFRC522.cpp b/lib/MFRC522/MFRC522.cpp index e06ae4b97..f9bde8207 100644 --- a/lib/MFRC522/MFRC522.cpp +++ b/lib/MFRC522/MFRC522.cpp @@ -291,7 +291,7 @@ void MFRC522::PCD_AntennaOff() { /** * Get the current MFRC522 Receiver Gain (RxGain[2:0]) value. - * See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf + * See 9.3.3.6 / table 98 in https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf * NOTE: Return value scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits. * * @return Value of the RxGain, scrubbed to the 3 bits used. @@ -302,7 +302,7 @@ uint8_t MFRC522::PCD_GetAntennaGain() { /** * Set the MFRC522 Receiver Gain (RxGain) to value specified by given mask. - * See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf + * See 9.3.3.6 / table 98 in https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf * NOTE: Given mask is scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits. */ void MFRC522::PCD_SetAntennaGain(uint8_t mask) { @@ -314,7 +314,7 @@ void MFRC522::PCD_SetAntennaGain(uint8_t mask) { /** * Performs a self-test of the MFRC522 - * See 16.1.1 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf + * See 16.1.1 in https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf * * @return Whether or not the test passed. Or false if no firmware reference is available. */ @@ -368,21 +368,28 @@ bool MFRC522::PCD_PerformSelfTest() { // Pick the appropriate reference values const uint8_t *reference; - switch (version) { - case 0x88: // Fudan Semiconductor FM17522 clone - reference = FM17522_firmware_reference; - break; - case 0x90: // Version 0.0 - reference = MFRC522_firmware_referenceV0_0; - break; - case 0x91: // Version 1.0 - reference = MFRC522_firmware_referenceV1_0; - break; - case 0x92: // Version 2.0 - reference = MFRC522_firmware_referenceV2_0; - break; - default: // Unknown version - return false; // abort test + switch(version) { + // Fudan Semiconductor clone: + case 0xb2: // FM17522 + reference = FM17522_firmware_referenceB2; + break; + case 0x88: // FM17522 + reference = FM17522_firmware_reference88; + break; + case 0x89: // FM17522E + reference = FM17522E_firmware_reference; + break; + case 0x90: // Version 0.0 + reference = MFRC522_firmware_referenceV0_0; + break; + case 0x91: // Version 1.0 + reference = MFRC522_firmware_referenceV1_0; + break; + case 0x92: // Version 2.0 + reference = MFRC522_firmware_referenceV2_0; + break; + default: // Unknown version + return false; // abort test } // Verify that the results match up to our expectations @@ -868,7 +875,7 @@ MFRC522::StatusCode MFRC522::PICC_HaltA() { /** * Executes the MFRC522 MFAuthent command. * This command manages MIFARE authentication to enable a secure communication to any MIFARE Mini, MIFARE 1K and MIFARE 4K card. - * The authentication is described in the MFRC522 datasheet section 10.3.1.9 and http://www.nxp.com/documents/data_sheet/MF1S503x.pdf section 10.1. + * The authentication is described in the MFRC522 datasheet section 10.3.1.9 and https://www.nxp.com/docs/en/data-sheet/MF1S503x.pdf section 10.1. * For use with MIFARE Classic PICCs. * The PICC must be selected - ie in state ACTIVE(*) - before calling this function. * Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise no new communications can start. diff --git a/lib/MFRC522/MFRC522.h b/lib/MFRC522/MFRC522.h index 9044c0e90..0e94b071a 100644 --- a/lib/MFRC522/MFRC522.h +++ b/lib/MFRC522/MFRC522.h @@ -64,7 +64,7 @@ const uint8_t MFRC522_firmware_referenceV2_0[] PROGMEM = { }; // Clone // Fudan Semiconductor FM17522 (0x88) -const uint8_t FM17522_firmware_reference[] PROGMEM = { +const uint8_t FM17522_firmware_reference88[] PROGMEM = { 0x00, 0xD6, 0x78, 0x8C, 0xE2, 0xAA, 0x0C, 0x18, 0x2A, 0xB8, 0x7A, 0x7F, 0xD3, 0x6A, 0xCF, 0x0B, 0xB1, 0x37, 0x63, 0x4B, 0x69, 0xAE, 0x91, 0xC7, @@ -74,6 +74,28 @@ const uint8_t FM17522_firmware_reference[] PROGMEM = { 0x51, 0x64, 0xAB, 0x3E, 0xE9, 0x15, 0xB5, 0xAB, 0x56, 0x9A, 0x98, 0x82, 0x26, 0xEA, 0x2A, 0x62 }; +// Another "FM17522" ic form Aliexpress +const uint8_t FM17522_firmware_referenceB2[] PROGMEM = { + 0x00, 0xeb, 0x44, 0x85, 0xfa, 0x9a, 0x78, 0x01, + 0x74, 0xe5, 0x1c, 0x7a, 0x0a, 0xa0, 0x71, 0xe1, + 0xf3, 0xfa, 0x96, 0x6d, 0x28, 0xa1, 0x34, 0x46, + 0x3a, 0x1c, 0x32, 0x96, 0xb9, 0xe6, 0x44, 0x87, + 0x0a, 0x45, 0x98, 0xa9, 0x36, 0x60, 0x89, 0x0f, + 0x06, 0x9b, 0x7b, 0x17, 0xb3, 0x0c, 0x1a, 0x6c, + 0x1a, 0xae, 0x2c, 0xac, 0x0e, 0x6f, 0x2e, 0x02, + 0x2b, 0xcb, 0x8a, 0xb2, 0x45, 0xdd, 0x7e, 0x3c +}; +// Fudan Semiconductor FM17522E (0x89) +const uint8_t FM17522E_firmware_reference[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x04, 0xcc, 0xc8, 0x00, + 0x10, 0x04, 0x00, 0xc0, 0x00, 0x90, 0x00, 0x20, + 0x00, 0x00, 0x23, 0x00, 0x38, 0x06, 0x01, 0x33, + 0x98, 0xf3, 0x80, 0x06, 0xc0, 0xf9, 0x80, 0x08, + 0x27, 0x04, 0x23, 0x82, 0x21, 0x12, 0xf9, 0xc7 +}; class MFRC522 { public: @@ -173,7 +195,7 @@ public: }; // MFRC522 RxGain[2:0] masks, defines the receiver's signal voltage gain factor (on the PCD). - // Described in 9.3.3.6 / table 98 of the datasheet at http://www.nxp.com/documents/data_sheet/MFRC522.pdf + // Described in 9.3.3.6 / table 98 of the datasheet at https://www.nxp.com/docs/en/data-sheet/MFRC522.pdf enum PCD_RxGain : uint8_t { RxGain_18dB = 0x00 << 4, // 000b - 18 dB, minimum RxGain_23dB = 0x01 << 4, // 001b - 23 dB @@ -210,7 +232,7 @@ public: PICC_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register. PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register. PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block. - // The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6) + // The commands used for MIFARE Ultralight (from https://www.nxp.com/docs/en/data-sheet/MF0ICU1.pdf, Section 8.6) // The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight. PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 uint8_t page to the PICC. }; diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index e19c70d5f..6459103f8 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -120,7 +120,7 @@ board_build.filesystem = littlefs lib_ignore = ${esp32_always.lib_ignore} ESP32_ping ESP32 BLE Arduino - ${core_esp32_IDF5_3_2__3_1_0_LittleFS.lib_ignore} + ${esp32_base_idf5.lib_ignore} [esp32_IRExt] diff --git a/src/_P111_RC522_RFID.ino b/src/_P111_RC522_RFID.ino index 403482c91..42aa1e5f2 100644 --- a/src/_P111_RC522_RFID.ino +++ b/src/_P111_RC522_RFID.ino @@ -36,7 +36,7 @@ boolean Plugin_111(uint8_t function, struct EventStruct *event, String& string) { auto& dev = Device[++deviceCount]; dev.Number = PLUGIN_ID_111; - dev.Type = DEVICE_TYPE_SPI2; + dev.Type = DEVICE_TYPE_SPI3; dev.VType = Sensor_VType::SENSOR_TYPE_ULONG; dev.ValueCount = 1; dev.SendDataOption = true; @@ -59,9 +59,23 @@ boolean Plugin_111(uint8_t function, struct EventStruct *event, String& string) { event->String1 = formatGpioName_output(F("CS PIN")); // P111_CS_PIN event->String2 = formatGpioName_output_optional(F("RST PIN ")); // P111_RST_PIN + event->String3 = formatGpioName_input_optional(F("IRQ PIN ")); // P111_IRQ_PIN break; } + case PLUGIN_WEBFORM_SHOW_GPIO_DESCR: + { + string = event->String1; + string += concat(F("CS: "), formatGpioLabel(CONFIG_PIN1, false)); + string += event->String1; + string += concat(F("RST: "), formatGpioLabel(CONFIG_PIN2, false)); + string += event->String1; + string += concat(F("IRQ: "), formatGpioLabel(CONFIG_PIN3, false)); + success = true; + break; + } + + case PLUGIN_SET_DEFAULTS: { P111_REMOVALTIMEOUT = 500; // Default 500 msec reset delay @@ -70,8 +84,17 @@ boolean Plugin_111(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_WEBFORM_LOAD: { - addFormSubHeader(F("Options")); + P111_data_struct *P111_data = static_cast(getPluginTaskData(event->TaskIndex)); + if (nullptr != P111_data) { + uint8_t v{}; + const String version = P111_data->PCD_getVersion(v); + if (v != 0 && v != 0xFF) { + addRowLabel(F("Reader Version")); + addHtml(version); + } + } + addFormSubHeader(F("Options")); { const __FlashStringHelper *removaltype[] = { F("None"), diff --git a/src/src/PluginStructs/P111_data_struct.cpp b/src/src/PluginStructs/P111_data_struct.cpp index aee4a1edb..3d1953962 100644 --- a/src/src/PluginStructs/P111_data_struct.cpp +++ b/src/src/PluginStructs/P111_data_struct.cpp @@ -26,6 +26,8 @@ void P111_data_struct::init() { if (mfrc522 != nullptr) { mfrc522->PCD_Init(); // Initialize MFRC522 reader + mfrc522->PCD_WriteRegister(MFRC522::ComIEnReg, 0b10100000); // enable receiver interrupt + mfrc522->PCD_WriteRegister(MFRC522::DivIEnReg, 0x80); // Set as CMOS output pin initPhase = P111_initPhases::Ready; } } @@ -116,10 +118,15 @@ bool P111_data_struct::reset(int8_t csPin, if ((resetPin != -1) && (initPhase == P111_initPhases::Ready)) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("MFRC522: Reset on pin: "); - log += resetPin; - addLogMove(LOG_LEVEL_INFO, log); + addLogMove( + LOG_LEVEL_INFO, + concat(F("MFRC522: Reset on pin: "), resetPin)); } + + init(); + return true; + + // FIXME TD-er: Remove the rest of this function. pinMode(resetPin, OUTPUT); digitalWrite(resetPin, LOW); timeToWait = 100; @@ -140,6 +147,8 @@ bool P111_data_struct::reset(int8_t csPin, digitalWrite(csPin, LOW); mfrc522->PCD_Init(csPin, resetPin); // Init MFRC522 module + mfrc522->PCD_WriteRegister(MFRC522::ComIEnReg, 0b10100000); // enable receiver interrupt + mfrc522->PCD_WriteRegister(MFRC522::DivIEnReg, 0x80); // Set as CMOS output pin // If you set Antenna Gain to Max it will increase reading distance mfrc522->PCD_SetAntennaGain(mfrc522->RxGain_max); @@ -226,8 +235,10 @@ bool P111_data_struct::plugin_ten_per_second(struct EventStruct *event) { } counter++; // This variable replaces a static variable in the original implementation + const bool ComIrqReg_bits = (mfrc522->PCD_ReadRegister(MFRC522::ComIrqReg) & (1<<5)) != 0; + mfrc522->PCD_WriteRegister(MFRC522::ComIrqReg, 0x34); - if (counter == 3) { // Only every 3rd 0.1 second we do a read + if (counter >= 10 || ComIrqReg_bits) { // Only every 3rd 0.1 second we do a read counter = 0; uint32_t key = P111_NO_KEY; @@ -300,4 +311,45 @@ bool P111_data_struct::plugin_fifty_per_second() { return true; } + +String P111_data_struct::PCD_getVersion(uint8_t& v) { + v = 0xFF; + if (mfrc522) { + v = mfrc522->PCD_ReadRegister(MFRC522::VersionReg); + if (v != 0xFF && v != 0) { + // Human readable version. + String res = concat(formatToHex(v, 2), F(" = ")); + switch(v) { + case 0xb2: + res += F("FM17522_1"); + break; + case 0x88: + res += F("FM17522"); + break; + case 0x89: + res += F("FM17522E"); + break; + case 0x90: + res += F("v0.0"); + break; + case 0x91: + res += F("v1.0"); + break; + case 0x92: + res += F("v2.0"); + break; + case 0x12: + res += F("counterfeit chip"); + break; + default: + res += F("(unknown)"); + break; + } + return res; + } + } + return EMPTY_STRING; +} + + #endif // ifdef USES_P111 diff --git a/src/src/PluginStructs/P111_data_struct.h b/src/src/PluginStructs/P111_data_struct.h index 219af16fb..4a5d68c40 100644 --- a/src/src/PluginStructs/P111_data_struct.h +++ b/src/src/PluginStructs/P111_data_struct.h @@ -39,6 +39,8 @@ struct P111_data_struct : public PluginTaskData_base { bool plugin_ten_per_second(struct EventStruct *event); bool plugin_fifty_per_second(); + String PCD_getVersion(uint8_t& v); + private: MFRC522 *mfrc522 = nullptr;