libftdi1 1.3

- 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 LIBUSB_CALL
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 {
185 err = LIBUSB_ERROR_NO_MEM;
186 goto cleanup;
187 }
188
189 for (xferIndex = 0; xferIndex < numTransfers; xferIndex++)
190 {
191 struct libusb_transfer *transfer;
192
193 transfer = libusb_alloc_transfer(0);
194 transfers[xferIndex] = transfer;
195 if (!transfer)
196 {
197 err = LIBUSB_ERROR_NO_MEM;
198 goto cleanup;
199 }
200
201 libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->out_ep,
202 malloc(bufferSize), bufferSize,
203 ftdi_readstream_cb,
204 &state, 0);
205
206 if (!transfer->buffer)
207 {
208 err = LIBUSB_ERROR_NO_MEM;
209 goto cleanup;
210 }
211
212 transfer->status = -1;
213 err = libusb_submit_transfer(transfer);
214 if (err)
215 goto cleanup;
216 }
217
218 /* Start the transfers only when everything has been set up.
219 * Otherwise the transfers start stuttering and the PC not
220 * fetching data for several to several ten milliseconds
221 * and we skip blocks
222 */
223 if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_SYNCFF) < 0)
224 {
225 fprintf(stderr,"Can't set synchronous fifo mode: %s\n",
226 ftdi_get_error_string(ftdi));
227 goto cleanup;
228 }
229
230 /*
231 * Run the transfers, and periodically assess progress.
232 */
233
234 gettimeofday(&state.progress.first.time, NULL);
235
236 do
237 {
238 FTDIProgressInfo *progress = &state.progress;
239 const double progressInterval = 1.0;
240 struct timeval timeout = { 0, ftdi->usb_read_timeout * 1000};
241 struct timeval now;
242
243 int err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout);
244 if (err == LIBUSB_ERROR_INTERRUPTED)
245 /* restart interrupted events */
246 err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout);
247 if (!state.result)
248 {
249 state.result = err;
250 }
251 if (state.activity == 0)
252 state.result = 1;
253 else
254 state.activity = 0;
255
256 // If enough time has elapsed, update the progress
257 gettimeofday(&now, NULL);
258 if (TimevalDiff(&now, &progress->current.time) >= progressInterval)
259 {
260 progress->current.time = now;
261 progress->totalTime = TimevalDiff(&progress->current.time,
262 &progress->first.time);
263
264 if (progress->prev.totalBytes)
265 {
266 // We have enough information to calculate rates
267
268 double currentTime;
269
270 currentTime = TimevalDiff(&progress->current.time,
271 &progress->prev.time);
272
273 progress->totalRate =
274 progress->current.totalBytes /progress->totalTime;
275 progress->currentRate =
276 (progress->current.totalBytes -
277 progress->prev.totalBytes) / currentTime;
278 }
279
280 state.callback(NULL, 0, progress, state.userdata);
281 progress->prev = progress->current;
282
283 }
284 } while (!state.result);
285
286 /*
287 * Cancel any outstanding transfers, and free memory.
288 */
289
290 cleanup:
291 fprintf(stderr, "cleanup\n");
292 if (transfers)
293 free(transfers);
294 if (err)
295 return err;
296 else
297 return state.result;
298 }
299
ftdi_readstream
int ftdi_readstream(struct ftdi_context *ftdi, FTDIStreamCallback *callback, void *userdata, int packetsPerTransfer, int numTransfers)
Definition: ftdi_stream.c:147
TYPE_2232H
Definition: ftdi.h:42
FTDIStreamState::result
int result
Definition: ftdi_stream.c:54
FTDIStreamState::activity
int activity
Definition: ftdi_stream.c:53
ftdi_context
Main context structure for all libftdi functions.
Definition: ftdi.h:219
BITMODE_SYNCFF
Definition: ftdi.h:67
size_and_time::time
struct timeval time
Definition: ftdi.h:429
FTDIProgressInfo::totalRate
double totalRate
Definition: ftdi.h:438
ftdi_set_bitmode
int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode)
Definition: ftdi.c:2041
ftdi_context::type
enum ftdi_chip_type type
Definition: ftdi.h:233
FTDIStreamCallback
int( FTDIStreamCallback)(uint8_t *buffer, int length, FTDIProgressInfo *progress, void *userdata)
Definition: ftdi.h:442
FTDIStreamState::userdata
void * userdata
Definition: ftdi_stream.c:51
FTDIProgressInfo::prev
struct size_and_time prev
Definition: ftdi.h:435
FTDIProgressInfo::current
struct size_and_time current
Definition: ftdi.h:436
FTDIStreamState
Definition: ftdi_stream.c:48
ftdi_context::out_ep
int out_ep
Definition: ftdi.h:259
FTDIStreamState::progress
FTDIProgressInfo progress
Definition: ftdi_stream.c:55
FTDIProgressInfo::first
struct size_and_time first
Definition: ftdi.h:434
TYPE_232H
Definition: ftdi.h:44
ftdi_context::usb_ctx
struct libusb_context * usb_ctx
Definition: ftdi.h:223
FTDIProgressInfo::currentRate
double currentRate
Definition: ftdi.h:439
ftdi_context::usb_read_timeout
int usb_read_timeout
Definition: ftdi.h:227
FTDIProgressInfo
Definition: ftdi.h:432
ftdi.h
FTDIStreamState::callback
FTDIStreamCallback * callback
Definition: ftdi_stream.c:50
FTDIStreamState::packetsize
int packetsize
Definition: ftdi_stream.c:52
FTDIProgressInfo::totalTime
double totalTime
Definition: ftdi.h:437
ftdi_context::usb_dev
struct libusb_device_handle * usb_dev
Definition: ftdi.h:225
ftdi_context::max_packet_size
unsigned int max_packet_size
Definition: ftdi.h:249
size_and_time::totalBytes
uint64_t totalBytes
Definition: ftdi.h:428
ftdi_get_error_string
char * ftdi_get_error_string(struct ftdi_context *ftdi)
Definition: ftdi.c:4476
ftdi_usb_purge_buffers
int ftdi_usb_purge_buffers(struct ftdi_context *ftdi)
Definition: ftdi.c:1019
BITMODE_RESET
Definition: ftdi.h:59