1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // Routines to get sample data from FPGA.
17 //-----------------------------------------------------------------------------
19 #include "proxmark3_arm.h"
21 #include "fpgaloader.h"
29 static void RAMFUNC
optimizedSniff(uint16_t *dest
, uint16_t dsize
) {
31 if (AT91C_BASE_SSC
->SSC_SR
& AT91C_SSC_RXRDY
) {
32 *dest
= (uint16_t)(AT91C_BASE_SSC
->SSC_RHR
);
34 dsize
-= sizeof(dsize
);
39 static void RAMFUNC
skipSniff(uint8_t *dest
, uint16_t dsize
, uint8_t skipMode
, uint8_t skipRatio
) {
40 uint32_t accum
= (skipMode
== HF_SNOOP_SKIP_MIN
) ? 0xffffffff : 0;
41 uint8_t ratioindx
= 0;
43 if (AT91C_BASE_SSC
->SSC_SR
& AT91C_SSC_RXRDY
) {
44 volatile uint16_t val
= (uint16_t)(AT91C_BASE_SSC
->SSC_RHR
);
46 case HF_SNOOP_SKIP_MAX
:
47 if (accum
< (val
& 0xff))
49 if (accum
< (val
>> 8))
52 case HF_SNOOP_SKIP_MIN
:
53 if (accum
> (val
& 0xff))
55 if (accum
> (val
>> 8))
58 case HF_SNOOP_SKIP_AVG
:
59 accum
+= (val
& 0xff) + (val
& 0xff);
61 default: { // HF_SNOOP_SKIP_DROP and the rest
68 if (ratioindx
>= skipRatio
) {
69 if (skipMode
== HF_SNOOP_SKIP_AVG
&& skipRatio
> 0) {
70 accum
= accum
/ (skipRatio
* 2);
81 accum
= (skipMode
== HF_SNOOP_SKIP_MIN
) ? 0xffffffff : 0;
88 int HfSniff(uint32_t samplesToSkip
, uint32_t triggersToSkip
, uint16_t *len
, uint8_t skipMode
, uint8_t skipRatio
) {
90 BigBuf_Clear_ext(false);
92 Dbprintf("Skipping first %d sample pairs, Skipping %d triggers", samplesToSkip
, triggersToSkip
);
96 FpgaDownloadAndGo(FPGA_BITSTREAM_HF
);
98 SetAdcMuxFor(GPIO_MUXSEL_HIPKD
);
100 // Set up the synchronous serial port
101 FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SNIFF
);
103 // Setting Frame Mode For better performance on high speed data transfer.
104 AT91C_BASE_SSC
->SSC_RFMR
= SSC_FRAME_MODE_BITS_IN_WORD(16);
106 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNIFF
);
109 *len
= BigBuf_max_traceLen();
110 uint8_t *mem
= BigBuf_malloc(*len
);
112 uint32_t trigger_cnt
= 0;
113 uint16_t r
= 0, interval
= 0;
115 bool pressed
= false;
116 while (pressed
== false) {
119 // cancel w usb command.
120 if (interval
== 2000) {
121 if (data_available())
129 // check if trigger is reached
130 if (AT91C_BASE_SSC
->SSC_SR
& (AT91C_SSC_RXRDY
)) {
131 r
= (uint16_t)AT91C_BASE_SSC
->SSC_RHR
;
133 r
= MAX(r
& 0xFF, r
>> 8);
135 // 180 (0xB4) arbitrary value to see if a strong RF field is near.
138 if (++trigger_cnt
> triggersToSkip
) {
144 pressed
= BUTTON_PRESS();
147 if (pressed
== false) {
150 while (samplesToSkip
!= 0) {
152 if (AT91C_BASE_SSC
->SSC_SR
& (AT91C_SSC_RXRDY
)) {
158 optimizedSniff((uint16_t *)mem
, *len
);
160 skipSniff(mem
, *len
, skipMode
, skipRatio
);
162 if (g_dbglevel
>= DBG_INFO
) {
163 Dbprintf("Trigger kicked in (%d >= 180)", r
);
164 Dbprintf("Collected %u samples", *len
);
168 //Resetting Frame mode (First set in fpgaloader.c)
169 AT91C_BASE_SSC
->SSC_RFMR
= SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF
| SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
171 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF
);
173 return (pressed
) ? PM3_EOPABORTED
: PM3_SUCCESS
;
176 void HfPlotDownload(void) {
178 tosend_t
*ts
= get_tosend();
179 uint8_t *this_buf
= ts
->buf
;
181 FpgaDownloadAndGo(FPGA_BITSTREAM_HF
);
183 FpgaSetupSsc(FPGA_MAJOR_MODE_HF_GET_TRACE
);
185 AT91C_BASE_PDC_SSC
->PDC_PTCR
= AT91C_PDC_RXTDIS
; // Disable DMA Transfer
186 AT91C_BASE_PDC_SSC
->PDC_RPR
= (uint32_t) this_buf
; // start transfer to this memory address
187 AT91C_BASE_PDC_SSC
->PDC_RCR
= PM3_CMD_DATA_SIZE
; // transfer this many samples
188 ts
->buf
[0] = (uint8_t)AT91C_BASE_SSC
->SSC_RHR
; // clear receive register
189 AT91C_BASE_PDC_SSC
->PDC_PTCR
= AT91C_PDC_RXTEN
; // Start DMA transfer
191 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_GET_TRACE
); // let FPGA transfer its internal Block-RAM
194 for (size_t i
= 0; i
< FPGA_TRACE_SIZE
; i
+= PM3_CMD_DATA_SIZE
) {
195 // prepare next DMA transfer:
196 uint8_t *next_buf
= ts
->buf
+ ((i
+ PM3_CMD_DATA_SIZE
) % (2 * PM3_CMD_DATA_SIZE
));
198 AT91C_BASE_PDC_SSC
->PDC_RNPR
= (uint32_t)next_buf
;
199 AT91C_BASE_PDC_SSC
->PDC_RNCR
= PM3_CMD_DATA_SIZE
;
201 size_t len
= MIN(FPGA_TRACE_SIZE
- i
, PM3_CMD_DATA_SIZE
);
203 while (!(AT91C_BASE_SSC
->SSC_SR
& (AT91C_SSC_ENDRX
))) {}; // wait for DMA transfer to complete
205 reply_old(CMD_FPGAMEM_DOWNLOADED
, i
, len
, FPGA_TRACE_SIZE
, this_buf
, len
);
209 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF
);
211 // Trigger a finish downloading signal with an ACK frame
212 reply_ng(CMD_FPGAMEM_DOWNLOAD
, PM3_SUCCESS
, NULL
, 0);