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 | * | |
7 | * To check for skipped block with appended code, | |
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 | { | |
42 | exitRequested = 1; | |
43 | } | |
44 | ||
45 | static void | |
46 | usage(const char *argv0) | |
47 | { | |
48 | fprintf(stderr, | |
36335b92 | 49 | "Usage: %s [options...] \n" |
40da63b1 | 50 | "Test streaming read from FT2232H\n" |
36335b92 UB |
51 | "[-P string] only look for product with given string\n" |
52 | "[-n] don't check for special block structure\n" | |
40da63b1 UB |
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" | |
36335b92 | 60 | "Copyright (C) 2009 Micah Dowty <micah@navi.cx>\n" |
40da63b1 UB |
61 | "Adapted for use with libftdi (C) 2010 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>\n", |
62 | argv0); | |
63 | exit(1); | |
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 | { | |
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; | |
d042a097 UB |
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); | |
40da63b1 UB |
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; | |
d042a097 UB |
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); | |
40da63b1 UB |
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 | { | |
705f012d | 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", |
40da63b1 UB |
128 | progress->totalTime, |
129 | progress->current.totalBytes / (1024.0 * 1024.0), | |
130 | progress->currentRate / 1024.0, | |
705f012d UB |
131 | progress->totalRate / 1024.0, |
132 | n_err); | |
40da63b1 UB |
133 | } |
134 | return exitRequested ? 1 : 0; | |
135 | } | |
136 | ||
137 | int main(int argc, char **argv) | |
138 | { | |
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},}; | |
148 | ||
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 | { | |
705f012d | 196 | fprintf(stderr,"Can't set latency, Error %s\n",ftdi_get_error_string(&ftdic)); |
40da63b1 UB |
197 | return EXIT_FAILURE; |
198 | } | |
199 | ||
200 | /* if(ftdi_usb_purge_rx_buffer(&ftdic) < 0) | |
201 | { | |
202 | fprintf(stderr,"Can't rx purge\n",ftdi_get_error_string(&ftdic)); | |
203 | return EXIT_FAILURE; | |
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 | fclose(outputFile); | |
219 | outputFile = NULL; | |
220 | } | |
221 | fprintf(stderr, "Capture ended.\n"); | |
222 | ||
223 | if (ftdi_set_bitmode(&ftdic, 0xff, BITMODE_RESET) < 0) | |
224 | { | |
705f012d | 225 | fprintf(stderr,"Can't set synchronous fifo mode, Error %s\n",ftdi_get_error_string(&ftdic)); |
40da63b1 UB |
226 | return EXIT_FAILURE; |
227 | } | |
228 | ftdi_usb_close(&ftdic); | |
229 | ftdi_deinit(&ftdic); | |
230 | signal(SIGINT, SIG_DFL); | |
231 | if (check && outfile) | |
232 | { | |
233 | if ((outputFile = fopen(outfile,"r")) == 0) | |
234 | { | |
235 | fprintf(stderr,"Can't open logfile %s, Error %s\n", outfile, strerror(errno)); | |
236 | return EXIT_FAILURE; | |
237 | } | |
238 | check_outfile(descstring); | |
239 | fclose(outputFile); | |
240 | } | |
241 | else if (check) | |
d042a097 UB |
242 | fprintf(stderr,"%d errors of %llu blocks (%Le), %d (%Le) blocks skipped\n", |
243 | n_err, (unsigned long long) blocks, (long double)n_err/(long double) blocks, | |
40da63b1 UB |
244 | skips, (long double)skips/(long double) blocks); |
245 | exit (0); | |
246 | } | |
247 | ||
248 | void check_outfile(char *descstring) | |
249 | { | |
250 | if(strcmp(descstring,"FT2232HTEST") == 0) | |
251 | { | |
252 | char buf0[1024]; | |
253 | char buf1[1024]; | |
254 | char bufr[1024]; | |
255 | char *pa, *pb, *pc; | |
256 | unsigned int num_lines = 0, line_num = 1; | |
257 | int err_count = 0; | |
258 | unsigned int num_start, num_end; | |
259 | ||
40da63b1 UB |
260 | pa = buf0; |
261 | pb = buf1; | |
262 | pc = buf0; | |
263 | if(fgets(pa, 1023, outputFile) == NULL) | |
264 | { | |
265 | fprintf(stderr,"Empty output file\n"); | |
266 | return; | |
267 | } | |
268 | while(fgets(pb, 1023, outputFile) != NULL) | |
269 | { | |
270 | num_lines++; | |
271 | unsigned int num_save = num_start; | |
272 | if( sscanf(pa,"%6u%94s%6u",&num_start, bufr,&num_end) !=3) | |
273 | { | |
274 | fprintf(stdout,"Format doesn't match at line %8d \"%s", | |
275 | num_lines, pa); | |
276 | err_count++; | |
277 | line_num = num_save +2; | |
278 | } | |
279 | else | |
280 | { | |
281 | if ((num_start+1)%100000 != num_end) | |
282 | { | |
283 | if (err_count < 20) | |
284 | fprintf(stdout,"Malformed line %d \"%s\"\n", | |
285 | num_lines, pa); | |
286 | err_count++; | |
287 | } | |
288 | else if(num_start != line_num) | |
289 | { | |
290 | if (err_count < 20) | |
291 | fprintf(stdout,"Skipping from %d to %d\n", | |
292 | line_num, num_start); | |
293 | err_count++; | |
294 | ||
295 | } | |
296 | line_num = num_end; | |
297 | } | |
298 | pa = pb; | |
299 | pb = pc; | |
300 | pc = pa; | |
301 | } | |
302 | if(err_count) | |
303 | fprintf(stdout,"\n%d errors of %d data sets %f\n", err_count, num_lines, (double) err_count/(double)num_lines); | |
304 | else | |
305 | fprintf(stdout,"No errors for %d lines\n",num_lines); | |
306 | } | |
307 | else if(strcmp(descstring,"LLBBC10") == 0) | |
308 | { | |
309 | uint32_t block0[4]; | |
310 | uint32_t block1[4]; | |
311 | uint32_t *pa = block0; | |
312 | uint32_t *pb = block1; | |
313 | uint32_t *pc = block0; | |
314 | uint32_t start= 0; | |
315 | uint32_t nread = 0; | |
40da63b1 UB |
316 | int n_shown = 0; |
317 | int n_errors = 0; | |
318 | if (fread(pa, sizeof(uint32_t), 4,outputFile) < 4) | |
319 | { | |
320 | fprintf(stderr,"Empty result file\n"); | |
321 | return; | |
322 | } | |
323 | while(fread(pb, sizeof(uint32_t), 4,outputFile) != 0) | |
324 | { | |
325 | blocks++; | |
326 | nread = pa[0]; | |
327 | if(start>0 && (nread != start)) | |
328 | { | |
329 | if(n_shown < 30) | |
330 | { | |
d042a097 UB |
331 | fprintf(stderr, "Skip %7d blocks from 0x%08x to 0x%08x at blocks %10llu \n", |
332 | (nread-start)/0x4000, start -0x4000, nread, (unsigned long long) blocks); | |
40da63b1 UB |
333 | n_shown ++; |
334 | } | |
335 | n_errors++; | |
336 | } | |
337 | else if (n_shown >0) | |
338 | n_shown--; | |
339 | start = nread + 0x4000; | |
340 | pa = pb; | |
341 | pb = pc; | |
342 | pc = pa; | |
343 | } | |
344 | if(n_errors) | |
d042a097 UB |
345 | fprintf(stderr, "%d blocks wrong from %llu blocks read\n", |
346 | n_errors, (unsigned long long) blocks); | |
40da63b1 | 347 | else |
d042a097 | 348 | fprintf(stderr, "%llu blocks all fine\n", (unsigned long long) blocks); |
40da63b1 UB |
349 | } |
350 | } |