1 /* baud_test.c
2  *
3  * test setting the baudrate and compare it with the expected runtime
4  *
5  * options:
6  *  -p <devicestring> defaults to "i:0x0403:0x6001" (this is the first FT232R with default id)
7  *       d:<devicenode> path of bus and device-node (e.g. "003/001") within usb device tree (usually at /proc/bus/usb/)
8  *       i:<vendor>:<product> first device with given vendor and product id,
9  *                            ids can be decimal, octal (preceded by "0") or hex (preceded by "0x")
10  *       i:<vendor>:<product>:<index> as above with index being the number of the device (starting with 0)
11  *                            if there are more than one
12  *       s:<vendor>:<product>:<serial> first device with given vendor id, product id and serial string
13  *  -d <datasize to send in bytes>
14  *  -b <baudrate> (divides by 16 if bitbang as taken from the ftdi datasheets)
15  *  -m <mode to use> r: serial a: async bitbang s:sync bitbang
16  *  -c <chunksize>
17  *
18  * (C) 2009 by Gerd v. Egidy <gerd.von.egidy@intra2net.com>
19  *
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License as published by
22  * the Free Software Foundation; either version 2 of the License, or
23  * (at your option) any later version.
24 
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  * GNU General Public License for more details.
29  *
30  */
31 
32 #include <sys/time.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <ftdi.h>
37 
get_prec_time()38 double get_prec_time()
39 {
40     struct timeval tv;
41     double res;
42 
43     gettimeofday(&tv,NULL);
44 
45     res=tv.tv_sec;
46     res+=((double)tv.tv_usec/1000000);
47 
48     return res;
49 }
50 
main(int argc,char ** argv)51 int main(int argc, char **argv)
52 {
53     struct ftdi_context *ftdi;
54     int i, t;
55     unsigned char *txbuf;
56     unsigned char *rxbuf;
57     double start, duration, plan;
58     int retval= 0;
59 
60     // default values
61     int baud=9600;
62     int set_baud;
63     int datasize=100000;
64 
65     char default_devicedesc[] = "i:0x0403:0x6001";
66     char *devicedesc=default_devicedesc;
67     int txchunksize=256;
68     enum ftdi_mpsse_mode test_mode=BITMODE_BITBANG;
69 
70     while ((t = getopt (argc, argv, "b:d:p:m:c:")) != -1)
71     {
72         switch (t)
73         {
74             case 'd':
75                 datasize = atoi (optarg);
76                 break;
77             case 'm':
78                 switch (*optarg)
79                 {
80                     case 'r':
81                         // serial
82                         test_mode=BITMODE_RESET;
83                         break;
84                     case 'a':
85                         // async
86                         test_mode=BITMODE_BITBANG;
87                         break;
88                     case 's':
89                         // sync
90                         test_mode=BITMODE_SYNCBB;
91                         break;
92                 }
93                 break;
94             case 'b':
95                 baud = atoi (optarg);
96                 break;
97             case 'p':
98                 devicedesc=optarg;
99                 break;
100             case 'c':
101                 txchunksize = atoi (optarg);
102                 break;
103         }
104     }
105 
106     txbuf=malloc(txchunksize);
107     rxbuf=malloc(txchunksize);
108     if (txbuf == NULL || rxbuf == NULL)
109     {
110         fprintf(stderr, "can't malloc\n");
111         return EXIT_FAILURE;
112     }
113 
114     if ((ftdi = ftdi_new()) == 0)
115     {
116         fprintf(stderr, "ftdi_new failed\n");
117         retval = EXIT_FAILURE;
118         goto done;
119     }
120 
121     if (ftdi_usb_open_string(ftdi, devicedesc) < 0)
122     {
123         fprintf(stderr,"Can't open ftdi device: %s\n",ftdi_get_error_string(ftdi));
124         retval = EXIT_FAILURE;
125         goto do_deinit;
126     }
127 
128     set_baud=baud;
129     if (test_mode!=BITMODE_RESET)
130     {
131         // we do bitbang, so real baudrate / 16
132         set_baud=baud/16;
133     }
134 
135     ftdi_set_baudrate(ftdi,set_baud);
136     printf("real baudrate used: %d\n",(test_mode==BITMODE_RESET) ? ftdi->baudrate : ftdi->baudrate*16);
137 
138     if (ftdi_set_bitmode(ftdi, 0xFF,test_mode) < 0)
139     {
140         fprintf(stderr,"Can't set mode: %s\n",ftdi_get_error_string(ftdi));
141         retval = EXIT_FAILURE;
142         goto do_close;
143     }
144 
145     if (test_mode==BITMODE_RESET)
146     {
147         // serial 8N1: 8 data bits, 1 startbit, 1 stopbit
148         plan=((double)(datasize*10))/baud;
149     }
150     else
151     {
152         // bitbang means 8 bits at once
153         plan=((double)datasize)/baud;
154     }
155 
156     printf("this test should take %.2f seconds\n",plan);
157 
158     // prepare data to send: 0 and 1 bits alternating (except for serial start/stopbit):
159     // maybe someone wants to look at this with a scope or logic analyzer
160     for (i=0; i<txchunksize; i++)
161     {
162         if (test_mode==BITMODE_RESET)
163             txbuf[i]=0xAA;
164         else
165             txbuf[i]=(i%2) ? 0xff : 0;
166     }
167 
168     if (ftdi_write_data_set_chunksize(ftdi, txchunksize) < 0 ||
169             ftdi_read_data_set_chunksize(ftdi, txchunksize) < 0)
170     {
171         fprintf(stderr,"Can't set chunksize: %s\n",ftdi_get_error_string(ftdi));
172         retval = EXIT_FAILURE;
173         goto do_close;
174     }
175 
176     if (test_mode==BITMODE_SYNCBB)
177     {
178         // completely clear the receive buffer before beginning
179         while (ftdi_read_data(ftdi, rxbuf, txchunksize)>0);
180     }
181 
182     start=get_prec_time();
183 
184     // don't wait for more data to arrive, take what we get and keep on sending
185     // yes, we really would like to have libusb 1.0+ with async read/write...
186     ftdi->usb_read_timeout=1;
187 
188     i=0;
189     while (i < datasize)
190     {
191         int sendsize=txchunksize;
192         if (i+sendsize > datasize)
193             sendsize=datasize-i;
194 
195         if ((sendsize=ftdi_write_data(ftdi, txbuf, sendsize)) < 0)
196         {
197             fprintf(stderr,"write failed at %d: %s\n",
198                     i, ftdi_get_error_string(ftdi));
199             retval = EXIT_FAILURE;
200             goto do_close;
201         }
202 
203         i+=sendsize;
204 
205         if (test_mode==BITMODE_SYNCBB)
206         {
207             // read the same amount of data as sent
208             ftdi_read_data(ftdi, rxbuf, sendsize);
209         }
210     }
211 
212     duration=get_prec_time()-start;
213     printf("and took %.4f seconds, this is %.0f baud or factor %.3f\n",duration,(plan*baud)/duration,plan/duration);
214 do_close:
215     ftdi_usb_close(ftdi);
216 do_deinit:
217     ftdi_free(ftdi);
218 done:
219     if(rxbuf)
220         free(rxbuf);
221     if(txbuf)
222         free(txbuf);
223     exit (retval);
224 }
225