Commit | Line | Data |
---|---|---|
40da63b1 UB |
1 | /* stream_test.c |
2 | * | |
3 | * Test reading from FT2232H in synchronous FIFO mode. | |
4 | * | |
5 | * The FT2232H must supply data due to an appropriate circuit | |
6 | * | |
05c2e40a | 7 | * To check for skipped block with appended code, |
40da63b1 UB |
8 | * a structure as follows is assumed |
9 | * 1* uint32_t num (incremented in 0x4000 steps) | |
10 | * 3* uint32_t dont_care | |
11 | * | |
12 | * After start, data will be read in streaming until the program is aborted | |
13 | * Progess information wil be printed out | |
14 | * If a filename is given on the command line, the data read will be | |
15 | * written to that file | |
16 | * | |
17 | */ | |
18 | #include <stdio.h> | |
19 | #include <stdlib.h> | |
20 | #include <stdint.h> | |
21 | #include <string.h> | |
22 | #include <unistd.h> | |
23 | #include <getopt.h> | |
24 | #include <signal.h> | |
25 | #include <errno.h> | |
26 | #include <ftdi.h> | |
27 | void check_outfile(char *); | |
28 | ||
29 | static FILE *outputFile; | |
30 | ||
31 | static int check = 1; | |
32 | static int exitRequested = 0; | |
33 | /* | |
34 | * sigintHandler -- | |
35 | * | |
36 | * SIGINT handler, so we can gracefully exit when the user hits ctrl-C. | |
37 | */ | |
38 | ||
39 | static void | |
40 | sigintHandler(int signum) | |
41 | { | |
05c2e40a | 42 | exitRequested = 1; |
40da63b1 UB |
43 | } |
44 | ||
45 | static void | |
46 | usage(const char *argv0) | |
47 | { | |
05c2e40a TJ |
48 | fprintf(stderr, |
49 | "Usage: %s [options...] \n" | |
50 | "Test streaming read from FT2232H\n" | |
51 | "[-P string] only look for product with given string\n" | |
52 | "[-n] don't check for special block structure\n" | |
53 | "\n" | |
54 | "If some filename is given, write data read to that file\n" | |
55 | "Progess information is printed each second\n" | |
56 | "Abort with ^C\n" | |
57 | "\n" | |
58 | "Options:\n" | |
59 | "\n" | |
60 | "Copyright (C) 2009 Micah Dowty <micah@navi.cx>\n" | |
61 | "Adapted for use with libftdi (C) 2010 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>\n", | |
62 | argv0); | |
63 | exit(1); | |
40da63b1 UB |
64 | } |
65 | ||
66 | static uint32_t start = 0; | |
67 | static uint32_t offset = 0; | |
705f012d | 68 | static uint64_t blocks = 0; |
40da63b1 UB |
69 | static uint32_t skips = 0; |
70 | static uint32_t n_err = 0; | |
71 | static int | |
72 | readCallback(uint8_t *buffer, int length, FTDIProgressInfo *progress, void *userdata) | |
73 | { | |
05c2e40a TJ |
74 | if (length) |
75 | { | |
76 | if (check) | |
77 | { | |
78 | int i,rem; | |
79 | uint32_t num; | |
80 | for (i= offset; i<length-16; i+=16) | |
81 | { | |
82 | num = *(uint32_t*) (buffer+i); | |
83 | if (start && (num != start +0x4000)) | |
84 | { | |
85 | uint32_t delta = ((num-start)/0x4000)-1; | |
86 | fprintf(stderr, "Skip %7d blocks from 0x%08x to 0x%08x at blocks %10llu\n", | |
87 | delta, start -0x4000, num, (unsigned long long)blocks); | |
88 | n_err++; | |
89 | skips += delta; | |
90 | } | |
91 | blocks ++; | |
92 | start = num; | |
93 | } | |
94 | rem = length -i; | |
95 | if (rem >3) | |
96 | { | |
97 | num = *(uint32_t*) (buffer+i); | |
98 | if (start && (num != start +0x4000)) | |
99 | { | |
100 | uint32_t delta = ((num-start)/0x4000)-1; | |
101 | fprintf(stderr, "Skip %7d blocks from 0x%08x to 0x%08x at blocks %10llu\n", | |
102 | delta, start -0x4000, num, (unsigned long long) blocks); | |
103 | n_err++; | |
104 | skips += delta; | |
105 | } | |
106 | start = num; | |
107 | } | |
108 | else if (rem) | |
109 | start += 0x4000; | |
110 | if (rem != 0); | |
111 | { | |
112 | blocks ++; | |
113 | offset = 16-rem; | |
114 | } | |
115 | } | |
116 | if (outputFile) | |
117 | { | |
118 | if (fwrite(buffer, length, 1, outputFile) != 1) | |
119 | { | |
120 | perror("Write error"); | |
121 | return 1; | |
122 | } | |
123 | } | |
124 | } | |
125 | if (progress) | |
126 | { | |
127 | fprintf(stderr, "%10.02fs total time %9.3f MiB captured %7.1f kB/s curr rate %7.1f kB/s totalrate %d dropouts\n", | |
128 | progress->totalTime, | |
129 | progress->current.totalBytes / (1024.0 * 1024.0), | |
130 | progress->currentRate / 1024.0, | |
131 | progress->totalRate / 1024.0, | |
132 | n_err); | |
133 | } | |
134 | return exitRequested ? 1 : 0; | |
40da63b1 UB |
135 | } |
136 | ||
137 | int main(int argc, char **argv) | |
138 | { | |
05c2e40a TJ |
139 | struct ftdi_context ftdic; |
140 | int err, c; | |
141 | FILE *of = NULL; | |
142 | char const *outfile = 0; | |
143 | outputFile =0; | |
144 | exitRequested = 0; | |
145 | char *descstring = NULL; | |
146 | int option_index; | |
147 | static struct option long_options[] = {{NULL},}; | |
40da63b1 | 148 | |
05c2e40a TJ |
149 | while ((c = getopt_long(argc, argv, "P:n", long_options, &option_index)) !=- 1) |
150 | switch (c) | |
151 | { | |
152 | case -1: | |
153 | break; | |
154 | case 'P': | |
155 | descstring = optarg; | |
156 | break; | |
157 | case 'n': | |
158 | check = 0; | |
159 | break; | |
160 | default: | |
161 | usage(argv[0]); | |
162 | } | |
163 | ||
164 | if (optind == argc - 1) | |
165 | { | |
166 | // Exactly one extra argument- a dump file | |
167 | outfile = argv[optind]; | |
168 | } | |
169 | else if (optind < argc) | |
170 | { | |
171 | // Too many extra args | |
172 | usage(argv[0]); | |
173 | } | |
174 | ||
175 | if (ftdi_init(&ftdic) < 0) | |
176 | { | |
177 | fprintf(stderr, "ftdi_init failed\n"); | |
178 | return EXIT_FAILURE; | |
179 | } | |
180 | ||
181 | if (ftdi_set_interface(&ftdic, INTERFACE_A) < 0) | |
182 | { | |
183 | fprintf(stderr, "ftdi_set_interface failed\n"); | |
184 | return EXIT_FAILURE; | |
185 | } | |
186 | ||
187 | if (ftdi_usb_open_desc(&ftdic, 0x0403, 0x6010, descstring, NULL) < 0) | |
188 | { | |
189 | fprintf(stderr,"Can't open ftdi device: %s\n",ftdi_get_error_string(&ftdic)); | |
190 | return EXIT_FAILURE; | |
191 | } | |
192 | ||
193 | /* A timeout value of 1 results in may skipped blocks */ | |
194 | if (ftdi_set_latency_timer(&ftdic, 2)) | |
195 | { | |
196 | fprintf(stderr,"Can't set latency, Error %s\n",ftdi_get_error_string(&ftdic)); | |
197 | return EXIT_FAILURE; | |
198 | } | |
199 | ||
200 | /* if(ftdi_usb_purge_rx_buffer(&ftdic) < 0) | |
40da63b1 | 201 | { |
05c2e40a | 202 | fprintf(stderr,"Can't rx purge\n",ftdi_get_error_string(&ftdic)); |
40da63b1 | 203 | return EXIT_FAILURE; |
05c2e40a TJ |
204 | }*/ |
205 | if (outfile) | |
206 | if ((of = fopen(outfile,"w+")) == 0) | |
207 | fprintf(stderr,"Can't open logfile %s, Error %s\n", outfile, strerror(errno)); | |
208 | if (of) | |
209 | if (setvbuf(of, NULL, _IOFBF , 1<<16) == 0) | |
210 | outputFile = of; | |
211 | signal(SIGINT, sigintHandler); | |
212 | ||
213 | err = ftdi_readstream(&ftdic, readCallback, NULL, 8, 256); | |
214 | if (err < 0 && !exitRequested) | |
215 | exit(1); | |
216 | ||
217 | if (outputFile) | |
218 | { | |
219 | fclose(outputFile); | |
220 | outputFile = NULL; | |
221 | } | |
222 | fprintf(stderr, "Capture ended.\n"); | |
223 | ||
224 | if (ftdi_set_bitmode(&ftdic, 0xff, BITMODE_RESET) < 0) | |
225 | { | |
226 | fprintf(stderr,"Can't set synchronous fifo mode, Error %s\n",ftdi_get_error_string(&ftdic)); | |
227 | return EXIT_FAILURE; | |
228 | } | |
229 | ftdi_usb_close(&ftdic); | |
230 | ftdi_deinit(&ftdic); | |
231 | signal(SIGINT, SIG_DFL); | |
232 | if (check && outfile) | |
233 | { | |
234 | if ((outputFile = fopen(outfile,"r")) == 0) | |
235 | { | |
236 | fprintf(stderr,"Can't open logfile %s, Error %s\n", outfile, strerror(errno)); | |
237 | return EXIT_FAILURE; | |
238 | } | |
239 | check_outfile(descstring); | |
240 | fclose(outputFile); | |
241 | } | |
242 | else if (check) | |
243 | fprintf(stderr,"%d errors of %llu blocks (%Le), %d (%Le) blocks skipped\n", | |
244 | n_err, (unsigned long long) blocks, (long double)n_err/(long double) blocks, | |
245 | skips, (long double)skips/(long double) blocks); | |
246 | exit (0); | |
40da63b1 UB |
247 | } |
248 | ||
249 | void check_outfile(char *descstring) | |
250 | { | |
05c2e40a | 251 | if (strcmp(descstring,"FT2232HTEST") == 0) |
40da63b1 | 252 | { |
05c2e40a TJ |
253 | char buf0[1024]; |
254 | char buf1[1024]; | |
255 | char bufr[1024]; | |
256 | char *pa, *pb, *pc; | |
257 | unsigned int num_lines = 0, line_num = 1; | |
258 | int err_count = 0; | |
259 | unsigned int num_start, num_end; | |
40da63b1 | 260 | |
05c2e40a TJ |
261 | pa = buf0; |
262 | pb = buf1; | |
263 | pc = buf0; | |
264 | if (fgets(pa, 1023, outputFile) == NULL) | |
265 | { | |
266 | fprintf(stderr,"Empty output file\n"); | |
267 | return; | |
268 | } | |
269 | while (fgets(pb, 1023, outputFile) != NULL) | |
270 | { | |
271 | num_lines++; | |
272 | unsigned int num_save = num_start; | |
273 | if ( sscanf(pa,"%6u%94s%6u",&num_start, bufr,&num_end) !=3) | |
274 | { | |
275 | fprintf(stdout,"Format doesn't match at line %8d \"%s", | |
276 | num_lines, pa); | |
277 | err_count++; | |
278 | line_num = num_save +2; | |
279 | } | |
280 | else | |
281 | { | |
282 | if ((num_start+1)%100000 != num_end) | |
283 | { | |
284 | if (err_count < 20) | |
285 | fprintf(stdout,"Malformed line %d \"%s\"\n", | |
286 | num_lines, pa); | |
287 | err_count++; | |
288 | } | |
289 | else if (num_start != line_num) | |
290 | { | |
291 | if (err_count < 20) | |
292 | fprintf(stdout,"Skipping from %d to %d\n", | |
293 | line_num, num_start); | |
294 | err_count++; | |
295 | ||
296 | } | |
297 | line_num = num_end; | |
298 | } | |
299 | pa = pb; | |
300 | pb = pc; | |
301 | pc = pa; | |
302 | } | |
303 | if (err_count) | |
304 | fprintf(stdout,"\n%d errors of %d data sets %f\n", err_count, num_lines, (double) err_count/(double)num_lines); | |
305 | else | |
306 | fprintf(stdout,"No errors for %d lines\n",num_lines); | |
307 | } | |
308 | else if (strcmp(descstring,"LLBBC10") == 0) | |
309 | { | |
40da63b1 UB |
310 | uint32_t block0[4]; |
311 | uint32_t block1[4]; | |
312 | uint32_t *pa = block0; | |
313 | uint32_t *pb = block1; | |
314 | uint32_t *pc = block0; | |
315 | uint32_t start= 0; | |
316 | uint32_t nread = 0; | |
40da63b1 UB |
317 | int n_shown = 0; |
318 | int n_errors = 0; | |
319 | if (fread(pa, sizeof(uint32_t), 4,outputFile) < 4) | |
320 | { | |
321 | fprintf(stderr,"Empty result file\n"); | |
322 | return; | |
323 | } | |
05c2e40a | 324 | while (fread(pb, sizeof(uint32_t), 4,outputFile) != 0) |
40da63b1 UB |
325 | { |
326 | blocks++; | |
327 | nread = pa[0]; | |
05c2e40a | 328 | if (start>0 && (nread != start)) |
40da63b1 | 329 | { |
05c2e40a | 330 | if (n_shown < 30) |
40da63b1 | 331 | { |
ededbc1c UB |
332 | fprintf(stderr, "Skip %7d blocks from 0x%08x to 0x%08x at blocks %10llu \n", |
333 | (nread-start)/0x4000, start -0x4000, nread, (unsigned long long) blocks); | |
40da63b1 UB |
334 | n_shown ++; |
335 | } | |
336 | n_errors++; | |
337 | } | |
05c2e40a TJ |
338 | else if (n_shown >0) |
339 | n_shown--; | |
40da63b1 UB |
340 | start = nread + 0x4000; |
341 | pa = pb; | |
342 | pb = pc; | |
343 | pc = pa; | |
344 | } | |
05c2e40a | 345 | if (n_errors) |
ededbc1c UB |
346 | fprintf(stderr, "%d blocks wrong from %llu blocks read\n", |
347 | n_errors, (unsigned long long) blocks); | |
40da63b1 | 348 | else |
ededbc1c | 349 | fprintf(stderr, "%llu blocks all fine\n", (unsigned long long) blocks); |
40da63b1 UB |
350 | } |
351 | } |