feat(nfc): emulate Type 2 NDEF tag
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
#if 1
|
#if 1
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include "ql_rtos.h"
|
#include "ql_rtos.h"
|
||||||
#include "ql_application.h"
|
#include "ql_application.h"
|
||||||
#include "ql_audio.h"
|
#include "ql_audio.h"
|
||||||
@@ -10,6 +11,7 @@
|
|||||||
#include "DP1312EA.h"
|
#include "DP1312EA.h"
|
||||||
#include "TypeA.h"
|
#include "TypeA.h"
|
||||||
#include "LPCD.h"
|
#include "LPCD.h"
|
||||||
|
#include "hal_api.h"
|
||||||
|
|
||||||
#define NFC_WORK_MODE_READER 0
|
#define NFC_WORK_MODE_READER 0
|
||||||
#define NFC_WORK_MODE_CARD_EMULATION 1
|
#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_TX_POLLS 20
|
||||||
#define NFC_CARD_RX_POLLS 200
|
#define NFC_CARD_RX_POLLS 200
|
||||||
#define NFC_CARD_SESSION_POLL_MS 1
|
#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_TX 0x40
|
||||||
#define NFC_IRQ_RX 0x20
|
#define NFC_IRQ_RX 0x20
|
||||||
#define NFC_IRQ_ERR 0x02
|
#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)
|
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",
|
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);
|
DP1312EA_WriteRawRC(BitFramingReg, 0x00);
|
||||||
nfc_card_emulation_log_status("ATS transmit failed");
|
nfc_card_emulation_log_status("frame transmit failed");
|
||||||
return 0;
|
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[] = {
|
static const u8 card_config[] = {
|
||||||
0x44, 0x00, /* SENS_RES / ATQA */
|
0x44, 0x00, /* SENS_RES / ATQA */
|
||||||
0xAA, 0xBB, 0xCC, /* NFCID1; first byte 08 is added by PN512 */
|
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,
|
0x01, 0xFE, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
|
||||||
0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
0xFF, 0xFF,
|
0xFF, 0xFF,
|
||||||
@@ -161,19 +238,16 @@ static void nfc_card_emulation_start(void)
|
|||||||
DP1312EA_WriteRawRC(DivIrqReg, 0x7F);
|
DP1312EA_WriteRawRC(DivIrqReg, 0x7F);
|
||||||
DP1312EA_SetBitMask(FIFOLevelReg, 0x80);
|
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");
|
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 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[NFC_CARD_FRAME_MAX];
|
||||||
|
u8 response[NFC_TYPE2_READ_SIZE];
|
||||||
u8 frame_len;
|
u8 frame_len;
|
||||||
u16 poll_count;
|
u16 poll_count;
|
||||||
u8 last_command = 0xFF;
|
u8 last_command = 0xFF;
|
||||||
@@ -191,22 +265,16 @@ static void nfc_card_emulation_task(void)
|
|||||||
|
|
||||||
if (command == DP1312EA_TRANSCEIVE) {
|
if (command == DP1312EA_TRANSCEIVE) {
|
||||||
frame_len = nfc_card_emulation_read_frame(frame, sizeof(frame));
|
frame_len = nfc_card_emulation_read_frame(frame, sizeof(frame));
|
||||||
nfc_card_emulation_log_frame("activation RX", frame, frame_len);
|
while (frame_len >= 2 && frame[0] == 0x30) {
|
||||||
|
nfc_card_emulation_log_frame("Type 2 READ RX", frame,
|
||||||
if (frame_len == 2 && frame[0] == 0xE0) {
|
frame_len);
|
||||||
if (!nfc_card_emulation_send_frame(ats, sizeof(ats))) {
|
nfc_type2_read_pages(frame[1], response);
|
||||||
nfc_card_emulation_log_status("session complete");
|
if (!nfc_card_emulation_send_frame(response,
|
||||||
nfc_card_emulation_start();
|
sizeof(response))) {
|
||||||
last_command = DP1312EA_AUTOCOLL;
|
break;
|
||||||
ql_rtos_task_sleep_ms(1);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
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);
|
DP1312EA_WriteRawRC(ComIrqReg, NFC_IRQ_TX);
|
||||||
for (poll_count = 0;
|
for (poll_count = 0;
|
||||||
poll_count < NFC_CARD_RX_POLLS;
|
poll_count < NFC_CARD_RX_POLLS;
|
||||||
@@ -214,7 +282,7 @@ static void nfc_card_emulation_task(void)
|
|||||||
u8 irq = DP1312EA_ReadRawRC(ComIrqReg);
|
u8 irq = DP1312EA_ReadRawRC(ComIrqReg);
|
||||||
|
|
||||||
if ((irq & NFC_IRQ_ERR) != 0) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,8 +290,6 @@ static void nfc_card_emulation_task(void)
|
|||||||
(DP1312EA_ReadRawRC(FIFOLevelReg) & 0x7F) != 0) {
|
(DP1312EA_ReadRawRC(FIFOLevelReg) & 0x7F) != 0) {
|
||||||
frame_len = nfc_card_emulation_read_frame(
|
frame_len = nfc_card_emulation_read_frame(
|
||||||
frame, sizeof(frame));
|
frame, sizeof(frame));
|
||||||
nfc_card_emulation_log_frame(
|
|
||||||
"first ISO-DEP RX", frame, frame_len);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,10 +297,18 @@ static void nfc_card_emulation_task(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (poll_count == NFC_CARD_RX_POLLS) {
|
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");
|
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)
|
void ql_nfc_task_thread(void *arvg)
|
||||||
{
|
{
|
||||||
#if (NFC_WORK_MODE == NFC_WORK_MODE_CARD_EMULATION)
|
#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();
|
nfc_card_emulation_task();
|
||||||
#else
|
#else
|
||||||
s8 read_status;
|
s8 read_status;
|
||||||
|
|||||||
Reference in New Issue
Block a user