From 3185d8f5e3fb570460e184b643e4b4080050b786 Mon Sep 17 00:00:00 2001 From: chenjintao Date: Tue, 22 Sep 2026 16:08:58 +0800 Subject: [PATCH] feat(nfc): emulate Type 2 NDEF tag --- .../threadx/interface/custom_app/nfc.c | 142 +++++++++++++----- 1 file changed, 108 insertions(+), 34 deletions(-) diff --git a/ql-application/threadx/interface/custom_app/nfc.c b/ql-application/threadx/interface/custom_app/nfc.c index 95a6308..1d3e2fa 100644 --- a/ql-application/threadx/interface/custom_app/nfc.c +++ b/ql-application/threadx/interface/custom_app/nfc.c @@ -1,6 +1,7 @@ -#if 1 -#include -#include "ql_rtos.h" +#if 1 +#include +#include +#include "ql_rtos.h" #include "ql_application.h" #include "ql_audio.h" #include "ql_iic.h" @@ -10,6 +11,7 @@ #include "DP1312EA.h" #include "TypeA.h" #include "LPCD.h" +#include "hal_api.h" #define NFC_WORK_MODE_READER 0 #define NFC_WORK_MODE_CARD_EMULATION 1 @@ -48,11 +50,19 @@ static volatile int g_nfc_irq_trigger = 0; #define NFC_CARD_TX_POLLS 20 #define NFC_CARD_RX_POLLS 200 #define NFC_CARD_SESSION_POLL_MS 1 +#define NFC_TYPE2_PAGE_SIZE 4 +#define NFC_TYPE2_READ_SIZE 16 +#define NFC_TYPE2_MEMORY_SIZE 160 +#define NFC_TYPE2_NDEF_OFFSET 16 #define NFC_IRQ_TX 0x40 #define NFC_IRQ_RX 0x20 #define NFC_IRQ_ERR 0x02 +extern int hal_os_get_device_sn(char *pdevice_sn); + +static u8 nfc_type2_memory[NFC_TYPE2_MEMORY_SIZE]; + 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 txm=%02X rxm=%02X framing=%02X\r\n", @@ -130,16 +140,83 @@ static u8 nfc_card_emulation_send_frame(const u8 *frame, u8 length) } DP1312EA_WriteRawRC(BitFramingReg, 0x00); - nfc_card_emulation_log_status("ATS transmit failed"); + nfc_card_emulation_log_status("frame transmit failed"); return 0; } -static void nfc_card_emulation_configure_iso_dep(void) +static void nfc_type2_build_ndef(void) +{ + char device_id[32] = {0}; + char serial_number[32] = {0}; + char json[128]; + int json_len; + u8 *ndef; + u8 record_len; + + if (hal_os_get_device_id(device_id) != 0) { + strcpy(device_id, "unknown"); + } + if (hal_os_get_device_sn(serial_number) != 0) { + strcpy(serial_number, "unknown"); + } + + json_len = snprintf(json, sizeof(json), + "{\"device_id\":\"%s\",\"serial_number\":\"%s\"}", + device_id, serial_number); + if (json_len < 0) { + json_len = 0; + } else if (json_len >= (int)sizeof(json)) { + json_len = sizeof(json) - 1; + } + + memset(nfc_type2_memory, 0, sizeof(nfc_type2_memory)); + + /* Static UID/manufacturer pages followed by a read-only Type 2 CC. */ + nfc_type2_memory[0] = 0x08; + nfc_type2_memory[1] = 0xAA; + nfc_type2_memory[2] = 0xBB; + nfc_type2_memory[3] = 0xCC; + nfc_type2_memory[12] = 0xE1; + nfc_type2_memory[13] = 0x10; + nfc_type2_memory[14] = 0x12; /* 144 data bytes (18 x 8). */ + nfc_type2_memory[15] = 0x0F; /* Read-only access. */ + + ndef = &nfc_type2_memory[NFC_TYPE2_NDEF_OFFSET]; + record_len = (u8)(7 + json_len); + ndef[0] = 0x03; /* NDEF Message TLV. */ + ndef[1] = record_len; + ndef[2] = 0xD1; /* MB, ME, SR, TNF well-known. */ + ndef[3] = 0x01; /* Type length. */ + ndef[4] = (u8)(3 + json_len); /* Text status/lang plus JSON. */ + ndef[5] = 'T'; + ndef[6] = 0x02; /* UTF-8, language length 2. */ + ndef[7] = 'e'; + ndef[8] = 'n'; + memcpy(&ndef[9], json, json_len); + ndef[9 + json_len] = 0xFE; /* Terminator TLV. */ + + printf("NFC Type 2 NDEF: %s\r\n", json); +} + +static void nfc_type2_read_pages(u8 start_page, u8 *response) +{ + u16 start = (u16)start_page * NFC_TYPE2_PAGE_SIZE; + u8 i; + + for (i = 0; i < NFC_TYPE2_READ_SIZE; i++) { + u16 offset = start + i; + response[i] = offset < NFC_TYPE2_MEMORY_SIZE + ? nfc_type2_memory[offset] + : 0x00; + } +} + +static void nfc_card_emulation_configure_type2(void) { static const u8 card_config[] = { 0x44, 0x00, /* SENS_RES / ATQA */ 0xAA, 0xBB, 0xCC, /* NFCID1; first byte 08 is added by PN512 */ - 0x20, /* SEL_RES / SAK: ISO-DEP supported */ + 0x00, /* SEL_RES / SAK: Type 2, no ISO-DEP */ 0x01, 0xFE, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xFF, 0xFF, @@ -161,19 +238,16 @@ static void nfc_card_emulation_start(void) DP1312EA_WriteRawRC(DivIrqReg, 0x7F); DP1312EA_SetBitMask(FIFOLevelReg, 0x80); - nfc_card_emulation_configure_iso_dep(); + nfc_type2_build_ndef(); + nfc_card_emulation_configure_type2(); nfc_card_emulation_log_status("started"); - printf("NFC phase-2 probe: ATQA=44 00, UID=08 AA BB CC, SAK=20\r\n"); + printf("NFC Type 2 tag: 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 response[NFC_TYPE2_READ_SIZE]; u8 frame_len; u16 poll_count; u8 last_command = 0xFF; @@ -191,22 +265,16 @@ static void nfc_card_emulation_task(void) 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) { - if (!nfc_card_emulation_send_frame(ats, sizeof(ats))) { - nfc_card_emulation_log_status("session complete"); - nfc_card_emulation_start(); - last_command = DP1312EA_AUTOCOLL; - ql_rtos_task_sleep_ms(1); - continue; + while (frame_len >= 2 && frame[0] == 0x30) { + nfc_card_emulation_log_frame("Type 2 READ RX", frame, + frame_len); + nfc_type2_read_pages(frame[1], response); + if (!nfc_card_emulation_send_frame(response, + sizeof(response))) { + break; } + printf("NFC Type 2 READ page %u TX complete\r\n", frame[1]); - nfc_card_emulation_log_frame("ATS TX complete", ats, - sizeof(ats)); - - /* Transceive automatically switches from transmit to receive. - * Only clear the completed TX interrupt; do not stop command. */ DP1312EA_WriteRawRC(ComIrqReg, NFC_IRQ_TX); for (poll_count = 0; poll_count < NFC_CARD_RX_POLLS; @@ -214,7 +282,7 @@ static void nfc_card_emulation_task(void) u8 irq = DP1312EA_ReadRawRC(ComIrqReg); if ((irq & NFC_IRQ_ERR) != 0) { - nfc_card_emulation_log_status("ISO-DEP receive error"); + nfc_card_emulation_log_status("Type 2 receive error"); break; } @@ -222,8 +290,6 @@ static void nfc_card_emulation_task(void) (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; } @@ -231,10 +297,18 @@ static void nfc_card_emulation_task(void) } if (poll_count == NFC_CARD_RX_POLLS) { - nfc_card_emulation_log_status("ISO-DEP receive timeout"); + nfc_card_emulation_log_status("Type 2 receive timeout"); + break; } - } else { - printf("NFC activation frame is not RATS\r\n"); + + if ((DP1312EA_ReadRawRC(ComIrqReg) & NFC_IRQ_ERR) != 0) { + break; + } + } + + if (frame_len > 0 && !(frame_len >= 2 && frame[0] == 0x30)) { + nfc_card_emulation_log_frame("Type 2 session end RX", frame, + frame_len); } nfc_card_emulation_log_status("session complete"); @@ -273,7 +347,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 2 probe)\r\n"); + printf("NFC work mode: CARD_EMULATION (Type 2 NDEF)\r\n"); nfc_card_emulation_task(); #else s8 read_status;