]>
Commit | Line | Data |
---|---|---|
31abe49f MHS |
1 | //----------------------------------------------------------------------------- |
2 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, | |
3 | // at your option, any later version. See the LICENSE.txt file for the text of | |
4 | // the license. | |
5 | //----------------------------------------------------------------------------- | |
6 | // Miscellaneous routines for low frequency sampling. | |
7 | //----------------------------------------------------------------------------- | |
8 | ||
9 | #include "proxmark3.h" | |
10 | #include "apps.h" | |
11 | #include "util.h" | |
12 | #include "string.h" | |
31abe49f | 13 | #include "lfsampling.h" |
e04475c4 | 14 | #include "usb_cdc.h" // for usb_poll_validate_length |
fc52fbd4 | 15 | #include "fpgaloader.h" |
10a8875c | 16 | |
2de26056 | 17 | sample_config config = { 1, 8, 1, 95, 0, 0 } ; |
31abe49f MHS |
18 | |
19 | void printConfig() | |
20 | { | |
e2012d1b | 21 | Dbprintf("LF Sampling config: "); |
31abe49f MHS |
22 | Dbprintf(" [q] divisor: %d ", config.divisor); |
23 | Dbprintf(" [b] bps: %d ", config.bits_per_sample); | |
24 | Dbprintf(" [d] decimation: %d ", config.decimation); | |
25 | Dbprintf(" [a] averaging: %d ", config.averaging); | |
26 | Dbprintf(" [t] trigger threshold: %d ", config.trigger_threshold); | |
2de26056 | 27 | Dbprintf(" [s] samples to skip: %d ", config.samples_to_skip); |
31abe49f MHS |
28 | } |
29 | ||
30 | ||
31 | /** | |
32 | * Called from the USB-handler to set the sampling configuration | |
33 | * The sampling config is used for std reading and snooping. | |
34 | * | |
35 | * Other functions may read samples and ignore the sampling config, | |
36 | * such as functions to read the UID from a prox tag or similar. | |
37 | * | |
2de26056 | 38 | * Values set to '0' implies no change (except for averaging, threshold, samples_to_skip) |
31abe49f MHS |
39 | * @brief setSamplingConfig |
40 | * @param sc | |
41 | */ | |
42 | void setSamplingConfig(sample_config *sc) | |
43 | { | |
44 | if(sc->divisor != 0) config.divisor = sc->divisor; | |
45 | if(sc->bits_per_sample!= 0) config.bits_per_sample= sc->bits_per_sample; | |
46 | if(sc->decimation!= 0) config.decimation= sc->decimation; | |
47 | if(sc->trigger_threshold != -1) config.trigger_threshold= sc->trigger_threshold; | |
2de26056 | 48 | if(sc->samples_to_skip != -1) config.samples_to_skip = sc->samples_to_skip; |
31abe49f MHS |
49 | |
50 | config.averaging= sc->averaging; | |
51 | if(config.bits_per_sample > 8) config.bits_per_sample = 8; | |
52 | if(config.decimation < 1) config.decimation = 1; | |
53 | ||
54 | printConfig(); | |
55 | } | |
56 | ||
57 | sample_config* getSamplingConfig() | |
58 | { | |
59 | return &config; | |
60 | } | |
10a8875c | 61 | |
31abe49f MHS |
62 | typedef struct { |
63 | uint8_t * buffer; | |
64 | uint32_t numbits; | |
65 | uint32_t position; | |
66 | } BitstreamOut; | |
67 | ||
31abe49f MHS |
68 | /** |
69 | * @brief Pushes bit onto the stream | |
70 | * @param stream | |
71 | * @param bit | |
72 | */ | |
10a8875c | 73 | void pushBit( BitstreamOut* stream, uint8_t bit) |
31abe49f MHS |
74 | { |
75 | int bytepos = stream->position >> 3; // divide by 8 | |
76 | int bitpos = stream->position & 7; | |
77 | *(stream->buffer+bytepos) |= (bit > 0) << (7 - bitpos); | |
78 | stream->position++; | |
79 | stream->numbits++; | |
80 | } | |
10a8875c | 81 | |
31abe49f MHS |
82 | /** |
83 | * Setup the FPGA to listen for samples. This method downloads the FPGA bitstream | |
84 | * if not already loaded, sets divisor and starts up the antenna. | |
85 | * @param divisor : 1, 88> 255 or negative ==> 134.8 KHz | |
86 | * 0 or 95 ==> 125 KHz | |
87 | * | |
88 | **/ | |
89 | void LFSetupFPGAForADC(int divisor, bool lf_field) | |
90 | { | |
91 | FpgaDownloadAndGo(FPGA_BITSTREAM_LF); | |
92 | if ( (divisor == 1) || (divisor < 0) || (divisor > 255) ) | |
93 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz | |
94 | else if (divisor == 0) | |
95 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz | |
96 | else | |
97 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); | |
98 | ||
99 | FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | (lf_field ? FPGA_LF_ADC_READER_FIELD : 0)); | |
100 | ||
101 | // Connect the A/D to the peak-detected low-frequency path. | |
102 | SetAdcMuxFor(GPIO_MUXSEL_LOPKD); | |
103 | // Give it a bit of time for the resonant antenna to settle. | |
104 | SpinDelay(50); | |
105 | // Now set up the SSC to get the ADC samples that are now streaming at us. | |
6a5d4e17 | 106 | FpgaSetupSsc(FPGA_MAJOR_MODE_LF_ADC); |
31abe49f MHS |
107 | } |
108 | ||
31abe49f MHS |
109 | /** |
110 | * Does the sample acquisition. If threshold is specified, the actual sampling | |
111 | * is not commenced until the threshold has been reached. | |
112 | * This method implements decimation and quantization in order to | |
113 | * be able to provide longer sample traces. | |
114 | * Uses the following global settings: | |
115 | * @param decimation - how much should the signal be decimated. A decimation of N means we keep 1 in N samples, etc. | |
116 | * @param bits_per_sample - bits per sample. Max 8, min 1 bit per sample. | |
117 | * @param averaging If set to true, decimation will use averaging, so that if e.g. decimation is 3, the sample | |
118 | * value that will be used is the average value of the three samples. | |
119 | * @param trigger_threshold - a threshold. The sampling won't commence until this threshold has been reached. Set | |
120 | * to -1 to ignore threshold. | |
121 | * @param silent - is true, now outputs are made. If false, dbprints the status | |
122 | * @return the number of bits occupied by the samples. | |
123 | */ | |
2de26056 | 124 | uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, int cancel_after, int samples_to_skip) |
31abe49f MHS |
125 | { |
126 | //. | |
0644d5e3 | 127 | uint8_t *dest = BigBuf_get_addr(); |
a37228c8 | 128 | bufsize = (bufsize > 0 && bufsize < BigBuf_max_traceLen()) ? bufsize : BigBuf_max_traceLen(); |
0644d5e3 | 129 | |
3cec7061 | 130 | //memset(dest, 0, bufsize); //creates issues with cmdread (marshmellow) |
31abe49f MHS |
131 | |
132 | if(bits_per_sample < 1) bits_per_sample = 1; | |
133 | if(bits_per_sample > 8) bits_per_sample = 8; | |
134 | ||
135 | if(decimation < 1) decimation = 1; | |
136 | ||
137 | // Use a bit stream to handle the output | |
138 | BitstreamOut data = { dest , 0, 0}; | |
139 | int sample_counter = 0; | |
140 | uint8_t sample = 0; | |
141 | //If we want to do averaging | |
142 | uint32_t sample_sum =0 ; | |
143 | uint32_t sample_total_numbers =0 ; | |
144 | uint32_t sample_total_saved =0 ; | |
217cfb6b | 145 | uint32_t cancel_counter = 0; |
2de26056 | 146 | uint32_t samples_skipped = 0; |
31abe49f | 147 | |
e04475c4 | 148 | while(!BUTTON_PRESS() && !usb_poll_validate_length() ) { |
31abe49f MHS |
149 | WDT_HIT(); |
150 | if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { | |
151 | AT91C_BASE_SSC->SSC_THR = 0x43; | |
152 | LED_D_ON(); | |
153 | } | |
154 | if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { | |
155 | sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; | |
156 | LED_D_OFF(); | |
b29d55f2 | 157 | // threshold either high or low values 128 = center 0. if trigger = 178 |
217cfb6b | 158 | if ((trigger_threshold > 0) && (sample < (trigger_threshold+128)) && (sample > (128-trigger_threshold))) { // |
6469d550 I |
159 | if (cancel_after > 0) { |
160 | cancel_counter++; | |
161 | if (cancel_after == cancel_counter) break; | |
162 | } | |
31abe49f | 163 | continue; |
217cfb6b | 164 | } |
31abe49f | 165 | trigger_threshold = 0; |
2de26056 | 166 | if (samples_to_skip > samples_skipped) { |
167 | samples_skipped++; | |
168 | continue; | |
169 | } | |
31abe49f MHS |
170 | sample_total_numbers++; |
171 | ||
172 | if(averaging) | |
173 | { | |
174 | sample_sum += sample; | |
175 | } | |
176 | //Check decimation | |
177 | if(decimation > 1) | |
178 | { | |
179 | sample_counter++; | |
180 | if(sample_counter < decimation) continue; | |
181 | sample_counter = 0; | |
182 | } | |
183 | //Averaging | |
184 | if(averaging && decimation > 1) { | |
185 | sample = sample_sum / decimation; | |
186 | sample_sum =0; | |
187 | } | |
188 | //Store the sample | |
189 | sample_total_saved ++; | |
190 | if(bits_per_sample == 8){ | |
191 | dest[sample_total_saved-1] = sample; | |
192 | data.numbits = sample_total_saved << 3;//Get the return value correct | |
193 | if(sample_total_saved >= bufsize) break; | |
194 | } | |
195 | else{ | |
196 | pushBit(&data, sample & 0x80); | |
197 | if(bits_per_sample > 1) pushBit(&data, sample & 0x40); | |
198 | if(bits_per_sample > 2) pushBit(&data, sample & 0x20); | |
199 | if(bits_per_sample > 3) pushBit(&data, sample & 0x10); | |
200 | if(bits_per_sample > 4) pushBit(&data, sample & 0x08); | |
201 | if(bits_per_sample > 5) pushBit(&data, sample & 0x04); | |
202 | if(bits_per_sample > 6) pushBit(&data, sample & 0x02); | |
203 | //Not needed, 8bps is covered above | |
204 | //if(bits_per_sample > 7) pushBit(&data, sample & 0x01); | |
205 | if((data.numbits >> 3) +1 >= bufsize) break; | |
206 | } | |
207 | } | |
208 | } | |
209 | ||
210 | if(!silent) | |
211 | { | |
212 | Dbprintf("Done, saved %d out of %d seen samples at %d bits/sample",sample_total_saved, sample_total_numbers,bits_per_sample); | |
213 | Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...", | |
214 | dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); | |
215 | } | |
216 | return data.numbits; | |
217 | } | |
218 | /** | |
219 | * @brief Does sample acquisition, ignoring the config values set in the sample_config. | |
220 | * This method is typically used by tag-specific readers who just wants to read the samples | |
221 | * the normal way | |
222 | * @param trigger_threshold | |
223 | * @param silent | |
224 | * @return number of bits sampled | |
225 | */ | |
226 | uint32_t DoAcquisition_default(int trigger_threshold, bool silent) | |
227 | { | |
2de26056 | 228 | return DoAcquisition(1,8,0,trigger_threshold,silent,0,0,0); |
31abe49f | 229 | } |
b9957414 | 230 | uint32_t DoAcquisition_config(bool silent, int sample_size) |
31abe49f MHS |
231 | { |
232 | return DoAcquisition(config.decimation | |
233 | ,config.bits_per_sample | |
234 | ,config.averaging | |
235 | ,config.trigger_threshold | |
a37228c8 | 236 | ,silent |
217cfb6b | 237 | ,sample_size |
2de26056 | 238 | ,0 |
239 | ,config.samples_to_skip); | |
a37228c8 | 240 | } |
241 | ||
217cfb6b | 242 | uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, int cancel_after) { |
2de26056 | 243 | return DoAcquisition(1,8,0,trigger_threshold,silent,sample_size,cancel_after,0); |
31abe49f MHS |
244 | } |
245 | ||
b9957414 | 246 | uint32_t ReadLF(bool activeField, bool silent, int sample_size) |
31abe49f | 247 | { |
1fbf8956 | 248 | if (!silent) printConfig(); |
31abe49f MHS |
249 | LFSetupFPGAForADC(config.divisor, activeField); |
250 | // Now call the acquisition routine | |
b9957414 | 251 | return DoAcquisition_config(silent, sample_size); |
31abe49f MHS |
252 | } |
253 | ||
254 | /** | |
255 | * Initializes the FPGA for reader-mode (field on), and acquires the samples. | |
256 | * @return number of bits sampled | |
257 | **/ | |
b9957414 | 258 | uint32_t SampleLF(bool printCfg, int sample_size) |
31abe49f | 259 | { |
b9957414 | 260 | uint32_t ret = ReadLF(true, printCfg, sample_size); |
e04475c4 | 261 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); |
262 | return ret; | |
31abe49f MHS |
263 | } |
264 | /** | |
265 | * Initializes the FPGA for snoop-mode (field off), and acquires the samples. | |
266 | * @return number of bits sampled | |
267 | **/ | |
268 | ||
269 | uint32_t SnoopLF() | |
270 | { | |
b9957414 | 271 | uint32_t ret = ReadLF(false, true, 0); |
e04475c4 | 272 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); |
273 | return ret; | |
31abe49f | 274 | } |
7cfc777b | 275 | |
e04475c4 | 276 | /** |
2896e490 | 277 | * acquisition of Cotag LF signal. Similar to other LF, since the Cotag has such long datarate RF/384 |
e04475c4 | 278 | * and is Manchester?, we directly gather the manchester data into bigbuff |
279 | **/ | |
280 | #define COTAG_T1 384 | |
281 | #define COTAG_T2 (COTAG_T1>>1) | |
282 | #define COTAG_ONE_THRESHOLD 128+30 | |
283 | #define COTAG_ZERO_THRESHOLD 128-30 | |
284 | #ifndef COTAG_BITS | |
285 | #define COTAG_BITS 264 | |
286 | #endif | |
287 | void doCotagAcquisition(size_t sample_size) { | |
288 | ||
289 | uint8_t *dest = BigBuf_get_addr(); | |
290 | uint16_t bufsize = BigBuf_max_traceLen(); | |
291 | ||
292 | if ( bufsize > sample_size ) | |
293 | bufsize = sample_size; | |
294 | ||
295 | dest[0] = 0; | |
296 | uint8_t sample = 0, firsthigh = 0, firstlow = 0; | |
297 | uint16_t i = 0; | |
298 | ||
299 | while (!BUTTON_PRESS() && !usb_poll_validate_length() && (i < bufsize) ) { | |
300 | WDT_HIT(); | |
301 | if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { | |
302 | AT91C_BASE_SSC->SSC_THR = 0x43; | |
303 | LED_D_ON(); | |
304 | } | |
305 | ||
306 | if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { | |
307 | sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; | |
308 | LED_D_OFF(); | |
309 | ||
310 | // find first peak | |
311 | if ( !firsthigh ) { | |
312 | if (sample < COTAG_ONE_THRESHOLD) | |
313 | continue; | |
314 | firsthigh = 1; | |
315 | } | |
316 | if ( !firstlow ){ | |
317 | if (sample > COTAG_ZERO_THRESHOLD ) | |
318 | continue; | |
319 | firstlow = 1; | |
320 | } | |
321 | ||
322 | ++i; | |
323 | ||
324 | if ( sample > COTAG_ONE_THRESHOLD) | |
325 | dest[i] = 255; | |
326 | else if ( sample < COTAG_ZERO_THRESHOLD) | |
327 | dest[i] = 0; | |
328 | else | |
329 | dest[i] = dest[i-1]; | |
330 | } | |
331 | } | |
332 | } | |
333 | ||
334 | uint32_t doCotagAcquisitionManchester() { | |
335 | ||
336 | uint8_t *dest = BigBuf_get_addr(); | |
337 | uint16_t bufsize = BigBuf_max_traceLen(); | |
338 | ||
339 | if ( bufsize > COTAG_BITS ) | |
340 | bufsize = COTAG_BITS; | |
341 | ||
342 | dest[0] = 0; | |
343 | uint8_t sample = 0, firsthigh = 0, firstlow = 0; | |
344 | uint16_t sample_counter = 0, period = 0; | |
345 | uint8_t curr = 0, prev = 0; | |
217cfb6b | 346 | uint16_t noise_counter = 0; |
cb593491 | 347 | while (!BUTTON_PRESS() && !usb_poll_validate_length() && (sample_counter < bufsize) && (noise_counter < (COTAG_T1<<1)) ) { |
e04475c4 | 348 | WDT_HIT(); |
349 | if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { | |
350 | AT91C_BASE_SSC->SSC_THR = 0x43; | |
351 | LED_D_ON(); | |
352 | } | |
353 | ||
354 | if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { | |
355 | sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; | |
356 | LED_D_OFF(); | |
357 | ||
358 | // find first peak | |
359 | if ( !firsthigh ) { | |
217cfb6b | 360 | if (sample < COTAG_ONE_THRESHOLD) { |
361 | noise_counter++; | |
e04475c4 | 362 | continue; |
217cfb6b | 363 | } |
364 | noise_counter = 0; | |
e04475c4 | 365 | firsthigh = 1; |
366 | } | |
367 | ||
368 | if ( !firstlow ){ | |
217cfb6b | 369 | if (sample > COTAG_ZERO_THRESHOLD ) { |
370 | noise_counter++; | |
e04475c4 | 371 | continue; |
217cfb6b | 372 | } |
373 | noise_counter=0; | |
e04475c4 | 374 | firstlow = 1; |
375 | } | |
376 | ||
377 | // set sample 255, 0, or previous | |
378 | if ( sample > COTAG_ONE_THRESHOLD){ | |
379 | prev = curr; | |
380 | curr = 1; | |
381 | } | |
382 | else if ( sample < COTAG_ZERO_THRESHOLD) { | |
383 | prev = curr; | |
384 | curr = 0; | |
385 | } | |
386 | else { | |
387 | curr = prev; | |
388 | } | |
389 | ||
390 | // full T1 periods, | |
391 | if ( period > 0 ) { | |
392 | --period; | |
393 | continue; | |
394 | } | |
395 | ||
396 | dest[sample_counter] = curr; | |
397 | ++sample_counter; | |
398 | period = COTAG_T1; | |
399 | } | |
400 | } | |
401 | return sample_counter; | |
402 | } |