From 1929af0c9e70cbc2411628e14f70f86ef555dfed Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 25 Mar 2014 21:31:37 +0100 Subject: [PATCH 1/2] Provide .gitignore to prevent unwanted files to be committed --- .gitignore | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..a43a00fe7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# .gitignore +# don't push these files to the repository + +*.o +*.a +*.d +*.elf +*.s19 +*.map +*.bin +*.dll +*.moc.cpp +*.exe +proxmark +flasher +version.c + +fpga/* +!fpga/fpga.bit +!fpga/*.v +!fpga/Makefile +!fpga/fpga.ucf +!fpga/xst.scr +!fpga/go.bat +!fpga/sim.tcl + + From d714d3effc50b7761dd308c6b0864deea14bd483 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 25 Mar 2014 21:38:24 +0100 Subject: [PATCH 2/2] Improvements/Fixes to 14443 sniffing/snooping - fixed a circular buffer rollover bug in iso14443a.c - fixed 7 Byte UID handling in hf mf sniff - fixed "cannot append" error in hf mf sniff d - fixed hint on mfkey32 in hf mf sim x - fixed hf mf sniff sometimes showing rogue data from previous calloc - improve snooping/sniffing by syncing modulation detector window with reader signal (hi_iso14443a.v) - code cleanup of hi_iso14443a.v --- armsrc/fpgaloader.c | 4 +- armsrc/iso14443a.c | 71 ++-- armsrc/mifaresniff.c | 3 +- armsrc/util.c | 2 - client/cmdhfmf.c | 10 +- fpga/fpga.bit | Bin 42172 -> 42172 bytes fpga/hi_iso14443a.v | 757 +++++++++++++++++++++++++------------------ 7 files changed, 478 insertions(+), 369 deletions(-) diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index 1e728e118..d63310a35 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -115,11 +115,11 @@ void FpgaSetupSsc(void) AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1); // 8 bits per transfer, no loopback, MSB first, 1 transfer per sync - // pulse, no output sync, start on positive-going edge of sync + // pulse, no output sync AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); // clock comes from TK pin, no clock output, outputs change on falling - // edge of TK, sample on rising edge of TK + // edge of TK, sample on rising edge of TK, start on positive-going edge of sync AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5); // tx framing is the same as the rx framing diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index b105e792d..9afe0788c 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -42,15 +42,14 @@ static uint8_t iso14_pcb_blocknum = 0; // // Total delays including SSC-Transfers between ARM and FPGA. These are in carrier clock cycles (1/13,56MHz) // -// When the PM acts as reader and is receiving, it takes -// 3 ticks for the A/D conversion -// 10 ticks ( 16 on average) delay in the modulation detector. -// 6 ticks until the SSC samples the first data -// 7*16 ticks to complete the transfer from FPGA to ARM -// 8 ticks to the next ssp_clk rising edge +// When the PM acts as reader and is receiving tag data, it takes +// 3 ticks delay in the AD converter +// 16 ticks until the modulation detector completes and sets curbit +// 8 ticks until bit_to_arm is assigned from curbit +// 8*16 ticks for the transfer from FPGA to ARM // 4*16 ticks until we measure the time // - 8*16 ticks because we measure the time of the previous transfer -#define DELAY_AIR2ARM_AS_READER (3 + 10 + 6 + 7*16 + 8 + 4*16 - 8*16) +#define DELAY_AIR2ARM_AS_READER (3 + 16 + 8 + 8*16 + 4*16 - 8*16) // When the PM acts as a reader and is sending, it takes // 4*16 ticks until we can write data to the sending hold register @@ -61,15 +60,15 @@ static uint8_t iso14_pcb_blocknum = 0; #define DELAY_ARM2AIR_AS_READER (4*16 + 8*16 + 8 + 8 + 1) // When the PM acts as tag and is receiving it takes -// 12 ticks delay in the RF part, +// 2 ticks delay in the RF part (for the first falling edge), // 3 ticks for the A/D conversion, // 8 ticks on average until the start of the SSC transfer, // 8 ticks until the SSC samples the first data // 7*16 ticks to complete the transfer from FPGA to ARM // 8 ticks until the next ssp_clk rising edge -// 3*16 ticks until we measure the time +// 4*16 ticks until we measure the time // - 8*16 ticks because we measure the time of the previous transfer -#define DELAY_AIR2ARM_AS_TAG (12 + 3 + 8 + 8 + 7*16 + 8 + 3*16 - 8*16) +#define DELAY_AIR2ARM_AS_TAG (2 + 3 + 8 + 8 + 7*16 + 8 + 4*16 - 8*16) // The FPGA will report its internal sending delay in uint16_t FpgaSendQueueDelay; @@ -78,29 +77,30 @@ uint16_t FpgaSendQueueDelay; #define DELAY_FPGA_QUEUE (FpgaSendQueueDelay<<1) // When the PM acts as tag and is sending, it takes -// 5*16 ticks until we can write data to the sending hold register +// 4*16 ticks until we can write data to the sending hold register // 8*16 ticks until the SHR is transferred to the Sending Shift Register // 8 ticks until the first transfer starts // 8 ticks later the FPGA samples the data // + a varying number of ticks in the FPGA Delay Queue (mod_sig_buf) // + 1 tick to assign mod_sig_coil -#define DELAY_ARM2AIR_AS_TAG (5*16 + 8*16 + 8 + 8 + DELAY_FPGA_QUEUE + 1) +#define DELAY_ARM2AIR_AS_TAG (4*16 + 8*16 + 8 + 8 + DELAY_FPGA_QUEUE + 1) // When the PM acts as sniffer and is receiving tag data, it takes // 3 ticks A/D conversion -// 16 ticks delay in the modulation detector (on average). -// + 16 ticks until it's result is sampled. +// 14 ticks to complete the modulation detection +// 8 ticks (on average) until the result is stored in to_arm // + the delays in transferring data - which is the same for // sniffing reader and tag data and therefore not relevant -#define DELAY_TAG_AIR2ARM_AS_SNIFFER (3 + 16 + 16) +#define DELAY_TAG_AIR2ARM_AS_SNIFFER (3 + 14 + 8) -// When the PM acts as sniffer and is receiving tag data, it takes -// 12 ticks delay in analogue RF receiver +// When the PM acts as sniffer and is receiving reader data, it takes +// 2 ticks delay in analogue RF receiver (for the falling edge of the +// start bit, which marks the start of the communication) // 3 ticks A/D conversion -// 8 ticks on average until we sample the data. +// 8 ticks on average until the data is stored in to_arm. // + the delays in transferring data - which is the same for // sniffing reader and tag data and therefore not relevant -#define DELAY_READER_AIR2ARM_AS_SNIFFER (12 + 3 + 8) +#define DELAY_READER_AIR2ARM_AS_SNIFFER (2 + 3 + 8) //variables used for timing purposes: //these are in ssp_clk cycles: @@ -258,23 +258,7 @@ void UartReset() Uart.endTime = 0; } -/* inline RAMFUNC Modulation_t MillerModulation(uint8_t b) -{ - // switch (b & 0x88) { - // case 0x00: return MILLER_MOD_BOTH_HALVES; - // case 0x08: return MILLER_MOD_FIRST_HALF; - // case 0x80: return MILLER_MOD_SECOND_HALF; - // case 0x88: return MILLER_MOD_NOMOD; - // } - // test the second cycle for a pause. For whatever reason the startbit tends to appear earlier than the rest. - switch (b & 0x44) { - case 0x00: return MOD_BOTH_HALVES; - case 0x04: return MOD_FIRST_HALF; - case 0x40: return MOD_SECOND_HALF; - default: return MOD_NOMOD; - } -} - */ + // use parameter non_real_time to provide a timestamp. Set to 0 if the decoder should measure real time static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) { @@ -398,10 +382,10 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) static tDemod Demod; // Lookup-Table to decide if 4 raw bits are a modulation. -// We accept three or four consecutive "1" in any position +// We accept three or four "1" in any position const bool Mod_Manchester_LUT[] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, - FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE + FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE }; #define IsManchesterModulationNibble1(b) (Mod_Manchester_LUT[(b & 0x00F0) >> 4]) @@ -646,7 +630,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { previous_data = *data; rsamples++; data++; - if(data > dmaBuf + DMA_BUFFER_SIZE) { + if(data == dmaBuf + DMA_BUFFER_SIZE) { data = dmaBuf; } } // main cycle @@ -1423,7 +1407,7 @@ static int EmSendCmd14443aRaw(uint8_t *resp, int respLen, bool correctionNeeded) i = 1; } - // clear receiving shift register and holding register + // clear receiving shift register and holding register while(!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); b = AT91C_BASE_SSC->SSC_RHR; (void) b; while(!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); @@ -2593,11 +2577,12 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * //May just aswell send the collected ar_nr in the response aswell cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,0,0,&ar_nr_responses,ar_nr_collected*4*4); } + if(flags & FLAG_NR_AR_ATTACK) { if(ar_nr_collected > 1) { Dbprintf("Collected two pairs of AR/NR which can be used to extract keys from reader:"); - Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x", + Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x", ar_nr_responses[0], // UID ar_nr_responses[1], //NT ar_nr_responses[2], //AR1 @@ -2608,7 +2593,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } else { Dbprintf("Failed to obtain two AR/NR pairs!"); if(ar_nr_collected >0) { - Dbprintf("Only got these: UID=%08d, nonce=%08d, AR1=%08d, NR1=%08d", + Dbprintf("Only got these: UID=%08x, nonce=%08x, AR1=%08x, NR1=%08x", ar_nr_responses[0], // UID ar_nr_responses[1], //NT ar_nr_responses[2], //AR1 @@ -2762,7 +2747,7 @@ void RAMFUNC SniffMifare(uint8_t param) { previous_data = *data; sniffCounter++; data++; - if(data > dmaBuf + DMA_BUFFER_SIZE) { + if(data == dmaBuf + DMA_BUFFER_SIZE) { data = dmaBuf; } diff --git a/armsrc/mifaresniff.c b/armsrc/mifaresniff.c index bd9840e8c..3e5570f9c 100644 --- a/armsrc/mifaresniff.c +++ b/armsrc/mifaresniff.c @@ -93,7 +93,8 @@ bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint32_t parity, ui } case SNF_ANTICOL2:{ if ((!reader) && (len == 5) && ((data[0] ^ data[1] ^ data[2] ^ data[3]) == data[4])) { // CL2 UID - memcpy(sniffUID, data, 4); + memcpy(sniffUID, sniffUID+4, 3); + memcpy(sniffUID+3, data, 4); sniffUIDType = SNF_UID_7; sniffState = SNF_UID2; } diff --git a/armsrc/util.c b/armsrc/util.c index 6d34ae5e8..905bad253 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -363,8 +363,6 @@ void StartCountSspClk() // while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame) while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low - // after the falling edge of ssp_frame, there is delay of 1/13,56MHz (73ns) until the next rising edge of ssp_clk. This are only a few - // processor cycles. We therefore may or may not be able to sync on this edge. Therefore better make sure that we miss it: while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high // note: up to now two ssp_clk rising edges have passed since the rising edge of ssp_frame // it is now safe to assert a sync signal. This sets all timers to 0 on next active clock edge diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index cc9b4c76d..2dc1ab2bf 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1847,8 +1847,9 @@ int CmdHF14AMfSniff(const char *Cmd){ printf("Press the key on pc keyboard to abort the client.\n"); printf("-------------------------------------------------------------------------\n"); - UsbCommand c = {CMD_MIFARE_SNIFFER, {0, 0, 0}}; - SendCommand(&c); + UsbCommand c = {CMD_MIFARE_SNIFFER, {0, 0, 0}}; + clearCommandBuffer(); + SendCommand(&c); // wait cycle while (true) { @@ -1895,7 +1896,7 @@ int CmdHF14AMfSniff(const char *Cmd){ sak = bufPtr[11]; PrintAndLog("tag select uid:%s atqa:%02x %02x sak:0x%02x", sprint_hex(uid, 7), atqa[0], atqa[1], sak); - if (wantLogToFile) { + if (wantLogToFile || wantDecrypt) { FillFileNameByUID(logHexFileName, uid, ".log", 7); AddLogCurrentDT(logHexFileName); } @@ -1911,7 +1912,8 @@ int CmdHF14AMfSniff(const char *Cmd){ } } // resp not NILL } // while (true) - return 0; + + return 0; } static command_t CommandTable[] = diff --git a/fpga/fpga.bit b/fpga/fpga.bit index f494783311398ea66fd32529687f55b09e320fb9..e773ef9326d66be61c29bc6c169be07d9703a364 100644 GIT binary patch literal 42172 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 B!4Cic literal 42172 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 PM3: +// detecting and shaping the reader's signal. Reader will modulate the carrier by 100% (signal is either on or off). Use a +// hysteresis (Schmitt Trigger) to avoid false triggers during slowly increasing or decreasing carrier amplitudes +reg after_hysteresis; reg [11:0] has_been_low_for; -reg [8:0] saw_deep_modulation; -reg [2:0] deep_counter; -reg deep_modulation; always @(negedge adc_clk) begin - if(& adc_d[7:6]) after_hysteresis <= 1'b1; // adc_d >= 196 (U >= 3,28V) -> after_hysteris = 1 - else if(~(| adc_d[7:4])) after_hysteresis <= 1'b0; // if adc_d <= 15 (U <= 1,13V) -> after_hysteresis = 0 - - pre_after_hysteresis <= after_hysteresis; + if(adc_d >= 16) after_hysteresis <= 1'b1; // U >= 1,14V -> after_hysteresis = 1 + else if(adc_d < 8) after_hysteresis <= 1'b0; // U < 1,04V -> after_hysteresis = 0 + // Note: was >= 3,53V and <= 1,19V. The new trigger values allow more reliable detection of the first bit + // (it might not reach 3,53V due to the high time constant of the high pass filter in the analogue RF part). + // In addition, the new values are more in line with ISO14443-2: "The PICC shall detect the ”End of Pause” after the field exceeds + // 5% of H_INITIAL and before it exceeds 60% of H_INITIAL." Depending on the signal strength, 60% might well be less than 3,53V. + + // detecting a loss of reader's field (adc_d < 192 for 4096 clock cycles). If this is the case, + // set the detected reader signal (after_hysteresis) to '1' (unmodulated) + if(adc_d >= 192) + begin + has_been_low_for <= 12'd0; + end + else + begin + if(has_been_low_for == 12'd4095) + begin + has_been_low_for <= 12'd0; + after_hysteresis <= 1'b1; + end + else + begin + has_been_low_for <= has_been_low_for + 1; + end + end + +end + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Reader -> PM3 +// detect when a reader is active (modulating). We assume that the reader is active, if we see the carrier off for at least 8 +// carrier cycles. We assume that the reader is inactive, if the carrier stayed high for at least 256 carrier cycles. +reg deep_modulation; +reg [2:0] deep_counter; +reg [8:0] saw_deep_modulation; + +always @(negedge adc_clk) +begin if(~(| adc_d[7:0])) // if adc_d == 0 (U <= 0,94V) begin - if(deep_counter == 3'd7) // adc_d == 0 for 7 adc_clk ticks -> deep_modulation (by reader) + if(deep_counter == 3'd7) // adc_d == 0 for 8 adc_clk ticks -> deep_modulation (by reader) begin deep_modulation <= 1'b1; saw_deep_modulation <= 8'd0; @@ -61,136 +97,147 @@ begin else begin deep_counter <= 3'd0; - if(saw_deep_modulation == 8'd255) // adc_d != 0 for 255 adc_clk ticks -> deep_modulation is over, now waiting for tag's response + if(saw_deep_modulation == 8'd255) // adc_d != 0 for 256 adc_clk ticks -> deep_modulation is over, probably waiting for tag's response deep_modulation <= 1'b0; else saw_deep_modulation <= saw_deep_modulation + 1; end - - if(after_hysteresis) - begin - has_been_low_for <= 12'd0; - end - else - begin - if(has_been_low_for == 12'd4095) - begin - has_been_low_for <= 12'd0; - after_hysteresis <= 1'b1; // reset after_hysteresis to 1 if it had been 0 for 4096 cycles (no field) - end - else - begin - has_been_low_for <= has_been_low_for + 1; - end - end end -// Report every 4 subcarrier cycles -// 128 periods of carrier frequency => 7-bit counter [negedge_cnt] -reg [6:0] negedge_cnt; -reg bit1, bit2, bit3, bit4; -reg curbit; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Tag -> PM3 +// filter the input for a tag's signal. The filter box needs the 4 previous input values and is a gaussian derivative filter +// for noise reduction and edge detection. +// store 4 previous samples: +reg [7:0] input_prev_4, input_prev_3, input_prev_2, input_prev_1; +// convert to signed signals (and multiply by two for samples at t-4 and t) +wire signed [10:0] input_prev_4_times_2 = {0, 0, input_prev_4, 0}; +wire signed [10:0] input_prev_3_times_1 = {0, 0, 0, input_prev_3}; +wire signed [10:0] input_prev_1_times_1 = {0, 0, 0, input_prev_1}; +wire signed [10:0] adc_d_times_2 = {0, 0, adc_d, 0}; -// storage for four previous samples: -reg [7:0] adc_d_1; -reg [7:0] adc_d_2; -reg [7:0] adc_d_3; -reg [7:0] adc_d_4; - -// the filtered signal (filter performs noise reduction and edge detection) -// (gaussian derivative) +wire signed [10:0] tmp_1, tmp_2; wire signed [10:0] adc_d_filtered; -assign adc_d_filtered = (adc_d_4 << 1) + adc_d_3 - adc_d_1 - (adc_d << 1); +integer i; -// Registers to store steepest edges detected: -reg [7:0] rx_mod_falling_edge_max; -reg [7:0] rx_mod_rising_edge_max; - -// A register to send 8 Bit results to the arm -reg [7:0] to_arm; - - -reg bit_to_arm; -reg fdt_indicator, fdt_elapsed; -reg [10:0] fdt_counter; -//reg [47:0] mod_sig_buf; -reg [31:0] mod_sig_buf; -//reg [5:0] mod_sig_ptr; -reg [4:0] mod_sig_ptr; -reg [3:0] mod_sig_flip; -reg mod_sig, mod_sig_coil; -reg temp_buffer_reset; -reg sendbit; -reg [3:0] sub_carrier_cnt; -reg[3:0] reader_falling_edge_time; - -// ADC data appears on the rising edge, so sample it on the falling edge +assign tmp_1 = input_prev_4_times_2 + input_prev_3_times_1; +assign tmp_2 = input_prev_1_times_1 + adc_d_times_2; + always @(negedge adc_clk) begin - // ------------------------------------------------------------------------------------------------------------------------------------------------------------------ - // relevant for TAGSIM_MOD only. Timing of Tag's answer relative to a command received from a reader - // ISO14443-3 specifies: - // fdt = 1172, if last bit was 0. - // fdt = 1236, if last bit was 1. - // the FPGA takes care for the 1172 delay. To achieve the additional 1236-1172=64 ticks delay, the ARM must send an additional correction bit (before the start bit). - // The correction bit will be coded as 00010000, i.e. it adds 4 bits to the transmission stream, causing the required delay. - if(fdt_counter == 11'd547) fdt_indicator <= 1'b1; // The ARM must not send earlier to prevent mod_sig_buf overflow. - // The mod_sig_buf can buffer 29 excess data bits, i.e. a maximum delay of 29 * 16 = 464 adc_clk ticks. fdt_indicator - // could appear at ssp_din after 1 tick, 16 ticks for the transfer, 128 ticks until response is sended. - // 1148 - 464 - 1 - 128 - 8 = 547 - - if ((mod_type == `TAGSIM_MOD) || (mod_type == `TAGSIM_LISTEN)) - begin - if(fdt_counter == 11'd1148) // the RF part delays the rising edge by approx 5 adc_clk_ticks, the ADC needs 3 clk_ticks for A/D conversion, - // 16 ticks delay by mod_sig_buf - // 1172 - 5 - 3 - 16 = 1148. - begin - if(fdt_elapsed) - begin - if(negedge_cnt[3:0] == mod_sig_flip) mod_sig_coil <= mod_sig; // start modulating (if mod_sig is already set) - sub_carrier_cnt[3:0] <= sub_carrier_cnt[3:0] + 1; - end - else - begin - mod_sig_flip <= negedge_cnt[3:0]; // start modulation at this time - sub_carrier_cnt[3:0] <= 0; // subcarrier phase in sync with start of modulation - mod_sig_coil <= mod_sig; // assign signal to coil - fdt_elapsed = 1'b1; - if(~(| mod_sig_ptr[4:0])) mod_sig_ptr <= 5'd9; // if mod_sig_ptr == 0 -> didn't receive a 1 yet. Delay next 1 by n*128 ticks. - else temp_buffer_reset = 1'b1; // else fix the buffer size at current position - end - end - else - begin - fdt_counter <= fdt_counter + 1; // Count until 1155 - end - end - else // other modes: don't use the delay line. - begin - mod_sig_coil <= ssp_dout; - end - - - //------------------------------------------------------------------------------------------------------------------------------------------- - // Relevant for READER_LISTEN only - // look for steepest falling and rising edges: + // for (i = 3; i > 0; i = i - 1) + // begin + // input_shift[i] <= input_shift[i-1]; + // end + // input_shift[0] <= adc_d; + input_prev_4 <= input_prev_3; + input_prev_3 <= input_prev_2; + input_prev_2 <= input_prev_1; + input_prev_1 <= adc_d; +end - if(negedge_cnt[3:0] == 4'd1) // reset modulation detector. Save current edge. +// assign adc_d_filtered = (input_shift[3] << 1) + input_shift[2] - input_shift[0] - (adc_d << 1); +assign adc_d_filtered = tmp_1 - tmp_2; + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// internal FPGA timing. Maximum required period is 128 carrier clock cycles for a full 8 Bit transfer to ARM. (i.e. we need a +// 7 bit counter). Adjust its frequency to external reader's clock when simulating a tag or sniffing. +reg pre_after_hysteresis; +reg [3:0] reader_falling_edge_time; +reg [6:0] negedge_cnt; + +always @(negedge adc_clk) +begin + // detect a reader signal's falling edge and remember its timing: + pre_after_hysteresis <= after_hysteresis; + if (pre_after_hysteresis && ~after_hysteresis) begin - if (adc_d_filtered > 0) + reader_falling_edge_time[3:0] <= negedge_cnt[3:0]; + end + + // adjust internal timer counter if necessary: + if (negedge_cnt[3:0] == 4'd13 && (mod_type == `SNIFFER || mod_type == `TAGSIM_LISTEN) && deep_modulation) + begin + if (reader_falling_edge_time == 4'd1) // reader signal changes right after sampling. Better sample earlier next time. begin - rx_mod_falling_edge_max <= adc_d_filtered; - rx_mod_rising_edge_max <= 0; + negedge_cnt <= negedge_cnt + 2; // time warp end + else if (reader_falling_edge_time == 4'd0) // reader signal changes right before sampling. Better sample later next time. + begin + negedge_cnt <= negedge_cnt; // freeze time + end else begin - rx_mod_falling_edge_max <= 0; - rx_mod_rising_edge_max <= -adc_d_filtered; + negedge_cnt <= negedge_cnt + 1; // Continue as usual + end + reader_falling_edge_time[3:0] <= 4'd8; // adjust only once per detected edge + end + else if (negedge_cnt == 7'd127) // normal operation: count from 0 to 127 + begin + negedge_cnt <= 0; + end + else + begin + negedge_cnt <= negedge_cnt + 1; + end +end + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Tag -> PM3: +// determine best possible time for starting/resetting the modulation detector. +reg [3:0] mod_detect_reset_time; + +always @(negedge adc_clk) +begin + if (mod_type == `READER_LISTEN) + // (our) reader signal changes at t=1, tag response expected n*16+4 ticks later, further delayed by + // 3 ticks ADC conversion. + // 1 + 4 + 3 = 8 + begin + mod_detect_reset_time <= 4'd8; + end + else + if (mod_type == `SNIFFER) + begin + // detect a rising edge of reader's signal and sync modulation detector to the tag's answer: + if (~pre_after_hysteresis && after_hysteresis && deep_modulation) + // reader signal rising edge detected at negedge_cnt[3:0]. This signal had been delayed + // 9 ticks by the RF part + 3 ticks by the A/D converter + 1 tick to assign to after_hysteresis. + // The tag will respond n*16 + 4 ticks later + 3 ticks A/D converter delay. + // - 9 - 3 - 1 + 4 + 3 = -6 + begin + mod_detect_reset_time <= negedge_cnt[3:0] - 4'd4; end end - else // detect modulation +end + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Tag -> PM3: +// modulation detector. Looks for the steepest falling and rising edges within a 16 clock period. If there is both a significant +// falling and rising edge (in any order), a modulation is detected. +reg signed [10:0] rx_mod_falling_edge_max; +reg signed [10:0] rx_mod_rising_edge_max; +reg curbit; + +always @(negedge adc_clk) +begin + if(negedge_cnt[3:0] == mod_detect_reset_time) + begin + // detect modulation signal: if modulating, there must have been a falling AND a rising edge + if (rx_mod_falling_edge_max > 5 && rx_mod_rising_edge_max > 5) + curbit <= 1'b1; // modulation + else + curbit <= 1'b0; // no modulation + // reset modulation detector + rx_mod_rising_edge_max <= 0; + rx_mod_falling_edge_max <= 0; + end + else // look for steepest edges (slopes) begin if (adc_d_filtered > 0) begin @@ -204,35 +251,279 @@ begin end end - // detect modulation signal: if modulating, there must be a falling and a rising edge - if (rx_mod_falling_edge_max > 6 && rx_mod_rising_edge_max > 6) - curbit <= 1'b1; // modulation +end + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Tag+Reader -> PM3 +// sample 4 bits reader data and 4 bits tag data for sniffing +reg [3:0] reader_data; +reg [3:0] tag_data; + +always @(negedge adc_clk) +begin + if(negedge_cnt[3:0] == 4'd0) + begin + reader_data[3:0] <= {reader_data[2:0], after_hysteresis}; + tag_data[3:0] <= {tag_data[2:0], curbit}; + end +end + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PM3 -> Tag: +// a delay line to ensure that we send the (emulated) tag's answer at the correct time according to ISO14443-3 +reg [31:0] mod_sig_buf; +reg [4:0] mod_sig_ptr; +reg mod_sig; + +always @(negedge adc_clk) +begin + if(negedge_cnt[3:0] == 4'd0) // sample data at rising edge of ssp_clk - ssp_dout changes at the falling edge. + begin + mod_sig_buf[31:2] <= mod_sig_buf[30:1]; // shift + if (~ssp_dout && ~mod_sig_buf[1]) + mod_sig_buf[1] <= 1'b0; // delete the correction bit (a single 1 preceded and succeeded by 0) else - curbit <= 1'b0; // no modulation - - - // store previous samples for filtering and edge detection: - adc_d_4 <= adc_d_3; - adc_d_3 <= adc_d_2; - adc_d_2 <= adc_d_1; - adc_d_1 <= adc_d; + mod_sig_buf[1] <= mod_sig_buf[0]; + mod_sig_buf[0] <= ssp_dout; // add new data to the delay line + + mod_sig = mod_sig_buf[mod_sig_ptr]; // the delayed signal. + end +end - // Relevant for TAGSIM_MOD only (timing the Tag's answer. See above) - // When we see end of a modulation and we are emulating a Tag, start fdt_counter. - // Reset fdt_counter when modulation is detected. - if(~after_hysteresis /* && mod_sig_buf_empty */ && mod_type == `TAGSIM_LISTEN) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PM3 -> Tag, internal timing: +// a timer for the 1172 cycles fdt (Frame Delay Time). Start the timer with a rising edge of the reader's signal. +// set fdt_elapsed when we no longer need to delay data. Set fdt_indicator when we can start sending data. +// Note: the FPGA only takes care for the 1172 delay. To achieve an additional 1236-1172=64 ticks delay, the ARM must send +// a correction bit (before the start bit). The correction bit will be coded as 00010000, i.e. it adds 4 bits to the +// transmission stream, causing the required additional delay. +reg [10:0] fdt_counter; +reg fdt_indicator, fdt_elapsed; +reg [3:0] mod_sig_flip; +reg [3:0] sub_carrier_cnt; + +// we want to achieve a delay of 1172. The RF part already has delayed the reader signals's rising edge +// by 9 ticks, the ADC took 3 ticks and there is always a delay of 32 ticks by the mod_sig_buf. Therefore need to +// count to 1172 - 9 - 3 - 32 = 1128 +`define FDT_COUNT 11'd1128 + +// The ARM must not send too early, otherwise the mod_sig_buf will overflow, therefore signal that we are ready +// with fdt_indicator. The mod_sig_buf can buffer 29 excess data bits, i.e. a maximum delay of 29 * 16 = 464 adc_clk ticks. +// fdt_indicator could appear at ssp_din after 1 tick, the transfer needs 16 ticks, the ARM can send 128 ticks later. +// 1128 - 464 - 1 - 128 - 8 = 535 +`define FDT_INDICATOR_COUNT 11'd535 + +// reset on a pause in listen mode. I.e. the counter starts when the pause is over: +assign fdt_reset = ~after_hysteresis && mod_type == `TAGSIM_LISTEN; + +always @(negedge adc_clk) +begin + if (fdt_reset) begin fdt_counter <= 11'd0; - fdt_elapsed = 1'b0; + fdt_elapsed <= 1'b0; fdt_indicator <= 1'b0; + end + else + begin + if(fdt_counter == `FDT_COUNT) + begin + if(~fdt_elapsed) // just reached fdt. + begin + mod_sig_flip <= negedge_cnt[3:0]; // start modulation at this time + sub_carrier_cnt <= 4'd0; // subcarrier phase in sync with start of modulation + fdt_elapsed <= 1'b1; + end + else + begin + sub_carrier_cnt <= sub_carrier_cnt + 1; + end + end + else + begin + fdt_counter <= fdt_counter + 1; + end + end + + if(fdt_counter == `FDT_INDICATOR_COUNT) fdt_indicator <= 1'b1; +end + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PM3 -> Reader or Tag +// assign a modulation signal to the antenna. This signal is either a delayed signal (to achieve fdt when sending to a reader) +// or undelayed when sending to a tag +reg mod_sig_coil; + +always @(negedge adc_clk) +begin + if (mod_type == `TAGSIM_MOD) // need to take care of proper fdt timing + begin + if(fdt_counter == `FDT_COUNT) + begin + if(fdt_elapsed) + begin + if(negedge_cnt[3:0] == mod_sig_flip) mod_sig_coil <= mod_sig; + end + else + begin + mod_sig_coil <= mod_sig; // just reached fdt. Immediately assign signal to coil + end + end + end + else // other modes: don't delay + begin + mod_sig_coil <= ssp_dout; + end +end + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PM3 -> Reader +// determine the required delay in the mod_sig_buf (set mod_sig_ptr). +reg temp_buffer_reset; + +always @(negedge adc_clk) +begin + if(fdt_reset) + begin + mod_sig_ptr <= 5'd0; temp_buffer_reset = 1'b0; - mod_sig_ptr <= 5'b00000; - mod_sig = 1'b0; + end + else + begin + if(fdt_counter == `FDT_COUNT && ~fdt_elapsed) // if we just reached fdt + if(~(| mod_sig_ptr[4:0])) + mod_sig_ptr <= 5'd8; // ... but didn't buffer a 1 yet, delay next 1 by n*128 ticks. + else + temp_buffer_reset = 1'b1; // else no need for further delays. + + if(negedge_cnt[3:0] == 4'd0) // at rising edge of ssp_clk - ssp_dout changes at the falling edge. + begin + if((ssp_dout || (| mod_sig_ptr[4:0])) && ~fdt_elapsed) // buffer a 1 (and all subsequent data) until fdt is reached. + if (mod_sig_ptr == 5'd31) + mod_sig_ptr <= 5'd0; // buffer overflow - data loss. + else + mod_sig_ptr <= mod_sig_ptr + 1; // increase buffer (= increase delay by 16 adc_clk ticks). mod_sig_ptr always points ahead of first 1. + else if(fdt_elapsed && ~temp_buffer_reset) + begin + // wait for the next 1 after fdt_elapsed before fixing the delay and starting modulation. This ensures that the response can only happen + // at intervals of 8 * 16 = 128 adc_clk ticks (as defined in ISO14443-3) + if(ssp_dout) + temp_buffer_reset = 1'b1; + if(mod_sig_ptr == 5'd1) + mod_sig_ptr <= 5'd8; // still nothing received, need to go for the next interval + else + mod_sig_ptr <= mod_sig_ptr - 1; // decrease buffer. + end + end + end +end + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FPGA -> ARM communication: +// buffer 8 bits data to be sent to ARM. Shift them out bit by bit. +reg [7:0] to_arm; + +always @(negedge adc_clk) +begin + if (negedge_cnt[5:0] == 6'd63) // fill the buffer + begin + if (mod_type == `SNIFFER) + begin + if(deep_modulation) // a reader is sending (or there's no field at all) + begin + to_arm <= {reader_data[3:0], 4'b0000}; // don't send tag data + end + else + begin + to_arm <= {reader_data[3:0], tag_data[3:0]}; + end + end + else + begin + to_arm[7:0] <= {mod_sig_ptr[4:0], mod_sig_flip[3:1]}; // feedback timing information + end end + if(negedge_cnt[2:0] == 3'b000 && mod_type == `SNIFFER) // shift at double speed + begin + // Don't shift if we just loaded new data, obviously. + if(negedge_cnt[5:0] != 6'd0) + begin + to_arm[7:1] <= to_arm[6:0]; + end + end - if(negedge_cnt[3:0] == 4'd1) + if(negedge_cnt[3:0] == 4'b0000 && mod_type != `SNIFFER) + begin + // Don't shift if we just loaded new data, obviously. + if(negedge_cnt[6:0] != 7'd0) + begin + to_arm[7:1] <= to_arm[6:0]; + end + end + +end + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FPGA -> ARM communication: +// generate a ssp clock and ssp frame signal for the synchronous transfer from/to the ARM +reg ssp_clk; +reg ssp_frame; +reg [2:0] ssp_frame_counter; + +always @(negedge adc_clk) +begin + if(mod_type == `SNIFFER) + // SNIFFER mode (ssp_clk = adc_clk / 8, ssp_frame clock = adc_clk / 64)): + begin + if(negedge_cnt[2:0] == 3'd0) + ssp_clk <= 1'b1; + if(negedge_cnt[2:0] == 3'd4) + ssp_clk <= 1'b0; + + if(negedge_cnt[5:0] == 6'd0) // ssp_frame rising edge indicates start of frame + ssp_frame <= 1'b1; + if(negedge_cnt[5:0] == 6'd8) + ssp_frame <= 1'b0; + end + else + // all other modes (ssp_clk = adc_clk / 16, ssp_frame clock = adc_clk / 128): + begin + if(negedge_cnt[3:0] == 4'd0) + ssp_clk <= 1'b1; + if(negedge_cnt[3:0] == 4'd8) + ssp_clk <= 1'b0; + + if(negedge_cnt[6:0] == 7'd7) // ssp_frame rising edge indicates start of frame + ssp_frame <= 1'b1; + if(negedge_cnt[6:0] == 7'd23) + ssp_frame <= 1'b0; + end +end + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// FPGA -> ARM communication: +// select the data to be sent to ARM +reg bit_to_arm; +reg sendbit; + +always @(negedge adc_clk) +begin + if(negedge_cnt[3:0] == 4'd0) begin // What do we communicate to the ARM if(mod_type == `TAGSIM_LISTEN) @@ -248,190 +539,22 @@ begin end - - // check timing of a falling edge in reader signal - if (pre_after_hysteresis && ~after_hysteresis) - reader_falling_edge_time[3:0] <= negedge_cnt[3:0]; - - - - // sync clock to external reader's clock: - if (negedge_cnt[3:0] == 4'd13 && (mod_type == `SNIFFER || mod_type == `TAGSIM_MOD || mod_type == `TAGSIM_LISTEN)) - begin - // adjust clock if necessary: - if (reader_falling_edge_time < 4'd8 && reader_falling_edge_time > 4'd1) - begin - negedge_cnt <= negedge_cnt; // freeze time - end - else if (reader_falling_edge_time == 4'd8) - begin - negedge_cnt <= negedge_cnt + 1; // the desired state. Advance as usual; - end - else - begin - negedge_cnt[3:0] <= 4'd15; // time warp - end - reader_falling_edge_time <= 4'd8; // only once per detected rising edge - end - - - - //------------------------------------------------------------------------------------------------------------------------------------------ - // Prepare 8 Bits to communicate to ARM - if (negedge_cnt == 7'd63) - begin - if (mod_type == `SNIFFER) - begin - if(deep_modulation) // a reader is sending (or there's no field at all) - begin - to_arm <= {after_hysteresis_prev1,after_hysteresis_prev2,after_hysteresis_prev3,after_hysteresis_prev4,1'b0,1'b0,1'b0,1'b0}; - end - else - begin - to_arm <= {after_hysteresis_prev1,after_hysteresis_prev2,after_hysteresis_prev3,after_hysteresis_prev4,bit1,bit2,bit3,bit4}; - end - negedge_cnt <= 0; - end - else - begin - negedge_cnt <= negedge_cnt + 1; - end - end - else if(negedge_cnt == 7'd127) - begin - if (mod_type == `TAGSIM_MOD) - begin - to_arm[7:0] <= {mod_sig_ptr[4:0], mod_sig_flip[3:1]}; - negedge_cnt <= 0; - end - else - begin - to_arm[7:0] <= 8'd0; - negedge_cnt <= negedge_cnt + 1; - end - end - else - begin - negedge_cnt <= negedge_cnt + 1; - end - - - if(negedge_cnt == 7'd1) - begin - after_hysteresis_prev1 <= after_hysteresis; - bit1 <= curbit; - end - if(negedge_cnt == 7'd17) - begin - after_hysteresis_prev2 <= after_hysteresis; - bit2 <= curbit; - end - if(negedge_cnt == 7'd33) - begin - after_hysteresis_prev3 <= after_hysteresis; - bit3 <= curbit; - end - if(negedge_cnt == 7'd49) - begin - after_hysteresis_prev4 <= after_hysteresis; - bit4 <= curbit; - end - - //-------------------------------------------------------------------------------------------------------------------------------------------------------------- - // Relevant in TAGSIM_MOD only. Delay-Line to buffer data and send it at the correct time - if(negedge_cnt[3:0] == 4'd0) // at rising edge of ssp_clk - ssp_dout changes at the falling edge. - begin - mod_sig_buf[31:0] <= {mod_sig_buf[30:1], ssp_dout, 1'b0}; // shift in new data starting at mod_sig_buf[1]. mod_sig_buf[0] = 0 always. - // asign the delayed signal to mod_sig, but don't modulate with the correction bit (which is sent as 00010000, all other bits will come with at least 2 consecutive 1s) - // side effect: when ptr = 1 it will cancel the first 1 of every block of ones. Note: this would only be the case if we received a 1 just before fdt_elapsed. - if((ssp_dout || (| mod_sig_ptr[4:0])) && ~fdt_elapsed) // buffer a 1 (and all subsequent data) until fdt_counter = 1148 adc_clk ticks. - //if(mod_sig_ptr == 6'b101110) // buffer overflow at 46 - this would mean data loss - //begin - // mod_sig_ptr <= 6'b000000; - //end - if (mod_sig_ptr == 5'd30) mod_sig_ptr <= 5'd0; - else mod_sig_ptr <= mod_sig_ptr + 1; // increase buffer (= increase delay by 16 adc_clk ticks). ptr always points to first 1. - else if(fdt_elapsed && ~temp_buffer_reset) - // fdt_elapsed. If we didn't receive a 1 yet, ptr will be at 9 and not yet fixed. Otherwise temp_buffer_reset will be 1 already. - begin - // wait for the next 1 after fdt_elapsed before fixing the delay and starting modulation. This ensures that the response can only happen - // at intervals of 8 * 16 = 128 adc_clk ticks intervals (as defined in ISO14443-3) - if(ssp_dout) temp_buffer_reset = 1'b1; - if(mod_sig_ptr == 5'd2) mod_sig_ptr <= 5'd9; // still nothing received, need to go for the next interval - else mod_sig_ptr <= mod_sig_ptr - 1; // decrease buffer. - end - else - begin - if(~mod_sig_buf[mod_sig_ptr-1] && ~mod_sig_buf[mod_sig_ptr+1]) mod_sig = 1'b0; - // finally, assign the delayed signal: - else mod_sig = mod_sig_buf[mod_sig_ptr]; - end - end - - //----------------------------------------------------------------------------------------------------------------------------------------------------------------------- - // Communication to ARM (SSP Clock and data) - // SNIFFER mode (ssp_clk = adc_clk / 8, ssp_frame clock = adc_clk / 64)): if(mod_type == `SNIFFER) - begin - if(negedge_cnt[2:0] == 3'b100) - ssp_clk <= 1'b0; - - if(negedge_cnt[2:0] == 3'b000) - begin - ssp_clk <= 1'b1; - // Don't shift if we just loaded new data, obviously. - if(negedge_cnt[5:0] != 6'd0) - begin - to_arm[7:1] <= to_arm[6:0]; - end - end - - if(negedge_cnt[5:4] == 2'b00) - ssp_frame = 1'b1; - else - ssp_frame = 1'b0; - + // send sampled reader and tag data: + bit_to_arm = to_arm[7]; + else if (mod_type == `TAGSIM_MOD && fdt_elapsed && temp_buffer_reset) + // send timing information: bit_to_arm = to_arm[7]; - end else - //----------------------------------------------------------------------------------------------------------------------------------------------------------------------- - // Communication to ARM (SSP Clock and data) - // all other modes (ssp_clk = adc_clk / 16, ssp_frame clock = adc_clk / 128): - begin - if(negedge_cnt[3:0] == 4'b1000) ssp_clk <= 1'b0; + // send data or fdt_indicator + bit_to_arm = sendbit; +end + - if(negedge_cnt[3:0] == 4'b0111) - begin - // if(ssp_frame_counter == 3'd7) ssp_frame_counter <= 3'd0; - // else ssp_frame_counter <= ssp_frame_counter + 1; - if (negedge_cnt[6:4] == 3'b000) ssp_frame = 1'b1; - else ssp_frame = 1'b0; - end - // ssp_frame = (ssp_frame_counter == 3'd7); - if(negedge_cnt[3:0] == 4'b0000) - begin - ssp_clk <= 1'b1; - // Don't shift if we just loaded new data, obviously. - if(negedge_cnt[6:0] != 7'd0) - begin - to_arm[7:1] <= to_arm[6:0]; - end - end - - if (mod_type == `TAGSIM_MOD && fdt_elapsed && temp_buffer_reset) - // transmit timing information - bit_to_arm = to_arm[7]; - else - // transmit data or fdt_indicator - bit_to_arm = sendbit; - end - -end //always @(negedge adc_clk) assign ssp_din = bit_to_arm; - // Subcarrier (adc_clk/16, for TAGSIM_MOD only). wire sub_carrier; assign sub_carrier = ~sub_carrier_cnt[3];