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