]>
Commit | Line | Data |
---|---|---|
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 "lfsampling.h" | |
10 | ||
11 | sample_config config = { 1, 8, 1, 95, 0 } ; | |
12 | ||
13 | void printConfig() { | |
14 | Dbprintf("LF Sampling config: "); | |
15 | Dbprintf(" [q] divisor: %d ", config.divisor); | |
16 | Dbprintf(" [b] bps: %d ", config.bits_per_sample); | |
17 | Dbprintf(" [d] decimation: %d ", config.decimation); | |
18 | Dbprintf(" [a] averaging: %d ", config.averaging); | |
19 | Dbprintf(" [t] trigger threshold: %d ", config.trigger_threshold); | |
20 | } | |
21 | ||
22 | ||
23 | /** | |
24 | * Called from the USB-handler to set the sampling configuration | |
25 | * The sampling config is used for std reading and snooping. | |
26 | * | |
27 | * Other functions may read samples and ignore the sampling config, | |
28 | * such as functions to read the UID from a prox tag or similar. | |
29 | * | |
30 | * Values set to '0' implies no change (except for averaging) | |
31 | * @brief setSamplingConfig | |
32 | * @param sc | |
33 | */ | |
34 | void setSamplingConfig(sample_config *sc) { | |
35 | if(sc->divisor != 0) config.divisor = sc->divisor; | |
36 | if(sc->bits_per_sample != 0) config.bits_per_sample = sc->bits_per_sample; | |
37 | if(sc->decimation != 0) config.decimation = sc->decimation; | |
38 | if(sc->trigger_threshold != -1) config.trigger_threshold = sc->trigger_threshold; | |
39 | ||
40 | config.averaging = sc->averaging; | |
41 | if(config.bits_per_sample > 8) config.bits_per_sample = 8; | |
42 | if(config.decimation < 1) config.decimation = 1; | |
43 | ||
44 | printConfig(); | |
45 | } | |
46 | ||
47 | sample_config* getSamplingConfig() { | |
48 | return &config; | |
49 | } | |
50 | ||
51 | struct BitstreamOut { | |
52 | uint8_t * buffer; | |
53 | uint32_t numbits; | |
54 | uint32_t position; | |
55 | }; | |
56 | ||
57 | /** | |
58 | * @brief Pushes bit onto the stream | |
59 | * @param stream | |
60 | * @param bit | |
61 | */ | |
62 | void pushBit( BitstreamOut* stream, uint8_t bit) { | |
63 | int bytepos = stream->position >> 3; // divide by 8 | |
64 | int bitpos = stream->position & 7; | |
65 | *(stream->buffer+bytepos) |= (bit > 0) << (7 - bitpos); | |
66 | stream->position++; | |
67 | stream->numbits++; | |
68 | } | |
69 | ||
70 | /** | |
71 | * Setup the FPGA to listen for samples. This method downloads the FPGA bitstream | |
72 | * if not already loaded, sets divisor and starts up the antenna. | |
73 | * @param divisor : 1, 88> 255 or negative ==> 134.8 KHz | |
74 | * 0 or 95 ==> 125 KHz | |
75 | * | |
76 | **/ | |
77 | void LFSetupFPGAForADC(int divisor, bool lf_field) { | |
78 | FpgaDownloadAndGo(FPGA_BITSTREAM_LF); | |
79 | if ( (divisor == 1) || (divisor < 0) || (divisor > 255) ) | |
80 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz | |
81 | else if (divisor == 0) | |
82 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz | |
83 | else | |
84 | FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); | |
85 | ||
86 | FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | (lf_field ? FPGA_LF_ADC_READER_FIELD : 0)); | |
87 | ||
88 | // Connect the A/D to the peak-detected low-frequency path. | |
89 | SetAdcMuxFor(GPIO_MUXSEL_LOPKD); | |
90 | // 50ms for the resonant antenna to settle. | |
91 | SpinDelay(50); | |
92 | // Now set up the SSC to get the ADC samples that are now streaming at us. | |
93 | FpgaSetupSsc(); | |
94 | // start a 1.5ticks is 1us | |
95 | StartTicks(); | |
96 | } | |
97 | ||
98 | /** | |
99 | * Does the sample acquisition. If threshold is specified, the actual sampling | |
100 | * is not commenced until the threshold has been reached. | |
101 | * This method implements decimation and quantization in order to | |
102 | * be able to provide longer sample traces. | |
103 | * Uses the following global settings: | |
104 | * @param decimation - how much should the signal be decimated. A decimation of N means we keep 1 in N samples, etc. | |
105 | * @param bits_per_sample - bits per sample. Max 8, min 1 bit per sample. | |
106 | * @param averaging If set to true, decimation will use averaging, so that if e.g. decimation is 3, the sample | |
107 | * value that will be used is the average value of the three samples. | |
108 | * @param trigger_threshold - a threshold. The sampling won't commence until this threshold has been reached. Set | |
109 | * to -1 to ignore threshold. | |
110 | * @param silent - is true, now outputs are made. If false, dbprints the status | |
111 | * @return the number of bits occupied by the samples. | |
112 | */ | |
113 | uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent) { | |
114 | //bigbuf, to hold the aquired raw data signal | |
115 | uint8_t *dest = BigBuf_get_addr(); | |
116 | uint16_t bufsize = BigBuf_max_traceLen(); | |
117 | ||
118 | //BigBuf_Clear_ext(false); //creates issues with cmdread (marshmellow) | |
119 | ||
120 | if(bits_per_sample < 1) bits_per_sample = 1; | |
121 | if(bits_per_sample > 8) bits_per_sample = 8; | |
122 | ||
123 | if(decimation < 1) decimation = 1; | |
124 | ||
125 | // Use a bit stream to handle the output | |
126 | BitstreamOut data = { dest , 0, 0}; | |
127 | int sample_counter = 0; | |
128 | uint8_t sample = 0; | |
129 | //If we want to do averaging | |
130 | uint32_t sample_sum =0 ; | |
131 | uint32_t sample_total_numbers =0 ; | |
132 | uint32_t sample_total_saved =0 ; | |
133 | ||
134 | while(!BUTTON_PRESS() && !usb_poll_validate_length() ) { | |
135 | WDT_HIT(); | |
136 | if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { | |
137 | AT91C_BASE_SSC->SSC_THR = 0x43; | |
138 | LED_D_ON(); | |
139 | } | |
140 | if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { | |
141 | sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; | |
142 | LED_D_OFF(); | |
143 | // threshold either high or low values 128 = center 0. if trigger = 178 | |
144 | if ((trigger_threshold > 0) && (sample < (trigger_threshold+128)) && (sample > (128-trigger_threshold))) // | |
145 | continue; | |
146 | ||
147 | trigger_threshold = 0; | |
148 | sample_total_numbers++; | |
149 | ||
150 | if(averaging) | |
151 | { | |
152 | sample_sum += sample; | |
153 | } | |
154 | //Check decimation | |
155 | if(decimation > 1) | |
156 | { | |
157 | sample_counter++; | |
158 | if(sample_counter < decimation) continue; | |
159 | sample_counter = 0; | |
160 | } | |
161 | //Averaging | |
162 | if(averaging && decimation > 1) { | |
163 | sample = sample_sum / decimation; | |
164 | sample_sum =0; | |
165 | } | |
166 | //Store the sample | |
167 | sample_total_saved ++; | |
168 | if(bits_per_sample == 8){ | |
169 | dest[sample_total_saved-1] = sample; | |
170 | data.numbits = sample_total_saved << 3;//Get the return value correct | |
171 | if(sample_total_saved >= bufsize) break; | |
172 | } | |
173 | else{ | |
174 | pushBit(&data, sample & 0x80); | |
175 | if(bits_per_sample > 1) pushBit(&data, sample & 0x40); | |
176 | if(bits_per_sample > 2) pushBit(&data, sample & 0x20); | |
177 | if(bits_per_sample > 3) pushBit(&data, sample & 0x10); | |
178 | if(bits_per_sample > 4) pushBit(&data, sample & 0x08); | |
179 | if(bits_per_sample > 5) pushBit(&data, sample & 0x04); | |
180 | if(bits_per_sample > 6) pushBit(&data, sample & 0x02); | |
181 | //Not needed, 8bps is covered above | |
182 | //if(bits_per_sample > 7) pushBit(&data, sample & 0x01); | |
183 | if((data.numbits >> 3) +1 >= bufsize) break; | |
184 | } | |
185 | } | |
186 | } | |
187 | ||
188 | if(!silent) | |
189 | { | |
190 | Dbprintf("Done, saved %d out of %d seen samples at %d bits/sample",sample_total_saved, sample_total_numbers,bits_per_sample); | |
191 | Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...", | |
192 | dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); | |
193 | } | |
194 | return data.numbits; | |
195 | } | |
196 | /** | |
197 | * @brief Does sample acquisition, ignoring the config values set in the sample_config. | |
198 | * This method is typically used by tag-specific readers who just wants to read the samples | |
199 | * the normal way | |
200 | * @param trigger_threshold | |
201 | * @param silent | |
202 | * @return number of bits sampled | |
203 | */ | |
204 | uint32_t DoAcquisition_default(int trigger_threshold, bool silent) { | |
205 | return DoAcquisition(1,8,0,trigger_threshold,silent); | |
206 | } | |
207 | uint32_t DoAcquisition_config( bool silent) { | |
208 | return DoAcquisition(config.decimation | |
209 | ,config.bits_per_sample | |
210 | ,config.averaging | |
211 | ,config.trigger_threshold | |
212 | ,silent); | |
213 | } | |
214 | ||
215 | uint32_t ReadLF(bool activeField, bool silent) { | |
216 | if (!silent) | |
217 | printConfig(); | |
218 | LFSetupFPGAForADC(config.divisor, activeField); | |
219 | return DoAcquisition_config(silent); | |
220 | } | |
221 | ||
222 | /** | |
223 | * Initializes the FPGA for reader-mode (field on), and acquires the samples. | |
224 | * @return number of bits sampled | |
225 | **/ | |
226 | uint32_t SampleLF(bool printCfg) { | |
227 | BigBuf_Clear_ext(false); | |
228 | uint32_t ret = ReadLF(true, printCfg); | |
229 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); | |
230 | return ret; | |
231 | } | |
232 | /** | |
233 | * Initializes the FPGA for snoop-mode (field off), and acquires the samples. | |
234 | * @return number of bits sampled | |
235 | **/ | |
236 | uint32_t SnoopLF() { | |
237 | BigBuf_Clear_ext(false); | |
238 | uint32_t ret = ReadLF(false, true); | |
239 | FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); | |
240 | return ret; | |
241 | } | |
242 | ||
243 | /** | |
244 | * acquisition of T55x7 LF signal. Similart to other LF, but adjusted with @marshmellows thresholds | |
245 | * the data is collected in BigBuf. | |
246 | **/ | |
247 | void doT55x7Acquisition(size_t sample_size) { | |
248 | ||
249 | #define T55xx_READ_UPPER_THRESHOLD 128+40 // 60 grph | |
250 | #define T55xx_READ_LOWER_THRESHOLD 128-40 // -60 grph | |
251 | #define T55xx_READ_TOL 2 | |
252 | ||
253 | uint8_t *dest = BigBuf_get_addr(); | |
254 | uint16_t bufsize = BigBuf_max_traceLen(); | |
255 | ||
256 | if ( bufsize > sample_size ) | |
257 | bufsize = sample_size; | |
258 | ||
259 | uint8_t curSample = 0, lastSample = 0; | |
260 | uint16_t i = 0, skipCnt = 0; | |
261 | bool startFound = false; | |
262 | bool highFound = false; | |
263 | bool lowFound = false; | |
264 | ||
265 | while(!BUTTON_PRESS() && !usb_poll_validate_length() && skipCnt < 1000 && (i < bufsize) ) { | |
266 | WDT_HIT(); | |
267 | if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { | |
268 | AT91C_BASE_SSC->SSC_THR = 0x43; //43 | |
269 | LED_D_ON(); | |
270 | } | |
271 | if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { | |
272 | curSample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; | |
273 | LED_D_OFF(); | |
274 | ||
275 | // skip until the first high sample above threshold | |
276 | if (!startFound && curSample > T55xx_READ_UPPER_THRESHOLD) { | |
277 | //if (curSample > lastSample) | |
278 | // lastSample = curSample; | |
279 | highFound = true; | |
280 | } else if (!highFound) { | |
281 | skipCnt++; | |
282 | continue; | |
283 | } | |
284 | // skip until the first low sample below threshold | |
285 | if (!startFound && curSample < T55xx_READ_LOWER_THRESHOLD) { | |
286 | //if (curSample > lastSample) | |
287 | lastSample = curSample; | |
288 | lowFound = true; | |
289 | } else if (!lowFound) { | |
290 | skipCnt++; | |
291 | continue; | |
292 | } | |
293 | ||
294 | // skip until first high samples begin to change | |
295 | if (startFound || curSample > T55xx_READ_LOWER_THRESHOLD + T55xx_READ_TOL){ | |
296 | // if just found start - recover last sample | |
297 | if (!startFound) { | |
298 | dest[i++] = lastSample; | |
299 | startFound = true; | |
300 | } | |
301 | // collect samples | |
302 | dest[i++] = curSample; | |
303 | } | |
304 | } | |
305 | } | |
306 | } | |
307 |