mirror of
https://github.com/m5stack/M5Unit-NFC.git
synced 2026-05-20 11:48:34 -07:00
Fixes emulation for NFC-A
This commit is contained in:
@@ -43,18 +43,21 @@ m5::unit::HackerCapNFC unit{}; // HackerCap (SPI)
|
||||
#endif
|
||||
m5::nfc::EmulationLayerA emu_a{unit};
|
||||
|
||||
// KeyA that can authenticate all blocks
|
||||
// If it's a different key value, change it
|
||||
constexpr Key keyA = DEFAULT_KEY; // Default as 0xFFFFFFFFFFFF
|
||||
// constexpr Key keyA = DEFAULT_KEY; // Default as 0xFFFFFFFFFFFF
|
||||
// constexpr Key keyB = DEFAULT_KEY; // Default as 0xFFFFFFFFFFFF
|
||||
|
||||
PICC picc{};
|
||||
|
||||
//#define EMU_MIFARE_ULTRALIGHT
|
||||
#define EMU_NTAG213
|
||||
#define EMU_MIFARE_ULTRALIGHT
|
||||
// HackerCap : iPhone, NFC tools, NFC Taginfo. NFC Tap
|
||||
// Basic+I2C : iPhone, NFC Tap
|
||||
// NG -> NFC tools, NFC Taginfo
|
||||
|
||||
#if defined(EMU_MIFARE_CLASSIC_1K)
|
||||
// #define EMU_NTAG213
|
||||
// HackerCap : iPhone, NFC tools, NFC Taginfo. NFC Tap
|
||||
// Basic+I2C : iPhone, NFC tools, NFC Taginfo. NFC Tap
|
||||
|
||||
#elif defined(EMU_MIFARE_ULTRALIGHT)
|
||||
#if defined(EMU_MIFARE_ULTRALIGHT)
|
||||
constexpr Type type{Type::MIFARE_Ultralight};
|
||||
constexpr uint8_t uid[] = {0x04, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE};
|
||||
uint8_t picc_memory[] = {
|
||||
@@ -186,7 +189,7 @@ void setup()
|
||||
M5_LOGI("getPin: SDA:%u SCL:%u", pin_num_sda, pin_num_scl);
|
||||
Wire.end();
|
||||
Wire.begin(pin_num_sda, pin_num_scl, 400 * 1000U);
|
||||
|
||||
// Wire.begin(pin_num_sda, pin_num_scl, 1000 * 1000u);
|
||||
if (!Units.add(unit, Wire) || !Units.begin()) {
|
||||
M5_LOGE("Failed to begin");
|
||||
lcd.clear(TFT_RED);
|
||||
@@ -221,38 +224,25 @@ void setup()
|
||||
lcd.setFont(&fonts::Font2);
|
||||
|
||||
//
|
||||
picc.emulate(type, uid, sizeof(uid)); // PICC information to emulate
|
||||
if (picc.isMifareUltralight() || picc.isNTAG()) {
|
||||
lcd.startWrite();
|
||||
lcd.fillScreen(TFT_RED);
|
||||
if (picc.emulate(type, uid, sizeof(uid))) {
|
||||
embed_uid(picc_memory, uid);
|
||||
}
|
||||
if (emu_a.begin(picc, picc_memory, sizeof(picc_memory))) {
|
||||
lcd.fillScreen(TFT_DARKGREEN);
|
||||
lcd.setCursor(0, 16);
|
||||
const auto& e_picc = emu_a.emulatePICC();
|
||||
M5.Log.printf("Emulation:%s %s ATQA:%04X SAK:%u\n", e_picc.typeAsString().c_str(), e_picc.uidAsString().c_str(),
|
||||
e_picc.atqa, e_picc.sak);
|
||||
lcd.printf("%s\n%s\nATQA:%04X SAK:%u", e_picc.typeAsString().c_str(), e_picc.uidAsString().c_str(), e_picc.atqa,
|
||||
e_picc.sak);
|
||||
} else {
|
||||
lcd.fillScreen(TFT_RED);
|
||||
if (emu_a.begin(picc, picc_memory, sizeof(picc_memory))) {
|
||||
lcd.fillScreen(TFT_DARKGREEN);
|
||||
lcd.setCursor(0, 16);
|
||||
const auto& e_picc = emu_a.emulatePICC();
|
||||
M5.Log.printf("Emulation:%s %s ATQA:%04X SAK:%u\n", e_picc.typeAsString().c_str(),
|
||||
e_picc.uidAsString().c_str(), e_picc.atqa, e_picc.sak);
|
||||
lcd.printf("%s\n%s\nATQA:%04X SAK:%u", e_picc.typeAsString().c_str(), e_picc.uidAsString().c_str(),
|
||||
e_picc.atqa, e_picc.sak);
|
||||
}
|
||||
}
|
||||
lcd.fillRect(0, 0, 32, 16, color_table[0]);
|
||||
lcd.drawString(state_table[0], 0, 0);
|
||||
lcd.endWrite();
|
||||
}
|
||||
|
||||
/*
|
||||
17:31:54.797 > PICC:04C90EC2DA1C94 NTAG 213 144/180
|
||||
17:31:54.828 > Page :00 01 02 03
|
||||
17:31:54.832 > --------------------
|
||||
17:31:54.834 > [000/00]:04 C9 0E 4B
|
||||
17:31:54.840 > [001/01]:C2 DA 1C 94
|
||||
17:31:54.840 > [002/02]:90 48 00 00
|
||||
|
||||
|
||||
17:34:34.767 > [000/00]:04 C9 0E 4B
|
||||
17:34:34.767 > [001/01]:C2 DA 1C 94
|
||||
17:34:34.767 > [002/02]:18 A3 00 00
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
M5.update();
|
||||
|
||||
@@ -241,6 +241,13 @@ void setup()
|
||||
M5.Log.printf("Please put the PICC and click/hold BtnA\n");
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// NRT 計算が正しいか確認 RFAL 比較
|
||||
// S3:PICC Hacker:NDEF で通すことを目標?
|
||||
// PCD からくる? FRT とかはのうタイミングは?
|
||||
// ISR での IRQ取得のトランザクションは?
|
||||
// no_crc 除去? RFAL は?
|
||||
|
||||
void loop()
|
||||
{
|
||||
M5.update();
|
||||
|
||||
+32
-1
@@ -3,7 +3,8 @@
|
||||
; For UnitTest and examples (Using M5UnitUnified)
|
||||
;-----------------------------------------------------------------------
|
||||
[platformio]
|
||||
;default_envs = UnitNFC_NFCA_Detect_Core_Arduino_latest, UnitNFC_NFCA_Dump_Core_Arduino_latest, UnitNFC_NFCA_ReadWrite_Core_Arduino_latest, UnitNFC_NFCA_ValueBlock_Core_Arduino_latest, UnitNFC_NFCA_NDEF_Core_Arduino_latest, UnitNFC_NFCF_Detect_Core_Arduino_latest, UnitNFC_NFCF_Dump_Core_Arduino_latest, UnitNFC_NFCF_NDEF_Core_Arduino_latest, UnitNFC_NFCF_Subtract_Core_Arduino_latest, UnitNFC_NFCF_ReadWriteMAC_Core_Arduino_latest, UnitNFC_NFCF_JapanTransportationICCard_Core_Arduino_latest, UnitNFC_NFCV_Detect_CardputerADV_Arduino_latest, UnitNFC_NFCV_Dump_CardputerADV_Arduino_latest, UnitNFC_NFCV_NDEF_Core_Arduino_latest
|
||||
;default_envs = UnitNFC_NFCA_Detect_Core_Arduino_latest, UnitNFC_NFCA_Dump_Core_Arduino_latest, UnitNFC_NFCA_ReadWrite_Core_Arduino_latest, UnitNFC_NFCA_ValueBlock_Core_Arduino_latest, UnitNFC_NFCA_NDEF_Core_Arduino_latest, UnitNFC_NFCF_Detect_Core_Arduino_latest, UnitNFC_NFCF_Dump_Core_Arduino_latest, UnitNFC_NFCF_NDEF_Core_Arduino_latest, UnitNFC_NFCF_Subtract_Core_Arduino_latest, UnitNFC_NFCF_ReadWriteMAC_Core_Arduino_latest, UnitNFC_NFCF_JapanTransportationICCard_Core_Arduino_latest, UnitNFC_NFCV_Detect_CardputerADV_Arduino_latest, UnitNFC_NFCV_Dump_CardputerADV_Arduino_latest, UnitNFC_NFCV_NDEF_Core_Arduino_latest, UnitNFC_NFCB_Detect_Core_Arduino_latest, UnitNFC_NFCB_Dump_Core_Arduino_latest, CapHacker_NFCB_Detect_CardputerADV_Arduino_latest, CapHacker_NFCB_Dump_CardputerADV_Arduino_latest
|
||||
|
||||
|
||||
|
||||
[env]
|
||||
@@ -234,6 +235,28 @@ build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/NFCA/NDEF>
|
||||
build_flags = ${option_release.build_flags}
|
||||
-D USING_UNIT_NFC
|
||||
|
||||
[env:UnitNFC_NFCA_Emulation_Core_Arduino_latest]
|
||||
extends=Core, option_release, arduino_latest
|
||||
build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/NFCA/Emulation>
|
||||
build_flags = ${option_release.build_flags}
|
||||
-D USING_UNIT_NFC
|
||||
|
||||
|
||||
|
||||
; NFC-B
|
||||
[env:UnitNFC_NFCB_Detect_Core_Arduino_latest]
|
||||
extends=Core, option_release, arduino_latest
|
||||
build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/NFCB/Detect>
|
||||
build_flags = ${option_release.build_flags}
|
||||
-D USING_UNIT_NFC
|
||||
|
||||
[env:UnitNFC_NFCB_Dump_Core_Arduino_latest]
|
||||
extends=Core, option_release, arduino_latest
|
||||
build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/NFCB/Dump>
|
||||
build_flags = ${option_release.build_flags}
|
||||
-D USING_UNIT_NFC
|
||||
|
||||
|
||||
; NFC-F
|
||||
[env:UnitNFC_NFCF_Detect_Core_Arduino_latest]
|
||||
extends=Core, option_release, arduino_latest
|
||||
@@ -329,6 +352,14 @@ build_flags = ${option_release.build_flags}
|
||||
${CardputerADV.build_flags}
|
||||
-D USING_HACKER_CAP
|
||||
|
||||
[env:CapHacker_NFCA_Emulation_CardputerADV_Arduino_latest]
|
||||
extends=CardputerADV, option_release, arduino_latest
|
||||
build_src_filter = +<*> -<.git/> -<.svn/> +<../examples/UnitUnified/NFCA/Emulation>
|
||||
build_flags = ${option_release.build_flags}
|
||||
${CardputerADV.build_flags}
|
||||
-D USING_HACKER_CAP
|
||||
|
||||
|
||||
; NFC-B
|
||||
[env:CapHacker_NFCB_Detect_CardputerADV_Arduino_latest]
|
||||
extends=CardputerADV, option_release, arduino_latest
|
||||
|
||||
@@ -31,6 +31,11 @@ bool EmulationLayerA::begin(const m5::nfc::a::PICC& picc, uint8_t* ptr, const ui
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(picc.isNTAG() || picc.type == Type::MIFARE_Ultralight)) {
|
||||
M5_LIB_LOGE("Not support %u %s", picc.type, picc.typeAsString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
_picc = picc;
|
||||
_memory = ptr;
|
||||
_memory_size = size;
|
||||
@@ -43,6 +48,8 @@ bool EmulationLayerA::begin(const m5::nfc::a::PICC& picc, uint8_t* ptr, const ui
|
||||
|
||||
_state = _impl->start_emulation(_picc) ? State::Off : State::None;
|
||||
_prev = State::None;
|
||||
|
||||
_expired_at = m5::utility::millis() + _expired_ms;
|
||||
return (_state != State::None);
|
||||
}
|
||||
|
||||
@@ -58,28 +65,31 @@ bool EmulationLayerA::end()
|
||||
void EmulationLayerA::update()
|
||||
{
|
||||
auto save = _state;
|
||||
// if (_state != _prev) {
|
||||
// _expired_at = m5::utility::millis() + _expired_ms; // IRQ byGT ???
|
||||
// }
|
||||
|
||||
switch (_state) {
|
||||
case State::None:
|
||||
break;
|
||||
case State::Off:
|
||||
if (_state != _prev) M5_LIB_LOGE("==OFF");
|
||||
// if (_state != _prev) M5_LIB_LOGE("==OFF");
|
||||
update_off();
|
||||
break;
|
||||
case State::Idle:
|
||||
if (_state != _prev) M5_LIB_LOGE("==IDLE");
|
||||
// if (_state != _prev) M5_LIB_LOGE("==IDLE");
|
||||
update_idle();
|
||||
break;
|
||||
case State::Ready:
|
||||
if (_state != _prev) M5_LIB_LOGE("==READY");
|
||||
// if (_state != _prev) M5_LIB_LOGE("==READY");
|
||||
update_ready();
|
||||
break;
|
||||
case State::Active:
|
||||
if (_state != _prev) M5_LIB_LOGE("==ACTIVE");
|
||||
// if (_state != _prev) M5_LIB_LOGE("==ACTIVE");
|
||||
update_active();
|
||||
break;
|
||||
case State::Halt:
|
||||
if (_state != _prev) M5_LIB_LOGE("==HALT");
|
||||
// if (_state != _prev) M5_LIB_LOGE("==HALT");
|
||||
update_halt();
|
||||
break;
|
||||
default:
|
||||
@@ -119,7 +129,6 @@ EmulationLayerA::State EmulationLayerA::receive_callback(const uint8_t* rx, cons
|
||||
return State::Idle;
|
||||
}
|
||||
// m5::utility::log::dump(rx, rx_len, false);
|
||||
M5_LIB_LOGE("cmd:%02X %u", rx[0], rx_len);
|
||||
|
||||
State ret{State::Idle};
|
||||
switch (static_cast<Command>(rx[0])) {
|
||||
@@ -127,6 +136,8 @@ EmulationLayerA::State EmulationLayerA::receive_callback(const uint8_t* rx, cons
|
||||
ret = (rx_len == 2 && rx[1] == 0x00) ? State::Halt : State::Idle;
|
||||
break;
|
||||
case Command::READ: // 16 bytes read
|
||||
// M5_LIB_LOGE(" R:%u", rx[1]);
|
||||
|
||||
ret = (rx_len == 2) && _impl->transmit(_memory + _picc.unitSize() * rx[1], 16, 4) ? State::Active
|
||||
: State::Idle;
|
||||
break;
|
||||
@@ -156,6 +167,7 @@ EmulationLayerA::State EmulationLayerA::receive_callback(const uint8_t* rx, cons
|
||||
const uint32_t offset = 4 * rx[1];
|
||||
if (offset + 4 <= _memory_size) {
|
||||
memcpy(_memory + offset, rx + 2, 4);
|
||||
// ret = _impl->send_ack() ? State::Active : State::Idle; // Return ACK
|
||||
ret = _impl->transmit(&ACK_NIBBLE, 1, 1) ? State::Active : State::Idle; // Return ACK
|
||||
}
|
||||
}
|
||||
@@ -170,6 +182,7 @@ EmulationLayerA::State EmulationLayerA::receive_callback(const uint8_t* rx, cons
|
||||
break;
|
||||
|
||||
default:
|
||||
M5_LIB_LOGE("cmd:%02X %u", rx[0], rx_len);
|
||||
break;
|
||||
}
|
||||
// M5_LIB_LOGE(" --> %u", ret);
|
||||
|
||||
@@ -51,16 +51,25 @@ public:
|
||||
{
|
||||
return _picc;
|
||||
}
|
||||
inline uint32_t expiredTime() const
|
||||
{
|
||||
return _expired_ms;
|
||||
}
|
||||
void setExpiredTime(const uint32_t ms)
|
||||
{
|
||||
_expired_ms = ms;
|
||||
}
|
||||
|
||||
bool begin(const m5::nfc::a::PICC& picc, uint8_t* ptr, const uint32_t size);
|
||||
bool end();
|
||||
void update();
|
||||
|
||||
State receive_callback(const uint8_t* rx, const uint32_t rx_len);
|
||||
virtual State receive_callback(const uint8_t* rx, const uint32_t rx_len);
|
||||
|
||||
protected:
|
||||
bool load_config();
|
||||
void update_expired();
|
||||
|
||||
private:
|
||||
void update_off();
|
||||
void update_idle();
|
||||
void update_ready();
|
||||
@@ -73,7 +82,7 @@ protected:
|
||||
|
||||
private:
|
||||
State _state{}, _prev{};
|
||||
uint32_t _expired_ms{10*1000};
|
||||
uint32_t _expired_ms{60 * 1000u};
|
||||
unsigned int _expired_at{};
|
||||
std::unique_ptr<Adapter> _impl;
|
||||
m5::nfc::a::PICC _picc{};
|
||||
@@ -84,9 +93,6 @@ private:
|
||||
struct EmulationLayerA::Adapter {
|
||||
virtual ~Adapter() = default;
|
||||
|
||||
// virtual uint16_t max_fifo_depth() = 0;
|
||||
|
||||
virtual bool load_config(const m5::nfc::a::PICC& picc) = 0;
|
||||
virtual bool start_emulation(const m5::nfc::a::PICC& picc) = 0;
|
||||
virtual bool stop_emulation() = 0;
|
||||
virtual bool transmit(const uint8_t* tx, const uint16_t tx_len, const uint32_t timeout_ms) = 0;
|
||||
|
||||
@@ -277,6 +277,7 @@ bool NFCLayerA::identify_picc(m5::nfc::a::PICC& picc)
|
||||
}
|
||||
// The PICC goes idle when sending an external command, so select again
|
||||
if (!reactivate(picc)) {
|
||||
M5_LIB_LOGE(">>>> ERR3");
|
||||
return false;
|
||||
}
|
||||
// Try ULC Auth
|
||||
@@ -981,12 +982,11 @@ bool NFCLayerA::dump_page_structure(const uint16_t maxPage)
|
||||
"Page :00 01 02 03\n"
|
||||
"--------------------");
|
||||
|
||||
bool ret{true};
|
||||
for (uint_fast8_t page = 0; page < maxPage; page += 4) {
|
||||
if (!dump_page(page, maxPage)) {
|
||||
return false;
|
||||
}
|
||||
ret &= dump_page(page, maxPage);
|
||||
}
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool NFCLayerA::dump_page(const uint8_t page, uint16_t maxPage)
|
||||
|
||||
@@ -245,6 +245,8 @@ EmulationLayerA::State ListenerST25R3916ForA::goto_off()
|
||||
_u.enable_interrupts(I_nfct32 | I_rxs32 | I_crc32 | I_err132 | I_osc32 | I_err232 | I_par32 | I_eon32 | I_eof32 |
|
||||
mode_irq);
|
||||
|
||||
_u.set_bit_register8(REG_AUXILIARY_DEFINITION, no_crc_rx);
|
||||
|
||||
if (is_extra_field()) {
|
||||
return goto_idle();
|
||||
} else {
|
||||
@@ -270,8 +272,9 @@ EmulationLayerA::State ListenerST25R3916ForA::goto_idle()
|
||||
(void)get_irq(I_osc32);
|
||||
}
|
||||
|
||||
_u.set_bit_register8(REG_AUXILIARY_DEFINITION, no_crc_rx);
|
||||
|
||||
if (_layer.state() == EmulationLayerA::State::Active && !_wakeup) {
|
||||
M5_LIB_LOGE(" >> Active to idle");
|
||||
_u.clear_bit_register8(REG_NFCIP_1_PASSIVE_TARGET_DEFINITION, d_106_ac_a); // Enable auto response for NFC-A
|
||||
_u.writeDirectCommand(CMD_GO_TO_SENSE);
|
||||
}
|
||||
@@ -291,6 +294,9 @@ EmulationLayerA::State ListenerST25R3916ForA::goto_ready()
|
||||
return goto_off();
|
||||
}
|
||||
|
||||
_u.clear_bit_register8(REG_AUXILIARY_DEFINITION, no_crc_rx);
|
||||
|
||||
|
||||
_u.clear_bit_register8(REG_OPERATION_CONTROL, wu); // Disable wakeup mode
|
||||
_u.writeModeDefinition(mode_listen_nfc_a); // Disable birrate detection and collision
|
||||
_u.writeBitrate(_bitrate, _bitrate);
|
||||
@@ -364,7 +370,7 @@ EmulationLayerA::State ListenerST25R3916ForA::update_idle()
|
||||
}
|
||||
|
||||
if (is_eof(irq32) && !_data_flag) {
|
||||
M5_LIB_LOGE("OFF");
|
||||
//M5_LIB_LOGE("OFF");
|
||||
return goto_off();
|
||||
}
|
||||
if ((irq32 & I_rxe32) && _bitrate != Bitrate::Invalid) {
|
||||
|
||||
Reference in New Issue
Block a user