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 {
52  void *userdata;
54  int activity;
55  int result;
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
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 
int ftdi_readstream(struct ftdi_context *ftdi, FTDIStreamCallback *callback, void *userdata, int packetsPerTransfer, int numTransfers)
Definition: ftdi_stream.c:148
Main context structure for all libftdi functions.
Definition: ftdi.h:221
struct timeval time
Definition: ftdi.h:431
double totalRate
Definition: ftdi.h:440
int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode)
Definition: ftdi.c:2091
enum ftdi_chip_type type
Definition: ftdi.h:235
struct size_and_time prev
Definition: ftdi.h:437
struct size_and_time current
Definition: ftdi.h:438
int out_ep
Definition: ftdi.h:261
FTDIProgressInfo progress
Definition: ftdi_stream.c:56
int() FTDIStreamCallback(uint8_t *buffer, int length, FTDIProgressInfo *progress, void *userdata)
Definition: ftdi.h:444
struct size_and_time first
Definition: ftdi.h:436
Definition: ftdi.h:46
struct libusb_context * usb_ctx
Definition: ftdi.h:225
double currentRate
Definition: ftdi.h:441
int usb_read_timeout
Definition: ftdi.h:229
FTDIStreamCallback * callback
Definition: ftdi_stream.c:51
double totalTime
Definition: ftdi.h:439
const char * ftdi_get_error_string(struct ftdi_context *ftdi)
Definition: ftdi.c:4594
struct libusb_device_handle * usb_dev
Definition: ftdi.h:227
unsigned int max_packet_size
Definition: ftdi.h:251
uint64_t totalBytes
Definition: ftdi.h:430
int ftdi_usb_purge_buffers(struct ftdi_context *ftdi)
Definition: ftdi.c:1069