added: hf 14b apdu

This commit is contained in:
iceman1001 2020-09-30 17:06:19 +02:00
commit 181bb3bc74
4 changed files with 483 additions and 93 deletions

View file

@ -41,15 +41,18 @@
// defaults to 2000ms
#ifndef FWT_TIMEOUT_14B
# define FWT_TIMEOUT_14B 35312
# define FWT_TIMEOUT_14B 35312
#endif
// 1 tick == 1/13.56 mhz
// 1 us = 1.5 tick
// 330/848kHz = 1558us / 4 == 400us,
#define ISO14443B_READER_TIMEOUT 1700 //330
#define ISO14443B_READER_TIMEOUT 10000 //330
// 1024/3.39MHz = 302.1us between end of tag response and next reader cmd
#define DELAY_ISO14443B_VICC_TO_VCD_READER 600 // 1024
#define DELAY_ISO14443B_VCD_TO_VICC_READER 600// 1056
#define DELAY_ISO14443B_VICC_TO_VCD_READER (28*9) // 1024 ( counting from start of PICC EOF 14 ETU's)
#define DELAY_ISO14443B_VCD_TO_VICC_READER (28*9) // 1056
#ifndef RECEIVE_MASK
# define RECEIVE_MASK (DMA_BUFFER_SIZE - 1)
@ -57,7 +60,7 @@
// Guard Time (per 14443-2)
#ifndef TR0
# define TR0 64 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA
# define TR0 32 // TR0 max is 151/fs = 151/(848kHz) = 302us or 64 samples from FPGA
#endif
// Synchronization time (per 14443-2)
@ -76,10 +79,9 @@ static void iso14b_set_timeout(uint32_t timeout);
static void iso14b_set_maxframesize(uint16_t size);
// the block number for the ISO14443-4 PCB (used with APDUs)
static uint8_t pcb_blocknum = 0;
static uint8_t iso14b_pcb_blocknum = 0;
static uint32_t iso14b_timeout = FWT_TIMEOUT_14B;
/* ISO 14443 B
*
* Reader to card | ASK - Amplitude Shift Keying Modulation (PCD to PICC for Type B) (NRZ-L encodig)
@ -306,7 +308,6 @@ static void Demod14bInit(uint8_t *data, uint16_t max_len) {
Demod14bReset();
}
/*
* 9.4395 us = 1 ETU and clock is about 1.5 us
* 13560000Hz
@ -740,7 +741,7 @@ void SimulateIso14443bTag(uint32_t pupi) {
*/
static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
int v;
int v = 0;
// The soft decision on the bit uses an estimate of just the
// quadrant of the reference angle, not the exact angle.
@ -757,7 +758,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
} \
}
#define SUBCARRIER_DETECT_THRESHOLD 8
#define SUBCARRIER_DETECT_THRESHOLD 8
// 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))
@ -797,7 +798,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;
Demod.posCount = 0; // start of SOF sequence
} else {
if (Demod.posCount > 200 / 4) { // maximum length of TR1 = 200 1/fs
if (Demod.posCount > 200/4) { // maximum length of TR1 = 200 1/fs
Demod.state = DEMOD_UNSYNCD;
}
}
@ -820,7 +821,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
Demod.state = DEMOD_AWAITING_START_BIT;
}
} else {
if (Demod.posCount > 14 * 2) { // low phase of SOF too long (> 12 etu)
if (Demod.posCount > 12 * 2) { // low phase of SOF too long (> 12 etu)
Demod.state = DEMOD_UNSYNCD;
LED_C_OFF();
}
@ -831,7 +832,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
Demod.posCount++;
MAKE_SOFT_DECISION();
if (v > 0) {
if (Demod.posCount > 6 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs
if (Demod.posCount > 3 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs
LED_C_OFF();
if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass
return true;
@ -873,7 +874,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
Demod.bitCount = 0;
Demod.state = DEMOD_AWAITING_START_BIT;
} else {
Demod.state = DEMOD_UNSYNCD;
Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;
LED_C_OFF();
if (s == 0x000) {
// This is EOF (start, stop and all data bits == '0'
@ -894,23 +895,16 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
return false;
}
/*
* Demodulate the samples we received from the tag, also log to tracebuffer
*/
static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeout, uint32_t *eof_time) {
int samples = 0, ret = 0;
// Set up the demodulator for tag -> reader responses.
Demod14bInit(response, max_len);
// wait for last transfer to complete
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) {};
// And put the FPGA in the appropriate mode
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ);
// Setup and start DMA.
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
@ -924,6 +918,9 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
uint32_t dma_start_time = 0;
uint16_t *upTo = dma->buf;
// Put FPGA in the appropriate mode
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ);
for (;;) {
volatile uint16_t behindBy = ((uint16_t *)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1);
@ -971,7 +968,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
if (Handle14443bSamplesFromTag(ci, cq)) {
*eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM; // end of EOF
*eof_time = dma_start_time + (samples ) - DELAY_TAG_TO_ARM; // end of EOF
if (Demod.len > Demod.max_len) {
ret = -2; // overflow
@ -986,19 +983,17 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
}
FpgaDisableSscDma();
if (ret < 0) {
return ret;
}
if (Demod.len > 0) {
uint32_t sof_time = *eof_time
- (Demod.len * 8 * 8 * 16) // time for byte transfers
- (32 * 16) // time for SOF transfer
- 0; // time for EOF transfer
- (Demod.len * (8 + 2)) // time for byte transfers
- (12) // time for SOF transfer
- (12); // time for EOF transfer
LogTrace(Demod.output, Demod.len, (sof_time * 4), (*eof_time * 4), NULL, false);
}
return Demod.len;
}
@ -1011,6 +1006,7 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD);
// TR2 minimum 14 ETUs
if (*start_time < DELAY_ARM_TO_TAG) {
*start_time = DELAY_ARM_TO_TAG;
}
@ -1018,21 +1014,20 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) {
*start_time = (*start_time - DELAY_ARM_TO_TAG) & 0xfffffff0;
if (GetCountSspClk() > *start_time) { // we may miss the intended time
*start_time = (GetCountSspClk() + 16) & 0xfffffff0; // next possible time
*start_time = (GetCountSspClk() + 32) & 0xfffffff0; // next possible time
}
// wait
while (GetCountSspClk() < *start_time) ;
while (GetCountSspClk() < *start_time);
LED_B_ON();
for (int c = 0; c < ts->max; c++) {
volatile uint8_t data = ts->buf[c];
for (int i = 0; i < 8; i++) {
uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff;
for (uint8_t i = 0; i < 8; 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))) ;
@ -1045,6 +1040,9 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) {
LED_B_OFF();
*start_time += DELAY_ARM_TO_TAG;
// wait for last transfer to complete
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) {};
}
//-----------------------------------------------------------------------------
@ -1061,32 +1059,38 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) {
* - no modulation ONES
*
* 1 ETU == 1 BIT!
* TR0 - 8 ETUS minimum.
* TR0 - 8 ETU's minimum.
* TR0 - 32 ETU's maximum for ATQB only
* TR0 - FWT for all other commands
*
* QUESTION: how long is a 1 or 0 in pulses in the xcorr_848 mode?
* 1 "stuffbit" = 1ETU (9us)
*
* 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
*
*/
int i;
tosend_reset();
// Send SOF
// 10-11 ETUs of ZERO
for (int i = 0; i < 10; i++)
for (i = 0; i < 10; i++) {
tosend_stuffbit(0);
}
// 2-3 ETUs of ONE
tosend_stuffbit(1);
tosend_stuffbit(1);
// Sending cmd, LSB
// from here we add BITS
for (int i = 0; i < len; i++) {
for (i = 0; i < len; i++) {
// Start bit
tosend_stuffbit(0);
// Data bits
uint8_t b = cmd[i];
// Data bits
volatile uint8_t b = cmd[i];
tosend_stuffbit(b & 1);
tosend_stuffbit((b >> 1) & 1);
tosend_stuffbit((b >> 2) & 1);
@ -1098,28 +1102,28 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) {
// Stop bit
tosend_stuffbit(1);
// EGT extra guard time
// For PCD it ranges 0-57us (1etu = 9us)
// tosend_stuffbit(1);
// tosend_stuffbit(1);
// tosend_stuffbit(1);
// 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
}
// Send EOF
// 10-11 ETUs of ZERO
for (int i = 0; i < 10; i++)
for (i = 0; i < 10; i++) {
tosend_stuffbit(0);
}
// Transition time. TR0 - guard time
// 8ETUS minum?
// Per specification, Subcarrier must be stopped no later than 2 ETUs after EOF.
// I'm guessing this is for the FPGA to be able to send all bits before we switch to listening mode
tosend_stuffbit(1);
/* 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
*/
// ensure that last byte is filled up
for (int i = 0; i < 8 ; ++i)
for (i = 0; i < 8 ; ++i)
tosend_stuffbit(1);
// TR1 - Synchronization time
// Convert from last character reference to length
tosend_t *ts = get_tosend();
ts->max++;
@ -1132,54 +1136,100 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t
tosend_t *ts = get_tosend();
CodeIso14443bAsReader(cmd, len);
TransmitFor14443b_AsReader(start_time);
*eof_time = *start_time + (32 * (8 * ts->max));
*eof_time = *start_time + (10 * ts->max) + 10 + 2 + 10;
LogTrace(cmd, len, *start_time, *eof_time, NULL, true);
}
/* Sends an APDU to the tag
* TODO: check CRC and preamble
*/
int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response, uint16_t respmaxlen) {
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, uint8_t *response, uint16_t respmaxlen) {
LED_A_ON();
uint8_t message_frame[message_length + 4];
// PCB
message_frame[0] = 0x0A | pcb_blocknum;
pcb_blocknum ^= 1;
// CID
message_frame[1] = 0;
// INF
memcpy(message_frame + 2, message, message_length);
// EDC (CRC)
AddCrc14B(message_frame, message_length + 2);
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;
}
AddCrc14B(real_cmd, msg_len + 1);
// send
uint32_t start_time = 0;
uint32_t eof_time = 0;
CodeAndTransmit14443bAsReader(message_frame, sizeof(message_frame), &start_time, &eof_time);
// Get response?
if (response == NULL) {
LED_A_OFF();
return 0;
}
CodeAndTransmit14443bAsReader(real_cmd, msg_len + 3, &start_time, &eof_time);
eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER;
int retlen = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time);
int len = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time);
FpgaDisableTracing();
if (retlen < 3) {
LED_A_OFF();
return -1;
uint8_t *data_bytes = (uint8_t *) response;
if (len <= 0) {
return 0; //DATA LINK ERROR
} else {
// S-Block WTX
while (len && ((data_bytes[0] & 0xF2) == 0xF2)) {
uint32_t save_iso14b_timeout = iso14b_timeout;
// temporarily increase timeout
iso14b_set_timeout(MAX((data_bytes[1] & 0x3f) * save_iso14b_timeout, ISO14443B_READER_TIMEOUT));
// Transmit WTX back
// byte1 - WTXM [1..59]. command FWT=FWT*WTXM
data_bytes[1] = data_bytes[1] & 0x3f; // 2 high bits mandatory set to 0b
// now need to fix CRC.
AddCrc14B(data_bytes, len - 2);
// transmit S-Block
CodeAndTransmit14443bAsReader(data_bytes, len, &start_time, &eof_time);
// retrieve the result again (with increased timeout)
eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER;
len = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time);
FpgaDisableTracing();
data_bytes = response;
// restore timeout
iso14b_set_timeout(save_iso14b_timeout);
}
// if we received an I- or R(ACK)-Block with a block number equal to the
// current block number, toggle the current block number
if (len >= 3 // PCB+CRC = 3 bytes
&& ((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
if (response)
*response = data_bytes[0];
// crc check
if (len >= 3 && !check_crc(CRC_14443_B, data_bytes, len)) {
return -1;
}
}
// VALIDATE CRC
if (!check_crc(CRC_14443_B, response, retlen)) {
if (DBGLEVEL > DBG_DEBUG) DbpString("CRC fail");
return -2;
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];
}
return retlen;
return len;
}
/**
@ -1272,7 +1322,10 @@ static int iso14443b_select_srx_card(iso14b_card_select_t *card) {
int iso14443b_select_card(iso14b_card_select_t *card) {
// WUPB command (including CRC)
// Note: WUPB wakes up all tags, REQB doesn't wake up tags in HALT state
static const uint8_t wupb[] = { ISO14443B_REQB, 0x00, 0x08, 0x39, 0x73 };
// 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 };
// ATTRIB command (with space for CRC)
uint8_t attrib[] = { ISO14443B_ATTRIB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00};
@ -1350,7 +1403,7 @@ int iso14443b_select_card(iso14b_card_select_t *card) {
}
}
// reset PCB block number
pcb_blocknum = 0;
iso14b_pcb_blocknum = 0;
return 0;
}
@ -1720,7 +1773,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
if ((param & ISO14B_APDU) == ISO14B_APDU) {
uint8_t buf[100] = {0};
status = iso14443b_apdu(cmd, len, buf, sizeof(buf));
status = iso14443b_apdu(cmd, len, (param & ISO14A_SEND_CHAINING), buf, sizeof(buf));
reply_mix(CMD_HF_ISO14443B_COMMAND, status, status, 0, buf, status);
}