Files
portable_modules/nfc/README.md
2026-07-20 10:48:38 +08:00

5.2 KiB
Raw Blame History

NFC Module

这个模块从当前 custom_app 中抽取 DP1312EA + NTAG213 UID 读取功能,目标是后续可以直接移植到别的业务项目。

核心原则:

  • NFC 模块不依赖业务层。
  • 业务层通过回调接入 NFC 事件。
  • I2C/GPIO/中断/RTOS/sleep/log 全部走平台适配层。
  • Quectel SDK 调用只允许出现在 platform/quectel/

目录结构

portable_modules/nfc/
  include/
    nfc_service.h
    nfc_platform.h
  src/
    nfc_service.c
    nfc_dp1312ea.c
    nfc_ntag213.c
  platform/quectel/
    nfc_platform_ql.c
  vendor/dp1312ea/
    TypeA.c
    LPCD.c
    reg.h
    ...
  examples/
    banban_adapter.c
  module.mk

分层说明

  • include/nfc_service.h: 业务层接口。业务只需要关心初始化、启动、UID 回调。
  • include/nfc_platform.h: 平台适配接口。移植到新 SDK 时实现这里的函数。
  • src/nfc_service.c: NFC 服务状态机,包含 LPCD 等待、中断唤醒、轮询读卡、失败回退。
  • src/nfc_dp1312ea.c: DP1312EA 寄存器、reset、transceive 等芯片封装。
  • src/nfc_ntag213.c: NTAG213 兼容 UID 读取。
  • platform/quectel/nfc_platform_ql.c: 当前移远 SDK 适配。
  • vendor/dp1312ea/: 原 DP1312EA TypeA/LPCD/寄存器等底层代码。
  • examples/banban_adapter.c: 当前 Banban 业务接入示例。

当前能力

  • 初始化 DP1312EA。
  • 进入 LPCD 低功耗检卡。
  • IRQ 唤醒后轮询读卡。
  • 读取 NTAG213/Ultralight 兼容标签 UID。
  • 将 UID 以二进制和十六进制字符串形式回调给业务层。

暂未实现完整写 NFC 标签功能。vendor 中保留了 MIFARE 风格的 16 字节块写底层函数,但 NTAG213 页写入和 NDEF 写入需要后续单独补。

业务层怎么使用

业务层只包含:

#include "nfc_service.h"

然后实现两个核心回调:

static int app_can_poll(void *ctx)
{
    // 返回 1 表示当前允许读卡,返回 0 表示暂时不读。
    return 1;
}

static void app_on_uid(const nfc_uid_t *uid, void *ctx)
{
    // uid->value 是十六进制字符串,例如 "04A1B2C3D4E5F6"。
    // 业务层在这里决定绑定、触发 MQTT、播放提示音等。
}

启动 NFC

nfc_service_config_t config;
nfc_service_callbacks_t callbacks = {
    .can_poll = app_can_poll,
    .on_uid = app_on_uid,
    .on_error = 0,
    .ctx = 0,
};

nfc_service_default_config(&config);
nfc_service_init(&config, &callbacks);
nfc_service_start();

can_poll 可以为空;为空时模块默认一直允许读卡。on_uid 必须提供。

当前 Banban 项目接入方式

参考:

examples/banban_adapter.c

这个示例把原项目中的业务判断放回业务层:

  • FOTA 中不读卡。
  • 休眠中不读卡。
  • MQTT 未连接不读卡。
  • 录音/TTS/播放队列忙时不读卡。
  • 测试模式允许读卡。
  • 读到 UID 后,根据 g_nfc_bind_status 决定调用绑定还是触发上报。

在当前项目中正式切换时,应用层可以把原来的:

DP1312EA_Init();

替换为:

banban_nfc_start();

并把 examples/banban_adapter.c 加入业务工程源码。

Quectel SDK 工程怎么接入

如果工程的 Makefile 支持 include 片段,可以引入:

include ../portable_modules/nfc/module.mk

或者手动加入这些源码:

SRC_FILES += \
  ../portable_modules/nfc/src/nfc_service.c \
  ../portable_modules/nfc/src/nfc_dp1312ea.c \
  ../portable_modules/nfc/src/nfc_ntag213.c \
  ../portable_modules/nfc/platform/quectel/nfc_platform_ql.c \
  ../portable_modules/nfc/vendor/dp1312ea/LPCD.c \
  ../portable_modules/nfc/vendor/dp1312ea/TypeA.c

INC_DIRS += \
  -I../portable_modules/nfc/include \
  -I../portable_modules/nfc/src \
  -I../portable_modules/nfc/vendor/dp1312ea

如果要使用 Banban 示例,还需要加入:

SRC_FILES += ../portable_modules/nfc/examples/banban_adapter.c

默认硬件配置

  • I2C bus: 1
  • DP1312EA I2C slave address: 0x50 >> 1
  • Reset pin: 86
  • IRQ pin: 87

如硬件不同,在初始化前修改 nfc_service_config_t

nfc_service_default_config(&config);
config.i2c_bus = 1;
config.reset_pin = 86;
config.irq_pin = 87;
nfc_service_init(&config, &callbacks);

移植到其他平台

移植新平台时,不需要改 src/vendor/。只需要新增一个平台实现,例如:

platform/my_sdk/nfc_platform_my_sdk.c

实现 include/nfc_platform.h 中的函数:

  • nfc_platform_i2c_init
  • nfc_platform_i2c_read
  • nfc_platform_i2c_write
  • nfc_platform_gpio_init
  • nfc_platform_gpio_set_level
  • nfc_platform_gpio_get_level
  • nfc_platform_irq_register
  • nfc_platform_irq_enable_wakeup
  • nfc_platform_irq_disable_wakeup
  • nfc_platform_sem_create
  • nfc_platform_sem_wait
  • nfc_platform_sem_release
  • nfc_platform_task_create
  • nfc_platform_sleep_ms
  • nfc_platform_log

分层约束

维护时请保持这些边界:

  • src/vendor/ 不能 include ql_*.h
  • src/vendor/ 不能 include app_inc.h
  • src/vendor/ 不能调用 MQTT、绑定、播放、录音、FOTA 等业务函数。
  • 业务判断必须放在 can_poll 回调。
  • UID 后续动作必须放在 on_uid 回调。