M5Unit-NFC 0.1.0 git rev:93745b5
Loading...
Searching...
No Matches
isoDEP.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
10#ifndef M5_UNIT_UNIFIED_NFC_NFC_ISODEP_ISODEP_HPP
11#define M5_UNIT_UNIFIED_NFC_NFC_ISODEP_ISODEP_HPP
12#include <cstdint>
13#include <vector>
14
15namespace m5 {
16namespace nfc {
17class NFCLayerInterface;
22namespace isodep {
23
30uint32_t fwi_to_ms(const uint8_t fwi, const float fc);
31
32constexpr uint16_t MAX_FRAME_SIZE{256};
33
34namespace detail {
36
37inline bool is_i_block(uint8_t pcb)
38{
39 return (pcb & 0xC0) == 0x00;
40}
41
42inline bool is_r_block(uint8_t pcb)
43{
44 return (pcb & 0xC0) == 0x80;
45}
46
47inline bool is_s_block(uint8_t pcb)
48{
49 return (pcb & 0xC0) == 0xC0;
50}
51
52inline bool i_has_more(uint8_t pcb)
53{
54 return (pcb & 0x10) != 0;
55}
56
57inline uint8_t i_bn(uint8_t pcb)
58{
59 return (pcb >> 0) & 0x01;
60}
61
62inline bool is_s_wtx(uint8_t pcb)
63{
64 return (pcb & 0xC0) == 0xC0 && (pcb & 0x30) == 0x30; // S-Block & WTX
65}
66
67inline bool is_valid_rblock(uint8_t pcb)
68{
69 // R-Block MUST bits: b6=1, b3=0, b2=1 (mask 0x26, val 0x22), type=0x80
70 return ((pcb & 0xC0) == 0x80) && ((pcb & 0x26) == 0x22);
71}
72
73inline bool r_is_nak(uint8_t pcb)
74{
75 return (pcb & 0x10) != 0; // bit4 distinguishes ACK/NAK (0x10)
76}
77
78inline bool r_is_ack(uint8_t pcb)
79{
80 return !r_is_nak(pcb);
81}
82
83inline uint8_t get_wtxm(uint8_t inf)
84{
85 return inf & 0x3F;
86}
87
88inline bool is_valid_wtxm(uint8_t wtxm)
89{
90 return (wtxm >= 1) && (wtxm <= 59);
91}
92
93inline uint32_t mul_clamp_u32(uint32_t a, uint32_t b, uint32_t maxv)
94{
95 if (!a || !b) {
96 return 0;
97 }
98 if (a > maxv / b) {
99 return maxv;
100 }
101 uint32_t v = a * b;
102 return (v > maxv) ? maxv : v;
103}
104
105// I-Block PCB
106inline uint8_t make_i_pcb(uint8_t bn, bool more, bool has_cid, bool has_nad)
107{
108 uint8_t pcb = 0x02; // I-Block base (0x00/0x02?)
109 pcb &= ~0x01;
110 pcb |= (bn & 0x01);
111 pcb |= more ? 0x10 : 0x00;
112 pcb |= has_cid ? 0x08 : 0x00;
113 pcb |= has_nad ? 0x04 : 0x00;
114 return pcb;
115}
116
117// R-Block ACK
118inline uint8_t make_r_ack(uint8_t bn, bool has_cid)
119{
120 uint8_t pcb = 0xA2; // 0xA0 or 0xA2?
121 pcb &= ~0x01;
122 pcb |= (bn & 0x01);
123 pcb |= has_cid ? 0x08 : 0x00;
124 return pcb;
125}
126
127// S-Block WTX-ACK
128inline uint8_t make_s_wtx_ack(bool has_cid)
129{
130 uint8_t pcb = 0xF2; // S(WTX)
131 pcb |= has_cid ? 0x08 : 0x00;
132 return pcb;
133}
134
136} // namespace detail
137
143inline uint16_t fsci_to_fsc(const uint8_t fsci)
144{
145 static constexpr uint16_t table[] = {16, 24, 32, 40, 48, 64, 96, 128, 256};
146 return (fsci < (sizeof(table) / sizeof(table[0]))) ? table[fsci] : 0;
147}
148
153struct config_t {
154 uint16_t fsc{};
155 uint16_t pcd_max_frame_tx{};
156 uint16_t pcd_max_frame_rx{};
157 uint32_t fwt_ms{100};
158 uint32_t wtx_max_ms{5000};
159
160 // options
161 bool use_cid{};
162 uint8_t cid{};
163 bool use_nad{};
164 uint8_t nad{};
165
166 uint8_t max_retries{2};
167 bool rx_crc{true}; // Remove CRC if true in INF
168
173 inline uint16_t max_frame_cap_tx() const
174 {
175 const auto max_frame = std::min<uint16_t>(pcd_max_frame_tx, fsc);
176 return (max_frame > (overhead() + 2)) ? (max_frame - overhead() - 2) : 0;
177 }
182 inline uint16_t max_frame_size_rx() const
183 {
184 return std::min<uint16_t>(pcd_max_frame_rx, fsc);
185 }
190 inline uint16_t fsc_inf_cap() const
191 {
192 return (fsc > overhead()) ? static_cast<uint16_t>(fsc - overhead()) : 0;
193 }
198 inline uint16_t overhead() const
199 {
200 return 1 + (use_cid ? 1 : 0) + (use_nad ? 1 : 0);
201 }
202};
203
209struct policy_t {
210 uint32_t fwt_ms{};
211 uint32_t wtx_max_ms{};
212 uint8_t max_retries{};
213
214 policy_t() = default;
221 policy_t(const uint32_t fwt, const uint32_t wtx, const uint8_t retries)
222 : fwt_ms(fwt), wtx_max_ms(wtx), max_retries(retries)
223 {
224 }
225};
226
231struct RxInfo {
232 bool more{}; // Continue chaining?
233 bool wtx_seen{}; // WTX?
234};
235
240class IsoDEP {
241public:
246 explicit IsoDEP(NFCLayerInterface& layer) : _layer{layer}
247 {
248 }
254 IsoDEP(NFCLayerInterface& layer, const config_t& c) : _layer{layer}, _cfg{c}
255 {
256 }
257
262 inline config_t config() const
263 {
264 return _cfg;
265 }
271 inline void config(const config_t& cfg)
272 {
273 _cfg = cfg;
274 _block_num = 0;
275 }
276
288 bool transceiveINF(uint8_t* rx_inf, uint16_t& rx_inf_len, const uint8_t* tx_inf, const uint16_t tx_inf_len,
289 RxInfo* info = nullptr, const policy_t* override_policy = nullptr);
300 bool transceiveAPDU(uint8_t* rx, uint16_t& rx_len, const uint8_t* cmd, const uint16_t cmd_len,
301 const policy_t* override_policy = nullptr);
311 bool transceive(uint8_t* rx, uint16_t& rx_len, const uint8_t* tx, const uint16_t tx_len, const uint32_t timeout_ms);
312
313private:
314 NFCLayerInterface& _layer;
315 config_t _cfg{};
316 uint8_t _block_num{}; // I-Block BN (0/1)
317};
318
319} // namespace isodep
320} // namespace nfc
321} // namespace m5
322#endif
Common interface for NFC layer.
Definition nfc_layer.hpp:26
ISO Data Exchange Protocol.
Definition isoDEP.hpp:240
void config(const config_t &cfg)
Set configuration.
Definition isoDEP.hpp:271
IsoDEP(NFCLayerInterface &layer, const config_t &c)
Constructor with NFC layer and configuration.
Definition isoDEP.hpp:254
bool transceiveAPDU(uint8_t *rx, uint16_t &rx_len, const uint8_t *cmd, const uint16_t cmd_len, const policy_t *override_policy=nullptr)
Transceive APDU.
Definition isoDEP.cpp:442
IsoDEP(NFCLayerInterface &layer)
Constructor with NFC layer.
Definition isoDEP.hpp:246
bool transceive(uint8_t *rx, uint16_t &rx_len, const uint8_t *tx, const uint16_t tx_len, const uint32_t timeout_ms)
Transceive normal.
Definition isoDEP.cpp:535
config_t config() const
Get configuration.
Definition isoDEP.hpp:262
bool transceiveINF(uint8_t *rx_inf, uint16_t &rx_inf_len, const uint8_t *tx_inf, const uint16_t tx_inf_len, RxInfo *info=nullptr, const policy_t *override_policy=nullptr)
Transceive INF.
Definition isoDEP.cpp:111
uint32_t fwi_to_ms(const uint8_t fwi, const float fc)
Calculate waiting time(ms) by fwi and fc.
Definition isoDEP.cpp:92
uint16_t fsci_to_fsc(const uint8_t fsci)
Convert FSCI to FSC (ISO/IEC 14443-4)
Definition isoDEP.hpp:143
NFC-A definitions.
NFC-B definitions.
For ISO-DEP.
Top level namespace of M5Stack.
NFC related definitions.
NFC-V definitions.
RX information.
Definition isoDEP.hpp:231
ISO-DEP configuration.
Definition isoDEP.hpp:153
uint16_t max_frame_size_rx() const
Maximum receive frame size.
Definition isoDEP.hpp:182
uint16_t overhead() const
ISO-DEP frame overhead.
Definition isoDEP.hpp:198
uint16_t fsc_inf_cap() const
Maximum INF capacity allowed by FSC.
Definition isoDEP.hpp:190
uint16_t max_frame_cap_tx() const
Maximum INF payload capacity for transmission.
Definition isoDEP.hpp:173
Per-exchange timeout/retry override for transceiveINF/transceiveAPDU.
Definition isoDEP.hpp:209
uint32_t fwt_ms
Frame waiting time (ms). 0 is clamped to 1 internally.
Definition isoDEP.hpp:210
policy_t(const uint32_t fwt, const uint32_t wtx, const uint8_t retries)
Construct with explicit values (enables positional brace-init under C++11)
Definition isoDEP.hpp:221
uint32_t wtx_max_ms
Upper bound for WTX extension (ms)
Definition isoDEP.hpp:211
uint8_t max_retries
Number of resends (0 = no resend)
Definition isoDEP.hpp:212