From 67ac4bf75c6953cae546159acd3e887d757bd0c3 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 2 Jun 2015 07:22:23 +0200 Subject: [PATCH 1/9] fix issue #103: revert type change. Samples from FPGA are signed. Renamed iso14443.c to iso14443b.c --- armsrc/Makefile | 2 +- armsrc/{iso14443.c => iso14443b.c} | 34 +++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 11 deletions(-) rename armsrc/{iso14443.c => iso14443b.c} (98%) diff --git a/armsrc/Makefile b/armsrc/Makefile index 899b0307..502ab958 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -17,7 +17,7 @@ APP_CFLAGS = -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ SRC_LF = lfops.c hitag2.c lfsampling.c SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c -SRC_ISO14443b = iso14443.c +SRC_ISO14443b = iso14443b.c SRC_CRAPTO1 = crapto1.c crypto1.c des.c aes.c SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c diff --git a/armsrc/iso14443.c b/armsrc/iso14443b.c similarity index 98% rename from armsrc/iso14443.c rename to armsrc/iso14443b.c index c202e312..8add8f9c 100644 --- a/armsrc/iso14443.c +++ b/armsrc/iso14443b.c @@ -619,6 +619,8 @@ static RAMFUNC int Handle14443SamplesDemod(int ci, int cq) if (Demod.state == DEMOD_UNSYNCD) LED_C_OFF(); // Not synchronized... return FALSE; } + + static void DemodReset() { // Clear out the state of the "UART" that receives from the tag. @@ -626,12 +628,15 @@ static void DemodReset() Demod.state = DEMOD_UNSYNCD; memset(Demod.output, 0x00, MAX_FRAME_SIZE); } + + static void DemodInit(uint8_t *data) { Demod.output = data; DemodReset(); } + static void UartReset() { Uart.byteCntMax = MAX_FRAME_SIZE; @@ -639,12 +644,15 @@ static void UartReset() Uart.byteCnt = 0; Uart.bitCnt = 0; } + + static void UartInit(uint8_t *data) { Uart.output = data; UartReset(); } + /* * Demodulate the samples we received from the tag, also log to tracebuffer * weTx: set to 'TRUE' if we behave like a reader @@ -665,15 +673,15 @@ static void GetSamplesFor14443Demod(int weTx, int n, int quiet) uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE); // The DMA buffer, used to stream samples from the FPGA - uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); + int8_t *dmaBuf = (int8_t*) BigBuf_malloc(DMA_BUFFER_SIZE); // Set up the demodulator for tag -> reader responses. DemodInit(receivedResponse); // Setup and start DMA. - FpgaSetupSscDma(dmaBuf, DMA_BUFFER_SIZE); + FpgaSetupSscDma((uint8_t*) dmaBuf, DMA_BUFFER_SIZE); - uint8_t *upTo= dmaBuf; + int8_t *upTo = dmaBuf; lastRxCounter = DMA_BUFFER_SIZE; // Signal field is ON with the appropriate LED: @@ -724,6 +732,7 @@ static void GetSamplesFor14443Demod(int weTx, int n, int quiet) } } + //----------------------------------------------------------------------------- // Read the tag's response. We just receive a stream of slightly-processed // samples from the FPGA, which we will later do some signal processing on, @@ -756,6 +765,7 @@ static void GetSamplesFor14443Demod(int weTx, int n, int quiet) } }*/ + //----------------------------------------------------------------------------- // Transmit the command (to the tag) that was placed in ToSend[]. //----------------------------------------------------------------------------- @@ -806,6 +816,7 @@ static void TransmitFor14443(void) LED_B_OFF(); // Finished sending } + //----------------------------------------------------------------------------- // Code a layer 2 command (string of octets, including CRC) into ToSend[], // so that it is ready to transmit to the tag using TransmitFor14443(). @@ -862,6 +873,7 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) ToSendMax++; } + //----------------------------------------------------------------------------- // Read an ISO 14443 tag. We send it some set of commands, and record the // responses. @@ -877,6 +889,7 @@ void AcquireRawAdcSamplesIso14443(uint32_t parameter) SendRawCommand14443B(sizeof(cmd1),1,1,cmd1); } + /** Convenience function to encode, transmit and trace iso 14443b comms **/ @@ -891,6 +904,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) } } + //----------------------------------------------------------------------------- // Read a SRI512 ISO 14443 tag. // @@ -1059,9 +1073,9 @@ void RAMFUNC SnoopIso14443(void) set_tracing(TRUE); // The DMA buffer, used to stream samples from the FPGA - uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); + int8_t *dmaBuf = (int8_t*) BigBuf_malloc(DMA_BUFFER_SIZE); int lastRxCounter; - uint8_t *upTo; + int8_t *upTo; int ci, cq; int maxBehindBy = 0; @@ -1092,7 +1106,7 @@ void RAMFUNC SnoopIso14443(void) FpgaSetupSsc(); upTo = dmaBuf; lastRxCounter = DMA_BUFFER_SIZE; - FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); + FpgaSetupSscDma((uint8_t*) dmaBuf, DMA_BUFFER_SIZE); uint8_t parity[MAX_PARITY_SIZE]; LED_A_ON(); @@ -1138,7 +1152,7 @@ void RAMFUNC SnoopIso14443(void) if(Handle14443UartBit(cq & 1)) { if(triggered && tracing) { GetParity(Uart.output, Uart.byteCnt, parity); - LogTrace(Uart.output,Uart.byteCnt,samples, samples,parity,TRUE); + LogTrace(Uart.output,Uart.byteCnt,samples, samples, parity, TRUE); } if(Uart.byteCnt==0) Dbprintf("[2] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt); @@ -1156,7 +1170,7 @@ void RAMFUNC SnoopIso14443(void) { uint8_t parity[MAX_PARITY_SIZE]; GetParity(Demod.output, Demod.len, parity); - LogTrace(Demod.output,Demod.len,samples, samples,parity,FALSE); + LogTrace(Demod.output, Demod.len,samples, samples, parity, FALSE); } triggered = TRUE; LED_A_OFF(); @@ -1190,6 +1204,7 @@ void RAMFUNC SnoopIso14443(void) Dbprintf(" Trace length: %i", BigBuf_get_traceLen()); } + /* * Send raw command to tag ISO14443B * @Input @@ -1202,8 +1217,7 @@ void RAMFUNC SnoopIso14443(void) * none * */ - -void SendRawCommand14443B(uint32_t datalen, uint32_t recv,uint8_t powerfield, uint8_t data[]) +void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, uint8_t data[]) { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); if(!powerfield) From 5b95953d4227d9af4b5a5f20156b668bba55aac8 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 2 Jun 2015 22:27:14 +0200 Subject: [PATCH 2/9] fixing iso14443b (issue #103): - most significant bit of tag data (which happens to be the sign bit) had been dropped when snooping (FPGA change) - avoid trying to decode both tag and reader data when snooping (we don't have the time to do so). --- armsrc/iso14443b.c | 96 ++++++++++++++++++++++------------------ fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/hi_read_rx_xcorr.v | 13 +++--- 3 files changed, 60 insertions(+), 49 deletions(-) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 8add8f9c..d6595586 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -158,7 +158,6 @@ static int Handle14443UartBit(int bit) { switch(Uart.state) { case STATE_UNSYNCD: - LED_A_OFF(); if(!bit) { // we went low, so this could be the beginning // of an SOF @@ -272,8 +271,7 @@ static int Handle14443UartBit(int bit) break; } - // This row make the error blew circular buffer in hf 14b snoop - //if (Uart.state == STATE_ERROR_WAIT) LED_A_OFF(); // Error + if (Uart.state == STATE_UNSYNCD) LED_A_OFF(); return FALSE; } @@ -1054,17 +1052,17 @@ void ReadSTMemoryIso14443(uint32_t dwLast) //----------------------------------------------------------------------------- /* * Memory usage for this function, (within BigBuf) - * 0-4095 : Demodulated samples receive (4096 bytes) - DEMOD_TRACE_SIZE - * 4096-6143 : Last Received command, 2048 bytes (reader->tag) - READER_TAG_BUFFER_SIZE - * 6144-8191 : Last Received command, 2048 bytes(tag->reader) - TAG_READER_BUFFER_SIZE - * 8192-9215 : DMA Buffer, 1024 bytes (samples) - DEMOD_DMA_BUFFER_SIZE + * Last Received command (reader->tag) - MAX_FRAME_SIZE + * Last Received command (tag->reader) - MAX_FRAME_SIZE + * DMA Buffer, 1024 bytes (samples) - DMA_BUFFER_SIZE + * Demodulated samples received - all the rest */ void RAMFUNC SnoopIso14443(void) { // 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. - int triggered = TRUE; + int triggered = TRUE; // TODO: set and evaluate trigger condition FpgaDownloadAndGo(FPGA_BITSTREAM_HF); BigBuf_free(); @@ -1109,7 +1107,10 @@ void RAMFUNC SnoopIso14443(void) FpgaSetupSscDma((uint8_t*) dmaBuf, DMA_BUFFER_SIZE); uint8_t parity[MAX_PARITY_SIZE]; LED_A_ON(); - + + bool TagIsActive = FALSE; + bool ReaderIsActive = FALSE; + // And now we loop, receiving samples. for(;;) { int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & @@ -1136,49 +1137,56 @@ void RAMFUNC SnoopIso14443(void) samples += 2; - if(Handle14443UartBit(ci & 1)) { - if(triggered && tracing) { - GetParity(Uart.output, Uart.byteCnt, parity); - LogTrace(Uart.output,Uart.byteCnt,samples, samples,parity,TRUE); - } - if(Uart.byteCnt==0) Dbprintf("[1] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt); + if (!TagIsActive) { // no need to try decoding reader data if the tag is sending + if(Handle14443UartBit(ci & 0x01)) { + if(triggered && tracing) { + GetParity(Uart.output, Uart.byteCnt, parity); + LogTrace(Uart.output,Uart.byteCnt,samples, samples,parity,TRUE); + } + if(Uart.byteCnt==0) Dbprintf("[1] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt); - /* And ready to receive another command. */ - UartReset(); - /* And also reset the demod code, which might have been */ - /* false-triggered by the commands from the reader. */ - DemodReset(); - } - if(Handle14443UartBit(cq & 1)) { - if(triggered && tracing) { - GetParity(Uart.output, Uart.byteCnt, parity); - LogTrace(Uart.output,Uart.byteCnt,samples, samples, parity, TRUE); + /* And ready to receive another command. */ + UartReset(); + /* And also reset the demod code, which might have been */ + /* false-triggered by the commands from the reader. */ + DemodReset(); } - if(Uart.byteCnt==0) Dbprintf("[2] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt); + if(Handle14443UartBit(cq & 0x01)) { + if(triggered && tracing) { + GetParity(Uart.output, Uart.byteCnt, parity); + LogTrace(Uart.output,Uart.byteCnt,samples, samples, parity, TRUE); + } + if(Uart.byteCnt==0) Dbprintf("[2] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt); - /* And ready to receive another command. */ - UartReset(); - /* And also reset the demod code, which might have been */ - /* false-triggered by the commands from the reader. */ - DemodReset(); + /* And ready to receive another command. */ + UartReset(); + /* And also reset the demod code, which might have been */ + /* false-triggered by the commands from the reader. */ + DemodReset(); + } + ReaderIsActive = (Uart.state != STATE_UNSYNCD); } - if(Handle14443SamplesDemod(ci, cq)) { + if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time + if(Handle14443SamplesDemod(ci, cq)) { - //Use samples as a time measurement - if(tracing) - { - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(Demod.output, Demod.len, parity); - LogTrace(Demod.output, Demod.len,samples, samples, parity, FALSE); + //Use samples as a time measurement + if(tracing) + { + uint8_t parity[MAX_PARITY_SIZE]; + GetParity(Demod.output, Demod.len, parity); + LogTrace(Demod.output, Demod.len,samples, samples, parity, FALSE); + } + triggered = TRUE; + LED_A_OFF(); + LED_B_ON(); + + // And ready to receive another response. + DemodReset(); } - triggered = TRUE; - LED_A_OFF(); - LED_B_ON(); - - // And ready to receive another response. - DemodReset(); + TagIsActive = (Demod.state != DEMOD_UNSYNCD); } + WDT_HIT(); if(!tracing) { diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 20fb2bd4401254d899d6273451bfccbd827f562b..53078a782422c09596f006d95c85ae45da20072d 100644 GIT binary patch literal 42175 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 literal 42175 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 diff --git a/fpga/hi_read_rx_xcorr.v b/fpga/hi_read_rx_xcorr.v index dece2db3..ec6583b2 100644 --- a/fpga/hi_read_rx_xcorr.v +++ b/fpga/hi_read_rx_xcorr.v @@ -99,8 +99,10 @@ end reg [5:0] corr_i_cnt; reg [5:0] corr_q_cnt; // And a couple of registers in which to accumulate the correlations. -reg signed [15:0] corr_i_accum; -reg signed [15:0] corr_q_accum; +// we would add at most 32 times adc_d, the result can be held in 13 bits. +// Need one additional bit because it can be negative as well +reg signed [13:0] corr_i_accum; +reg signed [13:0] corr_q_accum; reg signed [7:0] corr_i_out; reg signed [7:0] corr_q_out; @@ -114,12 +116,13 @@ begin begin if(snoop) begin - corr_i_out <= {corr_i_accum[12:6], after_hysteresis_prev}; - corr_q_out <= {corr_q_accum[12:6], after_hysteresis}; + // highest 7 significant bits of tag signal (signed), 1 bit reader signal: + corr_i_out <= {corr_i_accum[13:7], after_hysteresis_prev}; + corr_q_out <= {corr_q_accum[13:7], after_hysteresis}; end else begin - // Only correlations need to be delivered. + // highest 8 significant bits of tag signal corr_i_out <= corr_i_accum[13:6]; corr_q_out <= corr_q_accum[13:6]; end From 09c66f1f09776989fda2d1005a2c9feb1db6b3ac Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 3 Jun 2015 13:28:28 +0200 Subject: [PATCH 3/9] fixing iso14443b (issue #103): fix timing issue (speeding up the decoders) --- armsrc/iso14443b.c | 22 +++++++++++----------- fpga/hi_read_rx_xcorr.v | 4 +++- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index d6595586..4e40bb68 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -210,7 +210,6 @@ static int Handle14443UartBit(int bit) Uart.bitCnt = 0; Uart.shiftReg = 0; Uart.state = STATE_RECEIVING_DATA; - LED_A_ON(); // Indicate we're receiving } break; @@ -263,6 +262,7 @@ static int Handle14443UartBit(int bit) Uart.posCnt++; if(Uart.posCnt > 10) { Uart.state = STATE_UNSYNCD; + LED_A_OFF(); } break; @@ -271,8 +271,6 @@ static int Handle14443UartBit(int bit) break; } - if (Uart.state == STATE_UNSYNCD) LED_A_OFF(); - return FALSE; } @@ -548,6 +546,7 @@ static RAMFUNC int Handle14443SamplesDemod(int ci, int cq) } else { if(Demod.posCount > 100) { Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); } } Demod.posCount++; @@ -558,6 +557,7 @@ static RAMFUNC int Handle14443SamplesDemod(int ci, int cq) if(v > 0) { if(Demod.posCount > 10) { Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); } } else { Demod.bitCount = 0; @@ -596,13 +596,13 @@ static RAMFUNC int Handle14443SamplesDemod(int ci, int cq) Demod.output[Demod.len] = b; Demod.len++; Demod.state = DEMOD_AWAITING_START_BIT; - } else if(s == 0x000) { - // This is EOF - LED_C_OFF(); - Demod.state = DEMOD_UNSYNCD; - return TRUE; } else { Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + if(s == 0x000) { + // This is EOF + return TRUE; + } } } Demod.posCount = 0; @@ -611,10 +611,10 @@ static RAMFUNC int Handle14443SamplesDemod(int ci, int cq) default: Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); break; } - if (Demod.state == DEMOD_UNSYNCD) LED_C_OFF(); // Not synchronized... return FALSE; } @@ -1168,14 +1168,14 @@ void RAMFUNC SnoopIso14443(void) } if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time - if(Handle14443SamplesDemod(ci, cq)) { + if(Handle14443SamplesDemod(ci & 0xFE, cq & 0xFE)) { //Use samples as a time measurement if(tracing) { uint8_t parity[MAX_PARITY_SIZE]; GetParity(Demod.output, Demod.len, parity); - LogTrace(Demod.output, Demod.len,samples, samples, parity, FALSE); + LogTrace(Demod.output, Demod.len, samples, samples, parity, FALSE); } triggered = TRUE; LED_A_OFF(); diff --git a/fpga/hi_read_rx_xcorr.v b/fpga/hi_read_rx_xcorr.v index ec6583b2..06142637 100644 --- a/fpga/hi_read_rx_xcorr.v +++ b/fpga/hi_read_rx_xcorr.v @@ -171,7 +171,9 @@ begin end end - if(corr_i_cnt[5:2] == 4'b000 || corr_i_cnt[5:2] == 4'b1000) + // set ssp_frame signal for corr_i_cnt = 0..3 and corr_i_cnt = 32..35 + // (two frames with 8 Bits each) + if(corr_i_cnt[5:2] == 4'b0000 || corr_i_cnt[5:2] == 4'b1000) ssp_frame = 1'b1; else ssp_frame = 1'b0; From 51d4f6f1146b083f12381419bbfb6addd550e6a3 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Fri, 12 Jun 2015 07:43:00 +0200 Subject: [PATCH 4/9] fixing iso14443b (issue #103): - fix: IQ demodulator (FPGA) - fix: approximately align reader signal delay to tag response delay (FPGA) - fix: remove deprecated RSSI calculation to improve decoder speed (iso14443b.c) - fix: better approximation of signal amplitude to avoid false carrier detection (iso14443b.c) - fix: remove initial power off in iso14443b raw command (iso14443b.c) - add: enable tracing for iso14443b raw command (iso14443b.c) - fix: client crashed when checking CRC for incomplete responses (iso14433b.c) - speeding up snoop to avoid circular buffer overflow - added some comments for better documentation - rename functions (iso14443 -> iso14443b) - remove unused code in hi_read_rx_xcorr.v --- armsrc/appmain.c | 12 +- armsrc/apps.h | 8 +- armsrc/iso14443b.c | 476 ++++++++++++++++++++-------------------- client/cmdhf14b.c | 14 +- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/fpga_hf.v | 11 +- fpga/hi_read_rx_xcorr.v | 78 ++----- 7 files changed, 279 insertions(+), 320 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index c226c726..9bfa5ea7 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -263,7 +263,7 @@ void SimulateTagHfListen(void) // We're using this mode just so that I can test it out; the simulated // tag mode would work just as well and be simpler. FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_SNOOP); // We need to listen to the high-frequency, peak-detected path. SetAdcMuxFor(GPIO_MUXSEL_HIPKD); @@ -783,19 +783,19 @@ void UsbPacketReceived(uint8_t *packet, int len) #ifdef WITH_ISO14443b case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443: - AcquireRawAdcSamplesIso14443(c->arg[0]); + AcquireRawAdcSamplesIso14443b(c->arg[0]); break; case CMD_READ_SRI512_TAG: - ReadSTMemoryIso14443(0x0F); + ReadSTMemoryIso14443b(0x0F); break; case CMD_READ_SRIX4K_TAG: - ReadSTMemoryIso14443(0x7F); + ReadSTMemoryIso14443b(0x7F); break; case CMD_SNOOP_ISO_14443: - SnoopIso14443(); + SnoopIso14443b(); break; case CMD_SIMULATE_TAG_ISO_14443: - SimulateIso14443Tag(); + SimulateIso14443bTag(); break; case CMD_ISO_14443B_COMMAND: SendRawCommand14443B(c->arg[0],c->arg[1],c->arg[2],c->d.asBytes); diff --git a/armsrc/apps.h b/armsrc/apps.h index 6360b664..542f3a65 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -141,10 +141,10 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode); void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode); /// iso14443.h -void SimulateIso14443Tag(void); -void AcquireRawAdcSamplesIso14443(uint32_t parameter); -void ReadSTMemoryIso14443(uint32_t); -void RAMFUNC SnoopIso14443(void); +void SimulateIso14443bTag(void); +void AcquireRawAdcSamplesIso14443b(uint32_t parameter); +void ReadSTMemoryIso14443b(uint32_t); +void RAMFUNC SnoopIso14443b(void); void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]); /// iso14443a.h diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 4e40bb68..f598df3c 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -5,9 +5,8 @@ // at your option, any later version. See the LICENSE.txt file for the text of // the license. //----------------------------------------------------------------------------- -// Routines to support ISO 14443. This includes both the reader software and -// the `fake tag' modes. At the moment only the Type B modulation is -// supported. +// Routines to support ISO 14443B. This includes both the reader software and +// the `fake tag' modes. //----------------------------------------------------------------------------- #include "proxmark3.h" @@ -17,15 +16,8 @@ #include "iso14443crc.h" -//static void GetSamplesFor14443(int weTx, int n); - -/*#define DEMOD_TRACE_SIZE 4096 -#define READER_TAG_BUFFER_SIZE 2048 -#define TAG_READER_BUFFER_SIZE 2048 -#define DEMOD_DMA_BUFFER_SIZE 1024 -*/ - #define RECEIVE_SAMPLES_TIMEOUT 2000 +#define ISO14443B_DMA_BUFFER_SIZE 512 //============================================================================= // An ISO 14443 Type B tag. We listen for commands from the reader, using @@ -104,14 +96,14 @@ static void CodeIso14443bAsTag(const uint8_t *cmd, int len) ToSendStuffBit(1); } - // Send SOF. + // Send EOF. for(i = 0; i < 10; i++) { ToSendStuffBit(0); ToSendStuffBit(0); ToSendStuffBit(0); ToSendStuffBit(0); } - for(i = 0; i < 10; i++) { + for(i = 0; i < 2; i++) { ToSendStuffBit(1); ToSendStuffBit(1); ToSendStuffBit(1); @@ -120,9 +112,6 @@ static void CodeIso14443bAsTag(const uint8_t *cmd, int len) // Convert from last byte pos to length ToSendMax++; - - // Add a few more for slop - ToSendMax += 2; } //----------------------------------------------------------------------------- @@ -146,6 +135,9 @@ static struct { } Uart; /* Receive & handle a bit coming from the reader. + * + * This function is called 4 times per bit (every 2 subcarrier cycles). + * Subcarrier frequency fs is 848kHz, 1/fs = 1,18us, i.e. function is called every 2,36us * * LED handling: * LED A -> ON once we have received the SOF and are expecting the rest. @@ -154,7 +146,7 @@ static struct { * Returns: true if we received a EOF * false if we are still waiting for some more */ -static int Handle14443UartBit(int bit) +static int Handle14443bUartBit(int bit) { switch(Uart.state) { case STATE_UNSYNCD: @@ -169,9 +161,9 @@ static int Handle14443UartBit(int bit) case STATE_GOT_FALLING_EDGE_OF_SOF: Uart.posCnt++; - if(Uart.posCnt == 2) { + if(Uart.posCnt == 2) { // sample every 4 1/fs in the middle of a bit if(bit) { - if(Uart.bitCnt >= 10) { + if(Uart.bitCnt > 9) { // we've seen enough consecutive // zeros that it's a valid SOF Uart.posCnt = 0; @@ -189,7 +181,7 @@ static int Handle14443UartBit(int bit) Uart.bitCnt++; } if(Uart.posCnt >= 4) Uart.posCnt = 0; - if(Uart.bitCnt > 14) { + if(Uart.bitCnt > 12) { // Give up if we see too many zeros without // a one, too. Uart.state = STATE_ERROR_WAIT; @@ -199,7 +191,7 @@ static int Handle14443UartBit(int bit) case STATE_AWAITING_START_BIT: Uart.posCnt++; if(bit) { - if(Uart.posCnt > 25) { + if(Uart.posCnt > 50/2) { // max 57us between characters = 49 1/fs, max 3 etus after low phase of SOF = 24 1/fs // stayed high for too long between // characters, error Uart.state = STATE_ERROR_WAIT; @@ -283,12 +275,12 @@ static int Handle14443UartBit(int bit) // Assume that we're called with the SSC (to the FPGA) and ADC path set // correctly. //----------------------------------------------------------------------------- -static int GetIso14443CommandFromReader(uint8_t *received, int *len, int maxLen) +static int GetIso14443bCommandFromReader(uint8_t *received, int *len, int maxLen) { uint8_t mask; int i, bit; - // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen + // 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(); @@ -314,7 +306,7 @@ static int GetIso14443CommandFromReader(uint8_t *received, int *len, int maxLen) mask = 0x80; for(i = 0; i < 8; i++, mask >>= 1) { bit = (b & mask); - if(Handle14443UartBit(bit)) { + if(Handle14443bUartBit(bit)) { *len = Uart.byteCnt; return TRUE; } @@ -327,9 +319,13 @@ static int GetIso14443CommandFromReader(uint8_t *received, int *len, int maxLen) // Main loop of simulated tag: receive commands from reader, decide what // response to send, and send it. //----------------------------------------------------------------------------- -void SimulateIso14443Tag(void) +void SimulateIso14443bTag(void) { + // the only command we understand is REQB, AFI=0, Select All, N=0: static const uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; + // ... and we 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: static const uint8_t response1[] = { 0x50, 0x82, 0x0d, 0xe1, 0x74, 0x20, 0x38, 0x19, 0x22, 0x00, 0x21, 0x85, 0x5e, 0xd7 @@ -338,10 +334,9 @@ void SimulateIso14443Tag(void) uint8_t *resp; int respLen; - uint8_t *resp1 = BigBuf_get_addr() + 800; - int resp1Len; - - uint8_t *receivedCmd = BigBuf_get_addr(); + // allocate command receive buffer + BigBuf_free(); + uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); int len; int i; @@ -349,10 +344,12 @@ void SimulateIso14443Tag(void) int cmdsRecvd = 0; FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - memset(receivedCmd, 0x44, 400); + // prepare the (only one) tag answer: CodeIso14443bAsTag(response1, sizeof(response1)); - memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax; + uint8_t *resp1 = BigBuf_malloc(ToSendMax); + memcpy(resp1, ToSend, ToSendMax); + uint16_t resp1Len = ToSendMax; // We need to listen to the high-frequency, peak-detected path. SetAdcMuxFor(GPIO_MUXSEL_HIPKD); @@ -363,14 +360,14 @@ void SimulateIso14443Tag(void) for(;;) { uint8_t b1, b2; - if(!GetIso14443CommandFromReader(receivedCmd, &len, 100)) { - Dbprintf("button pressed, received %d commands", cmdsRecvd); - break; - } + if(!GetIso14443bCommandFromReader(receivedCmd, &len, 100)) { + Dbprintf("button pressed, received %d commands", cmdsRecvd); + break; + } // Good, look at the command now. - if(len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len)==0) { + if(len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len) == 0) { resp = resp1; respLen = resp1Len; } else { Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsRecvd); @@ -385,8 +382,6 @@ void SimulateIso14443Tag(void) break; } - memset(receivedCmd, 0x44, 32); - cmdsRecvd++; if(cmdsRecvd > 0x30) { @@ -444,8 +439,10 @@ static struct { int bitCount; int posCount; int thisBit; +/* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented. int metric; int metricN; +*/ uint16_t shiftReg; uint8_t *output; int len; @@ -456,6 +453,9 @@ static struct { /* * Handles reception of a bit from the tag * + * This function is called 2 times per bit (every 4 subcarrier cycles). + * Subcarrier frequency fs is 848kHz, 1/fs = 1,18us, i.e. function is called every 4,72us + * * 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 @@ -464,12 +464,12 @@ static struct { * false if we are still waiting for some more * */ -static RAMFUNC int Handle14443SamplesDemod(int ci, int cq) +static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) { int v; - // The soft decision on the bit uses an estimate of just the - // quadrant of the reference angle, not the exact angle. +// 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() { \ if(Demod.sumI > 0) { \ v = ci; \ @@ -483,47 +483,87 @@ static RAMFUNC int Handle14443SamplesDemod(int ci, int cq) } \ } +#define SUBCARRIER_DETECT_THRESHOLD 8 + +// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by abs(ci) + abs(cq) +/* #define CHECK_FOR_SUBCARRIER() { \ + v = ci; \ + if(v < 0) v = -v; \ + if(cq > 0) { \ + v += cq; \ + } else { \ + v -= cq; \ + } \ + } + */ +// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) +#define CHECK_FOR_SUBCARRIER() { \ + if(ci < 0) { \ + if(cq < 0) { /* ci < 0, cq < 0 */ \ + if (cq < ci) { \ + v = -cq - (ci >> 1); \ + } else { \ + v = -ci - (cq >> 1); \ + } \ + } else { /* ci < 0, cq >= 0 */ \ + if (cq < -ci) { \ + v = -ci + (cq >> 1); \ + } else { \ + v = cq - (ci >> 1); \ + } \ + } \ + } else { \ + if(cq < 0) { /* ci >= 0, cq < 0 */ \ + if (-cq < ci) { \ + v = ci - (cq >> 1); \ + } else { \ + v = -cq + (ci >> 1); \ + } \ + } else { /* ci >= 0, cq >= 0 */ \ + if (cq < ci) { \ + v = ci + (cq >> 1); \ + } else { \ + v = cq + (ci >> 1); \ + } \ + } \ + } \ + } + switch(Demod.state) { case DEMOD_UNSYNCD: - v = ci; - if(v < 0) v = -v; - if(cq > 0) { - v += cq; - } else { - v -= cq; - } - if(v > 40) { - Demod.posCount = 0; + CHECK_FOR_SUBCARRIER(); + if(v > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected Demod.state = DEMOD_PHASE_REF_TRAINING; - Demod.sumI = 0; - Demod.sumQ = 0; - } + Demod.sumI = ci; + Demod.sumQ = cq; + Demod.posCount = 1; + } break; case DEMOD_PHASE_REF_TRAINING: if(Demod.posCount < 8) { - Demod.sumI += ci; - Demod.sumQ += cq; - } else if(Demod.posCount > 100) { - // error, waited too long - Demod.state = DEMOD_UNSYNCD; - } else { - MAKE_SOFT_DECISION(); - if(v < 0) { - Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF; - Demod.posCount = 0; + CHECK_FOR_SUBCARRIER(); + if (v > SUBCARRIER_DETECT_THRESHOLD) { + // set the reference phase (will code a logic '1') by averaging over 32 1/fs. + // note: synchronization time > 80 1/fs + Demod.sumI += ci; + Demod.sumQ += cq; + Demod.posCount++; + } else { // subcarrier lost + Demod.state = DEMOD_UNSYNCD; } + } else { + Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF; } - Demod.posCount++; break; case DEMOD_AWAITING_FALLING_EDGE_OF_SOF: MAKE_SOFT_DECISION(); - if(v < 0) { + if(v < 0) { // logic '0' detected Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF; - Demod.posCount = 0; + Demod.posCount = 0; // start of SOF sequence } else { - if(Demod.posCount > 100) { + if(Demod.posCount > 200/4) { // maximum length of TR1 = 200 1/fs Demod.state = DEMOD_UNSYNCD; } } @@ -531,37 +571,40 @@ static RAMFUNC int Handle14443SamplesDemod(int ci, int cq) break; case DEMOD_GOT_FALLING_EDGE_OF_SOF: + Demod.posCount++; MAKE_SOFT_DECISION(); if(v > 0) { - if(Demod.posCount < 12) { + 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.state = DEMOD_AWAITING_START_BIT; Demod.posCount = 0; Demod.len = 0; +/* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented. Demod.metricN = 0; Demod.metric = 0; +*/ } } else { - if(Demod.posCount > 100) { + if(Demod.posCount > 12*2) { // low phase of SOF too long (> 12 etu) Demod.state = DEMOD_UNSYNCD; LED_C_OFF(); } } - Demod.posCount++; break; case DEMOD_AWAITING_START_BIT: + Demod.posCount++; MAKE_SOFT_DECISION(); if(v > 0) { - if(Demod.posCount > 10) { + if(Demod.posCount > 3*2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs Demod.state = DEMOD_UNSYNCD; LED_C_OFF(); } - } else { + } else { // start bit detected Demod.bitCount = 0; - Demod.posCount = 1; + Demod.posCount = 1; // this was the first half Demod.thisBit = v; Demod.shiftReg = 0; Demod.state = DEMOD_RECEIVING_DATA; @@ -570,28 +613,30 @@ static RAMFUNC int Handle14443SamplesDemod(int ci, int cq) case DEMOD_RECEIVING_DATA: MAKE_SOFT_DECISION(); - if(Demod.posCount == 0) { + if(Demod.posCount == 0) { // first half of bit Demod.thisBit = v; Demod.posCount = 1; - } else { + } else { // second half of bit Demod.thisBit += v; +/* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented. if(Demod.thisBit > 0) { Demod.metric += Demod.thisBit; } else { Demod.metric -= Demod.thisBit; } (Demod.metricN)++; +*/ Demod.shiftReg >>= 1; - if(Demod.thisBit > 0) { + if(Demod.thisBit > 0) { // logic '1' Demod.shiftReg |= 0x200; } Demod.bitCount++; if(Demod.bitCount == 10) { uint16_t s = Demod.shiftReg; - if((s & 0x200) && !(s & 0x001)) { + if((s & 0x200) && !(s & 0x001)) { // stop bit == '1', start bit == '0' uint8_t b = (s >> 1); Demod.output[Demod.len] = b; Demod.len++; @@ -600,7 +645,7 @@ static RAMFUNC int Handle14443SamplesDemod(int ci, int cq) Demod.state = DEMOD_UNSYNCD; LED_C_OFF(); if(s == 0x000) { - // This is EOF + // This is EOF (start, stop and all data bits == '0' return TRUE; } } @@ -624,6 +669,7 @@ static void DemodReset() // Clear out the state of the "UART" that receives from the tag. Demod.len = 0; Demod.state = DEMOD_UNSYNCD; + Demod.posCount = 0; memset(Demod.output, 0x00, MAX_FRAME_SIZE); } @@ -653,14 +699,12 @@ static void UartInit(uint8_t *data) /* * Demodulate the samples we received from the tag, also log to tracebuffer - * weTx: set to 'TRUE' if we behave like a reader - * set to 'FALSE' if we behave like a snooper * quiet: set to 'TRUE' to disable debug output */ -static void GetSamplesFor14443Demod(int weTx, int n, int quiet) +static void GetSamplesFor14443bDemod(int n, bool quiet) { int max = 0; - int gotFrame = FALSE; + bool gotFrame = FALSE; int lastRxCounter, ci, cq, samples = 0; // Allocate memory from BigBuf for some buffers @@ -671,57 +715,56 @@ static void GetSamplesFor14443Demod(int weTx, int n, int quiet) uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE); // The DMA buffer, used to stream samples from the FPGA - int8_t *dmaBuf = (int8_t*) BigBuf_malloc(DMA_BUFFER_SIZE); + int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); // Set up the demodulator for tag -> reader responses. DemodInit(receivedResponse); // Setup and start DMA. - FpgaSetupSscDma((uint8_t*) dmaBuf, DMA_BUFFER_SIZE); + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); int8_t *upTo = dmaBuf; - lastRxCounter = DMA_BUFFER_SIZE; + lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; // Signal field is ON with the appropriate LED: - if (weTx) LED_D_ON(); else LED_D_OFF(); + LED_D_ON(); // And put the FPGA in the appropriate mode - FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | - (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP)); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); for(;;) { int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR; if(behindBy > max) max = behindBy; - while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE-1)) - > 2) - { + while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1)) > 2) { ci = upTo[0]; cq = upTo[1]; upTo += 2; - if(upTo >= dmaBuf + DMA_BUFFER_SIZE) { + if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { upTo = dmaBuf; AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; - AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; } lastRxCounter -= 2; if(lastRxCounter <= 0) { - lastRxCounter += DMA_BUFFER_SIZE; + lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; } samples += 2; - if(Handle14443SamplesDemod(ci, cq)) { - gotFrame = 1; + if(Handle14443bSamplesDemod(ci, cq)) { + gotFrame = TRUE; + break; } } - if(samples > n) { + if(samples > n || gotFrame) { break; } } + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; - if (!quiet) Dbprintf("%x %x %x", max, gotFrame, Demod.len); + + if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", max, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ); //Tracing if (tracing && Demod.len > 0) { uint8_t parity[MAX_PARITY_SIZE]; @@ -731,43 +774,10 @@ static void GetSamplesFor14443Demod(int weTx, int n, int quiet) } -//----------------------------------------------------------------------------- -// Read the tag's response. We just receive a stream of slightly-processed -// samples from the FPGA, which we will later do some signal processing on, -// to get the bits. -//----------------------------------------------------------------------------- -/*static void GetSamplesFor14443(int weTx, int n) -{ - uint8_t *dest = (uint8_t *)BigBuf; - int c; - - FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | - (weTx ? 0 : FPGA_HF_READER_RX_XCORR_SNOOP)); - - c = 0; - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x43; - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - int8_t b; - b = (int8_t)AT91C_BASE_SSC->SSC_RHR; - - dest[c++] = (uint8_t)b; - - if(c >= n) { - break; - } - } - } -}*/ - - //----------------------------------------------------------------------------- // Transmit the command (to the tag) that was placed in ToSend[]. //----------------------------------------------------------------------------- -static void TransmitFor14443(void) +static void TransmitFor14443b(void) { int c; @@ -781,8 +791,7 @@ static void TransmitFor14443(void) LED_D_ON(); // Signal we are transmitting with the Green LED LED_B_ON(); - FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); for(c = 0; c < 10;) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { @@ -817,7 +826,7 @@ static void TransmitFor14443(void) //----------------------------------------------------------------------------- // Code a layer 2 command (string of octets, including CRC) into ToSend[], -// so that it is ready to transmit to the tag using TransmitFor14443(). +// so that it is ready to transmit to the tag using TransmitFor14443b(). //----------------------------------------------------------------------------- static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { @@ -873,16 +882,16 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) //----------------------------------------------------------------------------- -// Read an ISO 14443 tag. We send it some set of commands, and record the +// Read an ISO 14443B tag. We send it some set of commands, and record the // responses. // The command name is misleading, it actually decodes the reponse in HEX // into the output buffer (read the result using hexsamples, not hisamples) // // obsolete function only for test //----------------------------------------------------------------------------- -void AcquireRawAdcSamplesIso14443(uint32_t parameter) +void AcquireRawAdcSamplesIso14443b(uint32_t parameter) { - uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; + uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; // REQB with AFI=0, Request All, N=0 SendRawCommand14443B(sizeof(cmd1),1,1,cmd1); } @@ -894,7 +903,7 @@ void AcquireRawAdcSamplesIso14443(uint32_t parameter) static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) { CodeIso14443bAsReader(cmd, len); - TransmitFor14443(); + TransmitFor14443b(); if (tracing) { uint8_t parity[MAX_PARITY_SIZE]; GetParity(cmd, len, parity); @@ -904,7 +913,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) //----------------------------------------------------------------------------- -// Read a SRI512 ISO 14443 tag. +// Read a SRI512 ISO 14443B tag. // // 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 @@ -912,7 +921,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) // // I tried to be systematic and check every answer of the tag, every CRC, etc... //----------------------------------------------------------------------------- -void ReadSTMemoryIso14443(uint32_t dwLast) +void ReadSTMemoryIso14443b(uint32_t dwLast) { clear_trace(); set_tracing(TRUE); @@ -933,15 +942,15 @@ void ReadSTMemoryIso14443(uint32_t dwLast) // Signal field is on with the appropriate LED LED_D_ON(); FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); + FPGA_MAJOR_MODE_HF_READER_RX_XCORR); SpinDelay(200); // First command: wake up the tag using the INITIATE command - uint8_t cmd1[] = { 0x06, 0x00, 0x97, 0x5b}; + uint8_t cmd1[] = {0x06, 0x00, 0x97, 0x5b}; CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); // LED_A_ON(); - GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); // LED_A_OFF(); if (Demod.len == 0) { @@ -949,7 +958,7 @@ void ReadSTMemoryIso14443(uint32_t dwLast) return; } else { Dbprintf("Randomly generated UID from tag (+ 2 byte CRC): %x %x %x", - Demod.output[0], Demod.output[1],Demod.output[2]); + Demod.output[0], Demod.output[1], Demod.output[2]); } // There is a response, SELECT the uid DbpString("Now SELECT tag:"); @@ -959,22 +968,22 @@ void ReadSTMemoryIso14443(uint32_t dwLast) CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); // LED_A_ON(); - GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); // LED_A_OFF(); if (Demod.len != 3) { - Dbprintf("Expected 3 bytes from tag, got %d", Demod.len); - return; + Dbprintf("Expected 3 bytes from tag, got %d", Demod.len); + return; } // Check the CRC of the answer: ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]); if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) { - DbpString("CRC Error reading select response."); - return; + DbpString("CRC Error reading select response."); + return; } // Check response from the tag: should be the same UID as the command we just sent: if (cmd1[1] != Demod.output[0]) { - Dbprintf("Bad response to SELECT from Tag, aborting: %x %x", cmd1[1], Demod.output[0]); - return; + Dbprintf("Bad response to SELECT from Tag, aborting: %x %x", cmd1[1], Demod.output[0]); + return; } // Tag is now selected, // First get the tag's UID: @@ -983,22 +992,22 @@ void ReadSTMemoryIso14443(uint32_t dwLast) CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one // LED_A_ON(); - GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); // LED_A_OFF(); if (Demod.len != 10) { - Dbprintf("Expected 10 bytes from tag, got %d", Demod.len); - return; + Dbprintf("Expected 10 bytes from tag, got %d", Demod.len); + return; } // The check the CRC of the answer (use cmd1 as temporary variable): ComputeCrc14443(CRC_14443_B, Demod.output, 8, &cmd1[2], &cmd1[3]); - if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) { - Dbprintf("CRC Error reading block! - Below: expected, got %x %x", - (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]); - // Do not return;, let's go on... (we should retry, maybe ?) + if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) { + Dbprintf("CRC Error reading block! - Below: expected, got %x %x", + (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]); + // Do not return;, let's go on... (we should retry, maybe ?) } Dbprintf("Tag UID (64 bits): %08x %08x", - (Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4], - (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]); + (Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4], + (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]); // Now loop to read all 16 blocks, address from 0 to last block Dbprintf("Tag memory dump, block 0 to %d",dwLast); @@ -1006,7 +1015,7 @@ void ReadSTMemoryIso14443(uint32_t dwLast) i = 0x00; dwLast++; for (;;) { - if (i == dwLast) { + if (i == dwLast) { DbpString("System area block (0xff):"); i = 0xff; } @@ -1015,25 +1024,25 @@ void ReadSTMemoryIso14443(uint32_t dwLast) CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); // LED_A_ON(); - GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE); + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); // LED_A_OFF(); if (Demod.len != 6) { // Check if we got an answer from the tag - DbpString("Expected 6 bytes from tag, got less..."); - return; + DbpString("Expected 6 bytes from tag, got less..."); + return; } // The check the CRC of the answer (use cmd1 as temporary variable): ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]); - if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) { - Dbprintf("CRC Error reading block! - Below: expected, got %x %x", - (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]); - // Do not return;, let's go on... (we should retry, maybe ?) + if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) { + Dbprintf("CRC Error reading block! - Below: expected, got %x %x", + (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]); + // Do not return;, let's go on... (we should retry, maybe ?) } // Now print out the memory location: Dbprintf("Address=%x, Contents=%x, CRC=%x", i, - (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0], - (Demod.output[4]<<8)+Demod.output[5]); + (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0], + (Demod.output[4]<<8)+Demod.output[5]); if (i == 0xff) { - break; + break; } i++; } @@ -1054,10 +1063,10 @@ void ReadSTMemoryIso14443(uint32_t dwLast) * Memory usage for this function, (within BigBuf) * Last Received command (reader->tag) - MAX_FRAME_SIZE * Last Received command (tag->reader) - MAX_FRAME_SIZE - * DMA Buffer, 1024 bytes (samples) - DMA_BUFFER_SIZE + * DMA Buffer - ISO14443B_DMA_BUFFER_SIZE * Demodulated samples received - all the rest */ -void RAMFUNC SnoopIso14443(void) +void RAMFUNC SnoopIso14443b(void) { // 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 @@ -1071,7 +1080,7 @@ void RAMFUNC SnoopIso14443(void) set_tracing(TRUE); // The DMA buffer, used to stream samples from the FPGA - int8_t *dmaBuf = (int8_t*) BigBuf_malloc(DMA_BUFFER_SIZE); + int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); int lastRxCounter; int8_t *upTo; int ci, cq; @@ -1089,24 +1098,21 @@ void RAMFUNC SnoopIso14443(void) Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); Dbprintf(" Reader -> tag: %i bytes", MAX_FRAME_SIZE); Dbprintf(" tag -> Reader: %i bytes", MAX_FRAME_SIZE); - Dbprintf(" DMA: %i bytes", DMA_BUFFER_SIZE); + Dbprintf(" DMA: %i bytes", ISO14443B_DMA_BUFFER_SIZE); - // Signal field is off with the appropriate LED - LED_D_OFF(); + // Signal field is off, no reader signal, no tag signal + LEDsoff(); // And put the FPGA in the appropriate mode - FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | - FPGA_HF_READER_RX_XCORR_SNOOP); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_SNOOP); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Setup for the DMA. FpgaSetupSsc(); upTo = dmaBuf; - lastRxCounter = DMA_BUFFER_SIZE; - FpgaSetupSscDma((uint8_t*) dmaBuf, DMA_BUFFER_SIZE); + lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); uint8_t parity[MAX_PARITY_SIZE]; - LED_A_ON(); bool TagIsActive = FALSE; bool ReaderIsActive = FALSE; @@ -1114,50 +1120,56 @@ void RAMFUNC SnoopIso14443(void) // And now we loop, receiving samples. for(;;) { int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & - (DMA_BUFFER_SIZE-1); + (ISO14443B_DMA_BUFFER_SIZE-1); if(behindBy > maxBehindBy) { maxBehindBy = behindBy; - if(behindBy > (9*DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not? - Dbprintf("blew circular buffer! behindBy=0x%x", behindBy); - break; - } } + if(behindBy < 2) continue; ci = upTo[0]; cq = upTo[1]; upTo += 2; lastRxCounter -= 2; - if(upTo >= dmaBuf + DMA_BUFFER_SIZE) { + if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { upTo = dmaBuf; - lastRxCounter += DMA_BUFFER_SIZE; + lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; + WDT_HIT(); + if(behindBy > (9*ISO14443B_DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not? + Dbprintf("blew circular buffer! behindBy=0x%x", behindBy); + break; + } + if(!tracing) { + DbpString("Reached trace limit"); + break; + } + if(BUTTON_PRESS()) { + DbpString("cancelled"); + break; + } } samples += 2; if (!TagIsActive) { // no need to try decoding reader data if the tag is sending - if(Handle14443UartBit(ci & 0x01)) { + if(Handle14443bUartBit(ci & 0x01)) { if(triggered && tracing) { GetParity(Uart.output, Uart.byteCnt, parity); - LogTrace(Uart.output,Uart.byteCnt,samples, samples,parity,TRUE); + LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE); } - if(Uart.byteCnt==0) Dbprintf("[1] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt); - /* And ready to receive another command. */ UartReset(); /* And also reset the demod code, which might have been */ /* false-triggered by the commands from the reader. */ DemodReset(); } - if(Handle14443UartBit(cq & 0x01)) { + if(Handle14443bUartBit(cq & 0x01)) { if(triggered && tracing) { GetParity(Uart.output, Uart.byteCnt, parity); - LogTrace(Uart.output,Uart.byteCnt,samples, samples, parity, TRUE); + LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE); } - if(Uart.byteCnt==0) Dbprintf("[2] Error, Uart.byteCnt==0, Uart.bitCnt=%d", Uart.bitCnt); - /* And ready to receive another command. */ UartReset(); /* And also reset the demod code, which might have been */ @@ -1168,7 +1180,7 @@ void RAMFUNC SnoopIso14443(void) } if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time - if(Handle14443SamplesDemod(ci & 0xFE, cq & 0xFE)) { + if(Handle14443bSamplesDemod(ci & 0xFE, cq & 0xFE)) { //Use samples as a time measurement if(tracing) @@ -1178,31 +1190,17 @@ void RAMFUNC SnoopIso14443(void) LogTrace(Demod.output, Demod.len, samples, samples, parity, FALSE); } triggered = TRUE; - LED_A_OFF(); - LED_B_ON(); // And ready to receive another response. DemodReset(); } - TagIsActive = (Demod.state != DEMOD_UNSYNCD); + TagIsActive = (Demod.state > DEMOD_PHASE_REF_TRAINING); } - WDT_HIT(); - - if(!tracing) { - DbpString("Reached trace limit"); - break; - } - - if(BUTTON_PRESS()) { - DbpString("cancelled"); - break; - } } + FpgaDisableSscDma(); - LED_A_OFF(); - LED_B_OFF(); - LED_C_OFF(); + LEDsoff(); AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; DbpString("Snoop statistics:"); Dbprintf(" Max behind by: %i", maxBehindBy); @@ -1228,38 +1226,36 @@ void RAMFUNC SnoopIso14443(void) void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, uint8_t data[]) { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - if(!powerfield) - { + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + set_tracing(TRUE); + +/* if(!powerfield) { // Make sure that we start from off, since the tags are stateful; // confusing things will happen if we don't reset them between reads. FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); SpinDelay(200); } + */ - if(!GETBIT(GPIO_LED_D)) - { - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); - - // Now give it time to spin up. - // Signal field is on with the appropriate LED - LED_D_ON(); - FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); - SpinDelay(200); - } + // if(!GETBIT(GPIO_LED_D)) { // if field is off + // FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + // // Signal field is on with the appropriate LED + // LED_D_ON(); + // SpinDelay(200); + // } CodeAndTransmit14443bAsReader(data, datalen); - if(recv) - { - GetSamplesFor14443Demod(TRUE, RECEIVE_SAMPLES_TIMEOUT, TRUE); - uint16_t iLen = MIN(Demod.len,USB_CMD_DATA_SIZE); - cmd_send(CMD_ACK,iLen,0,0,Demod.output,iLen); + if(recv) { + GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); + uint16_t iLen = MIN(Demod.len, USB_CMD_DATA_SIZE); + cmd_send(CMD_ACK, iLen, 0, 0, Demod.output, iLen); } - if(!powerfield) - { + + if(!powerfield) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); } diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index 525ffcc6..21a4e179 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -288,7 +288,7 @@ int CmdHF14BCmdRaw (const char *cmd) { if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { recv = resp.d.asBytes; PrintAndLog("received %i octets",resp.arg[0]); - if(!resp.arg[0]) + if(resp.arg[0] == 0) return 0; hexout = (char *)malloc(resp.arg[0] * 3 + 1); if (hexout != NULL) { @@ -298,11 +298,13 @@ int CmdHF14BCmdRaw (const char *cmd) { } PrintAndLog("%s", hexout); free(hexout); - ComputeCrc14443(CRC_14443_B, recv, resp.arg[0]-2, &first, &second); - if(recv[resp.arg[0]-2]==first && recv[resp.arg[0]-1]==second) { - PrintAndLog("CRC OK"); - } else { - PrintAndLog("CRC failed"); + if (resp.arg[0] > 2) { + ComputeCrc14443(CRC_14443_B, recv, resp.arg[0]-2, &first, &second); + if(recv[resp.arg[0]-2]==first && recv[resp.arg[0]-1]==second) { + PrintAndLog("CRC OK"); + } else { + PrintAndLog("CRC failed"); + } } } else { PrintAndLog("malloc failed your client has low memory?"); diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 53078a782422c09596f006d95c85ae45da20072d..717dad13eb67e5ef2cfeb39da3c4a0f6e9e04fd3 100644 GIT binary patch literal 42175 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 literal 42175 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 diff --git a/fpga/fpga_hf.v b/fpga/fpga_hf.v index a2100df6..e84081b3 100644 --- a/fpga/fpga_hf.v +++ b/fpga/fpga_hf.v @@ -67,15 +67,10 @@ assign major_mode = conf_word[7:5]; // some fraction of the buffers) wire hi_read_tx_shallow_modulation = conf_word[0]; -// For the high-frequency receive correlator: frequency against which to -// correlate. -wire hi_read_rx_xcorr_848 = conf_word[0]; -// and whether to drive the coil (reader) or just short it (snooper) +// For the high-frequency receive correlator: +// whether to drive the coil (reader) or just short it (snooper) wire hi_read_rx_xcorr_snoop = conf_word[1]; -// Divide the expected subcarrier frequency for hi_read_rx_xcorr by 4 -wire hi_read_rx_xcorr_quarter = conf_word[2]; - // For the high-frequency simulated tag: what kind of modulation to use. wire [2:0] hi_simulate_mod_type = conf_word[2:0]; @@ -102,7 +97,7 @@ hi_read_rx_xcorr hrxc( hrxc_ssp_frame, hrxc_ssp_din, ssp_dout, hrxc_ssp_clk, cross_hi, cross_lo, hrxc_dbg, - hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter + hi_read_rx_xcorr_snoop ); hi_simulate hs( diff --git a/fpga/hi_read_rx_xcorr.v b/fpga/hi_read_rx_xcorr.v index 06142637..a6a99cd5 100644 --- a/fpga/hi_read_rx_xcorr.v +++ b/fpga/hi_read_rx_xcorr.v @@ -10,7 +10,7 @@ module hi_read_rx_xcorr( ssp_frame, ssp_din, ssp_dout, ssp_clk, cross_hi, cross_lo, dbg, - xcorr_is_848, snoop, xcorr_quarter_freq + snoop ); input pck0, ck_1356meg, ck_1356megb; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; @@ -20,58 +20,20 @@ module hi_read_rx_xcorr( output ssp_frame, ssp_din, ssp_clk; input cross_hi, cross_lo; output dbg; - input xcorr_is_848, snoop, xcorr_quarter_freq; + input snoop; // Carrier is steady on through this, unless we're snooping. assign pwr_hi = ck_1356megb & (~snoop); assign pwr_oe1 = 1'b0; -assign pwr_oe2 = 1'b0; assign pwr_oe3 = 1'b0; assign pwr_oe4 = 1'b0; -reg ssp_clk; -reg ssp_frame; - -reg fc_div_2; -always @(posedge ck_1356meg) - fc_div_2 = ~fc_div_2; - -reg fc_div_4; -always @(posedge fc_div_2) - fc_div_4 = ~fc_div_4; - -reg fc_div_8; -always @(posedge fc_div_4) - fc_div_8 = ~fc_div_8; - -reg adc_clk; - -always @(xcorr_is_848 or xcorr_quarter_freq or ck_1356meg) - if(~xcorr_quarter_freq) - begin - if(xcorr_is_848) - // The subcarrier frequency is fc/16; we will sample at fc, so that - // means the subcarrier is 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 ... - adc_clk <= ck_1356meg; - else - // The subcarrier frequency is fc/32; we will sample at fc/2, and - // the subcarrier will look identical. - adc_clk <= fc_div_2; - end - else - begin - if(xcorr_is_848) - // The subcarrier frequency is fc/64 - adc_clk <= fc_div_4; - else - // The subcarrier frequency is fc/128 - adc_clk <= fc_div_8; - end +wire adc_clk = ck_1356megb; // When we're a reader, we just need to do the BPSK demod; but when we're an // eavesdropper, we also need to pick out the commands sent by the reader, // using AM. Do this the same way that we do it for the simulated tag. -reg after_hysteresis, after_hysteresis_prev; +reg after_hysteresis, after_hysteresis_prev, after_hysteresis_prev_prev; reg [11:0] has_been_low_for; always @(negedge adc_clk) begin @@ -97,7 +59,6 @@ end // Let us report a correlation every 4 subcarrier cycles, or 4*16 samples, // so we need a 6-bit counter. reg [5:0] corr_i_cnt; -reg [5:0] corr_q_cnt; // And a couple of registers in which to accumulate the correlations. // we would add at most 32 times adc_d, the result can be held in 13 bits. // Need one additional bit because it can be negative as well @@ -105,32 +66,38 @@ reg signed [13:0] corr_i_accum; reg signed [13:0] corr_q_accum; reg signed [7:0] corr_i_out; reg signed [7:0] corr_q_out; +// clock and frame signal for communication to ARM +reg ssp_clk; +reg ssp_frame; + + // ADC data appears on the rising edge, so sample it on the falling edge always @(negedge adc_clk) begin + corr_i_cnt <= corr_i_cnt + 1; + // These are the correlators: we correlate against in-phase and quadrature // versions of our reference signal, and keep the (signed) result to // send out later over the SSP. - if(corr_i_cnt == 7'd63) + if(corr_i_cnt == 7'd0) begin if(snoop) begin - // highest 7 significant bits of tag signal (signed), 1 bit reader signal: - corr_i_out <= {corr_i_accum[13:7], after_hysteresis_prev}; - corr_q_out <= {corr_q_accum[13:7], after_hysteresis}; + // 7 most significant bits of tag signal (signed), 1 bit reader signal: + corr_i_out <= {corr_i_accum[13:7], after_hysteresis_prev_prev}; + corr_q_out <= {corr_q_accum[13:7], after_hysteresis_prev}; + after_hysteresis_prev_prev <= after_hysteresis; end else begin - // highest 8 significant bits of tag signal + // 8 most significant bits of tag signal corr_i_out <= corr_i_accum[13:6]; corr_q_out <= corr_q_accum[13:6]; end corr_i_accum <= adc_d; corr_q_accum <= adc_d; - corr_q_cnt <= 4; - corr_i_cnt <= 0; end else begin @@ -139,13 +106,11 @@ begin else corr_i_accum <= corr_i_accum + adc_d; - if(corr_q_cnt[3]) - corr_q_accum <= corr_q_accum - adc_d; - else + if(corr_i_cnt[3] == corr_i_cnt[2]) // phase shifted by pi/2 corr_q_accum <= corr_q_accum + adc_d; + else + corr_q_accum <= corr_q_accum - adc_d; - corr_i_cnt <= corr_i_cnt + 1; - corr_q_cnt <= corr_q_cnt + 1; end // The logic in hi_simulate.v reports 4 samples per bit. We report two @@ -172,7 +137,7 @@ begin end // set ssp_frame signal for corr_i_cnt = 0..3 and corr_i_cnt = 32..35 - // (two frames with 8 Bits each) + // (send two frames with 8 Bits each) if(corr_i_cnt[5:2] == 4'b0000 || corr_i_cnt[5:2] == 4'b1000) ssp_frame = 1'b1; else @@ -186,5 +151,6 @@ assign dbg = corr_i_cnt[3]; // Unused. assign pwr_lo = 1'b0; +assign pwr_oe2 = 1'b0; endmodule From d5875804a3555b9d6305a4c9dcdbfeac380d9f00 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 18 Jun 2015 07:56:08 +0200 Subject: [PATCH 5/9] fixing iso14443b (issue #103): fix: don't waste time to calculate parity bits. Instead add void parity bits to trace and ignore them on client side --- armsrc/iso14443b.c | 11 +++++------ client/cmdhf.c | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index f598df3c..989b477c 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -17,7 +17,6 @@ #include "iso14443crc.h" #define RECEIVE_SAMPLES_TIMEOUT 2000 -#define ISO14443B_DMA_BUFFER_SIZE 512 //============================================================================= // An ISO 14443 Type B tag. We listen for commands from the reader, using @@ -768,7 +767,7 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) //Tracing if (tracing && Demod.len > 0) { uint8_t parity[MAX_PARITY_SIZE]; - GetParity(Demod.output, Demod.len, parity); + //GetParity(Demod.output, Demod.len, parity); LogTrace(Demod.output, Demod.len, 0, 0, parity, FALSE); } } @@ -1156,7 +1155,7 @@ void RAMFUNC SnoopIso14443b(void) if (!TagIsActive) { // no need to try decoding reader data if the tag is sending if(Handle14443bUartBit(ci & 0x01)) { if(triggered && tracing) { - GetParity(Uart.output, Uart.byteCnt, parity); + //GetParity(Uart.output, Uart.byteCnt, parity); LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE); } /* And ready to receive another command. */ @@ -1167,7 +1166,7 @@ void RAMFUNC SnoopIso14443b(void) } if(Handle14443bUartBit(cq & 0x01)) { if(triggered && tracing) { - GetParity(Uart.output, Uart.byteCnt, parity); + //GetParity(Uart.output, Uart.byteCnt, parity); LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE); } /* And ready to receive another command. */ @@ -1186,7 +1185,7 @@ void RAMFUNC SnoopIso14443b(void) if(tracing) { uint8_t parity[MAX_PARITY_SIZE]; - GetParity(Demod.output, Demod.len, parity); + //GetParity(Demod.output, Demod.len, parity); LogTrace(Demod.output, Demod.len, samples, samples, parity, FALSE); } triggered = TRUE; @@ -1194,7 +1193,7 @@ void RAMFUNC SnoopIso14443b(void) // And ready to receive another response. DemodReset(); } - TagIsActive = (Demod.state > DEMOD_PHASE_REF_TRAINING); + TagIsActive = (Demod.state > DEMOD_GOT_FALLING_EDGE_OF_SOF); } } diff --git a/client/cmdhf.c b/client/cmdhf.c index 16f7bb0f..fc6127c2 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -378,7 +378,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui oddparity ^= (((frame[j] & 0xFF) >> k) & 0x01); } uint8_t parityBits = parityBytes[j>>3]; - if (isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { + if (protocol != ISO_14443B && isResponse && (oddparity != ((parityBits >> (7-(j&0x0007))) & 0x01))) { snprintf(line[j/16]+(( j % 16) * 4),110, "%02x! ", frame[j]); } else { From 132a02179cfad11fbf484b191544fb3c8475eda8 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 18 Jun 2015 09:49:22 +0200 Subject: [PATCH 6/9] fixing iso 14443b (issue #103): - fix: treat empty commands as error - deleting dead code - rename USB-Commands (ISO14443 -> iso14443B) --- armsrc/appmain.c | 60 +-------------- armsrc/iso14443b.c | 70 +++++++---------- client/cmdhf14b.c | 144 ++--------------------------------- client/hid-flasher/usb_cmd.h | 6 +- client/lualibs/commands.lua | 6 +- include/usb_cmd.h | 6 +- 6 files changed, 42 insertions(+), 250 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 9bfa5ea7..fb3c0f18 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -250,55 +250,6 @@ void MeasureAntennaTuningHf(void) } -void SimulateTagHfListen(void) -{ - // ToDo: historically this used the free buffer, which was 2744 Bytes long. - // There might be a better size to be defined: - #define HF_14B_SNOOP_BUFFER_SIZE 2744 - uint8_t *dest = BigBuf_malloc(HF_14B_SNOOP_BUFFER_SIZE); - uint8_t v = 0; - int i; - int p = 0; - - // We're using this mode just so that I can test it out; the simulated - // tag mode would work just as well and be simpler. - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_SNOOP); - - // We need to listen to the high-frequency, peak-detected path. - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - FpgaSetupSsc(); - - i = 0; - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0xff; - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - uint8_t r = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - - v <<= 1; - if(r & 1) { - v |= 1; - } - p++; - - if(p >= 8) { - dest[i] = v; - v = 0; - p = 0; - i++; - - if(i >= HF_14B_SNOOP_BUFFER_SIZE) { - break; - } - } - } - } - DbpString("simulate tag (now type bitsamples)"); -} - void ReadMem(int addr) { const uint8_t *data = ((uint8_t *)addr); @@ -782,19 +733,16 @@ void UsbPacketReceived(uint8_t *packet, int len) #endif #ifdef WITH_ISO14443b - case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443: - AcquireRawAdcSamplesIso14443b(c->arg[0]); - break; case CMD_READ_SRI512_TAG: ReadSTMemoryIso14443b(0x0F); break; case CMD_READ_SRIX4K_TAG: ReadSTMemoryIso14443b(0x7F); break; - case CMD_SNOOP_ISO_14443: + case CMD_SNOOP_ISO_14443B: SnoopIso14443b(); break; - case CMD_SIMULATE_TAG_ISO_14443: + case CMD_SIMULATE_TAG_ISO_14443B: SimulateIso14443bTag(); break; case CMD_ISO_14443B_COMMAND: @@ -911,10 +859,6 @@ void UsbPacketReceived(uint8_t *packet, int len) break; #endif - case CMD_SIMULATE_TAG_HF_LISTEN: - SimulateTagHfListen(); - break; - case CMD_BUFF_CLEAR: BigBuf_Clear(); break; diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 989b477c..80f93678 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -237,7 +237,11 @@ static int Handle14443bUartBit(int bit) } else if(Uart.shiftReg == 0x000) { // this is an EOF byte LED_A_OFF(); // Finished receiving - return TRUE; + if (Uart.byteCnt != 0) { + return TRUE; + } + Uart.posCnt = 0; + Uart.state = STATE_ERROR_WAIT; } else { // this is an error Uart.posCnt = 0; @@ -714,16 +718,16 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE); // The DMA buffer, used to stream samples from the FPGA - int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); + int8_t *dmaBuf = (int8_t*) BigBuf_malloc(DMA_BUFFER_SIZE); // Set up the demodulator for tag -> reader responses. DemodInit(receivedResponse); // Setup and start DMA. - FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); + FpgaSetupSscDma((uint8_t*) dmaBuf, DMA_BUFFER_SIZE); int8_t *upTo = dmaBuf; - lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; + lastRxCounter = DMA_BUFFER_SIZE; // Signal field is ON with the appropriate LED: LED_D_ON(); @@ -734,18 +738,18 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR; if(behindBy > max) max = behindBy; - while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1)) > 2) { + while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE-1)) > 2) { ci = upTo[0]; cq = upTo[1]; upTo += 2; - if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { + if(upTo >= dmaBuf + DMA_BUFFER_SIZE) { upTo = dmaBuf; AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; } lastRxCounter -= 2; if(lastRxCounter <= 0) { - lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; + lastRxCounter += DMA_BUFFER_SIZE; } samples += 2; @@ -880,22 +884,6 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) } -//----------------------------------------------------------------------------- -// Read an ISO 14443B tag. We send it some set of commands, and record the -// responses. -// The command name is misleading, it actually decodes the reponse in HEX -// into the output buffer (read the result using hexsamples, not hisamples) -// -// obsolete function only for test -//----------------------------------------------------------------------------- -void AcquireRawAdcSamplesIso14443b(uint32_t parameter) -{ - uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; // REQB with AFI=0, Request All, N=0 - - SendRawCommand14443B(sizeof(cmd1),1,1,cmd1); -} - - /** Convenience function to encode, transmit and trace iso 14443b comms **/ @@ -956,7 +944,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) DbpString("No response from tag"); return; } else { - Dbprintf("Randomly generated UID from tag (+ 2 byte CRC): %x %x %x", + Dbprintf("Randomly generated UID from tag (+ 2 byte CRC): %02x %02x %02x", Demod.output[0], Demod.output[1], Demod.output[2]); } // There is a response, SELECT the uid @@ -981,7 +969,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) } // Check response from the tag: should be the same UID as the command we just sent: if (cmd1[1] != Demod.output[0]) { - Dbprintf("Bad response to SELECT from Tag, aborting: %x %x", cmd1[1], Demod.output[0]); + Dbprintf("Bad response to SELECT from Tag, aborting: %02x %02x", cmd1[1], Demod.output[0]); return; } // Tag is now selected, @@ -1000,7 +988,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) // The check the CRC of the answer (use cmd1 as temporary variable): ComputeCrc14443(CRC_14443_B, Demod.output, 8, &cmd1[2], &cmd1[3]); if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) { - Dbprintf("CRC Error reading block! - Below: expected, got %x %x", + Dbprintf("CRC Error reading block! Expected: %04x got: %04x", (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]); // Do not return;, let's go on... (we should retry, maybe ?) } @@ -1009,7 +997,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]); // Now loop to read all 16 blocks, address from 0 to last block - Dbprintf("Tag memory dump, block 0 to %d",dwLast); + Dbprintf("Tag memory dump, block 0 to %d", dwLast); cmd1[0] = 0x08; i = 0x00; dwLast++; @@ -1032,12 +1020,12 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) // The check the CRC of the answer (use cmd1 as temporary variable): ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]); if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) { - Dbprintf("CRC Error reading block! - Below: expected, got %x %x", + Dbprintf("CRC Error reading block! Expected: %04x got: %04x", (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]); // Do not return;, let's go on... (we should retry, maybe ?) } // Now print out the memory location: - Dbprintf("Address=%x, Contents=%x, CRC=%x", i, + Dbprintf("Address=%02x, Contents=%08x, CRC=%04x", i, (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0], (Demod.output[4]<<8)+Demod.output[5]); if (i == 0xff) { @@ -1062,7 +1050,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) * Memory usage for this function, (within BigBuf) * Last Received command (reader->tag) - MAX_FRAME_SIZE * Last Received command (tag->reader) - MAX_FRAME_SIZE - * DMA Buffer - ISO14443B_DMA_BUFFER_SIZE + * DMA Buffer - DMA_BUFFER_SIZE * Demodulated samples received - all the rest */ void RAMFUNC SnoopIso14443b(void) @@ -1079,7 +1067,7 @@ void RAMFUNC SnoopIso14443b(void) set_tracing(TRUE); // The DMA buffer, used to stream samples from the FPGA - int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); + int8_t *dmaBuf = (int8_t*) BigBuf_malloc(DMA_BUFFER_SIZE); int lastRxCounter; int8_t *upTo; int ci, cq; @@ -1097,7 +1085,7 @@ void RAMFUNC SnoopIso14443b(void) Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); Dbprintf(" Reader -> tag: %i bytes", MAX_FRAME_SIZE); Dbprintf(" tag -> Reader: %i bytes", MAX_FRAME_SIZE); - Dbprintf(" DMA: %i bytes", ISO14443B_DMA_BUFFER_SIZE); + Dbprintf(" DMA: %i bytes", DMA_BUFFER_SIZE); // Signal field is off, no reader signal, no tag signal LEDsoff(); @@ -1109,8 +1097,8 @@ void RAMFUNC SnoopIso14443b(void) // Setup for the DMA. FpgaSetupSsc(); upTo = dmaBuf; - lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; - FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); + lastRxCounter = DMA_BUFFER_SIZE; + FpgaSetupSscDma((uint8_t*) dmaBuf, DMA_BUFFER_SIZE); uint8_t parity[MAX_PARITY_SIZE]; bool TagIsActive = FALSE; @@ -1119,7 +1107,7 @@ void RAMFUNC SnoopIso14443b(void) // And now we loop, receiving samples. for(;;) { int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & - (ISO14443B_DMA_BUFFER_SIZE-1); + (DMA_BUFFER_SIZE-1); if(behindBy > maxBehindBy) { maxBehindBy = behindBy; } @@ -1130,14 +1118,14 @@ void RAMFUNC SnoopIso14443b(void) cq = upTo[1]; upTo += 2; lastRxCounter -= 2; - if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { + if(upTo >= dmaBuf + DMA_BUFFER_SIZE) { upTo = dmaBuf; - lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; + lastRxCounter += DMA_BUFFER_SIZE; AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; WDT_HIT(); - if(behindBy > (9*ISO14443B_DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not? - Dbprintf("blew circular buffer! behindBy=0x%x", behindBy); + if(behindBy > (9*DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not? + Dbprintf("blew circular buffer! behindBy=%d", behindBy); break; } if(!tracing) { diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index 21a4e179..496267cd 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -25,154 +25,23 @@ static int CmdHelp(const char *Cmd); -int CmdHF14BDemod(const char *Cmd) -{ - int i, j, iold; - int isum, qsum; - int outOfWeakAt; - bool negateI, negateQ; - - uint8_t data[256]; - int dataLen = 0; - - // As received, the samples are pairs, correlations against I and Q - // square waves. So estimate angle of initial carrier (or just - // quadrant, actually), and then do the demod. - - // First, estimate where the tag starts modulating. - for (i = 0; i < GraphTraceLen; i += 2) { - if (abs(GraphBuffer[i]) + abs(GraphBuffer[i + 1]) > 40) { - break; - } - } - if (i >= GraphTraceLen) { - PrintAndLog("too weak to sync"); - return 0; - } - PrintAndLog("out of weak at %d", i); - outOfWeakAt = i; - - // Now, estimate the phase in the initial modulation of the tag - isum = 0; - qsum = 0; - for (; i < (outOfWeakAt + 16); i += 2) { - isum += GraphBuffer[i + 0]; - qsum += GraphBuffer[i + 1]; - } - negateI = (isum < 0); - negateQ = (qsum < 0); - - // Turn the correlation pairs into soft decisions on the bit. - j = 0; - for (i = 0; i < GraphTraceLen / 2; i++) { - int si = GraphBuffer[j]; - int sq = GraphBuffer[j + 1]; - if (negateI) si = -si; - if (negateQ) sq = -sq; - GraphBuffer[i] = si + sq; - j += 2; - } - GraphTraceLen = i; - - i = outOfWeakAt / 2; - while (GraphBuffer[i] > 0 && i < GraphTraceLen) - i++; - if (i >= GraphTraceLen) goto demodError; - - iold = i; - while (GraphBuffer[i] < 0 && i < GraphTraceLen) - i++; - if (i >= GraphTraceLen) goto demodError; - if ((i - iold) > 23) goto demodError; - - PrintAndLog("make it to demod loop"); - - for (;;) { - iold = i; - while (GraphBuffer[i] >= 0 && i < GraphTraceLen) - i++; - if (i >= GraphTraceLen) goto demodError; - if ((i - iold) > 6) goto demodError; - - uint16_t shiftReg = 0; - if (i + 20 >= GraphTraceLen) goto demodError; - - for (j = 0; j < 10; j++) { - int soft = GraphBuffer[i] + GraphBuffer[i + 1]; - - if (abs(soft) < (abs(isum) + abs(qsum)) / 20) { - PrintAndLog("weak bit"); - } - - shiftReg >>= 1; - if(GraphBuffer[i] + GraphBuffer[i+1] >= 0) { - shiftReg |= 0x200; - } - - i+= 2; - } - - if ((shiftReg & 0x200) && !(shiftReg & 0x001)) - { - // valid data byte, start and stop bits okay - PrintAndLog(" %02x", (shiftReg >> 1) & 0xff); - data[dataLen++] = (shiftReg >> 1) & 0xff; - if (dataLen >= sizeof(data)) { - return 0; - } - } else if (shiftReg == 0x000) { - // this is EOF - break; - } else { - goto demodError; - } - } - - uint8_t first, second; - ComputeCrc14443(CRC_14443_B, data, dataLen-2, &first, &second); - PrintAndLog("CRC: %02x %02x (%s)\n", first, second, - (first == data[dataLen-2] && second == data[dataLen-1]) ? - "ok" : "****FAIL****"); - - RepaintGraphWindow(); - return 0; - -demodError: - PrintAndLog("demod error"); - RepaintGraphWindow(); - return 0; -} - int CmdHF14BList(const char *Cmd) { PrintAndLog("Deprecated command, use 'hf list 14b' instead"); return 0; } -int CmdHF14BRead(const char *Cmd) -{ - UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443, {strtol(Cmd, NULL, 0), 0, 0}}; - SendCommand(&c); - return 0; -} -int CmdHF14Sim(const char *Cmd) +int CmdHF14BSim(const char *Cmd) { - UsbCommand c={CMD_SIMULATE_TAG_ISO_14443}; - SendCommand(&c); - return 0; -} - -int CmdHFSimlisten(const char *Cmd) -{ - UsbCommand c = {CMD_SIMULATE_TAG_HF_LISTEN}; + UsbCommand c={CMD_SIMULATE_TAG_ISO_14443B}; SendCommand(&c); return 0; } int CmdHF14BSnoop(const char *Cmd) { - UsbCommand c = {CMD_SNOOP_ISO_14443}; + UsbCommand c = {CMD_SNOOP_ISO_14443B}; SendCommand(&c); return 0; } @@ -387,12 +256,9 @@ int CmdHF14BWrite( const char *Cmd){ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"demod", CmdHF14BDemod, 1, "Demodulate ISO14443 Type B from tag"}, {"list", CmdHF14BList, 0, "[Deprecated] List ISO 14443b history"}, - {"read", CmdHF14BRead, 0, "Read HF tag (ISO 14443)"}, - {"sim", CmdHF14Sim, 0, "Fake ISO 14443 tag"}, - {"simlisten", CmdHFSimlisten, 0, "Get HF samples as fake tag"}, - {"snoop", CmdHF14BSnoop, 0, "Eavesdrop ISO 14443"}, + {"sim", CmdHF14BSim, 0, "Fake ISO 14443B tag"}, + {"snoop", CmdHF14BSnoop, 0, "Eavesdrop ISO 14443B"}, {"sri512read", CmdSri512Read, 0, "Read contents of a SRI512 tag"}, {"srix4kread", CmdSrix4kRead, 0, "Read contents of a SRIX4K tag"}, {"raw", CmdHF14BCmdRaw, 0, "Send raw hex data to tag"}, diff --git a/client/hid-flasher/usb_cmd.h b/client/hid-flasher/usb_cmd.h index c5b91f99..b3a7f4ec 100644 --- a/client/hid-flasher/usb_cmd.h +++ b/client/hid-flasher/usb_cmd.h @@ -89,7 +89,6 @@ typedef struct { // For the 13.56 MHz tags #define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 0x0300 -#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443 0x0301 #define CMD_READ_SRI512_TAG 0x0303 #define CMD_READ_SRIX4K_TAG 0x0304 #define CMD_READER_ISO_15693 0x0310 @@ -105,9 +104,8 @@ typedef struct { #define CMD_SIMULATE_HITAG 0x0371 #define CMD_READER_HITAG 0x0372 -#define CMD_SIMULATE_TAG_HF_LISTEN 0x0380 -#define CMD_SIMULATE_TAG_ISO_14443 0x0381 -#define CMD_SNOOP_ISO_14443 0x0382 +#define CMD_SIMULATE_TAG_ISO_14443B 0x0381 +#define CMD_SNOOP_ISO_14443B 0x0382 #define CMD_SNOOP_ISO_14443a 0x0383 #define CMD_SIMULATE_TAG_ISO_14443a 0x0384 #define CMD_READER_ISO_14443a 0x0385 diff --git a/client/lualibs/commands.lua b/client/lualibs/commands.lua index 678c745e..4c7bc638 100644 --- a/client/lualibs/commands.lua +++ b/client/lualibs/commands.lua @@ -59,7 +59,6 @@ local _commands = { --// For the 13.56 MHz tags CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 = 0x0300, - CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443 = 0x0301, CMD_READ_SRI512_TAG = 0x0303, CMD_READ_SRIX4K_TAG = 0x0304, CMD_READER_ISO_15693 = 0x0310, @@ -76,9 +75,8 @@ local _commands = { CMD_SIMULATE_HITAG = 0x0371, CMD_READER_HITAG = 0x0372, - CMD_SIMULATE_TAG_HF_LISTEN = 0x0380, - CMD_SIMULATE_TAG_ISO_14443 = 0x0381, - CMD_SNOOP_ISO_14443 = 0x0382, + CMD_SIMULATE_TAG_ISO_14443B = 0x0381, + CMD_SNOOP_ISO_14443B = 0x0382, CMD_SNOOP_ISO_14443a = 0x0383, CMD_SIMULATE_TAG_ISO_14443a = 0x0384, CMD_READER_ISO_14443a = 0x0385, diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 357395d4..132e1805 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -100,7 +100,6 @@ typedef struct{ // For the 13.56 MHz tags #define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 0x0300 -#define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_14443 0x0301 #define CMD_READ_SRI512_TAG 0x0303 #define CMD_READ_SRIX4K_TAG 0x0304 #define CMD_ISO_14443B_COMMAND 0x0305 @@ -118,9 +117,8 @@ typedef struct{ #define CMD_SIMULATE_HITAG 0x0371 #define CMD_READER_HITAG 0x0372 -#define CMD_SIMULATE_TAG_HF_LISTEN 0x0380 -#define CMD_SIMULATE_TAG_ISO_14443 0x0381 -#define CMD_SNOOP_ISO_14443 0x0382 +#define CMD_SIMULATE_TAG_ISO_14443B 0x0381 +#define CMD_SNOOP_ISO_14443B 0x0382 #define CMD_SNOOP_ISO_14443a 0x0383 #define CMD_SIMULATE_TAG_ISO_14443a 0x0384 #define CMD_READER_ISO_14443a 0x0385 From da586b170276fd44963ec4a8934beaf563feb132 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 18 Jun 2015 15:30:56 +0200 Subject: [PATCH 7/9] fixing iso14443b (issue #103): - revert removal of FPGA_HF_READER_RX_XCORR_848_KHZ. Need to be able to switch to 424kHz for ISO15693. --- armsrc/iso14443b.c | 8 ++++---- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/fpga_hf.v | 8 +++++--- fpga/hi_read_rx_xcorr.v | 20 +++++++++++++++++--- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 80f93678..8d1a5cca 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -732,7 +732,7 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) // Signal field is ON with the appropriate LED: LED_D_ON(); // And put the FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); for(;;) { int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR; @@ -929,7 +929,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) // Signal field is on with the appropriate LED LED_D_ON(); FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); SpinDelay(200); // First command: wake up the tag using the INITIATE command @@ -1091,7 +1091,7 @@ void RAMFUNC SnoopIso14443b(void) LEDsoff(); // And put the FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_SNOOP); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Setup for the DMA. @@ -1228,7 +1228,7 @@ void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, u */ // if(!GETBIT(GPIO_LED_D)) { // if field is off - // FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + // FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); // // Signal field is on with the appropriate LED // LED_D_ON(); // SpinDelay(200); diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 717dad13eb67e5ef2cfeb39da3c4a0f6e9e04fd3..49bec2242cb7720524289f3eba1397bbc2a22867 100644 GIT binary patch literal 42175 zcmeIb4RjpUl`gvLR7;e*Tkf)KGXe}LwPeybZMiKO;}}^wmIV>P2}*_}zVldf8$$9t zxlFDg_sw%=ax+IiVEG5!fak`!!{j!`nQ;xgC~CcXb7GH#{WU+ntd zZ~gaczqqjLj$1$fh1(mx{Q2AIHi|ZWr781QcP`Fk=<^h7%q+foQD*6)#mne+nz8um z<&D=YZ)&115bfwXhoA3$^D|$}kTQtqqKuK{|5_QtF-Wy8%#h3foBZF;$PoHV|J%rr zq)w{;JXPD={d;~QO8?@I7-N{f=Mi4F_Z;y@jH&)ZV|9Sua7t!7C z*_5Rksw6}C4aysL(2XP%mT*`<$E`R==j^5#RnokIeon20#FY6}=jZurxG_mx{2*md zs6AcD9kf$iNt;wdA+}dsrv68E0XGVf43FurI7~y>n;CZH9rPfj-B{-O4&%X^dNjmw zLqErz`zQ@jlB}H<*V86yaAN}^Mc<Kj(h)5FR+_ zJ;&i!jZ~!RS(Qv#mS|90FrS%Q#c8pHl02UiI6(L*RIH|cmdN|{7W52I}|OMXG8o`1Hp>J{@9Iwf25oarYSG;-!ID!ceOH5FrYkeXzo(_DfE zel=>og9Zf5na_LswahM1KlCD|go8!{Hwwz{dC8OAsu;#p^O#|j=bYlH4vTK`=j^>} zZlBm-K;&(r9_!P<%Q774_GS0>B0pyb9W;{vXX3wNoe$D-nfM2jXQ<~h?&(*GcF=FA zrR|7~EjUG2V5&xePSGQzdrSY90R_96xS>dmF+cFd~mjSPu9+}I59l6b^BV~2|R#m6{ZusVfJ zd+0CSXqPxl->_@>JdgX&v0B9X{uPB(N9+Omomx>ybeKO^zgABa66?%2J^ivS|9;{0 zN*qxIk6}7it=U3H_BXLTbiMuB3H{nl3p--B z30v;5p z%3gBN5F_5c@0|NIR=#CC5s4)oo^vc`rs;@h$NYCGf=ys?RBxdu*I`&uEmwguycdQ& zEsm%a9k;;V(C?_p#W_4nFVMAYGu?JQraN*6ZKN+A@93{g(o<{(cborR8(}C>LE8Kr zh5hQUZBYH2+v*}u(QRxhC#cuZHoV~Ng+*~v5XT}xFdzjMXS47?p{QSEeGPAKa8oMk zV9wfnO+&8byeY1yU-`?YY1+7kUap`K^b3fl zH$@~3?_IMVrNMOa25TS*{jwIgn|49=r#v9bc>6AaU#B8XD(=P_#o^ASZepA1?@q?F zOZatGJ=^^sC(V;`O2NDzHGLps{F1!Rj9)L*G`oO_e*1V9%fkEaAKFn*zZkzZs0O!V z0Q!EkW2qY(Y+LC1^9kXXa?|PtXdUI%IOK}XEXq~FFL96hj|FRnh{|uMFBD?82q2nT zcpiQ|N6qTq+S&c$I4v7a*k;`N4K;`H>vC^*KK!~lWuIf%>SVdh1n<|Vr(cX;Q@2&B z$TstKI^|$}Z1d5gTp|1#oZ~1fQ$0^SVga@~#XL`m%JHk`3k7S9_@vmQ<`-gX1S6WB za|yp_=vJq&cA1FNBNDJ>qv7vq7{5lA=Hide{tG&7Kdu0*Kr|1?Lihy}SD)zabscT% z`pf{x0{j}od0s9Xa;wHX{K`e^B{WxFRE}T5>9lg<7qHLUJwyG3XQ)f~Mcp>=Yf?> zZZ+SqPRSMtn}AKhoJ06!jG?D_ZN;|dzDNi2dJKAm9`n4X7mQzf0b5p|a5^>%55IH| zfGmVxm|^FPPH{8cZR@EX4(9CHsG7Nu)M{wAj*1q#S2f5Rf!%gdb|1gy;_YtBnyPIk z=A&BVP1|71{W%x$%h&-QsU^F`jxl~=st=hHbNn%3{BoOVbB{?dpUVMTvD=F4Q^c9enCFa#RwBN(877r8( zVf=ccqd{G^t*w@R0^1Uc!?FKYw$J$hzl=2PRbSqBnZj1W#d2fY+R{?nOpNjID-x$c zO1qcQ$F0bNELSdy%|#FP)b|gm>T7&jR7{x;jWB)%_BkKm*Cm*91ak&{MKn)w&13Xy z`jDF_1o(yh0$SC^r_6V0ST$wiN6qCxo@*#RY6keF(aN#dm4$QbS{ZNh&b`}23BR!N z4KkGx>?k_k7=_7Oc7R{tUr*7O3D0rG_tbV54J?9{bT{OBLilxtnvM7XT=at@jbrg$ zF^fhzms0%iVj=v3IQ6jVlk_vtu0>Pu`KMGfEvhNwU#xmKt8hg$zNctJHV((P;yDiM z1>+Z1p4huU1AC$8L&-uSCmOxI(EN+i)ljQpm_Z&Bo#AYvJoP)#WuAU%{-qWsp;rG) zKgiXN#lBj3X?DGOxIVU4Sl)A(fB9%N4E5BsE7ivQEAE)pf~P}LMC&Obj z|Dt9EZA#I5vTfWV95(J0HLgWNc<*BV#nw2rRlGqPT&Ghvuqj=S=FF_mzasT|jHSoOWT$RCL3M4` zsHpVz!iq#-`5UA)2YU*zlQ^QoD<5-eB@nI6V6kZLjI5q>oXpqT71kr(ZMrn&G+JqQ zQ-i7P>bA>yhOIL3fH~H4mRj2qpEggbQ{&IHpO0UyEY5t|M~$8F`^^X)luZ))Rq5?l z5x=T7Mw31LYA}`Rk2Y@a&nH!t68CwsGyh_QwLaZ5hwe_*c3`S=6f-hRUKm|GXN_Nw zYlbZ_rgJ`vGlvyc&d7;-yuHXXeo@O^m`}X}+LeuOGnt5Gy3mvI`IoVS$8p<$GWMNnB1_X#S}6pTsf;frU04Y@dJaw60*<Ua+$G@P1QcSMgY}Jt^d;XdEmxNs8=@;V{WG}!= zaY;#sKv;&Mr`XdLVR`$$6E+k2{?C}qt#fvFnbw*tVsa^nmxNQX;Qn^W$-WSDN2uy6vQ$R%sLgzwl#|_=61H& zPLY3Uo9S9`FWF|w8*{=zJSwTj6!pvVa&a;v7?YR4F9&iVij~1x<)cbebqAd>TEGlo z$EIMu66$01JRcb!h>@pX%)fltn#7z}5P<9?_sA_J{ssJ+rXeRW+50XXF`5jF$*_PF zA1(2(x1l?YGWL)-9@(UlPOL{Hfx=103gZ_rx8B{90mkuEWAM0W01Ze{xcX{}g8Ah~lSTc|ykQi6{?IjBMbty*SN8^``upxLQZ__Y4y9=JVFnHs^di>McTVM7B<$)xMfT+zyV7O+>xp5&%{N88^TY@MC@1QBuwS=! zt;6io*~-r=@-Wjr_>;A z?l+ytRKCTD_d}0I)S$C@B#0j}ehs(Yn%EjU=^6Zo=nXn0VfnX)ewdqmGWufw z@-NLiYA)@0G2g_7vC_i}jbA&r6MMPTFO#;_m(3&Md=p0c& z-H-w(T*5DFmz}(s^^3kqSSSuGY#_l4RY_SsV;aA*jS@5brTPgimosx_MdSt=l<8b7 z<=N+y0sciTD-#2=$8xVzvrK3rCb&_CU$PpoRaXFhA*|YC)(SY%ytz@RJ$_OZz^|j* zcUn8dPv|};sba^)wW^1b{or3wPcJxrxXX2J-B~GKa`9l{e-Q z+^~YxE>1c<1`amk@;^xg7P3G_$?szPdPg;74|kYH=|JD&LSk8LCjAS?4^y!Po_<-E zKT4-8nD=`gJZ!VGqyhS;v~(YUEX==DYhmVyd7Azf4H%g#=-1pBH$(Bm#}PKPR(|@& z>UoYIeo9;}*E>2$7~)@#(IPi0#Zl-We$~Zuj_5IA{$-_q0@!*HK0oLQ2efsdz9AXJ z4}o7+OXtkZ=0xOgM9V&4Q<^mYO7({L*SVD~?oE%t&3HjVuC3-9+BiV25PnUl*3S5t zxy<=3^RG#B9vyL7M-l~5!Y_InKGMee{okV}T=?n_A)cTUM)@-Qs%dchbCt;%PxK>f zxEEWXlRb zdHc@sL%LkTN=y>`Ll^GuNp47h@7l^P-gnmk|8kqM2=g||A9~xgf{x^O<>QDS8r~S> zzn*fEhs-=|f+vpob@zYtCG*j};9m|uXQbkAe#mh~FvEIp3!G?N_1Z}V$F(=v}e39=!{wp~U9S|k{WuKws7*_tn&cPhSL81q8WpXh1<^0Qq6xz;n;~4e} zOf$%Tb#nd-t5KCV(+YkjmZg`UGdKVXIa-{v_9gbgElgkwz?XL*@Uk9?mJ0G;;}xqF zd=httBQC-jt9Ng7lAH|U=$!E5hXV#j3l|lv@dXzUNS6h*rWc3v7boYBu|aEilV@?D6woM4bNu|MKI99TmfLw^iF_b@njr((%J~?8TK5{^5R4ziQ_86;XID zU`yw}B4}LMF$1y({7dkBEM8}wkIR|2qh~kI$B!Sb1%6=*ZcpUu#+1Jo1$u{;vs`8T zORq)-_@!aXvC*)wKB4&GlLQOk@h{+40lxZ1qi*|x0=Sjr^UU})q;SSSyZC6iv3@aA zvVKA10{(>*lB{LgbqQ@zz^`^O55$KFLYRNOr-qnzA&{tc6=GAdE4Cj{yYf|`_+b#) zo+z64w_NZPHS>J@$|5Dfw5zp{7%^Muf2wQp@eqD(1D-CFfUQxv-d;EyTWQ`R*VDsP zl@%fULXJ#;f4vLZrSWSXeFJlbRtESrLIZ^Oj}kwG$lAQG=0zBQ>|y+ZUc?4wzez8s z7IzEq3yJT{1JJJkzt}~GsRZrnIb)--!#vDAsvN)GgN2;OwCf0C!D+JrvAEWrc%c|S zRFQRBOKS?E*@L8p>PP9P-3^1_%Y_pELJVYODksR+HasWN@_SB09=lxd_SA}4UaY`| zUE`X87>Uh@+oTmNiLYObU#wP^nq4nm5SVk$Y!-~muxzf`$!8;f`4sT06_hIW3j6bn zU$BQlTgdTB51TlC=v?c>C(WhSv}%2QCX*VEf0?29;j_If`FD*0%Cdfi`4=Uf{(;IzX<5In-zYeHEjWq+|03kS&d@Tl3!mBkMs*W~Qogu~`0 zCVx0B-=b@W%lX$CIj9nk>-;<9;-CTWT_JE6iXRSHsNcA&XCD2y61sDjI1Ih0A;Nc=7cQJk~spjW6u6~Zj6fb_*luP7iFQB&-ROZ{} zxHzN+6^K|Ueh9RxP7v^Gjm84g#p!LPL>d1=w2&?2d^*^#@oS9sm%Lsr}HvG?O&1TIq(t&eoexCE(rrD*y0SFq}! zegjaeV3xtZ1ZrG>Uzj`_>a<(NzuK`)Tg_MKtkQFSL!4Ua@h|VJa{b0xTI|MO<#Q;s zfMfI`4axX<@k2yuRJEhS5in?l2=Gfq&*NW7nVr+tXYGPoX(IM8rC7g8{0p$o+7#W< zxr=T?+(wKEjvq$BzXJRMHf3boz6c<-W>DV5LBe0rUw5K%CKYj5cCO!eC&J?Newoc6 zZ_2QJ%JTV_HwN_^Q?%TwQf8K>WNCfubP2yA;9qLdHme{~@h7_)RBUI@I8{=TZQUWf z2tS&CQOdnx9>rGet; z=hR{+{x`8!`JQST1OIBFbA3$(#1BV9@x#c~w)H8V&r0Cw&E_rk9;$UQpAde5Gm`b` zu6fRG{OYnvaf@UkhA}>VWp(_pUSS83FtQwX(-HwRhm(x>;Ze_L^WulvPiU~t6b4z} z?}(hHXWaC%F#m#^VJGa_6LU_t!6xkJMHPX(ln00S7d(8C{*l?-|DMz2{x>+ukrOm9 z5)a1@QPq%k;MX0j`RVaRV2R-F9^kGarJ!vG}8@YbtDUdageTOve zc>D`!Wq&-505W_MyYjFNPuQJNiXU2O-U|ioPJ_KSx-t0S=xKC0ekgqWnr6185~HgS zhJrmbyBNQ;VKm1tD&d!EEhJ8uU&qF^s`&o8uhFrZCMM34-hL_Duhw`x+5iC?ejD8& z((Z;ra^$@FLv|r%ZDjJOV^*sj%y~bo-*KPEY5s*{49Er%YZ!@c>q#^Jf_G7@Ka?83 zumy)>TEG)lv&l%U6IkW-hr@|(U4Ph8fKNM3Kg+Sf562I&K5iniNk3;aK8W?fF7uv_ zdV1>Tzf{b{G@dfjg{oZJG<`Ipf%SxkJAVGljafKjkZTx+Z30FHk_PtCt4 z0Bgf?Ar1+Dto<}QFaiJK`a`WLe}?))UuFCZLcqVg{MVwab%~xc$m2S3h2r2Rz_*Nl z;XKdvWM2m-+1p&m9_C;0;^6mkvSY>e_}gf_hm#4%qr83t5YP)yh_uim^&lD^D1`Xe zDT7TVa2eaw8L##l=qbZ5rWH2g0B{1c)_)-{+l3Pq#xEYjp)*dF=|DXjxP6W?ei)zqXm)It5mn5FYy#{dCnjH2E~6R|I0&H?}8 zUm+a&XIh+A`H4{mG7l6&^@m))QMIv$@e6V6yhtk4Ik0D5R=)vpX8UuVVYl@;K6%{l z>6gxb84dCVP)?S;9pU{QdJ$N5AHQbl`TSMf_NLK^LXI89`Go2>FvD!(n_8~sEaHc^ z)2W;WvNHbFV&9}T>GiSWeZ5%#nI>Xo{41?u1#>OVMk4=-XZa8pGBro_4Xn4X|v!7Yr#KZHHZl=H8K;q-v1 zC!b00OoBkkA+7J;p8EMO$Q8YV1#}=61ms9*8GfBJ*h0pdEi@=`+&l)qx7CeL7Wo&~ zAL>esTcX-NXRuAvOvLs9n?n3ck9oke;TgoNCNx>&F`muz@r$jx-cv$Qj{RN@3L*aG z??syDjMITRbNmpJ2K;N0s?!V6GW_B!RTYb~Pogk#aqr>C8Eep;d4BwG zSiC!Xx)OV#H;(aZe^m&--d2eJ>;vkhpyaVf?z+xjS<8K4{ZC`x~BG9b?5G zK~JfEUfietvT)l@25gP$ zviTrN6W|xB4P|9bOvPTOW%e_a=!0A6JMCfoavujTsH+DZfT`SO{z5S$gNIh)Uy&y$ z)v@s(#QgqW(Q+C477{&ANM;-Xei=xO(HG@5Bx%;a3Hu_>#QTZi^TX z%ajCc4bv{^NGpV2Tuq0v1h0O+g>GX0b($LIfnOBy>yls6Z;|5w{~C+Dnj6es~ zvKoyLe(l4vh7Dp-5-4G#EM2)~#~)!3EocwBML z7AiV;&e|7c{Ngc}uz&c3wSXZTvIEhgCH$H@CieXq^Dp!E$f?dJ{W&wj2Jyp`v6)X4 zel>f-IYmn)j@DQNRg^q9gkNBzHOLV#Y{C9ueH>=2A^uf?vW;8oavvW@ibR(k<^{)* zbwn}1uTN5M!O6{7QXQAqLcidAzaSA&bW8jzZ&cBJqKrDY>#r*60YUyFRAsN!8ZtQPNxOqs2+H8(Vd_~CoT&(z<#W%$KNG_UF|F|YGkPBgcRW5(moU$TA$ z{3}PBscwHqXJw7CN6dFO@thHL9LAUsej%EXnPCeHd7^sg7i*gzT?QVn`)ht zOL?k?QPU3N0DrZJU(m1p&-5pjfLESzmb=g|5KK?5fPbB)Y1Pyp-winSA>gbRNSrj> z_6)C2cO-lJz$MN=%>c~%vuqFd!XCb+7O|lY@Jm-LC`8QCN}GaRV$9(xZXQ#_FQTU+ zj>5@|FfQ|+4pUBPxdQx>(62!}2X;&Y*?>7=a|Qu&1^6|IQh(-Ob$*@*K*kY87l;<% z*J*i7wK~|Q6WF-c0s_BWztLLg4dE9MRy8neO*m-0j+)7<G<#^5r zkP^Oba4##vFNF6ct0(U8cYv3+!A2*19>QrIXZb>j-OGdAZQfitH4LqGo&@GlM9KS4h zdd&*BGeL@)UHG(-$O*g4O=Rj`_VkPMUs!pGsM@5^XAFGVIw$^?_iMB=%X8NC^K9PP zoNBoS%;P-=jg|uZmY{xq8>5wirW~U_==+Ub;;3^EKAf?__(guTygz3yp1iwzVPRW{ ze;s7mEgV0W)Cgq13i{QHb68V`U(gi956uxeQ~>Q7Gso$rHHZv^_}8R@T%_f~MlpW< z3zHgx6k+^AwIM#!8}sury>A1**oubm%i?N79Gfv1YE7x$DDsOC|9TA7hOtp`lJ51! zFn%?(hxylB`T;#GW1Zs12pfWSWyJ9N@h?NO2^T`^sUA{O`DUJT5x+S9<;~DXjj`X zbt_E148Ojk7G+~U!uJI}`aj^(pZ$8?cpwi#|nMNRM)SZYi|KdWD+)KQGf%reRKTxw;8s6G&xbwVn@_ya&{TShK=z&r)Kz*Lu+W6G=3s|)aJ zf=;hNYHX`H?&$p2L*@ZG(~pQ^8UON95{OXg{MTgfG8hn?!^trJ!hX52$FWU1x3x{w za)ZM7l~x!t5>wS95k2NxiTBZOZs(9&118gC%r26H-K{skkx8{bvpUkzE5L1wW#huxo2I*(}-=n1Fp6*L0= zwHg*1btxHffaU5-EfcG0APfJnxhI5QTe@E#19N##enTzHBNq26T@Cy~!;jA+|0SR6 z$he8c<}m#WfDG|NB*J7D%N4?}-`Ur?iAm!awn-Cbzwo9Ezo2o2_(0t-7OFW9x!zKz zS*~T_{1?<}e~R%7pPVQ(jygjiVpdl;|Mj?9$TLKKSuM)XVElTV3+dNIyU5`qhWdFM z=WsuE@Sxt)85yyUh6+hHl@Xuz_MP)z@3}1loAc%==MX+BuNpH)Bns&nzy7+ydk%qZ z&1#v$n5)?6&Ai7zj|U15kUl?_4O1Bfoy?iv#@kxjz`rKwM@9anpM&}h8})TvK%xVr z&9Vn%$xdXGL-+-Z8^M@w^O$VxejLbe>iUh!Ab!YY8%}4;7H>rST8J^~Ca2wEEMU>~ z_sdh1QCk#B{k470!(lj@&nM$y{6bjczh^P$cVXw*k6MLnm#wiN#J`wD!q3#O#i1$& zg{HOfQL`+5m~=Xn2wUb2{Qz2G3IguJ>Hy){L6mA&f{HeW6Fmu z#%|cdF#kd&Mq_(AXa0iMStkCA$>2LE(G%bo?0lr90J$_SckrB*uE!4ZF9*>=3v3I^ z!duzh%X`}BV0}vXMNjr66~dvX730^9JH$9WDeLkGrUm@#6EvV4u9kn(d64C@D)Cis z-YFoe7T{M6JuT~cae9w3Y)OxQ>HJqufL~Y0ll_a|0NXl^a*GvN@UPcsQlX-wqr|_y zqb9RY=OB*$&Q~V>5oZi>Hie!L|C&}q9EN(0ey&=xRTHyYtaDCNHeA2)O+rfRd3^Tu zWBE_^!glMrUJh*55oQ?R*H(HO8V6{brf<+9IRn9v>>e8#v8)LA*9i0rrP{FS4s1&n z6}hVkRd5ok5yCI5>Lh09IzOf6yFRhiTu8`(^L_>R^#)eHwVJny;kW}E2f282cSBOG zU;6tm(K?o33km#^akqEcIp?mR_-F~gzCe5X7CEtj>R;0LjD}$pj!w{1Sp>8POZ*F! z=XS#=Y^Jv1(i*6qutCHMQ8u2Eb;pWm=E8CT3nDs1fS46PVP^=xvTOld%z1+GOTv!n zIV&^*{FLD)zYy=OZ5oN6c%-@iuyKvp?3%Vh0qXuZSb)s( zd|cEYKAWq1qkmeoN_?AbTX!cvEKx{536S#F2la=}km>B}$N;vw=hVBFU1@=lIWErO z@oq;yN9Vtih^AJj?S2CUlMq<=dwl-|yqNUz-CVzM4&|Nk$+~8gD=&58J7W&&ZP2sP zbiFYJ<7o@K<0iU5InU%;Iu>oMdsm{C#!b9h#IKuCe~5V9Vc7Y&h3{_M%^=|N1^)i4 zJHRg^Om=}I26zG0%aka6b+A^fs?v-!#XOf)WfghQCK#79Gr%Mm_)O&T0F z#J^gG_+g)_bx;C|+q!8vZNtrYU2j~gy9M}lQI^N(`a`GXXyWm@x9N~*R3FMG-xM#Xuee}9e%-RJ zKeXT$qHM$AusqTP?61}qQ2ALMarim9{%~MnA@EGpf0#{~WJ=0~R2UvJI|MM49oF^HKzX#DW>B-|*3@U{4`8 zo#^X5PE*!1{Pj>7|7yv`bF*RIU4#uET6HDtDwMIh?E5c{nCY;X+AdQMMNxR8K*YA< z0~5W@H5K(tJ-Fg-jLo}*!LOH3*qW?W7WIqqtHHfWLqN*;xYgJb$wR+nthz_c)v|l_ z^DRzQzj>S{^NlGl{{@FC@m(|c{tM<^wswA!%azaWZ2eN=)!vhcC^mE^M$O~iS>0AK z)^>0^zGB;EUa1iHZI9gk}&r#1m+{^cGMBvvA)WN(fZSa4E#YAJX`LEs? zL;lM;BU?rp3uww{ri5j_p-xE%__SG|Ea6At`{ftCvUwCmh*lSNK0`>p5G38#uJ=6` z`5M8WKMrh~Ae0M}H7OQ4Pj-NjZRiQ&hiTDmC5QDGeMC9Y>;(-(fjaqJ%)ju3EPqR- zKe2aH6tx(?U`fRO2oE8J`a`G#uRP|Ay@1=3F7A%&?U(-kE27a#=f4=XxV8{;c8k82 zTQOZY($`u@oHEbR5x42~&8N&Y0BF5~lSTe@R&8<+KZIOpI3w1emFh>Nog<2q-a7OB z8@(20*qA&_n~da$)hH~7Yt=C46Gj)$nd|2@-zFPf+Pp2cj`rDu+!Nr}=3*8P{7b>SzXB3^3JnNY;$PMaj{lr9veAw2MqR-{ zN3YnZr>7$oEzTy1-QoQj#54e-AEgbF=aYQbvvpj*(JS@JvkQ@TXAC4$)GhNY*J*FR zIDV+ZhF=x0&DqmeJ9gESxK=Wvfssvn&jJ4uxPQY%{O~ZgDKlK<#H?HQAtQ#KfPeh} z*zN5XF7;|1o_VJ^^{0N%Xl0hyXJ^G*%(7j4zs$$GivkT!Ba_rJQ=Bu7POxfGD+0lE-Wtp%)D5Q5Ttlwzh zYK?K)NJ$W}wiMlm26_ViwHi*3K4UMzbxg7oi0>=+Ieh8@{)PA<`(s^gKcn@FREP}NG#>Q`j@fpz}I5@;v*W=bOrqDoPBPzwZL0x zy{LxxGrbHULd88L{PJRhcZ!qRm#FF#Hr+i3xve{k_(hbX-2!vYicvx$jDWcp!-r%k za1I?ltInJe94yH0!162CSu!I6Ea3P&WcTrFC*m6c=04Y-8AbvtMThz!#en&?x2Fmh z)|{5QXF~X88{^^(E#)x*|3V6hQ|cUxdx@Gss5Xta-x+7nx=crn&&^Be? zM~^5_#b(%Nwvb6bzM(1>@EtGcfq%%!*8UudX1}S&Knlsv@%a}^F|5Z}xoQ&kdzK`K zA7=R$8r}=9tQQvr)O!gd%-Pg9n7>@370-DREBynyh`(RfJSD`xUZb~Zv52?L&ZuE) zmxzCQ74KI$e!Wc_Ujf_V??E>WFPO9*6iEXAV*K)DXZ-puCAoA8N!tj{s@)TTt<&eQ zRKF3$F?Kt0R3F(u3uFiCH!#M>uPn>X{0sAmr`tdS4?9hA^ET|)b4ue^kpFrb6>iVE ziOK(Mn)5_z(NAJy-tL6)iw@D?ocNB|RfNxJT@>tDSp*V!PXqjls~!oJ`G%OkzuR%< zS-Us-AEt%kho2NZ1jx2UA9Z&)G~>yr;9wf>j?cfc#uc*1t#hn#@ua*@)fHy^J5dcR zSjgy5iXYN`%8aBlvo{O=>}%m-GvXqUScYFLS1WH*C%YMPCh8BRS2a}1f4xm_MgYe) z+aJovd5m9Y=<6(3fL{+$58TvLHd;gX(05d{Gdd^27so+&O7$D`j|x$mDbXUfV9u#^ z)tAy9SI;?Af7oN>se^DKr!rFbh(O#|^rJ%fbsXZP^O(kd(qY48u5TQI`VG)7$hAen z0^mD(E72!7dT<3}K^gyQL{!9Jxdx@jQ(!a8?~g*YM%LOEy;5-5e5yKHulz($IDQzf z%UVap<8-e=gUN_LCcv)LxpIV_t`QEoOJym9K|qx zfu6Lr0RF^v^bS5--tuSQU#QIp;nz0fB>gI%@%dLC_g!?FON5_q3dIjmEsxKZ1?D2_ zIBe(;=f7qs@k!6NFn)bs*0!hcsdeOT+vvoBj2PWUT3*JO>tQACXJgvcaa1g|wd~u( zmBt2ePq5MJOZfFGpjBG)FRXJK2gyPHbR{r1z^@&Et!HGy?j1(3u^Hk(zW`(`S1A8= zm=;qUdO*-q{_HESe3o70U&bX8Un{Hl4%{*Ns$80@n!pEKaN5i8s~u-Gi>lvBMT$~n zEss`lCf&U;0|oZ%m@yCD7qUx};vxL1-kl-wVThl23gK6;+Lga|ZR|dJUVSv*z7~ZX z2qc!_*Jik!kis@$Jh`Ea3A)y^2?75)L2q|2c2=*!wFw8*;_T{i*3d0;1_Jmnj7L`rONNi z*Q7|yl)ZMEZHpg2%){q@lWe*0p4e?_B#St}Uhov(!w=$zDBBP%eKQAoAGLqOWrsUg z`QI-G_{IE-(_Zl`f=-NI2=6x+z2%^O;}e81Z#DQk;UMjnRjIZsNf&7hl;Vf!PK*J^ zuXJdGk(5@ySQLyY;#XYsVwYmx{`3`-fDY;;i%{p&_Osdxme4GTgC%KzAK&bcY+vVSXIT4(w zFVh3}=k4#>9HZu_nj@BZ`sLMc)H*<`KNtAE(pm7e%8TV5RaLlbTv*Qsc)2WdaH3>@Pqmd@XBY~aqY&_;%}+7uj(ChO6vV8!~*_>^~pCrka*He z8_#uT49N9m?>y(j__e3Awm-I{rx_{({pyP5Z0-AH!}zr)Z*a~IUn5W^8<;?a;)fdy z9WCUvS3@?HyFTuZ5tT*#0^4fWDWn6`4P~_EReE1E1BryEUmQPl`+!y)KRk-_vAW+x z#gB(yrTC#ZwGT7IT^8^T;mRKSh`xwJB7RuLzqAzB&|AO@#27ukgN>^U^REVGTS>rH z(ui#oj=}sZ9Ab!aARE#9LMKp`iTEM&uSB=$ zz$XC_bIoYP;q#oTfGdlzA;%BZMhCQO%v=lnVj?D@-d^zcUpQKP#&p=w-Sm%bo59H7 zS*0+hlb@3}u28sHn!T@EB!>}j?cp)fUo_tiZ&~sfzW?w!Rm<_i7KQJZZ$}*aTL=Jx zh)tF5-}rw1jC_XkUpoZSd7Rg~!y{rr{1El?&XJL(Nubqx^y|K+Y+?=Y3-QA&D%=A6 zdI*qID>0vw^kcpjd!?8s^%u=S{E!eoWQ@a@W2oh;y*}nfZy|iqOo-3>_~jtJ0S|u; zWXGKo+Ul1WUO$LMEvYgfFmU>SSM3OxaS-GTWe)rtlf8qHX zA^eK-7@=cUsKHa#&VSzN-La`k{436TDrc}hwHbx%psa{UCp z1n_hx&JQ#$SIU1OykmP@mu)wiwfpC4P?--5PrR@z_yNJn{drnA->z;p1^`)ugG#W1r(ev!^rvb$=3fAXe!}29-9hE}^(1X~Z&Ypd zeH$W4>ewOp`>%!`tVRgGU=Q8IpmsA*II2vc#&az;ZWRgP7gm0MqJXlEY1!HZfS!~; z;~Npf_~o4L$8!eiK(~=6iZ6NOxHHn(ax*I2Mm_x+saVKi!xNZcgu45k+pN7kuTyNa z;bbhF|Dr*O)DOE5;Al5kHjZBp+i)uKFUGHD)We0?n&_o;k9v4VYMpqE?#V4g4>nHg z7vt9njut9htOb2&5C9!Bng5_L!s$DH#D-&}{jU*`Ia*f@}SvjTZ!AiKNo zFS6DxB0~T==xd`q{*~mcP=H_B8^@qXR4GQN9uy#>A_{~PjO zw)V%o_~9bLov0S6y#9j-9{;*5$bVTCuMjNcN?5jt@Gj!uKw|g8>}6{L{ssKvY!}AV z1DC<&Ub%D$-Rmssh`n4MKWqWC#pc@wJGRU8HpFcXx-DHXRIi2b%hH&uY1c{s^st9$ zx!!<(4bV8JXqEXoBH~SS)9|W{{2IQHy~&+j1^DO{7tue8vm*J7 zr7Aio@20z9!zbA2?TbD3k8v8ZaEwCn!xmscP*3|X#Uy+!U;$FdrTUF1{Zg&SC;qef znpzJ(9AU#t>9?AH^#<|7N7=mN+kf+|JT{k=ag6bcX7&~HUsQ3L5DLySemQ6qkVji; z;70oTa{SsO7v>n7Y=$I@?-#}HFk1PTLKLb222~_W3e4F6e#tO?AuFU}ndA|PJ0FfC zc3LHeSul<-T(4<+Vv)}G3?jK=qVua2hN76+bH3BTwJ=zn6U4%g{ZOJtD(*qs@{ zt-pJrXc=B-0}+sOk=B)o$yLo3>)@6F^JM-#r!|$>AI7hzWW#4RaainGTI9xDF|MA- zHcZ8Km-ttTp5kmW`?PzrpfC!-VQ3sKs}}`tPyO$|cnr3Z;h2F8mW0CiwU+lnCh$EP zV5^xAk_KNFh{o|J{P_1DVhq>m>5tcn2E;Al*R*p)HaS=y{2>)%*TY+mn=SK>WDqcU zxx~MwX-lWbB3d{>k1a{&V~<34s4W@XAN9{YCH!)FL47dQ!>Y-009!r%POk&7n^odp zn{m_rc3WdNio~4Q-i4cyjS0GD}<_Nb5KQMQ3tci+QFq=G{H z>p5D&^@oS$JCvETdSH`-LJrNyO8g6dKLxlvxoVpJcC?iiy>6bA=wU`y!Y}ngwj~9A z%AeQ|^1grHdBJH!_O>^;f8!tI`c&1h)zt==vN89pyrF#0=8bG zU8**N%P77@@N$`vh48Caq{mPVbr|1wJI8TsKvltOoa^oqDlml58>BA`ubYz4z3W)H_AlrvNQ~Sqg+*n zUmNJl1@MbE6z*q(5#IC#CK@h!O8g6dLj?N8^&9+Y80rtNbUZRr!Y|FX*v=m?c1ccz zEx3-5)8vd;fM0Di(%pdNoeii}gLI^yFXB**NRGz>{Q4!Gayh(a{({cBIFQqIsOWGJ zi#rzPUyy>Ma{xQlC_lEQ?lCPFdP4jQ?w*1vK-pnoI}%}tOXT4wq9??^x(%J}LfK&l z8W;EUsczCeCH^J44PF+=zDwW|lH7uC>%Sdi&I;eZf$(gno(~dXU5Tx;cL?;Xxrp!I z(0H0M`ZzbyhA}u}5#+yeo5m1GgtggL&cC2d%0x|R63cS8zNkd^l<}|aYDQlC3JxCB zYFsRHHq!RJK(uoHHOY2^hFpiuV1whIv4DTgb9a| z7IU=lHD?-WubbAvAxFC-jBJ6&iG2PgF~g&VzJH@DI>+%D8Ii;G z*+KmVs^v3~oo|qI3i#CM$|PjJJ@(P4<@tx;U*d={nDnNaAAA`lh5GNOz^a@6yZHNM zRH1nFhv1bifD92uXk09aA9DR6_*V-5>LmE`(EdbcU9&`;LsufRirO{C@%PKH#`srl z1$q=}wP~tu9rx709y-$IIjf2^tY2~zJtGn|3~p?fSZLv!YqptA3BMqPf?UH!9_|Uu zU_09lphMKxFTQ{N2qh)t()lkqt;xlC2JYHI0A8mFFS+LQnH3?0h{gRBRkUgD<{dMrOWJ#ILlD7Fv$@h#H_|#yWv~ z<+FGf_Tq$(Ux;sLxd^un58z|NWzVovA+%h6{YJs?uHCSH0@&KqU0bO6D!7dPqa@+_ z4ZI!KWe`enCaEzR&&1;PZ|o&*xPF6ix#i_WZ0m3!3l~AZ*Gugmo}jEghx9GXaN(QQc$E3qBaZdg(V6c0 z{6a?If~Q}){*cm>9n0`>5{@7CG|79K<~=QoAGT6_fw_RZ{FlK*3^pNDzX1qBT z6<7Ccp-0-I7wa)!W~=^uQNJP_&9GxPN5Q}3!=1rJ95K6XzroAn*UvXQm?6in_y+1Xj7}co-#?#8)BwNUQO{%(53SPo_i99|?9yW@G)K!OMopxZ!BY@k^ZpRn zhZyzrnBx8OKq~>ga2(_mJpP3qzkZ(U5B&@s67AR@#AFZ<;FwIfeuGz|&Ho!=j;oh;2GWi1#X7rtR-VP`{Dq9kjvvoupU4u?hH2 zjmAZ4RfvCawhPh1CfZ1KWF6MQnWbuGdHn|4jf_ahUdm5eE41AJkcIe{&UQ_tx}tpT zVeRuZU6sHuHQxm~jC*^E`+Fn5>u&v3{B+M1?w0)GH`6V3SBU47MznJNHHtgEVPtH? z*>;X-yWPu>hZg zDBu_DGwQ>OHvAb7mQ4n@)j(0dfM1@?#25!awjYBrhWXb(Wud5Fu#kFBai-B<@m*HD}VrvXcAaZhF^MyN#GZUYY<5E=lr&(UmkvGR)T8} zais?0Y&zfuDe5lFe|a!*6Kc_ma)s(Q{0d|Tc3vmKK*YR;k6+>ZS0wcPm&ULCW%(~i z5v{j2c(Q|pdJFZw_$4uUc9wi>3dawbZRLWnp*be~F+u!L;}`E>L5y_h`e%Q0%fJ7k z20wn7)j)>tzr3D9o?httdnpaOfiu?YY9I^jMyP&6pWeH~F@}JGg>PMo=edMmz?~J$ zzg|M!MROqyB3A4v$1l&k>x<~2L`6Fv@GsN@u=ShnZ6Vapvl;YzLiHPrO@OUQsFfe6 z59Z@z3iB^tn>GzCyKAZpdQ()`Zd`WG-UMkMH z48QcRCM>9)HV(xx1y8@2fB6;?4QsIrKxCexu^^QH@~tuIvGckfJMCkWDAmsgHk_WY zQHRuiUwnVBwpx?e0>l9rzk<4y^7tX6RdDS_Acc=# zbYLa!!#-wT6RFy#8-IdEMb}E*<1Xgu5FKc*xYM{re$JjdtQ()!4VuS2?&3~8MhU}F z9r){&k)8`0%F#oBYep6qxL!=xDZf#HhH(peDvDzcbX44B+@e0`%pEB;8jaQ5Q+(F} z2@+BEhoub_^c3gZ5lI@BYIE%VVnan7uSXTfe7vHqyEA`tYHqaH5EY&3=7F2jbEzm- z-1t-aj5{||vD#~Nq47DA?yO8i26B;v`yU~LNJeaGC&NMmQD>r+{+I(ITQ|h!n>hxZeDfdL?^xO;xzj{SfyQ-*w>niaWb+$$qY;;(5O@_xX#w z9-LKgeXhISyi*;^ez>OUdEK}MgAMMvrl!iBRU8xi^PmyAQ(4(nHFJymMWRftYPF(e zpmBdx{IhXg z8)Z>FR%sb14Mam9*lag%oS}+yZi_hRY2!L$Zs?73u!HC+jj52`o%nMFa|JgtpNY?H zGvvOTxrh9Bk!f_gH)rO?D^`UX>SkxIRU!R3gKV~ut<{$sP_$XlFZ5J8P<-#_x;8;d zfxB8Du}bBg6gRqcPw`!lJ!`Dd+7vV{D)#tt9gybv`o%WN(=Y#BL=hBD(JHdtQlksA zaN*y+7ED}bM~Cbfr`b{A!pf<;5l^_YjNS%XE)D% ziXJQ{oIILZ+xo1Jv*zW4?U&lT-Q14 z=E!G^xiVFYeoXtKW#2q%l4Bf$v{V#?a!9Q`( zMlj~uuYdCA5AGRz>l8O0xMu9$Q`fHRcz*V-v5Bt+V+_$HAF@9jG4}b58Gd8l47WHa z;^T6Khsyy#GcFg$h%&no0_d8EDvqH5J>RF{53(Y68S~V~oLM6mG~EAt&p98LeSpr| zs`#7*k&ky*=i7JAy0GC7vD`Rm)0Ht+U(k@6$}qA~36}$a=7uypw~j2gs5azji;ish zic}gC@o?r68lgCu5} zQMmWtLd5g@hO37VzpD&S17Jl%dA3&?=izeLLs8yyI*mW{oZ`D=q|=x~*U_vC8*SdZ zI;fIXDmxpgF)nO)kD(4=-1)d1^!Q^W@brCf*+XjSV~TNo(AM^ zUfii30xr*Z{(^=-rt`WYzRxY;dl8`b`)ha}E{F7saasRJ$bPG;$>Ju#doF1BW9YhU zWF6x8A5*gm7c`1z1N&8m%Nn2^52=gq!hV(EvMd5LdYM5NfL;13AV zLq)kv>U8I1D&oef3mVdY&Uv^T05mteA^ff~Tn+%58^w1S@^3R*1Vo#q@ma6w~#@m;GT*?l#c>*KR}FK8%# z4Gl?U=0p_jif-r!Nuz_|m{C~ca#=$a-zD2SXU&ORXUuw^MsdGFzF6Rtd5z*;Pzi+t zI1U=#tFT|6F#lA(GJ5rrstX&kC|Ab?5DpzGXj;o8fT-I1w9PRrMS5Tr>zh^Y(*& zn<<+g@UGWaS)5JQBa zARF0!zqQYqGeK0Jv2Wt?fs7^asw^=a{uq& z@PBOha&!O28@}{=H?{oHmu{jPDcbfY?U_Hld3h#7U!quBX8FfkGb>w{ucVu3{_<6; z+gGe!(N4cdw7dTte!lm2pZ{`(RD_7;Wg=Pre=8GlBBZ*SGvxArlmGkq8N&0*e@8MT zsgIhzM0GYl{v|)A(!coCee&GL7P{vz`$y?t{5pN=e%UMdxvB6E(XZ2Iq3-!h{xS9Q zU)YqT_4FaCQW38aQIU;wF;z>-ca7;~K@*mx$+$fnD?lW9TbnMo9l z6ZB*1bkUeF^?OQ@gLIC%rfQEh&Wdwxmz$Vg_@X#RSD<0cV9fZD_PuydM=4$~rrhTn zI{Wl{o-Dt|;XdP4X?loSTB-4k zoOIE6UHv%I#`E)9lFn>mL z(rxYyh2dN4UOM!*ssX}_X>$0pdKdAUw%mUCZ6ZeB7|QOpu%Zy7M4QwmXLVmJ-#yvAiIOsw7bUX! zJ@r*h+-H1QzAh~`QOkP#YRueZ>OP0PwXjT+_ENgT@r<<21rDzhUTg-|=BBbAQcx<2i9^;1hii6;Esy-gu?D-;;;? zbjieovBErJ3mMNFZ_>Yd<2vlE*DAY22dIT&g>HxTs3fISvP8p_q?i&0AB!?k0eS->~%-&}$-mT{+cBg2fop!RP7xP2@{2cbyqOfQ;&+|12J7zW=$+g`A zc_!`WX@q5-^7Jc3x(}YLorDstDB)Kwy-9jpPk8#3vI}}m<3kG@u*W+o&TBfZ+IW7R zFdZIy%1mKzv?%L@Sgkfk&?s~t7hk891F?d5!dr`!r(ap?;;88i6w>u6>@k`1_Sh3; z{kjDExp~@hg-y3vX|np0FVY=!8Sm#Q|2@_cdRKL2(;MpQ#AE6zCw{AOE_YZhFC}g@ zUK1=1S(ma+SmMreFq~6PXC5l^df_eXx|*UfTAk%S(zA!z#FWuSADw8=%$qUJ+Rvyf z*dDsxdhOBr)$GQyEDwF$jP=*ODDUWN7>nI3Ui0Reh;^{J8+}&M55#2>zdBl$+4b}* ztMvDUbYWavkeiPBvBT0LI7&p4qK4NIBAjJ3Hiu(qdP zz%LW)HDS$)6DACZti`ynf=Rb#w`lX$g7NDiN>4-&h!Zd%Ei#s=PGNPXTq}v4spr|l zujZ0QfPEIeVq$>yTC@HOj6YAeO}7|X)=1^xO{@gnWF zKQ3bZbPT%F;6_WL&fD`Y-2(}m8LeKTgQE>B^9!^MM#$PA;0&@nj9(Z#uNPzYws^4wA!pfLU9BX)m{!Lwl#{1w`lMUdI@$E(v^t7!Hjp~Tj!2rLMZ~$cKRBAYy z%nhquPHH?_Yiix8;8&Evx4GN;EwRYCE!7~cJ|R3CRqx@K3&>^=hXd0m7FoBE?o;ip zMPV`HsYaqEI^}l48DM!-TNV?Z^6@L8@vA$LZ$xMGN!(?i;lK&Z8*}ih%}fyHXGSu9 z>4|EixN884cyFYt7{3||u@clu16cu$&6HHo_b5rP5BrC(8!6ZgHhR`7QHwp6Emn6NVzh@8d>zup1kVwUrsCU&>4c1g_wRl?X zE2L*)%LIRvhhOF+P#NQOUN36(Hf^WE6Cb}we$89>%5@no4d&pv(;o?HUeYbAhhhK8(WVXcQW4$I?s_(hgo9jC$i zv^_t9Unv4W+rskJo$>1&M1|Gr5L+Z1yaVjGs?Ji{iTR(U@yqPIGqD@C?mf{tis5KP zbD@=C{1RPeVyDqT&rlb!skF{gmxA%69=*qW{L06g>e8SLt%QY}p+~3{jrb zEHQ5Ff?jN%NUGS^#KYOmPUEC?Foa)fpGLIYO=>fxX@YDK`m7Tk-mC*4#* zEESvSdnz_8?o~PdtAKyW1(?mi1!|c=Q-eC1>^VBv#ua(6M*#vY86Jh?PusSI?&B{(WaGz@FdstHtu@L_{ZM7BR|1oy4JWOqB+lH7!Pe)cN_#1Qh z7wm>Ivb{4_XLaIsy;nQV!!Mw)YyoW1k$ju`$vn)(k;sD*b~S`wn}Ak;n~%~ar70By zSyEd03Vwl70j;d<(aR+N>e_s+NorLeY{4%R(0BEJ5ZGZ~kaZytZkkf0`1^5O2 zH4a!<2eT|dD{LRgRugtqnSWjS3h=9o(dr#KCt>HWH>O`XmFnzC+!?|z$t)6Rbs0TH z0O$#$Nj*`J9JTWtcgOKnl2K^ABkS#$W;ZBE0d8IssnmrTUyP6jFF zj2Z{)7YxCQGFsIwx_Xn1`MDE)cG5DQpECbiJSlv%`lve6y|OQ{eXvPBPn|Md;a`kj z9$HO;b}i{i?AU^lQV07IbMcF3W4S%=Vgr73-4vM&mY3CGkQ%MR@0bjXZqF& zAZyQt`PUBmAvH^*Pt?TOHyV*h7Gn|5=Kr z7>@bL6iunlvFq;A_@y~o2*1wK6)I7hw*vdH-Aznf%NWxwFHqDwJaqj?-A0ccqi7~)$w9$X@tU}~&(xf; z96wyJM-D`mSr#aa+9GPlV#O$ZFeFrkNMdNbz!%GOSrOT@m;Maa}R$Vcg z_@~%u#^n;sy9Q_%jSzmFrnW^uy;og-ae<7MUgZhTKOCznE<`I@VV~VZNh$Qgffz2;tWZWo*O`UHO)+!-hxc zE$SE##}5x6T6h&Drq|Bc2pa;n76#)A@as4|S;|oQfRR!d*QYDKRw#bBRU%qQR=;zJ z!~QB%=0#Wl9d8NZhyS;@eYnwy&e$xxC$o8f;SWpU_~BCy*w%-m^}W#$n1lEp;P|UuLIy^#I2Ysnhg)Evt48e!U?voSR_P-=I@Xo$fXU zGFVZGjUC|Em)XF zjvq$;Yxk+1&T*z)j!)Jm%Q6S}rD%Lj+of?8i`dLh6FK%tq@Jh%zm~Dx$b)TtLTz?d zEBHuLAYvDRqyw8I;Ro?UF&J@PuFr^hG@#NhXa@8v8|OV1;1}4|Ktl;=bxHINy4=0E zKZpH{1~>_a4TtXVl)~=^0T?h#xZUyo89NZUp$XmEOCxvo|p^sE6auW1fNmx=^A3 zzuo~S=_*|}Gw=@m+dzA1-ZA4Wopk|Zq4?o;dB4-F@afOVA2KBMi5KnrJb6O+<*VLv z(7}dL?n6I155JzKeJZ^m_5eJqz2uazrbn?eQ#|$nzy493D|D`cW&0lxHB-Ve!A8ls z_;tbo#vQ{bN=grBJNiHwd0Zjv+89+e%7~9MgfNa`u!~83GE9_y?f$q4y zcfuZy&@#rRAb!Xi=P2}9N)I?lzNj3_lRU(I%J^jxI5onC(IJcreF)=vi1fI8{bK%g z4p|1s(`2)Kj^`Jih;V!iGP{PyyS?}!A#B*MW&Y#@WPZQ+VOJ?JZpQ{&X@6v^I!NC)M}EpL@+Lm7yKmP zUp+d0h?yT6ob3jFP1h8SS&U1s#e}KHRf-&B*m4sk;|+0c5!-pJmygRK{Nlf=-ENFI zPf+Kxn3fat^YVKf)*ZJh?a6aD%>13(q07}lzYGYSBHz(h)#P=0Je_O|DX;xj9>n^T;rU?a1_RcwV;o3QGhxP7mTO+$z1#z zi`^h5Xd5-=0lq<>fPeX(@G3DzgOrldkbaGO@p(W0!MH9Z6fkmPY0y{1^@O8(1>AG$DKQv^HDjX>tP_~m|P+W2#NH=@I9Y!AC! z6b1zG!`b0?hOTttM~qJKule>Y)(iX#1T)S^t^GP>pOp^|Ia{o|x~cGEXIa)7$+ciy z$pQe#p$zLF*KdqaimYUv6}i(%y7M!2@yI@EQdUMJz4(TU_~C=VWpJ6M$ltrmB!0!S z@n0FpGJf26@hm)t)%9r=YZ6}^%513NLWOg*qA89zZKZw#k=p^-4e%7|>ep-WF0H24 zVugPlq$ku$JHE?s#(vyCg1qM-&rjPrYyjJISmyDn4np*DcklkYn#Io*!ZrJmi~NPN ztlxSsoc{vzz1}h}YOVgR%t~LsoPJbv1o^L8ns?}ilJ&*zy0za{|LJ9mlS<#2xZFX* z^465&hmXn?YkCVYtNT@_=q8o}zuv>-r86ZYX{)82tGC}eAIQTGLS{Mki!V!*O3DF*Efx&Lq`gm zyAg2X;8jNAiSX8o>o+#3rMFr;;QKxAu0-xeOxj@3eb(LBhc>TieWVGH^v5#Aakfpg zY)#6u;k&x6e6G5zUkm|%*jImj^z-8HqyJaiHMf@K-G;l+#W)FEQ0~+ zuo%GCNs6=;YcaH5?D*nO#VJ~ujnyx_o&G}IFB3Z;^QrttWklL zH1%$hBeI!!<(Xkb6psy7d-?_ZGKbBUlx2x!G_<>u!-n8rQ;4$-iBSG)0N8CkD^{r6 zoTQu&{uP1KE>kvQGFqPc1-lU`ZIP*o=n8Qgcg|@3m1H(r?dQK1O`1m{NW-xhM`+}h z&wzhfr)Z=PPg34Ir;w*%guU+Xn19JfdSP1_h2d*){7}yi*KdqFolZy2aFATp_>TF> zjM&iJa{deU;Omqw);Q3D7wDjh{R8mp4VfIaO2}>LALd^JYU5b_3Q;4zVP+2@fqs-8 zQjP##W!)OQ= zVjvRI=sC=qN7)rodYN`As1M`U2yL7|=BVD&FUBu6?{U-v(0>E%LL!XyeJLA!|Fby% zbxOjA95P;2uVpbVPK2GJ)z5N8hi9L;egkn)H~zxlN(}Hy_ap2Zzf0}Y2@2=G9>_PV zUN_lReQzE%{9fZ;^WpKO{}kI_i63qxL^DdMrtZtt771#07clNYwRALA%sJG@6V3G- zKJBt1--7|cUfoJXLfnRe{1@ssPGRhE!dS=YK{v+ug@~C8n?ORphwC@aP(oejA`kmf zOV^%Pe+UbZ5pnu^tWPYHTjzOJnIQj#wb)065@H1mTe}#$12hlfhuRvSOz&NrroXqL z7sY{%ST7CGLHy9?DKjycchx1gooYO**z#js=kYJBavFcm@6qe-zen$%a{fz;fpPt5 z*p~?6hviX3<1D;`K5ltjLHy9?U$=tG+z(LLa;tb2jpmm@YQ{bN^7CJZAO;E%MJ58; zHOBEn4#Gd{=~qy{@g}wwh9fbYx9OZNys6+9&ky!9r*Y9Bz!t}>^tk5azmVqU`osGX zVnXA&vVR!F5AR_Kk6SZ2$UNNY0Ji>_pOh{>zy7e4S|#FC4E6S!4=KY(xp$S5mep4-XV}r7VkuzQgc>pO86-AMQpUj6#=fpfS%|6g{pv{0r3@ z99A8tc5YyCu_3X_LHv;U7f@K2Z3x|XU;d>W&VO;)Myg=hbd>x(7Uo}G{tJP`?#uHS zV8CTU{L9aOaoNU0rS$vrFGSUNXL79(r-vFnZGu+%_{H@bXVg_$*u!@SWgE`AW8$pz z?V;=A7vdY7|AH9LF_4*Ic|!baKef_)nVaCUjVyF9kU7M^P_C1iPgrinwMNTxs5l|* zCaaZgLnL2DfM4Z4o~`5h4fd=qMp_vTRZ}Fz zxa^NB6hGu@C`K#nAGoO@`&{N<^HH9Mm@DcxblC>m!$9VMf1Sx6Ez_*nz3=ufE|3>JKwm0?1Q} z6_c~H8RJTY>JL9dJCOPzb_)?=%EfGSW>yleKdhx8)jDN;wfZIVhdIO#zbam`@5nby zT65|TCxBM*jB!)}wvHwmjH4V77@J#vI2*a@h__63*JIlNWES?=SfUiFKg@y`l<=N3 zy{FnnVKY1E$ss+i3V!8or)K5hS479>myl*;*-HKVJ?eJVS{i1|MIlG&;wdz4Q;j7g z*+cQeE!p&dmC@LpJQ;&?f*{YX9;{a=e)zQP+8%d|lyzFQ-IX{FAbZ+rE2K+v>Ngm+ zhS8m^K4y!Ut>bkNtEZArv%5tVdoLxVqOs7*Y7)+XD=lv+ zvACEh#xEe+ochDfrn5Iz(qY5aoroX4rV$MlTv5-~rK)}t+SD|;WhKt1z;4W7k0C3> z`W31_tf6g-c9ISwAWYZI_392{1#YcTCq)l zf5^crjkzKGLMe{hUfia`P^znxm;sP!dl;%e{AIujNdgOPY!~;?dg|WsXxq1 zNXRm?52-_o69BTtIrWEQ_P!{pUNZttvI22kE?gRx*a>s%4}01&iA*E(-N6z-cmP>j zDO`VuuwevcQQo+`K3=ZBfJMo$KNhj4fmT;IiHU_BY*J)mdT<7w0vwM}{o$7&D(ZXh zj;2v?-g+y1^(n#UI8x#I4fPN$9ollhqaIoG86#bb&bwFgXIZ8NL~|6z#UZ#fp}_&t zf{Pt4BHV=t^-=GNl?pYk7#HtDPSv@*fAW?3!)b{6BbUqb*o}wG8py69=vRPWXMu6; zR6AjG(%F1h6Us!}x`Aj|cXZYqjrrFBm2_(I3;)P^$Y~h|=EfCl_&5?_LH!1og*z0r zMI36MCW~^W$~g!f%;8@LL{e%M%$#^@i2CHDR5 zvMfquIT6;71*r+~ualJNO*h2ibP`S=>JN{aqf}Htq7eT=T(mdws^?}%EYmcdvGu}D zRA*UcFaO18#p6;VOvEgA?a_TnEJoiGy)iR#@x+za~8h&{R=%X5mY`Vxpox%OF*)b*EnQuXbRgv4WnLZNRVC z3XDrL%`pF>Bn`6#7~Z|hi4AuzD-IW0mO5_e*pq4nL{CB#!EZ_FLZ<<#J}EE=`5-ZFXFO|sloiyIu>|AKvSk%7UTu zMC0&jzl&<;&I#yFh<}|^?WOp5>>~P!YCoBn89eQPe;o&qh4>fn3-XA1xy?pxVZS(5 z2B{GL0)9#BX2|@vw9^gu3Gpu=wS=Bpw8e2IVk>e-oPERTX`TdAtKbs=~Mk;K#0rUQ>T@ zL;Oq21Fs2!=`xZT2nKnI=hbgW;Ftd^Ht)X7A^dtr0fjkDiSrKG=5YX-$CqOP|9ZoG z5cmbOI^q0Sp#W@;K>kaCup9{UuMvofU3XNWenaZwf5@!xmJt7XQ0^KBI-Ed^v1JR9fD3^l`IL4lIw|(Ux%lO*z!E%-)K6Nj zN`0DF2f6+gbMQ;;oP_0n2@ue_(b|w>P-xE1jUS%0Gj5`-?u0WKG};krEduwDNh5)Fm?yC5#nEGOMqjx z2~W^fh34#F$~+zE+&&k-W*RycdA>Szidr>TGU4}{coOh0U_o8mL>x9#aDt{b4}$P2 zAujsO3jex^_A2HV;xU+I#xG68a0)UX!Y^dRcJZ$!9qtny(O_4LKGkLX>M;RroH=6J zg+BENbolYZ>VSU%zo@OSl|y-KmRp#JZNSXW!7uY1E$Q3F=%5cNPs8A!imYaXKL@`$ zZp4$f>3N2&J|Cdt6W3PwmkHWs$CNm(_LwaM*wRFd8=?G{Utu!l+{t6N#SmoHjevhK zWViHUHYVx2)N(cAhfVyXFICBZdFQ{@Yixo%z3IFsPu2|auiY>yn0a1{Q_w-(8I4aR z@`EA#nvwcgoUY%nYs*9x^Haeuu2S9uH9tkDk5Vwy98rW#$chktp@#ez?8Y12sNZm- z_AP_sw)ea(DtwtUvE6(*~4Q-1;2V$c$Dfz`5m19 zihfpHB2m$S{FkWUSFhiPk6yOAR-d@LjBz3Sf_{xco2FR5O7JrMvCqM;X^FM)^?fw{ z;X#eUF7zveU(lwc)qYj#Kbq_&W#-*Dp-h}$q0%$o|~S7Zl{&chmi)%-Ca z>AJlh$%#bDy$F3vOpEoxhb^{;8goPV1%D%3Gi|)Uf#*V^w{gUp z&2=FW)|ipnhxFrBUHbEQ4rRG z$z#_c6r8`!g&Z$q*M<1kd&6x>;Na^t?r3_FCiWq>oD^U4QJ42fJt$6l(N`$=u@uWn2Esh=XW}(Tf5KF;7~*9+FR?E zm_Hl}*0^O`cEPVn@QtT{;Unpg3-X1jr3Lm(_O5(6Z7 zAQSVl+=uzsTLcS<`QdaY3@jWN9o6516Cw`x@#+uZ^4-$?A`9OeJZ*qW3X`jCw zKct)Jf$XyNoAa2uP0mUgtLL-H3eHl#JIufAWVW86?YjhOhGGWiVY?NLF#p<1-;>b= z=(Ce9ld(Qp#I{Aot{0SqX{*{<$tl$^)eI=t6r@dCA>@Z5!R%$_`j9*^; zVNynIF$NG%XEFAbaF)0ct*hj}xLTgE8?d!Z#_qat5q-_%`4LO~`i%uFA@XrRSdTm+ z5e6cr=h?5{2mRy34Awpl_ep8J}6p4V;HPX57d4wL3Ah#jfPP?xTjG8u*7C zNQ68|_=i%gjG&YkVvR)k7a@n23EvZ09|uw)B_vE4v8Q8p0{e&xmK_K3Q;M zPIo-NuQz>HY(=+UzfnNWzxy&mP)WWW%%|6tSO$1 zau3Li`a_s66)&!ZStiI_gkJDkwDcQpwO%i--#}E&WqSzSft~M1gJu5AbR~W`UHXO7 z?j+taGV*N&MSH%nv*#&3zx)T4{MV~$TPEqm-W3fBfy5m;ez?U+j`!{oMGwD*t6ch) zr6WsKFmcYw-x-Of)qvxST25Wt0zJ>};sF{Yya%Nykps#pL=i+S3@YWqLo53GXYo%_ z<<4*ubDWbq+Y7b#7&SO=-u7&|V3^)|p?=qke!Vx-_`|V2oAxc1@vfyaL z!$k>W&Wpmuu8=vXKa4tqssYTU`kS<0?JUgS5M9!Dhq@dmnsI_y@_O}JCjKfjk;p7m zk?Dracx$mezUD~@Z!~oO#(rL%(d*tcZjR`q@yLJ4zp}3w3*W!-O5w>Yjx9fEw7@^* z4Pc}f=n5sA!1DB~cfnSAoNu#P4pDEX1{KZL@g)F=w`4_|H_xuThamG*?5oKobh}EG ztQqkUx?`~U`0xgi^=uUID~D2?i7hy`Y!1rQ7`AAu8gyG`;7I?Lx9(GmzwfXZz^`TM zuzIKvFU77DPphsxEbE_npT+lYOrbt2p<*~oWq(KmnKe_dZQWgz;rX%b6EKx+Uq(Fq z4SC8Mk?R=0o{wlm6W(Vj^Y>tuk%rUuStUPBJFUFT@oXLLk8(J_?Dz2xDZ@EI zj;y-cTMMhFiuOu}kB>cu7ora?;(!BF;5?cipFg0_e<8m-Z1DN7HYctC+I*rpO-75M z^>oLjKciFbBW~jEH9s@|4Rx@s>kZESca@Mt4)L#7dDk(1q0BGK04)(0?LkH2Qg6Mu zex9=oz%O^v0ZMkHtj$T0;}gwKg!5lJF)qul1AdXSw%#w~kXD}v@N1|rK)Ym$=LZQ0 zS${qJmh>m0-1kodccU%~45 z_?6}L0)9!(c4=6Le@L2tjmr^=&&hvr{RYB@f6((iCpiF>!HF=H1fqrWUvRNF?X^`7 zx{eDI$AuiI=m_P%>Ld3%4UghNjTh(#gnBk4m7F`Q^Y7nytFU)>;xCPRoX3Wj7g~Ca z)#9*fFCeA142Xdr>(auW_pZmaQTrGEfttSY5ml>VT*#p<|7dkqcdB~FLjEh8m^C`( z|Eb!4S~Fv;q^DGS7KxPrzw-1Wr$NGQT;kqOJD*PV8(%?;8qvZvmHZdjme8TaMf7m} z2qXAxI|HL*!SDXELvm0__)4wGYB`AYra4;0Qxxws_*=Kapq6Ez2M zF8fJUETs#v7Eiwv;X0AXYL0>)GT-a@(0Bru4mnu3QD|krzh+QvxX(#U8=W|Zm{Iq- zT*zSo(WVWbgAABAm+ba1PVj+4XjrxgFc*@ollkX%NtZ;+*AaWb8 z;MY2aWAer&(}nq&ZuFT(pGX+bnh^dbkjqyk8dRmQJ4O;d&v zi;Sa8yK*%dBTl1E#swoQ^Do?g$Yr8fQy$kgN%E&ckzr=5)6t)}q>Nu4 z|H3GWz%M}Cjqx3^rOuJz_8a5lgLC+o#xLeyEq3ZQ!~wQ)WMFHVe{uaG?7XyC=DjlQ zMkmAy`!@EYaI-)}`-gn~3$WD#6rNm!OJig-A6-db8%SmM?AR5m-#FFVCewMy!;n;K z8zvp02lk(@4j(t7S z*E;0kmyInno(t+X)<{4j!Z*+t`o$??P1B5J6nsblmX_m}fu z%)id4_Q`cKYmr9DcV*-M35{ol+KiZ9EpeJCIDb;!lcWcNySe~2fmU;SR z6W1s<%x92(k z1%1!N+jMvh1?RhQ3gHFW{!j7!<@=-Zbi#U19wZ(Yz1M?6slAWBVZWw2ONmG3`S=C? zWrOb!_F)I?#+7^GC2&vJc^CC9)T8x_?~ghlcdY>10_{>Q88n`8k?VI;2P^gSX>8G? z94>aFcmNy?Ys$%&q-(8AI%WNeV@(UvDn@l7y-a0Lr?&-TN0iw251D_l{{wk6|5EWn z`$p_T$WyG;Z}|0xY!43t$gblCAHM$M{>A{mW(nsV+&K7`LYa-J6JebH0xk#mb;j9} zyYfZrUC}5v4}hom=a=2#dCDNmN;7j0avJ-)*Z1k`pE9bu!Z;fuTFl0m>ySD&1 z<}+|`>=gb+CI7|Y2p+{JFr0mLTlJ#wlLeLf!+WiB`BgwGV;pb{_ld^^q;^|(gyM%{ zd|juD(^bpp$u*rSy_Xjk?}1hZ_|-vMT!f~lu@=bLDNgWdd0_oQ@k2GCM`6K*XrcKl zay%{&XB$~*?T6$3Lph|HCxKQ=x^K(jQd|$nnia43B z#xIOwEW!2jXCqxhwdHYPfD@j7i1?uz@9!Ls@58zu$)X&tJU^I?fPa0>9kSBTS#OGZ zahu(muR*;QE1DaduAKk6hyGSIPeJBdKyCA$R7K_rew~2(MEoi0NDlcLop>gs8tzW+Uq(r^g-stKp4L`inR{0LG`5I@&-7ZY+&{I zFAu-yCfbs1ksI>HmvJR;D-(?-pcQgJmGfU!>=Eg#P@4EK6pXpwXS)dSt15zXH%z;F zu%>9(*tDEovg&dn{)K($c(4`ebkgt-p>dsdd@Ig>>2(MH5|Hp_l*s;D^(ldKh`z!9 zkFCcBL;ULyk0Ng@h5OW*jrYa8ix3kNMhL(7*m4TjM$vF}OGmSx|5}DXVkrN`$Cg>t zZZx`6WtoA(75oyLvbs-`z3K9n-udPE!F~?m*AdC{9BXng;p@|R_&+|k3h-;F{N!or zT^rTtfgSFq3*pzeTuBLKG_b0xhvD4q-B*Jg+LmssZA-<#!p0V`Tbgz#%nX%12w z;j^y88PAxzs3NG~m%>>^E|ZAccSLmAh6aw3mCXhCRhvWoVJR^aTOuAG=tBK`j1diX z>{x|={ewJhb&hVk|IycrFa?KzU!F~9MU7CIf1M+g&6i*Xm(VkJURByU1Hz)~0Ydq& zgNSCpZrma+k&m06JW}gdUnu`Yw@LgelkA|s6|JLXuyZjA*TXLd_?642K~JLbB<#-w z!Ws-@&@WsxTE?$~2(!RGPa7@tW9piYXEcz(%biod0r!cYAZ*AcZhNC|>-Iy@wC?cv zucsaTo)_sEt7{Z5WFXUtFt>tV!%Exd6Xq5k;N8GD6e4o9Mo_;Ir(p@30MjkE2y{Nk zUW864Nv-yOBh5HZ!$jdns8sJx{Fl;4B^OT1iEj(9Cp`v5B zf?s25AmTi6F=2JE1TxCCh2UQ^^W%e?{P(sg=xa|OS+j@miI z*K}L^shJBoCU6mAgL|#4;MZL=q#7JZ_$=*Ltx4e5Y1)b>v2hXbucv5G;{5V*@s!+$ zuM)sA@rHCYRTDArf-PMKO?;a^`W%z%Gw z9n$u>on>}}j&HaX{)MPo0pYc88fd748xqGBj+uN<`*n7if7MsLBc3X>Z-`GI-2nGe zCd#A+BR%Z-^Q-Ka<*?NJ%c0={6iq>i4wx-uxt01uq+e}>IvKV$S&js3Jx4!Ouq}P4 zne691&-@D~R-|Po(TA@!&WpDT4^ykOj#cUpUy-<868vjnlXawz>mhX_tOHL5r@Z)l zDzY1+cm$%xCX+}(cKdyF{4l^TMF<;O&?bk*#}d8iBCm`8`%{#;O8@mNmhA^BdI;T3-b;UvLYw@B4_=QU5 zp{~NZnFz}KR96A2cM)FLl|^nnsNdL5_tiJ6)XlkxEMTh|kaP(R$>!T3Po;hX{0nEq zvRJ13Ep{EN>#@fm^9C%g!((?A9d`FR=``5ZA%f_3EK^sjauXXzfx!WO{R80&<%#$~ z-)+%|nQoZLOZ7AMrAQXwX9v_p=o%_|+sC3#{$ky6g~v#Ha(~iHq8HRPf70 zg?52b9u^>7p24Ptf2dG1FdE^ZqkjG-;1~2=A=ZsWVO!_tmsJJ7aP1+}F1Cj{kl4Qv z=V9qe7o7wCg|MOOI)EsMS~ypzu8zO244t&+|w_Y5yCvd> z7>=91*O-(~DFD!p$eX|~G`Mb1>uGR*)CuEld=&)@{@#VI2hels5BWXuM~oBlNO$M> zw!EP)RP^5C@Dy_VP-;yx;eyXn(__lOSS$ zF4;%IdX@Q?H$TVXL&gczfgn-1U*o%;pGy59*jD;ksQGLZ`7d{VW-}}R^RICIA!G*s zx)$-n+W@r?75OivWuEr*%d6jLafer7y%@;muR@~GU(<5^VbvZFw!UXfIZuxwVEaAf z9dJTTL3hIUA3~d28FOdqAF&NI9B>%|D3tMwJP$w4=KYXr+W=R;NiZX0+v4r9;QLdG z;%C+-dslxfpIi!yt?Ls?LH^5QWCsM_F_q+CBff0K>vPy!3yvQ`n-~kY{!n898Te(>q>ZAOn60>@r=yF{geW+zQ8*BRk=oLDVV;@5>zE7hgLMS~@v@ zlcUFeS$TdAd-_$rf1c-AzBSzY5GoDL!C0 zYP@&E(ihSD^Ao}^W?QK}7hOqT@4X^#6tqtZ!wCHH)`Ia1cEg1Y{}|^=3ec~60c6^4 z1o*{lD?N@B?Ip=?&}BLFxx2idL-@sI^YQhAtLb0Vay|(5H-ZZh(RfX;y8GXsf@=A{ zfs6HX9!@d#dj+-Mh>0h}1 z@ci#j;S*{TgjAif`o-b0%mIFBo9S8~78{^e2$`-DkL!pB1{mPiy|9N}OiysnlG{e< z;@~TeZx2KGrAM(_yc)$7uYDNKq~nh(#J`Y|aN$SI(&IQV1(SmBPw{L^h<|A&rQjYs z-SA~D+Q@yRsN^mWugv`ES4B;2}7ms2*)<(0co!6b8gzt}X?c=0U zEm4S?hG3}qKhQl(+c@4k4c?^ji|Y^du44*}AUs4(dcHawsx}|L78gis^h_3B++D^}nkhgpihN!#g7eG8O8wyhnsp&FPRP=^0_x1CF$vnv z_gDDWZ8*W#Ch+Hc6r!z!Mp|K_+;t-r{*~fbt{WQyeicctMHj}^IAhJ$t@QlEQdKX0 zRd8`T$`cL}5WEBl=+~|ps{>wTAL~Ua@*%>t8&0e@_s_JS8>hq)!ujPAh*(g+VR8P; zO)N0RXxb@SxIZfHJZWdfu^|Kgg}P-MRpkZjRlWW8#*l}#pzE} za4^4Fy?1#VpVao_hhF_5R;LfTGeix7{X>ZYr=zJW%JmzH?sAICNm{*iCrQ&T1V0Ji zQo%AiaZQ!t>I^}@E+yz{IGt%~{Ir%Sy+>=@GFWenk!bP=9 zl1&y0FmAQ(#=$h3Wv;JE)5C;p7x9kM!1ln z0Uo0tKjiwu0mJ`XHm(6Jon-uS(K#GHgx{OqQMYvX zQ)~2v$;{t5!Wm0>{^5qmkO2ScPW;{XU+KYGtZB^~B?o~-_#1;SP?lx(?vHA#TBrF} z?+C4fa}9jgj4YJ@`Z~4e@%>-*OvJVip8&PrY&K>r7xjlyzbCQ|u2Iu;3j9lbtFCEc zPorqHu-T?l9hLZDoFTxq`g4ouI|G+V99oR;My~c)>SQkEy~pEU`%A!`CG>{6q5%H2 zWc2Yp%ctXiVJySE;>Y{`FKAO?Z3&eis|h~j>+XBmNBAt2k6)bsI=i#0KwmUgqtH#m z76{$2K6qt&>xKMR_CBk1*!og#k-9(Id=2ZDV0(y$pa0_e!~G4-R6kKy?|_J@*fh@m zbB+vsK)qO=?4qZrDAOyb2{l%G`}Ez9X$@pBjKTd;KQK=XboSkQ@MFycE!>r`+iAgOo}g2`oZ!3GV*%*w;}_Q-KIJTz;9u_$5=P_OX4uY0x;QZ9*DxsL zzlM+C0>EKxzhT)jzGZ*z7g@fjwwH;R)-MJ9LbhuRTWd;fcHm<1{Tur5(S7J6d0ePJ z6geuWJtPny#TJFlJgR*X*bQI5IRB-y+t^yzHkuTlz_>V&7;_A5SGoR>`Il!mxY5V> zWomzZF8?ZlCTk*g6hv%R!2{uQ6La_%XxE5%!+I#!`Xcf~|0)@&;YZEoUoMLZj7z)A zSa@!LGnV-ma*_J4%4x4C=l=ZnoX5W~^H>7JMQc@~zZQiH_?HLA9q#;7JT6AzQU$;6 z^&mjM2h##ant`5oZw0?RUjn;@#b|Y@Q1&-M^@r=cQIyAJRbyQGQp%uyzWn`PpfFs& z(Okm$<(Gu!GIQ?V(Alnxq3bu?7wyKQr1@8<{_vnT3eJD=aQ^B!W7hG;6`QEb^4{>y zFJlz`{ZV6l*BNkGk82M9(rino3C8$~zzYAu{3{ze|D{ER%z!P(9J@97lF~A75OesK z_Jjdjyxgm>55J+;w64s*P(SZwyEJTpcI`13$k521&%eO77<@Y;NPD^52=g!R`zzt< zgMYEB&jg{&3xt{Bv6uN5;D+nNk=r`p-@g&tjv$8CFVr9EUj=kk9{;ynf;wwm=zIi+y@q29(W_Ns1-gVf-=Ao)hAoA74Id&95aC?!sNX|L(@`oR~( z`+WZwYs!5&6g&uAdziys)w?&qFTOuYTfdpXPOjf5fq!)p3U9K=Rs``w=3f>48V9%H zYK>3Gx$#54&+pRxk+fT10*E7+PqFplJpKjy<4r<+S`5QmP7zjl+}rcP{k_x1Mi?{@ zv4ewY&$7)q|K+nS&*-%lU}W$;2yE--@GouoJG5DG_m0uTy84+>qSJm7gd_zlIb=vb3J63Eul z5#8YRd91hUmdNj_-*y&{U(hIj)?*S*V7-3Ng^jYzy=F3Escy#}E;p3vcu!Qh&!?-p z2l@)vrxr)c4H1z8eZ}k3i>W-Wc;s{Rd3SN9YMs~UN8`6ix(hO<48}zg=F_AI=|&Gl zEHrRy3(*?C&tqAn!gAy&%kdk%XjGvpP+4pI&w5N&Wg}mtFVJO}7H-JJYTiweUOZVG z$SjR4ZpK`huoP^^BtdD-; zXe{70&8T(GLdzU2Hy*75gXJf#L;B~j?yBs-dglw);#|2gSd~50%TH8!T;1Vu`xB7y zW+EhWcA(z5##$guzmYRn49s_~>0J=?$yTk8e1Sf%7FQaPdg|sUvbyQseE z!Up*=V_c*p%9OEJ(P+?{)>La8ySJy@=do*y&#LFLAFr?B#+ct2&`-*r_1HC4HxK-7 z_P6UVJB-G9G!}D%pDcF$wYd5k<7V|@_KNzN!+xWR`@ER_&-ItO3%ohJy8NEt&p&^7 z(Q;+!_bl-Ai$qzQa@=5aV_if!C|rj89=e1W#@DQ z3y18~ZT0-5(x(dAxXtkIRVkxz}eF$E((c8tQsyu~j8~ zneqAEWNY=MZqtsK^jQnx5&fjxEpBAc&`-FbDxc-x&4OTI(NMyn zy#6fx#P4MF+_<1#UDL2&m>WaaM9|1`qhUeiJy-WFxZb=vvRLZI=h0ZhPqPB$%36SFKh&T;>PFbIrrn4nsvJ2=tk8TKdF3{4*^vbESPso zWIdyUTYgbveeYp=`OwxI{6_qSMq9ddnW3!>j%*apSHlCck#-%3FI6 zFWftM;;TWQi0GGh+aEP?@PZrj%8idMn(vl7nR9Si{)P|GjMPCNF~@Gq#pUvQh<*v4 z+7VUmW0|)^E>WL!7K~re2tMnVz6Xe3dC&Q{>;v=$JLt2_{PaLwp=Zy63mg7xEH_Tt zbY)<=&TmK$z5r-62bTkYHf03b$v>7W%WC844;}@IROw@8fiu_80;L;YE;smz_Z~YU zMV5BZQkt(WXyo)qk-YkSaoIy^*RzKbT`$Dt;E8^bgn$_pcMOY0FKD>Bi~g(tM$d03 z|Fa_Rhs(Z)qP+L?MY=0+e8GFlpC!${$RfI$7F^iq_CBkZs%ed~vu1td!iM)6>IKGy zaXA2JZuos9@HB+W0YH1W>|;vg8uR9XOR}G=UvT(>hU?25xklWq?#_O+e*WPL8g4{) z>bnq^1AtyUT3)YTsb6{{N{symRiCY{kKBGiLwWMh)mih_$P)UbT2Q*6QQjL^uQ|9J z05s#W_a2G$nuE&$Kr=4;eXtMZ01jZVuXTQd%HuMq&s~(MVstydA^rD2RVug~0Q4MO z#-2Y9mji$fa9Kv=T>T0ZjT`=F{VM$`_rV;liqz6tg)c-nzv0heA3^hF+%`-)bV0-Q zKZ~jek;*<}5j}Q6W7O|+^;&${Ks~-Ba>3vQjX=L7g>kuJSG38|FOrd74~_#|4mDKy zv)~&nSOi>N@IH<5dWC$k@S5j9dc4=*-wWY5c;fewSAWL%oP2KL<11<|Y)JpJBE1(t zKmZDE`NJ5F>&m!1r?IBo<^NY)o(soifc}f%vo3_=@{=<`pEkAZuou51~&MU zaKm)M|Mjcd9UZ^ow~55B_~rksUv-^3ch2RPU)Tsf^1@#QPyUzfGe?&LrT(9z%fF6I z_!T20oa94`$$l8TfZR z1KMAL!vudx{yUzA4~G81416#HAI!i9Gw{I-d@uw5PGEnA;7jp)4pq`p{!9KJU6^^c diff --git a/fpga/fpga_hf.v b/fpga/fpga_hf.v index e84081b3..8a465e75 100644 --- a/fpga/fpga_hf.v +++ b/fpga/fpga_hf.v @@ -67,8 +67,10 @@ assign major_mode = conf_word[7:5]; // some fraction of the buffers) wire hi_read_tx_shallow_modulation = conf_word[0]; -// For the high-frequency receive correlator: -// whether to drive the coil (reader) or just short it (snooper) +// For the high-frequency receive correlator: frequency against which to +// correlate. +wire hi_read_rx_xcorr_848 = conf_word[0]; +// and whether to drive the coil (reader) or just short it (snooper) wire hi_read_rx_xcorr_snoop = conf_word[1]; // For the high-frequency simulated tag: what kind of modulation to use. @@ -97,7 +99,7 @@ hi_read_rx_xcorr hrxc( hrxc_ssp_frame, hrxc_ssp_din, ssp_dout, hrxc_ssp_clk, cross_hi, cross_lo, hrxc_dbg, - hi_read_rx_xcorr_snoop + hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop ); hi_simulate hs( diff --git a/fpga/hi_read_rx_xcorr.v b/fpga/hi_read_rx_xcorr.v index a6a99cd5..4a5de553 100644 --- a/fpga/hi_read_rx_xcorr.v +++ b/fpga/hi_read_rx_xcorr.v @@ -10,7 +10,7 @@ module hi_read_rx_xcorr( ssp_frame, ssp_din, ssp_dout, ssp_clk, cross_hi, cross_lo, dbg, - snoop + xcorr_is_848, snoop ); input pck0, ck_1356meg, ck_1356megb; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; @@ -20,7 +20,7 @@ module hi_read_rx_xcorr( output ssp_frame, ssp_din, ssp_clk; input cross_hi, cross_lo; output dbg; - input snoop; + input xcorr_is_848, snoop; // Carrier is steady on through this, unless we're snooping. assign pwr_hi = ck_1356megb & (~snoop); @@ -28,8 +28,22 @@ assign pwr_oe1 = 1'b0; assign pwr_oe3 = 1'b0; assign pwr_oe4 = 1'b0; -wire adc_clk = ck_1356megb; +(* clock_signal = "yes" *) reg fc_div_2; +always @(negedge ck_1356megb) + fc_div_2 <= fc_div_2 + 1; +(* clock_signal = "yes" *) reg adc_clk; +always @(xcorr_is_848, ck_1356megb, fc_div_2) +if (xcorr_is_848) + // The subcarrier frequency is fc/16; we will sample at fc, so that + // means the subcarrier is 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 ... + adc_clk <= ck_1356megb; +else + // The subcarrier frequency is fc/32; we will sample at fc/2, and + // the subcarrier will look identical. + adc_clk <= fc_div_2; + + // When we're a reader, we just need to do the BPSK demod; but when we're an // eavesdropper, we also need to pick out the commands sent by the reader, // using AM. Do this the same way that we do it for the simulated tag. From 467340996e7af6563070df2c96c374e6a97b1456 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sun, 21 Jun 2015 18:00:42 +0200 Subject: [PATCH 8/9] fixing iso14443b (issue #103): - fix hf 14b snoop - fix hf 14b sim --- armsrc/iso14443b.c | 161 ++++++++++++++++++++-------------------- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/hi_read_rx_xcorr.v | 26 +++---- 3 files changed, 90 insertions(+), 97 deletions(-) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 8d1a5cca..1ae1692b 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -122,8 +122,7 @@ static struct { STATE_UNSYNCD, STATE_GOT_FALLING_EDGE_OF_SOF, STATE_AWAITING_START_BIT, - STATE_RECEIVING_DATA, - STATE_ERROR_WAIT + STATE_RECEIVING_DATA } state; uint16_t shiftReg; int bitCnt; @@ -145,7 +144,7 @@ static struct { * Returns: true if we received a EOF * false if we are still waiting for some more */ -static int Handle14443bUartBit(int bit) +static RAMFUNC int Handle14443bUartBit(uint8_t bit) { switch(Uart.state) { case STATE_UNSYNCD: @@ -172,7 +171,7 @@ static int Handle14443bUartBit(int bit) } else { // didn't stay down long enough // before going high, error - Uart.state = STATE_ERROR_WAIT; + Uart.state = STATE_UNSYNCD; } } else { // do nothing, keep waiting @@ -183,7 +182,8 @@ static int Handle14443bUartBit(int bit) if(Uart.bitCnt > 12) { // Give up if we see too many zeros without // a one, too. - Uart.state = STATE_ERROR_WAIT; + LED_A_OFF(); + Uart.state = STATE_UNSYNCD; } break; @@ -193,7 +193,7 @@ static int Handle14443bUartBit(int bit) if(Uart.posCnt > 50/2) { // max 57us between characters = 49 1/fs, max 3 etus after low phase of SOF = 24 1/fs // stayed high for too long between // characters, error - Uart.state = STATE_ERROR_WAIT; + Uart.state = STATE_UNSYNCD; } } else { // falling edge, this starts the data byte @@ -227,41 +227,30 @@ static int Handle14443bUartBit(int bit) if(Uart.byteCnt >= Uart.byteCntMax) { // Buffer overflowed, give up - Uart.posCnt = 0; - Uart.state = STATE_ERROR_WAIT; + LED_A_OFF(); + Uart.state = STATE_UNSYNCD; } else { // so get the next byte now Uart.posCnt = 0; Uart.state = STATE_AWAITING_START_BIT; } - } else if(Uart.shiftReg == 0x000) { + } else if (Uart.shiftReg == 0x000) { // this is an EOF byte LED_A_OFF(); // Finished receiving + Uart.state = STATE_UNSYNCD; if (Uart.byteCnt != 0) { return TRUE; } - Uart.posCnt = 0; - Uart.state = STATE_ERROR_WAIT; } else { // this is an error - Uart.posCnt = 0; - Uart.state = STATE_ERROR_WAIT; + LED_A_OFF(); + Uart.state = STATE_UNSYNCD; } } break; - case STATE_ERROR_WAIT: - // We're all screwed up, so wait a little while - // for whatever went wrong to finish, and then - // start over. - Uart.posCnt++; - if(Uart.posCnt > 10) { - Uart.state = STATE_UNSYNCD; - LED_A_OFF(); - } - break; - default: + LED_A_OFF(); Uart.state = STATE_UNSYNCD; break; } @@ -269,6 +258,23 @@ static int Handle14443bUartBit(int bit) return FALSE; } + +static void UartReset() +{ + Uart.byteCntMax = MAX_FRAME_SIZE; + Uart.state = STATE_UNSYNCD; + Uart.byteCnt = 0; + Uart.bitCnt = 0; +} + + +static void UartInit(uint8_t *data) +{ + Uart.output = data; + UartReset(); +} + + //----------------------------------------------------------------------------- // 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 @@ -278,44 +284,34 @@ static int Handle14443bUartBit(int bit) // Assume that we're called with the SSC (to the FPGA) and ADC path set // correctly. //----------------------------------------------------------------------------- -static int GetIso14443bCommandFromReader(uint8_t *received, int *len, int maxLen) +static int GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len) { - uint8_t mask; - int i, bit; - // 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); - // Now run a `software UART' on the stream of incoming samples. - Uart.output = received; - Uart.byteCntMax = maxLen; - Uart.state = STATE_UNSYNCD; + UartInit(received); for(;;) { WDT_HIT(); if(BUTTON_PRESS()) return FALSE; - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; - } if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - - mask = 0x80; - for(i = 0; i < 8; i++, mask >>= 1) { - bit = (b & mask); - if(Handle14443bUartBit(bit)) { + for(uint8_t mask = 0x80; mask != 0x00; mask >>= 1) { + if(Handle14443bUartBit(b & mask)) { *len = Uart.byteCnt; return TRUE; } } } } + + return FALSE; } //----------------------------------------------------------------------------- @@ -324,9 +320,12 @@ static int GetIso14443bCommandFromReader(uint8_t *received, int *len, int maxLen //----------------------------------------------------------------------------- void SimulateIso14443bTag(void) { - // the only command we understand is REQB, AFI=0, Select All, N=0: + // the only commands we understand is REQB, AFI=0, Select All, N=0: static const uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; - // ... and we respond with ATQB, PUPI = 820de174, Application Data = 0x20381922, + // ... and REQB, AFI=0, Normal Request, N=0: + static const uint8_t cmd2[] = { 0x05, 0x00, 0x00, 0x71, 0xFF }; + + // ... and 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: static const uint8_t response1[] = { @@ -334,25 +333,27 @@ void SimulateIso14443bTag(void) 0x00, 0x21, 0x85, 0x5e, 0xd7 }; - uint8_t *resp; - int respLen; + clear_trace(); + set_tracing(TRUE); + + const uint8_t *resp; + uint8_t *respCode; + uint16_t respLen, respCodeLen; // allocate command receive buffer BigBuf_free(); uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); - int len; - int i; - - int cmdsRecvd = 0; + uint16_t len; + uint16_t cmdsRecvd = 0; FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // prepare the (only one) tag answer: CodeIso14443bAsTag(response1, sizeof(response1)); - uint8_t *resp1 = BigBuf_malloc(ToSendMax); - memcpy(resp1, ToSend, ToSendMax); - uint16_t resp1Len = ToSendMax; + uint8_t *resp1Code = BigBuf_malloc(ToSendMax); + memcpy(resp1Code, ToSend, ToSendMax); + uint16_t resp1CodeLen = ToSendMax; // We need to listen to the high-frequency, peak-detected path. SetAdcMuxFor(GPIO_MUXSEL_HIPKD); @@ -361,20 +362,28 @@ void SimulateIso14443bTag(void) cmdsRecvd = 0; for(;;) { - uint8_t b1, b2; - if(!GetIso14443bCommandFromReader(receivedCmd, &len, 100)) { + if(!GetIso14443bCommandFromReader(receivedCmd, &len)) { Dbprintf("button pressed, received %d commands", cmdsRecvd); break; - } + } + + if (tracing) { + uint8_t parity[MAX_PARITY_SIZE]; + LogTrace(receivedCmd, len, 0, 0, parity, TRUE); + } // Good, look at the command now. - - if(len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len) == 0) { - resp = resp1; respLen = resp1Len; + if ( (len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len) == 0) + || (len == sizeof(cmd2) && memcmp(receivedCmd, cmd2, len) == 0) ) { + resp = response1; + respLen = sizeof(response1); + respCode = resp1Code; + respCodeLen = resp1CodeLen; } else { Dbprintf("new cmd from reader: len=%d, cmdsRecvd=%d", len, cmdsRecvd); // And print whether the CRC fails, just for good measure + uint8_t b1, b2; ComputeCrc14443(CRC_14443_B, receivedCmd, len-2, &b1, &b2); if(b1 != receivedCmd[len-2] || b2 != receivedCmd[len-1]) { // Not so good, try again. @@ -392,7 +401,7 @@ void SimulateIso14443bTag(void) break; } - if(respLen <= 0) continue; + if(respCodeLen <= 0) continue; // Modulate BPSK // Signal field is off with the appropriate LED @@ -402,15 +411,15 @@ void SimulateIso14443bTag(void) FpgaSetupSsc(); // Transmit the response. - i = 0; + uint16_t i = 0; for(;;) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - uint8_t b = resp[i]; + uint8_t b = respCode[i]; AT91C_BASE_SSC->SSC_THR = b; i++; - if(i > respLen) { + if(i > respCodeLen) { break; } } @@ -419,6 +428,13 @@ void SimulateIso14443bTag(void) (void)b; } } + + // trace the response: + if (tracing) { + uint8_t parity[MAX_PARITY_SIZE]; + LogTrace(resp, respLen, 0, 0, parity, FALSE); + } + } } @@ -436,8 +452,7 @@ static struct { DEMOD_AWAITING_FALLING_EDGE_OF_SOF, DEMOD_GOT_FALLING_EDGE_OF_SOF, DEMOD_AWAITING_START_BIT, - DEMOD_RECEIVING_DATA, - DEMOD_ERROR_WAIT + DEMOD_RECEIVING_DATA } state; int bitCount; int posCount; @@ -684,22 +699,6 @@ static void DemodInit(uint8_t *data) } -static void UartReset() -{ - Uart.byteCntMax = MAX_FRAME_SIZE; - Uart.state = STATE_UNSYNCD; - Uart.byteCnt = 0; - Uart.bitCnt = 0; -} - - -static void UartInit(uint8_t *data) -{ - Uart.output = data; - UartReset(); -} - - /* * Demodulate the samples we received from the tag, also log to tracebuffer * quiet: set to 'TRUE' to disable debug output @@ -1163,11 +1162,11 @@ void RAMFUNC SnoopIso14443b(void) /* false-triggered by the commands from the reader. */ DemodReset(); } - ReaderIsActive = (Uart.state != STATE_UNSYNCD); + ReaderIsActive = (Uart.state > STATE_GOT_FALLING_EDGE_OF_SOF); } if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time - if(Handle14443bSamplesDemod(ci & 0xFE, cq & 0xFE)) { + if(Handle14443bSamplesDemod(ci | 0x01, cq | 0x01)) { //Use samples as a time measurement if(tracing) diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 49bec2242cb7720524289f3eba1397bbc2a22867..a4d72e373bb59cfa56cc3869b1ccb3c18908250a 100644 GIT binary patch literal 42175 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 z Date: Mon, 22 Jun 2015 21:45:28 +0200 Subject: [PATCH 9/9] fixing iso14443b (issue #103): - increased DMA_BUFFER_SIZE to avoid occasional circular buffer overflows. - minor code cleanups --- armsrc/iso14443b.c | 93 ++++++++++++++-------------------------- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/hi_read_rx_xcorr.v | 4 +- 3 files changed, 33 insertions(+), 64 deletions(-) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 1ae1692b..416c31f9 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -17,6 +17,7 @@ #include "iso14443crc.h" #define RECEIVE_SAMPLES_TIMEOUT 2000 +#define ISO14443B_DMA_BUFFER_SIZE 256 //============================================================================= // An ISO 14443 Type B tag. We listen for commands from the reader, using @@ -717,16 +718,16 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE); // The DMA buffer, used to stream samples from the FPGA - int8_t *dmaBuf = (int8_t*) BigBuf_malloc(DMA_BUFFER_SIZE); + int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); // Set up the demodulator for tag -> reader responses. DemodInit(receivedResponse); // Setup and start DMA. - FpgaSetupSscDma((uint8_t*) dmaBuf, DMA_BUFFER_SIZE); + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); int8_t *upTo = dmaBuf; - lastRxCounter = DMA_BUFFER_SIZE; + lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; // Signal field is ON with the appropriate LED: LED_D_ON(); @@ -737,18 +738,18 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR; if(behindBy > max) max = behindBy; - while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE-1)) > 2) { + while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1)) > 2) { ci = upTo[0]; cq = upTo[1]; upTo += 2; - if(upTo >= dmaBuf + DMA_BUFFER_SIZE) { + if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { upTo = dmaBuf; AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; - AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; } lastRxCounter -= 2; if(lastRxCounter <= 0) { - lastRxCounter += DMA_BUFFER_SIZE; + lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; } samples += 2; @@ -770,7 +771,6 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) //Tracing if (tracing && Demod.len > 0) { uint8_t parity[MAX_PARITY_SIZE]; - //GetParity(Demod.output, Demod.len, parity); LogTrace(Demod.output, Demod.len, 0, 0, parity, FALSE); } } @@ -892,7 +892,6 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) TransmitFor14443b(); if (tracing) { uint8_t parity[MAX_PARITY_SIZE]; - GetParity(cmd, len, parity); LogTrace(cmd,len, 0, 0, parity, TRUE); } } @@ -927,35 +926,29 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) // Now give it time to spin up. // Signal field is on with the appropriate LED LED_D_ON(); - FpgaWriteConfWord( - FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); SpinDelay(200); // First command: wake up the tag using the INITIATE command uint8_t cmd1[] = {0x06, 0x00, 0x97, 0x5b}; - CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); -// LED_A_ON(); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); -// LED_A_OFF(); if (Demod.len == 0) { - DbpString("No response from tag"); - return; + DbpString("No response from tag"); + return; } else { - Dbprintf("Randomly generated UID from tag (+ 2 byte CRC): %02x %02x %02x", - Demod.output[0], Demod.output[1], Demod.output[2]); + Dbprintf("Randomly generated Chip ID (+ 2 byte CRC): %02x %02x %02x", + Demod.output[0], Demod.output[1], Demod.output[2]); } + // There is a response, SELECT the uid DbpString("Now SELECT tag:"); cmd1[0] = 0x0E; // 0x0E is SELECT cmd1[1] = Demod.output[0]; ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); - -// LED_A_ON(); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); -// LED_A_OFF(); if (Demod.len != 3) { Dbprintf("Expected 3 bytes from tag, got %d", Demod.len); return; @@ -971,15 +964,13 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) Dbprintf("Bad response to SELECT from Tag, aborting: %02x %02x", cmd1[1], Demod.output[0]); return; } + // Tag is now selected, // First get the tag's UID: cmd1[0] = 0x0B; ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]); CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one - -// LED_A_ON(); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); -// LED_A_OFF(); if (Demod.len != 10) { Dbprintf("Expected 10 bytes from tag, got %d", Demod.len); return; @@ -988,12 +979,12 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) ComputeCrc14443(CRC_14443_B, Demod.output, 8, &cmd1[2], &cmd1[3]); if(cmd1[2] != Demod.output[8] || cmd1[3] != Demod.output[9]) { Dbprintf("CRC Error reading block! Expected: %04x got: %04x", - (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]); + (cmd1[2]<<8)+cmd1[3], (Demod.output[8]<<8)+Demod.output[9]); // Do not return;, let's go on... (we should retry, maybe ?) } Dbprintf("Tag UID (64 bits): %08x %08x", - (Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4], - (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]); + (Demod.output[7]<<24) + (Demod.output[6]<<16) + (Demod.output[5]<<8) + Demod.output[4], + (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0]); // Now loop to read all 16 blocks, address from 0 to last block Dbprintf("Tag memory dump, block 0 to %d", dwLast); @@ -1008,10 +999,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) cmd1[1] = i; ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); - -// LED_A_ON(); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE); -// LED_A_OFF(); if (Demod.len != 6) { // Check if we got an answer from the tag DbpString("Expected 6 bytes from tag, got less..."); return; @@ -1020,13 +1008,13 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]); if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) { Dbprintf("CRC Error reading block! Expected: %04x got: %04x", - (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]); + (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]); // Do not return;, let's go on... (we should retry, maybe ?) } // Now print out the memory location: Dbprintf("Address=%02x, Contents=%08x, CRC=%04x", i, - (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0], - (Demod.output[4]<<8)+Demod.output[5]); + (Demod.output[3]<<24) + (Demod.output[2]<<16) + (Demod.output[1]<<8) + Demod.output[0], + (Demod.output[4]<<8)+Demod.output[5]); if (i == 0xff) { break; } @@ -1049,7 +1037,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) * Memory usage for this function, (within BigBuf) * Last Received command (reader->tag) - MAX_FRAME_SIZE * Last Received command (tag->reader) - MAX_FRAME_SIZE - * DMA Buffer - DMA_BUFFER_SIZE + * DMA Buffer - ISO14443B_DMA_BUFFER_SIZE * Demodulated samples received - all the rest */ void RAMFUNC SnoopIso14443b(void) @@ -1066,7 +1054,7 @@ void RAMFUNC SnoopIso14443b(void) set_tracing(TRUE); // The DMA buffer, used to stream samples from the FPGA - int8_t *dmaBuf = (int8_t*) BigBuf_malloc(DMA_BUFFER_SIZE); + int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); int lastRxCounter; int8_t *upTo; int ci, cq; @@ -1084,7 +1072,7 @@ void RAMFUNC SnoopIso14443b(void) Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); Dbprintf(" Reader -> tag: %i bytes", MAX_FRAME_SIZE); Dbprintf(" tag -> Reader: %i bytes", MAX_FRAME_SIZE); - Dbprintf(" DMA: %i bytes", DMA_BUFFER_SIZE); + Dbprintf(" DMA: %i bytes", ISO14443B_DMA_BUFFER_SIZE); // Signal field is off, no reader signal, no tag signal LEDsoff(); @@ -1096,8 +1084,8 @@ void RAMFUNC SnoopIso14443b(void) // Setup for the DMA. FpgaSetupSsc(); upTo = dmaBuf; - lastRxCounter = DMA_BUFFER_SIZE; - FpgaSetupSscDma((uint8_t*) dmaBuf, DMA_BUFFER_SIZE); + lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); uint8_t parity[MAX_PARITY_SIZE]; bool TagIsActive = FALSE; @@ -1106,7 +1094,7 @@ void RAMFUNC SnoopIso14443b(void) // And now we loop, receiving samples. for(;;) { int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & - (DMA_BUFFER_SIZE-1); + (ISO14443B_DMA_BUFFER_SIZE-1); if(behindBy > maxBehindBy) { maxBehindBy = behindBy; } @@ -1117,13 +1105,13 @@ void RAMFUNC SnoopIso14443b(void) cq = upTo[1]; upTo += 2; lastRxCounter -= 2; - if(upTo >= dmaBuf + DMA_BUFFER_SIZE) { + if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { upTo = dmaBuf; - lastRxCounter += DMA_BUFFER_SIZE; + lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; - AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; WDT_HIT(); - if(behindBy > (9*DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not? + if(behindBy > (9*ISO14443B_DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not? Dbprintf("blew circular buffer! behindBy=%d", behindBy); break; } @@ -1142,7 +1130,6 @@ void RAMFUNC SnoopIso14443b(void) if (!TagIsActive) { // no need to try decoding reader data if the tag is sending if(Handle14443bUartBit(ci & 0x01)) { if(triggered && tracing) { - //GetParity(Uart.output, Uart.byteCnt, parity); LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE); } /* And ready to receive another command. */ @@ -1153,7 +1140,6 @@ void RAMFUNC SnoopIso14443b(void) } if(Handle14443bUartBit(cq & 0x01)) { if(triggered && tracing) { - //GetParity(Uart.output, Uart.byteCnt, parity); LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE); } /* And ready to receive another command. */ @@ -1172,7 +1158,6 @@ void RAMFUNC SnoopIso14443b(void) if(tracing) { uint8_t parity[MAX_PARITY_SIZE]; - //GetParity(Demod.output, Demod.len, parity); LogTrace(Demod.output, Demod.len, samples, samples, parity, FALSE); } triggered = TRUE; @@ -1217,22 +1202,6 @@ void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, u set_tracing(TRUE); -/* if(!powerfield) { - // Make sure that we start from off, since the tags are stateful; - // confusing things will happen if we don't reset them between reads. - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - SpinDelay(200); - } - */ - - // if(!GETBIT(GPIO_LED_D)) { // if field is off - // FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); - // // Signal field is on with the appropriate LED - // LED_D_ON(); - // SpinDelay(200); - // } - CodeAndTransmit14443bAsReader(data, datalen); if(recv) { diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index a4d72e373bb59cfa56cc3869b1ccb3c18908250a..50c7eef97c8b98461b7d8be9e4e643dd85910241 100644 GIT binary patch literal 42175 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
aF>5%M+C8_(G-6 z$7*^8`U~}M`4oNHU6jE^6)p5b_$*0xLB^E9yhy@5F$uQM z7c2-C|Nm?JK2K#)%8>(;c%)jP#;q zk*bVY8d*9{*HfLU2*dc>J<`i9sxq&hVBS?B z8-wA9GTe$__SsJ?7N zW6d1lHg2KnyhusMhA$HFh1>#Dt#RyLv(o3On~mRAFJ?c|SjWP6c3EQ_!odC9QhC=? zH`m-b@VV?~8*84fxl?V(ex`BJ-B)-m&( zkN=#8yK9>6;s-8z+PqU)+23qj%-sC3c# zB?J9}Fi9=23A)AaR1;Yy*Y_`MFrQ+fkA<3L)GHU-X7HTmnoUQ3H}jbtiypX4P}O%i zgiITe!tn(PI>g}_2;AcTSnKXs(5P;1S}@GQ(9MzG9$uGap=m+Thi>XyaGQBkWP#Me zry;EAvu`s$9a$uU=iqODqjt#Ae+0ZQx5yK2%|{lJbm%}=DC$l zW(bZoKr=3TLeNJ^+CiVC=Enx=3+qM}TrT*JvD`Rm)0K&=zf6#}*UJsy_)O zeN4ugn`wc%T=4qX5h=2?i%SLB!BvhSfN?>T*uo+=z)_MFPQq}dl~pqpsH0O$ukcRK)jtg>IfQojORmYDnPsxe#J7`gj0LHQHA zDQj+tTtmO97L+d&DrW=xbqOv90A0~9iT#>`%K<<$F8g!GIrIvE7KqCPs?5uvKDQxL z!{~OYApPe6VXC;S;dnvN;&tJ3cnK~8l`1WjcSYpoY8ABj@48gKz8F?CzYo@MWn@0B zRefb&umizg!#;xM%Q#nA9l1Q^dmBih!1}%DdK@*&~gao8t=x zwNP6T(4zb`j7ZXOTrnqNj^Mp3((A!-1($0pLKT$k|f(DJtTBrdo2Q8KT3i)E; zJbpjq(y$eTWHd`iAJ`H>ZMmkY8ouU=wm7KVTT6x_?^JxI9N# zQ|ah-q;w3;(<;9*5^ob6M-83SX+LsGKpE>iIYx2EU;Z46}St<)vd5%q2WN^5@ zLW^Ap6I#H^Yhlbg(beam20Y_0ct!A^L&0P?ILNDr6{`sTc<>+p7rbBoQU-$GsbXL$ z&Q*clPav3%-||2FPiN=9(WO;Xs!w z!ezSrOKhh9uBt8vN?jGId+O_QpwuD3?-b~A^&eHG_jUP~nS%ds^}V_~ze>vBFG2A! z$xzR4{i;6ix4*vv@2|l7EAajbyuSkPufY2&@E>^vw7&$03I3A&kGu}=&;9)scz*@n zUxD{m;QbYNe+B+yt^mUM$TWQZiy2b*FCnTg=lwb>;rFk};47fq-+RuHYFf&F$o~V| Ce|JUz literal 42175 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