From 76909dcb2d5b4d1bab3b0f1d84048d328d3aa4d7 Mon Sep 17 00:00:00 2001 From: GOB Date: Mon, 15 Dec 2025 20:54:16 +0900 Subject: [PATCH] Add NFC-B(WIP) --- examples/UnitUnified/NFCB/Detect/Detect.ino | 19 ++ .../UnitUnified/NFCB/Detect/main/Detect.cpp | 127 ++++++++++ examples/UnitUnified/NFCB/Dump/Dump.ino | 19 ++ examples/UnitUnified/NFCB/Dump/main/Dump.cpp | 139 +++++++++++ platformio.ini | 31 +++ src/M5UnitUnifiedNFC.hpp | 1 + src/nfc/a/file_system.hpp | 62 +++++ src/nfc/a/nfca.cpp | 5 +- src/nfc/a/nfca.hpp | 105 +++++---- src/nfc/b/nfcb.cpp | 63 +++++ src/nfc/b/nfcb.hpp | 154 +++++++++++- src/nfc/layer/nfc_layer_a.cpp | 24 +- src/nfc/layer/nfc_layer_a.hpp | 9 +- src/nfc/layer/nfc_layer_b.cpp | 220 ++++++++++++++++++ src/nfc/layer/nfc_layer_b.hpp | 192 +++++++++++++++ src/nfc/layer/nfc_layer_f.cpp | 2 +- src/nfc/layer/nfc_layer_f.hpp | 3 +- src/nfc/layer/nfc_layer_v.cpp | 3 +- src/nfc/layer/nfc_layer_v.hpp | 3 +- src/nfc/layer/unit/nfc_layer_a_ST25R3916.cpp | 2 +- src/nfc/layer/unit/nfc_layer_b_ST25R3916.cpp | 72 ++++++ src/nfc/layer/unit/nfc_layer_v_ST25R3916.cpp | 4 +- src/nfc/v/nfcv.cpp | 40 ++-- src/unit/unit_ST25R3916.hpp | 4 + src/unit/unit_ST25R3916_nfca.cpp | 5 +- src/unit/unit_ST25R3916_nfcb.cpp | 184 ++++++++++++++- src/unit/unit_ST25R3916_nfcv.cpp | 4 +- 27 files changed, 1403 insertions(+), 93 deletions(-) create mode 100644 examples/UnitUnified/NFCB/Detect/Detect.ino create mode 100644 examples/UnitUnified/NFCB/Detect/main/Detect.cpp create mode 100644 examples/UnitUnified/NFCB/Dump/Dump.ino create mode 100644 examples/UnitUnified/NFCB/Dump/main/Dump.cpp create mode 100644 src/nfc/a/file_system.hpp create mode 100644 src/nfc/b/nfcb.cpp create mode 100644 src/nfc/layer/nfc_layer_b.cpp create mode 100644 src/nfc/layer/nfc_layer_b.hpp create mode 100644 src/nfc/layer/unit/nfc_layer_b_ST25R3916.cpp diff --git a/examples/UnitUnified/NFCB/Detect/Detect.ino b/examples/UnitUnified/NFCB/Detect/Detect.ino new file mode 100644 index 0000000..9e41b52 --- /dev/null +++ b/examples/UnitUnified/NFCB/Detect/Detect.ino @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +/* + Example using M5UnitUnified for ST25R3916 + Detect NFC-B PICC +*/ +// ************************************************************* +// Choose one define symbol to match the unit you are using +// ************************************************************* +#if !defined(USING_UNIT_NFC) && !defined(USING_HACKER_CAP) +// For UnitNFC +// #define USING_UNIT_NFC +// For CapNFC +// #define USING_HACKER_CAP +#endif +#include "main/Detect.cpp" diff --git a/examples/UnitUnified/NFCB/Detect/main/Detect.cpp b/examples/UnitUnified/NFCB/Detect/main/Detect.cpp new file mode 100644 index 0000000..32ef2a2 --- /dev/null +++ b/examples/UnitUnified/NFCB/Detect/main/Detect.cpp @@ -0,0 +1,127 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +/* + Example using M5UnitUnified for M5Cardputer-ADV with HackerCap + Detect NFC-B PICC +*/ +#include +#include +#include +#include +#include + +// ************************************************************* +// Choose one define symbol to match the unit you are using +// ************************************************************* +#if !defined(USING_UNIT_NFC) && !defined(USING_HACKER_CAP) +// For UnitNFC +// #define USING_UNIT_NFC +// For CapNFC +// #define USING_HACKER_CAP +#endif + +using namespace m5::nfc; +using namespace m5::nfc::b; + +namespace { +auto& lcd = M5.Display; +m5::unit::UnitUnified Units; + +#if defined(USING_UNIT_NFC) +#pragma message "Choose UnitNFC" +m5::unit::UnitNFC unit{}; // I2C +#elif defined(USING_HACKER_CAP) +#pragma message "Choose HackerCapNFC" +m5::unit::HackerCapNFC unit{}; // HackerCap (SPI) +#else +#error Choose unit please! +#endif +m5::unit::nfc::NFCLayerB nfc_b{unit}; +} // namespace + +void setup() +{ + M5.begin(); + + auto cfg = unit.config(); + cfg.mode = NFC::B; + unit.config(cfg); + +#if 0 + //// M5GFX 0.2.15 NG! with HackerCap + auto board = M5.getBoard(); + if (board != lgfx::board_t::board_M5CardputerADV) { + M5_LOGE("This is NOT M5Cardputer-ADV %U/%XH", board, board); + lcd.fillScreen(TFT_RED); + while (true) { + m5::utility::delay(10000); + } + } +#endif + +#if defined(USING_UNIT_NFC) + auto pin_num_sda = M5.getPin(m5::pin_name_t::port_a_sda); + auto pin_num_scl = M5.getPin(m5::pin_name_t::port_a_scl); + M5_LOGI("getPin: SDA:%u SCL:%u", pin_num_sda, pin_num_scl); + Wire.end(); + Wire.begin(pin_num_sda, pin_num_scl, 400 * 1000U); + + if (!Units.add(unit, Wire) || !Units.begin()) { + M5_LOGE("Failed to begin"); + lcd.clear(TFT_RED); + while (true) { + m5::utility::delay(10000); + } + } +#elif defined(USING_HACKER_CAP) + if (!SPI.bus()) { + auto spi_sclk = M5.getPin(m5::pin_name_t::sd_spi_sclk); + auto spi_mosi = M5.getPin(m5::pin_name_t::sd_spi_mosi); + auto spi_miso = M5.getPin(m5::pin_name_t::sd_spi_miso); + M5_LOGI("getPin: %d,%d,%d", spi_sclk, spi_mosi, spi_miso); + SPI.begin(spi_sclk, spi_miso, spi_mosi /* SS is shared SD, CC1101, ST25R3916 */); + } + + SPISettings settings = {10000000, MSBFIRST, SPI_MODE1}; + if (!Units.add(unit, SPI, settings) || !Units.begin()) { + M5_LOGE("Failed to begin"); + lcd.fillScreen(TFT_RED); + while (true) { + m5::utility::delay(10000); + } + } +#endif + M5_LOGI("M5UnitUnified has been begun"); + M5_LOGI("%s", Units.debugInfo().c_str()); + + if (lcd.width() < lcd.height()) { + lcd.setRotation(1); + } + lcd.setFont(&fonts::Font0); + lcd.fillScreen(0); + lcd.setCursor(0, 0); +} + +void loop() +{ + M5.update(); + Units.update(); + + std::vector piccs; + if (nfc_b.detect(piccs)) { + M5.Speaker.tone(3000, 10); + lcd.fillScreen(0); + lcd.setCursor(0, 0); + lcd.printf("%zu PICC\n", piccs.size()); + M5.Log.printf("%zu PICC\n", piccs.size()); + uint32_t idx{}; + for (auto&& u : piccs) { + M5.Log.printf("PICC:%s %s\n", u.pupiAsString().c_str(), u.typeAsString().c_str()); + lcd.printf("[%2u]:PICC:<%s>%s\n", idx, u.pupiAsString().c_str(), u.typeAsString().c_str()); + ++idx; + } + } +} diff --git a/examples/UnitUnified/NFCB/Dump/Dump.ino b/examples/UnitUnified/NFCB/Dump/Dump.ino new file mode 100644 index 0000000..e37b388 --- /dev/null +++ b/examples/UnitUnified/NFCB/Dump/Dump.ino @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +/* + Example using M5UnitUnified for ST25R3916 + Dump NFC-B PICC +*/ +// ************************************************************* +// Choose one define symbol to match the unit you are using +// ************************************************************* +#if !defined(USING_UNIT_NFC) && !defined(USING_HACKER_CAP) +// For UnitNFC +// #define USING_UNIT_NFC +// For CapNFC +// #define USING_HACKER_CAP +#endif +#include "main/Dump.cpp" diff --git a/examples/UnitUnified/NFCB/Dump/main/Dump.cpp b/examples/UnitUnified/NFCB/Dump/main/Dump.cpp new file mode 100644 index 0000000..bd547c5 --- /dev/null +++ b/examples/UnitUnified/NFCB/Dump/main/Dump.cpp @@ -0,0 +1,139 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +/* + Example using M5UnitUnified for ST25R3916 + Dump NFC-B PICC +*/ +#include +#include +#include +#include +#include + +// ************************************************************* +// Choose one define symbol to match the unit you are using +// ************************************************************* +#if !defined(USING_UNIT_NFC) && !defined(USING_HACKER_CAP) +// For UnitNFC +// #define USING_UNIT_NFC +// For CapNFC +// #define USING_HACKER_CAP +#endif + +using namespace m5::nfc; +using namespace m5::nfc::b; + +namespace { +auto& lcd = M5.Display; +m5::unit::UnitUnified Units; + +#if defined(USING_UNIT_NFC) +#pragma message "Choose UnitNFC" +m5::unit::UnitNFC unit{}; // I2C +#elif defined(USING_HACKER_CAP) +#pragma message "Choose HackerCapNFC" +m5::unit::HackerCapNFC unit{}; // HackerCap (SPI) +#else +#error Choose unit please! +#endif +m5::unit::nfc::NFCLayerB nfc_b{unit}; + +} // namespace + +void setup() +{ + M5.begin(); + M5.setTouchButtonHeightByRatio(100); + + auto cfg = unit.config(); + cfg.mode = NFC::B; + unit.config(cfg); + +#if 0 + //// M5GFX 0.2.15 NG! with HackerCap + auto board = M5.getBoard(); + if (board != lgfx::board_t::board_M5CardputerADV) { + M5_LOGE("This is NOT M5Cardputer-ADV %U/%XH", board, board); + lcd.fillScreen(TFT_RED); + while (true) { + m5::utility::delay(10000); + } + } +#endif + +#if defined(USING_UNIT_NFC) + auto pin_num_sda = M5.getPin(m5::pin_name_t::port_a_sda); + auto pin_num_scl = M5.getPin(m5::pin_name_t::port_a_scl); + M5_LOGI("getPin: SDA:%u SCL:%u", pin_num_sda, pin_num_scl); + Wire.end(); + Wire.begin(pin_num_sda, pin_num_scl, 400 * 1000U); + + if (!Units.add(unit, Wire) || !Units.begin()) { + M5_LOGE("Failed to begin"); + lcd.clear(TFT_RED); + while (true) { + m5::utility::delay(10000); + } + } +#elif defined(USING_HACKER_CAP) + if (!SPI.bus()) { + auto spi_sclk = M5.getPin(m5::pin_name_t::sd_spi_sclk); + auto spi_mosi = M5.getPin(m5::pin_name_t::sd_spi_mosi); + auto spi_miso = M5.getPin(m5::pin_name_t::sd_spi_miso); + M5_LOGI("getPin: %d,%d,%d", spi_sclk, spi_mosi, spi_miso); + SPI.begin(spi_sclk, spi_miso, spi_mosi /* SS is shared SD, CC1101, ST25R3916 */); + } + + SPISettings settings = {10000000, MSBFIRST, SPI_MODE1}; + if (!Units.add(unit, SPI, settings) || !Units.begin()) { + M5_LOGE("Failed to begin"); + lcd.fillScreen(TFT_RED); + while (true) { + m5::utility::delay(10000); + } + } +#endif + M5_LOGI("M5UnitUnified has been begun"); + M5_LOGI("%s", Units.debugInfo().c_str()); + + if (lcd.width() < lcd.height()) { + lcd.setRotation(1); + } + lcd.setFont(&fonts::Font0); + lcd.fillScreen(0); + lcd.setCursor(0, 0); + lcd.printf("Please put the PICC and click BtnA"); + M5.Log.printf("Please put the PICC and click BtnA\n"); +} + +void loop() +{ + M5.update(); + Units.update(); + + if (M5.BtnA.wasClicked()) { + lcd.fillRect(0, lcd.fontHeight(), lcd.width(), lcd.height() - lcd.fontHeight()); + PICC picc{}; + if (nfc_b.select(picc)) { + M5.Speaker.tone(3000, 20); + M5.Log.printf("==== Dump %s %s %u bytes ====\n", picc.pupiAsString().c_str(), picc.typeAsString().c_str(), + /*picc.totalSize()*/ 0); + nfc_b.deactivate(); + +#if 0 + + if (nfc_b.reactivate(picc)) { + M5.Speaker.tone(3000, 20); + M5.Log.printf("==== Dump %s %s %u bytes ====\n", picc.pupiAsString().c_str(), + picc.typeAsString().c_str(), /*picc.totalSize()*/ 0); + // nfc_b.dump(); + } +#endif + } else { + M5.Log.printf("PICC NOT exists\n"); + } + } +} diff --git a/platformio.ini b/platformio.ini index c738fe6..baaa9d9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -3,6 +3,8 @@ ; For UnitTest and examples (Using M5UnitUnified) ;----------------------------------------------------------------------- [platformio] +;default_envs = UnitNFC_NFCA_Detect_Core_Arduino_latest, UnitNFC_NFCA_Dump_Core_Arduino_latest, UnitNFC_NFCA_ReadWrite_Core_Arduino_latest, UnitNFC_NFCA_ValueBlock_Core_Arduino_latest, UnitNFC_NFCA_NDEF_Core_Arduino_latest, UnitNFC_NFCF_Detect_Core_Arduino_latest, UnitNFC_NFCF_Dump_Core_Arduino_latest, UnitNFC_NFCF_NDEF_Core_Arduino_latest, UnitNFC_NFCF_Subtract_Core_Arduino_latest, UnitNFC_NFCF_ReadWriteMAC_Core_Arduino_latest, UnitNFC_NFCF_JapanTransportationICCard_Core_Arduino_latest, UnitNFC_NFCV_Detect_CardputerADV_Arduino_latest, UnitNFC_NFCV_Dump_CardputerADV_Arduino_latest, UnitNFC_NFCV_NDEF_Core_Arduino_latest + [env] build_flags = -Wall -Wextra -Wreturn-local-addr -Werror=format -Werror=return-local-addr @@ -282,6 +284,12 @@ build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/NFCV/Dump> build_flags = ${option_release.build_flags} -D USING_UNIT_NFC +[env:UnitNFC_NFCV_NDEF_Core_Arduino_latest] +extends=Core, option_release, arduino_latest +build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/NFCV/NDEF> +build_flags = ${option_release.build_flags} + -D USING_UNIT_NFC + ; -------------------------------- ; CapHacker @@ -321,6 +329,22 @@ build_flags = ${option_release.build_flags} ${CardputerADV.build_flags} -D USING_HACKER_CAP +; NFC-B +[env:CapHacker_NFCB_Detect_CardputerADV_Arduino_latest] +extends=CardputerADV, option_release, arduino_latest +build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/NFCB/Detect> +build_flags = ${option_release.build_flags} + ${CardputerADV.build_flags} + -D USING_HACKER_CAP + +[env:CapHacker_NFCB_Dump_CardputerADV_Arduino_latest] +extends=CardputerADV, option_release, arduino_latest +build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/NFCB/Dump> +build_flags = ${option_release.build_flags} + ${CardputerADV.build_flags} + -D USING_HACKER_CAP + + ; NFC-F [env:CapHacker_NFCF_Detect_CardputerADV_Arduino_latest] extends=CardputerADV, option_release, arduino_latest @@ -379,4 +403,11 @@ build_flags = ${option_release.build_flags} ${CardputerADV.build_flags} -D USING_HACKER_CAP +[env:CapHacker_NFCV_NDEF_CardputerADV_Arduino_latest] +extends=CardputerADV, option_release, arduino_latest +build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/NFCV/NDEF> +build_flags = ${option_release.build_flags} + ${CardputerADV.build_flags} + -D USING_HACKER_CAP + diff --git a/src/M5UnitUnifiedNFC.hpp b/src/M5UnitUnifiedNFC.hpp index 7e47290..c8b63ac 100644 --- a/src/M5UnitUnifiedNFC.hpp +++ b/src/M5UnitUnifiedNFC.hpp @@ -22,6 +22,7 @@ #include "unit/unit_ST25R3916.hpp" #include "nfc/layer/nfc_layer_a.hpp" +#include "nfc/layer/nfc_layer_b.hpp" #include "nfc/layer/nfc_layer_f.hpp" #include "nfc/layer/nfc_layer_v.hpp" diff --git a/src/nfc/a/file_system.hpp b/src/nfc/a/file_system.hpp new file mode 100644 index 0000000..1f82845 --- /dev/null +++ b/src/nfc/a/file_system.hpp @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +/*! + @file file_system.hpp + @brief File system for MIFARE Plus, DESFire / ST25TA +*/ +#ifndef M5_UNIT_UNIFIED_NFC_NFC_A_FILE_SYSTEM_HPP +#define M5_UNIT_UNIFIED_NFC_NFC_A_FILE_SYSTEM_HPP +#include +#include + +namespace m5 { +namespace nfc { +namespace a { + +struct FileInfo { + uint8_t fileId; // DESFire: FileNo, ST25TA: FileID (上位1byte省略でもOK) + uint32_t size; // バイト数 + uint8_t type; // DESFire: file type enum, ST25TA: NDEF/CC/System enum + uint8_t readAccess; // アクセス条件など(DESFire用) + uint8_t writeAccess; +}; + +class FileSystem { +public: + enum class Category : uint8_t { + Unknown, + DESFire, + St25TA, + }; + + explicit FileSystem(const Category c) : _category{c} + { + } + virtual ~FileSystem() = default; + + inline Category category() const + { + return _category; + } + + // ルート/アプリケーションの列挙 + virtual bool listApplications(std::vector& aids) = 0; // ST25TAは空 or 固定 + virtual bool selectApplication(const uint32_t aid) = 0; // ST25TAではダミー or 常にtrue + + // ファイル一覧 + virtual bool listFiles(std::vector& files) = 0; + virtual bool readFile(std::vector rbuf, const uint8_t fileId, const uint32_t offset, + const uint32_t rlen) = 0; + virtual bool writeFile(const uint8_t fileId, const uint32_t offset, const uint8_t* wbuf, const uint32_t wlen) = 0; + +private: + Category _category{}; +}; + +} // namespace a +} // namespace nfc +} // namespace m5 +#endif diff --git a/src/nfc/a/nfca.cpp b/src/nfc/a/nfca.cpp index 51ae4e6..519ee41 100644 --- a/src/nfc/a/nfca.cpp +++ b/src/nfc/a/nfca.cpp @@ -115,11 +115,11 @@ constexpr uint8_t user_block_table[][2] = { {4, 39}, // 213 Exclusive 0-3 and last 5 pages {4, 129}, // 215 Exclusive 0-3 and last 5 pages {4, 225}, // 216 Exclusive 0-3 and last 5 pages - // + // ST25TA {0, 0}, {0, 0}, {0, 0}, - // + // 14443-4 {0, 0}, // Plus {1, 126}, @@ -151,6 +151,7 @@ constexpr uint16_t user_area_size_table[] = { 240, 752, 1504, 3440, // Classic 48, 48, 128, 40, 144, // Light 144, 48, 144, 208, 144, 504, 888, // NTAG + 0, 0, 0, // ST25 0, // 1504, 3440, 752, // Plus 0, 0, 0, // Desfire diff --git a/src/nfc/a/nfca.hpp b/src/nfc/a/nfca.hpp index 162f246..a8a63d0 100644 --- a/src/nfc/a/nfca.hpp +++ b/src/nfc/a/nfca.hpp @@ -205,6 +205,10 @@ bool is_user_block(const Type t, const uint16_t block); //! @brief Calculate bcc8 uint8_t calculate_bcc8(const uint8_t* data, const uint32_t len); +/*! + @struct ATS + @brief Answer to request + */ struct ATS { union { uint8_t header[5]{}; @@ -237,65 +241,71 @@ struct ATS { */ struct PICC { uint8_t _pad{}; - Type type{}; //!< PICC type + Type type{}; //!< PICC type + uint8_t sak{}; //!< The SAK (Select acknowledge) returned from the PICC after successful selection + uint8_t size{}; //!< UID size 4, 7 or 10. + uint8_t uid[10]{}; //!< uid (Valid up to the value of size) + uint16_t atqa{}; //!< ATQA + uint16_t blocks{}; //!< Number of the blocks or pages union { uint8_t sub_type{}; //!< uint8_t access SubTypePlus sub_type_plus; //!< For Plus SubTypeDESFire sub_type_desfire; //!< For DESFire }; //!< SubType for Plus/DESFire; - uint8_t sak{}; //!< The SAK (Select acknowledge) returned from the PICC after successful selection - uint8_t security_level{}; //!< Security level for Plus - uint8_t size{}; //!< UID size 4, 7 or 10. - uint8_t uid[10]{}; //!< uid (Valid up to the value of size) - uint16_t atqa{}; //!< ATQA - uint16_t blocks{}; //!< Number of the blocks or pages + union { + uint8_t security_level{}; //!< Security level for Plus + }; //!< Optional information //! @brief Valid? inline bool valid() const { return (size == 4 || size == 7 || size == 10) && (type != Type::Unknown) && blocks; } + //! @brief Retrieve the last 4 bytes of UID + void tail4(uint8_t buf[4]) const + { + if (buf) { + memcpy(buf, uid + size - 4, 4); + } + } + std::string uidAsString() const; //!< @brief Gets the uid string + std::string typeAsString() const; //!< @brief Gets the type string + ///@name Type + ///@{ //! @brief Is MIFARE? inline bool isMifare() const { - return valid() && is_mifare(type); + return is_mifare(type); } //! @brief Is MIFARE classic? inline bool isMifareClassic() const { - return valid() && is_mifare_classic(type); + return is_mifare_classic(type); } //! @brief Is MIFARE Ultralight series? inline bool isMifareUltralight() const { - return valid() && is_mifare_ultralight(type); + return is_mifare_ultralight(type); } //! @brief Is MIFARE Plus? inline bool isMifarePlus() const { - return valid() && is_mifare_plus(type); + return is_mifare_plus(type); } //! @brief Is NTAG? inline bool isNTAG() const { - return valid() && is_ntag(type); + return is_ntag(type); } inline bool isISO14443_4() const { - return is_iso14443_4(type); // Don't check valid(), as there may exist where blocks == 0 + return is_iso14443_4(type); } + ///@} - //! @brief Supports NFC? - inline bool supportsNFC() const - { - return valid() && supports_NFC(type); - } - //! @brief Can use FAST_READ command? - inline bool canFastRead() const - { - return valid() && has_fast_read(type); - } + ///@name Information + ///@{ //! @brief Total size inline uint16_t totalSize() const { @@ -321,31 +331,36 @@ struct PICC { return valid() ? is_user_block(type, block) : false; } - //! @brief Retrieve the last 4 bytes - void tail4(uint8_t buf[4]) const - { - if (buf) { - memcpy(buf, uid + size - 4, 4); - } - } - //! @brief NFC ForumTag inline NFCForumTag nfcForumTagType() const { return get_nfc_forum_tag_type(type); } + ///@} - //! @brief Gets the uid string - std::string uidAsString() const; - //! @brief Gets the type string - std::string typeAsString() const; - //! @brief clear - void clear() + ///@name Capability + ///@{ + //! @brief Supports NFC? + inline bool supportsNFC() const { - size = sak = blocks = 0; - type = Type::Unknown; - std::memset(uid, 0x00, sizeof(uid)); + return valid() && supports_NFC(type); } + //! @brief Can use FAST_READ command? + inline bool canFastRead() const + { + return valid() && has_fast_read(type); + } +#if 0 + FileSystem::Type get_file_system() const + { + return (isMifareClassic() || isMifarePlus()) + ? FileSystem::Type::Sector + : ((isMifareUltralight() || isNTAG()) + ? FileSystem::Page + : ((isMifareDESFire() || isST25TA()) ? FileSystem : File:FileSystem : None)); + } +#endif + ///@} }; //! @brief Equal? @@ -400,6 +415,16 @@ enum class Command : uint8_t { READ_SIG = 0x3C, //!< NTAG 21x Read NXP ECC signature WRITE_SIG = 0xA9, //!< NTAG 210u Write custom signature LOCK_SIG = 0xAC, //!< NTAG 210u Lock/Unlock signature + // ISO/IEC 7816 + SELECT = 0xA4, //!< Select Application or file + READ_BINARY = 0xB0, //!< Read binary data + UPDATE_BINARY = 0xD6, //!< Write binary data + READ_RECORDS = 0xB2, //!< Read recode data + APPEND_RECORD = 0xE2, //!< pend recored data + GET_CHALLENGE = 0x84, + INTERNAL_AUTHENTICATE = 0x88, + EXTERNAL_AUTHENTICATE = 0x82, + }; ///@name Timeout diff --git a/src/nfc/b/nfcb.cpp b/src/nfc/b/nfcb.cpp new file mode 100644 index 0000000..ec9b883 --- /dev/null +++ b/src/nfc/b/nfcb.cpp @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +/*! + @file nfcb.hpp + @brief NFC-B definitions +*/ +#include "nfcb.hpp" +#include + +using namespace m5::nfc; +using namespace m5::nfc::b; + +namespace { + +constexpr char name_unknown[] = "Unknown"; +constexpr char name_unclassified[] = "Unclassified"; + +constexpr const char* name_table[] = { + name_unknown, // + name_unclassified, +}; + +constexpr uint16_t frame_length_table[9] = { + 16, 24, 32, 40, 48, 64, 96, 128, 256, +}; + +} // namespace + +namespace m5 { +namespace nfc { +namespace b { + +uint16_t maximum_frame_length(const uint8_t protocol[3]) +{ + if (protocol && ((protocol[1] >> 4) <= 8)) { + return frame_length_table[protocol[1] >> 4]; + } + return 0; +} + +// +std::string PICC::pupiAsString() const +{ + char buf[2 * 4 + 1]{}; + uint8_t left{}; + for (uint8_t i = 0; i < 4; ++i) { + left += snprintf(buf + left, 3, "%02X", this->pupi[i]); + } + return std::string(buf); +} + +std::string PICC::typeAsString() const +{ + auto idx = m5::stl::to_underlying(this->type); + return std::string((idx <= m5::stl::size(name_table)) ? name_table[idx] : name_unknown); +} + +} // namespace b +} // namespace nfc +} // namespace m5 diff --git a/src/nfc/b/nfcb.hpp b/src/nfc/b/nfcb.hpp index 34edfbe..cfcb44f 100644 --- a/src/nfc/b/nfcb.hpp +++ b/src/nfc/b/nfcb.hpp @@ -10,7 +10,10 @@ #ifndef M5_UNIT_UNIFIED_NFC_NFC_B_NFCB_HPP #define M5_UNIT_UNIFIED_NFC_NFC_B_NFCB_HPP +#include "nfc/nfc.hpp" #include +#include +#include namespace m5 { namespace nfc { @@ -25,18 +28,157 @@ namespace b { @brief Type of the PICC */ enum class Type : uint8_t { - Unknown, //!< Unknown type + Unknown, //!< Unknown type + Unclassified, //!< Unclassified }; /*! - @struct PUPI - @brief The PUPI(Pseudo-Unique PICC Identifier) of the PICC + @enum Require + @brief Number of slots required in the request/wakeup */ -struct PUPI { - //! @brief uid data - uint8_t uid[8]{}; +enum class Require : uint8_t { + Slot1, + Slot2, + Slot4, + Slot8, + Slot16, }; +constexpr uint8_t ATQB_LENGTH{11}; //!< ATQB length pupi(4) + application(4) + protocol(3) + +///@name Communication speed bits +///@{ +constexpr uint8_t COMMUNICATION_SAME_SPEED{0x80}; +constexpr uint8_t COMMUNICATION_SPPED_106K{0X00}; +constexpr uint8_t COMMUNICATION_SPPED_212K_FROM_PICC{0X10}; +constexpr uint8_t COMMUNICATION_SPPED_424K_FROM_PICC{0X20}; +constexpr uint8_t COMMUNICATION_SPPED_847K_FROM_PICC{0X40}; +constexpr uint8_t COMMUNICATION_SPPED_212K_TO_PICC{0X01}; +constexpr uint8_t COMMUNICATION_SPPED_424K_TO_PICC{0X02}; +constexpr uint8_t COMMUNICATION_SPPED_847K_TO_PICC{0X04}; +///@} + +///@name Frame option bits +///@{ +const uint8_t FRAME_OPTION_NAD{0x02}; +const uint8_t FRAME_OPTION_CID{0x01}; +///@} + +//! @breif Get maxumum frame length from protocl bytes +uint16_t maximum_frame_length(const uint8_t protocol[3]); + +inline uint8_t maximum_frame_length_bits(const uint8_t protocol[3]) +{ + return protocol ? protocol[1] >> 4 : 0x0F; +} + +//! @brief Supports ISO/IEC 14443-4? +inline bool supports_iso14443_4(const uint8_t protocol[3]) +{ + return protocol ? ((protocol[1] & 0x0F) & 0x01) : false; +} + +//! @brief Gets the frame option bits +inline uint8_t get_frame_option(const uint8_t protocol[3]) +{ + return protocol ? (protocol[2] & 0x03) : 0x00; +} + +/*! + @struct PICC + @brief PICC for NFC-B + */ +struct PICC { + uint8_t uid[8]{}; + union { + uint8_t atqb[ATQB_LENGTH]{}; //!< ATQB + struct { + uint8_t pupi[4]; //!< Pseudo-Unique PICC Identifier + uint8_t application[4]; //!< Application Data + uint8_t protocol[3]; //!< Protocol information + // uint8_t cid[1]; + } __attribute__((packed)); + } __attribute__((packed)); + Type type{Type::Unknown}; //!< Type + uint8_t cid{}; //!< CID; + uint8_t option{}; + + //! @brief Valid? + inline bool valid() const + { + return isISO14443_4(); + } + + std::string pupiAsString() const; //!< @brief Gets the pupi string + std::string typeAsString() const; //!< @brief Gets the type string + + ///@name Type + ///@{ + //! @brief ISO14443-4? + inline bool isISO14443_4() const + { + return supports_iso14443_4(protocol); + } + ///@} + + ///@name Information + ///@{ + inline bool supportsNAD() const + { + return get_frame_option(protocol) & FRAME_OPTION_NAD; + } + inline bool supportsCID() const + { + return get_frame_option(protocol) & FRAME_OPTION_CID; + } + inline uint16_t maximumFrmeLength() const + { + return maximum_frame_length(protocol); + } + inline uint8_t maximumFrmeLengthBits() const + { + return maximum_frame_length_bits(protocol); + } + inline uint8_t communicationSpeed() const + { + return protocol[0]; + } + ///@} +}; + +//! @brief Equal? +inline bool operator==(const PICC& a, const PICC& b) +{ + return std::memcmp(a.atqb, b.atqb, sizeof(a.atqb)) == 0; +} +//! @brief Not equal? +inline bool operator!=(const PICC& a, const PICC& b) +{ + return !(a == b); +} + +/*! + @enum Command + @brief ISO/IEC 14443 Type B command (Layer 3 / activation) + */ +enum class Command : uint8_t { + // ISO/IEC 14443B + REQ_WUPB = 0x05, ///< Request/Wakeup Type B + ATTRIB = 0x1D, ///< Attribute (activate ISO-DEP) + HLTB = 0x50, ///< Halt Type B (rarely used) + // ISO/IEC 14443-4 + DESELECT = 0xC2, //!< DESELECT + DESELECT_WITH_CID = 0xCA, //!< DESELECT with CID +}; + +///@name Timeout +///@{ +constexpr uint32_t TIMEOUT_REQ_WUP_B{5}; +constexpr uint32_t TIMEOUT_ATTRIB{5}; +constexpr uint32_t TIMEOUT_HLTB{5}; +constexpr uint32_t TIMEOUT_DESELECT{5}; +///@} + } // namespace b } // namespace nfc } // namespace m5 diff --git a/src/nfc/layer/nfc_layer_a.cpp b/src/nfc/layer/nfc_layer_a.cpp index 61cb3ab..b794d93 100644 --- a/src/nfc/layer/nfc_layer_a.cpp +++ b/src/nfc/layer/nfc_layer_a.cpp @@ -5,7 +5,7 @@ */ /*! @file nfc_layer_a.cpp - @brief Common layer for NFC-A related units + @brief Common layer for NFC-A */ #include "nfc_layer_a.hpp" #include "nfc/ndef/ndef.hpp" @@ -135,7 +135,7 @@ bool NFCLayerA::detect(std::vector& piccs, const uint32_t timeout_ms) bool NFCLayerA::select(m5::nfc::a::PICC& picc) { - _activePICC.clear(); + _activePICC = PICC{}; if (_impl->select(picc)) { _activePICC = picc; return true; @@ -145,7 +145,7 @@ bool NFCLayerA::select(m5::nfc::a::PICC& picc) bool NFCLayerA::activate(const PICC& picc) { - _activePICC.clear(); // (*1) + _activePICC = PICC{}; if (_impl->activate(picc)) { _activePICC = picc; return true; @@ -155,7 +155,6 @@ bool NFCLayerA::activate(const PICC& picc) bool NFCLayerA::reactivate(const PICC& picc) { - // If arg referrence is the same as _activePICC, it will cause an error, so it must be a separate instance (*1) PICC tmp = picc; uint16_t discard{}; if (deactivate()) { @@ -167,13 +166,12 @@ bool NFCLayerA::reactivate(const PICC& picc) bool NFCLayerA::deactivate() { + _activePICC = PICC{}; if (_activePICC.isISO14443_4()) { if (_impl->deactivate(true)) { return true; } } - - _activePICC.clear(); return _impl->deactivate(false); } @@ -184,6 +182,10 @@ bool NFCLayerA::identify(m5::nfc::a::PICC& picc) return ret; } +bool NFCLayerA::getVersion(uint8_t rx, uint16_t& rx_len) +{ +} + bool NFCLayerA::identify_picc(m5::nfc::a::PICC& picc) { Type type{}; @@ -201,11 +203,13 @@ bool NFCLayerA::identify_picc(m5::nfc::a::PICC& picc) } // GetVersion(L4) - uint8_t ver[8]{}; + uint8_t ver[16]{}; if (_impl->mifare_get_version_L4(ver)) { type = version4_to_type(picc.sub_type, ver); + // m5::utility::log::dump(ver, 16, false); } else { // Check historical bytes + // m5::utility::log::dump(ats.historical.data(), ats.historical_len, false); type = historical_bytes_to_type_sak20(picc.sub_type, ats.historical.data(), ats.historical_len, picc.atqa); } // If it's still unclassify at this stage, read more in SystemFile @@ -519,8 +523,10 @@ bool NFCLayerA::write_using_write16(const uint8_t addr, const uint8_t* tx, const bool NFCLayerA::dump(const Key& mkey) { if (_activePICC.valid()) { - if (_activePICC.isMifareClassic()) { - return dump_sector_structure(_activePICC, mkey); + if (_activePICC.isMifareClassic() || _activePICC.isMifarePlus()) { + Key keytmp{}; + // return dump_sector_structure(_activePICC, mkey); + return dump_sector_structure(_activePICC, keytmp); } else if (_activePICC.supportsNFC()) { return dump_page_structure(_activePICC.blocks); } diff --git a/src/nfc/layer/nfc_layer_a.hpp b/src/nfc/layer/nfc_layer_a.hpp index 8a9096c..9d55058 100644 --- a/src/nfc/layer/nfc_layer_a.hpp +++ b/src/nfc/layer/nfc_layer_a.hpp @@ -5,7 +5,7 @@ */ /*! @file nfc_layer_a.hpp - @brief Common layer for NFC-A related units + @brief Common layer for NFC-A @note Glossary - PCD: Proximity Coupling Device (reader) @@ -441,6 +441,13 @@ public: bool ndefWrite(const std::vector& tlvs); ///@} + + + bool getVersion(uint8_t rx, uint16_t& rx_len); + + + + protected: virtual bool read(uint8_t* rx, uint16_t& rx_len, const uint8_t saddr) override; virtual bool write(const uint8_t saddr, const uint8_t* tx, const uint16_t tx_len) override; diff --git a/src/nfc/layer/nfc_layer_b.cpp b/src/nfc/layer/nfc_layer_b.cpp new file mode 100644 index 0000000..9da0851 --- /dev/null +++ b/src/nfc/layer/nfc_layer_b.cpp @@ -0,0 +1,220 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +/*! + @file nfc_layer_b.hpp + @brief Common layer for NFC-B + + @note Glossary + - PCD: Proximity Coupling Device (reader) + - PICC: Proximity Integrated Circuit Card (card/tag, target device) + + @note In NFC Forum (NDEF) context, a PICC is often called a "Tag" +*/ +#include "nfc_layer_b.hpp" +#include "nfc/ndef/ndef.hpp" +#include "nfc/ndef/ndef_tlv.hpp" +#include +#include +#include +#include + +using namespace m5::nfc::b; +using namespace m5::nfc::ndef; + +namespace { + +inline bool exists_picc(const std::vector& v, const PICC& picc) +{ + return std::find_if(v.begin(), v.end(), [&picc](const PICC& p) { // + return memcmp(p.pupi, picc.pupi, 4) == 0; + }) != v.end(); +} + +constexpr uint8_t make_request_param(const bool wakeup, const Require slots) +{ + return (wakeup ? 0x08 : 0x00) | (m5::stl::to_underlying(slots) & 0x07); +} + +constexpr uint8_t required_slots(const Require slots) +{ + return 1U << m5::stl::to_underlying(slots); +} +} // namespace + +namespace m5 { +namespace unit { +namespace nfc { + +bool NFCLayerB::detect(m5::nfc::b::PICC& picc, const uint8_t afi, const uint32_t timeout_ms) +{ + std::vector piccs{}; + if (detect(piccs, afi, timeout_ms)) { + picc = piccs.front(); + return true; + } + return false; +} + +bool NFCLayerB::detect(std::vector& piccs, const uint8_t afi, const uint32_t timeout_ms) +{ + piccs.clear(); + + auto timeout_at = m5::utility::millis() + timeout_ms; + do { + uint8_t rx[ATQB_LENGTH * 16]{}; + uint16_t rx_len = sizeof(rx); + if (!request(rx, rx_len, afi, Require::Slot1)) { + continue; + } + + uint8_t picc_num = rx_len / ATQB_LENGTH; + for (uint_fast8_t i = 0; i < picc_num; ++i) { + PICC picc{}; + memcpy(picc.atqb, rx + i * ATQB_LENGTH, ATQB_LENGTH); + + M5_LIB_LOGV("Detected: %s", picc.pupiAsString().c_str()); + if (!exists_picc(piccs, picc)) { + hlt(picc.pupi); // If you don't perform hlt, it will be detected again + picc.type = Type::Unclassified; + piccs.emplace_back(picc); + } + } + if (piccs.size() >= 16) { + break; + } + } while (m5::utility::millis() <= timeout_at); + + return !piccs.empty(); +} + +bool NFCLayerB::select(m5::nfc::b::PICC& picc) +{ + // Wakeup for READY + uint16_t len = ATQB_LENGTH; + if (!wakeup(picc.atqb, len)) { + return false; + } + + // ATTRIB + uint8_t cmd[1 + 4 + 1 + 1 + 1 + 1] = {m5::stl::to_underlying(Command::ATTRIB)}; // without option + memcpy(cmd + 1, picc.pupi, 4); + cmd[5] = 0x00; // PARAM1 + cmd[6] = picc.maximumFrmeLengthBits(); // PARAM2 | com speed + cmd[7] = picc.protocol[1] & 0x0F; // PARAM 3protocol type + cmd[8] = 0x00; // PARAM 4 + + std::vector frame; + frame.assign(cmd, cmd + sizeof(cmd)); + + uint8_t rx[128]{}; + uint16_t rx_len = sizeof(rx); + if (!_impl->transceive(rx, rx_len, frame.data(), frame.size(), TIMEOUT_ATTRIB) || !rx_len) { + M5_LIB_LOGE("Failed to select"); + return false; + } + //m5::utility::log::dump(rx, rx_len, false); + // rx[0] MBLI(7:4) CID(3:0) + return true; +} + +bool NFCLayerB::hlt(const uint8_t pupi[4]) +{ + if (pupi) { + uint8_t cmd[1 + 4] = {m5::stl::to_underlying(Command::HLTB)}; + memcpy(cmd + 1, pupi, 4); + uint8_t rx[1]{}; + uint16_t rx_len = sizeof(rx); + if (!_impl->transceive(rx, rx_len, cmd, sizeof(cmd), TIMEOUT_HLTB) || rx_len < 1) { + M5_LIB_LOGE("Failed to hlt %02X%02X%02X%02X", cmd[1], cmd[2], cmd[3], cmd[4]); + return false; + } + return rx[0] == 0x00; + } + return false; +} + +bool NFCLayerB::deselect(const uint8_t pupi[4], const uint8_t cid) +{ + uint8_t cmd[2] = {m5::stl::to_underlying(cid != 0xFF ? Command::DESELECT_WITH_CID : Command::DESELECT)}; + uint16_t cmd_len = 1 + (cid != 0xFF); + if (cid != 0xFF) { + cmd[1] = cid; + } + uint8_t rx[2]{}; + uint16_t rx_len = cmd_len; + + if (!_impl->transceive(rx, rx_len, cmd, cmd_len, TIMEOUT_DESELECT) || rx_len < cmd_len) { + M5_LIB_LOGE("Failed to deselecte %02X:%02X", cmd[0], cmd[1]); + return false; + } + + if (memcmp(cmd, rx, cmd_len)) { + m5::utility::log::dump(cmd, cmd_len, false); + m5::utility::log::dump(rx, cmd_len, false); + return false; + } + return true; +} + +bool NFCLayerB::deactivate() +{ + PICC tmp = _activePICC; + _activePICC = PICC{}; + return deselect(tmp.pupi) || hlt(tmp.pupi); +} + +// +bool NFCLayerB::request_wakeup(uint8_t* atqb, uint16_t& atqb_len, const uint8_t afi, const Require slots, + const bool wakeup) +{ + if (!atqb || atqb_len < ATQB_LENGTH) { + return false; + } + + uint8_t cmd[] = {m5::stl::to_underlying(Command::REQ_WUPB), afi, make_request_param(wakeup, slots)}; + uint8_t rx[1 + ATQB_LENGTH + 2]{}; + uint16_t rx_len = sizeof(rx); + uint32_t offset{}; + m5::utility::CRC16 crc16(0XFFFF, 0x1021, true, true, 0XFFFF); + const auto max_slots = required_slots(slots); + const auto max_rx_len = atqb_len; + atqb_len = 0; + + // Ignore non-responsive slots and proceed to the next one. + if (_impl->transceive(rx, rx_len, cmd, sizeof(cmd), TIMEOUT_REQ_WUP_B, true) && rx_len == sizeof(rx) && + rx[0] == 0x50) { + // Occur collision if CRC error + const uint16_t crc = crc16.range(rx, ATQB_LENGTH + 1); + if (crc == ((uint16_t)rx[13] << 8 | rx[12])) { + memcpy(atqb, rx + 1, ATQB_LENGTH); + atqb_len += ATQB_LENGTH; + } + // hlt(rx + 1); // If you don't perform hlt, it will be detected again + } + + uint8_t slot_marker[1]{}; + for (uint_fast8_t i = 1; (offset + ATQB_LENGTH) < max_rx_len && i < max_slots; ++i) { + rx_len = sizeof(rx); + slot_marker[0] = ((uint8_t)i << 4) | 0x05; + // Ignore non-responsive slots and proceed to the next one. + if (!_impl->transceive(rx, rx_len, slot_marker, sizeof(slot_marker), TIMEOUT_REQ_WUP_B, true) || + rx[0] != 0x50 || rx_len < sizeof(rx)) { + continue; + } + // Occur collision if CRC error + const uint16_t crc = crc16.range(rx, 1 + ATQB_LENGTH); + if (crc == ((uint16_t)rx[13] << 8 | rx[12])) { + memcpy(atqb + atqb_len, rx + 1, ATQB_LENGTH); + atqb_len += ATQB_LENGTH; + } + // hlt(rx + 1); // If you don't perform hlt, it will be detected again + } + return atqb_len > 0; +} + +} // namespace nfc +} // namespace unit +} // namespace m5 diff --git a/src/nfc/layer/nfc_layer_b.hpp b/src/nfc/layer/nfc_layer_b.hpp new file mode 100644 index 0000000..b3bf901 --- /dev/null +++ b/src/nfc/layer/nfc_layer_b.hpp @@ -0,0 +1,192 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +/*! + @file nfc_layer_b.hpp + @brief Common layer for NFC-B + + @note Glossary + - PCD: Proximity Coupling Device (reader) + - PICC: Proximity Integrated Circuit Card (card/tag, target device) + + @note In NFC Forum (NDEF) context, a PICC is often called a "Tag" +*/ +#ifndef M5_UNIT_NFC_NFC_LAYER_NFC_LAYER_B_HPP +#define M5_UNIT_NFC_NFC_LAYER_NFC_LAYER_B_HPP + +#include "nfc/b/nfcb.hpp" +#include "ndef_layer.hpp" +#include +#include + +namespace m5 { + +namespace unit { +class UnitST25R3916; +class CapST25R3916; + +namespace nfc { + +/*! + @class NFCLayerB + @brief Common interface layer for each chip of the NFC-V reader + */ +class NFCLayerB : public m5::nfc::NFCLayerInterface { +public: + struct Adapter; + explicit NFCLayerB(UnitST25R3916& u); + explicit NFCLayerB(CapST25R3916& u); + + /*! + @brief Is the specified PICC currently active? + @param picc PICC to check + @return True if this PICC is the one currently selected (ACTIVE state) + */ + inline bool isActive(const m5::nfc::b::PICC& picc) const + { + return _activePICC.valid() && _activePICC == picc; + } + /*! + @brief Retrieve the currently activated PICC + @return Active PICC + @note Returns an empty PICC if no PICC is selected (no ACTIVE state) + */ + const m5::nfc::b::PICC& activatedPICC() const + { + return _activePICC; + } + + ///@name Detection and activation + ///@{ + /*! + @brief Send REQB to discover a PICC in IDLE + @param[out] atqb ATQB received from PICC (at atqb_len) + @param[in/out] in:atqb length out:actual received length + @param afi Application Family Identifier (0x00 all) + @param slots Number of slots required + @return True if successful + @note The ATQB per one of the PICC is 11 bytes + @post PICC transitions: IDLE -> READY on successful response + */ + inline bool request(uint8_t* atqb, uint16_t& atqb_len, const uint8_t afi = 0x00, + const m5::nfc::b::Require slots = m5::nfc::b::Require::Slot1) + { + return request_wakeup(atqb, atqb_len, afi, slots, false); + } + /*! + @brief Send WUPB to wake a PICC from IDLE or HALT + @param[out] atqb ATQB received from PICC (at least atqb_len) + @param[in/out] in:atqb length out:actual received length + @param afi Application Family Identifier (0x00 all) + @param slots Number of slots required + @return True if successful + @note The ATQB per one of the PICC is 11 bytes + @post PICC transitions: IDLE/HALT -> READY on successful response + */ + inline bool wakeup(uint8_t* atqb, uint16_t& atqb_len, const uint8_t afi = 0x00, + const m5::nfc::b::Require slots = m5::nfc::b::Require::Slot1) + { + return request_wakeup(atqb, atqb_len, afi, slots, true); + } + + /*! + @brief Detect single idle PICC + @param[out] picc Detected PICC + @param afi Application Family Identifier (0x00 all) + @param timeout_ms Polling time budget in milliseconds + @return True if detected + @note The detected PICC is typically put into HALT during enumeration to allow discovering others + */ + bool detect(m5::nfc::b::PICC& picc, const uint8_t afi = 0x00, const uint32_t timeout_ms = 100U); + /*! + @brief Detect idle PICCs + @param[out] piccs Detected PICC PICCs (one per activated PICC candidate) + @param afi Application Family Identifier (0x00 all) + @param timeout_ms Polling time budget in milliseconds + @return True if detected + @note The detected PICC is typically put into HALT during enumeration to allow discovering others + */ + bool detect(std::vector& piccs, const uint8_t afi = 0x00, const uint32_t timeout_ms = 1000U); + + /*! + */ + bool select(m5::nfc::b::PICC& picc); +#if 0 + bool activate(m5::nfc::b::PICC& picc); + bool reactivate(const m5::nfc::b::PICC& picc); + inline bool reactivate() + { + return reactivate(_activePICC); + } +#endif + + ///@} + + ///@name For activated PICC + ///@{ + bool hlt(const uint8_t pupi[4]); + bool deselect(const uint8_t pupi[4], const uint8_t cid = 0xFF); + bool deactivate(); + ///@} + +protected: + bool request_wakeup(uint8_t* atqb, uint16_t& atqb_len, const uint8_t afi, const m5::nfc::b::Require slots, + const bool wakeup); + + virtual bool read(uint8_t* rx, uint16_t& rx_len, const uint8_t saddr) override + { + return false; + } + virtual bool write(const uint8_t saddr, const uint8_t* tx, const uint16_t tx_len) override + { + return false; + } + inline virtual uint16_t first_user_block() const override + { + return 0; + } + inline virtual uint16_t last_user_block() const override + { + return 0; + } + inline virtual uint16_t user_area_size() const + { + return 0; + } + inline virtual uint16_t unit_size_read() const override + { + return 0; + } + inline virtual uint16_t unit_size_write() const override + { + return 0; + } + +protected: + m5::nfc::b::PICC _activePICC{}; + +private: + std::unique_ptr _impl; + m5::nfc::ndef::NDEFLayer _ndef; +}; + +///@cond +// Impl for units +struct NFCLayerB::Adapter { + virtual ~Adapter() = default; + + virtual bool transceive(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len, + const uint32_t timeout_ms, const bool rx_crc = false) = 0; + virtual bool transmit(const uint8_t* tx, const uint16_t tx_len, const uint32_t timeout_ms, + const bool rx_crc = false) = 0; + virtual bool receive(uint8_t* rx, uint16_t& rx_len, const uint32_t timeout_ms) = 0; +}; +///@endcond + +} // namespace nfc +} // namespace unit +} // namespace m5 + +#endif diff --git a/src/nfc/layer/nfc_layer_f.cpp b/src/nfc/layer/nfc_layer_f.cpp index a24770c..97c660e 100644 --- a/src/nfc/layer/nfc_layer_f.cpp +++ b/src/nfc/layer/nfc_layer_f.cpp @@ -5,7 +5,7 @@ */ /*! @file nfc_layer_f.cpp - @brief Common layer for NFC-F related units + @brief Common layer for NFC-F */ #include "nfc_layer_f.hpp" #include "nfc/ndef/ndef.hpp" diff --git a/src/nfc/layer/nfc_layer_f.hpp b/src/nfc/layer/nfc_layer_f.hpp index 7f2b8ef..75413fb 100644 --- a/src/nfc/layer/nfc_layer_f.hpp +++ b/src/nfc/layer/nfc_layer_f.hpp @@ -5,12 +5,11 @@ */ /*! @file nfc_layer_f.hpp - @brief Common layer for NFC-F related units + @brief Common layer for NFC-F @note Glossary - PCD: Proximity Coupling Device (reader) - PICC: Proximity Integrated Circuit Card (card/tag, target device) - - IDLE/READY/ACTIVE/HALT: ISO14443-3 state names @note In NFC Forum (NDEF) context, a PICC is often called a "Tag" */ diff --git a/src/nfc/layer/nfc_layer_v.cpp b/src/nfc/layer/nfc_layer_v.cpp index df52c10..18957a8 100644 --- a/src/nfc/layer/nfc_layer_v.cpp +++ b/src/nfc/layer/nfc_layer_v.cpp @@ -5,9 +5,8 @@ */ /*! @file nfc_layer_v.cpp - @brief Common layer for NFC-V related units + @brief Common layer for NFC-V */ - #include "nfc_layer_v.hpp" #include "nfc/ndef/ndef.hpp" #include "nfc/ndef/ndef_tlv.hpp" diff --git a/src/nfc/layer/nfc_layer_v.hpp b/src/nfc/layer/nfc_layer_v.hpp index 65cf7b3..412a85b 100644 --- a/src/nfc/layer/nfc_layer_v.hpp +++ b/src/nfc/layer/nfc_layer_v.hpp @@ -5,12 +5,11 @@ */ /*! @file nfc_layer_v.hpp - @brief Common layer for NFC-V related units + @brief Common layer for NFC-V @note Glossary - PCD: Proximity Coupling Device (reader) - PICC: Proximity Integrated Circuit Card (card/tag, target device) - - IDLE/READY/ACTIVE/HALT: ISO14443-3 state names @note In NFC Forum (NDEF) context, a PICC is often called a "Tag" */ diff --git a/src/nfc/layer/unit/nfc_layer_a_ST25R3916.cpp b/src/nfc/layer/unit/nfc_layer_a_ST25R3916.cpp index a51e811..0b0c270 100644 --- a/src/nfc/layer/unit/nfc_layer_a_ST25R3916.cpp +++ b/src/nfc/layer/unit/nfc_layer_a_ST25R3916.cpp @@ -74,7 +74,7 @@ bool AdapterST25R3916ForA::select(m5::nfc::a::PICC& picc) { uint8_t lv{1}; // Cascade level 1-3 bool completed{}; - picc.clear(); + picc = PICC{}; do { if (!_u.nfcaSelectWithAnticollision(completed, picc, lv)) { return false; diff --git a/src/nfc/layer/unit/nfc_layer_b_ST25R3916.cpp b/src/nfc/layer/unit/nfc_layer_b_ST25R3916.cpp new file mode 100644 index 0000000..0616bbc --- /dev/null +++ b/src/nfc/layer/unit/nfc_layer_b_ST25R3916.cpp @@ -0,0 +1,72 @@ +/* + * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD + * + * SPDX-License-Identifier: MIT + */ +/*! + @file nfc_layer_b_ST25R3916.cpp + @brief ST25R3916 NFC-B adapter for common layer +*/ +#include "nfc/layer/nfc_layer_b.hpp" +#include "nfc/layer/ndef_layer.hpp" +#include "unit/unit_ST25R3916.hpp" +#include + +using namespace m5::unit; +using namespace m5::unit::st25r3916; +using namespace m5::nfc::b; + +namespace m5 { +namespace unit { +namespace nfc { + +// +struct AdapterST25R3916ForB final : NFCLayerB::Adapter { + explicit AdapterST25R3916ForB(UnitST25R3916& ref) : _u{ref} + { + } + + bool transceive(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len, const uint32_t timeout_ms, + const bool rx_crc) override; + bool transmit(const uint8_t* tx, const uint16_t tx_len, const uint32_t timeout_ms, const bool rx_crc) override; + bool receive(uint8_t* rx, uint16_t& rx_len, const uint32_t timeout_ms) override; + + UnitST25R3916& _u; +}; + +bool AdapterST25R3916ForB::transceive(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len, + const uint32_t timeout_ms, const bool rx_crc) +{ + return _u.nfcbTransceive(rx, rx_len, tx, tx_len, timeout_ms, rx_crc); +} + +bool AdapterST25R3916ForB::transmit(const uint8_t* tx, const uint16_t tx_len, const uint32_t timeout_ms, + const bool rx_crc) +{ + return _u.nfcbTransmit(tx, tx_len, timeout_ms, rx_crc); +} + +bool AdapterST25R3916ForB::receive(uint8_t* rx, uint16_t& rx_len, const uint32_t timeout_ms) +{ + return _u.nfcbReceive(rx, rx_len, timeout_ms); +} + +// +namespace { +std::unique_ptr make_st25r3916_adapter(UnitST25R3916& u) +{ + return std::unique_ptr(new AdapterST25R3916ForB(u)); +} +} // namespace + +NFCLayerB::NFCLayerB(UnitST25R3916& u) : _impl(make_st25r3916_adapter(u)), _ndef{*this} +{ +} + +NFCLayerB::NFCLayerB(CapST25R3916& u) : _impl(make_st25r3916_adapter(static_cast(u))), _ndef{*this} +{ +} + +} // namespace nfc +} // namespace unit +} // namespace m5 diff --git a/src/nfc/layer/unit/nfc_layer_v_ST25R3916.cpp b/src/nfc/layer/unit/nfc_layer_v_ST25R3916.cpp index b3d884f..4584c32 100644 --- a/src/nfc/layer/unit/nfc_layer_v_ST25R3916.cpp +++ b/src/nfc/layer/unit/nfc_layer_v_ST25R3916.cpp @@ -4,8 +4,8 @@ * SPDX-License-Identifier: MIT */ /*! - @file nfc_layer_f_ST25R3916.cpp - @brief ST25R3916 NFC-F adapter for common layer + @file nfc_layer_v_ST25R3916.cpp + @brief ST25R3916 NFC-V adapter for common layer */ #include "nfc/layer/nfc_layer_v.hpp" #include "nfc/layer/ndef_layer.hpp" diff --git a/src/nfc/v/nfcv.cpp b/src/nfc/v/nfcv.cpp index 9622cdc..aaafa72 100644 --- a/src/nfc/v/nfcv.cpp +++ b/src/nfc/v/nfcv.cpp @@ -15,27 +15,29 @@ using namespace m5::nfc::v; namespace { -constexpr char name_unknown[] = "Unknown"; -constexpr char nxp_icode_sli[] = "ICODE SLI"; -constexpr char nxp_icode_slix[] = "ICODE SLIX"; -constexpr char nxp_icode_slix2[] = "ICODE SLIX2"; -constexpr char nxp[] = "NXP(Unclassified)"; -constexpr char ti_tagit_hf_i[] = "Tag-it HF-I"; -constexpr char ti_tagit_hf_i_plus[] = "Tag-it HF-I Plus"; -constexpr char ti_tagit_hf_i_pro[] = "Tag-it HF-I Pro"; -constexpr char ti[] = "TI(Unclassified)"; -constexpr char st_lri[] = "ST LRI"; -constexpr char st_st25v[] = "ST25V"; -constexpr char st[] = "ST(Unclassified)"; -constexpr char fujitsu_fram[] = "FRAM"; -constexpr char fujitsu[] = "Fujitsu(Unclassified)"; -constexpr char unclassified[] = "Unclassified"; +constexpr char name_unknown[] = "Unknown"; +constexpr char name_sli[] = "ICODE SLI"; +constexpr char name_slix[] = "ICODE SLIX"; +constexpr char name_slix2[] = "ICODE SLIX2"; +constexpr char name_nxp[] = "NXP(Unclassified)"; +constexpr char name_hf_i[] = "Tag-it HF-I"; +constexpr char name_hf_i_plus[] = "Tag-it HF-I Plus"; +constexpr char name_hf_i_pro[] = "Tag-it HF-I Pro"; +constexpr char name_ti[] = "TI(Unclassified)"; +constexpr char name_lri[] = "ST LRI"; +constexpr char name_st25v[] = "ST25V"; +constexpr char name_st[] = "ST(Unclassified)"; +constexpr char name_fram[] = "FRAM"; +constexpr char name_fujitsu[] = "Fujitsu(Unclassified)"; +constexpr char name_unclassified[] = "Unclassified"; constexpr const char* name_table[] = { - name_unknown, // - nxp_icode_sli, nxp_icode_slix, nxp_icode_slix2, nxp, // - ti_tagit_hf_i, ti_tagit_hf_i_plus, ti_tagit_hf_i_pro, ti, st_lri, st_st25v, st, fujitsu_fram, - fujitsu, unclassified, + name_unknown, // + name_sli, name_slix, name_slix2, name_nxp, // + name_hf_i, name_hf_i_plus, name_hf_i_pro, name_ti, // + name_lri, name_st25v, name_st, // + name_fram, name_fujitsu, // + name_unclassified, }; constexpr uint8_t FLAG_TWO_SUBCARRIERS{0x01}; diff --git a/src/unit/unit_ST25R3916.hpp b/src/unit/unit_ST25R3916.hpp index 77dc2e3..dca01c2 100644 --- a/src/unit/unit_ST25R3916.hpp +++ b/src/unit/unit_ST25R3916.hpp @@ -1877,6 +1877,10 @@ public: // ---------------------------------------------------------------------------------------------- ///@name NFC-B ///@{ + bool nfcbTransceive(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len, + const uint32_t timeout_ms, const bool rx_crc); + bool nfcbTransmit(const uint8_t* tx, const uint16_t tx_len, const uint32_t timeout_ms, const bool rx_crc); + bool nfcbReceive(uint8_t* rx, uint16_t& rx_len, const uint32_t timeout_ms); ///@} // ---------------------------------------------------------------------------------------------- diff --git a/src/unit/unit_ST25R3916_nfca.cpp b/src/unit/unit_ST25R3916_nfca.cpp index 47d8ac3..8b8708c 100644 --- a/src/unit/unit_ST25R3916_nfca.cpp +++ b/src/unit/unit_ST25R3916_nfca.cpp @@ -707,11 +707,12 @@ bool UnitST25R3916::mifare_classic_authenticate(const Command cmd, const PICC& p { CHECK_MODE(); - if ((cmd != Command::AUTH_WITH_KEY_A && cmd != Command::AUTH_WITH_KEY_B) || !picc.isMifareClassic()) { + if ((cmd != Command::AUTH_WITH_KEY_A && cmd != Command::AUTH_WITH_KEY_B) || + (!picc.isMifareClassic() && picc.isMifarePlus())) { return false; } - M5_LIB_LOGD("AUTH:%02X %u %02X:%02X:%02X:%02X:%02X:%02X", cmd, block, // + M5_LIB_LOGE("AUTH:%02X %u %02X:%02X:%02X:%02X:%02X:%02X", cmd, block, // mkey[0], mkey[1], mkey[2], mkey[3], mkey[4], mkey[5]); // 3-pass mutual authentication diff --git a/src/unit/unit_ST25R3916_nfcb.cpp b/src/unit/unit_ST25R3916_nfcb.cpp index 068a01c..df8f496 100644 --- a/src/unit/unit_ST25R3916_nfcb.cpp +++ b/src/unit/unit_ST25R3916_nfcb.cpp @@ -29,6 +29,14 @@ using namespace m5::nfc::b; } while (0) namespace { + +constexpr uint8_t val_table[] = { + 0x07, 0x3C, 0xCB, 0x14, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x38, 0x00, 0x04, 0x3D, 0x00, 0x00, 0x07, + 0x10, 0x0D, 0x23, 0x00, 0x58, 0x80, 0x85, 0xA6, 0x0F, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x00, 0xE1, 0x82, 0x82, 0x70, 0x5F, 0x13, 0x02, 0x00, 0xAB, 0x38, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + } // namespace namespace m5 { @@ -36,9 +44,181 @@ namespace unit { // -------------------------------- For NFC-B bool UnitST25R3916::configure_nfc_b() { - M5_LIB_LOGE("Not yet"); - return false; + uint8_t reg = 0x00; + for (auto&& v : val_table) { + // if (reg < 2) { + // continue; + // } + write_register8(reg, v); + ++reg; + } + + { + uint16_t r{}; + r = 0x05; + writeRegister8(r, 0xC4); + r = 0x06; + writeRegister8(r, 0x14); + r = 0x0B; + writeRegister8(r, 0x0C); + r = 0x0C; + writeRegister8(r, 0x1B); + r = 0x0D; + writeRegister8(r, 0x00); + r = 0x0F; + writeRegister8(r, 0x00); + r = 0x15; + writeRegister8(r, 0x00); + r = 0x28; + writeRegister8(r, 0x10); + r = 0x29; + writeRegister8(r, 0x7C); + r = 0x2A; + writeRegister8(r, 0x80); + r = 0x2B; + writeRegister8(r, 0x04); + r = 0x2C; + writeRegister8(r, 0xD0); + } + + nfc_initial_field_on(); + + return true; +} + +bool UnitST25R3916::nfcbTransceive(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len, + const uint32_t timeout_ms, const bool rx_crc) +{ + return nfcbTransmit(tx, tx_len, timeout_ms, rx_crc) && nfcbReceive(rx, rx_len, timeout_ms); +} + +bool UnitST25R3916::nfcbTransmit(const uint8_t* tx, const uint16_t tx_len, const uint32_t timeout_ms, const bool rx_crc) +{ + CHECK_MODE(); + + if (!tx || !tx_len) { + return false; + } + if (timeout_ms && !write_noresponse_timeout(timeout_ms)) { + return false; + } + + if (!modify_bit_register8(REG_AUXILIARY_DEFINITION, rx_crc ? 0x00 : no_crc_rx, no_crc_rx) || // + !clearInterrupts() || !writeDirectCommand(CMD_CLEAR_FIFO) || !writeFIFO(tx, tx_len) || + !writeNumberOfTransmittedBytes(tx_len, 0) || !writeDirectCommand(CMD_TRANSMIT_WITH_CRC)) { + return false; + } + return true; +} + +bool UnitST25R3916::nfcbReceive(uint8_t* rx, uint16_t& rx_len, const uint32_t timeout_ms) +{ + CHECK_MODE(); + + const auto rx_len_org = rx_len; + rx_len = 0; + if (!rx || !rx_len_org) { + return false; + } + + uint8_t rbuf[256]{}; + if (!wait_for_FIFO(timeout_ms, sizeof(rbuf))) { + return false; + } + uint16_t actual{}; + auto bb = readFIFO(actual, rbuf, sizeof(rbuf)); + if (!bb) { + M5_LIB_LOGD("Failed to readFIFO %u/%u", actual, rx_len_org); + return false; + } + rx_len = std::min(actual, rx_len_org); + memcpy(rx, rbuf, rx_len); + return true; } } // namespace unit } // namespace m5 + +/* +14:07:01.211 > [ 5260][I][RFAL.cpp:44] dump_regs(): Reg[0x00]:0x07:00000111 +14:07:01.217 > [ 5267][I][RFAL.cpp:44] dump_regs(): Reg[0x01]:0x3C:00111100 +14:07:01.223 > [ 5273][I][RFAL.cpp:44] dump_regs(): Reg[0x02]:0xCB:11001011 +14:07:01.230 > [ 5279][I][RFAL.cpp:44] dump_regs(): Reg[0x03]:0x14:00010100 +14:07:01.236 > [ 5286][I][RFAL.cpp:44] dump_regs(): Reg[0x04]:0x00:00000000 +14:07:01.243 > [ 5292][I][RFAL.cpp:44] dump_regs(): Reg[0x05]:0x00:00000000 +14:07:01.249 > [ 5299][I][RFAL.cpp:44] dump_regs(): Reg[0x06]:0x00:00000000 +14:07:01.256 > [ 5305][I][RFAL.cpp:44] dump_regs(): Reg[0x07]:0x00:00000000 +14:07:01.262 > [ 5312][I][RFAL.cpp:44] dump_regs(): Reg[0x08]:0x5D:01011101 +14:07:01.268 > [ 5318][I][RFAL.cpp:44] dump_regs(): Reg[0x09]:0x38:00111000 +14:07:01.275 > [ 5324][I][RFAL.cpp:44] dump_regs(): Reg[0x0A]:0x00:00000000 +14:07:01.281 > [ 5331][I][RFAL.cpp:44] dump_regs(): Reg[0x0B]:0x04:00000100 +14:07:01.288 > [ 5337][I][RFAL.cpp:44] dump_regs(): Reg[0x0C]:0x3D:00111101 +14:07:01.294 > [ 5344][I][RFAL.cpp:44] dump_regs(): Reg[0x0D]:0x00:00000000 +14:07:01.301 > [ 5350][I][RFAL.cpp:44] dump_regs(): Reg[0x0E]:0x00:00000000 +14:07:01.307 > [ 5357][I][RFAL.cpp:44] dump_regs(): Reg[0x0F]:0x07:00000111 +14:07:01.313 > [ 5363][I][RFAL.cpp:44] dump_regs(): Reg[0x10]:0x10:00010000 +14:07:01.320 > [ 5369][I][RFAL.cpp:44] dump_regs(): Reg[0x11]:0x0D:00001101 +14:07:01.326 > [ 5376][I][RFAL.cpp:44] dump_regs(): Reg[0x12]:0x23:00100011 +14:07:01.333 > [ 5382][I][RFAL.cpp:44] dump_regs(): Reg[0x13]:0x00:00000000 +14:07:01.339 > [ 5389][I][RFAL.cpp:44] dump_regs(): Reg[0x14]:0x58:01011000 +14:07:01.345 > [ 5395][I][RFAL.cpp:44] dump_regs(): Reg[0x15]:0x80:10000000 +14:07:01.352 > [ 5401][I][RFAL.cpp:44] dump_regs(): Reg[0x16]:0x85:10000101 +14:07:01.358 > [ 5408][I][RFAL.cpp:44] dump_regs(): Reg[0x17]:0xA6:10100110 +14:07:01.365 > [ 5414][I][RFAL.cpp:44] dump_regs(): Reg[0x18]:0x0F:00001111 +14:07:01.371 > [ 5421][I][RFAL.cpp:44] dump_regs(): Reg[0x19]:0x7B:01111011 +14:07:01.378 > [ 5427][I][RFAL.cpp:44] dump_regs(): Reg[0x1A]:0x00:00000000 +14:07:01.384 > [ 5434][I][RFAL.cpp:44] dump_regs(): Reg[0x1B]:0x00:00000000 +14:07:01.390 > [ 5440][I][RFAL.cpp:44] dump_regs(): Reg[0x1C]:0x00:00000000 +14:07:01.397 > [ 5446][I][RFAL.cpp:44] dump_regs(): Reg[0x1D]:0x00:00000000 +14:07:01.403 > [ 5453][I][RFAL.cpp:44] dump_regs(): Reg[0x1E]:0x02:00000010 +14:07:01.410 > [ 5459][I][RFAL.cpp:44] dump_regs(): Reg[0x1F]:0x00:00000000 +14:07:01.416 > [ 5466][I][RFAL.cpp:44] dump_regs(): Reg[0x20]:0x00:00000000 +14:07:01.423 > [ 5472][I][RFAL.cpp:44] dump_regs(): Reg[0x21]:0x00:00000000 +14:07:01.429 > [ 5479][I][RFAL.cpp:44] dump_regs(): Reg[0x22]:0x00:00000000 +14:07:01.435 > [ 5485][I][RFAL.cpp:44] dump_regs(): Reg[0x23]:0x48:01001000 +14:07:01.442 > [ 5491][I][RFAL.cpp:44] dump_regs(): Reg[0x24]:0x00:00000000 +14:07:01.448 > [ 5498][I][RFAL.cpp:44] dump_regs(): Reg[0x25]:0xE1:11100001 +14:07:01.455 > [ 5504][I][RFAL.cpp:44] dump_regs(): Reg[0x26]:0x82:10000010 +14:07:01.461 > [ 5511][I][RFAL.cpp:44] dump_regs(): Reg[0x27]:0x82:10000010 +14:07:01.468 > [ 5517][I][RFAL.cpp:44] dump_regs(): Reg[0x28]:0x70:01110000 +14:07:01.474 > [ 5524][I][RFAL.cpp:44] dump_regs(): Reg[0x29]:0x5F:01011111 +14:07:01.480 > [ 5530][I][RFAL.cpp:44] dump_regs(): Reg[0x2A]:0x13:00010011 +14:07:01.487 > [ 5536][I][RFAL.cpp:44] dump_regs(): Reg[0x2B]:0x02:00000010 +14:07:01.493 > [ 5543][I][RFAL.cpp:44] dump_regs(): Reg[0x2C]:0x00:00000000 +14:07:01.500 > [ 5549][I][RFAL.cpp:44] dump_regs(): Reg[0x2D]:0xAB:10101011 +14:07:01.506 > [ 5556][I][RFAL.cpp:44] dump_regs(): Reg[0x2E]:0x38:00111000 +14:07:01.512 > [ 5562][I][RFAL.cpp:44] dump_regs(): Reg[0x2F]:0x00:00000000 +14:07:01.519 > [ 5568][I][RFAL.cpp:44] dump_regs(): Reg[0x30]:0x00:00000000 +14:07:01.525 > [ 5575][I][RFAL.cpp:44] dump_regs(): Reg[0x31]:0x10:00010000 +14:07:01.532 > [ 5581][I][RFAL.cpp:44] dump_regs(): Reg[0x32]:0x00:00000000 +14:07:01.538 > [ 5588][I][RFAL.cpp:44] dump_regs(): Reg[0x33]:0x00:00000000 +14:07:01.545 > [ 5594][I][RFAL.cpp:44] dump_regs(): Reg[0x34]:0x00:00000000 +14:07:01.551 > [ 5601][I][RFAL.cpp:44] dump_regs(): Reg[0x35]:0x00:00000000 +14:07:01.557 > [ 5607][I][RFAL.cpp:44] dump_regs(): Reg[0x36]:0x00:00000000 +14:07:01.564 > [ 5613][I][RFAL.cpp:44] dump_regs(): Reg[0x37]:0x00:00000000 +14:07:01.570 > [ 5620][I][RFAL.cpp:44] dump_regs(): Reg[0x38]:0x00:00000000 +14:07:01.577 > [ 5626][I][RFAL.cpp:44] dump_regs(): Reg[0x39]:0x00:00000000 +14:07:01.583 > [ 5633][I][RFAL.cpp:44] dump_regs(): Reg[0x3A]:0x00:00000000 +14:07:01.590 > [ 5639][I][RFAL.cpp:44] dump_regs(): Reg[0x3B]:0x00:00000000 +14:07:01.596 > [ 5646][I][RFAL.cpp:44] dump_regs(): Reg[0x3C]:0x00:00000000 +14:07:01.602 > [ 5652][I][RFAL.cpp:44] dump_regs(): Reg[0x3D]:0x00:00000000 +14:07:01.609 > [ 5658][I][RFAL.cpp:44] dump_regs(): Reg[0x3E]:0x00:00000000 +14:07:01.615 > [ 5665][I][RFAL.cpp:44] dump_regs(): Reg[0x3F]:0x2A:00101010 +14:07:01.620 > [ 5671][W][RFAL.cpp:46] dump_regs(): SpaceB +14:07:01.627 > [ 5676][I][RFAL.cpp:48] dump_regs(): Reg[0x00]:0xC4:11000100 +14:07:01.633 > [ 5683][I][RFAL.cpp:48] dump_regs(): Reg[0x01]:0x14:00010100 +14:07:01.640 > [ 5689][I][RFAL.cpp:48] dump_regs(): Reg[0x02]:0x0C:00001100 +14:07:01.646 > [ 5695][I][RFAL.cpp:48] dump_regs(): Reg[0x03]:0x1B:00011011 +14:07:01.652 > [ 5702][I][RFAL.cpp:48] dump_regs(): Reg[0x04]:0x00:00000000 +14:07:01.659 > [ 5708][I][RFAL.cpp:48] dump_regs(): Reg[0x05]:0x00:00000000 +14:07:01.665 > [ 5715][I][RFAL.cpp:48] dump_regs(): Reg[0x06]:0x00:00000000 +14:07:01.672 > [ 5721][I][RFAL.cpp:48] dump_regs(): Reg[0x07]:0x10:00010000 +14:07:01.678 > [ 5728][I][RFAL.cpp:48] dump_regs(): Reg[0x08]:0x7C:01111100 +14:07:01.684 > [ 5734][I][RFAL.cpp:48] dump_regs(): Reg[0x09]:0x80:10000000 +14:07:01.691 > [ 5740][I][RFAL.cpp:48] dump_regs(): Reg[0x0A]:0x04:00000100 +14:07:01.697 > [ 5747][I][RFAL.cpp:48] dump_regs(): Reg[0x0B]:0xD0:11010000 +14:07:01.704 > [ 5753][I][RFAL.cpp:48] dump_regs(): Reg[0x0C]:0x00:00000000 +14:07:01.710 > [ 5760][I][RFAL.cpp:48] dump_regs(): Reg[0x0D]:0x00:00000000 +14:07:01.717 > [ 5766][I][RFAL.cpp:48] dump_regs(): Reg[0x0E]:0x00:00000000 +14:07:01.723 > [ 5773][I][RFAL.cpp:48] dump_regs(): Reg[0x0F]:0x00:00000000 +*/ diff --git a/src/unit/unit_ST25R3916_nfcv.cpp b/src/unit/unit_ST25R3916_nfcv.cpp index 2870101..2d79aaf 100644 --- a/src/unit/unit_ST25R3916_nfcv.cpp +++ b/src/unit/unit_ST25R3916_nfcv.cpp @@ -30,7 +30,7 @@ using namespace m5::nfc::v; namespace { -uint8_t val_table[] = { +constexpr uint8_t val_table[] = { 0x07, 0x3C, 0xCB, 0x70, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x38, 0x01, 0x13, 0x2D, 0x00, 0x00, 0x41, 0x00, 0x52, 0x20, 0x01, 0x84, 0x80, 0x85, 0xA7, 0x0F, 0x7B, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x00, 0xE0, 0x82, 0x82, 0x70, 0x5F, 0x13, 0x02, 0x00, 0xCB, 0x00, 0x00, @@ -96,8 +96,8 @@ bool UnitST25R3916::configure_nfc_v() #if 1 uint8_t reg = 0x00; for (auto&& v : val_table) { + if(reg < 2){continue; } write_register8(reg, v); - // } ++reg; }