ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
pn532.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file pn532.cpp
6 * @brief PN532 NFC frame codec - implementation.
7 *
8 * Normal information frame: 00 | 00 FF | LEN | LCS | TFI | PData | DCS | 00, where
9 * (LEN + LCS) & 0xFF == 0 and (TFI + sum(PData) + DCS) & 0xFF == 0 (PN532 User Manual).
10 */
11
13
14#if PC_ENABLE_PN532
15
16namespace
17{
18const uint8_t ACK[6] = {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00};
19}
20
21uint16_t pc_pn532_build_frame(uint8_t tfi, const uint8_t *data, uint8_t len, uint8_t *out, uint16_t cap)
22{
23 if (!out || len > PC_PN532_MAX_DATA || (data == nullptr && len > 0))
24 {
25 return 0;
26 }
27 uint16_t total = (uint16_t)(8 + len); // preamble+start(3) + LEN+LCS(2) + TFI + data + DCS + postamble
28 if (total > cap)
29 {
30 return 0;
31 }
32 uint8_t frame_len = (uint8_t)(1 + len); // TFI + PData
33 out[0] = 0x00;
34 out[1] = 0x00;
35 out[2] = 0xFF;
36 out[3] = frame_len;
37 out[4] = (uint8_t)(0x100 - frame_len); // LCS: LEN + LCS == 0
38 out[5] = tfi;
39 uint8_t sum = tfi;
40 for (uint8_t i = 0; i < len; i++)
41 {
42 out[6 + i] = data[i];
43 sum = (uint8_t)(sum + data[i]);
44 }
45 out[6 + len] = (uint8_t)(0x100 - sum); // DCS: TFI + sum(PData) + DCS == 0
46 out[7 + len] = 0x00; // postamble
47 return total;
48}
49
50int pc_pn532_parse_frame(const uint8_t *raw, uint16_t len, uint8_t *tfi, const uint8_t **pdata, uint8_t *pdata_len)
51{
52 if (!raw || len < 1)
53 {
54 return 0;
55 }
56 if (raw[0] != 0x00)
57 {
58 return -1; // preamble
59 }
60 if (len < 5)
61 {
62 return 0; // need 00 00 FF LEN LCS
63 }
64 if (raw[1] != 0x00 || raw[2] != 0xFF)
65 {
66 return -1; // start code
67 }
68 uint8_t frame_len = raw[3];
69 if ((uint8_t)(frame_len + raw[4]) != 0)
70 {
71 return -1; // length checksum
72 }
73 if (frame_len == 0 || frame_len > PC_PN532_MAX_DATA + 1)
74 {
75 return -1; // no TFI, or implausible length
76 }
77 uint16_t total = (uint16_t)(7 + frame_len);
78 if (len < total)
79 {
80 return 0; // wait for TFI + PData + DCS + postamble
81 }
82 uint8_t sum = 0;
83 for (uint8_t i = 0; i < frame_len; i++)
84 {
85 sum = (uint8_t)(sum + raw[5 + i]); // TFI + PData
86 }
87 if ((uint8_t)(sum + raw[5 + frame_len]) != 0)
88 {
89 return -1; // data checksum
90 }
91 if (tfi)
92 {
93 *tfi = raw[5];
94 }
95 if (pdata)
96 {
97 *pdata = &raw[6];
98 }
99 if (pdata_len)
100 {
101 *pdata_len = (uint8_t)(frame_len - 1);
102 }
103 return (int)total;
104}
105
106bool pc_pn532_is_ack(const uint8_t *raw, uint16_t len)
107{
108 if (!raw || len < 6)
109 {
110 return false;
111 }
112 for (uint8_t i = 0; i < 6; i++)
113 {
114 if (raw[i] != ACK[i])
115 {
116 return false;
117 }
118 }
119 return true;
120}
121
122uint16_t pc_pn532_build_ack(uint8_t *out, uint16_t cap)
123{
124 if (!out || cap < 6)
125 {
126 return 0;
127 }
128 for (uint8_t i = 0; i < 6; i++)
129 {
130 out[i] = ACK[i];
131 }
132 return 6;
133}
134
135#endif // PC_ENABLE_PN532
PN532 NFC frame codec (PC_ENABLE_PN532) - NXP PN532 NFC/RFID controller.
#define PC_PN532_MAX_DATA
Reject a PN532 normal frame whose declared length exceeds this (framing sanity).