@@ -43,6 +43,20 @@ constexpr uint8_t required_slots(const Require slots)
4343{
4444 return 1U << m5::stl::to_underlying (slots);
4545}
46+
47+ // ISO/IEC 14443-4 FSDI table (Frame Size for Device Index, bit[7:4] of ATTRIB PARAM2)
48+ constexpr uint8_t fsdi_for_size (const uint16_t bytes)
49+ {
50+ return (bytes >= 256 ) ? 8
51+ : (bytes >= 128 ) ? 7
52+ : (bytes >= 96 ) ? 6
53+ : (bytes >= 64 ) ? 5
54+ : (bytes >= 48 ) ? 4
55+ : (bytes >= 40 ) ? 3
56+ : (bytes >= 32 ) ? 2
57+ : (bytes >= 24 ) ? 1
58+ : 0 ;
59+ }
4660} // namespace
4761
4862namespace m5 {
@@ -69,26 +83,27 @@ bool NFCLayerB::receive(uint8_t* rx, uint16_t& rx_len, const uint32_t timeout_ms
6983 return _impl->receive (rx, rx_len, timeout_ms);
7084}
7185
72- bool NFCLayerB::detect (m5::nfc::b::PICC & picc, const uint8_t afi, const uint32_t timeout_ms)
86+ bool NFCLayerB::detect (m5::nfc::b::PICC & picc, const uint8_t afi, const uint32_t timeout_ms,
87+ const uint32_t req_timeout_ms)
7388{
7489 std::vector<PICC > piccs{};
75- if (detect (piccs, afi, 1 , timeout_ms)) {
90+ if (detect (piccs, afi, 1 , timeout_ms, req_timeout_ms )) {
7691 picc = piccs.front ();
7792 return true ;
7893 }
7994 return false ;
8095}
8196
8297bool NFCLayerB::detect (std::vector<m5::nfc::b::PICC >& piccs, const uint8_t afi, const uint8_t max_piccs,
83- const uint32_t timeout_ms)
98+ const uint32_t timeout_ms, const uint32_t req_timeout_ms )
8499{
85100 piccs.clear ();
86101
87102 auto timeout_at = m5::utility::millis () + timeout_ms;
88103 do {
89104 uint8_t rx[ATQB_LENGTH ]{};
90105 uint16_t rx_len = sizeof (rx);
91- if (!request (rx, rx_len, afi, Require::Slot1)) {
106+ if (!request (rx, rx_len, afi, Require::Slot1, req_timeout_ms )) {
92107 continue ;
93108 }
94109
@@ -110,44 +125,58 @@ bool NFCLayerB::detect(std::vector<m5::nfc::b::PICC>& piccs, const uint8_t afi,
110125 return !piccs.empty ();
111126}
112127
113- bool NFCLayerB::select (m5::nfc::b::PICC & picc)
128+ bool NFCLayerB::select (m5::nfc::b::PICC & picc, const uint32_t timeout_ms )
114129{
115130 // Wakeup for READY
116131 uint16_t len = ATQB_LENGTH ;
117132 if (!wakeup (picc.atqb , len)) {
118133 return false ;
119134 }
120135
136+ M5_LIB_LOGI (" ATQB protocol: %02X %02X %02X (FSCI=%u, ISO14443-4=%d, FWI=%u)" , picc.protocol [0 ], picc.protocol [1 ],
137+ picc.protocol [2 ], (picc.protocol [1 ] >> 4 ) & 0x0F , (picc.protocol [1 ] & 0x01 ),
138+ (picc.protocol [2 ] >> 4 ) & 0x0F );
139+
140+ // ATTRIB PARAM2 (per ISO/IEC 14443-3 §7.10.2 with b1 = LSB):
141+ // bit[3:0] = FSDI (PCD's max receive frame size index)
142+ // bit[5:4] = PCD->PICC bit rate divisor
143+ // bit[7:6] = PICC->PCD bit rate divisor
144+ // Take min(PCD FIFO, PICC FSCI) so the PICC chains I-blocks within what we can receive.
145+ const uint16_t pcd_rx_cap = maximum_fifo_depth () - 2 /* CRC*/ ;
146+ const uint8_t pcd_fsdi = fsdi_for_size (pcd_rx_cap);
147+ const uint8_t picc_fsci = picc.maximumFrameLengthBits ();
148+ const uint8_t fsdi = std::min<uint8_t >(pcd_fsdi, picc_fsci);
149+
121150 // ATTRIB
122151 uint8_t cmd[1 + 4 + 1 + 1 + 1 + 1 ] = {m5::stl::to_underlying (Command::ATTRIB )}; // without option
123152 memcpy (cmd + 1 , picc.pupi , 4 );
124- cmd[5 ] = 0x00 ; // PARAM1
125- cmd[6 ] = picc. maximumFrameLengthBits () ; // PARAM2 | com speed
126- cmd[7 ] = picc.protocol [1 ] & 0x0F ; // PARAM 3protocol type
127- cmd[8 ] = 0x00 ; // PARAM 4
153+ cmd[5 ] = 0x00 ; // PARAM1
154+ cmd[6 ] = ( uint8_t )(fsdi & 0x0F ) ; // PARAM2: FSDI(PCD cap) bit[3:0] | rates=0 (106k both)
155+ cmd[7 ] = picc.protocol [1 ] & 0x0F ; // PARAM3 protocol type
156+ cmd[8 ] = 0x00 ; // PARAM 4
128157
129158 std::vector<uint8_t > frame;
130159 frame.assign (cmd, cmd + sizeof (cmd));
131160
132161 uint8_t rx[128 ]{};
133162 uint16_t rx_len = sizeof (rx);
134- if (!transceive (rx, rx_len, frame.data (), frame.size (), TIMEOUT_ATTRIB ) || !rx_len) {
135- M5_LIB_LOGE (" Failed to select" );
163+ if (!transceive (rx, rx_len, frame.data (), frame.size (), timeout_ms ) || !rx_len) {
164+ M5_LIB_LOGE (" Failed to select: rx_len=%u " , rx_len );
136165 return false ;
137166 }
138167
139168 _activePICC = picc;
140169 return true ;
141170}
142171
143- bool NFCLayerB::hlt (const uint8_t pupi[4 ])
172+ bool NFCLayerB::hlt (const uint8_t pupi[4 ], const uint32_t timeout_ms )
144173{
145174 if (pupi) {
146175 uint8_t cmd[1 + 4 ] = {m5::stl::to_underlying (Command::HLTB )};
147176 memcpy (cmd + 1 , pupi, 4 );
148- uint8_t rx[1 ]{};
177+ uint8_t rx[1 + 2 ]{}; // 1 byte payload + 2 byte CRC_B
149178 uint16_t rx_len = sizeof (rx);
150- if (!transceive (rx, rx_len, cmd, sizeof (cmd), TIMEOUT_HLTB ) || rx_len < 1 ) {
179+ if (!transceive (rx, rx_len, cmd, sizeof (cmd), timeout_ms ) || rx_len < 1 ) {
151180 M5_LIB_LOGE (" Failed to hlt %02X%02X%02X%02X" , cmd[1 ], cmd[2 ], cmd[3 ], cmd[4 ]);
152181 return false ;
153182 }
@@ -156,17 +185,18 @@ bool NFCLayerB::hlt(const uint8_t pupi[4])
156185 return false ;
157186}
158187
159- bool NFCLayerB::deselect (const uint8_t pupi[4 ], const uint8_t cid)
188+ bool NFCLayerB::deselect (const uint8_t pupi[4 ], const uint8_t cid, const uint32_t timeout_ms )
160189{
161190 uint8_t cmd[2 ] = {m5::stl::to_underlying (cid != 0xFF ? Command::DESELECT_WITH_CID : Command::DESELECT )};
162191 uint16_t cmd_len = 1 + (cid != 0xFF );
163192 if (cid != 0xFF ) {
164193 cmd[1 ] = cid;
165194 }
166- uint8_t rx[2 ]{};
167- uint16_t rx_len = cmd_len;
195+ uint8_t rx[2 + 2 ]{}; // payload (1 or 2) + 2 byte CRC_B
196+ uint16_t rx_len =
197+ cmd_len + 2 ; // Match actual response size to keep wait_for_FIFO fallback equivalent to the old behavior
168198
169- if (!transceive (rx, rx_len, cmd, cmd_len, TIMEOUT_DESELECT ) || rx_len < cmd_len) {
199+ if (!transceive (rx, rx_len, cmd, cmd_len, timeout_ms ) || rx_len < cmd_len) {
170200 M5_LIB_LOGE (" Failed to deselecte %02X:%02X" , cmd[0 ], cmd[1 ]);
171201 return false ;
172202 }
@@ -188,7 +218,7 @@ bool NFCLayerB::deactivate()
188218
189219//
190220bool NFCLayerB::request_wakeup (uint8_t * atqb, uint16_t & atqb_len, const uint8_t afi, const Require slots,
191- const bool wakeup)
221+ const bool wakeup, const uint32_t timeout_ms )
192222{
193223 if (!atqb || atqb_len < ATQB_LENGTH ) {
194224 return false ;
@@ -204,7 +234,7 @@ bool NFCLayerB::request_wakeup(uint8_t* atqb, uint16_t& atqb_len, const uint8_t
204234 atqb_len = 0 ;
205235
206236 // Ignore non-responsive slots and proceed to the next one.
207- if (transceive (rx, rx_len, cmd, sizeof (cmd), TIMEOUT_REQ_WUP_B ) && rx_len == sizeof (rx) && rx[0 ] == 0x50 ) {
237+ if (transceive (rx, rx_len, cmd, sizeof (cmd), timeout_ms ) && rx_len == sizeof (rx) && rx[0 ] == 0x50 ) {
208238 // Occur collision if CRC error
209239 const uint16_t crc = crc16.range (rx, ATQB_LENGTH + 1 );
210240 if (crc == ((uint16_t )rx[13 ] << 8 | rx[12 ])) {
@@ -219,7 +249,7 @@ bool NFCLayerB::request_wakeup(uint8_t* atqb, uint16_t& atqb_len, const uint8_t
219249 rx_len = sizeof (rx);
220250 slot_marker[0 ] = ((uint8_t )i << 4 ) | 0x05 ;
221251 // Ignore non-responsive slots and proceed to the next one.
222- if (!transceive (rx, rx_len, slot_marker, sizeof (slot_marker), TIMEOUT_REQ_WUP_B ) || rx[0 ] != 0x50 ||
252+ if (!transceive (rx, rx_len, slot_marker, sizeof (slot_marker), timeout_ms ) || rx[0 ] != 0x50 ||
223253 rx_len < sizeof (rx)) {
224254 continue ;
225255 }
0 commit comments