From 913c5b9f7160e9700f5c092adda229745ae8249e Mon Sep 17 00:00:00 2001 From: chenjintao Date: Tue, 22 Sep 2026 15:30:06 +0800 Subject: [PATCH] feat(nfc): probe ISO-DEP activation --- .../threadx/interface/custom_app/nfc.c | 110 ++++++++++++++++-- 1 file changed, 100 insertions(+), 10 deletions(-) diff --git a/ql-application/threadx/interface/custom_app/nfc.c b/ql-application/threadx/interface/custom_app/nfc.c index 6539d90..c0ab62e 100644 --- a/ql-application/threadx/interface/custom_app/nfc.c +++ b/ql-application/threadx/interface/custom_app/nfc.c @@ -44,6 +44,10 @@ static volatile int g_nfc_irq_trigger = 0; #endif #if (NFC_WORK_MODE == NFC_WORK_MODE_CARD_EMULATION) +#define NFC_CARD_FRAME_MAX 64 +#define NFC_CARD_SESSION_POLLS 200 +#define NFC_CARD_SESSION_POLL_MS 1 + static void nfc_card_emulation_log_status(const char *reason) { printf("NFC card emulation %s: cmd=%02X irq=%02X err=%02X status1=%02X status2=%02X fifo=%02X\r\n", @@ -56,6 +60,52 @@ static void nfc_card_emulation_log_status(const char *reason) DP1312EA_ReadRawRC(FIFOLevelReg)); } +static u8 nfc_card_emulation_read_frame(u8 *frame, u8 capacity) +{ + u8 fifo_len = DP1312EA_ReadRawRC(FIFOLevelReg) & 0x7F; + u8 read_len = fifo_len; + + if (read_len > capacity) { + read_len = capacity; + } + + if (read_len > 0) { + DP1312EA_ReadFIFO(frame, read_len); + } + + while (read_len < fifo_len) { + (void)DP1312EA_ReadRawRC(FIFODataReg); + read_len++; + } + + return fifo_len > capacity ? capacity : fifo_len; +} + +static void nfc_card_emulation_log_frame(const char *prefix, + const u8 *frame, + u8 length) +{ + u8 i; + + printf("NFC %s (%u):", prefix, length); + for (i = 0; i < length; i++) { + printf(" %02X", frame[i]); + } + printf("\r\n"); +} + +static void nfc_card_emulation_send_frame(const u8 *frame, u8 length) +{ + DP1312EA_WriteRawRC(ComIrqReg, 0x7F); + DP1312EA_SetBitMask(FIFOLevelReg, 0x80); + DP1312EA_WriteFIFO((u8 *)frame, length); + + /* AutoColl leaves Transceive active and waiting for StartSend. */ + DP1312EA_SetBitMask(TxModeReg, 0x80); + DP1312EA_SetBitMask(RxModeReg, 0x80); + DP1312EA_WriteRawRC(BitFramingReg, 0x80); +} + static void nfc_card_emulation_start(void) { DP1312EA_WriteRawRC(CommandReg, DP1312EA_IDLE); @@ -65,11 +115,19 @@ static void nfc_card_emulation_start(void) DP1312EA_Simulate_Card(); nfc_card_emulation_log_status("started"); - printf("NFC phase-1 target: ATQA=44 00, UID=08 AA BB CC, SAK=00\r\n"); + printf("NFC phase-2 probe: ATQA=44 00, UID=08 AA BB CC, SAK=00\r\n"); } static void nfc_card_emulation_task(void) { + static const u8 ats[] = { + 0x03, /* TL: three ATS bytes */ + 0x24, /* TB(1) present, FSCI=4 (48-byte frame size) */ + 0x80 /* FWI=8 (~77 ms frame waiting time), SFGI=0 */ + }; + u8 frame[NFC_CARD_FRAME_MAX]; + u8 frame_len; + u16 poll_count; u8 last_command = 0xFF; u8 command; @@ -83,18 +141,50 @@ static void nfc_card_emulation_task(void) last_command = command; } - if (command != DP1312EA_AUTOCOLL) { - /* - * AutoColl normally exits after selection or on an RF/error event. - * Phase 1 has no ISO14443-4 handler yet, so allow the phone time to - * finish its probe, then arm AutoColl again for the next tap. - */ - ql_rtos_task_sleep_ms(500); + if (command == DP1312EA_TRANSCEIVE) { + frame_len = nfc_card_emulation_read_frame(frame, sizeof(frame)); + nfc_card_emulation_log_frame("activation RX", frame, frame_len); + + if (frame_len == 2 && frame[0] == 0xE0) { + nfc_card_emulation_send_frame(ats, sizeof(ats)); + nfc_card_emulation_log_frame("ATS TX", ats, sizeof(ats)); + + for (poll_count = 0; + poll_count < NFC_CARD_SESSION_POLLS; + poll_count++) { + u8 irq = DP1312EA_ReadRawRC(ComIrqReg); + u8 error = DP1312EA_ReadRawRC(ErrorReg); + + if (error != 0) { + nfc_card_emulation_log_status("ISO-DEP error"); + break; + } + + if ((irq & 0x20) != 0 && + (DP1312EA_ReadRawRC(FIFOLevelReg) & 0x7F) != 0) { + frame_len = nfc_card_emulation_read_frame( + frame, sizeof(frame)); + nfc_card_emulation_log_frame( + "first ISO-DEP RX", frame, frame_len); + break; + } + + ql_rtos_task_sleep_ms(NFC_CARD_SESSION_POLL_MS); + } + } else { + printf("NFC activation frame is not RATS\r\n"); + } + + nfc_card_emulation_log_status("session complete"); + nfc_card_emulation_start(); + last_command = DP1312EA_AUTOCOLL; + } else if (command != DP1312EA_AUTOCOLL) { + nfc_card_emulation_log_status("unexpected command"); nfc_card_emulation_start(); last_command = DP1312EA_AUTOCOLL; } - ql_rtos_task_sleep_ms(20); + ql_rtos_task_sleep_ms(1); } } #endif @@ -121,7 +211,7 @@ static void nfc_irq_wake(void *args) void ql_nfc_task_thread(void *arvg) { #if (NFC_WORK_MODE == NFC_WORK_MODE_CARD_EMULATION) - printf("NFC work mode: CARD_EMULATION (phase 1)\r\n"); + printf("NFC work mode: CARD_EMULATION (phase 2 probe)\r\n"); nfc_card_emulation_task(); #else s8 read_status;