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