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, | |
49 | "Usage: %s [tions...] \n" | |
50 | "Test streaming read from FT2232H\n" | |
51 | "[-P string] only look for product with given string" | |
52 | "[-n] don't check for special block structure" | |
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); | |
64 | } | |
65 | ||
66 | static uint32_t start = 0; | |
67 | static uint32_t offset = 0; | |
68 | static uint32_t blocks = 0; | |
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; | |
86 | fprintf(stderr, "Skip %7d blocks from 0x%08x to 0x%08x at blocks %10d \n", | |
87 | delta, start -0x4000, num, 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 %10d \n", | |
102 | delta, start -0x4000, num, 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 \n", | |
128 | progress->totalTime, | |
129 | progress->current.totalBytes / (1024.0 * 1024.0), | |
130 | progress->currentRate / 1024.0, | |
131 | progress->totalRate / 1024.0); | |
132 | } | |
133 | return exitRequested ? 1 : 0; | |
134 | } | |
135 | ||
136 | int main(int argc, char **argv) | |
137 | { | |
138 | struct ftdi_context ftdic; | |
139 | int err, c; | |
140 | FILE *of = NULL; | |
141 | char const *outfile = 0; | |
142 | outputFile =0; | |
143 | exitRequested = 0; | |
144 | char *descstring = NULL; | |
145 | int option_index; | |
146 | static struct option long_options[] = {{NULL},}; | |
147 | ||
148 | while ((c = getopt_long(argc, argv, "P:n", long_options, &option_index)) !=- 1) | |
149 | switch (c) | |
150 | { | |
151 | case -1: | |
152 | break; | |
153 | case 'P': | |
154 | descstring = optarg; | |
155 | break; | |
156 | case 'n': | |
157 | check = 0; | |
158 | break; | |
159 | default: | |
160 | usage(argv[0]); | |
161 | } | |
162 | ||
163 | if (optind == argc - 1) | |
164 | { | |
165 | // Exactly one extra argument- a dump file | |
166 | outfile = argv[optind]; | |
167 | } | |
168 | else if (optind < argc) | |
169 | { | |
170 | // Too many extra args | |
171 | usage(argv[0]); | |
172 | } | |
173 | ||
174 | if (ftdi_init(&ftdic) < 0) | |
175 | { | |
176 | fprintf(stderr, "ftdi_init failed\n"); | |
177 | return EXIT_FAILURE; | |
178 | } | |
179 | ||
180 | if (ftdi_set_interface(&ftdic, INTERFACE_A) < 0) | |
181 | { | |
182 | fprintf(stderr, "ftdi_set_interface failed\n"); | |
183 | return EXIT_FAILURE; | |
184 | } | |
185 | ||
186 | if (ftdi_usb_open_desc(&ftdic, 0x0403, 0x6010, descstring, NULL) < 0) | |
187 | { | |
188 | fprintf(stderr,"Can't open ftdi device: %s\n",ftdi_get_error_string(&ftdic)); | |
189 | return EXIT_FAILURE; | |
190 | } | |
191 | ||
192 | /* A timeout value of 1 results in may skipped blocks */ | |
193 | if(ftdi_set_latency_timer(&ftdic, 2)) | |
194 | { | |
195 | fprintf(stderr,"Can't set latency\n",ftdi_get_error_string(&ftdic)); | |
196 | return EXIT_FAILURE; | |
197 | } | |
198 | ||
199 | /* if(ftdi_usb_purge_rx_buffer(&ftdic) < 0) | |
200 | { | |
201 | fprintf(stderr,"Can't rx purge\n",ftdi_get_error_string(&ftdic)); | |
202 | return EXIT_FAILURE; | |
203 | }*/ | |
204 | if (outfile) | |
205 | if ((of = fopen(outfile,"w+")) == 0) | |
206 | fprintf(stderr,"Can't open logfile %s, Error %s\n", outfile, strerror(errno)); | |
207 | if (of) | |
208 | if (setvbuf(of, NULL, _IOFBF , 1<<16) == 0) | |
209 | outputFile = of; | |
210 | signal(SIGINT, sigintHandler); | |
211 | ||
212 | err = ftdi_readstream(&ftdic, readCallback, NULL, 8, 256); | |
213 | if (err < 0 && !exitRequested) | |
214 | exit(1); | |
215 | ||
216 | if (outputFile) { | |
217 | fclose(outputFile); | |
218 | outputFile = NULL; | |
219 | } | |
220 | fprintf(stderr, "Capture ended.\n"); | |
221 | ||
222 | if (ftdi_set_bitmode(&ftdic, 0xff, BITMODE_RESET) < 0) | |
223 | { | |
224 | fprintf(stderr,"Can't set synchronous fifo mode\n",ftdi_get_error_string(&ftdic)); | |
225 | return EXIT_FAILURE; | |
226 | } | |
227 | ftdi_usb_close(&ftdic); | |
228 | ftdi_deinit(&ftdic); | |
229 | signal(SIGINT, SIG_DFL); | |
230 | if (check && outfile) | |
231 | { | |
232 | if ((outputFile = fopen(outfile,"r")) == 0) | |
233 | { | |
234 | fprintf(stderr,"Can't open logfile %s, Error %s\n", outfile, strerror(errno)); | |
235 | return EXIT_FAILURE; | |
236 | } | |
237 | check_outfile(descstring); | |
238 | fclose(outputFile); | |
239 | } | |
240 | else if (check) | |
241 | fprintf(stderr,"%d errors of %d blocks (%Le), %d (%Le) blocks skipped\n", | |
242 | n_err, blocks, (long double)n_err/(long double) blocks, | |
243 | skips, (long double)skips/(long double) blocks); | |
244 | exit (0); | |
245 | } | |
246 | ||
247 | void check_outfile(char *descstring) | |
248 | { | |
249 | if(strcmp(descstring,"FT2232HTEST") == 0) | |
250 | { | |
251 | char buf0[1024]; | |
252 | char buf1[1024]; | |
253 | char bufr[1024]; | |
254 | char *pa, *pb, *pc; | |
255 | unsigned int num_lines = 0, line_num = 1; | |
256 | int err_count = 0; | |
257 | unsigned int num_start, num_end; | |
258 | ||
259 | unsigned int block[4]; | |
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; | |
316 | int expect = 1; | |
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 | } | |
324 | while(fread(pb, sizeof(uint32_t), 4,outputFile) != 0) | |
325 | { | |
326 | blocks++; | |
327 | nread = pa[0]; | |
328 | if(start>0 && (nread != start)) | |
329 | { | |
330 | if(n_shown < 30) | |
331 | { | |
332 | fprintf(stderr, "Skip %7d blocks from 0x%08x to 0x%08x at blocks %10d \n", | |
333 | (nread-start)/0x4000, start -0x4000, nread, blocks); | |
334 | n_shown ++; | |
335 | } | |
336 | n_errors++; | |
337 | } | |
338 | else if (n_shown >0) | |
339 | n_shown--; | |
340 | start = nread + 0x4000; | |
341 | pa = pb; | |
342 | pb = pc; | |
343 | pc = pa; | |
344 | } | |
345 | if(n_errors) | |
346 | fprintf(stderr, "%d blocks wrong from %d blocks read\n", | |
347 | n_errors, blocks); | |
348 | else | |
349 | fprintf(stderr, "%d blocks all fine\n",blocks); | |
350 | } | |
351 | } |