@@ -2110,7 +2110,7 @@ static data_frame_tx_t *cmd_processor_hf14a_4_reader_apdu(uint16_t cmd, uint16_t
21102110
21112111 /* ISO14443-4 chaining: PCB bit5 (0x20) set means more blocks follow */
21122112 while (resp_pcb & 0x20 ) {
2113- uint8_t rack = 0xA2 | (blk_num & 0x01 ); /* R(ACK) */
2113+ uint8_t rack = 0xA2 | (resp_pcb & 0x01 ); /* R(ACK) block_num matches received I-block */
21142114 uint8_t rack_frame [3 ];
21152115 rack_frame [0 ] = rack ;
21162116 crc_14a_append (rack_frame , 1 );
@@ -2135,6 +2135,81 @@ static data_frame_tx_t *cmd_processor_hf14a_4_reader_apdu(uint16_t cmd, uint16_t
21352135 return data_frame_make (cmd , STATUS_HF_TAG_OK , resp_chain_len , resp_chain );
21362136}
21372137
2138+ /* -----------------------------------------------------------------------
2139+ * tcl_apdu_: ISO 14443-4 APDU helper used by cmd_processor_hf14a_4_emv_scan.
2140+ * Sends one I-block, receives full response handling card-side chaining.
2141+ * ----------------------------------------------------------------------- */
2142+ static bool tcl_apdu_ (
2143+ const uint8_t * apdu , uint8_t apdu_sz ,
2144+ uint8_t * * rdata_ptr , uint16_t * rlen_ptr ,
2145+ uint8_t * abuf , uint8_t * rbuf , uint8_t * chain_buf ,
2146+ uint16_t * rbits_p , uint8_t * blk_p )
2147+ {
2148+ /* Build I-block: PCB + APDU + CRC */
2149+ abuf [0 ] = 0x02 | (* blk_p & 0x01 );
2150+ memcpy (& abuf [1 ], apdu , apdu_sz );
2151+ crc_14a_append (abuf , apdu_sz + 1 );
2152+ uint8_t frame_len = apdu_sz + 3 ; /* PCB + APDU + CRC */
2153+
2154+ /* Clear stale RxIRq before transmit.
2155+ * bytes_transfer only clears ComIrqReg bit7 (Set1).
2156+ * RxIRq (bit4) stays set from the previous receive and causes the
2157+ * wait-loop to exit instantly, returning garbage from FIFO. */
2158+ write_register_single (ComIrqReg , 0x7F );
2159+ pcd_14a_reader_timeout_set (600 );
2160+ uint16_t rbits = 0 ;
2161+ uint8_t st = pcd_14a_reader_bytes_transfer (
2162+ PCD_TRANSCEIVE , abuf , frame_len , rbuf , & rbits , 70u * 8u );
2163+ if (st != STATUS_HF_TAG_OK || rbits < 24u ) return false;
2164+
2165+ uint16_t rb = rbits / 8u ;
2166+ uint8_t crc [2 ];
2167+ crc_14a_calculate (rbuf , rb - 2u , crc );
2168+ if (rbuf [rb - 2 ] != crc [0 ] || rbuf [rb - 1 ] != crc [1 ]) return false;
2169+
2170+ * blk_p ^= 1 ;
2171+ uint8_t resp_pcb = rbuf [0 ];
2172+ uint16_t chain_len = 0 ;
2173+ uint8_t dlen = (uint8_t )(rb - 3u );
2174+ if (dlen > 0 && dlen < 512u ) {
2175+ memcpy (chain_buf , & rbuf [1 ], dlen );
2176+ chain_len = dlen ;
2177+ }
2178+
2179+ /* Handle card-side chaining ---------------------------------------- */
2180+ while (resp_pcb & 0x20u ) {
2181+ if ((resp_pcb & 0xC0u ) != 0x00u ) break ; /* not an I-block */
2182+
2183+ /* R(ACK) block_num must match the received I-block's block_num */
2184+ uint8_t rf [3 ];
2185+ rf [0 ] = 0xA2u | (resp_pcb & 0x01u );
2186+ crc_14a_append (rf , 1 );
2187+
2188+ /* Use bytes_transfer for chain R(ACK) — clear stale RxIRq first */
2189+ write_register_single (ComIrqReg , 0x7F );
2190+ pcd_14a_reader_timeout_set (600 );
2191+ uint16_t chain_rbits = 0 ;
2192+ uint8_t chain_st = pcd_14a_reader_bytes_transfer (
2193+ PCD_TRANSCEIVE , rf , 3 , rbuf , & chain_rbits , 70u * 8u );
2194+ if (chain_st != STATUS_HF_TAG_OK || chain_rbits < 24u ) break ;
2195+ rb = chain_rbits / 8u ; /* bytes_transfer returns BIT count */
2196+
2197+ crc_14a_calculate (rbuf , rb - 2u , crc );
2198+ if (rbuf [rb - 2 ] != crc [0 ] || rbuf [rb - 1 ] != crc [1 ]) break ;
2199+
2200+ resp_pcb = rbuf [0 ];
2201+ dlen = (uint8_t )(rb - 3u );
2202+ if (dlen > 0u && chain_len + dlen < 512u ) {
2203+ memcpy (& chain_buf [chain_len ], & rbuf [1 ], dlen );
2204+ chain_len += dlen ;
2205+ }
2206+ }
2207+
2208+ * rdata_ptr = chain_buf ;
2209+ * rlen_ptr = chain_len ;
2210+ return chain_len > 0u ;
2211+ }
2212+
21382213/**
21392214 * HF14A-4 EMV scan — complete EMV card read in a single firmware call.
21402215 *
@@ -2157,16 +2232,15 @@ static data_frame_tx_t *cmd_processor_hf14a_4_emv_scan(uint16_t cmd, uint16_t st
21572232
21582233 /* ---- helpers -------------------------------------------------- */
21592234 static uint8_t abuf [64 ]; /* TX frame: PCB + APDU + CRC */
2160- static uint8_t rbuf [64 ]; /* single-frame receive buffer (RC522 FIFO = 64 bytes) */
2235+ static uint8_t rbuf [70 ]; /* single-frame receive buffer: FIFO(64) + PCB(1) + CRC(2) + slack */
21612236 static uint8_t chain_buf [512 ]; /* reassembled chained response */
21622237 uint16_t rbits ;
21632238 uint8_t blk = 0 ; /* alternating block number */
21642239
2165- /* Send one I-block APDU, handling ISO14443-4 response chaining.
2166- * The RC522 FIFO is 64 bytes. If the card chains its response
2167- * (PCB bit4=1), we send R(ACK) blocks and reassemble here.
2168- * Returns pointer into chain_buf, sets *rlen_ptr to total length. */
2169- #define SEND_APDU (apdu_ptr , apdu_sz , rdata_ptr , rlen_ptr ) ({ bool _ok = false; uint8_t _pcb = 0x02 | (blk & 0x01); abuf[0] = _pcb; memcpy(&abuf[1], (apdu_ptr), (apdu_sz)); rbits = 0; uint8_t _st = pcd_14a_reader_raw_cmd( false, true, true, false, true, false, 600, ((apdu_sz) + 1) * 8, abuf, rbuf, &rbits, sizeof(rbuf) * 8); if (_st == STATUS_HF_TAG_OK && rbits > 0) { uint16_t _rb = rbits; /* raw_cmd checkCrc=false returns byte count */ /* Verify and strip CRC manually (checkCrc=false above) */ if (_rb >= 3 ) { uint8_t _crc [2 ]; crc_14a_calculate (rbuf , _rb - 2 , _crc ); if (rbuf [_rb - 2 ] == _crc [0 ] && rbuf [_rb - 1 ] == _crc [1 ]) { blk ^= 1 ; uint16_t _chain_len = 0 ; uint8_t _resp_pcb = rbuf [0 ]; /* Copy data portion (strip PCB and CRC) */ uint8_t _dlen = _rb - 3 ; if (_dlen > 0 && _chain_len + _dlen < sizeof (chain_buf )) { memcpy (& chain_buf [_chain_len ], & rbuf [1 ], _dlen ); _chain_len += _dlen ; } /* Handle chaining: PCB bit5=1 (b6 in ISO14443-4) means more data */ while (_resp_pcb & 0x20 ) { /* Send R(ACK) to request next block */ uint8_t _rack = 0xA2 | (blk & 0x01 ); abuf [0 ] = _rack ; crc_14a_append (abuf , 1 ); rbits = 0 ; _st = pcd_14a_reader_bytes_transfer (PCD_TRANSCEIVE , abuf , 3 , rbuf , & rbits , sizeof (rbuf ) * 8 ); if (_st != STATUS_HF_TAG_OK || rbits < 24 ) break ; _rb = rbits / 8 ; /* bytes_transfer returns bits */ crc_14a_calculate (rbuf , _rb - 2 , _crc ); if (rbuf [_rb - 2 ] != _crc [0 ] || rbuf [_rb - 1 ] != _crc [1 ]) break ; blk ^= 1 ; _resp_pcb = rbuf [0 ]; _dlen = _rb - 3 ; if (_dlen > 0 && _chain_len + _dlen < sizeof (chain_buf )) { memcpy (& chain_buf [_chain_len ], & rbuf [1 ], _dlen ); _chain_len += _dlen ; } } * (rdata_ptr ) = chain_buf ; * (rlen_ptr ) = (_chain_len < sizeof (chain_buf ) ? _chain_len : (uint16_t )(sizeof (chain_buf ) - 1 )); _ok = true; } } } _ok ; })
2240+ /* SEND_APDU: thin wrapper that calls the static tcl_apdu_ helper. */
2241+ #define SEND_APDU (ap , asz , rd , rl ) tcl_apdu_((ap),(asz),(rd),(rl),abuf,rbuf,chain_buf,&rbits,&blk)
2242+
2243+
21702244
21712245 /* Append a cmd+resp pair to out buffer */
21722246 #define APPEND_PAIR (cmd_ptr , cmd_sz , resp_ptr , resp_sz ) do { if (out_len + 1 + (cmd_sz) + 2 + (resp_sz) < NETDATA_MAX_DATA_LENGTH) { out[out_len++] = (uint8_t)(cmd_sz); memcpy(&out[out_len], (cmd_ptr), (cmd_sz)); out_len += (cmd_sz); out[out_len++] = (uint8_t)((resp_sz) & 0xFF); out[out_len++] = (uint8_t)((resp_sz) >> 8); memcpy(&out[out_len], (resp_ptr), (resp_sz)); out_len += (resp_sz); } } while(0)
@@ -2243,6 +2317,23 @@ static data_frame_tx_t *cmd_processor_hf14a_4_emv_scan(uint16_t cmd, uint16_t st
22432317 APPEND_PAIR (ppse_cmd , sizeof (ppse_cmd ), ppse_resp , ppse_rlen );
22442318 num_apdus ++ ;
22452319
2320+ /* ---- Re-establish T=CL after PPSE ----------------------------
2321+ * The PPSE exchange leaves the RC522 in an unknown internal state.
2322+ * Rather than trying to clear it piecemeal, do a full reset:
2323+ * turn the field off briefly, rescan the card, re-run RATS.
2324+ * This guarantees a clean RC522 state before SELECT AID.
2325+ * blk resets to 0 because a new T=CL session starts after RATS. */
2326+ pcd_14a_reader_antenna_off ();
2327+ bsp_delay_ms (10 );
2328+ {
2329+ picc_14a_tag_t tag2 ;
2330+ pcd_14a_reader_reset ();
2331+ pcd_14a_reader_antenna_on ();
2332+ bsp_delay_ms (8 );
2333+ if (pcd_14a_reader_scan_auto (& tag2 ) != STATUS_HF_TAG_OK ) goto done ;
2334+ }
2335+ blk = 0 ; /* new T=CL session: block number restarts at 0 */
2336+
22462337 /* ---- Extract first AID from PPSE ----------------------------- */
22472338 uint8_t aid [16 ]; uint8_t aid_len = 0 ;
22482339 for (uint8_t i = 0 ; i + 1 < ppse_rlen ; i ++ ) {
0 commit comments