libftdi1 1.0

- Main Page
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

ftdi_stream.c
Go to the documentation of this file.
1 /***************************************************************************
2 ftdi_stream.c - description
3 -------------------
4 copyright : (C) 2009 Micah Dowty 2010 Uwe Bonnes
5 email : opensource@intra2net.com
6 ***************************************************************************/
7
8 /***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU Lesser General Public License *
12 * version 2.1 as published by the Free Software Foundation; *
13 * *
14 ***************************************************************************/
15
16 /* Adapted from
17 * fastftdi.c - A minimal FTDI FT232H interface for which supports bit-bang
18 * mode, but focuses on very high-performance support for
19 * synchronous FIFO mode. Requires libusb-1.0
20 *
21 * Copyright (C) 2009 Micah Dowty
22 *
23 * Permission is hereby granted, free of charge, to any person obtaining a copy
24 * of this software and associated documentation files (the "Software"), to deal
25 * in the Software without restriction, including without limitation the rights
26 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27 * copies of the Software, and to permit persons to whom the Software is
28 * furnished to do so, subject to the following conditions:
29 *
30 * The above copyright notice and this permission notice shall be included in
31 * all copies or substantial portions of the Software.
32 *
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39 * THE SOFTWARE.
40 */
41
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <libusb.h>
45
46 #include "ftdi.h"
47
48 typedef struct
49 {
50 FTDIStreamCallback *callback;
51 void *userdata;
52 int packetsize;
53 int activity;
54 int result;
55 FTDIProgressInfo progress;
56 } FTDIStreamState;
57
58 /* Handle callbacks
59 *
60 * With Exit request, free memory and release the transfer
61 *
62 * state->result is only set when some error happens
63 */
64 static void
65 ftdi_readstream_cb(struct libusb_transfer *transfer)
66 {
67 FTDIStreamState *state = transfer->user_data;
68 int packet_size = state->packetsize;
69
70 state->activity++;
71 if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
72 {
73 int i;
74 uint8_t *ptr = transfer->buffer;
75 int length = transfer->actual_length;
76 int numPackets = (length + packet_size - 1) / packet_size;
77 int res = 0;
78
79 for (i = 0; i < numPackets; i++)
80 {
81 int payloadLen;
82 int packetLen = length;
83
84 if (packetLen > packet_size)
85 packetLen = packet_size;
86
87 payloadLen = packetLen - 2;
88 state->progress.current.totalBytes += payloadLen;
89
90 res = state->callback(ptr + 2, payloadLen,
91 NULL, state->userdata);
92
93 ptr += packetLen;
94 length -= packetLen;
95 }
96 if (res)
97 {
98 free(transfer->buffer);
99 libusb_free_transfer(transfer);
100 }
101 else
102 {
103 transfer->status = -1;
104 state->result = libusb_submit_transfer(transfer);
105 }
106 }
107 else
108 {
109 fprintf(stderr, "unknown status %d\n",transfer->status);
110 state->result = LIBUSB_ERROR_IO;
111 }
112 }
113
120 static double
121 TimevalDiff(const struct timeval *a, const struct timeval *b)
122 {
123 return (a->tv_sec - b->tv_sec) + 1e-6 * (a->tv_usec - b->tv_usec);
124 }
125
146 int
147 ftdi_readstream(struct ftdi_context *ftdi,
148 FTDIStreamCallback *callback, void *userdata,
149 int packetsPerTransfer, int numTransfers)
150 {
151 struct libusb_transfer **transfers;
152 FTDIStreamState state = { callback, userdata, ftdi->max_packet_size, 1 };
153 int bufferSize = packetsPerTransfer * ftdi->max_packet_size;
154 int xferIndex;
155 int err = 0;
156
157 /* Only FT2232H and FT232H know about the synchronous FIFO Mode*/
158 if ((ftdi->type != TYPE_2232H) && (ftdi->type != TYPE_232H))
159 {
160 fprintf(stderr,"Device doesn't support synchronous FIFO mode\n");
161 return 1;
162 }
163
164 /* We don't know in what state we are, switch to reset*/
165 if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET) < 0)
166 {
167 fprintf(stderr,"Can't reset mode\n");
168 return 1;
169 }
170
171 /* Purge anything remaining in the buffers*/
172 if (ftdi_usb_purge_buffers(ftdi) < 0)
173 {
174 fprintf(stderr,"Can't Purge\n");
175 return 1;
176 }
177
178 /*
179 * Set up all transfers
180 */
181
182 transfers = calloc(numTransfers, sizeof *transfers);
183 if (!transfers) {
184 err = LIBUSB_ERROR_NO_MEM;
185 goto cleanup;
186 }
187
188 for (xferIndex = 0; xferIndex < numTransfers; xferIndex++)
189 {
190 struct libusb_transfer *transfer;
191
192 transfer = libusb_alloc_transfer(0);
193 transfers[xferIndex] = transfer;
194 if (!transfer) {
195 err = LIBUSB_ERROR_NO_MEM;
196 goto cleanup;
197 }
198
199 libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->out_ep,
200 malloc(bufferSize), bufferSize,
201 ftdi_readstream_cb,
202 &state, 0);
203
204 if (!transfer->buffer) {
205 err = LIBUSB_ERROR_NO_MEM;
206 goto cleanup;
207 }
208
209 transfer->status = -1;
210 err = libusb_submit_transfer(transfer);
211 if (err)
212 goto cleanup;
213 }
214
215 /* Start the transfers only when everything has been set up.
216 * Otherwise the transfers start stuttering and the PC not
217 * fetching data for several to several ten milliseconds
218 * and we skip blocks
219 */
220 if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_SYNCFF) < 0)
221 {
222 fprintf(stderr,"Can't set synchronous fifo mode: %s\n",
223 ftdi_get_error_string(ftdi));
224 goto cleanup;
225 }
226
227 /*
228 * Run the transfers, and periodically assess progress.
229 */
230
231 gettimeofday(&state.progress.first.time, NULL);
232
233 do
234 {
235 FTDIProgressInfo *progress = &state.progress;
236 const double progressInterval = 1.0;
237 struct timeval timeout = { 0, ftdi->usb_read_timeout };
238 struct timeval now;
239
240 int err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout);
241 if (err == LIBUSB_ERROR_INTERRUPTED)
242 /* restart interrupted events */
243 err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout);
244 if (!state.result)
245 {
246 state.result = err;
247 }
248 if (state.activity == 0)
249 state.result = 1;
250 else
251 state.activity = 0;
252
253 // If enough time has elapsed, update the progress
254 gettimeofday(&now, NULL);
255 if (TimevalDiff(&now, &progress->current.time) >= progressInterval)
256 {
257 progress->current.time = now;
258 progress->totalTime = TimevalDiff(&progress->current.time,
259 &progress->first.time);
260
261 if (progress->prev.totalBytes)
262 {
263 // We have enough information to calculate rates
264
265 double currentTime;
266
267 currentTime = TimevalDiff(&progress->current.time,
268 &progress->prev.time);
269
270 progress->totalRate =
271 progress->current.totalBytes /progress->totalTime;
272 progress->currentRate =
273 (progress->current.totalBytes -
274 progress->prev.totalBytes) / currentTime;
275 }
276
277 state.callback(NULL, 0, progress, state.userdata);
278 progress->prev = progress->current;
279
280 }
281 } while (!state.result);
282
283 /*
284 * Cancel any outstanding transfers, and free memory.
285 */
286
287 cleanup:
288 fprintf(stderr, "cleanup\n");
289 if (transfers)
290 free(transfers);
291 if (err)
292 return err;
293 else
294 return state.result;
295 }
296