libftdi1: ftdi_stream.c Source File

libftdi1 1.4

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 <sys/time.h>
45 #include <libusb.h>
46
47 #include "ftdi.h"
48
49 typedef struct
50 {
51 FTDIStreamCallback *callback;
52 void *userdata;
53 int packetsize;
54 int activity;
55 int result;
56 FTDIProgressInfo progress;
57 } FTDIStreamState;
58
59 /* Handle callbacks
60 *
61 * With Exit request, free memory and release the transfer
62 *
63 * state->result is only set when some error happens
64 */
65 static void LIBUSB_CALL
66 ftdi_readstream_cb(struct libusb_transfer *transfer)
67 {
68 FTDIStreamState *state = transfer->user_data;
69 int packet_size = state->packetsize;
70
71 state->activity++;
72 if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
73 {
74 int i;
75 uint8_t *ptr = transfer->buffer;
76 int length = transfer->actual_length;
77 int numPackets = (length + packet_size - 1) / packet_size;
78 int res = 0;
79
80 for (i = 0; i < numPackets; i++)
81 {
82 int payloadLen;
83 int packetLen = length;
84
85 if (packetLen > packet_size)
86 packetLen = packet_size;
87
88 payloadLen = packetLen - 2;
89 state->progress.current.totalBytes += payloadLen;
90
91 res = state->callback(ptr + 2, payloadLen,
92 NULL, state->userdata);
93
94 ptr += packetLen;
95 length -= packetLen;
96 }
97 if (res)
98 {
99 free(transfer->buffer);
100 libusb_free_transfer(transfer);
101 }
102 else
103 {
104 transfer->status = -1;
105 state->result = libusb_submit_transfer(transfer);
106 }
107 }
108 else
109 {
110 fprintf(stderr, "unknown status %d\n",transfer->status);
111 state->result = LIBUSB_ERROR_IO;
112 }
113 }
114
121 static double
122 TimevalDiff(const struct timeval *a, const struct timeval *b)
123 {
124 return (a->tv_sec - b->tv_sec) + 1e-6 * (a->tv_usec - b->tv_usec);
125 }
126
147 int
148 ftdi_readstream(struct ftdi_context *ftdi,
149 FTDIStreamCallback *callback, void *userdata,
150 int packetsPerTransfer, int numTransfers)
151 {
152 struct libusb_transfer **transfers;
153 FTDIStreamState state = { callback, userdata, ftdi->max_packet_size, 1 };
154 int bufferSize = packetsPerTransfer * ftdi->max_packet_size;
155 int xferIndex;
156 int err = 0;
157
158 /* Only FT2232H and FT232H know about the synchronous FIFO Mode*/
159 if ((ftdi->type != TYPE_2232H) && (ftdi->type != TYPE_232H))
160 {
161 fprintf(stderr,"Device doesn't support synchronous FIFO mode\n");
162 return 1;
163 }
164
165 /* We don't know in what state we are, switch to reset*/
166 if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET) < 0)
167 {
168 fprintf(stderr,"Can't reset mode\n");
169 return 1;
170 }
171
172 /* Purge anything remaining in the buffers*/
173 if (ftdi_usb_purge_buffers(ftdi) < 0)
174 {
175 fprintf(stderr,"Can't Purge\n");
176 return 1;
177 }
178
179 /*
180 * Set up all transfers
181 */
182
183 transfers = calloc(numTransfers, sizeof *transfers);
184 if (!transfers)
185 {
186 err = LIBUSB_ERROR_NO_MEM;
187 goto cleanup;
188 }
189
190 for (xferIndex = 0; xferIndex < numTransfers; xferIndex++)
191 {
192 struct libusb_transfer *transfer;
193
194 transfer = libusb_alloc_transfer(0);
195 transfers[xferIndex] = transfer;
196 if (!transfer)
197 {
198 err = LIBUSB_ERROR_NO_MEM;
199 goto cleanup;
200 }
201
202 libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->out_ep,
203 malloc(bufferSize), bufferSize,
204 ftdi_readstream_cb,
205 &state, 0);
206
207 if (!transfer->buffer)
208 {
209 err = LIBUSB_ERROR_NO_MEM;
210 goto cleanup;
211 }
212
213 transfer->status = -1;
214 err = libusb_submit_transfer(transfer);
215 if (err)
216 goto cleanup;
217 }
218
219 /* Start the transfers only when everything has been set up.
220 * Otherwise the transfers start stuttering and the PC not
221 * fetching data for several to several ten milliseconds
222 * and we skip blocks
223 */
224 if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_SYNCFF) < 0)
225 {
226 fprintf(stderr,"Can't set synchronous fifo mode: %s\n",
227 ftdi_get_error_string(ftdi));
228 goto cleanup;
229 }
230
231 /*
232 * Run the transfers, and periodically assess progress.
233 */
234
235 gettimeofday(&state.progress.first.time, NULL);
236
237 do
238 {
239 FTDIProgressInfo *progress = &state.progress;
240 const double progressInterval = 1.0;
241 struct timeval timeout = { 0, ftdi->usb_read_timeout * 1000};
242 struct timeval now;
243
244 int err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout);
245 if (err == LIBUSB_ERROR_INTERRUPTED)
246 /* restart interrupted events */
247 err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout);
248 if (!state.result)
249 {
250 state.result = err;
251 }
252 if (state.activity == 0)
253 state.result = 1;
254 else
255 state.activity = 0;
256
257 // If enough time has elapsed, update the progress
258 gettimeofday(&now, NULL);
259 if (TimevalDiff(&now, &progress->current.time) >= progressInterval)
260 {
261 progress->current.time = now;
262 progress->totalTime = TimevalDiff(&progress->current.time,
263 &progress->first.time);
264
265 if (progress->prev.totalBytes)
266 {
267 // We have enough information to calculate rates
268
269 double currentTime;
270
271 currentTime = TimevalDiff(&progress->current.time,
272 &progress->prev.time);
273
274 progress->totalRate =
275 progress->current.totalBytes /progress->totalTime;
276 progress->currentRate =
277 (progress->current.totalBytes -
278 progress->prev.totalBytes) / currentTime;
279 }
280
281 state.callback(NULL, 0, progress, state.userdata);
282 progress->prev = progress->current;
283
284 }
285 } while (!state.result);
286
287 /*
288 * Cancel any outstanding transfers, and free memory.
289 */
290
291 cleanup:
292 fprintf(stderr, "cleanup\n");
293 if (transfers)
294 free(transfers);
295 if (err)
296 return err;
297 else
298 return state.result;
299 }
300
ftdi_readstream
int ftdi_readstream(struct ftdi_context *ftdi, FTDIStreamCallback *callback, void *userdata, int packetsPerTransfer, int numTransfers)
Definition: ftdi_stream.c:148
TYPE_2232H
Definition: ftdi.h:44
FTDIStreamState::result
int result
Definition: ftdi_stream.c:55
FTDIStreamState::activity
int activity
Definition: ftdi_stream.c:54
ftdi_context
Main context structure for all libftdi functions.
Definition: ftdi.h:221
BITMODE_SYNCFF
Definition: ftdi.h:69
size_and_time::time
struct timeval time
Definition: ftdi.h:431
FTDIProgressInfo::totalRate
double totalRate
Definition: ftdi.h:440
ftdi_set_bitmode
int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode)
Definition: ftdi.c:2091
ftdi_context::type
enum ftdi_chip_type type
Definition: ftdi.h:235
FTDIStreamState::userdata
void * userdata
Definition: ftdi_stream.c:52
FTDIProgressInfo::prev
struct size_and_time prev
Definition: ftdi.h:437
FTDIProgressInfo::current
struct size_and_time current
Definition: ftdi.h:438
FTDIStreamState
Definition: ftdi_stream.c:49
ftdi_context::out_ep
int out_ep
Definition: ftdi.h:261
FTDIStreamState::progress
FTDIProgressInfo progress
Definition: ftdi_stream.c:56
FTDIStreamCallback
int() FTDIStreamCallback(uint8_t *buffer, int length, FTDIProgressInfo *progress, void *userdata)
Definition: ftdi.h:444
FTDIProgressInfo::first
struct size_and_time first
Definition: ftdi.h:436
TYPE_232H
Definition: ftdi.h:46
ftdi_context::usb_ctx
struct libusb_context * usb_ctx
Definition: ftdi.h:225
FTDIProgressInfo::currentRate
double currentRate
Definition: ftdi.h:441
ftdi_context::usb_read_timeout
int usb_read_timeout
Definition: ftdi.h:229
FTDIProgressInfo
Definition: ftdi.h:434
ftdi.h
FTDIStreamState::callback
FTDIStreamCallback * callback
Definition: ftdi_stream.c:51
FTDIStreamState::packetsize
int packetsize
Definition: ftdi_stream.c:53
FTDIProgressInfo::totalTime
double totalTime
Definition: ftdi.h:439
ftdi_get_error_string
const char * ftdi_get_error_string(struct ftdi_context *ftdi)
Definition: ftdi.c:4594
ftdi_context::usb_dev
struct libusb_device_handle * usb_dev
Definition: ftdi.h:227
ftdi_context::max_packet_size
unsigned int max_packet_size
Definition: ftdi.h:251
size_and_time::totalBytes
uint64_t totalBytes
Definition: ftdi.h:430
ftdi_usb_purge_buffers
int ftdi_usb_purge_buffers(struct ftdi_context *ftdi)
Definition: ftdi.c:1069
BITMODE_RESET
Definition: ftdi.h:61