2015-06-02 18:17:34 +08:00
//-----------------------------------------------------------------------------
2022-01-06 09:19:46 +08:00
// Copyright (C) Jonathan Westhues, Nov 2006
// Copyright (C) Gerhard de Koning Gans - May 2008
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
2015-06-02 18:17:34 +08:00
//
2022-01-06 09:19:46 +08:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
2015-06-02 18:17:34 +08:00
//-----------------------------------------------------------------------------
2015-06-18 15:52:53 +08:00
// Routines to support ISO 14443B. This includes both the reader software and
// the `fake tag' modes.
2015-06-02 18:17:34 +08:00
//-----------------------------------------------------------------------------
2016-03-21 02:33:07 +08:00
# include "iso14443b.h"
2015-06-02 18:17:34 +08:00
2019-08-08 22:57:33 +08:00
# include "proxmark3_arm.h"
2021-08-22 05:02:27 +08:00
# include "common.h" // access to global variable: g_dbglevel
2019-08-08 22:57:33 +08:00
# include "util.h"
# include "string.h"
# include "crc16.h"
# include "protocols.h"
# include "appmain.h"
# include "BigBuf.h"
# include "cmd.h"
# include "fpgaloader.h"
# include "commonutil.h"
# include "dbprint.h"
# include "ticks.h"
2021-04-24 04:25:58 +08:00
# include "iso14b.h" // defines for ETU conversions
2021-05-06 03:04:48 +08:00
/*
2021-04-24 04:25:58 +08:00
* Current timing issues with ISO14443 - b implementation
2021-05-06 03:04:48 +08:00
* Proxmark3
* Carrier Frequency 13.56 MHz
2023-08-24 16:20:01 +08:00
* 1 / 13 560 000 = 73.74 nano seconds ( 0.07374 µ s )
2021-04-24 04:25:58 +08:00
* SSP_CLK runs at 13.56 MHz / 4 = 3 , 39 MHz
2023-08-24 16:20:01 +08:00
* 1 / 3 390 000 = 294.98 nano seconds ( 0.2949 µ s )
2021-05-06 03:04:48 +08:00
*
2023-08-24 16:20:01 +08:00
* 1 ETU = 9.4395 µ s = 32 SSP_CLK = 128 FC
2023-09-08 02:13:18 +08:00
* 1 SSP_CLK = 4 FC
2023-08-24 16:20:01 +08:00
* 1 µ s 3 SSP_CLK about 14 FC
2021-04-24 04:25:58 +08:00
* PROBLEM 1.
* - - - - - - - - - -
* one way of calculating time , that relates both to PM3 ssp_clk 3.39 MHz , ISO freq of 13.56 Mhz and ETUs
* convert from µ S - > our SSP_CLK units which is used in the DEFINES . .
* convert from ms - > our SSP_CLK units . . .
* convert from ETU - > our SSP_CLK units . . .
* All ETU - > µ S - > ms should be diveded by for to match Proxmark3 FPGA SSP_CLK : )
*
*
* PROBLEM 2.
* - - - - - - - - - -
* all DEFINES is in SSP_CLK ticks
* all delays is in SSP_CLK ticks
*/
2019-08-08 22:57:33 +08:00
2021-04-24 04:25:58 +08:00
# ifndef RECEIVE_MASK
# define RECEIVE_MASK (DMA_BUFFER_SIZE - 1)
# endif
2020-07-04 03:33:17 +08:00
2020-08-14 20:58:27 +08:00
// SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag
2021-04-24 04:25:58 +08:00
// All values should be multiples of 2 (?)
2020-08-14 20:58:27 +08:00
# define DELAY_READER_TO_ARM 8
# define DELAY_ARM_TO_READER 0
2021-04-24 04:25:58 +08:00
// SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader.
// All values should be multiples of 16
2020-08-14 20:58:27 +08:00
# define DELAY_ARM_TO_TAG 16
# define DELAY_TAG_TO_ARM 32
2021-05-06 03:04:48 +08:00
// SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when sniffing.
2021-04-24 04:25:58 +08:00
// All values should be multiples of 16
2020-08-14 20:58:27 +08:00
# define DELAY_TAG_TO_ARM_SNIFF 32
# define DELAY_READER_TO_ARM_SNIFF 32
2021-04-24 04:25:58 +08:00
/* ISO14443-4
*
* Frame Waiting Time Integer ( FWI )
* can be between 0 and 14.
* FWI_default = 4
* FWI_max = 14
*
* Frame Waiting Time ( FWT ) formula
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* FWT = ( 256 x 16 / fc ) * 2 to the power for FWI
*
* sample :
* - - - - - - - 2 to the power of FWI ( 4 )
* FWT = ( 256 x 16 / fc ) * ( 2 * 2 * 2 * 2 ) = = 4.833 ms
* FTW ( default ) = = FWT ( 4 ) = = 4.822 ms
*
* FWI_max = = 2 ^ 14 = 16384
* FWT ( max ) = ( 256 x 16 / fc ) * 16384 = = 4949
2021-05-06 03:04:48 +08:00
*
2021-04-24 04:25:58 +08:00
* Which gives a maximum Frame Waiting time of FWT ( max ) = = 4949 ms
* FWT ( max ) in ETU 4949000 / 9.4395 µ S = 524286 ETU
*
* Simple calc to convert to ETU or µ S
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* uint32_t fwt_time_etu = ( 32 < < fwt ) ;
* uint32_t fwt_time_us = ( 302 < < fwt ) ;
*
*/
2023-08-24 16:20:01 +08:00
2021-04-24 04:25:58 +08:00
# ifndef MAX_14B_TIMEOUT
// FWT(max) = 4949 ms or 4.95 seconds.
// SSP_CLK = 4949000 * 3.39 = 16777120
# define MAX_14B_TIMEOUT (16777120U)
2020-08-17 03:13:10 +08:00
# endif
2021-04-24 04:25:58 +08:00
// Activation frame waiting time
// 512 ETU?
// 65536/fc == 4833 µS or 4.833ms
2021-05-06 03:04:48 +08:00
// SSP_CLK = 4833 µS * 3.39 = 16384
2021-04-24 04:25:58 +08:00
# ifndef FWT_TIMEOUT_14B
# define FWT_TIMEOUT_14B (16384)
2021-05-06 03:04:48 +08:00
# endif
2021-04-24 04:25:58 +08:00
2021-05-06 03:04:48 +08:00
// ETU 14 * 9.4395 µS = 132 µS == 0.132ms
2021-04-24 04:25:58 +08:00
// TR2, counting from start of PICC EOF 14 ETU.
2023-08-24 16:20:01 +08:00
# define DELAY_ISO14443B_PICC_TO_PCD_READER HF14_ETU_TO_SSP(14)
# define DELAY_ISO14443B_PCD_TO_PICC_READER HF14_ETU_TO_SSP(15)
2020-09-30 23:06:19 +08:00
2021-04-24 04:25:58 +08:00
/* Guard Time (per 14443-2) in ETU
*
* Transition time . TR0 - guard time
* TR0 - 8 ETU ' s minimum .
* TR0 - 32 ETU ' s maximum for ATQB only
* TR0 - FWT for all other commands
* 32 , 64 , 128 , 256 , 512 , . . . , 262144 , 524288 ETU
* TR0 = FWT ( 1 ) , FWT ( 2 ) , FWT ( 3 ) . . FWT ( 14 )
*
*
2021-05-06 03:04:48 +08:00
* TR0
2021-04-24 04:25:58 +08:00
*/
# ifndef ISO14B_TR0
2023-08-24 16:20:01 +08:00
# define ISO14B_TR0 HF14_ETU_TO_SSP(16)
2021-04-24 04:25:58 +08:00
# endif
2020-08-14 20:58:27 +08:00
2021-04-24 04:25:58 +08:00
# ifndef ISO14B_TR0_MAX
2023-08-24 16:20:01 +08:00
# define ISO14B_TR0_MAX HF14_ETU_TO_SSP(32)
2021-04-24 04:25:58 +08:00
// * TR0 - 32 ETU's maximum for ATQB only
// * TR0 - FWT for all other commands
2020-08-14 20:58:27 +08:00
2023-08-24 16:20:01 +08:00
// TR0 max is 159 µS or 32 samples from FPGA
// 16 ETU * 9.4395 µS == 151 µS
// 16 * 8 = 128 sub carrier cycles,
// 128 / 4 = 32 I/Q pairs.
2021-04-24 04:25:58 +08:00
// since 1 I/Q pair after 4 subcarrier cycles at 848kHz subcarrier
2016-08-07 23:49:33 +08:00
# endif
2015-06-02 18:17:34 +08:00
2021-04-24 04:25:58 +08:00
// 8 ETU = 75 µS == 256 SSP_CLK
# ifndef ISO14B_TR0_MIN
2023-08-24 16:20:01 +08:00
# define ISO14B_TR0_MIN HF14_ETU_TO_SSP(8)
2016-08-07 23:49:33 +08:00
# endif
2021-04-24 04:25:58 +08:00
// Synchronization time (per 14443-2) in ETU
2023-08-24 16:20:01 +08:00
// 16 ETU = 151 µS == 512 SSP_CLK
2021-04-24 04:25:58 +08:00
# ifndef ISO14B_TR1_MIN
2023-08-24 16:20:01 +08:00
# define ISO14B_TR1_MIN HF14_ETU_TO_SSP(16)
2021-04-24 04:25:58 +08:00
# endif
// Synchronization time (per 14443-2) in ETU
// 25 ETU == 236 µS == 800 SSP_CLK
# ifndef ISO14B_TR1_MAX
2023-08-24 16:20:01 +08:00
# define ISO14B_TR1 HF14_ETU_TO_SSP(25)
2016-08-07 23:49:33 +08:00
# endif
2021-04-24 04:25:58 +08:00
// Frame Delay Time PICC to PCD (per 14443-3 Amendment 1) in ETU
// 14 ETU == 132 µS == 448 SSP_CLK
# ifndef ISO14B_TR2
2023-08-24 16:20:01 +08:00
# define ISO14B_TR2 HF14_ETU_TO_SSP(14)
2016-08-07 23:49:33 +08:00
# endif
2016-04-28 02:42:01 +08:00
// 4sample
2020-07-14 00:14:34 +08:00
# define SEND4STUFFBIT(x) tosend_stuffbit(x);tosend_stuffbit(x);tosend_stuffbit(x);tosend_stuffbit(x);
2016-04-28 02:42:01 +08:00
2021-04-24 04:25:58 +08:00
static void iso14b_set_timeout ( uint32_t timeout_etu ) ;
2016-08-08 04:05:10 +08:00
static void iso14b_set_maxframesize ( uint16_t size ) ;
2021-04-24 04:25:58 +08:00
static void iso14b_set_fwt ( uint8_t fwt ) ;
2016-04-27 03:29:45 +08:00
2016-03-21 02:33:07 +08:00
// the block number for the ISO14443-4 PCB (used with APDUs)
2020-09-30 23:06:19 +08:00
static uint8_t iso14b_pcb_blocknum = 0 ;
2021-04-24 04:25:58 +08:00
static uint8_t iso14b_fwt = 9 ;
2020-08-17 03:13:10 +08:00
static uint32_t iso14b_timeout = FWT_TIMEOUT_14B ;
2020-07-04 03:33:17 +08:00
2021-04-24 04:25:58 +08:00
/*
* ISO 14443 - B communications
* - - - - - - - - - - - - - - - - - - - - - - - - - -
2020-07-04 03:33:17 +08:00
* Reader to card | ASK - Amplitude Shift Keying Modulation ( PCD to PICC for Type B ) ( NRZ - L encodig )
* Card to reader | BPSK - Binary Phase Shift Keying Modulation , ( PICC to PCD for Type B )
*
2021-04-24 04:25:58 +08:00
* It uses half duplex with a 106 kbit per second data rate in each direction .
* Data transmitted by the card is load modulated with a 847.5 kHz subcarrier .
*
2020-07-04 03:33:17 +08:00
* fc - carrier frequency 13.56 MHz
* TR0 - Guard Time per 14443 - 2
* TR1 - Synchronization Time per 14443 - 2
* TR2 - PICC to PCD Frame Delay Time ( per 14443 - 3 Amendment 1 )
*
2021-04-24 04:25:58 +08:00
* Elementary Time Unit ( ETU )
* - - - - - - - - - - - - - - - - - - - - - - - - - -
2021-10-10 07:35:38 +08:00
* ETU is used to denote 1 bit period i . e . how long one bit transfer takes .
2021-05-06 03:04:48 +08:00
*
2021-04-24 04:25:58 +08:00
* - 128 Carrier cycles / 13.56 MHz = 8 Subcarrier units / 848 kHz = 1 / 106 kHz = 9.4395 µ S
* - 16 Carrier cycles = 1 Subcarrier unit = 1.17 µ S
*
2021-04-22 00:36:21 +08:00
* Definition
2021-04-24 04:25:58 +08:00
* - - - - - - - - - -
2021-05-06 03:04:48 +08:00
* 1 ETU = 128 / ( D x fc )
2021-04-22 00:36:21 +08:00
* where
2021-10-10 07:35:38 +08:00
* D = divisor . Which initial is 1
2021-05-06 03:04:48 +08:00
* fc = carrier frequency
2021-04-22 00:36:21 +08:00
* gives
* 1 ETU = 128 / fc
* 1 ETU = 128 / 13 560 000 = 9.4395 µ S
* 1 ETU = 9.4395 µ S
2020-07-04 03:33:17 +08:00
*
2021-04-24 04:25:58 +08:00
* ( note : It seems we are using the subcarrier as base for our time calculations rather than the field clock )
2020-07-04 03:33:17 +08:00
*
2021-05-06 03:04:48 +08:00
* - 1 ETU = 1 / 106 KHz
2021-04-24 04:25:58 +08:00
* - 1 ETU = 8 subcarrier units ( 8 / 848 kHz )
* - 1 ETU = 1 bit period
2020-07-04 03:33:17 +08:00
*
*
2021-04-24 04:25:58 +08:00
* Card sends data at 848 kHz subcarrier
2021-04-22 00:36:21 +08:00
* subcar | duration | FC division | I / Q pairs
* - - - - - - - + - - - - - - - - + - - - - - - - - - - - - + - - - - - - - -
* 106 kHz | 9.44 µ S | FC / 128 | 16
* 212 kHz | 4.72 µ S | FC / 64 | 8
* 424 kHz | 2.36 µ S | FC / 32 | 4
* 848 kHz | 1.18 µ S | FC / 16 | 2
* - - - - - - - + - - - - - - - - + - - - - - - - - - - - - + - - - - - - - -
2020-07-04 03:33:17 +08:00
*
2021-04-24 04:25:58 +08:00
*
* One Character consists of 1 start , 1 stop , 8 databit with a total length of 10 bits .
* - 1 Character = 10 ETU = 1 startbit , 8 databits , 1 stopbit
* - startbit is a 0
* - stopbit is a 1
*
* Start of frame ( SOF ) is
* - [ 10 - 11 ] ETU of ZEROS , unmodulated time
* - [ 2 - 3 ] ETU of ONES ,
*
* End of frame ( EOF ) is
* - [ 10 - 11 ] ETU of ZEROS , unmodulated time
*
* Reader data transmission
* - - - - - - - - - - - - - - - - - - - - - - - -
2020-07-04 03:33:17 +08:00
* - no modulation ONES
* - SOF
2021-04-24 04:25:58 +08:00
* - Command , data and CRC_B ( 1 Character )
2020-07-04 03:33:17 +08:00
* - EOF
* - no modulation ONES
*
2021-04-24 04:25:58 +08:00
* Card data transmission
* - - - - - - - - - - - - - - - - - - - - - -
2020-07-04 03:33:17 +08:00
* - TR1
* - SOF
2021-04-24 04:25:58 +08:00
* - data ( 1 Character )
2020-07-04 03:33:17 +08:00
* - CRC_B
* - EOF
*
2021-04-24 04:25:58 +08:00
* Transfer times
* - - - - - - - - - - - - - -
* let calc how long it takes the reader to send a message
* SOF 10 ETU + 4 data bytes + 2 crc bytes + EOF 2 ETU
* 10 + ( 4 + 2 * 10 ) + 2 = 72 ETU
2021-05-06 03:04:48 +08:00
* 72 * 9.4395 = 680 µ S or 0.68 ms
*
2021-04-24 04:25:58 +08:00
*
* - > TO VERIFY THIS BELOW < -
* - - - - - - - - - - - - - - - - - - - - - - - - - -
* The mode FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK which we use to simulate tag
2021-05-06 03:04:48 +08:00
* works like this :
2021-10-10 07:35:38 +08:00
* Simulation per definition is " inverted " effect on the reader antenna .
2021-04-24 04:25:58 +08:00
* - A 1 - bit input to the FPGA becomes 8 pulses at 847.5 kHz ( 1.18 µ S / pulse ) = = 9.44 us
* - A 0 - bit input to the FPGA becomes an unmodulated time of 1.18 µ S or does it become 8 nonpulses for 9.44 us
*
2020-07-04 03:33:17 +08:00
*
2021-04-24 04:25:58 +08:00
* FPGA implementation
* - - - - - - - - - - - - - - - - - - -
* Piwi implemented a I / Q sampling mode for the FPGA , where . . .
*
* FPGA doesn ' t seem to work with ETU . It seems to work with pulse / duration instead .
*
2021-05-06 03:04:48 +08:00
* This means that we are using a bit rate of 106 kbit / s , or fc / 128.
2021-04-24 04:25:58 +08:00
* Oversample by 4 , which ought to make things practical for the ARM
* ( fc / 32 , 423.8 kbits / s , ~ 52 kbytes / s )
*
2021-05-06 03:04:48 +08:00
* We are sampling the signal at FC / 32 , we are reporting over SSP to PM3 each
*
* Current I / Q pair sampling
2021-04-24 04:25:58 +08:00
* - - - - - - - - - - - - - - - - - - - - - - - - -
2020-08-17 03:13:10 +08:00
* Let us report a correlation every 64 samples . I . e .
2021-04-24 04:25:58 +08:00
* 1 I / Q pair after 4 subcarrier cycles for the 848 kHz subcarrier ,
* 1 I / Q pair after 2 subcarrier cycles for the 424 kHz subcarrier ,
*/
2020-07-04 03:33:17 +08:00
2021-04-24 04:25:58 +08:00
/*
* Formula to calculate FWT ( in ETUs ) by timeout ( in ms ) :
*
* 1 tick is about 1.5 µ S
* 1000 ms / s
*
* FWT = 13560000 * 1000 / ( 8 * 16 ) * timeout
* FWT = 13560000 * 1000 / 128 * timeout
*
* sample : 3 sec = = 3000 ms
*
2021-05-06 03:04:48 +08:00
* 13560000 * 1000 / 128 * 3000 = = 13560000000 / 384000 = =
2021-04-24 04:25:58 +08:00
* 13560000 / 384 = 35312 FWT
*
* 35312 * 9.4395 = =
*
* @ param timeout is in frame wait time , fwt , measured in ETUs
*
* However we need to compensate for SSP_CLK . . .
2021-04-22 00:36:21 +08:00
*/
2016-04-27 03:29:45 +08:00
2021-04-24 04:25:58 +08:00
2015-06-02 18:17:34 +08:00
//=============================================================================
// An ISO 14443 Type B tag. We listen for commands from the reader, using
2020-07-04 03:33:17 +08:00
// a UART kind of thing that's implemented in software. When we get a
2015-06-02 18:17:34 +08:00
// frame (i.e., a group of bytes between SOF and EOF), we check the CRC.
// If it's good, then we can do something appropriate with it, and send
// a response.
//=============================================================================
2020-07-04 03:33:17 +08:00
//-----------------------------------------------------------------------------
// Code up a string of octets at layer 2 (including CRC, we don't generate
// that here) so that they can be transmitted to the reader. Doesn't transmit
// them yet, just leaves them ready to send in ToSend[].
//-----------------------------------------------------------------------------
static void CodeIso14443bAsTag ( const uint8_t * cmd , int len ) {
2020-07-14 21:46:05 +08:00
int i ;
2020-07-04 03:33:17 +08:00
2020-07-14 21:46:05 +08:00
tosend_reset ( ) ;
2020-07-04 03:33:17 +08:00
// Transmit a burst of ones, as the initial thing that lets the
// reader get phase sync.
// This loop is TR1, per specification
// TR1 minimum must be > 80/fs
// TR1 maximum 200/fs
// 80/fs < TR1 < 200/fs
// 10 ETU < TR1 < 24 ETU
// Send TR1.
// 10-11 ETU * 4times samples ONES
2021-03-05 17:21:25 +08:00
for ( i = 0 ; i < 10 ; i + + ) {
2020-07-14 21:46:05 +08:00
SEND4STUFFBIT ( 1 ) ;
}
2020-07-04 03:33:17 +08:00
// Send SOF.
// 10-11 ETU * 4times samples ZEROS
2020-07-14 21:46:05 +08:00
for ( i = 0 ; i < 10 ; i + + ) {
SEND4STUFFBIT ( 0 ) ;
}
2020-07-04 03:33:17 +08:00
// 2-3 ETU * 4times samples ONES
2020-07-14 21:46:05 +08:00
for ( i = 0 ; i < 2 ; i + + ) {
SEND4STUFFBIT ( 1 ) ;
}
2020-07-04 03:33:17 +08:00
// data
2020-07-14 21:46:05 +08:00
for ( i = 0 ; i < len ; i + + ) {
2020-07-04 03:33:17 +08:00
// Start bit
2020-07-14 21:46:05 +08:00
SEND4STUFFBIT ( 0 ) ;
2020-07-04 03:33:17 +08:00
2020-07-14 21:46:05 +08:00
// Data bits
uint8_t b = cmd [ i ] ;
for ( int j = 0 ; j < 8 ; j + + ) {
2020-07-04 03:33:17 +08:00
SEND4STUFFBIT ( b & 1 ) ;
2020-07-14 21:46:05 +08:00
b > > = 1 ;
}
2020-07-04 03:33:17 +08:00
2020-07-14 21:46:05 +08:00
// Stop bit
SEND4STUFFBIT ( 1 ) ;
2020-07-04 03:33:17 +08:00
// Extra Guard bit
// For PICC it ranges 0-18us (1etu = 9us)
//SEND4STUFFBIT(1);
2020-07-14 21:46:05 +08:00
}
2020-07-04 03:33:17 +08:00
// Send EOF.
// 10-11 ETU * 4 sample rate = ZEROS
2020-08-13 18:25:04 +08:00
for ( i = 0 ; i < 10 ; i + + ) {
2020-07-14 21:46:05 +08:00
SEND4STUFFBIT ( 0 ) ;
}
2020-08-13 18:25:04 +08:00
2021-04-24 04:25:58 +08:00
// why this? push out transfers between arm and fpga?
//for (i = 0; i < 2; i++) {
// SEND4STUFFBIT(1);
//}
2020-07-04 03:33:17 +08:00
2020-07-14 00:14:34 +08:00
tosend_t * ts = get_tosend ( ) ;
2020-07-14 21:46:05 +08:00
// Convert from last byte pos to length
ts - > max + + ;
2020-07-04 03:33:17 +08:00
}
2016-03-13 14:20:21 +08:00
//-----------------------------------------------------------------------------
2020-07-04 03:33:17 +08:00
// The software UART that receives commands from the reader, and its state
// variables.
2016-03-13 14:20:21 +08:00
//-----------------------------------------------------------------------------
static struct {
2019-03-10 03:34:41 +08:00
enum {
2019-08-08 22:57:33 +08:00
STATE_14B_UNSYNCD ,
STATE_14B_GOT_FALLING_EDGE_OF_SOF ,
STATE_14B_AWAITING_START_BIT ,
STATE_14B_RECEIVING_DATA
2019-03-10 03:34:41 +08:00
} state ;
uint16_t shiftReg ;
int bitCnt ;
int byteCnt ;
int byteCntMax ;
int posCnt ;
uint8_t * output ;
2016-03-13 14:20:21 +08:00
} Uart ;
2020-05-10 22:59:38 +08:00
static void Uart14bReset ( void ) {
2019-08-08 22:57:33 +08:00
Uart . state = STATE_14B_UNSYNCD ;
2019-03-10 03:34:41 +08:00
Uart . shiftReg = 0 ;
Uart . bitCnt = 0 ;
Uart . byteCnt = 0 ;
Uart . byteCntMax = MAX_FRAME_SIZE ;
Uart . posCnt = 0 ;
2016-03-13 14:20:21 +08:00
}
2019-08-08 22:57:33 +08:00
static void Uart14bInit ( uint8_t * data ) {
2019-03-10 03:34:41 +08:00
Uart . output = data ;
2019-08-08 22:57:33 +08:00
Uart14bReset ( ) ;
2016-03-13 14:20:21 +08:00
}
2021-05-06 03:04:48 +08:00
// param timeout accepts ETU
2021-04-24 04:25:58 +08:00
static void iso14b_set_timeout ( uint32_t timeout_etu ) {
2023-08-24 16:20:01 +08:00
uint32_t ssp = HF14_ETU_TO_SSP ( timeout_etu ) ;
2021-04-24 04:25:58 +08:00
if ( ssp > MAX_14B_TIMEOUT )
ssp = MAX_14B_TIMEOUT ;
iso14b_timeout = ssp ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) {
2021-04-24 04:25:58 +08:00
Dbprintf ( " ISO14443B Timeout set to %ld fwt " , iso14b_timeout ) ;
}
}
// keep track of FWT, also updates the timeout
static void iso14b_set_fwt ( uint8_t fwt ) {
iso14b_fwt = fwt ;
2021-05-06 03:04:48 +08:00
iso14b_set_timeout ( 32 < < fwt ) ;
2021-04-24 04:25:58 +08:00
}
static void iso14b_set_maxframesize ( uint16_t size ) {
if ( size > 256 )
size = MAX_FRAME_SIZE ;
Uart . byteCntMax = size ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) Dbprintf ( " ISO14443B Max frame size set to %d bytes " , Uart . byteCntMax ) ;
2021-04-24 04:25:58 +08:00
}
2016-04-27 03:29:45 +08:00
//-----------------------------------------------------------------------------
// The software Demod that receives commands from the tag, and its state variables.
//-----------------------------------------------------------------------------
2020-08-14 20:58:27 +08:00
# define NOISE_THRESHOLD 80 // don't try to correlate noise
# define MAX_PREVIOUS_AMPLITUDE (-1 - NOISE_THRESHOLD)
2016-03-13 14:20:21 +08:00
static struct {
2019-03-10 03:34:41 +08:00
enum {
DEMOD_UNSYNCD ,
DEMOD_PHASE_REF_TRAINING ,
2020-10-01 08:14:49 +08:00
WAIT_FOR_RISING_EDGE_OF_SOF ,
2019-03-10 03:34:41 +08:00
DEMOD_AWAITING_START_BIT ,
DEMOD_RECEIVING_DATA
} state ;
uint16_t bitCount ;
int posCount ;
int thisBit ;
uint16_t shiftReg ;
2020-08-14 20:58:27 +08:00
uint16_t max_len ;
2019-03-10 03:34:41 +08:00
uint8_t * output ;
uint16_t len ;
int sumI ;
int sumQ ;
2016-03-13 14:20:21 +08:00
} Demod ;
2016-04-27 03:29:45 +08:00
// Clear out the state of the "UART" that receives from the tag.
2020-05-10 22:59:38 +08:00
static void Demod14bReset ( void ) {
2019-03-10 03:34:41 +08:00
Demod . state = DEMOD_UNSYNCD ;
Demod . bitCount = 0 ;
Demod . posCount = 0 ;
Demod . thisBit = 0 ;
Demod . shiftReg = 0 ;
Demod . len = 0 ;
Demod . sumI = 0 ;
Demod . sumQ = 0 ;
2016-03-13 14:20:21 +08:00
}
2020-08-14 20:58:27 +08:00
static void Demod14bInit ( uint8_t * data , uint16_t max_len ) {
2019-03-10 03:34:41 +08:00
Demod . output = data ;
2020-08-14 20:58:27 +08:00
Demod . max_len = max_len ;
2019-08-08 22:57:33 +08:00
Demod14bReset ( ) ;
2016-03-13 14:20:21 +08:00
}
2015-06-02 18:17:34 +08:00
/* Receive & handle a bit coming from the reader.
2015-06-18 15:52:53 +08:00
*
* This function is called 4 times per bit ( every 2 subcarrier cycles ) .
* Subcarrier frequency fs is 848 kHz , 1 / fs = 1 , 18u s , i . e . function is called every 2 , 36u s
2015-06-02 18:17:34 +08:00
*
* LED handling :
* LED A - > ON once we have received the SOF and are expecting the rest .
* LED A - > OFF once we have received EOF or are in error state or unsynced
*
* Returns : true if we received a EOF
* false if we are still waiting for some more
*/
2020-08-14 20:58:27 +08:00
static RAMFUNC int Handle14443bSampleFromReader ( uint8_t bit ) {
2019-03-10 03:34:41 +08:00
switch ( Uart . state ) {
2019-08-08 22:57:33 +08:00
case STATE_14B_UNSYNCD :
2020-08-17 03:13:10 +08:00
if ( bit = = false ) {
2019-03-10 03:34:41 +08:00
// we went low, so this could be the beginning of an SOF
2019-08-08 22:57:33 +08:00
Uart . state = STATE_14B_GOT_FALLING_EDGE_OF_SOF ;
2019-03-10 03:34:41 +08:00
Uart . posCnt = 0 ;
Uart . bitCnt = 0 ;
}
break ;
2019-08-08 22:57:33 +08:00
case STATE_14B_GOT_FALLING_EDGE_OF_SOF :
2019-03-10 03:34:41 +08:00
Uart . posCnt + + ;
2020-08-17 03:13:10 +08:00
2019-03-10 03:34:41 +08:00
if ( Uart . posCnt = = 2 ) { // sample every 4 1/fs in the middle of a bit
2020-08-17 03:13:10 +08:00
2019-03-10 03:34:41 +08:00
if ( bit ) {
if ( Uart . bitCnt > 9 ) {
// we've seen enough consecutive
// zeros that it's a valid SOF
Uart . posCnt = 0 ;
Uart . byteCnt = 0 ;
2019-08-08 22:57:33 +08:00
Uart . state = STATE_14B_AWAITING_START_BIT ;
2019-03-10 03:34:41 +08:00
LED_A_ON ( ) ; // Indicate we got a valid SOF
} else {
// didn't stay down long enough before going high, error
2019-08-08 22:57:33 +08:00
Uart . state = STATE_14B_UNSYNCD ;
2019-03-10 03:34:41 +08:00
}
} else {
// do nothing, keep waiting
}
Uart . bitCnt + + ;
}
2020-08-17 03:13:10 +08:00
if ( Uart . posCnt > = 4 ) {
Uart . posCnt = 0 ;
}
2019-03-10 03:34:41 +08:00
if ( Uart . bitCnt > 12 ) {
// Give up if we see too many zeros without a one, too.
LED_A_OFF ( ) ;
2019-08-08 22:57:33 +08:00
Uart . state = STATE_14B_UNSYNCD ;
2019-03-10 03:34:41 +08:00
}
break ;
2019-08-08 22:57:33 +08:00
case STATE_14B_AWAITING_START_BIT :
2019-03-10 03:34:41 +08:00
Uart . posCnt + + ;
2020-08-17 03:13:10 +08:00
2019-03-10 03:34:41 +08:00
if ( bit ) {
2020-08-17 03:13:10 +08:00
// max 57us between characters = 49 1/fs,
// max 3 etus after low phase of SOF = 24 1/fs
if ( Uart . posCnt > 50 / 2 ) {
2019-03-10 03:34:41 +08:00
// stayed high for too long between characters, error
2019-08-08 22:57:33 +08:00
Uart . state = STATE_14B_UNSYNCD ;
2019-03-10 03:34:41 +08:00
}
2020-08-17 03:13:10 +08:00
2019-03-10 03:34:41 +08:00
} else {
// falling edge, this starts the data byte
Uart . posCnt = 0 ;
Uart . bitCnt = 0 ;
Uart . shiftReg = 0 ;
2019-08-08 22:57:33 +08:00
Uart . state = STATE_14B_RECEIVING_DATA ;
2019-03-10 03:34:41 +08:00
}
break ;
2019-08-08 22:57:33 +08:00
case STATE_14B_RECEIVING_DATA :
2020-08-17 03:13:10 +08:00
2019-03-10 03:34:41 +08:00
Uart . posCnt + + ;
2020-08-17 03:13:10 +08:00
2019-03-10 03:34:41 +08:00
if ( Uart . posCnt = = 2 ) {
// time to sample a bit
Uart . shiftReg > > = 1 ;
if ( bit ) {
Uart . shiftReg | = 0x200 ;
}
Uart . bitCnt + + ;
}
2020-08-17 03:13:10 +08:00
2019-03-10 03:34:41 +08:00
if ( Uart . posCnt > = 4 ) {
Uart . posCnt = 0 ;
}
2020-08-17 03:13:10 +08:00
2019-03-10 03:34:41 +08:00
if ( Uart . bitCnt = = 10 ) {
2019-03-10 07:00:59 +08:00
if ( ( Uart . shiftReg & 0x200 ) & & ! ( Uart . shiftReg & 0x001 ) ) {
2019-03-10 03:34:41 +08:00
// this is a data byte, with correct
// start and stop bits
2020-08-17 03:13:10 +08:00
Uart . output [ Uart . byteCnt ] = ( Uart . shiftReg > > 1 ) & 0xFF ;
2019-03-10 03:34:41 +08:00
Uart . byteCnt + + ;
if ( Uart . byteCnt > = Uart . byteCntMax ) {
// Buffer overflowed, give up
LED_A_OFF ( ) ;
2019-08-08 22:57:33 +08:00
Uart . state = STATE_14B_UNSYNCD ;
2019-03-10 03:34:41 +08:00
} else {
// so get the next byte now
Uart . posCnt = 0 ;
2019-08-08 22:57:33 +08:00
Uart . state = STATE_14B_AWAITING_START_BIT ;
2019-03-10 03:34:41 +08:00
}
} else if ( Uart . shiftReg = = 0x000 ) {
// this is an EOF byte
LED_A_OFF ( ) ; // Finished receiving
2019-08-08 22:57:33 +08:00
Uart . state = STATE_14B_UNSYNCD ;
2019-03-10 03:34:41 +08:00
if ( Uart . byteCnt ! = 0 )
return true ;
} else {
// this is an error
LED_A_OFF ( ) ;
2019-08-08 22:57:33 +08:00
Uart . state = STATE_14B_UNSYNCD ;
2019-03-10 03:34:41 +08:00
}
}
break ;
default :
LED_A_OFF ( ) ;
2019-08-08 22:57:33 +08:00
Uart . state = STATE_14B_UNSYNCD ;
2019-03-10 03:34:41 +08:00
break ;
}
return false ;
2015-06-02 18:17:34 +08:00
}
//-----------------------------------------------------------------------------
// Receive a command (from the reader to us, where we are the simulated tag),
// and store it in the given buffer, up to the given maximum length. Keeps
// spinning, waiting for a well-framed command, until either we get one
2017-07-07 18:52:51 +08:00
// (returns true) or someone presses the pushbutton on the board (false).
2015-06-02 18:17:34 +08:00
//
// Assume that we're called with the SSC (to the FPGA) and ADC path set
// correctly.
//-----------------------------------------------------------------------------
2019-03-10 18:20:22 +08:00
static int GetIso14443bCommandFromReader ( uint8_t * received , uint16_t * len ) {
2019-03-10 03:34:41 +08:00
// Set FPGA mode to "simulated ISO 14443B tag", no modulation (listen
// only, since we are receiving, not transmitting).
// Signal field is off with the appropriate LED
LED_D_OFF ( ) ;
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
// Now run a `software UART' on the stream of incoming samples.
2019-08-08 22:57:33 +08:00
Uart14bInit ( received ) ;
2019-03-10 03:34:41 +08:00
2020-07-04 03:33:17 +08:00
while ( BUTTON_PRESS ( ) = = false ) {
2019-03-10 03:34:41 +08:00
WDT_HIT ( ) ;
2020-08-13 18:25:04 +08:00
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_RXRDY ) ) {
2020-07-14 21:46:05 +08:00
uint8_t b = ( uint8_t ) AT91C_BASE_SSC - > SSC_RHR ;
for ( uint8_t mask = 0x80 ; mask ! = 0x00 ; mask > > = 1 ) {
2020-08-14 20:58:27 +08:00
if ( Handle14443bSampleFromReader ( b & mask ) ) {
2019-03-10 03:34:41 +08:00
* len = Uart . byteCnt ;
return true ;
}
}
}
}
return false ;
2015-06-02 18:17:34 +08:00
}
2022-01-06 22:40:11 +08:00
static void TransmitFor14443b_AsTag ( const uint8_t * response , uint16_t len ) {
2016-04-27 17:21:29 +08:00
2019-03-10 03:34:41 +08:00
// Signal field is off with the appropriate LED
LED_D_OFF ( ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
// Modulate BPSK
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK ) ;
2020-07-04 03:33:17 +08:00
AT91C_BASE_SSC - > SSC_THR = 0xFF ;
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_SIMULATOR ) ;
2016-04-27 17:21:29 +08:00
2019-03-10 03:34:41 +08:00
// Transmit the response.
2019-03-10 07:00:59 +08:00
for ( uint16_t i = 0 ; i < len ; ) {
2019-03-09 15:59:13 +08:00
2019-03-10 07:00:59 +08:00
// Put byte into tx holding register as soon as it is ready
if ( AT91C_BASE_SSC - > SSC_SR & AT91C_SSC_TXRDY ) {
2020-07-15 21:16:35 +08:00
AT91C_BASE_SSC - > SSC_THR = response [ i + + ] ;
2019-03-10 03:34:41 +08:00
}
}
2019-03-09 15:59:13 +08:00
}
2015-06-02 18:17:34 +08:00
//-----------------------------------------------------------------------------
// Main loop of simulated tag: receive commands from reader, decide what
// response to send, and send it.
//-----------------------------------------------------------------------------
2023-08-15 13:16:11 +08:00
void SimulateIso14443bTag ( const uint8_t * pupi ) {
2016-04-27 17:21:29 +08:00
2020-07-04 03:33:17 +08:00
LED_A_ON ( ) ;
2020-07-14 21:46:05 +08:00
// the only commands we understand is WUPB, AFI=0, Select All, N=1:
2020-07-04 03:33:17 +08:00
// static const uint8_t cmdWUPB[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 }; // WUPB
2020-07-14 21:46:05 +08:00
// ... and REQB, AFI=0, Normal Request, N=1:
2020-07-04 03:33:17 +08:00
// static const uint8_t cmdREQB[] = { ISO14443B_REQB, 0x00, 0x00, 0x71, 0xFF }; // REQB
2020-07-14 21:46:05 +08:00
// ... and HLTB
// static const uint8_t cmdHLTB[] = { 0x50, 0xff, 0xff, 0xff, 0xff }; // HLTB
// ... and ATTRIB
2020-07-04 03:33:17 +08:00
// static const uint8_t cmdATTRIB[] = { ISO14443B_ATTRIB, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; // ATTRIB
// ... if not PUPI/UID is supplied we always respond with ATQB, PUPI = 820de174, Application Data = 0x20381922,
// supports only 106kBit/s in both directions, max frame size = 32Bytes,
// supports ISO14443-4, FWI=8 (77ms), NAD supported, CID not supported:
uint8_t respATQB [ ] = {
2020-08-13 18:25:04 +08:00
0x50 ,
0x82 , 0x0d , 0xe1 , 0x74 ,
0x20 , 0x38 , 0x19 ,
0x22 , 0x00 , 0x21 , 0x85 ,
0x5e , 0xd7
2020-07-04 03:33:17 +08:00
} ;
// ...PUPI/UID supplied from user. Adjust ATQB response accordingly
2020-10-03 00:06:21 +08:00
if ( memcmp ( " \x00 \x00 \x00 \x00 " , pupi , 4 ) ! = 0 ) {
memcpy ( respATQB + 1 , pupi , 4 ) ;
2020-07-04 03:33:17 +08:00
AddCrc14B ( respATQB , 12 ) ;
}
2020-08-13 18:25:04 +08:00
2020-10-03 00:06:21 +08:00
// response to HLTB and ATTRIB
static const uint8_t respOK [ ] = { 0x00 , 0x78 , 0xF0 } ;
2019-03-10 03:34:41 +08:00
// setup device.
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
2020-07-04 03:33:17 +08:00
2019-03-10 03:34:41 +08:00
// connect Demodulated Signal to ADC:
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
2020-07-04 03:33:17 +08:00
2020-07-14 21:46:05 +08:00
// Set up the synchronous serial port
2020-07-04 03:33:17 +08:00
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_SIMULATOR ) ;
2019-03-10 03:34:41 +08:00
// allocate command receive buffer
2019-03-10 07:00:59 +08:00
BigBuf_free ( ) ;
BigBuf_Clear_ext ( false ) ;
2020-07-04 03:33:17 +08:00
clear_trace ( ) ;
2019-03-10 03:34:41 +08:00
set_tracing ( true ) ;
uint16_t len , cmdsReceived = 0 ;
int cardSTATE = SIM_NOFIELD ;
int vHf = 0 ; // in mV
2020-07-14 00:14:34 +08:00
tosend_t * ts = get_tosend ( ) ;
2020-08-13 18:25:04 +08:00
2019-03-10 03:34:41 +08:00
uint8_t * receivedCmd = BigBuf_malloc ( MAX_FRAME_SIZE ) ;
// prepare "ATQB" tag answer (encoded):
CodeIso14443bAsTag ( respATQB , sizeof ( respATQB ) ) ;
2020-07-14 00:14:34 +08:00
uint8_t * encodedATQB = BigBuf_malloc ( ts - > max ) ;
uint16_t encodedATQBLen = ts - > max ;
memcpy ( encodedATQB , ts - > buf , ts - > max ) ;
2019-03-10 03:34:41 +08:00
// prepare "OK" tag answer (encoded):
CodeIso14443bAsTag ( respOK , sizeof ( respOK ) ) ;
2020-07-14 00:14:34 +08:00
uint8_t * encodedOK = BigBuf_malloc ( ts - > max ) ;
uint16_t encodedOKLen = ts - > max ;
memcpy ( encodedOK , ts - > buf , ts - > max ) ;
2019-03-10 03:34:41 +08:00
// Simulation loop
2020-07-14 00:14:34 +08:00
while ( BUTTON_PRESS ( ) = = false ) {
2019-03-10 03:34:41 +08:00
WDT_HIT ( ) ;
2020-08-13 18:25:04 +08:00
2020-07-14 00:14:34 +08:00
//iceman: limit with 2000 times..
if ( data_available ( ) ) {
break ;
}
2019-03-10 03:34:41 +08:00
// find reader field
if ( cardSTATE = = SIM_NOFIELD ) {
2020-02-12 17:29:00 +08:00
2020-06-10 05:37:56 +08:00
vHf = ( MAX_ADC_HF_VOLTAGE * SumAdc ( ADC_CHAN_HF , 32 ) ) > > 15 ;
2019-03-10 07:00:59 +08:00
if ( vHf > MF_MINFIELDV ) {
2019-03-10 03:34:41 +08:00
cardSTATE = SIM_IDLE ;
LED_A_ON ( ) ;
}
}
if ( cardSTATE = = SIM_NOFIELD ) continue ;
// Get reader command
if ( ! GetIso14443bCommandFromReader ( receivedCmd , & len ) ) {
Dbprintf ( " button pressed, received %d commands " , cmdsReceived ) ;
break ;
}
// ISO14443-B protocol states:
// REQ or WUP request in ANY state
// WUP in HALTED state
2019-03-10 07:00:59 +08:00
if ( len = = 5 ) {
if ( ( receivedCmd [ 0 ] = = ISO14443B_REQB & & ( receivedCmd [ 2 ] & 0x8 ) = = 0x8 & & cardSTATE = = SIM_HALTED ) | |
2020-08-13 18:25:04 +08:00
receivedCmd [ 0 ] = = ISO14443B_REQB ) {
2019-03-10 03:34:41 +08:00
LogTrace ( receivedCmd , len , 0 , 0 , NULL , true ) ;
cardSTATE = SIM_SELECTING ;
}
}
/*
* How should this flow go ?
* REQB or WUPB
* send response ( waiting for Attrib )
* ATTRIB
* send response ( waiting for commands 7816 )
* HALT
send halt response ( waiting for wupb )
*/
switch ( cardSTATE ) {
//case SIM_NOFIELD:
case SIM_HALTED :
case SIM_IDLE : {
LogTrace ( receivedCmd , len , 0 , 0 , NULL , true ) ;
break ;
}
case SIM_SELECTING : {
2019-03-10 07:00:59 +08:00
TransmitFor14443b_AsTag ( encodedATQB , encodedATQBLen ) ;
2019-03-10 03:34:41 +08:00
LogTrace ( respATQB , sizeof ( respATQB ) , 0 , 0 , NULL , false ) ;
cardSTATE = SIM_WORK ;
break ;
}
case SIM_HALTING : {
2019-03-10 07:00:59 +08:00
TransmitFor14443b_AsTag ( encodedOK , encodedOKLen ) ;
2019-03-10 03:34:41 +08:00
LogTrace ( respOK , sizeof ( respOK ) , 0 , 0 , NULL , false ) ;
cardSTATE = SIM_HALTED ;
break ;
}
case SIM_ACKNOWLEDGE : {
2019-03-10 07:00:59 +08:00
TransmitFor14443b_AsTag ( encodedOK , encodedOKLen ) ;
2019-03-10 03:34:41 +08:00
LogTrace ( respOK , sizeof ( respOK ) , 0 , 0 , NULL , false ) ;
cardSTATE = SIM_IDLE ;
break ;
}
case SIM_WORK : {
2019-03-10 07:00:59 +08:00
if ( len = = 7 & & receivedCmd [ 0 ] = = ISO14443B_HALT ) {
2019-03-10 03:34:41 +08:00
cardSTATE = SIM_HALTED ;
2019-03-10 07:00:59 +08:00
} else if ( len = = 11 & & receivedCmd [ 0 ] = = ISO14443B_ATTRIB ) {
2019-03-10 03:34:41 +08:00
cardSTATE = SIM_ACKNOWLEDGE ;
} else {
// Todo:
// - SLOT MARKER
// - ISO7816
// - emulate with a memory dump
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG )
2020-07-04 03:33:17 +08:00
Dbprintf ( " new cmd from reader: len=%d, cmdsRecvd=%d " , len , cmdsReceived ) ;
2019-03-10 03:34:41 +08:00
// CRC Check
2019-03-10 07:00:59 +08:00
if ( len > = 3 ) { // if crc exists
2019-03-10 03:34:41 +08:00
2020-07-04 03:33:17 +08:00
if ( ! check_crc ( CRC_14443_B , receivedCmd , len ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) {
2020-07-04 03:33:17 +08:00
DbpString ( " CRC fail " ) ;
}
}
} else {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) {
2022-02-25 02:31:47 +08:00
DbpString ( " CRC ok " ) ;
2020-07-04 03:33:17 +08:00
}
2019-03-10 03:34:41 +08:00
}
cardSTATE = SIM_IDLE ;
}
break ;
}
2019-03-10 07:00:59 +08:00
default :
break ;
2019-03-10 03:34:41 +08:00
}
+ + cmdsReceived ;
}
2020-07-04 03:33:17 +08:00
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG )
2019-03-10 03:34:41 +08:00
Dbprintf ( " Emulator stopped. Trace length: %d " , BigBuf_get_traceLen ( ) ) ;
2020-08-13 18:25:04 +08:00
2020-07-14 00:14:34 +08:00
switch_off ( ) ; //simulate
2015-06-02 18:17:34 +08:00
}
2020-11-05 19:14:09 +08:00
/*
void Simulate_iso14443b_srx_tag ( uint8_t * uid ) {
LED_A_ON ( ) ;
/ SRI512
2020-11-07 08:32:43 +08:00
2020-11-05 19:14:09 +08:00
> initiate 06 00 ISO14443B_INITIATE
< xx crc crc
> select 0 e xx ISO14443B_SELECT
< xx nn nn
2020-11-07 08:32:43 +08:00
2020-11-05 19:14:09 +08:00
> readblock 08 blck_no ISO14443B_READ_BLK
< d0 d1 d2 d3 2 byte crc
2020-11-07 08:32:43 +08:00
2020-11-05 19:14:09 +08:00
> get uid ISO14443B_GET_UID
< 81 93 99 20 92 11 02 ( 8 byte UID in MSB D002 199220 999381 )
# define ISO14443B_REQB 0x05
# define ISO14443B_ATTRIB 0x1D
# define ISO14443B_HALT 0x50
# define ISO14443B_INITIATE 0x06
# define ISO14443B_SELECT 0x0E
# define ISO14443B_GET_UID 0x0B
# define ISO14443B_READ_BLK 0x08
# define ISO14443B_WRITE_BLK 0x09
# define ISO14443B_RESET 0x0C
# define ISO14443B_COMPLETION 0x0F
# define ISO14443B_AUTHENTICATE 0x0A
# define ISO14443B_PING 0xBA
# define ISO14443B_PONG 0xAB
static const uint8_t resp_init_srx [ ] = { 0x73 , 0x64 , 0xb1 } ;
uint8_t resp_select_srx [ ] = { 0x73 , 0x64 , 0xb1 } ;
// a default uid, or user supplied
uint8_t resp_getuid_srx [ 10 ] = {
0x81 , 0x93 , 0x99 , 0x20 , 0x92 , 0x11 , 0x02 , 0xD0 , 0x00 , 0x00
} ;
// ...UID supplied from user. Adjust ATQB response accordingly
if ( memcmp ( " \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 " , uid , 8 ) ! = 0 ) {
memcpy ( resp_getuid_srx , uid , 8 ) ;
AddCrc14B ( resp_getuid_srx , 8 ) ;
}
// response to HLTB and ATTRIB
static const uint8_t respOK [ ] = { 0x00 , 0x78 , 0xF0 } ;
// setup device.
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
// connect Demodulated Signal to ADC:
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
// Set up the synchronous serial port
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_SIMULATOR ) ;
// allocate command receive buffer
BigBuf_free ( ) ;
BigBuf_Clear_ext ( false ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
uint16_t len , cmdsReceived = 0 ;
int cardSTATE = SIM_NOFIELD ;
int vHf = 0 ; // in mV
tosend_t * ts = get_tosend ( ) ;
uint8_t * receivedCmd = BigBuf_malloc ( MAX_FRAME_SIZE ) ;
// prepare "ATQB" tag answer (encoded):
CodeIso14443bAsTag ( respATQB , sizeof ( respATQB ) ) ;
uint8_t * encodedATQB = BigBuf_malloc ( ts - > max ) ;
uint16_t encodedATQBLen = ts - > max ;
memcpy ( encodedATQB , ts - > buf , ts - > max ) ;
// prepare "OK" tag answer (encoded):
CodeIso14443bAsTag ( respOK , sizeof ( respOK ) ) ;
uint8_t * encodedOK = BigBuf_malloc ( ts - > max ) ;
uint16_t encodedOKLen = ts - > max ;
memcpy ( encodedOK , ts - > buf , ts - > max ) ;
// Simulation loop
while ( BUTTON_PRESS ( ) = = false ) {
WDT_HIT ( ) ;
//iceman: limit with 2000 times..
if ( data_available ( ) ) {
break ;
}
// find reader field
if ( cardSTATE = = SIM_NOFIELD ) {
vHf = ( MAX_ADC_HF_VOLTAGE * SumAdc ( ADC_CHAN_HF , 32 ) ) > > 15 ;
if ( vHf > MF_MINFIELDV ) {
cardSTATE = SIM_IDLE ;
LED_A_ON ( ) ;
}
}
if ( cardSTATE = = SIM_NOFIELD ) continue ;
// Get reader command
if ( ! GetIso14443bCommandFromReader ( receivedCmd , & len ) ) {
Dbprintf ( " button pressed, received %d commands " , cmdsReceived ) ;
break ;
}
// ISO14443-B protocol states:
// REQ or WUP request in ANY state
// WUP in HALTED state
if ( len = = 5 ) {
if ( ( receivedCmd [ 0 ] = = ISO14443B_REQB & & ( receivedCmd [ 2 ] & 0x8 ) = = 0x8 & & cardSTATE = = SIM_HALTED ) | |
receivedCmd [ 0 ] = = ISO14443B_REQB ) {
LogTrace ( receivedCmd , len , 0 , 0 , NULL , true ) ;
cardSTATE = SIM_SELECTING ;
}
}
/
* How should this flow go ?
* REQB or WUPB
* send response ( waiting for Attrib )
* ATTRIB
* send response ( waiting for commands 7816 )
* HALT
send halt response ( waiting for wupb )
/
switch ( cardSTATE ) {
//case SIM_NOFIELD:
case SIM_HALTED :
case SIM_IDLE : {
LogTrace ( receivedCmd , len , 0 , 0 , NULL , true ) ;
break ;
}
case SIM_SELECTING : {
TransmitFor14443b_AsTag ( encodedATQB , encodedATQBLen ) ;
LogTrace ( respATQB , sizeof ( respATQB ) , 0 , 0 , NULL , false ) ;
cardSTATE = SIM_WORK ;
break ;
}
case SIM_HALTING : {
TransmitFor14443b_AsTag ( encodedOK , encodedOKLen ) ;
LogTrace ( respOK , sizeof ( respOK ) , 0 , 0 , NULL , false ) ;
cardSTATE = SIM_HALTED ;
break ;
}
case SIM_ACKNOWLEDGE : {
TransmitFor14443b_AsTag ( encodedOK , encodedOKLen ) ;
LogTrace ( respOK , sizeof ( respOK ) , 0 , 0 , NULL , false ) ;
cardSTATE = SIM_IDLE ;
break ;
}
case SIM_WORK : {
if ( len = = 7 & & receivedCmd [ 0 ] = = ISO14443B_HALT ) {
cardSTATE = SIM_HALTED ;
} else if ( len = = 11 & & receivedCmd [ 0 ] = = ISO14443B_ATTRIB ) {
cardSTATE = SIM_ACKNOWLEDGE ;
} else {
// Todo:
// - SLOT MARKER
// - ISO7816
// - emulate with a memory dump
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG )
2020-11-05 19:14:09 +08:00
Dbprintf ( " new cmd from reader: len=%d, cmdsRecvd=%d " , len , cmdsReceived ) ;
// CRC Check
if ( len > = 3 ) { // if crc exists
if ( ! check_crc ( CRC_14443_B , receivedCmd , len ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) {
2020-11-05 19:14:09 +08:00
DbpString ( " CRC fail " ) ;
}
}
} else {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) {
2022-02-25 02:31:47 +08:00
DbpString ( " CRC ok " ) ;
2020-11-05 19:14:09 +08:00
}
}
cardSTATE = SIM_IDLE ;
}
break ;
}
default :
break ;
}
+ + cmdsReceived ;
}
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG )
2020-11-05 19:14:09 +08:00
Dbprintf ( " Emulator stopped. Trace length: %d " , BigBuf_get_traceLen ( ) ) ;
switch_off ( ) ; //simulate
}
*/
2015-06-02 18:17:34 +08:00
//=============================================================================
// An ISO 14443 Type B reader. We take layer two commands, code them
// appropriately, and then send them to the tag. We then listen for the
// tag's response, which we leave in the buffer to be demodulated on the
// PC side.
//=============================================================================
2020-10-01 08:14:49 +08:00
// We support both 14b framing and 14b' framing.
// 14b framing looks like:
// xxxxxxxx1111111111111111-000000000011-0........1-0........1-0........1-1-0........1-0........1-1000000000011xxxxxx
// TR1 SOF 10*0+2*1 start-stop ^^^^^^^^byte ^ occasional stuff bit EOF 10*0+N*1
// 14b' framing looks like:
// xxxxxxxxxxxxxxxx111111111111111111111-0........1-0........1-0........1-1-0........1-0........1-000000000000xxxxxxx
// SOF? start-stop ^^^^^^^^byte ^ occasional stuff bit EOF
2015-06-02 18:17:34 +08:00
/*
* Handles reception of a bit from the tag
*
2015-06-18 15:52:53 +08:00
* This function is called 2 times per bit ( every 4 subcarrier cycles ) .
* Subcarrier frequency fs is 848 kHz , 1 / fs = 1 , 18u s , i . e . function is called every 4 , 72u s
*
2015-06-02 18:17:34 +08:00
* LED handling :
* LED C - > ON once we have received the SOF and are expecting the rest .
* LED C - > OFF once we have received EOF or are unsynced
*
* Returns : true if we received a EOF
* false if we are still waiting for some more
*
*/
2020-08-17 03:13:10 +08:00
static RAMFUNC int Handle14443bSamplesFromTag ( int ci , int cq ) {
2020-09-30 23:06:19 +08:00
int v = 0 ;
2020-08-17 03:13:10 +08:00
// The soft decision on the bit uses an estimate of just the
// quadrant of the reference angle, not the exact angle.
# define MAKE_SOFT_DECISION() { \
2020-10-07 02:44:23 +08:00
if ( Demod . sumI > 0 ) { \
v = ci ; \
} else { \
v = - ci ; \
} \
if ( Demod . sumQ > 0 ) { \
v + = cq ; \
} else { \
v - = cq ; \
} \
}
# define SUBCARRIER_DETECT_THRESHOLD 8
2020-08-17 03:13:10 +08:00
// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq)))
# define AMPLITUDE(ci,cq) (MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq)) / 2))
2020-09-07 16:35:09 +08:00
switch ( Demod . state ) {
2020-08-17 03:13:10 +08:00
2020-09-07 16:35:09 +08:00
case DEMOD_UNSYNCD : {
2020-10-07 02:44:23 +08:00
if ( AMPLITUDE ( ci , cq ) > SUBCARRIER_DETECT_THRESHOLD ) { // subcarrier detected
2020-09-07 16:35:09 +08:00
Demod . state = DEMOD_PHASE_REF_TRAINING ;
Demod . sumI = ci ;
Demod . sumQ = cq ;
Demod . posCount = 1 ;
}
break ;
2020-08-14 20:58:27 +08:00
}
2020-09-07 16:35:09 +08:00
case DEMOD_PHASE_REF_TRAINING : {
2020-10-01 08:14:49 +08:00
// While we get a constant signal
if ( AMPLITUDE ( ci , cq ) > SUBCARRIER_DETECT_THRESHOLD ) {
if ( ( ( ABS ( Demod . sumI ) > ABS ( Demod . sumQ ) ) & & ( ( ( ci > 0 ) & & ( Demod . sumI > 0 ) ) | | ( ( ci < 0 ) & & ( Demod . sumI < 0 ) ) ) ) | | // signal closer to horizontal, polarity check based on on I
2020-10-07 00:41:15 +08:00
( ( ABS ( Demod . sumI ) < = ABS ( Demod . sumQ ) ) & & ( ( ( cq > 0 ) & & ( Demod . sumQ > 0 ) ) | | ( ( cq < 0 ) & & ( Demod . sumQ < 0 ) ) ) ) ) { // signal closer to vertical, polarity check based on on Q
2020-10-05 16:02:32 +08:00
2020-10-01 08:14:49 +08:00
if ( Demod . posCount < 10 ) { // refine signal approximation during first 10 samples
Demod . sumI + = ci ;
Demod . sumQ + = cq ;
}
Demod . posCount + = 1 ;
2020-09-07 16:35:09 +08:00
} else {
2020-10-01 08:14:49 +08:00
// transition
if ( Demod . posCount < 10 ) {
// subcarrier lost
Demod . state = DEMOD_UNSYNCD ;
break ;
} else {
// at this point it can be start of 14b' data or start of 14b SOF
MAKE_SOFT_DECISION ( ) ;
2020-10-07 02:44:23 +08:00
Demod . posCount = 1 ; // this was the first half
2020-10-01 08:14:49 +08:00
Demod . thisBit = v ;
Demod . shiftReg = 0 ;
Demod . state = DEMOD_RECEIVING_DATA ;
}
2020-09-07 16:35:09 +08:00
}
} else {
2020-10-01 08:14:49 +08:00
// subcarrier lost
Demod . state = DEMOD_UNSYNCD ;
2020-09-07 16:35:09 +08:00
}
break ;
2020-08-14 20:58:27 +08:00
}
2020-10-01 08:14:49 +08:00
case DEMOD_AWAITING_START_BIT : {
Demod . posCount + + ;
2020-09-07 16:35:09 +08:00
MAKE_SOFT_DECISION ( ) ;
2020-10-01 08:14:49 +08:00
if ( v > 0 ) {
2020-10-07 02:44:23 +08:00
if ( Demod . posCount > 3 * 2 ) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs
2020-10-01 08:14:49 +08:00
LED_C_OFF ( ) ;
if ( Demod . bitCount = = 0 & & Demod . len = = 0 ) { // received SOF only, this is valid for iClass/Picopass
return true ;
} else {
Demod . state = DEMOD_UNSYNCD ;
}
2020-09-07 16:35:09 +08:00
}
2020-10-07 02:44:23 +08:00
} else { // start bit detected
Demod . posCount = 1 ; // this was the first half
2020-10-01 08:14:49 +08:00
Demod . thisBit = v ;
Demod . shiftReg = 0 ;
Demod . state = DEMOD_RECEIVING_DATA ;
2020-09-07 16:35:09 +08:00
}
break ;
2020-08-14 20:58:27 +08:00
}
2020-10-01 08:14:49 +08:00
case WAIT_FOR_RISING_EDGE_OF_SOF : {
2020-09-07 16:35:09 +08:00
Demod . posCount + + ;
MAKE_SOFT_DECISION ( ) ;
if ( v > 0 ) {
if ( Demod . posCount < 9 * 2 ) { // low phase of SOF too short (< 9 etu). Note: spec is >= 10, but FPGA tends to "smear" edges
Demod . state = DEMOD_UNSYNCD ;
} else {
LED_C_ON ( ) ; // Got SOF
Demod . posCount = 0 ;
Demod . bitCount = 0 ;
Demod . len = 0 ;
Demod . state = DEMOD_AWAITING_START_BIT ;
}
} else {
2020-09-30 23:06:19 +08:00
if ( Demod . posCount > 12 * 2 ) { // low phase of SOF too long (> 12 etu)
2020-09-07 16:35:09 +08:00
Demod . state = DEMOD_UNSYNCD ;
LED_C_OFF ( ) ;
}
}
break ;
2020-08-14 20:58:27 +08:00
}
2020-09-07 16:35:09 +08:00
case DEMOD_RECEIVING_DATA : {
MAKE_SOFT_DECISION ( ) ;
2020-10-07 02:44:23 +08:00
if ( Demod . posCount = = 0 ) { // first half of bit
2020-09-07 16:35:09 +08:00
Demod . thisBit = v ;
Demod . posCount = 1 ;
2020-10-07 02:44:23 +08:00
} else { // second half of bit
2020-09-07 16:35:09 +08:00
Demod . thisBit + = v ;
Demod . shiftReg > > = 1 ;
2020-10-07 02:44:23 +08:00
if ( Demod . thisBit > 0 ) { // logic '1'
2020-09-07 16:35:09 +08:00
Demod . shiftReg | = 0x200 ;
}
Demod . bitCount + + ;
if ( Demod . bitCount = = 10 ) {
uint16_t s = Demod . shiftReg ;
if ( ( s & 0x200 ) & & ! ( s & 0x001 ) ) { // stop bit == '1', start bit == '0'
Demod . output [ Demod . len ] = ( s > > 1 ) ;
Demod . len + + ;
Demod . bitCount = 0 ;
Demod . state = DEMOD_AWAITING_START_BIT ;
} else {
if ( s = = 0x000 ) {
2020-10-01 08:14:49 +08:00
if ( Demod . len > 0 ) {
LED_C_OFF ( ) ;
// This is EOF (start, stop and all data bits == '0'
return true ;
} else {
// Zeroes but no data acquired yet?
// => Still in SOF of 14b, wait for raising edge
Demod . posCount = 10 * 2 ;
Demod . bitCount = 0 ;
Demod . len = 0 ;
Demod . state = WAIT_FOR_RISING_EDGE_OF_SOF ;
break ;
}
2020-09-07 16:35:09 +08:00
}
2020-10-02 06:58:41 +08:00
if ( AMPLITUDE ( ci , cq ) < SUBCARRIER_DETECT_THRESHOLD ) {
LED_C_OFF ( ) ;
// subcarrier lost
Demod . state = DEMOD_UNSYNCD ;
if ( Demod . len > 0 ) { // no EOF but no signal anymore and we got data, e.g. ASK CTx
return true ;
}
}
// we have still signal but no proper byte or EOF? this shouldn't happen
2020-10-02 20:31:52 +08:00
//Demod.posCount = 10 * 2;
Demod . bitCount = 0 ;
Demod . len = 0 ;
2020-10-02 06:58:41 +08:00
Demod . state = WAIT_FOR_RISING_EDGE_OF_SOF ;
2020-10-02 20:31:52 +08:00
break ;
2020-09-07 16:35:09 +08:00
}
}
Demod . posCount = 0 ;
}
break ;
2020-08-14 20:58:27 +08:00
}
2020-09-07 16:35:09 +08:00
default : {
Demod . state = DEMOD_UNSYNCD ;
LED_C_OFF ( ) ;
break ;
2020-08-14 20:58:27 +08:00
}
2020-09-07 16:35:09 +08:00
}
return false ;
2015-06-02 18:17:34 +08:00
}
/*
* Demodulate the samples we received from the tag , also log to tracebuffer
*/
2021-04-24 04:25:58 +08:00
static int Get14443bAnswerFromTag ( uint8_t * response , uint16_t max_len , uint32_t timeout , uint32_t * eof_time ) {
2020-07-04 03:33:17 +08:00
2019-03-10 03:34:41 +08:00
// Set up the demodulator for tag -> reader responses.
2020-08-17 03:13:10 +08:00
Demod14bInit ( response , max_len ) ;
2020-10-07 00:41:15 +08:00
2020-07-15 21:16:35 +08:00
// The DMA buffer, used to stream samples from the FPGA
dmabuf16_t * dma = get_dma16 ( ) ;
if ( FpgaSetupSscDma ( ( uint8_t * ) dma - > buf , DMA_BUFFER_SIZE ) = = false ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > DBG_ERROR ) Dbprintf ( " FpgaSetupSscDma failed. Exiting " ) ;
2020-07-04 03:33:17 +08:00
return - 1 ;
2019-03-10 03:34:41 +08:00
}
2016-08-07 23:49:33 +08:00
2020-08-14 20:58:27 +08:00
uint32_t dma_start_time = 0 ;
2020-07-15 21:16:35 +08:00
uint16_t * upTo = dma - > buf ;
2021-04-24 04:25:58 +08:00
int samples = 0 , ret = 0 ;
2020-07-15 21:16:35 +08:00
2020-09-30 23:06:19 +08:00
// Put FPGA in the appropriate mode
2021-05-07 18:27:13 +08:00
LED_D_ON ( ) ;
2020-09-30 23:06:19 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ ) ;
2020-08-13 18:25:04 +08:00
for ( ; ; ) {
2020-07-14 21:46:05 +08:00
2020-08-14 20:58:27 +08:00
volatile uint16_t behindBy = ( ( uint16_t * ) AT91C_BASE_PDC_SSC - > PDC_RPR - upTo ) & ( DMA_BUFFER_SIZE - 1 ) ;
if ( behindBy = = 0 )
continue ;
2020-07-14 21:46:05 +08:00
2020-07-15 21:16:35 +08:00
samples + + ;
2020-08-17 03:13:10 +08:00
2020-07-15 21:16:35 +08:00
if ( samples = = 1 ) {
// DMA has transferred the very first data
dma_start_time = GetCountSspClk ( ) & 0xfffffff0 ;
2020-07-14 21:46:05 +08:00
}
2020-08-17 03:13:10 +08:00
volatile int8_t ci = * upTo > > 8 ;
2020-09-07 16:35:09 +08:00
volatile int8_t cq = * upTo ;
upTo + + ;
2020-08-14 20:58:27 +08:00
// we have read all of the DMA buffer content.
if ( upTo > = dma - > buf + DMA_BUFFER_SIZE ) {
// start reading the circular buffer from the beginning again
upTo = dma - > buf ;
// DMA Counter Register had reached 0, already rotated.
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_ENDRX ) ) {
// primary buffer was stopped
if ( AT91C_BASE_PDC_SSC - > PDC_RCR = = false ) {
AT91C_BASE_PDC_SSC - > PDC_RPR = ( uint32_t ) dma - > buf ;
AT91C_BASE_PDC_SSC - > PDC_RCR = DMA_BUFFER_SIZE ;
}
// secondary buffer sets as primary, secondary buffer was stopped
if ( AT91C_BASE_PDC_SSC - > PDC_RNCR = = false ) {
AT91C_BASE_PDC_SSC - > PDC_RNPR = ( uint32_t ) dma - > buf ;
AT91C_BASE_PDC_SSC - > PDC_RNCR = DMA_BUFFER_SIZE ;
}
2020-09-07 16:35:09 +08:00
2020-08-14 20:58:27 +08:00
WDT_HIT ( ) ;
if ( BUTTON_PRESS ( ) ) {
2020-08-17 03:13:10 +08:00
DbpString ( " stopped " ) ;
2020-08-14 20:58:27 +08:00
break ;
}
2020-07-15 21:16:35 +08:00
}
}
2020-08-13 18:25:04 +08:00
2020-08-17 03:13:10 +08:00
if ( Handle14443bSamplesFromTag ( ci , cq ) ) {
2020-08-14 20:58:27 +08:00
2021-04-24 04:25:58 +08:00
* eof_time = GetCountSspClkDelta ( dma_start_time ) - DELAY_TAG_TO_ARM ; // end of EOF
2020-07-14 21:46:05 +08:00
2020-08-14 20:58:27 +08:00
if ( Demod . len > Demod . max_len ) {
2020-08-17 03:13:10 +08:00
ret = - 2 ; // overflow
2020-08-14 20:58:27 +08:00
}
2020-07-14 21:46:05 +08:00
break ;
}
2021-05-06 03:04:48 +08:00
if ( ( ( GetCountSspClkDelta ( dma_start_time ) ) > timeout ) & & Demod . state < DEMOD_PHASE_REF_TRAINING ) {
2020-08-17 03:13:10 +08:00
ret = - 1 ;
2020-07-14 21:46:05 +08:00
break ;
}
2019-03-10 03:34:41 +08:00
}
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
FpgaDisableSscDma ( ) ;
2020-07-14 21:46:05 +08:00
if ( ret < 0 ) {
return ret ;
}
2020-07-04 03:33:17 +08:00
if ( Demod . len > 0 ) {
2023-08-24 16:20:01 +08:00
uint32_t sof_time = * eof_time - HF14_ETU_TO_SSP (
2022-07-01 04:50:52 +08:00
( Demod . len * ( 8 + 2 ) ) // time for byte transfers
// + (10) // time for TR1
+ ( 10 + 2 ) // time for SOF transfer
+ ( 10 ) ) ; // time for EOF transfer
2020-12-18 09:14:50 +08:00
LogTrace ( Demod . output , Demod . len , sof_time , * eof_time , NULL , false ) ;
2020-07-04 03:33:17 +08:00
}
2020-08-14 20:58:27 +08:00
return Demod . len ;
2015-06-02 18:17:34 +08:00
}
//-----------------------------------------------------------------------------
// Transmit the command (to the tag) that was placed in ToSend[].
//-----------------------------------------------------------------------------
2021-04-24 04:25:58 +08:00
// param start_time in SSP_CLK
2020-08-14 20:58:27 +08:00
static void TransmitFor14443b_AsReader ( uint32_t * start_time ) {
2020-09-07 16:35:09 +08:00
2020-08-14 20:58:27 +08:00
tosend_t * ts = get_tosend ( ) ;
2020-09-07 16:35:09 +08:00
2023-08-28 18:00:44 +08:00
# ifdef RDV4
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD_RDV4 ) ;
2023-09-08 02:13:18 +08:00
# else
2020-07-14 21:46:05 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD ) ;
2023-09-08 02:13:18 +08:00
# endif
2018-06-19 18:57:27 +08:00
2020-09-30 23:06:19 +08:00
// TR2 minimum 14 ETUs
2021-04-24 04:25:58 +08:00
if ( * start_time < ISO14B_TR0 ) {
// *start_time = DELAY_ARM_TO_TAG;
* start_time = ISO14B_TR0 ;
2020-08-14 20:58:27 +08:00
}
2021-04-24 04:25:58 +08:00
// *start_time = (*start_time - DELAY_ARM_TO_TAG) & 0xfffffff0;
* start_time = ( * start_time & 0xfffffff0 ) ;
2020-09-07 16:35:09 +08:00
2020-08-14 20:58:27 +08:00
if ( GetCountSspClk ( ) > * start_time ) { // we may miss the intended time
2020-09-30 23:06:19 +08:00
* start_time = ( GetCountSspClk ( ) + 32 ) & 0xfffffff0 ; // next possible time
2020-08-14 20:58:27 +08:00
}
2020-10-07 00:41:15 +08:00
2020-08-14 20:58:27 +08:00
// wait
2020-09-30 23:06:19 +08:00
while ( GetCountSspClk ( ) < * start_time ) ;
2020-08-13 18:25:04 +08:00
2020-08-14 20:58:27 +08:00
LED_B_ON ( ) ;
2020-07-14 21:46:05 +08:00
for ( int c = 0 ; c < ts - > max ; c + + ) {
2020-08-14 20:58:27 +08:00
volatile uint8_t data = ts - > buf [ c ] ;
2020-07-15 21:16:35 +08:00
2020-09-30 23:06:19 +08:00
for ( uint8_t i = 0 ; i < 8 ; i + + ) {
volatile uint16_t send_word = ( data & 0x80 ) ? 0x0000 : 0xFFFF ;
2020-08-13 18:25:04 +08:00
2020-07-14 21:46:05 +08:00
while ( ! ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_TXRDY ) ) ) ;
2020-08-13 18:25:04 +08:00
AT91C_BASE_SSC - > SSC_THR = send_word ;
2020-07-15 21:16:35 +08:00
2020-07-14 21:46:05 +08:00
while ( ! ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_TXRDY ) ) ) ;
AT91C_BASE_SSC - > SSC_THR = send_word ;
data < < = 1 ;
}
2020-08-13 18:25:04 +08:00
WDT_HIT ( ) ;
2019-03-10 03:34:41 +08:00
}
2022-07-01 04:50:52 +08:00
// transmit remaining bits. we need one-sample granularity now
volatile uint8_t data = ts - > buf [ ts - > max ] , last_bits = ts - > bit ;
for ( uint8_t i = 0 ; i < last_bits ; i + + ) {
volatile uint16_t send_word = ( data & 0x80 ) ? 0x0000 : 0xFFFF ;
while ( ! ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_TXRDY ) ) ) ;
AT91C_BASE_SSC - > SSC_THR = send_word ;
while ( ! ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_TXRDY ) ) ) ;
AT91C_BASE_SSC - > SSC_THR = send_word ;
data < < = 1 ;
}
WDT_HIT ( ) ;
2020-07-14 21:46:05 +08:00
LED_B_OFF ( ) ;
2020-08-14 20:58:27 +08:00
2022-07-01 04:50:52 +08:00
// *start_time += DELAY_ARM_TO_TAG;
2020-10-07 00:41:15 +08:00
2020-09-30 23:06:19 +08:00
// wait for last transfer to complete
while ( ! ( AT91C_BASE_SSC - > SSC_SR & AT91C_SSC_TXEMPTY ) ) { } ;
2015-06-02 18:17:34 +08:00
}
//-----------------------------------------------------------------------------
// Code a layer 2 command (string of octets, including CRC) into ToSend[],
2015-06-18 15:52:53 +08:00
// so that it is ready to transmit to the tag using TransmitFor14443b().
2015-06-02 18:17:34 +08:00
//-----------------------------------------------------------------------------
2022-07-01 04:50:52 +08:00
static void CodeIso14443bAsReader ( const uint8_t * cmd , int len , bool framing ) {
2019-03-10 03:34:41 +08:00
/*
* QUESTION : how long is a 1 or 0 in pulses in the xcorr_848 mode ?
* 1 " stuffbit " = 1 ETU ( 9u s )
2020-10-07 00:41:15 +08:00
*
2020-09-30 23:06:19 +08:00
* TR2 - After the PICC response , the PCD is required to wait the Frame Delay Time ( TR2 )
before transmission of the next command . The minimum frame delay time required for
all commands is 14 ETUs
*
2019-03-10 03:34:41 +08:00
*/
2020-09-30 23:06:19 +08:00
int i ;
2020-07-14 00:14:34 +08:00
tosend_reset ( ) ;
2020-10-07 00:41:15 +08:00
2022-07-01 04:50:52 +08:00
// add framing enable flag. xerox chips use unframed commands during anticollision
if ( framing ) {
// Send SOF
// 10-11 ETUs of ZERO
for ( i = 0 ; i < 10 ; i + + ) {
tosend_stuffbit ( 0 ) ;
}
// 2-3 ETUs of ONE
tosend_stuffbit ( 1 ) ;
tosend_stuffbit ( 1 ) ;
2020-09-30 23:06:19 +08:00
}
2019-03-10 03:34:41 +08:00
// Sending cmd, LSB
// from here we add BITS
2020-09-30 23:06:19 +08:00
for ( i = 0 ; i < len ; i + + ) {
2019-03-10 03:34:41 +08:00
// Start bit
2020-07-14 00:14:34 +08:00
tosend_stuffbit ( 0 ) ;
2019-03-10 03:34:41 +08:00
2020-09-30 23:06:19 +08:00
// Data bits
volatile uint8_t b = cmd [ i ] ;
2020-07-14 00:14:34 +08:00
tosend_stuffbit ( b & 1 ) ;
tosend_stuffbit ( ( b > > 1 ) & 1 ) ;
tosend_stuffbit ( ( b > > 2 ) & 1 ) ;
tosend_stuffbit ( ( b > > 3 ) & 1 ) ;
tosend_stuffbit ( ( b > > 4 ) & 1 ) ;
tosend_stuffbit ( ( b > > 5 ) & 1 ) ;
tosend_stuffbit ( ( b > > 6 ) & 1 ) ;
tosend_stuffbit ( ( b > > 7 ) & 1 ) ;
2019-03-10 03:34:41 +08:00
// Stop bit
2020-07-14 00:14:34 +08:00
tosend_stuffbit ( 1 ) ;
2020-09-30 23:06:19 +08:00
// EGT extra guard time 1 ETU = 9us
// For PCD it ranges 0-57us === 0 - 6 ETU
// FOR PICC it ranges 0-19us == 0 - 2 ETU
2019-03-10 03:34:41 +08:00
}
2022-07-01 04:50:52 +08:00
if ( framing ) {
// Send EOF
// 10-11 ETUs of ZERO
for ( i = 0 ; i < 10 ; i + + ) {
tosend_stuffbit ( 0 ) ;
}
2020-09-30 23:06:19 +08:00
}
2019-03-10 03:34:41 +08:00
2022-07-01 04:50:52 +08:00
// we can't use padding now
/*
int pad = ( 10 + 2 + ( len * 10 ) + 10 ) & 0x7 ;
for ( i = 0 ; i < 16 - pad ; + + i )
tosend_stuffbit ( 1 ) ;
*/
2015-06-02 18:17:34 +08:00
}
2016-08-10 05:13:18 +08:00
/*
* Convenience function to encode , transmit and trace iso 14443 b comms
*/
2022-07-01 04:50:52 +08:00
static void CodeAndTransmit14443bAsReader ( const uint8_t * cmd , int len , uint32_t * start_time , uint32_t * eof_time , bool framing ) {
2020-08-14 20:58:27 +08:00
tosend_t * ts = get_tosend ( ) ;
2022-07-01 04:50:52 +08:00
CodeIso14443bAsReader ( cmd , len , framing ) ;
2020-08-14 20:58:27 +08:00
TransmitFor14443b_AsReader ( start_time ) ;
2020-11-06 06:05:52 +08:00
if ( g_trigger ) LED_A_ON ( ) ;
2022-07-01 04:50:52 +08:00
// eof_time in ssp clocks, but bits was added here!
// *eof_time = *start_time + (10 * ts->max) + 10 + 2 + 10;
2023-08-24 16:20:01 +08:00
* eof_time = * start_time + HF14_ETU_TO_SSP ( 8 * ts - > max ) ;
2022-07-01 04:50:52 +08:00
2020-08-18 04:07:50 +08:00
LogTrace ( cmd , len , * start_time , * eof_time , NULL , true ) ;
2015-06-02 18:17:34 +08:00
}
2015-07-13 06:04:16 +08:00
/* Sends an APDU to the tag
* TODO : check CRC and preamble
*/
2020-10-04 01:08:27 +08:00
int iso14443b_apdu ( uint8_t const * msg , size_t msg_len , bool send_chaining , void * rxdata , uint16_t rxmaxlen , uint8_t * res ) {
2020-08-17 03:13:10 +08:00
2020-09-30 23:06:19 +08:00
uint8_t real_cmd [ msg_len + 4 ] ;
if ( msg_len ) {
// ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02
real_cmd [ 0 ] = 0x02 ; // bnr, nad, cid, chn=0; i-block(0x00)
if ( send_chaining ) {
real_cmd [ 0 ] | = 0x10 ;
}
// put block number into the PCB
real_cmd [ 0 ] | = iso14b_pcb_blocknum ;
memcpy ( real_cmd + 1 , msg , msg_len ) ;
} else {
// R-block. ACK
real_cmd [ 0 ] = 0xA2 ; // r-block + ACK
real_cmd [ 0 ] | = iso14b_pcb_blocknum ;
}
2020-10-07 00:41:15 +08:00
2020-09-30 23:06:19 +08:00
AddCrc14B ( real_cmd , msg_len + 1 ) ;
2020-09-07 16:35:09 +08:00
2019-03-10 03:34:41 +08:00
// send
2020-08-14 20:58:27 +08:00
uint32_t start_time = 0 ;
2020-08-18 04:07:50 +08:00
uint32_t eof_time = 0 ;
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( real_cmd , msg_len + 3 , & start_time , & eof_time , true ) ;
2020-01-13 17:34:59 +08:00
2021-04-24 04:25:58 +08:00
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
2023-08-24 16:20:01 +08:00
// Activation frame waiting time
// 65536/fc == 4833 µS
// SSP_CLK = 4833 µS * 3.39 = 16384
2023-09-08 02:13:18 +08:00
int len = Get14443bAnswerFromTag ( rxdata , rxmaxlen , iso14b_timeout , & eof_time ) ;
2020-08-18 04:07:50 +08:00
FpgaDisableTracing ( ) ;
2020-01-16 02:25:29 +08:00
2020-10-04 01:08:27 +08:00
uint8_t * data_bytes = ( uint8_t * ) rxdata ;
2020-09-30 23:06:19 +08:00
if ( len < = 0 ) {
return 0 ; //DATA LINK ERROR
} else {
// S-Block WTX
while ( len & & ( ( data_bytes [ 0 ] & 0xF2 ) = = 0xF2 ) ) {
2021-04-24 04:25:58 +08:00
uint32_t save_iso14b_timeout_spp = iso14b_timeout ;
2021-05-06 03:04:48 +08:00
// 2 high bits mandatory set to 0b
// byte1 - WTXM [1..59].
2021-04-24 04:25:58 +08:00
uint8_t wtxm = data_bytes [ 1 ] & 0x3F ;
// command FWT = FWT * WTXM
uint32_t fwt_temp = iso14b_fwt * wtxm ;
2021-05-06 03:04:48 +08:00
2020-09-30 23:06:19 +08:00
// temporarily increase timeout
2021-05-06 03:04:48 +08:00
iso14b_set_timeout ( ( 32 < < fwt_temp ) ) ;
2021-04-24 04:25:58 +08:00
2020-09-30 23:06:19 +08:00
// Transmit WTX back
2021-04-24 04:25:58 +08:00
data_bytes [ 1 ] = wtxm ;
2020-09-30 23:06:19 +08:00
// now need to fix CRC.
AddCrc14B ( data_bytes , len - 2 ) ;
// transmit S-Block
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( data_bytes , len , & start_time , & eof_time , true ) ;
2020-09-30 23:06:19 +08:00
// retrieve the result again (with increased timeout)
2021-04-24 04:25:58 +08:00
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
len = Get14443bAnswerFromTag ( rxdata , rxmaxlen , iso14b_timeout , & eof_time ) ;
2020-09-30 23:06:19 +08:00
FpgaDisableTracing ( ) ;
2020-10-04 01:08:27 +08:00
data_bytes = rxdata ;
2021-04-24 04:25:58 +08:00
2020-09-30 23:06:19 +08:00
// restore timeout
2021-04-24 04:25:58 +08:00
iso14b_timeout = save_iso14b_timeout_spp ;
2020-09-30 23:06:19 +08:00
}
// if we received an I- or R(ACK)-Block with a block number equal to the
// current block number, toggle the current block number
2020-10-01 00:19:51 +08:00
if ( len > = 3 // PCB + CRC = 3 bytes
2020-09-30 23:06:19 +08:00
& & ( ( data_bytes [ 0 ] & 0xC0 ) = = 0 // I-Block
| | ( data_bytes [ 0 ] & 0xD0 ) = = 0x80 ) // R-Block with ACK bit set to 0
& & ( data_bytes [ 0 ] & 0x01 ) = = iso14b_pcb_blocknum ) { // equal block numbers
iso14b_pcb_blocknum ^ = 1 ;
}
// if we received I-block with chaining we need to send ACK and receive another block of data
2020-10-04 01:08:27 +08:00
if ( res )
* res = data_bytes [ 0 ] ;
2020-09-30 23:06:19 +08:00
// crc check
if ( len > = 3 & & ! check_crc ( CRC_14443_B , data_bytes , len ) ) {
return - 1 ;
}
2020-08-18 04:07:50 +08:00
}
2019-03-10 03:34:41 +08:00
2020-09-30 23:06:19 +08:00
if ( len ) {
// cut frame byte
len - = 1 ;
// memmove(data_bytes, data_bytes + 1, len);
for ( int i = 0 ; i < len ; i + + )
data_bytes [ i ] = data_bytes [ i + 1 ] ;
2019-03-10 03:34:41 +08:00
}
2020-08-18 04:07:50 +08:00
2020-09-30 23:06:19 +08:00
return len ;
2015-07-13 06:04:16 +08:00
}
2020-10-02 20:31:52 +08:00
/**
* ASK CTS initialise .
*/
static int iso14443b_select_cts_card ( iso14b_cts_card_select_t * card ) {
// INITIATE command: wake up the tag using the INITIATE
uint8_t cmdINIT [ ] = { ASK_REQT , 0xF9 , 0xE0 } ;
uint8_t cmdMSBUID [ ] = { ASK_SELECT , 0xFF , 0xFF , 0x00 , 0x00 } ;
uint8_t cmdLSBUID [ ] = { 0xC4 , 0x00 , 0x00 } ;
AddCrc14B ( cmdMSBUID , 3 ) ;
AddCrc14B ( cmdLSBUID , 1 ) ;
uint8_t r [ 8 ] ;
2020-10-07 00:41:15 +08:00
2020-10-02 20:31:52 +08:00
uint32_t start_time = 0 ;
uint32_t eof_time = 0 ;
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( cmdINIT , sizeof ( cmdINIT ) , & start_time , & eof_time , true ) ;
2020-10-02 20:31:52 +08:00
2021-04-24 04:25:58 +08:00
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
int retlen = Get14443bAnswerFromTag ( r , sizeof ( r ) , iso14b_timeout , & eof_time ) ;
2020-10-02 20:31:52 +08:00
FpgaDisableTracing ( ) ;
if ( retlen ! = 4 ) {
return - 1 ;
}
if ( check_crc ( CRC_14443_B , r , retlen ) = = false ) {
return - 2 ;
}
if ( card ) {
// pc. fc Product code, Facility code
card - > pc = r [ 0 ] ;
card - > fc = r [ 1 ] ;
}
2021-04-24 04:25:58 +08:00
start_time = eof_time + ISO14B_TR2 ;
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( cmdMSBUID , sizeof ( cmdMSBUID ) , & start_time , & eof_time , true ) ;
2020-10-02 20:31:52 +08:00
2021-04-24 04:25:58 +08:00
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
retlen = Get14443bAnswerFromTag ( r , sizeof ( r ) , iso14b_timeout , & eof_time ) ;
2020-10-02 20:31:52 +08:00
FpgaDisableTracing ( ) ;
if ( retlen ! = 4 ) {
return - 1 ;
}
if ( check_crc ( CRC_14443_B , r , retlen ) = = false ) {
return - 2 ;
}
if ( card ) {
memcpy ( card - > uid , r , 2 ) ;
}
2021-04-24 04:25:58 +08:00
start_time = eof_time + ISO14B_TR2 ;
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( cmdLSBUID , sizeof ( cmdLSBUID ) , & start_time , & eof_time , true ) ;
2020-10-02 20:31:52 +08:00
2021-04-24 04:25:58 +08:00
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
retlen = Get14443bAnswerFromTag ( r , sizeof ( r ) , iso14b_timeout , & eof_time ) ;
2020-10-02 20:31:52 +08:00
FpgaDisableTracing ( ) ;
if ( retlen ! = 4 ) {
return - 1 ;
}
if ( check_crc ( CRC_14443_B , r , retlen ) = = false ) {
return - 2 ;
}
if ( card ) {
memcpy ( card - > uid + 2 , r , 2 ) ;
}
return 0 ;
}
2016-03-21 02:33:07 +08:00
/**
* SRx Initialise .
*/
2020-09-26 15:33:36 +08:00
static int iso14443b_select_srx_card ( iso14b_card_select_t * card ) {
2019-03-10 03:34:41 +08:00
// INITIATE command: wake up the tag using the INITIATE
static const uint8_t init_srx [ ] = { ISO14443B_INITIATE , 0x00 , 0x97 , 0x5b } ;
2020-08-17 03:13:10 +08:00
uint8_t r_init [ 3 ] = { 0x0 } ;
uint8_t r_select [ 3 ] = { 0x0 } ;
uint8_t r_papid [ 10 ] = { 0x0 } ;
2020-09-07 16:35:09 +08:00
2020-08-14 20:58:27 +08:00
uint32_t start_time = 0 ;
2020-08-18 04:07:50 +08:00
uint32_t eof_time = 0 ;
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( init_srx , sizeof ( init_srx ) , & start_time , & eof_time , true ) ;
2020-08-17 03:13:10 +08:00
2021-04-24 04:25:58 +08:00
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
int retlen = Get14443bAnswerFromTag ( r_init , sizeof ( r_init ) , iso14b_timeout , & eof_time ) ;
2020-01-13 17:34:59 +08:00
FpgaDisableTracing ( ) ;
2016-03-21 02:33:07 +08:00
2020-10-02 20:31:52 +08:00
if ( retlen < = 0 ) {
2020-09-26 15:33:36 +08:00
return - 1 ;
2020-10-02 20:31:52 +08:00
}
2016-03-21 02:33:07 +08:00
2019-03-10 03:34:41 +08:00
// Randomly generated Chip ID
2020-08-17 03:13:10 +08:00
if ( card ) {
card - > chipid = Demod . output [ 0 ] ;
}
2019-03-09 15:59:13 +08:00
2020-08-17 03:13:10 +08:00
// SELECT command (with space for CRC)
uint8_t select_srx [ ] = { ISO14443B_SELECT , 0x00 , 0x00 , 0x00 } ;
select_srx [ 1 ] = r_init [ 0 ] ;
2020-09-07 16:35:09 +08:00
2019-03-10 03:34:41 +08:00
AddCrc14B ( select_srx , 2 ) ;
2019-03-09 15:59:13 +08:00
2021-04-24 04:25:58 +08:00
start_time = eof_time + ISO14B_TR2 ;
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( select_srx , sizeof ( select_srx ) , & start_time , & eof_time , true ) ;
2020-08-17 03:13:10 +08:00
2021-04-24 04:25:58 +08:00
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
retlen = Get14443bAnswerFromTag ( r_select , sizeof ( r_select ) , iso14b_timeout , & eof_time ) ;
2020-01-13 17:34:59 +08:00
FpgaDisableTracing ( ) ;
2019-03-09 15:59:13 +08:00
2020-08-17 03:13:10 +08:00
if ( retlen ! = 3 ) {
2020-09-26 15:33:36 +08:00
return - 1 ;
2020-08-17 03:13:10 +08:00
}
2021-04-24 04:25:58 +08:00
if ( check_crc ( CRC_14443_B , r_select , retlen ) = = false ) {
2020-09-26 15:33:36 +08:00
return - 2 ;
2020-08-17 03:13:10 +08:00
}
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
// Check response from the tag: should be the same UID as the command we just sent:
2020-08-17 03:13:10 +08:00
if ( select_srx [ 1 ] ! = r_select [ 0 ] ) {
2020-09-26 15:33:36 +08:00
return - 3 ;
2020-08-17 03:13:10 +08:00
}
2016-03-21 02:33:07 +08:00
2019-03-10 03:34:41 +08:00
// First get the tag's UID:
select_srx [ 0 ] = ISO14443B_GET_UID ;
2016-03-21 02:33:07 +08:00
2019-03-10 03:34:41 +08:00
AddCrc14B ( select_srx , 1 ) ;
2020-08-17 03:13:10 +08:00
2021-04-24 04:25:58 +08:00
start_time = eof_time + ISO14B_TR2 ;
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( select_srx , 3 , & start_time , & eof_time , true ) ; // Only first three bytes for this one
2020-09-07 16:35:09 +08:00
2021-04-24 04:25:58 +08:00
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
retlen = Get14443bAnswerFromTag ( r_papid , sizeof ( r_papid ) , iso14b_timeout , & eof_time ) ;
2020-01-13 17:34:59 +08:00
FpgaDisableTracing ( ) ;
2016-03-21 02:33:07 +08:00
2020-08-17 03:13:10 +08:00
if ( retlen ! = 10 ) {
2020-09-26 15:33:36 +08:00
return - 1 ;
2020-08-17 03:13:10 +08:00
}
if ( ! check_crc ( CRC_14443_B , r_papid , retlen ) ) {
2020-09-26 15:33:36 +08:00
return - 2 ;
2020-08-17 03:13:10 +08:00
}
2020-09-07 16:35:09 +08:00
2019-03-10 03:34:41 +08:00
if ( card ) {
card - > uidlen = 8 ;
2020-08-17 03:13:10 +08:00
memcpy ( card - > uid , r_papid , 8 ) ;
2019-03-10 03:34:41 +08:00
}
2016-03-21 02:33:07 +08:00
2019-03-10 03:34:41 +08:00
return 0 ;
2016-03-21 02:33:07 +08:00
}
2022-07-01 04:50:52 +08:00
// Xerox tag connect function: wup, anticoll, attrib, password
// the original chips require all commands in this sequence
// 0: OK, 1: select fail, 2: attrib fail, 3: crc fail, 4: password fail
int iso14443b_select_xrx_card ( iso14b_card_select_t * card ) {
// AFI
static const uint8_t x_wup1 [ ] = { 0x0D , 0x37 , 0x21 , 0x92 , 0xf2 } ;
static const uint8_t x_wup2 [ ] = { 0x5D , 0x37 , 0x21 , 0x71 , 0x71 } ;
uint8_t slot_mark [ 1 ] ;
2023-01-15 05:23:40 +08:00
uint8_t x_atqb [ 24 ] = { 0x0 } ; // ATQB len = 18
2022-07-01 04:50:52 +08:00
uint32_t start_time = 0 ;
uint32_t eof_time = 0 ;
2023-01-15 05:23:40 +08:00
iso14b_set_timeout ( 24 ) ; // wait for carrier
2022-07-01 04:50:52 +08:00
// wup1
CodeAndTransmit14443bAsReader ( x_wup1 , sizeof ( x_wup1 ) , & start_time , & eof_time , true ) ;
2023-01-15 05:23:40 +08:00
start_time = eof_time + US_TO_SSP ( 9000 ) ; // 9ms before next cmd
2022-07-01 04:50:52 +08:00
// wup2
CodeAndTransmit14443bAsReader ( x_wup2 , sizeof ( x_wup2 ) , & start_time , & eof_time , true ) ;
uint64_t uid = 0 ;
int retlen ;
for ( int uid_pos = 0 ; uid_pos < 64 ; uid_pos + = 2 ) {
int slot ;
for ( slot = 0 ; slot < 4 ; slot + + ) {
2023-08-24 16:20:01 +08:00
start_time = eof_time + HF14_ETU_TO_SSP ( 30 ) ; //(24); // next slot after 24 ETU
2022-07-01 04:50:52 +08:00
retlen = Get14443bAnswerFromTag ( x_atqb , sizeof ( x_atqb ) , iso14b_timeout , & eof_time ) ;
if ( retlen > 0 ) {
FpgaDisableTracing ( ) ;
Dbprintf ( " unexpected data %d " , retlen ) ;
Dbprintf ( " crc %s " , check_crc ( CRC_14443_B , x_atqb , retlen ) ? " OK " : " BAD " ) ;
return 1 ;
}
// tx unframed slot-marker
2023-01-15 05:23:40 +08:00
if ( Demod . posCount ) { // no rx, but subcarrier burst detected
2022-07-01 04:50:52 +08:00
uid | = ( uint64_t ) slot < < uid_pos ;
2023-01-15 05:23:40 +08:00
slot_mark [ 0 ] = 0xB1 + ( slot < < 1 ) ; // ack slot
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( slot_mark , sizeof ( slot_mark ) , & start_time , & eof_time , false ) ;
break ;
2023-01-15 05:23:40 +08:00
} else { // no subcarrier burst
slot_mark [ 0 ] = 0xA1 + ( slot < < 1 ) ; // nak slot
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( slot_mark , sizeof ( slot_mark ) , & start_time , & eof_time , false ) ;
}
}
if ( 4 = = slot ) {
FpgaDisableTracing ( ) ;
2022-07-08 05:43:45 +08:00
if ( g_dbglevel > = DBG_DEBUG ) {
DbpString ( " no answer to anticollision " ) ;
}
2022-07-01 04:50:52 +08:00
return 1 ;
}
}
retlen = Get14443bAnswerFromTag ( x_atqb , sizeof ( x_atqb ) , iso14b_timeout , & eof_time ) ;
2022-07-08 05:43:45 +08:00
if ( g_dbglevel > = DBG_DEBUG ) {
Dbprintf ( " anticollision uid %llx " , uid ) ;
}
2022-07-01 04:50:52 +08:00
// ATQB too short?
if ( retlen < 18 ) {
return 1 ;
}
// VALIDATE CRC
2023-01-15 05:23:40 +08:00
if ( check_crc ( CRC_14443_B , x_atqb , 18 ) = = false ) { // use fixed len because unstable EOF catch
2022-07-01 04:50:52 +08:00
return 3 ;
}
if ( x_atqb [ 0 ] ! = 0x50 ) {
// DbpString("aqtb bad");
return 1 ;
}
if ( card ) {
card - > uidlen = 8 ;
memcpy ( card - > uid , x_atqb + 1 , 8 ) ;
memcpy ( card - > atqb , x_atqb + 9 , 7 ) ;
}
// DbpString("aqtb ok");
// send ATTRIB command
uint8_t txbuf [ 18 ] ;
txbuf [ 1 ] = 0x1d ;
memcpy ( txbuf + 2 , & uid , 8 ) ;
txbuf [ 10 ] = 0 ;
txbuf [ 11 ] = 0xF ;
txbuf [ 12 ] = 1 ;
txbuf [ 13 ] = 0xF ;
AddCrc14B ( txbuf + 1 , 13 ) ;
start_time = eof_time + ISO14B_TR2 ;
CodeAndTransmit14443bAsReader ( txbuf + 1 , 15 , & start_time , & eof_time , true ) ;
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
retlen = Get14443bAnswerFromTag ( x_atqb , sizeof ( x_atqb ) , iso14b_timeout , & eof_time ) ;
FpgaDisableTracing ( ) ;
if ( retlen < 3 ) {
// DbpString("attrib failed");
return 2 ;
}
if ( check_crc ( CRC_14443_B , x_atqb , 3 ) = = false ) {
return 3 ;
}
if ( x_atqb [ 0 ] ! = 0 ) {
// DbpString("attrib failed");
return 2 ;
}
// DbpString("attrib ok");
// apply PASSWORD command
txbuf [ 0 ] = 2 ;
txbuf [ 1 ] = 0x38 ;
// uid from previous command used
txbuf [ 10 ] = 3 ;
txbuf [ 11 ] = 0x4e ;
txbuf [ 12 ] = 0x4b ;
txbuf [ 13 ] = 0x53 ;
txbuf [ 14 ] = 0x4F ;
AddCrc14B ( txbuf , 15 ) ;
start_time = eof_time + ISO14B_TR2 ;
CodeAndTransmit14443bAsReader ( txbuf , 17 , & start_time , & eof_time , true ) ;
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
retlen = Get14443bAnswerFromTag ( x_atqb , sizeof ( x_atqb ) , iso14b_timeout , & eof_time ) ;
if ( retlen < 4 ) {
// DbpString("passwd failed");
return 4 ;
}
if ( check_crc ( CRC_14443_B , x_atqb , 4 ) = = false ) {
return 3 ;
}
if ( x_atqb [ 0 ] ! = 2 | | x_atqb [ 1 ] ! = 0 ) {
// DbpString("passwd failed");
return 4 ;
}
// DbpString("passwd ok");
return 0 ;
}
2015-07-13 06:04:16 +08:00
/* Perform the ISO 14443 B Card Selection procedure
* Currently does NOT do any collision handling .
* It expects 0 - 1 cards in the device ' s range .
* TODO : Support multiple cards ( perform anticollision )
* TODO : Verify CRC checksums
*/
2020-07-04 03:33:17 +08:00
int iso14443b_select_card ( iso14b_card_select_t * card ) {
2019-03-10 03:34:41 +08:00
// WUPB command (including CRC)
// Note: WUPB wakes up all tags, REQB doesn't wake up tags in HALT state
2020-09-30 23:06:19 +08:00
// WUTB or REQB is denoted in the third byte, lower nibble. 0 vs 8
//static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 };
static const uint8_t wupb [ ] = { ISO14443B_REQB , 0x00 , 0x00 , 0x71 , 0xff } ;
2019-03-10 03:34:41 +08:00
// ATTRIB command (with space for CRC)
uint8_t attrib [ ] = { ISO14443B_ATTRIB , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x08 , 0x00 , 0x00 , 0x00 , 0x00 } ;
2020-08-17 03:13:10 +08:00
uint8_t r_pupid [ 14 ] = { 0x0 } ;
uint8_t r_attrib [ 3 ] = { 0x0 } ;
2019-03-10 03:34:41 +08:00
// first, wake up the tag
2020-08-14 20:58:27 +08:00
uint32_t start_time = 0 ;
2020-08-18 04:07:50 +08:00
uint32_t eof_time = 0 ;
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( wupb , sizeof ( wupb ) , & start_time , & eof_time , true ) ;
2020-08-17 03:13:10 +08:00
2021-04-24 04:25:58 +08:00
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
int retlen = Get14443bAnswerFromTag ( r_pupid , sizeof ( r_pupid ) , iso14b_timeout , & eof_time ) ;
2020-01-13 17:34:59 +08:00
FpgaDisableTracing ( ) ;
2019-03-10 03:34:41 +08:00
// ATQB too short?
2020-08-17 03:13:10 +08:00
if ( retlen < 14 ) {
2020-07-04 03:33:17 +08:00
return - 1 ;
2020-08-17 03:13:10 +08:00
}
2019-03-10 03:34:41 +08:00
// VALIDATE CRC
2021-04-24 04:25:58 +08:00
if ( check_crc ( CRC_14443_B , r_pupid , retlen ) = = false ) {
2020-07-04 03:33:17 +08:00
return - 2 ;
2020-08-17 03:13:10 +08:00
}
2019-03-10 03:34:41 +08:00
if ( card ) {
card - > uidlen = 4 ;
2020-08-17 03:13:10 +08:00
memcpy ( card - > uid , r_pupid + 1 , 4 ) ;
memcpy ( card - > atqb , r_pupid + 5 , 7 ) ;
2019-03-10 03:34:41 +08:00
}
2015-07-13 06:04:16 +08:00
2016-04-27 03:29:45 +08:00
// copy the PUPI to ATTRIB ( PUPI == UID )
2020-08-17 03:13:10 +08:00
memcpy ( attrib + 1 , r_pupid + 1 , 4 ) ;
2019-03-09 15:59:13 +08:00
2016-03-21 02:33:07 +08:00
// copy the protocol info from ATQB (Protocol Info -> Protocol_Type) into ATTRIB (Param 3)
2020-08-17 03:13:10 +08:00
attrib [ 7 ] = r_pupid [ 10 ] & 0x0F ;
2018-02-01 22:19:47 +08:00
AddCrc14B ( attrib , 9 ) ;
2021-04-24 04:25:58 +08:00
start_time = eof_time + ISO14B_TR2 ;
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( attrib , sizeof ( attrib ) , & start_time , & eof_time , true ) ;
2020-09-07 16:35:09 +08:00
2021-04-24 04:25:58 +08:00
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
retlen = Get14443bAnswerFromTag ( r_attrib , sizeof ( r_attrib ) , iso14b_timeout , & eof_time ) ;
2020-01-13 17:34:59 +08:00
FpgaDisableTracing ( ) ;
2016-03-21 02:33:07 +08:00
2015-07-13 06:04:16 +08:00
// Answer to ATTRIB too short?
2020-08-17 03:13:10 +08:00
if ( retlen < 3 ) {
2020-07-04 03:33:17 +08:00
return - 1 ;
2020-08-17 03:13:10 +08:00
}
2019-03-10 03:34:41 +08:00
// VALIDATE CRC
2021-04-24 04:25:58 +08:00
if ( check_crc ( CRC_14443_B , r_attrib , retlen ) = = false ) {
2020-07-04 03:33:17 +08:00
return - 2 ;
2020-08-17 03:13:10 +08:00
}
2019-03-10 03:34:41 +08:00
if ( card ) {
// CID
2020-08-17 03:13:10 +08:00
card - > cid = r_attrib [ 0 ] ;
2019-03-10 03:34:41 +08:00
// MAX FRAME
uint16_t maxFrame = card - > atqb [ 5 ] > > 4 ;
if ( maxFrame < 5 ) maxFrame = 8 * maxFrame + 16 ;
else if ( maxFrame = = 5 ) maxFrame = 64 ;
else if ( maxFrame = = 6 ) maxFrame = 96 ;
else if ( maxFrame = = 7 ) maxFrame = 128 ;
else if ( maxFrame = = 8 ) maxFrame = 256 ;
else maxFrame = 257 ;
iso14b_set_maxframesize ( maxFrame ) ;
// FWT
uint8_t fwt = card - > atqb [ 6 ] > > 4 ;
2021-04-24 04:25:58 +08:00
if ( fwt < 15 ) {
iso14b_set_fwt ( fwt ) ;
2019-03-10 03:34:41 +08:00
}
}
// reset PCB block number
2020-09-30 23:06:19 +08:00
iso14b_pcb_blocknum = 0 ;
2019-03-10 03:34:41 +08:00
return 0 ;
2015-07-13 06:04:16 +08:00
}
// Set up ISO 14443 Type B communication (similar to iso14443a_setup)
2016-04-27 03:29:45 +08:00
// field is setup for "Sending as Reader"
2020-05-10 22:59:38 +08:00
void iso14443b_setup ( void ) {
2019-03-10 03:34:41 +08:00
LEDsoff ( ) ;
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
2019-03-09 15:59:13 +08:00
2020-08-17 03:13:10 +08:00
// allocate command receive buffer
BigBuf_free ( ) ;
2019-03-10 03:34:41 +08:00
// Initialize Demod and Uart structs
2020-08-14 20:58:27 +08:00
Demod14bInit ( BigBuf_malloc ( MAX_FRAME_SIZE ) , MAX_FRAME_SIZE ) ;
2019-08-08 22:57:33 +08:00
Uart14bInit ( BigBuf_malloc ( MAX_FRAME_SIZE ) ) ;
2016-03-13 14:20:21 +08:00
2019-03-10 03:34:41 +08:00
// connect Demodulated Signal to ADC:
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
2015-07-13 06:04:16 +08:00
2019-03-10 03:34:41 +08:00
// Set up the synchronous serial port
2020-07-14 21:46:05 +08:00
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_READER ) ;
2019-03-09 15:59:13 +08:00
2019-03-10 03:34:41 +08:00
// Signal field is on with the appropriate LED
2023-08-28 18:00:44 +08:00
# ifdef RDV4
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD_RDV4 ) ;
2023-09-08 02:13:18 +08:00
# else
2020-07-04 03:33:17 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD ) ;
2023-09-08 02:13:18 +08:00
# endif
2023-08-28 18:00:44 +08:00
2021-05-07 18:27:13 +08:00
SpinDelay ( 100 ) ;
2015-07-13 06:04:16 +08:00
2019-03-10 03:34:41 +08:00
// Start the timer
StartCountSspClk ( ) ;
2019-03-09 15:59:13 +08:00
2021-04-24 04:25:58 +08:00
// reset timeout
2021-05-07 18:27:13 +08:00
iso14b_set_fwt ( 8 ) ;
2021-04-24 04:25:58 +08:00
2019-03-10 03:34:41 +08:00
LED_D_ON ( ) ;
2015-07-13 06:04:16 +08:00
}
2015-06-02 18:17:34 +08:00
//-----------------------------------------------------------------------------
2015-06-18 15:52:53 +08:00
// Read a SRI512 ISO 14443B tag.
2015-06-02 18:17:34 +08:00
//
// SRI512 tags are just simple memory tags, here we're looking at making a dump
// of the contents of the memory. No anticollision algorithm is done, we assume
// we have a single tag in the field.
//
// I tried to be systematic and check every answer of the tag, every CRC, etc...
//-----------------------------------------------------------------------------
2020-10-28 01:26:14 +08:00
static int read_srx_block ( uint8_t blocknr , uint8_t * block ) {
2020-11-02 08:46:47 +08:00
2020-08-17 03:13:10 +08:00
uint8_t cmd [ ] = { ISO14443B_READ_BLK , blocknr , 0x00 , 0x00 } ;
2019-03-10 03:34:41 +08:00
AddCrc14B ( cmd , 2 ) ;
2020-08-17 03:13:10 +08:00
uint8_t r_block [ 6 ] = { 0 } ;
2020-08-14 20:58:27 +08:00
uint32_t start_time = 0 ;
2020-08-18 04:07:50 +08:00
uint32_t eof_time = 0 ;
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( cmd , sizeof ( cmd ) , & start_time , & eof_time , true ) ;
2020-08-17 03:13:10 +08:00
2021-04-24 04:25:58 +08:00
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
int retlen = Get14443bAnswerFromTag ( r_block , sizeof ( r_block ) , iso14b_timeout , & eof_time ) ;
2020-01-13 17:34:59 +08:00
FpgaDisableTracing ( ) ;
2019-03-10 03:34:41 +08:00
// Check if we got an answer from the tag
2020-08-17 03:13:10 +08:00
if ( retlen ! = 6 ) {
2019-03-10 03:34:41 +08:00
DbpString ( " [!] expected 6 bytes from tag, got less... " ) ;
2020-10-28 01:26:14 +08:00
return PM3_EWRONGANSWER ;
2019-03-10 03:34:41 +08:00
}
// The check the CRC of the answer
2020-10-28 01:26:14 +08:00
if ( check_crc ( CRC_14443_B , r_block , retlen ) = = false ) {
2020-07-04 03:33:17 +08:00
DbpString ( " CRC fail " ) ;
2020-10-28 01:26:14 +08:00
return PM3_ECRC ;
2019-03-10 03:34:41 +08:00
}
2020-08-17 03:13:10 +08:00
if ( block ) {
memcpy ( block , r_block , 4 ) ;
}
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > = DBG_DEBUG ) {
2020-10-28 01:26:14 +08:00
Dbprintf ( " Address=%02x, Contents=%08x, CRC=%04x " ,
2020-11-02 08:46:47 +08:00
blocknr ,
( r_block [ 3 ] < < 24 ) + ( r_block [ 2 ] < < 16 ) + ( r_block [ 1 ] < < 8 ) + r_block [ 0 ] ,
( r_block [ 4 ] < < 8 ) + r_block [ 5 ]
) ;
2020-10-28 01:26:14 +08:00
}
2020-09-07 16:35:09 +08:00
2020-10-28 01:26:14 +08:00
return PM3_SUCCESS ;
2018-08-13 03:54:31 +08:00
}
2020-07-04 03:33:17 +08:00
2020-10-28 01:26:14 +08:00
void ReadSTBlock ( uint8_t blocknr ) {
2019-03-10 03:34:41 +08:00
iso14443b_setup ( ) ;
2020-08-17 03:13:10 +08:00
iso14b_card_select_t card ;
2020-09-26 15:33:36 +08:00
int res = iso14443b_select_srx_card ( & card ) ;
2020-10-28 01:26:14 +08:00
// 0: OK -1 wrong len, -2: attrib fail, -3:crc fail,
2020-11-02 08:46:47 +08:00
switch ( res ) {
2020-10-28 01:26:14 +08:00
case - 1 :
case - 3 : {
reply_ng ( CMD_HF_SRI_READ , PM3_EWRONGANSWER , NULL , 0 ) ;
goto out ;
}
case - 2 : {
reply_ng ( CMD_HF_SRI_READ , PM3_ECRC , NULL , 0 ) ;
goto out ;
2020-08-17 04:47:07 +08:00
}
2019-03-10 03:34:41 +08:00
}
2020-10-28 01:26:14 +08:00
uint8_t * data = BigBuf_malloc ( 4 ) ;
res = read_srx_block ( blocknr , data ) ;
reply_ng ( CMD_HF_SRI_READ , res , data , 4 ) ;
2019-03-09 15:59:13 +08:00
out :
2020-08-17 04:47:07 +08:00
BigBuf_free ( ) ;
switch_off ( ) ;
2015-06-02 18:17:34 +08:00
}
//=============================================================================
// Finally, the `sniffer' combines elements from both the reader and
// simulated tag, to show both sides of the conversation.
//=============================================================================
//-----------------------------------------------------------------------------
// Record the sequence of commands sent by the reader to the tag, with
// triggering so that we start recording at the point that the tag is moved
// near the reader.
//-----------------------------------------------------------------------------
/*
* Memory usage for this function , ( within BigBuf )
2015-06-04 03:12:55 +08:00
* Last Received command ( reader - > tag ) - MAX_FRAME_SIZE
* Last Received command ( tag - > reader ) - MAX_FRAME_SIZE
2015-06-23 03:45:28 +08:00
* DMA Buffer - ISO14443B_DMA_BUFFER_SIZE
2015-06-04 03:12:55 +08:00
* Demodulated samples received - all the rest
2015-06-02 18:17:34 +08:00
*/
2020-08-14 20:58:27 +08:00
void SniffIso14443b ( void ) {
2016-04-27 03:29:45 +08:00
2020-08-14 20:58:27 +08:00
LEDsoff ( ) ;
LED_A_ON ( ) ;
2016-08-08 00:49:36 +08:00
2020-08-14 20:58:27 +08:00
FpgaDownloadAndGo ( FPGA_BITSTREAM_HF ) ;
2016-04-27 03:29:45 +08:00
2020-08-14 20:58:27 +08:00
DbpString ( " Starting to sniff. Press PM3 Button to stop. " ) ;
2020-07-04 03:33:17 +08:00
2020-08-14 20:58:27 +08:00
BigBuf_free ( ) ;
clear_trace ( ) ;
set_tracing ( true ) ;
// Initialize Demod and Uart structs
uint8_t dm_buf [ MAX_FRAME_SIZE ] = { 0 } ;
Demod14bInit ( dm_buf , sizeof ( dm_buf ) ) ;
uint8_t ua_buf [ MAX_FRAME_SIZE ] = { 0 } ;
Uart14bInit ( ua_buf ) ;
//Demod14bInit(BigBuf_malloc(MAX_FRAME_SIZE), MAX_FRAME_SIZE);
//Uart14bInit(BigBuf_malloc(MAX_FRAME_SIZE));
2016-04-27 03:29:45 +08:00
2020-08-14 20:58:27 +08:00
// Set FPGA in the appropriate mode
2020-08-17 03:13:10 +08:00
FpgaWriteConfWord ( FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_SNIFF_IQ ) ;
// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_SNIFF_AMPLITUDE);
2020-08-14 20:58:27 +08:00
// connect Demodulated Signal to ADC:
SetAdcMuxFor ( GPIO_MUXSEL_HIPKD ) ;
FpgaSetupSsc ( FPGA_MAJOR_MODE_HF_READER ) ;
StartCountSspClk ( ) ;
2020-07-15 21:16:35 +08:00
// The DMA buffer, used to stream samples from the FPGA
dmabuf16_t * dma = get_dma16 ( ) ;
2019-03-10 03:34:41 +08:00
// Setup and start DMA.
2020-07-15 21:16:35 +08:00
if ( ! FpgaSetupSscDma ( ( uint8_t * ) dma - > buf , DMA_BUFFER_SIZE ) ) {
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > DBG_ERROR ) DbpString ( " FpgaSetupSscDma failed. Exiting " ) ;
2020-08-14 20:58:27 +08:00
switch_off ( ) ;
2019-03-10 03:34:41 +08:00
return ;
}
2017-08-28 01:41:24 +08:00
2020-08-14 20:58:27 +08:00
// We won't start recording the frames that we acquire until we trigger;
// a good trigger condition to get started is probably when we see a
// response from the tag.
bool tag_is_active = false ;
bool reader_is_active = false ;
bool expect_tag_answer = false ;
int dma_start_time = 0 ;
2020-09-07 16:35:09 +08:00
2020-08-14 20:58:27 +08:00
// Count of samples received so far, so that we can include timing
int samples = 0 ;
uint16_t * upTo = dma - > buf ;
2019-03-09 15:59:13 +08:00
2020-08-13 18:25:04 +08:00
for ( ; ; ) {
2020-07-04 03:33:17 +08:00
2020-08-14 20:58:27 +08:00
volatile int behind_by = ( ( uint16_t * ) AT91C_BASE_PDC_SSC - > PDC_RPR - upTo ) & ( DMA_BUFFER_SIZE - 1 ) ;
2020-09-07 16:35:09 +08:00
if ( behind_by < 1 ) continue ;
2020-08-14 20:58:27 +08:00
samples + + ;
if ( samples = = 1 ) {
// DMA has transferred the very first data
dma_start_time = GetCountSspClk ( ) & 0xfffffff0 ;
2020-07-14 21:46:05 +08:00
}
2020-07-04 03:33:17 +08:00
2020-08-17 03:13:10 +08:00
volatile int8_t ci = * upTo > > 8 ;
volatile int8_t cq = * upTo ;
2020-09-07 16:35:09 +08:00
upTo + + ;
2020-07-04 03:33:17 +08:00
2020-08-14 20:58:27 +08:00
// we have read all of the DMA buffer content.
if ( upTo > = dma - > buf + DMA_BUFFER_SIZE ) {
2020-07-15 21:16:35 +08:00
2020-08-14 20:58:27 +08:00
// start reading the circular buffer from the beginning again
upTo = dma - > buf ;
2020-07-04 03:33:17 +08:00
2020-08-14 20:58:27 +08:00
// DMA Counter Register had reached 0, already rotated.
if ( AT91C_BASE_SSC - > SSC_SR & ( AT91C_SSC_ENDRX ) ) {
2020-07-04 03:33:17 +08:00
2020-08-14 20:58:27 +08:00
// primary buffer was stopped
if ( AT91C_BASE_PDC_SSC - > PDC_RCR = = false ) {
AT91C_BASE_PDC_SSC - > PDC_RPR = ( uint32_t ) dma - > buf ;
AT91C_BASE_PDC_SSC - > PDC_RCR = DMA_BUFFER_SIZE ;
}
// secondary buffer sets as primary, secondary buffer was stopped
if ( AT91C_BASE_PDC_SSC - > PDC_RNCR = = false ) {
AT91C_BASE_PDC_SSC - > PDC_RNPR = ( uint32_t ) dma - > buf ;
AT91C_BASE_PDC_SSC - > PDC_RNCR = DMA_BUFFER_SIZE ;
}
2020-09-07 16:35:09 +08:00
2020-08-14 20:58:27 +08:00
WDT_HIT ( ) ;
if ( BUTTON_PRESS ( ) ) {
DbpString ( " Sniff stopped " ) ;
break ;
}
2020-07-14 21:46:05 +08:00
}
}
2020-07-04 03:33:17 +08:00
2019-03-10 03:34:41 +08:00
// no need to try decoding reader data if the tag is sending
2020-08-14 20:58:27 +08:00
if ( tag_is_active = = false ) {
2020-08-17 03:13:10 +08:00
if ( Handle14443bSampleFromReader ( ci & 0x01 ) ) {
2020-08-14 20:58:27 +08:00
uint32_t eof_time = dma_start_time + ( samples * 16 ) + 8 ; // - DELAY_READER_TO_ARM_SNIFF; // end of EOF
if ( Uart . byteCnt > 0 ) {
uint32_t sof_time = eof_time
- Uart . byteCnt * 1 // time for byte transfers
- 32 * 16 // time for SOF transfer
- 16 * 16 ; // time for EOF transfer
LogTrace ( Uart . output , Uart . byteCnt , ( sof_time * 4 ) , ( eof_time * 4 ) , NULL , true ) ;
}
// And ready to receive another command.
2019-08-08 22:57:33 +08:00
Uart14bReset ( ) ;
Demod14bReset ( ) ;
2020-09-07 16:35:09 +08:00
expect_tag_answer = true ;
2019-03-10 03:34:41 +08:00
}
2020-08-17 03:13:10 +08:00
if ( Handle14443bSampleFromReader ( cq & 0x01 ) ) {
2020-08-14 20:58:27 +08:00
uint32_t eof_time = dma_start_time + ( samples * 16 ) + 16 ; // - DELAY_READER_TO_ARM_SNIFF; // end of EOF
if ( Uart . byteCnt > 0 ) {
uint32_t sof_time = eof_time
- Uart . byteCnt * 1 // time for byte transfers
- 32 * 16 // time for SOF transfer
- 16 * 16 ; // time for EOF transfer
LogTrace ( Uart . output , Uart . byteCnt , ( sof_time * 4 ) , ( eof_time * 4 ) , NULL , true ) ;
}
// And ready to receive another command
2019-08-08 22:57:33 +08:00
Uart14bReset ( ) ;
Demod14bReset ( ) ;
2020-08-14 20:58:27 +08:00
expect_tag_answer = true ;
2019-03-10 03:34:41 +08:00
}
2020-09-07 16:35:09 +08:00
2020-08-14 20:58:27 +08:00
reader_is_active = ( Uart . state > STATE_14B_GOT_FALLING_EDGE_OF_SOF ) ;
2019-03-10 03:34:41 +08:00
}
// no need to try decoding tag data if the reader is sending - and we cannot afford the time
2020-08-14 20:58:27 +08:00
if ( reader_is_active = = false & & expect_tag_answer ) {
2020-09-07 16:35:09 +08:00
if ( Handle14443bSamplesFromTag ( ( ci > > 1 ) , ( cq > > 1 ) ) ) {
2020-08-14 20:58:27 +08:00
2020-09-07 16:35:09 +08:00
uint32_t eof_time = dma_start_time + ( samples * 16 ) ; // - DELAY_TAG_TO_ARM_SNIFF; // end of EOF
2020-08-14 20:58:27 +08:00
uint32_t sof_time = eof_time
2020-09-07 16:35:09 +08:00
- Demod . len * 8 * 8 * 16 // time for byte transfers
- ( 32 * 16 ) // time for SOF transfer
- 0 ; // time for EOF transfer
2019-03-10 03:34:41 +08:00
2020-08-14 20:58:27 +08:00
LogTrace ( Demod . output , Demod . len , ( sof_time * 4 ) , ( eof_time * 4 ) , NULL , false ) ;
// And ready to receive another response.
2019-08-08 22:57:33 +08:00
Uart14bReset ( ) ;
Demod14bReset ( ) ;
2020-08-14 20:58:27 +08:00
expect_tag_answer = false ;
tag_is_active = false ;
2019-03-10 03:34:41 +08:00
} else {
2020-10-01 08:14:49 +08:00
tag_is_active = ( Demod . state > WAIT_FOR_RISING_EDGE_OF_SOF ) ;
2019-03-10 03:34:41 +08:00
}
}
}
2020-08-14 20:58:27 +08:00
FpgaDisableTracing ( ) ;
2019-03-10 03:34:41 +08:00
switch_off ( ) ;
2020-08-14 20:58:27 +08:00
DbpString ( " " ) ;
DbpString ( _CYAN_ ( " Sniff statistics " ) ) ;
DbpString ( " ================================= " ) ;
Dbprintf ( " DecodeTag State........%d " , Demod . state ) ;
Dbprintf ( " DecodeTag byteCnt......%d " , Demod . len ) ;
Dbprintf ( " DecodeTag posCount.....%d " , Demod . posCount ) ;
Dbprintf ( " DecodeReader State.....%d " , Uart . state ) ;
Dbprintf ( " DecodeReader byteCnt...%d " , Uart . byteCnt ) ;
2020-09-07 16:35:09 +08:00
Dbprintf ( " DecodeReader posCount..%d " , Uart . posCnt ) ;
2020-08-14 20:58:27 +08:00
Dbprintf ( " Trace length........... " _YELLOW_ ( " %d " ) , BigBuf_get_traceLen ( ) ) ;
DbpString ( " " ) ;
2015-06-02 18:17:34 +08:00
}
2020-05-10 22:59:38 +08:00
static void iso14b_set_trigger ( bool enable ) {
2020-05-19 23:05:43 +08:00
g_trigger = enable ;
2016-03-21 02:33:07 +08:00
}
2015-06-02 18:17:34 +08:00
2021-05-07 18:27:13 +08:00
void SendRawCommand14443B_Ex ( iso14b_raw_cmd_t * p ) {
2020-07-04 03:33:17 +08:00
2021-04-22 00:36:21 +08:00
// receive buffer
uint8_t buf [ PM3_CMD_DATA_SIZE ] ;
2021-05-06 03:04:48 +08:00
memset ( buf , 0 , sizeof ( buf ) ) ;
2021-08-22 05:02:27 +08:00
if ( g_dbglevel > DBG_DEBUG ) {
2021-05-07 18:27:13 +08:00
Dbprintf ( " 14b raw: param, %04x " , p - > flags ) ;
2021-04-22 00:36:21 +08:00
}
2019-03-10 03:34:41 +08:00
// turn on trigger (LED_A)
2021-05-07 18:27:13 +08:00
if ( ( p - > flags & ISO14B_REQUEST_TRIGGER ) = = ISO14B_REQUEST_TRIGGER )
2019-03-10 03:34:41 +08:00
iso14b_set_trigger ( true ) ;
2021-05-07 18:27:13 +08:00
if ( ( p - > flags & ISO14B_CONNECT ) = = ISO14B_CONNECT ) {
2019-03-10 03:34:41 +08:00
iso14443b_setup ( ) ;
}
2019-03-14 19:30:32 +08:00
2021-05-07 18:27:13 +08:00
if ( ( p - > flags & ISO14B_SET_TIMEOUT ) = = ISO14B_SET_TIMEOUT ) {
iso14b_set_timeout ( p - > timeout ) ;
2020-10-05 16:02:32 +08:00
}
2020-10-07 00:41:15 +08:00
2021-05-07 18:27:13 +08:00
if ( ( p - > flags & ISO14B_CLEARTRACE ) = = ISO14B_CLEARTRACE ) {
2020-10-05 16:02:32 +08:00
clear_trace ( ) ;
2023-08-28 23:59:48 +08:00
BigBuf_Clear_ext ( false ) ;
2020-10-05 16:02:32 +08:00
}
2019-03-10 03:34:41 +08:00
set_tracing ( true ) ;
2020-08-17 03:13:10 +08:00
int status ;
uint32_t sendlen = sizeof ( iso14b_card_select_t ) ;
iso14b_card_select_t card ;
2020-10-07 00:41:15 +08:00
memset ( ( void * ) & card , 0x00 , sizeof ( card ) ) ;
2020-09-07 16:35:09 +08:00
2021-05-07 18:27:13 +08:00
if ( ( p - > flags & ISO14B_SELECT_STD ) = = ISO14B_SELECT_STD ) {
2020-08-17 03:13:10 +08:00
status = iso14443b_select_card ( & card ) ;
2020-09-07 16:35:09 +08:00
reply_mix ( CMD_HF_ISO14443B_COMMAND , status , sendlen , 0 , ( uint8_t * ) & card , sendlen ) ;
2020-07-04 03:33:17 +08:00
// 0: OK -1: attrib fail, -2:crc fail,
if ( status ! = 0 ) goto out ;
2019-03-10 03:34:41 +08:00
}
2021-05-07 18:27:13 +08:00
if ( ( p - > flags & ISO14B_SELECT_SR ) = = ISO14B_SELECT_SR ) {
2020-08-17 03:13:10 +08:00
status = iso14443b_select_srx_card ( & card ) ;
2020-09-07 16:35:09 +08:00
reply_mix ( CMD_HF_ISO14443B_COMMAND , status , sendlen , 0 , ( uint8_t * ) & card , sendlen ) ;
2019-03-10 03:34:41 +08:00
// 0: OK 2: demod fail, 3:crc fail,
2019-03-10 07:00:59 +08:00
if ( status > 0 ) goto out ;
2019-03-10 03:34:41 +08:00
}
2021-05-07 18:27:13 +08:00
if ( ( p - > flags & ISO14B_SELECT_CTS ) = = ISO14B_SELECT_CTS ) {
2020-10-02 20:31:52 +08:00
iso14b_cts_card_select_t cts ;
sendlen = sizeof ( iso14b_cts_card_select_t ) ;
status = iso14443b_select_cts_card ( & cts ) ;
reply_mix ( CMD_HF_ISO14443B_COMMAND , status , sendlen , 0 , ( uint8_t * ) & cts , sendlen ) ;
// 0: OK 2: demod fail, 3:crc fail,
if ( status > 0 ) goto out ;
2020-10-07 00:41:15 +08:00
}
2020-10-02 20:31:52 +08:00
2022-07-01 04:50:52 +08:00
if ( ( p - > flags & ISO14B_SELECT_XRX ) = = ISO14B_SELECT_XRX ) {
status = iso14443b_select_xrx_card ( & card ) ;
reply_mix ( CMD_HF_ISO14443B_COMMAND , status , sendlen , 0 , ( uint8_t * ) & card , sendlen ) ;
// 0: OK, 1: select fail, 2: attrib fail, 3: crc fail, 4: password fail
if ( status ! = 0 ) goto out ;
}
2021-05-07 18:27:13 +08:00
if ( ( p - > flags & ISO14B_APDU ) = = ISO14B_APDU ) {
2020-10-04 01:08:27 +08:00
uint8_t res ;
2021-05-07 18:27:13 +08:00
status = iso14443b_apdu ( p - > raw , p - > rawlen , ( p - > flags & ISO14B_SEND_CHAINING ) , buf , sizeof ( buf ) , & res ) ;
2020-10-01 01:20:40 +08:00
sendlen = MIN ( Demod . len , PM3_CMD_DATA_SIZE ) ;
2020-10-04 01:08:27 +08:00
reply_mix ( CMD_HF_ISO14443B_COMMAND , status , res , 0 , buf , sendlen ) ;
2019-03-10 03:34:41 +08:00
}
2021-05-07 18:27:13 +08:00
if ( ( p - > flags & ISO14B_RAW ) = = ISO14B_RAW ) {
if ( ( p - > flags & ISO14B_APPEND_CRC ) = = ISO14B_APPEND_CRC ) {
if ( p - > rawlen > 0 ) {
AddCrc14B ( p - > raw , p - > rawlen ) ;
p - > rawlen + = 2 ;
2021-04-22 00:36:21 +08:00
}
2019-03-10 03:34:41 +08:00
}
2020-08-14 20:58:27 +08:00
uint32_t start_time = 0 ;
2020-08-18 04:07:50 +08:00
uint32_t eof_time = 0 ;
2022-07-01 04:50:52 +08:00
CodeAndTransmit14443bAsReader ( p - > raw , p - > rawlen , & start_time , & eof_time , true ) ;
2020-08-17 03:13:10 +08:00
2021-03-08 06:43:53 +08:00
if ( tearoff_hook ( ) = = PM3_ETEAROFF ) { // tearoff occurred
2020-10-13 22:09:17 +08:00
FpgaDisableTracing ( ) ;
reply_mix ( CMD_HF_ISO14443B_COMMAND , - 2 , 0 , 0 , NULL , 0 ) ;
} else {
2021-04-24 04:25:58 +08:00
eof_time + = DELAY_ISO14443B_PCD_TO_PICC_READER ;
status = Get14443bAnswerFromTag ( buf , sizeof ( buf ) , iso14b_timeout , & eof_time ) ; // raw
2020-10-13 22:09:17 +08:00
FpgaDisableTracing ( ) ;
2019-03-10 03:34:41 +08:00
2020-10-13 22:09:17 +08:00
sendlen = MIN ( Demod . len , PM3_CMD_DATA_SIZE ) ;
reply_mix ( CMD_HF_ISO14443B_COMMAND , status , sendlen , 0 , Demod . output , sendlen ) ;
}
2019-03-10 03:34:41 +08:00
}
2019-03-09 15:59:13 +08:00
out :
2019-03-10 03:34:41 +08:00
// turn off trigger (LED_A)
2021-05-07 18:27:13 +08:00
if ( ( p - > flags & ISO14B_REQUEST_TRIGGER ) = = ISO14B_REQUEST_TRIGGER )
2019-03-10 03:34:41 +08:00
iso14b_set_trigger ( false ) ;
// turn off antenna et al
// we don't send a HALT command.
2021-05-07 18:27:13 +08:00
if ( ( p - > flags & ISO14B_DISCONNECT ) = = ISO14B_DISCONNECT ) {
2019-03-10 03:34:41 +08:00
switch_off ( ) ; // disconnect raw
SpinDelay ( 20 ) ;
}
2019-03-12 07:12:26 +08:00
}