mirror of
https://github.com/m5stack/M5Unit-NFC.git
synced 2026-05-20 11:48:34 -07:00
Add support NFC-F(WIP)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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{};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user