Add support NFC-F(WIP)

This commit is contained in:
GOB
2025-11-27 19:30:15 +09:00
parent 6f6e2508b0
commit b4e2f0cb7d
18 changed files with 1501 additions and 235 deletions
@@ -0,0 +1,10 @@
/*
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
/*
Example using M5UnitUnified for M5Cardputer-ADV with HackerCap
Detect NFC-A PICC
*/
#include "main/Detect.cpp"
@@ -0,0 +1,95 @@
/*
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
/*
Example using M5UnitUnified for M5Cardputer-ADV with HackerCap
Detect NFC-F PICC
*/
#include <M5Unified.h>
#include <M5UnitUnified.h>
#include <M5UnitUnifiedNFC.h>
#include <M5Utility.h>
#include <vector>
using namespace m5::nfc;
using namespace m5::nfc::f;
namespace {
auto& lcd = M5.Display;
m5::unit::UnitUnified Units;
m5::unit::CapST25R3916 cap; // ST25R3916 in the HackerCap
m5::unit::nfc::NFCLayerF nfc_f{cap};
} // namespace
void setup()
{
M5.begin();
auto cfg = cap.config();
cfg.mode = NFC::F;
cap.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 (!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 */);
}
delay(1000);
SPISettings settings = {10000000, MSBFIRST, SPI_MODE1};
if (!Units.add(cap, SPI, settings) || !Units.begin()) {
M5_LOGE("Failed to begin");
lcd.fillScreen(TFT_RED);
while (true) {
m5::utility::delay(10000);
}
}
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);
//
// cap.dumpRegister();
//
}
void loop()
{
M5.update();
Units.update();
std::vector<PICC> piccs;
// if (nfc_f.detect(piccs)) {
if (nfc_f.detect(piccs, 0x0003)) {
M5.Speaker.tone(3000, 10);
M5.Log.printf("%zu PICC\n", piccs.size());
for (auto&& picc : piccs) {
M5.Log.printf(" %s:%s %02X\n", picc.idmAsString().c_str(), picc.pmmAsString().c_str(), picc.format);
}
}
}
+10
View File
@@ -141,3 +141,13 @@ build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/NFCA/NDEF>
build_flags = ${option_release.build_flags}
${CardputerADV.build_flags}
; NFC-F
[env:CapHacker_NFCF_Detect_CardputerADV_Arduino_latest]
extends=CardputerADV, option_release, arduino_latest
build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/NFCF/Detect>
build_flags = ${option_release.build_flags}
${CardputerADV.build_flags}
+1
View File
@@ -22,6 +22,7 @@
#include "unit/unit_ST25R3916.hpp"
#include "nfc/layer/nfc_layer_a.hpp"
#include "nfc/layer/nfc_layer_f.hpp"
/*!
@namespace m5
+44
View File
@@ -0,0 +1,44 @@
/*
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
/*!
@file nfcf.cpp
@brief NFC-F definitions
*/
#include "nfcf.hpp"
#include <M5Utility.hpp>
namespace {
std::string to_string(const uint8_t* p, const uint8_t size)
{
char buf[2 * size + 1]{};
if (p && size) {
uint8_t left{};
for (uint_fast8_t i = 0; i < size; ++i) {
left += snprintf(buf + left, 3, "%02X", p[i]);
}
}
return std::string(buf);
}
} // namespace
namespace m5 {
namespace nfc {
namespace f {
std::string PICC::idmAsString() const
{
return to_string(this->idm.data(), this->idm.size());
}
std::string PICC::pmmAsString() const
{
return to_string(this->pmm.data(), this->pmm.size());
}
} // namespace f
} // namespace nfc
} // namespace m5
+104 -6
View File
@@ -11,6 +11,7 @@
#define M5_UNIT_UNIFIED_NFC_NFC_F_NFCF_HPP
#include <cstdint>
#include <array>
namespace m5 {
namespace nfc {
@@ -26,17 +27,114 @@ namespace f {
*/
enum class Type : uint8_t {
Unknown, //!< Unknown type
FeliCaStandard,
FeliCaLiteS,
FelicaPlugin,
};
///@name Format bits
///@{
using Format = uint8_t;
constexpr Format format_nfcip1{0x0001};
constexpr Format format_dfc{0x0002};
constexpr Format format_private{0x0004};
constexpr Format format_ndef{0x0008};
constexpr Format format_shared{0x0010};
constexpr Format format_secure{0x0020};
///@}
using IDm = std::array<uint8_t, 8>; //!< Manufacture ID
using PMm = std::array<uint8_t, 8>; //!< Manufacture Parameter
/*!
@enum CommandCode
@brief NFC-F Command code
*/
enum class CommandCode : uint8_t {
Polling,
RequestService = 0x02,
RequestResponse = 0x04,
};
/*!
@struct IDm
@brief The Idm(Identifier for Manufacturer) of the PICC
*/
struct IDm {
//! @brief uid data
uint8_t uid[8]{};
@enum ResponseCode
@brief NFC-F Response code
*/
enum class ResponseCode : uint8_t {
Polling = 0x01,
RequestService = 0x03,
};
///@name SystemCode
///@{
constexpr uint16_t system_code_wildcard{0xFFFF}; //!< Wildcard
constexpr uint16_t system_code_ndef{0x12FC}; //!< NDEF
constexpr uint16_t system_code_secure{0x957A}; //!< FeliCa secure ID
constexpr uint16_t system_code_shared{0xFE00}; //!< Shared area
constexpr uint16_t system_code_dfc{0x8884}; //!< DFC
///@}
/*!
@enum RequestCode
@brief Request code for Polling
*/
enum class RequestCode : uint8_t {
None, //!< No request
SystemCode, //!< Request system code
CommunicationPerformance, //!< Request communication performance
};
/*!
@enum TimeSlot
@brief Timeslot value for Polling
*/
enum class TimeSlot : uint8_t { Slot1, Slot2, Slot4 = 0x03, Slot8 = 0x07, Slot16 = 0x0F };
//! @brief TimeSlot to the number of the slot
inline constexpr uint8_t timeslot_to_slot(const TimeSlot ts)
{
return (ts == TimeSlot::Slot16) ? 16
: (ts == TimeSlot::Slot8) ? 8
: (ts == TimeSlot::Slot4) ? 4
: (ts == TimeSlot::Slot2) ? 2
: (ts == TimeSlot::Slot1) ? 1
: 0; // Illegal
}
/*!
@strutc PICC
@brief PICC informationg for NFC-F
*/
struct PICC {
IDm idm{}; //!< Manufacture ID
PMm pmm{}; //!< //!< Manufacture Parameter
uint16_t request_data{}; //!< Any request data
RequestCode request_code{}; //!< Tyepe of the request_data
Format format{}; //!< Format type group bits
//! @breif Gets the IDm string for debug
std::string idmAsString() const;
//! @breif Gets the PMm string for debug
std::string pmmAsString() const;
};
//! @brief Equal?
inline bool operator==(const PICC& a, const PICC& b)
{
return a.idm == b.idm && a.pmm == b.pmm;
}
//! @brief Not equal?
inline bool operator!=(const PICC& a, const PICC& b)
{
return !(a == b);
}
///@name Timeout
///@{
constexpr uint32_t TIMEOUT_POLLING{3};
constexpr uint32_t TIMEOUT_POLLING_PICC{2}; // 2 ms per PICC
} // namespace f
} // namespace nfc
} // namespace m5
+3 -1
View File
@@ -631,6 +631,8 @@ bool NFCLayerA::mifareUltralightChangeFormatToNTAG()
M5_LIB_LOGE("Failed to write4");
return false;
}
// Verify
return ntag_check_format();
}
}
return true;
@@ -662,7 +664,7 @@ bool NFCLayerA::ndefRead(std::vector<m5::nfc::ndef::Message>& msgs, const m5::nf
bool NFCLayerA::ndefWrite(const m5::nfc::ndef::Message& msg)
{
std::vector<Message> msgs = {msg};
return _activeUID.supportsNFC() && _ndef.write(msgs);
return msg.isNDEFMessage() && _activeUID.supportsNFC() && _ndef.write(msgs);
}
bool NFCLayerA::ndefWrite(const std::vector<m5::nfc::ndef::Message>& msgs)
+10 -12
View File
@@ -19,8 +19,8 @@
#include "nfc/a/nfca.hpp"
#include "ndef_layer.hpp"
#include <memory>
#include <vector>
#include <memory>
namespace m5 {
@@ -83,7 +83,7 @@ public:
@brief Detect idle PICCs
@param[out] uids Detected PICC UIDs (one per activated PICC candidate)
@param timeout_ms Polling time budget in milliseconds
@return True if successful
@return True if detected
@note The selected PICC is typically put into HALT during enumeration to allow discovering others
*/
bool detect(std::vector<m5::nfc::a::UID>& uids, const uint32_t timeout_ms = 10 * 1000U);
@@ -339,11 +339,12 @@ public:
bool mifareClassicRestoreValueBlock(const uint8_t block);
/*!
@brief Write change to NFC Type-2 (NDEF) format
@brief Write change to NFC Type-2 (NDEF) format for MIFARE Ultralight/C
@return True if successful
@note Returns true if the data is already in NDEF format or if the PICC is an NTAG
@warning Only MIFARE Ultralight,UltralightC
@warning Changes are irreversible and cannot be undone
@warning If the relevant area has already been overwritten, changes may not be possible
*/
bool mifareUltralightChangeFormatToNTAG();
///@}
@@ -365,7 +366,7 @@ public:
*/
bool ndefRead(m5::nfc::ndef::Message& msg);
/*!
@brief Read any NDEF Message
@brief Read any NDEF TLV
@param[out] msgs Messgae vector
@param tagBits Bit indicating the group of NDEF tags to be read
@return True if successful
@@ -374,8 +375,8 @@ public:
bool ndefRead(std::vector<m5::nfc::ndef::Message>& msgs,
const m5::nfc::ndef::TagBits tagBits = m5::nfc::ndef::tagBitsAll);
/*!
@brief Write NDEF message TLV
@param msg Messgae
@brief Write NDEF message
@param msg Messgae (NDEF Message)
@return True if successful
@note Other existing tags will be preserved
@warning Existing NDEF message TLVs will be overwritten
@@ -383,7 +384,7 @@ public:
*/
bool ndefWrite(const m5::nfc::ndef::Message& msg);
/*!
@brief Write any NDEF Messages
@brief Write any NDEF Messages TLV
@param msgs Messgae vector
@return True if successful
@note Write starting from the beginning of the user area
@@ -442,6 +443,7 @@ private:
m5::nfc::ndef::NDEFLayer _ndef;
};
///@cond
// Impl for units
struct NFCLayerA::Adapter {
virtual ~Adapter() = default;
@@ -466,12 +468,8 @@ struct NFCLayerA::Adapter {
virtual bool ntag_read_page(uint8_t* rx, uint16_t& rx_len, const uint8_t spage,
const uint8_t epage) = 0; // FAST_READ
// virtual bool mifare_classic_read_block(uint8_t* rx, uint16_t& rx_len, const uint16_t addr) = 0;
// virtual bool mifare_classic_write_block(const uint16_t addr, const uint8_t* tx, const uint16_t tx_len) = 0;
protected:
};
///@endcond
} // namespace nfc
} // namespace unit
+185
View File
@@ -0,0 +1,185 @@
/*
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
/*!
@file nfc_layer_f.cpp
@brief Common layer for NFC-F related units
*/
#include "nfc_layer_f.hpp"
#include "nfc/ndef/ndef.hpp"
#include "nfc/ndef/ndef_message.hpp"
#include <inttypes.h>
#include <M5Utility.hpp>
#include <algorithm>
using namespace m5::nfc::f;
using namespace m5::nfc::ndef;
namespace {
constexpr uint16_t known_system_code_table[] = {
system_code_wildcard, system_code_ndef, system_code_secure, system_code_shared, system_code_dfc,
};
inline bool exists_system_code(const uint16_t code)
{
return std::find(std::begin(known_system_code_table), std::end(known_system_code_table), code) !=
std::end(known_system_code_table);
}
inline bool exists_picc(const std::vector<PICC>& v, const PICC& picc)
{
return std::find_if(v.begin(), v.end(), [&picc](const PICC& p) { return p == picc; }) != v.end();
}
} // namespace
namespace m5 {
namespace unit {
namespace nfc {
bool NFCLayerF::polling(m5::nfc::f::PICC& picc, const uint16_t system_code, const m5::nfc::f::RequestCode request_code,
const m5::nfc::f::TimeSlot time_slot)
{
return _impl->polling(picc, system_code, request_code, time_slot);
}
bool NFCLayerF::detect(m5::nfc::f::PICC& picc, const uint16_t system_code, const uint32_t timeout_ms)
{
std::vector<PICC> v{};
uint16_t codes[1] = {system_code};
if (detect_picc(v, codes, 1, TimeSlot::Slot1, timeout_ms)) {
if (!exists_system_code(system_code) && picc.format & format_private) {
picc = v.front();
return true;
}
}
return false;
}
bool NFCLayerF::detect(std::vector<m5::nfc::f::PICC>& piccs, const uint16_t system_code, m5::nfc::f::TimeSlot time_slot,
const uint32_t timeout_ms)
{
uint16_t codes[1] = {system_code};
if (!detect_picc(piccs, codes, 1, time_slot, timeout_ms)) {
return false;
}
// Remove items that do not meet the conditions
if (!piccs.empty() && !exists_system_code(system_code)) {
auto it =
std::remove_if(piccs.begin(), piccs.end(), [](PICC& picc) { return (picc.format & format_private) == 0; });
piccs.erase(it, piccs.end());
}
return !piccs.empty();
}
bool NFCLayerF::detect_picc(std::vector<m5::nfc::f::PICC>& piccs, const uint16_t* private_code, const uint8_t pc_size,
m5::nfc::f::TimeSlot time_slot, const uint32_t timeout_ms)
{
uint8_t slots = timeslot_to_slot(time_slot);
piccs.clear();
piccs.reserve(slots);
auto timeout_at = m5::utility::millis() + timeout_ms;
uint8_t detected{};
do {
PICC picc1{}, picc2{};
uint8_t format{};
// 1. Polling wildcard
if (!polling(picc1, system_code_wildcard, RequestCode::None, time_slot)) {
break;
}
// Already exists?
if (exists_picc(piccs, picc1)) {
continue;
}
// 2. Check IDm for NFCIP-1 Transport Protocol / DFC
if (picc1.idm[0] == 0x01 && picc1.idm[1] == 0xFE) {
format |= format_nfcip1;
} else if (picc1.idm[0] == 0x03 && picc1.idm[1] == 0xFE) {
format |= format_dfc;
}
// 3. Check private area
for (uint_fast8_t i = 0; i < pc_size; ++i) {
auto code = private_code[i];
if (exists_system_code(code)) {
M5_LIB_LOGW("Skip %04X (known system code)", code);
continue;
}
if (polling(picc2, code, RequestCode::None, time_slot)) {
if (picc1 != picc2) {
continue;
}
format |= format_private;
}
}
// 4. Check NDEF
if (polling(picc2, system_code_ndef, RequestCode::None, time_slot)) {
if (picc1 != picc2) {
continue;
}
format |= format_ndef;
}
// 5. Check shared area
if (polling(picc2, system_code_shared, RequestCode::None, time_slot)) {
if (picc1 != picc2) {
continue;
}
format |= format_shared;
}
// 6. Check DEF for FeliCa Lite-S
if (polling(picc2, system_code_dfc, RequestCode::None, time_slot)) {
if (picc1 != picc2) {
continue;
}
// TODO: read lite-S
format |= format_shared;
}
// 7. Check secure
if (polling(picc2, system_code_secure, RequestCode::None, time_slot)) {
if (picc1 != picc2) {
continue;
}
format |= format_secure;
}
picc1.format = format;
piccs.push_back(picc1);
++detected;
} while (detected < slots && m5::utility::millis() <= timeout_at);
return !piccs.empty();
}
//
bool NFCLayerF::read(uint8_t* rx, uint16_t& rx_len, const uint8_t saddr)
{
return false;
}
bool NFCLayerF::write(const uint8_t saddr, const uint8_t* tx, const uint16_t tx_len)
{
return false;
}
uint16_t NFCLayerF::firstUserBlock() const
{
return 0;
}
uint16_t NFCLayerF::lastUserBlock() const
{
return 0;
}
} // namespace nfc
} // namespace unit
} // namespace m5
+125
View File
@@ -0,0 +1,125 @@
/*
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
/*!
@file nfc_layer_f.hpp
@brief Common layer for NFC-F related units
@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"
*/
#ifndef M5_UNIT_NFC_NFC_LAYER_NFC_LAYER_F_HPP
#define M5_UNIT_NFC_NFC_LAYER_NFC_LAYER_F_HPP
#include "nfc/f/nfcf.hpp"
#include "ndef_layer.hpp"
#include <vector>
#include <memory>
namespace m5 {
namespace unit {
class UnitST25R3916;
class CapST25R3916;
namespace nfc {
/*!
@class NFCLayerF
@brief Common interface layer for each chip of the NFC-F reader
*/
class NFCLayerF : public m5::nfc::NFCLayerInterface {
public:
struct Adapter;
explicit NFCLayerF(UnitST25R3916& u);
explicit NFCLayerF(CapST25R3916& u);
///@name Detection
///@{
/*!
@brief Polling
@param[out] PICC detected PICC
@param system_code System code
@param request_code Request code
@param time_slot Maximum number of slots that can be responded
@return True if successful
@note SENSF_REQ
*/
bool polling(m5::nfc::f::PICC& picc, const uint16_t system_code, const m5::nfc::f::RequestCode request_code,
const m5::nfc::f::TimeSlot time_slot);
/*!
@brief Detect single PICC
@param[out] picc Detected PICC
@param timeout_ms Polling time budget in milliseconds
@return True if detected
*/
inline bool detect(m5::nfc::f::PICC& picc, const uint32_t timeout_ms)
{
return detect(picc, 0xFFFF /*skip*/, timeout_ms);
}
/*!
@brief Detect single PICC matching the specified system code
@param[out] picc Detected PICC
@param system_code System code
@param timeout_ms Polling time budget in milliseconds
@return True if detected
*/
bool detect(m5::nfc::f::PICC& picc, const uint16_t system_code, const uint32_t timeout_ms = 100U);
/*!
@brief Detect PICCs
@param[out] piccs Detected PICCs
@param time_slot Maximum number of slots that can be responded
@param timeout_ms Polling time budget in milliseconds
@return True if detected
*/
inline bool detect(std::vector<m5::nfc::f::PICC>& piccs,
m5::nfc::f::TimeSlot time_slot = m5::nfc::f::TimeSlot::Slot16, const uint32_t timeout_ms = 500U)
{
return detect_picc(piccs, nullptr, 0, time_slot, timeout_ms);
}
/*!
@brief Detect PICCs matching the specified system code
@param[out] piccs Detected PICCs
@param system_code System code
@param time_slot Maximum number of slots that can be responded
@param timeout_ms Polling time budget in milliseconds
@return True if detected
*/
bool detect(std::vector<m5::nfc::f::PICC>& piccs, const uint16_t system_code,
m5::nfc::f::TimeSlot time_slot = m5::nfc::f::TimeSlot::Slot16, const uint32_t timeout_ms = 500U);
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;
virtual uint16_t firstUserBlock() const override;
virtual uint16_t lastUserBlock() const override;
bool detect_picc(std::vector<m5::nfc::f::PICC>& piccs, const uint16_t* private_system_code, const uint8_t pc_size,
m5::nfc::f::TimeSlot time_slot, const uint32_t timeout_ms);
private:
std::unique_ptr<Adapter> _impl;
m5::nfc::ndef::NDEFLayer _ndef;
};
///@cond
// Impl for units
struct NFCLayerF::Adapter {
virtual ~Adapter() = default;
virtual bool polling(m5::nfc::f::PICC& picc, const uint16_t system_code, const m5::nfc::f::RequestCode request_code,
const m5::nfc::f::TimeSlot time_slot) = 0;
};
///@endcond
} // namespace nfc
} // namespace unit
} // namespace m5
#endif
+17 -18
View File
@@ -5,7 +5,7 @@
*/
/*!
@file nfc_layer_a_ST25R3916.cpp
@brief ST25R3916 adapter for common layer
@brief ST25R3916 NFC-A adapter for common layer
*/
#include "nfc/layer/nfc_layer_a.hpp"
#include "nfc/layer/ndef_layer.hpp"
@@ -21,10 +21,9 @@ using namespace m5::nfc::a::mifare::classic;
namespace m5 {
namespace unit {
namespace nfc {
//
struct AdapterST25R3916 final : NFCLayerA::Adapter {
explicit AdapterST25R3916(UnitST25R3916& ref) : _u{ref}
struct AdapterST25R3916ForA final : NFCLayerA::Adapter {
explicit AdapterST25R3916ForA(UnitST25R3916& ref) : _u{ref}
{
}
@@ -55,17 +54,17 @@ struct AdapterST25R3916 final : NFCLayerA::Adapter {
UnitST25R3916& _u;
};
bool AdapterST25R3916::request(uint16_t& atqa)
bool AdapterST25R3916ForA::request(uint16_t& atqa)
{
return _u.nfcaRequest(atqa);
}
bool AdapterST25R3916::wakeup(uint16_t& atqa)
bool AdapterST25R3916ForA::wakeup(uint16_t& atqa)
{
return _u.nfcaWakeup(atqa);
}
bool AdapterST25R3916::select(m5::nfc::a::UID& uid)
bool AdapterST25R3916ForA::select(m5::nfc::a::UID& uid)
{
uint8_t lv{1}; // Cascade level 1-3
bool completed{};
@@ -78,44 +77,44 @@ bool AdapterST25R3916::select(m5::nfc::a::UID& uid)
return completed;
}
bool AdapterST25R3916::activate(const UID& uid)
bool AdapterST25R3916ForA::activate(const UID& uid)
{
return _u.nfcaSelect(uid);
}
bool AdapterST25R3916::deactivate()
bool AdapterST25R3916ForA::deactivate()
{
return _u.nfcaHlt();
}
bool AdapterST25R3916::nfca_read_block(uint8_t rx[16], const uint8_t addr)
bool AdapterST25R3916ForA::nfca_read_block(uint8_t rx[16], const uint8_t addr)
{
return _u.nfcaReadBlock(rx, addr);
}
bool AdapterST25R3916::nfca_write_block(const uint8_t addr, const uint8_t tx[16])
bool AdapterST25R3916ForA::nfca_write_block(const uint8_t addr, const uint8_t tx[16])
{
return _u.nfcaWriteBlock(addr, tx);
}
bool AdapterST25R3916::ntag_read_page(uint8_t* rx, uint16_t& rx_len, const uint8_t spage, const uint8_t epage)
bool AdapterST25R3916ForA::ntag_read_page(uint8_t* rx, uint16_t& rx_len, const uint8_t spage, const uint8_t epage)
{
return _u.ntagReadPage(rx, rx_len, spage, epage);
}
bool AdapterST25R3916::nfca_write_page(const uint8_t addr, const uint8_t tx[4])
bool AdapterST25R3916ForA::nfca_write_page(const uint8_t addr, const uint8_t tx[4])
{
return _u.nfcaWritePage(addr, tx);
}
bool AdapterST25R3916::mifare_classic_authenticate(const bool auth_a, const UID& uid, const uint8_t block,
const Key& key)
bool AdapterST25R3916ForA::mifare_classic_authenticate(const bool auth_a, const UID& uid, const uint8_t block,
const Key& key)
{
return auth_a ? _u.mifareClassicAuthenticateA(uid, block, key) : _u.mifareClassicAuthenticateB(uid, block, key);
}
bool AdapterST25R3916::mifare_classic_value_block(const m5::nfc::a::Command cmd, const uint8_t block,
const uint32_t arg)
bool AdapterST25R3916ForA::mifare_classic_value_block(const m5::nfc::a::Command cmd, const uint8_t block,
const uint32_t arg)
{
return _u.mifareClassicValueBlock(cmd, block, arg);
}
@@ -124,7 +123,7 @@ bool AdapterST25R3916::mifare_classic_value_block(const m5::nfc::a::Command cmd,
namespace {
std::unique_ptr<NFCLayerA::Adapter> make_st25r3916_adapter(UnitST25R3916& u)
{
return std::unique_ptr<NFCLayerA::Adapter>(new AdapterST25R3916(u));
return std::unique_ptr<NFCLayerA::Adapter>(new AdapterST25R3916ForA(u));
}
} // namespace
@@ -0,0 +1,59 @@
/*
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
/*!
@file nfc_layer_f_ST25R3916.cpp
@brief ST25R3916 NFC-F adapter for common layer
*/
#include "nfc/layer/nfc_layer_f.hpp"
#include "nfc/layer/ndef_layer.hpp"
#include "unit/unit_ST25R3916.hpp"
#include <M5Utility.hpp>
using namespace m5::unit;
using namespace m5::unit::st25r3916;
using namespace m5::nfc::f;
namespace m5 {
namespace unit {
namespace nfc {
//
struct AdapterST25R3916ForF final : NFCLayerF::Adapter {
explicit AdapterST25R3916ForF(UnitST25R3916& ref) : _u{ref}
{
}
virtual bool polling(m5::nfc::f::PICC& picc, const uint16_t system_code, const m5::nfc::f::RequestCode request_code,
const m5::nfc::f::TimeSlot time_slot) override;
UnitST25R3916& _u;
};
bool AdapterST25R3916ForF::polling(m5::nfc::f::PICC& picc, const uint16_t system_code,
const m5::nfc::f::RequestCode request_code, const m5::nfc::f::TimeSlot time_slot)
{
return _u.nfcfPolling(picc, system_code, request_code, time_slot);
}
//
namespace {
std::unique_ptr<NFCLayerF::Adapter> make_st25r3916_adapter(UnitST25R3916& u)
{
return std::unique_ptr<NFCLayerF::Adapter>(new AdapterST25R3916ForF(u));
}
} // namespace
NFCLayerF::NFCLayerF(UnitST25R3916& u) : _impl(make_st25r3916_adapter(u)), _ndef{*this}
{
}
NFCLayerF::NFCLayerF(CapST25R3916& u) : _impl(make_st25r3916_adapter(static_cast<UnitST25R3916&>(u))), _ndef{*this}
{
}
} // namespace nfc
} // namespace unit
} // namespace m5
+12
View File
@@ -22,6 +22,18 @@ namespace m5 {
*/
namespace nfc {
/*!
@enum NFC
@brief Operation Mode
*/
enum class NFC : uint8_t {
None, //!< No mode
A, //!< NFC-A
B, //!< NFC-B
F, //!< NFC-F
V //!< NFC-V
};
} // namespace nfc
} // namespace m5
+54 -15
View File
@@ -30,7 +30,7 @@ enum class InitiatorOperationMode : uint8_t {
NFCIP1 = 0x00 << 3, //!< NFCIP-1 active communication
ISO14443A = 0x01 << 3, //!< ISO14443A
ISO14443B = 0x02 << 3, //!< ISO14443B
Felica = 0x03 << 3, //!< Felica
FeliCa = 0x03 << 3, //!< FeliCa
NFCForumType1 = 0x04 << 3, //!< NFC Forum Type 1 tag (Topaz)
SubCarrierStream = 0x0E << 3, //!< Sub-carrier stream mode
BPSKStream = 0x0F << 3, //!< BPSK stream mode
@@ -232,40 +232,79 @@ constexpr uint8_t OP_DIRECT_COMMAND{0xC0}; // 11xxxxxxb;
*/
namespace regval {
///@cond
// IO configuration register 2
// 0x01 IO configuration register 2
constexpr uint8_t sup3v{0x80};
constexpr uint8_t io_drv_lvl{0x04};
constexpr uint8_t miso_pd1{0x08};
constexpr uint8_t miso_pd2{0x10};
// Operation control register
constexpr uint8_t en{0x80};
constexpr uint8_t rx_en{0x40};
constexpr uint8_t tx_en{0x08};
// ISO14443A and NFC 106kb/s settings register
// 0x02 Operation control register
constexpr uint8_t en{0x80}; // 1: Enables oscillator and regulator(Ready mode)
constexpr uint8_t rx_en{0x40}; // 1: Enables Rx operation
constexpr uint8_t tx_en{0x08}; // 1: Enables Tx operation
constexpr uint8_t wu{0x04}; // 1: Enables Wake-up mode
constexpr uint8_t en_fd_c1{0x02};
constexpr uint8_t en_fd_c0{0x01};
constexpr uint8_t en_fd_mask{0x03};
constexpr uint8_t en_fd_off{0x00};
constexpr uint8_t en_fd_manual_ca{0x01};
constexpr uint8_t en_fd_manual_pdt{0x02};
constexpr uint8_t en_fd_manual_auto{0x03};
// 0x03 Mode definition register
constexpr uint8_t targ{0x80}; // 0: Initiator 1: Target
constexpr uint8_t tr_am{0x04};
constexpr uint8_t nfc_ar0{0x01};
constexpr uint8_t nfc_ar1{0x02};
constexpr uint8_t nfc_ar8_off{0x00};
constexpr uint8_t nfc_ar8_auto{0x01};
constexpr uint8_t nfc_ar8_always{0x02};
constexpr uint8_t nfc_ar8_RFI{0x03};
// 0x05 ISO14443A and NFC 106kb/s settings register
constexpr uint8_t no_tx_par{0x80};
constexpr uint8_t no_rx_par{0x40};
constexpr uint8_t antcl{0x01};
// Auxiliary definition register
// 0x0A Auxiliary definition register
constexpr uint8_t no_crc_rx{0x80};
// Main interrupt register
constexpr uint8_t nfc_n1{0x02};
constexpr uint8_t nfc_n0{0x01};
constexpr uint8_t nfc_n_mask{0x03};
// 0x12 Timer and EMV control register
constexpr uint8_t mrt_step{0x08}; // Mask receive timer step size
constexpr uint8_t nrt_step{0x01}; // No-response timer step size
// 0x1A Main interrupt register
constexpr uint8_t I_wl{0x40}; // IRQ due to FIFO water level
constexpr uint8_t I_rxs{0x20}; // IRQ due to start of receive
constexpr uint8_t I_rxe{0x10}; // IRQ due to end of receive
constexpr uint8_t I_txe{0x08}; // IRQ due to end of transmission
constexpr uint8_t I_col{0x04}; // IRQ due to bit collision
// Timer and NFC interrupt register
// 0x1B Timer and NFC interrupt register
constexpr uint8_t I_nre{0x40}; // IRQ due to No-response timer expire
constexpr uint8_t I_cac{0x04}; // IRQ due to detection of collision during RF collision avoidance
// Timer and EMV control register
constexpr uint8_t mrt_step{0x08}; // Mask receive timer step size
constexpr uint8_t nrt_step{0x01}; // No-response timer step size
//
constexpr uint8_t I_cat{0x02}; // IRQ after minimum guard time expire
// 0x1D Passive target interrupt register
constexpr uint8_t I_apon{0x20}; // IRQ due to active P2P field on event
constexpr uint32_t I_wl32 = ((uint32_t)I_wl << 24);
constexpr uint32_t I_rxs32 = ((uint32_t)I_rxs << 24);
constexpr uint32_t I_rxe32 = ((uint32_t)I_rxe << 24);
constexpr uint32_t I_txe32 = ((uint32_t)I_txe << 24);
constexpr uint32_t I_col32 = ((uint32_t)I_col << 24) | ((uint32_t)I_cac << 16);
constexpr uint32_t I_col32 = ((uint32_t)I_col << 24);
constexpr uint32_t I_nre32 = ((uint32_t)I_nre << 16);
constexpr uint32_t I_cac32 = ((uint32_t)I_cac << 16);
constexpr uint32_t I_cat32 = ((uint32_t)I_cat << 16);
constexpr uint32_t I_apon32 = I_apon;
///@endcond
} // namespace regval
+224 -144
View File
@@ -12,10 +12,13 @@
#include <thread>
using namespace m5::utility::mmh3;
using namespace m5::unit::types;
using namespace m5::unit::st25r3916;
using namespace m5::unit::st25r3916::regval;
using namespace m5::unit::st25r3916::command;
using namespace m5::nfc;
using namespace m5::nfc::a;
using namespace m5::nfc::a::mifare;
using namespace m5::nfc::a::mifare::classic;
@@ -81,7 +84,7 @@ uint16_t calculate_nrt(const uint32_t ms, const bool nrt_step)
if (nrt > max) {
nrt = max;
}
// M5_LIB_LOGE(">>>> %ums fc4096:%u => %04X", ms, nrt_step, nrt);
// M5_LIB_LOGE(">>>> %ums fc4096:%u => %04X", ms, nrt_step, nrt);
return nrt;
}
@@ -185,23 +188,7 @@ bool UnitST25R3916::begin()
readTXDriver(txd);
M5_LIB_LOGD("TXD:%02X", txd);
writeReceiverConfiguration1(0x08); // z600k
writeReceiverConfiguration2(0x2D); // sqm_dyn , agc_en, agc_m, agc6_3,
writeReceiverConfiguration3(0x00);
writeReceiverConfiguration4(0x00);
//
// ISO14443A
// M5_LIB_LOGE(">>>>>> try ISO14443A REQA");
writeInitiatorOperationMode(InitiatorOperationMode::ISO14443A, 0x01 /* nfc_ar01 */);
writeBitrate(Bitrate::FC128_106Kbits, Bitrate::FC128_106Kbits);
writeSettingsISO14443A(0x0);
//
writeOperationControl(en | rx_en | tx_en);
writeMaskInterrupts(0);
writeDirectCommand(CMD_NFC_INITIAL_FIELD_ON);
m5::utility::delay(5);
#if 0
// MRT/SQT
@@ -215,70 +202,7 @@ bool UnitST25R3916::begin()
M5_LIB_LOGE("====== MRT:%02X SQT:%02X", mrt, sqt);
#endif
//
#if 0
uint8_t a_table[] = {
/*
0x07, 0x3C, 0x83, 0x08, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x08, 0x2D, 0xD8, 0x00, 0x0C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFB, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x82, 0x82, 0x70, 0x5F, 0x13, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
*/
0x07, 0x3C, 0xCB, 0x08, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x03, 0x08, 0x2D, 0x00, 0x00, 0x0E,
0x00, 0x23, 0x20, 0x02, 0xC8, 0x80, 0x87, 0xA6, 0x0F, 0x7B, 0x00, 0x20, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x38, 0x00, 0xDF, 0x82, 0x82, 0x70, 0x5F, 0x13, 0x02, 0x00, 0x33, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
struct B {
uint16_t reg;
uint8_t val;
} b_table[] = {
{0x05, 0x40}, {0x06, 0x00}, {0x0B, 0x0C}, {0x0C, 0x51}, {0x0D, 0x00}, {0x0F, 0x00}, {0x15, 0x00}, {0x28, 0x10},
{0x29, 0x7C}, {0x2A, 0x80}, {0x2B, 0x04}, {0x2C, 0xD0}, {0X30, 0x40}, {0x31, 0x03}, {0x32, 0x40}, {0x33, 0x03},
};
uint8_t r{};
for (auto&& v : a_table) {
write_register8(r++, v);
}
for (auto&& b : b_table) {
write_register8(b.reg, b.val);
}
#endif
#if 0
write_register8((uint8_t)0x08, 0x5D);
write_register8((uint8_t)0x09, 0x03);
write_register8((uint8_t)0x12, 0x20);
write_register8((uint8_t)0x13, 0x02);
write_register8((uint8_t)0x25, 0xDF);
write_register8((uint8_t)0x26, 0x82);
write_register8((uint8_t)0x27, 0x82);
write_register8((uint8_t)0x28, 0x70);
write_register8((uint8_t)0x29, 0x5F);
write_register8((uint8_t)0x2A, 0x13);
write_register8((uint8_t)0x2B, 0x02);
write_register8((uint8_t)0x00, 0x07);
write_register8((uint8_t)0x01, 0x3C);
write_register8((uint8_t)0x02, 0xCB);
write_register8((uint16_t)0x05, 0x40);
write_register8((uint16_t)0x0C, 0x51);
write_register8((uint16_t)0x15, 0x00);
write_register8((uint16_t)0x2A, 0x80);
write_register8((uint16_t)0x2C, 0xD0);
write_register8((uint16_t)0x30, 0x40);
write_register8((uint16_t)0x31, 0x03);
write_register8((uint16_t)0x32, 0x40);
write_register8((uint16_t)0x33, 0x03);
#endif
return true;
return configureNFCMode(_cfg.mode);
}
void UnitST25R3916::update(const bool /*force*/)
@@ -294,6 +218,188 @@ void UnitST25R3916::update(const bool /*force*/)
*/
}
bool UnitST25R3916::configureNFCMode(const m5::nfc::NFC mode)
{
if (mode == NFC::None) {
return false;
}
if (NFCMode() == mode) {
return true;
}
if (!writeDirectCommand(CMD_STOP_ALL_ACTIVITIES) || //
!modify_bit_register8(REG_OPERATION_CONTROL, 0x00, wu)) { // Disable wakeup mode
return false;
}
bool ok{};
switch (mode) {
case m5::nfc::NFC::A:
ok = configure_nfc_a();
break;
case m5::nfc::NFC::B:
ok = configure_nfc_b();
break;
case m5::nfc::NFC::F:
ok = configure_nfc_f();
break;
case m5::nfc::NFC::V:
ok = configure_nfc_v();
break;
default:
return false;
}
/*
write_noresponse_timeout(default_nrt_for(mode));
write_mask_receiver_timer(default_mrt_for(mode));
write_squelch_timer(default_sqt_for(mode));
*/
if (ok) {
M5_LIB_LOGE(">>>> Change to %u", mode);
_nfcMode = mode;
}
return ok;
}
bool UnitST25R3916::nfc_initial_field_on()
{
uint8_t v{};
if (!readOperationControl(v)) {
return false;
}
if (v & tx_en) {
M5_LIB_LOGE("Already tx_en");
return false;
}
writeDirectCommand(CMD_NFC_INITIAL_FIELD_ON);
m5::utility::delay(5);
return modify_bit_register8(REG_OPERATION_CONTROL, tx_en | rx_en, 0x00);
#if 0
if (!writeNFCFieldOnGuardTimer(0x00)) {
return false;
}
if (!modify_bit_register8(REG_OPERATION_CONTROL, en_fd_manual_ca, en_fd_mask)) {
return false;
}
//
writeExternalFieldDetectorActivationThreshold(0x00);
modify_bit_register8(REG_AUXILIARY_DEFINITION, 0x00, nfc_n_mask);
clearInterrupts();
uint32_t mask{};
readMaskInterrupts(mask);
mask |= (I_cac32 | I_cat32 | I_apon32);
writeMaskInterrupts(mask);
writeDirectCommand(CMD_NFC_INITIAL_FIELD_ON);
bool ret{};
auto irq = wait_for_interrupt(I_cac32 | I_cat32 | I_apon32, 10);
M5_LIB_LOGE("IRQ:%08X", irq);
if (irq & I_cac32) {
M5_LIB_LOGE("RF Collison");
} else if (irq & I_apon32) {
irq = wait_for_interrupt(I_cat32, 10);
M5_LIB_LOGE(" IRQ:%08X", irq);
ret = (irq & I_cat32) != 0;
} else {
M5_LIB_LOGE("ERROR");
}
clearInterrupts();
mask &= ~(I_cac32 | I_cat32 | I_apon32);
writeMaskInterrupts(mask);
return ret && modify_bit_register8(REG_OPERATION_CONTROL, tx_en | rx_en, 0x00);
#endif
#if 0
/*******************************************************************************/
ReturnCode RfalRfST25R3916Class::st25r3916PerformCollisionAvoidance(uint8_t FieldONCmd, uint8_t pdThreshold, uint8_t caThreshold, uint8_t nTRFW)
{
uint8_t treMask;
uint32_t irqs;
ReturnCode err;
if ((FieldONCmd != ST25R3916_CMD_INITIAL_RF_COLLISION) && (FieldONCmd != ST25R3916_CMD_RESPONSE_RF_COLLISION_N)) {
return ERR_PARAM;
}
err = ERR_INTERNAL;
/* Check if new thresholds are to be applied */
if ((pdThreshold != ST25R3916_THRESHOLD_DO_NOT_SET) || (caThreshold != ST25R3916_THRESHOLD_DO_NOT_SET)) {
treMask = 0;
if (pdThreshold != ST25R3916_THRESHOLD_DO_NOT_SET) {
treMask |= ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask;
}
if (caThreshold != ST25R3916_THRESHOLD_DO_NOT_SET) {
treMask |= ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask;
}
/* Set Detection Threshold and|or Collision Avoidance Threshold */
st25r3916ChangeRegisterBits(ST25R3916_REG_FIELD_THRESHOLD_ACTV, treMask, (pdThreshold & ST25R3916_REG_FIELD_THRESHOLD_ACTV_trg_mask) | (caThreshold & ST25R3916_REG_FIELD_THRESHOLD_ACTV_rfe_mask));
}
/* Set n x TRFW */
st25r3916ChangeRegisterBits(ST25R3916_REG_AUX, ST25R3916_REG_AUX_nfc_n_mask, nTRFW);
/*******************************************************************************/
/* Enable and clear CA specific interrupts and execute command */
st25r3916GetInterrupt((ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_APON));
st25r3916EnableInterrupts((ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_APON));
st25r3916ExecuteCommand(FieldONCmd);
/*******************************************************************************/
/* Wait for initial APON interrupt, indicating anticollision avoidance done and ST25R3916's
* field is now on, or a CAC indicating a collision */
irqs = st25r3916WaitForInterruptsTimed((ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_APON), ST25R3916_TOUT_CA);
if ((ST25R3916_IRQ_MASK_CAC & irqs) != 0U) { /* Collision occurred */
err = ERR_RF_COLLISION;
} else if ((ST25R3916_IRQ_MASK_APON & irqs) != 0U) {
/* After APON wait for CAT interrupt, indication field was switched on minimum guard time has been fulfilled */
irqs = st25r3916WaitForInterruptsTimed((ST25R3916_IRQ_MASK_CAT), ST25R3916_TOUT_CA);
if ((ST25R3916_IRQ_MASK_CAT & irqs) != 0U) { /* No Collision detected, Field On */
err = ERR_NONE;
}
} else {
/* MISRA 15.7 - Empty else */
}
/* Clear any previous External Field events and disable CA specific interrupts */
st25r3916GetInterrupt((ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_EON));
st25r3916DisableInterrupts((ST25R3916_IRQ_MASK_CAC | ST25R3916_IRQ_MASK_CAT | ST25R3916_IRQ_MASK_APON));
return err;
}
#endif
}
bool UnitST25R3916::configure_nfc_b()
{
M5_LIB_LOGE("Not yet supported");
return false;
}
bool UnitST25R3916::configure_nfc_v()
{
M5_LIB_LOGE("Not yet supported");
return false;
}
bool UnitST25R3916::writeDirectCommand(const uint8_t cmd, const uint8_t* data, uint32_t dlen)
{
TRANSACTION_GUARD();
@@ -428,62 +534,6 @@ bool UnitST25R3916::write_register8(const uint16_t reg, const uint8_t v)
return writeRegister8(to_write_reg(reg), v, false);
}
bool UnitST25R3916::set_bit_register8(const uint8_t reg, const uint8_t bits)
{
TRANSACTION_GUARD();
uint8_t v{};
if (read_register8(reg, v)) {
if ((v & bits) == bits) {
return true; // Already set spesific bits
}
return write_register8(reg, v | bits);
}
return false;
}
bool UnitST25R3916::set_bit_register8(const uint16_t reg, const uint8_t bits)
{
TRANSACTION_GUARD();
uint8_t v{};
if (read_register8(reg, v)) {
if ((v & bits) == bits) {
return true; // Already set spesific bits
}
return write_register8(reg, v | bits);
}
return false;
}
bool UnitST25R3916::clear_bit_register8(const uint8_t reg, const uint8_t bits)
{
TRANSACTION_GUARD();
uint8_t v{};
if (read_register8(reg, v)) {
if ((v & ~bits) == ~bits) {
return true; // Already cleared spesific bits
}
return write_register8(reg, v & ~bits);
}
return false;
}
bool UnitST25R3916::clear_bit_register8(const uint16_t reg, const uint8_t bits)
{
TRANSACTION_GUARD();
uint8_t v{};
if (read_register8(reg, v)) {
if ((v & ~bits) == ~bits) {
return true; // Already cleared spesific bits
}
return write_register8(reg, v & ~bits);
}
return false;
}
bool UnitST25R3916::read_register16(const uint8_t reg, uint16_t& v)
{
TRANSACTION_GUARD();
@@ -536,6 +586,34 @@ bool UnitST25R3916::write_register32(const uint16_t reg, const uint32_t v)
return writeRegister32BE(to_write_reg(reg), v, false);
}
bool UnitST25R3916::modify_bit_register8(const uint8_t reg, const uint8_t set_mask, const uint8_t clear_mask)
{
uint8_t v{};
if (read_register8(reg, v)) {
const uint8_t w = (v & ~clear_mask) | set_mask;
// M5_LIB_LOGE("[%2u]:%02X %02X/%02X => %02X %08o", reg, v, set_mask, clear_mask, w, OCB(w));
if (w == v) {
return true;
}
return write_register8(reg, w);
}
return false;
}
bool UnitST25R3916::modify_bit_register8(const uint16_t reg, const uint8_t set_mask, const uint8_t clear_mask)
{
uint8_t v{};
if (read_register8(reg, v)) {
const uint8_t w = (v & ~clear_mask) | set_mask;
// M5_LIB_LOGE("[%2u]:%02X %02X/%02X => %02X %08o", reg, v, set_mask, clear_mask, w, OCB(w));
if (w == v) {
return true;
}
return write_register8(reg, w);
}
return false;
}
uint32_t UnitST25R3916::wait_for_interrupt(const uint32_t irq, const uint32_t timeout_ms, bool include_error)
{
auto timeout_at = m5::utility::millis() + timeout_ms;
@@ -561,13 +639,18 @@ bool UnitST25R3916::wait_for_FIFO(const uint32_t timeout_ms, const uint16_t requ
auto irq = wait_for_interrupt(I_rxe32, timeout_ms);
const uint16_t reqSize = required_size ? required_size : 1;
if (has_irq32_error(irq)) {
M5_LIB_LOGE("Error: %08X", irq);
return false;
}
if (is_irq32_rxe(irq)) {
return true;
}
// M5_LIB_LOGE("IRQ:%08X %u", irq, timeout_ms);
// M5_LIB_LOGE("IRQ:%08X %u", irq, timeout_ms);
// Check the FIFO size in case I_rxe doesn't arrive
if (is_irq32_rxs(irq)) {
// Check the FIFO size in case I_rxe doesn't arrive
auto timeout_at = m5::utility::millis() + timeout_ms;
uint16_t bytes{};
uint8_t bits{};
@@ -578,11 +661,8 @@ bool UnitST25R3916::wait_for_FIFO(const uint32_t timeout_ms, const uint16_t requ
}
m5::utility::delay(1);
} while (m5::utility::millis() <= timeout_at);
readFIFOSize(bytes, bits);
// M5_LIB_LOGE(" FIFO:%u,%u/%u", bytes, bits, required_size);
return bytes >= reqSize;
// M5_LIB_LOGE(" FIFO:%u,%u/%u", bytes, bits, required_size);
return readFIFOSize(bytes, bits) && bytes >= reqSize;
}
return false;
}
+80 -21
View File
@@ -42,8 +42,9 @@ public:
@brief Settings for begin
*/
struct config_t {
bool vdd_voltage_5V{false}; //!< VDD voltage true:5V false:3.3V
uint8_t tx_am_modulation{13}; // 0-15 See also 4.5.48 TX driver register
m5::nfc::NFC mode{m5::nfc::NFC::A}; //!< Initial Operation Mode
bool vdd_voltage_5V{false}; //!< VDD voltage true:5V false:3.3V
uint8_t tx_am_modulation{13}; // 0-15 See also 4.5.48 TX driver register
};
///@name Settings for begin
@@ -60,6 +61,28 @@ public:
}
///@}
//! @brief Gets the current operating mode
inline m5::nfc::NFC NFCMode() const
{
return _nfcMode;
}
/*!
@brief Configure NFC mode
@param mode NFC mode
@return True if successful
*/
bool configureNFCMode(const m5::nfc::NFC mode);
/*!
@breif Is the current operating mode the one specified?
@param mode Mode
@return True if the current operation is in the specified mode
*/
inline bool isNFCMode(const m5::nfc::NFC mode)
{
return NFCMode() == mode;
}
/*!
@brief Write the direct command with data
@param cmd Direct command
@@ -351,8 +374,7 @@ public:
*/
inline bool writeAuxiliaryDefinition(const uint8_t value)
{
// return write_register8(st25r3916::command::REG_AUXILIARY_DEFINITION, value | 0x03);
return write_register8(st25r3916::command::REG_AUXILIARY_DEFINITION, value | 0x03);
return write_register8(st25r3916::command::REG_AUXILIARY_DEFINITION, value);
}
/*!
@@ -500,7 +522,7 @@ public:
@param value Value
@return True if successful
*/
inline bool writeP2PReceiverConfiguration(uint8_t& value)
inline bool writeP2PReceiverConfiguration(const uint8_t value)
{
return write_register8(st25r3916::command::REG_P2P_RECEIVER_CONFIGURATION, value);
}
@@ -518,7 +540,7 @@ public:
@param value Value
@return True if successful
*/
inline bool writeCorrelatorConfiguration1(uint8_t& value)
inline bool writeCorrelatorConfiguration1(const uint8_t value)
{
return write_register8(st25r3916::command::REG_CORRELATOR_CONFIGURATION_1, value);
}
@@ -536,7 +558,7 @@ public:
@param value Value
@return True if successful
*/
inline bool writeCorrelatorConfiguration2(uint8_t& value)
inline bool writeCorrelatorConfiguration2(const uint8_t value)
{
return write_register8(st25r3916::command::REG_CORRELATOR_CONFIGURATION_2, value);
}
@@ -554,7 +576,7 @@ public:
@param value Value (MSB cfg1,cfg2 LSB)
@return True if successful
*/
inline bool writeCorrelatorConfiguration(uint16_t& value)
inline bool writeCorrelatorConfiguration(const uint16_t value)
{
return write_register16(st25r3916::command::REG_CORRELATOR_CONFIGURATION_1, value);
}
@@ -739,7 +761,7 @@ public:
@param value Value
@return True if successful
*/
inline bool writeSquelchTimer(uint8_t value)
inline bool writeSquelchTimer(const uint8_t value)
{
return write_register8(st25r3916::command::REG_SQUELCH_TIMER, value);
}
@@ -757,7 +779,7 @@ public:
@param value Value
@return True if successful
*/
inline bool writeNFCFieldOnGuardTimer(uint8_t& value)
inline bool writeNFCFieldOnGuardTimer(const uint8_t value)
{
return write_register8(st25r3916::command::REG_NFC_FIELD_ON_GUARD_TIMER, value);
}
@@ -779,7 +801,7 @@ public:
@param value Value
@return True if successful
*/
inline bool writeMaskMainInterrupt(const uint8_t& value)
inline bool writeMaskMainInterrupt(const uint8_t value)
{
return write_register8(st25r3916::command::REG_MASK_MAIN_INTERRUPT, value);
}
@@ -797,7 +819,7 @@ public:
@param value Value
@return True if successful
*/
inline bool writeMaskTimerAndNFCInterrupt(const uint8_t& value)
inline bool writeMaskTimerAndNFCInterrupt(const uint8_t value)
{
return write_register8(st25r3916::command::REG_MASK_TIMER_AND_NFC_INTERRUPT, value);
}
@@ -815,7 +837,7 @@ public:
@param value Value
@return True if successful
*/
inline bool writeMaskErrorAndWakeupInterrupt(const uint8_t& value)
inline bool writeMaskErrorAndWakeupInterrupt(const uint8_t value)
{
return write_register8(st25r3916::command::REG_MASK_ERROR_AND_WAKEUP_INTERRUPT, value);
}
@@ -833,7 +855,7 @@ public:
@param value Value
@return True if successful
*/
inline bool writeMaskPassiveTargetInterrupt(const uint8_t& value)
inline bool writeMaskPassiveTargetInterrupt(const uint8_t value)
{
return write_register8(st25r3916::command::REG_MASK_PASSIVE_TARGET_INTERRUPT, value);
}
@@ -1652,7 +1674,7 @@ public:
bool readICIdentity(uint8_t& type, uint8_t& rev);
///@}
// ----------------------------------------------------------------
// ----------------------------------------------------------------------------------------------
///@name NFC-A
///@{
/*!
@@ -1779,6 +1801,38 @@ public:
bool ntagReadPage(uint8_t* rx, uint16_t& rx_len, const uint8_t spage, const uint8_t epage);
///@}
// ----------------------------------------------------------------------------------------------
///@name NFC-F
///@{
/*!
@brief Transceive
@param rx Receive buffer
@param[in/out] rx_len in:Size of receive buffer out:actual read size
@param tx Send buffer
@param tx_len Size of send buffer
@param timeout_ms Timeout(ms)
@return True if successful
*/
bool nfcfTransceive(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len,
const uint32_t timeout_ms);
/*!
@brief Polling
@param[out] PICC detected PICC
@param system_code System code
@param request_code Request code
@param time_slot Maximum number of slots that can be responded
@return True if successful
@note SENSF_REQ
*/
bool nfcfPolling(m5::nfc::f::PICC& picc, const uint16_t system_code, const m5::nfc::f::RequestCode request_code,
const m5::nfc::f::TimeSlot time_slot);
bool nfcfRequestService(const m5::nfc::f::PICC& picc);
///@}
// For debug
void dumpRegister();
@@ -1789,10 +1843,9 @@ protected:
bool read_register8(const uint16_t reg, uint8_t& v);
bool write_register8(const uint8_t reg, const uint8_t v);
bool write_register8(const uint16_t reg, const uint8_t v);
bool set_bit_register8(const uint8_t reg, const uint8_t bitss);
bool set_bit_register8(const uint16_t reg, const uint8_t bitss);
bool clear_bit_register8(const uint8_t reg, const uint8_t clear_bitss);
bool clear_bit_register8(const uint16_t reg, const uint8_t clear_bitss);
bool modify_bit_register8(const uint8_t reg, const uint8_t set_mask, const uint8_t clear_mask);
bool modify_bit_register8(const uint16_t reg, const uint8_t set_mask, const uint8_t clear_mask);
bool read_register16(const uint8_t reg, uint16_t& v);
bool read_register16(const uint16_t reg, uint16_t& v);
bool write_register16(const uint8_t reg, const uint16_t v);
@@ -1811,19 +1864,25 @@ protected:
bool wait_for_FIFO(const uint32_t timeout_ms, const uint16_t required_size = 0);
bool read_FIFO(std::vector<uint8_t>& out);
bool configure_nfc_a();
bool configure_nfc_b();
bool configure_nfc_f();
bool configure_nfc_v();
bool nfc_initial_field_on();
// NFC-A
bool nfca_request_wakeup(uint16_t& atqa, const bool req);
bool nfca_anti_collision(uint8_t rbuf[5], const uint8_t lv);
bool mifare_classic_send_encrypt(const uint8_t* tx, const uint16_t tx_len);
bool mifare_classic_transceive_encrypt(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len,
const uint32_t timeout_ms, const bool include_crc, const bool decrypt);
bool mifare_classic_authenticate(const m5::nfc::a::Command cmd, const m5::nfc::a::UID& uid, const uint8_t block,
const m5::nfc::a::mifare::classic::Key& key);
bool ntag_get_version(uint8_t info[10]);
private:
config_t _cfg{};
m5::nfc::NFC _nfcMode{};
m5::nfc::a::mifare::classic::Crypto1 _crypto1{};
bool _encrypted{};
volatile bool _interrupt_occurred{};
+57 -18
View File
@@ -11,20 +11,24 @@
#include <M5Utility.hpp>
using namespace m5::utility::mmh3;
using namespace m5::unit::types;
using namespace m5::unit::st25r3916;
using namespace m5::unit::st25r3916::regval;
using namespace m5::unit::st25r3916::command;
using namespace m5::nfc;
using namespace m5::nfc::a;
using namespace m5::nfc::a::mifare;
using namespace m5::nfc::a::mifare::classic;
using namespace m5::unit::st25r3916;
using namespace m5::unit::st25r3916::regval;
using namespace m5::unit::st25r3916::command;
using namespace m5::nfc::a;
using namespace m5::nfc::a::mifare;
using namespace m5::nfc::a::mifare::classic;
#define CHECK_MODE() \
do { \
if (!isNFCMode(NFC::A)) { \
M5_LIB_LOGE("Illegal mode %u", NFCMode()); \
return false; \
} \
} while (0)
namespace {
void suc_23(const uint32_t Nt, uint32_t& suc2, uint32_t& suc3)
@@ -95,11 +99,37 @@ void append_parity(uint8_t* out, const uint32_t out_len, const uint8_t* in, cons
namespace m5 {
namespace unit {
// -------------------------------- For NFC-A
bool UnitST25R3916::configure_nfc_a()
{
#if 0
//
// ISO14443A
// M5_LIB_LOGE(">>>>>> try ISO14443A REQA");
writeInitiatorOperationMode(InitiatorOperationMode::ISO14443A, 0x01 /* nfc_ar01 */);
writeBitrate(Bitrate::FC128_106Kbits, Bitrate::FC128_106Kbits);
writeSettingsISO14443A(0x0);
#endif
if (!writeInitiatorOperationMode(InitiatorOperationMode::ISO14443A, nfc_ar8_auto) || //
!writeBitrate(Bitrate::FC128_106Kbits, Bitrate::FC128_106Kbits) || //
!writeSettingsISO14443A(0x00)) {
return false;
}
return writeReceiverConfiguration1(0x08) && // z600k
writeReceiverConfiguration2(0x2D) && // sqm_dyn , agc_en, agc_m, agc6_3,
writeReceiverConfiguration3(0x00) && //
writeReceiverConfiguration4(0x00) && //
writeMaskInterrupts(0) && //
nfc_initial_field_on();
}
bool UnitST25R3916::nfcaTransceive(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len,
const uint32_t timeout_ms)
{
CHECK_MODE();
const auto rx_len_org = rx_len;
rx_len = 0;
if (!rx || !rx_len_org || !tx || !tx_len) {
@@ -135,6 +165,8 @@ bool UnitST25R3916::nfcaTransceive(uint8_t* rx, uint16_t& rx_len, const uint8_t*
bool UnitST25R3916::nfca_request_wakeup(uint16_t& atqa, const bool request)
{
CHECK_MODE();
_encrypted = false;
atqa = 0;
@@ -243,6 +275,8 @@ bool UnitST25R3916::nfcaSelectWithAnticollision(bool& completed, UID& uid, const
completed = false;
_encrypted = false;
CHECK_MODE();
if (lv < 1 || lv > 3) {
return false;
}
@@ -297,6 +331,8 @@ bool UnitST25R3916::nfcaSelect(const UID& uid)
{
_encrypted = false;
CHECK_MODE();
if (!uid.valid()) {
return false;
}
@@ -340,18 +376,10 @@ bool UnitST25R3916::nfcaSelect(const UID& uid)
bool UnitST25R3916::nfcaHlt()
{
CHECK_MODE();
const uint8_t hlt_frame[2] = {m5::stl::to_underlying(Command::HLTA), 0x00};
#if 0
if (!write_noresponse_timeout(TIMEOUT_HALT) || !writeSettingsISO14443A(0x00 /*standard*/) ||
!writeAuxiliaryDefinition(0) ||
!clearInterrupts() || !writeDirectCommand(CMD_CLEAR_FIFO) || !writeFIFO(hlta, sizeof(hlta)) ||
!writeNumberOfTransmittedBytes(sizeof(hlta), 0) || !writeDirectCommand(CMD_TRANSMIT_WITH_CRC)) {
return false;
}
#else
if (_encrypted) {
if (!write_noresponse_timeout(TIMEOUT_HALT) || !mifare_classic_send_encrypt(hlt_frame, sizeof(hlt_frame))) {
return false;
@@ -365,7 +393,6 @@ bool UnitST25R3916::nfcaHlt()
return false;
}
}
#endif
_encrypted = false;
// No response is coming back, so need to confirm if it was sent
auto irq = wait_for_interrupt(I_txe32, TIMEOUT_HALT);
@@ -374,6 +401,8 @@ bool UnitST25R3916::nfcaHlt()
bool UnitST25R3916::nfcaReadBlock(uint8_t rx[16], const uint8_t addr)
{
CHECK_MODE();
if (!rx) {
return false;
}
@@ -387,6 +416,8 @@ bool UnitST25R3916::nfcaReadBlock(uint8_t rx[16], const uint8_t addr)
bool UnitST25R3916::nfcaWriteBlock(const uint8_t addr, const uint8_t tx[16])
{
CHECK_MODE();
if (!tx) {
return false;
}
@@ -431,6 +462,8 @@ bool UnitST25R3916::nfcaWriteBlock(const uint8_t addr, const uint8_t tx[16])
bool UnitST25R3916::nfcaWritePage(const uint8_t page, const uint8_t tx[4])
{
CHECK_MODE();
if (!tx) {
return false;
}
@@ -566,6 +599,8 @@ bool UnitST25R3916::mifare_classic_transceive_encrypt(uint8_t* rx, uint16_t& rx_
bool UnitST25R3916::mifare_classic_authenticate(const Command cmd, const UID& uid, const uint8_t block, const Key& mkey)
{
CHECK_MODE();
if ((cmd != Command::AUTH_WITH_KEY_A && cmd != Command::AUTH_WITH_KEY_B) || !uid.isMifareClassic()) {
return false;
}
@@ -655,6 +690,8 @@ bool UnitST25R3916::mifare_classic_authenticate(const Command cmd, const UID& ui
bool UnitST25R3916::mifareClassicValueBlock(const m5::nfc::a::Command cmd, const uint8_t block, const uint32_t arg)
{
CHECK_MODE();
if (cmd != Command::DECREMENT && cmd != Command::INCREMENT && cmd != Command::RESTORE && cmd != Command::TRANSFER) {
return false;
}
@@ -692,6 +729,8 @@ bool UnitST25R3916::mifareClassicValueBlock(const m5::nfc::a::Command cmd, const
// -------------------------------- For NTAG
bool UnitST25R3916::ntagReadPage(uint8_t* rx, uint16_t& rx_len, const uint8_t spage, const uint8_t epage)
{
CHECK_MODE();
if (spage > epage) {
return false;
}
+411
View File
@@ -0,0 +1,411 @@
/*
* SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
*
* SPDX-License-Identifier: MIT
*/
/*!
@file unit_ST25R3916_nfcf.cpp
@brief class UnitST25R3916 implementation for NFC-F
*/
#include "unit_ST25R3916.hpp"
#include <M5Utility.hpp>
using namespace m5::utility::mmh3;
using namespace m5::unit::types;
using namespace m5::unit::st25r3916;
using namespace m5::unit::st25r3916::regval;
using namespace m5::unit::st25r3916::command;
using namespace m5::nfc;
using namespace m5::nfc::f;
#define CHECK_MODE() \
do { \
if (!isNFCMode(NFC::F)) { \
M5_LIB_LOGE("Illegal mode %u", NFCMode()); \
return false; \
} \
} while (0)
namespace {
/*
uint8_t val_table[] = {
0x07, 0x3C, 0xCB, 0x1C, 0x11, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x13, 0x3D, 0x00, 0x00, 0x28,
0x06, 0x11, 0x22, 0x02, 0xCA, 0x80, 0x85, 0xA6, 0x0F, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x28, 0x00, 0xDF, 0x82, 0x82, 0x70, 0x5F, 0x13, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
*/
}
namespace m5 {
namespace unit {
// -------------------------------- For NFC-F
bool UnitST25R3916::configure_nfc_f()
{
if (!writeInitiatorOperationMode(InitiatorOperationMode::FeliCa, tr_am) || //
!writeBitrate(Bitrate::FC64_212Kbits, Bitrate::FC64_212Kbits)) {
return false;
}
return modify_bit_register8(REG_OPERATION_CONTROL, en_fd_c1 | en_fd_c0, 0x00) && //
writeIOConfiguration1(0x07) && //
// writeAuxiliaryDefinition(nfc_n0) && //
writeAuxiliaryDefinition(0x00) && //
writeReceiverConfiguration1(0x13) && //
writeReceiverConfiguration2(0x3D) && //
writeReceiverConfiguration3(0x00) && //
writeReceiverConfiguration4(0x00) && //
writeCorrelatorConfiguration1(0x54) && //
writeCorrelatorConfiguration2(0x00) && //
writeMaskInterrupts(0) && //
nfc_initial_field_on();
#if 0
if (ret) {
uint8_t reg = 0x00;
for (auto&& v : val_table) {
// if (reg < 0x3F) {
// if(reg <= 0x20){ // OK
// if(reg <= 0x10){ // NG
// if(reg <= 0x18){ // OK
// if(reg <= 0x14){ // NG
// if(reg <= 0x16){ // OK
// if(reg <= 0x15){ // NG
if (reg >= 0x16 && reg <= 0x19) {
write_register8(reg, v);
}
++reg;
}
}
return true;
#endif
}
bool UnitST25R3916::nfcfTransceive(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len,
const uint32_t timeout_ms)
{
CHECK_MODE();
const auto rx_len_org = rx_len;
rx_len = 0;
if (!tx || !tx_len) {
return false;
}
if (timeout_ms && !write_noresponse_timeout(timeout_ms)) {
return false;
}
if (!writeAuxiliaryDefinition(0) || !clearInterrupts() || !writeDirectCommand(CMD_CLEAR_FIFO) ||
!writeFIFO(tx, tx_len) || !writeNumberOfTransmittedBytes(tx_len, 0) ||
!writeDirectCommand(CMD_TRANSMIT_WITH_CRC)) {
return false;
}
// Send only
if (!rx && !rx_len) {
return (wait_for_interrupt(I_txe32, timeout_ms) & I_txe32) != 0;
}
if (rx && rx_len_org) {
if (!wait_for_FIFO(timeout_ms, rx_len_org)) {
M5_LIB_LOGV("NFC-F Timeout");
return false;
}
uint16_t actual{};
if (readFIFO(actual, rx, rx_len_org)) {
rx_len = actual;
return true;
}
M5_LIB_LOGE("Failed to readFIFO %u/%u", actual, rx_len_org);
}
return false;
}
bool UnitST25R3916::nfcfPolling(m5::nfc::f::PICC& picc, const uint16_t system_code,
const m5::nfc::f::RequestCode request_code, const m5::nfc::f::TimeSlot time_slot)
{
CHECK_MODE();
picc = {};
uint8_t packet[] = {m5::stl::to_underlying(CommandCode::Polling), (uint8_t)(system_code >> 8),
(uint8_t)(system_code & 0xFF), m5::stl::to_underlying(request_code),
m5::stl::to_underlying(time_slot)};
// m5::utility::log::dump(packet, sizeof(packet), false);
uint8_t timeout_ms = TIMEOUT_POLLING * TIMEOUT_POLLING_PICC * timeslot_to_slot(time_slot);
uint8_t rbuf[128]{};
uint16_t rx_len{128};
if (!nfcfTransceive(rbuf, rx_len, packet, sizeof(packet), timeout_ms) //
|| rx_len < 20 || rbuf[1] != m5::stl::to_underlying(ResponseCode::Polling)) {
if (rx_len) {
M5_LIB_LOGE("Failed to Polling %u %u %u", rx_len, rbuf[0], rbuf[1]);
}
return false;
}
// m5::utility::log::dump(rbuf, rx_len, false);
memcpy(picc.idm.data(), rbuf + 2, picc.idm.size());
memcpy(picc.pmm.data(), rbuf + 10, picc.pmm.size());
picc.request_code = request_code;
if (rbuf[0] >= 20) {
picc.request_data = ((uint16_t)rbuf[18]) << 0;
picc.request_data |= (uint16_t)rbuf[19];
}
return true;
}
bool UnitST25R3916::nfcfRequestService(const m5::nfc::f::PICC& picc)
{
CHECK_MODE();
std::vector<uint8_t> packet{};
uint8_t node_size = 1;
packet.resize(1 + 8 + 1 + (2 * node_size));
uint8_t timeout_ms = 10;
packet[0] = m5::stl::to_underlying(CommandCode::RequestService);
memcpy(packet.data() + 1, picc.idm.data(), picc.idm.size());
packet[9] = node_size;
packet[10] = 0xAA; // todo
packet[11] = 0xBB; // toddo
uint8_t rbuf[packet.size()]{};
uint16_t rx_len{packet.size()};
if (!nfcfTransceive(rbuf, rx_len, packet.data(), packet.size(), timeout_ms) //
|| rx_len < packet.size() || rbuf[1] != m5::stl::to_underlying(ResponseCode::RequestService)) {
if (rx_len) {
M5_LIB_LOGE("Failed to RequestService %u %u", rx_len, rbuf[0]);
}
return false;
}
m5::utility::log::dump(rbuf, rx_len, false);
return true;
}
} // namespace unit
} // namespace m5
#if 0
/*
RFAL
14:34:49.261 > DUMP:0x3fcebc8b 5 bytes
14:34:49.267 > 0x3fcebc8b| 00 FF FF 00 03 |.....
14:34:49.268 > SpaceA
14:34:49.270 > Reg[0x00]:0x07:00000111
14:34:49.272 > Reg[0x01]:0x3C:00111100
14:34:49.274 > Reg[0x02]:0xCB:11001011
14:34:49.276 > Reg[0x03]:0x1C:00011100
14:34:49.278 > Reg[0x04]:0x11:00010001
14:34:49.280 > Reg[0x05]:0x00:00000000
14:34:49.283 > Reg[0x06]:0x00:00000000
14:34:49.285 > Reg[0x07]:0x00:00000000
14:34:49.287 > Reg[0x08]:0x5D:01011101
14:34:49.289 > Reg[0x09]:0x00:00000000
14:34:49.291 > Reg[0x0A]:0x00:00000000
14:34:49.293 > Reg[0x0B]:0x13:00010011
14:34:49.296 > Reg[0x0C]:0x3D:00111101
14:34:49.298 > Reg[0x0D]:0x00:00000000
14:34:49.300 > Reg[0x0E]:0x00:00000000
14:34:49.302 > Reg[0x0F]:0x28:00101000
14:34:49.304 > Reg[0x10]:0x06:00000110
14:34:49.306 > Reg[0x11]:0x11:00010001
14:34:49.309 > Reg[0x12]:0x22:00100010
14:34:49.311 > Reg[0x13]:0x02:00000010
14:34:49.313 > Reg[0x14]:0xCA:11001010
14:34:49.315 > Reg[0x15]:0x80:10000000
14:34:49.317 > Reg[0x16]:0x85:10000101 Mask M_osc, RFU, M_col
14:34:49.319 > Reg[0x17]:0xA6:10100110 M_dct, M_gpe, M_cac, M_cat
14:34:49.322 > Reg[0x18]:0x0F:00001111
14:34:49.324 > Reg[0x19]:0x7B:01111011 M_sl_wl, M_apon, M_rxe_pta, M_wu_f, M_wu_a_, M_wu_a
14:34:49.326 > Reg[0x1A]:0x00:00000000
14:34:49.328 > Reg[0x1B]:0x00:00000000
14:34:49.330 > Reg[0x1C]:0x00:00000000
14:34:49.332 > Reg[0x1D]:0x00:00000000
14:34:49.335 > Reg[0x1E]:0x00:00000000
14:34:49.337 > Reg[0x1F]:0x00:00000000
14:34:49.339 > Reg[0x20]:0x00:00000000
14:34:49.341 > Reg[0x21]:0x00:00000000
14:34:49.343 > Reg[0x22]:0x00:00000000
14:34:49.345 > Reg[0x23]:0x28:00101000
14:34:49.348 > Reg[0x24]:0x00:00000000
14:34:49.350 > Reg[0x25]:0xDF:11011111
14:34:49.352 > Reg[0x26]:0x82:10000010
14:34:49.354 > Reg[0x27]:0x82:10000010
14:34:49.356 > Reg[0x28]:0x70:01110000
14:34:49.358 > Reg[0x29]:0x5F:01011111
14:34:49.361 > Reg[0x2A]:0x13:00010011
14:34:49.363 > Reg[0x2B]:0x02:00000010
14:34:49.365 > Reg[0x2C]:0x00:00000000
14:34:49.367 > Reg[0x2D]:0x00:00000000
14:34:49.369 > Reg[0x2E]:0x00:00000000
14:34:49.372 > Reg[0x2F]:0x00:00000000
14:34:49.374 > Reg[0x30]:0x00:00000000
14:34:49.376 > Reg[0x31]:0x10:00010000
14:34:49.378 > Reg[0x32]:0x00:00000000
14:34:49.380 > Reg[0x33]:0x00:00000000
14:34:49.382 > Reg[0x34]:0x00:00000000
14:34:49.385 > Reg[0x35]:0x00:00000000
14:34:49.387 > Reg[0x36]:0x00:00000000
14:34:49.389 > Reg[0x37]:0x00:00000000
14:34:49.391 > Reg[0x38]:0x00:00000000
14:34:49.393 > Reg[0x39]:0x00:00000000
14:34:49.395 > Reg[0x3A]:0x00:00000000
14:34:49.398 > Reg[0x3B]:0x00:00000000
14:34:49.400 > Reg[0x3C]:0x00:00000000
14:34:49.402 > Reg[0x3D]:0x00:00000000
14:34:49.404 > Reg[0x3E]:0x00:00000000
14:34:49.406 > Reg[0x3F]:0x2A:00101010
14:34:49.407 > SpaceB
14:34:49.409 > Reg[0x00]:0x40:01000000
14:34:49.411 > Reg[0x01]:0x14:00010100
14:34:49.414 > Reg[0x02]:0x0C:00001100
14:34:49.416 > Reg[0x03]:0x54:01010100
14:34:49.418 > Reg[0x04]:0x00:00000000
14:34:49.420 > Reg[0x05]:0x00:00000000
14:34:49.422 > Reg[0x06]:0x00:00000000
14:34:49.424 > Reg[0x07]:0x10:00010000
14:34:49.426 > Reg[0x08]:0x7C:01111100
14:34:49.429 > Reg[0x09]:0x80:10000000
14:34:49.431 > Reg[0x0A]:0x04:00000100
14:34:49.433 > Reg[0x0B]:0xD0:11010000
14:34:49.435 > Reg[0x0C]:0x00:00000000
14:34:49.437 > Reg[0x0D]:0x00:00000000
14:34:49.439 > Reg[0x0E]:0x00:00000000
14:34:49.442 > Reg[0x0F]:0x00:00000000
14:34:49.445 > ST25R3916_CMD_TRANSMIT_WITH_CRC
----
MINE
14:36:51.267 > DUMP:0x3fcebce7 5 bytes
14:36:51.267 > 0x3fcebce7| 00 FF FF 00 03 |.....
14:36:51.269 > [ 4100][I][unit_ST25R3916.cpp:627] dumpRegister(): SpaceA
14:36:51.275 > [ 4102][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X00]:0X00:00000000
14:36:51.282 > [ 4109][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X01]:0X98:10011000
14:36:51.289 > [ 4115][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X02]:0X88:10001000
14:36:51.295 > [ 4122][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X03]:0X1C:00011100
14:36:51.302 > [ 4129][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X04]:0X11:00010001
14:36:51.309 > [ 4135][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X05]:0X00:00000000
14:36:51.315 > [ 4142][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X06]:0X00:00000000
14:36:51.322 > [ 4149][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X07]:0X00:00000000
14:36:51.329 > [ 4155][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X08]:0X00:00000000
14:36:51.336 > [ 4162][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X09]:0X00:00000000
14:36:51.342 > [ 4169][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X0A]:0X01:00000001
14:36:51.349 > [ 4175][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X0B]:0X13:00010011
14:36:51.356 > [ 4182][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X0C]:0X3D:00111101
14:36:51.362 > [ 4189][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X0D]:0X00:00000000
14:36:51.369 > [ 4195][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X0E]:0X00:00000000
14:36:51.376 > [ 4202][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X0F]:0X0C:00001100
14:36:51.382 > [ 4209][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X10]:0X4F:01001111
14:36:51.389 > [ 4215][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X11]:0X74:01110100
14:36:51.396 > [ 4222][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X12]:0X00:00000000
14:36:51.402 > [ 4229][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X13]:0X00:00000000
14:36:51.409 > [ 4236][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X14]:0X00:00000000
14:36:51.416 > [ 4242][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X15]:0X80:10000000
14:36:51.422 > [ 4249][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X16]:0XFF:11111111
14:36:51.429 > [ 4256][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X17]:0XFF:11111111
14:36:51.436 > [ 4262][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X18]:0X00:00000000
14:36:51.443 > [ 4269][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X19]:0XFB:11111011
14:34:49.317 > Reg[0x16]:0x85:10000101 Mask M_osc, RFU, M_col
14:34:49.319 > Reg[0x17]:0xA6:10100110 M_dct, M_gpe, M_cac, M_cat
14:34:49.322 > Reg[0x18]:0x0F:00001111 Error mask
14:34:49.324 > Reg[0x19]:0x7B:01111011 M_sl_wl, M_apon, M_rxe_pta, M_wu_f, M_wu_a_, M_wu_a
14:36:51.449 > [ 4276][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X1A]:0X00:00000000
14:36:51.456 > [ 4282][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X1B]:0X00:00000000
14:36:51.463 > [ 4289][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X1C]:0X00:00000000
14:36:51.469 > [ 4296][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X1D]:0X00:00000000
14:36:51.476 > [ 4302][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X1E]:0X00:00000000
14:36:51.483 > [ 4309][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X1F]:0X00:00000000
14:36:51.489 > [ 4316][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X20]:0X00:00000000
14:36:51.496 > [ 4322][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X21]:0X00:00000000
14:36:51.503 > [ 4329][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X22]:0X00:00000000
14:36:51.509 > [ 4336][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X23]:0X28:00101000
14:36:51.516 > [ 4342][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X24]:0X00:00000000
14:36:51.523 > [ 4349][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X25]:0X00:00000000
14:36:51.529 > [ 4356][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X26]:0X80:10000000
14:36:51.536 > [ 4363][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X27]:0X80:10000000
14:36:51.543 > [ 4369][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X28]:0XD0:11010000
14:36:51.549 > [ 4376][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X29]:0X60:01100000
14:36:51.556 > [ 4383][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X2A]:0X33:00110011
14:36:51.563 > [ 4389][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X2B]:0X22:00100010
14:36:51.569 > [ 4396][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X2C]:0X00:00000000
14:36:51.576 > [ 4403][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X2D]:0X00:00000000
14:36:51.583 > [ 4409][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X2E]:0X00:00000000
14:36:51.589 > [ 4416][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X2F]:0X00:00000000
14:36:51.596 > [ 4423][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X30]:0X00:00000000
14:36:51.603 > [ 4429][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X31]:0X10:00010000
14:36:51.610 > [ 4436][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X32]:0X00:00000000
14:36:51.616 > [ 4443][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X33]:0X00:00000000
14:36:51.623 > [ 4449][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X34]:0X00:00000000
14:36:51.630 > [ 4456][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X35]:0X00:00000000
14:36:51.636 > [ 4463][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X36]:0X00:00000000
14:36:51.643 > [ 4469][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X37]:0X00:00000000
14:36:51.650 > [ 4476][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X38]:0X00:00000000
14:36:51.656 > [ 4483][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X39]:0X00:00000000
14:36:51.663 > [ 4490][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X3A]:0X00:00000000
14:36:51.670 > [ 4496][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X3B]:0X00:00000000
14:36:51.676 > [ 4503][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X3C]:0X00:00000000
14:36:51.683 > [ 4510][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X3D]:0X00:00000000
14:36:51.690 > [ 4516][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X3E]:0X00:00000000
14:36:51.696 > [ 4523][I][unit_ST25R3916.cpp:631] dumpRegister(): Reg[0X3F]:0X2A:00101010
14:36:51.702 > [ 4530][I][unit_ST25R3916.cpp:652] dumpRegister(): SpaceB
14:36:51.708 > [ 4535][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X05]:0X00:00000000
14:36:51.715 > [ 4542][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X06]:0X00:00000000
14:36:51.722 > [ 4548][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X0B]:0X0C:00001100
14:36:51.728 > [ 4555][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X0C]:0X54:01010100
14:36:51.735 > [ 4562][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X0D]:0X00:00000000
14:36:51.742 > [ 4568][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X0F]:0X00:00000000
14:36:51.748 > [ 4575][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X15]:0X33:00110011
14:36:51.755 > [ 4582][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X28]:0X10:00010000
14:36:51.762 > [ 4588][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X29]:0X7C:01111100
14:36:51.768 > [ 4595][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X2A]:0X00:00000000
14:36:51.775 > [ 4602][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X2B]:0X04:00000100
14:36:51.782 > [ 4608][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X2C]:0XF0:11110000
14:36:51.789 > [ 4615][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X30]:0X00:00000000
14:36:51.795 > [ 4622][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X31]:0X00:00000000
14:36:51.802 > [ 4628][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X32]:0X00:00000000
14:36:51.809 > [ 4635][I][unit_ST25R3916.cpp:656] dumpRegister(): Reg[0X33]:0X00:00000000
14:34:49.407 > SpaceB
14:34:49.409 > Reg[0x05]:0x40:01000000
14:34:49.411 > Reg[0x06]:0x14:00010100
14:34:49.414 > Reg[0x0B]:0x0C:00001100
14:34:49.416 > Reg[0x0C]:0x54:01010100
14:34:49.418 > Reg[0x0D]:0x00:00000000
14:34:49.420 > Reg[0x0F]:0x00:00000000
14:34:49.422 > Reg[0x15]:0x00:00000000
14:34:49.424 > Reg[0x28]:0x10:00010000
14:34:49.426 > Reg[0x29]:0x7C:01111100
14:34:49.429 > Reg[0x2A]:0x80:10000000
14:34:49.431 > Reg[0x2B]:0x04:00000100
14:34:49.433 > Reg[0x2C]:0xD0:11010000
14:34:49.435 > Reg[0x30]:0x00:00000000
14:34:49.437 > Reg[0x31]:0x00:00000000
14:34:49.439 > Reg[0x32]:0x00:00000000
14:34:49.442 > Reg[0x33]:0x00:00000000
*/
#endif