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; | |
19382a28 | 110 | if (rem != 0) |
40da63b1 UB |
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 | { | |
cd2ead2f | 139 | struct ftdi_context *ftdi; |
40da63b1 UB |
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 | ||
cd2ead2f | 175 | if ((ftdi = ftdi_new()) == 0) |
40da63b1 | 176 | { |
cd2ead2f | 177 | fprintf(stderr, "ftdi_new failed\n"); |
40da63b1 UB |
178 | return EXIT_FAILURE; |
179 | } | |
180 | ||
cd2ead2f | 181 | if (ftdi_set_interface(ftdi, INTERFACE_A) < 0) |
40da63b1 UB |
182 | { |
183 | fprintf(stderr, "ftdi_set_interface failed\n"); | |
cd2ead2f | 184 | ftdi_free(ftdi); |
40da63b1 UB |
185 | return EXIT_FAILURE; |
186 | } | |
187 | ||
cd2ead2f | 188 | if (ftdi_usb_open_desc(ftdi, 0x0403, 0x6010, descstring, NULL) < 0) |
40da63b1 | 189 | { |
cd2ead2f UB |
190 | fprintf(stderr,"Can't open ftdi device: %s\n",ftdi_get_error_string(ftdi)); |
191 | ftdi_free(ftdi); | |
40da63b1 UB |
192 | return EXIT_FAILURE; |
193 | } | |
194 | ||
195 | /* A timeout value of 1 results in may skipped blocks */ | |
cd2ead2f | 196 | if(ftdi_set_latency_timer(ftdi, 2)) |
40da63b1 | 197 | { |
cd2ead2f UB |
198 | fprintf(stderr,"Can't set latency, Error %s\n",ftdi_get_error_string(ftdi)); |
199 | ftdi_usb_close(ftdi); | |
200 | ftdi_free(ftdi); | |
40da63b1 UB |
201 | return EXIT_FAILURE; |
202 | } | |
203 | ||
cd2ead2f | 204 | /* if(ftdi_usb_purge_rx_buffer(ftdi) < 0) |
40da63b1 | 205 | { |
cd2ead2f | 206 | fprintf(stderr,"Can't rx purge\n",ftdi_get_error_string(ftdi)); |
40da63b1 UB |
207 | return EXIT_FAILURE; |
208 | }*/ | |
209 | if (outfile) | |
210 | if ((of = fopen(outfile,"w+")) == 0) | |
211 | fprintf(stderr,"Can't open logfile %s, Error %s\n", outfile, strerror(errno)); | |
212 | if (of) | |
213 | if (setvbuf(of, NULL, _IOFBF , 1<<16) == 0) | |
214 | outputFile = of; | |
215 | signal(SIGINT, sigintHandler); | |
216 | ||
cd2ead2f | 217 | err = ftdi_readstream(ftdi, readCallback, NULL, 8, 256); |
40da63b1 UB |
218 | if (err < 0 && !exitRequested) |
219 | exit(1); | |
220 | ||
221 | if (outputFile) { | |
222 | fclose(outputFile); | |
223 | outputFile = NULL; | |
224 | } | |
225 | fprintf(stderr, "Capture ended.\n"); | |
226 | ||
cd2ead2f | 227 | if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET) < 0) |
40da63b1 | 228 | { |
cd2ead2f UB |
229 | fprintf(stderr,"Can't set synchronous fifo mode, Error %s\n",ftdi_get_error_string(ftdi)); |
230 | ftdi_usb_close(ftdi); | |
231 | ftdi_free(ftdi); | |
40da63b1 UB |
232 | return EXIT_FAILURE; |
233 | } | |
cd2ead2f UB |
234 | ftdi_usb_close(ftdi); |
235 | ftdi_free(ftdi); | |
40da63b1 UB |
236 | signal(SIGINT, SIG_DFL); |
237 | if (check && outfile) | |
238 | { | |
239 | if ((outputFile = fopen(outfile,"r")) == 0) | |
240 | { | |
241 | fprintf(stderr,"Can't open logfile %s, Error %s\n", outfile, strerror(errno)); | |
cd2ead2f UB |
242 | ftdi_usb_close(ftdi); |
243 | ftdi_free(ftdi); | |
40da63b1 UB |
244 | return EXIT_FAILURE; |
245 | } | |
246 | check_outfile(descstring); | |
247 | fclose(outputFile); | |
248 | } | |
249 | else if (check) | |
d042a097 UB |
250 | fprintf(stderr,"%d errors of %llu blocks (%Le), %d (%Le) blocks skipped\n", |
251 | n_err, (unsigned long long) blocks, (long double)n_err/(long double) blocks, | |
40da63b1 UB |
252 | skips, (long double)skips/(long double) blocks); |
253 | exit (0); | |
254 | } | |
255 | ||
256 | void check_outfile(char *descstring) | |
257 | { | |
258 | if(strcmp(descstring,"FT2232HTEST") == 0) | |
259 | { | |
260 | char buf0[1024]; | |
261 | char buf1[1024]; | |
262 | char bufr[1024]; | |
263 | char *pa, *pb, *pc; | |
264 | unsigned int num_lines = 0, line_num = 1; | |
265 | int err_count = 0; | |
266 | unsigned int num_start, num_end; | |
267 | ||
40da63b1 UB |
268 | pa = buf0; |
269 | pb = buf1; | |
270 | pc = buf0; | |
271 | if(fgets(pa, 1023, outputFile) == NULL) | |
272 | { | |
273 | fprintf(stderr,"Empty output file\n"); | |
274 | return; | |
275 | } | |
276 | while(fgets(pb, 1023, outputFile) != NULL) | |
277 | { | |
278 | num_lines++; | |
279 | unsigned int num_save = num_start; | |
280 | if( sscanf(pa,"%6u%94s%6u",&num_start, bufr,&num_end) !=3) | |
281 | { | |
282 | fprintf(stdout,"Format doesn't match at line %8d \"%s", | |
283 | num_lines, pa); | |
284 | err_count++; | |
285 | line_num = num_save +2; | |
286 | } | |
287 | else | |
288 | { | |
289 | if ((num_start+1)%100000 != num_end) | |
290 | { | |
291 | if (err_count < 20) | |
292 | fprintf(stdout,"Malformed line %d \"%s\"\n", | |
293 | num_lines, pa); | |
294 | err_count++; | |
295 | } | |
296 | else if(num_start != line_num) | |
297 | { | |
298 | if (err_count < 20) | |
299 | fprintf(stdout,"Skipping from %d to %d\n", | |
300 | line_num, num_start); | |
301 | err_count++; | |
302 | ||
303 | } | |
304 | line_num = num_end; | |
305 | } | |
306 | pa = pb; | |
307 | pb = pc; | |
308 | pc = pa; | |
309 | } | |
310 | if(err_count) | |
311 | fprintf(stdout,"\n%d errors of %d data sets %f\n", err_count, num_lines, (double) err_count/(double)num_lines); | |
312 | else | |
313 | fprintf(stdout,"No errors for %d lines\n",num_lines); | |
314 | } | |
315 | else if(strcmp(descstring,"LLBBC10") == 0) | |
316 | { | |
317 | uint32_t block0[4]; | |
318 | uint32_t block1[4]; | |
319 | uint32_t *pa = block0; | |
320 | uint32_t *pb = block1; | |
321 | uint32_t *pc = block0; | |
322 | uint32_t start= 0; | |
323 | uint32_t nread = 0; | |
40da63b1 UB |
324 | int n_shown = 0; |
325 | int n_errors = 0; | |
326 | if (fread(pa, sizeof(uint32_t), 4,outputFile) < 4) | |
327 | { | |
328 | fprintf(stderr,"Empty result file\n"); | |
329 | return; | |
330 | } | |
331 | while(fread(pb, sizeof(uint32_t), 4,outputFile) != 0) | |
332 | { | |
333 | blocks++; | |
334 | nread = pa[0]; | |
335 | if(start>0 && (nread != start)) | |
336 | { | |
337 | if(n_shown < 30) | |
338 | { | |
d042a097 UB |
339 | fprintf(stderr, "Skip %7d blocks from 0x%08x to 0x%08x at blocks %10llu \n", |
340 | (nread-start)/0x4000, start -0x4000, nread, (unsigned long long) blocks); | |
40da63b1 UB |
341 | n_shown ++; |
342 | } | |
343 | n_errors++; | |
344 | } | |
345 | else if (n_shown >0) | |
346 | n_shown--; | |
347 | start = nread + 0x4000; | |
348 | pa = pb; | |
349 | pb = pc; | |
350 | pc = pa; | |
351 | } | |
352 | if(n_errors) | |
d042a097 UB |
353 | fprintf(stderr, "%d blocks wrong from %llu blocks read\n", |
354 | n_errors, (unsigned long long) blocks); | |
40da63b1 | 355 | else |
d042a097 | 356 | fprintf(stderr, "%llu blocks all fine\n", (unsigned long long) blocks); |
40da63b1 UB |
357 | } |
358 | } |