feat(nfc): add phase-one card emulation mode

This commit is contained in:
chenjintao
2026-09-22 14:53:10 +08:00
parent 381db92214
commit d8b2114d0e
+142 -55
View File
@@ -5,47 +5,126 @@
#include "ql_audio.h"
#include "ql_iic.h"
#include "ql_gpio.h"
#include "app_inc.h"
#include "ql_fs.h"
extern int fota_start;
extern int audio_packet_type;
extern volatile int tts_playing;
extern int g_testmode;
static ql_sem_t nfc_irq_sem = NULL;
#define DP1312EA_PIN_IRQ GPIO_PIN_NO_85
// NFC 任务状态
#include "app_inc.h"
#include "ql_fs.h"
#include "DP1312EA.h"
#include "TypeA.h"
#include "LPCD.h"
#define NFC_WORK_MODE_READER 0
#define NFC_WORK_MODE_CARD_EMULATION 1
/*
* Phase-1 validation switch.
* Set to NFC_WORK_MODE_READER to restore the original NTAG213 reader flow.
*/
#ifndef NFC_WORK_MODE
#define NFC_WORK_MODE NFC_WORK_MODE_CARD_EMULATION
#endif
#define DP1312EA_PIN_IRQ GPIO_PIN_NO_85
#if (NFC_WORK_MODE == NFC_WORK_MODE_READER)
extern int fota_start;
extern int audio_packet_type;
extern volatile int tts_playing;
extern int g_testmode;
static ql_sem_t nfc_irq_sem = NULL;
// NFC 任务状态
typedef enum {
NFC_STATE_LPCD_WAIT, // 低功耗等待中断
NFC_STATE_POLLING, // 500ms 轮询读卡中
} nfc_state_t;
static volatile nfc_state_t g_nfc_state = NFC_STATE_LPCD_WAIT;
static volatile int g_poll_fail_count = 0;
static volatile int g_nfc_irq_trigger = 0;
static void nfc_irq_wake(void *args)
{
unsigned char level = 0;
ql_eint_disable_wakeup(DP1312EA_PIN_IRQ);
ql_gpio_get_level(DP1312EA_PIN_IRQ, &level);
printf("DP1312EA_PIN_IRQ level:%d\n", level);
ql_eint_enable_wakeup(DP1312EA_PIN_IRQ, PIN_RISING_EDGE);
if(g_nfc_irq_trigger==0){
g_nfc_irq_trigger = 1;
ql_rtos_semaphore_release(nfc_irq_sem);
}
}
void ql_nfc_task_thread(void *arvg)
{
s8 read_status;
static volatile nfc_state_t g_nfc_state = NFC_STATE_LPCD_WAIT;
static volatile int g_poll_fail_count = 0;
static volatile int g_nfc_irq_trigger = 0;
#endif
#if (NFC_WORK_MODE == NFC_WORK_MODE_CARD_EMULATION)
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",
reason,
DP1312EA_ReadRawRC(CommandReg),
DP1312EA_ReadRawRC(ComIrqReg),
DP1312EA_ReadRawRC(ErrorReg),
DP1312EA_ReadRawRC(Status1Reg),
DP1312EA_ReadRawRC(Status2Reg),
DP1312EA_ReadRawRC(FIFOLevelReg));
}
static void nfc_card_emulation_start(void)
{
DP1312EA_WriteRawRC(CommandReg, DP1312EA_IDLE);
DP1312EA_WriteRawRC(ComIrqReg, 0x7F);
DP1312EA_WriteRawRC(DivIrqReg, 0x7F);
DP1312EA_SetBitMask(FIFOLevelReg, 0x80);
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");
}
static void nfc_card_emulation_task(void)
{
u8 last_command = 0xFF;
u8 command;
nfc_card_emulation_start();
while (1) {
command = DP1312EA_ReadRawRC(CommandReg) & 0x0F;
if (command != last_command) {
nfc_card_emulation_log_status("state changed");
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);
nfc_card_emulation_start();
last_command = DP1312EA_AUTOCOLL;
}
ql_rtos_task_sleep_ms(20);
}
}
#endif
#if (NFC_WORK_MODE == NFC_WORK_MODE_READER)
static void nfc_irq_wake(void *args)
{
unsigned char level = 0;
ql_eint_disable_wakeup(DP1312EA_PIN_IRQ);
ql_gpio_get_level(DP1312EA_PIN_IRQ, &level);
printf("DP1312EA_PIN_IRQ level:%d\n", level);
ql_eint_enable_wakeup(DP1312EA_PIN_IRQ, PIN_RISING_EDGE);
if(g_nfc_irq_trigger==0){
g_nfc_irq_trigger = 1;
ql_rtos_semaphore_release(nfc_irq_sem);
}
}
#endif
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");
nfc_card_emulation_task();
#else
s8 read_status;
while(1)
{
@@ -136,28 +215,36 @@ void ql_nfc_task_thread(void *arvg)
ql_rtos_task_sleep_ms(300);
}
}
}
}
}
}
#endif
}
void DP1312EA_Init(void)
{
// 创建信号量
ql_rtos_semaphore_create(&nfc_irq_sem, 0);
// 配置中断引脚
ql_gpio_init(DP1312EA_PIN_IRQ, PIN_DIRECTION_IN, PIN_PULL_PD, PIN_LEVEL_LOW);
ql_eint_register(DP1312EA_PIN_IRQ, PIN_RISING_EDGE, PIN_PULL_PD, NULL, nfc_irq_wake);
ql_eint_enable_wakeup(DP1312EA_PIN_IRQ, PIN_RISING_EDGE);
// I2C 和芯片初始化
DP1312EA_Reset();
Check_Chip();
// 初始状态为低功耗等待
g_nfc_state = NFC_STATE_LPCD_WAIT;
g_poll_fail_count = 0;
void DP1312EA_Init(void)
{
#if (NFC_WORK_MODE == NFC_WORK_MODE_READER)
// 创建信号量
ql_rtos_semaphore_create(&nfc_irq_sem, 0);
// 配置中断引脚
ql_gpio_init(DP1312EA_PIN_IRQ, PIN_DIRECTION_IN, PIN_PULL_PD, PIN_LEVEL_LOW);
ql_eint_register(DP1312EA_PIN_IRQ, PIN_RISING_EDGE, PIN_PULL_PD, NULL, nfc_irq_wake);
ql_eint_enable_wakeup(DP1312EA_PIN_IRQ, PIN_RISING_EDGE);
#else
/* Poll IRQ/status registers during the phase-1 card-emulation test. */
ql_gpio_init(DP1312EA_PIN_IRQ, PIN_DIRECTION_IN, PIN_PULL_PD, PIN_LEVEL_LOW);
#endif
// I2C 和芯片初始化
DP1312EA_Reset();
Check_Chip();
// Reader mode starts in low-power card detection.
#if (NFC_WORK_MODE == NFC_WORK_MODE_READER)
g_nfc_state = NFC_STATE_LPCD_WAIT;
g_poll_fail_count = 0;
#endif
// 创建任务
ql_task_t nfcTaskRef = NULL;