libftdi1  1.3
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 {
51  void *userdata;
53  int activity;
54  int result;
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
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 
int ftdi_readstream(struct ftdi_context *ftdi, FTDIStreamCallback *callback, void *userdata, int packetsPerTransfer, int numTransfers)
Definition: ftdi_stream.c:147
Main context structure for all libftdi functions.
Definition: ftdi.h:219
struct timeval time
Definition: ftdi.h:429
double totalRate
Definition: ftdi.h:438
int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode)
Definition: ftdi.c:2041
enum ftdi_chip_type type
Definition: ftdi.h:233
struct size_and_time prev
Definition: ftdi.h:435
struct size_and_time current
Definition: ftdi.h:436
int out_ep
Definition: ftdi.h:259
FTDIProgressInfo progress
Definition: ftdi_stream.c:55
int() FTDIStreamCallback(uint8_t *buffer, int length, FTDIProgressInfo *progress, void *userdata)
Definition: ftdi.h:442
struct size_and_time first
Definition: ftdi.h:434
Definition: ftdi.h:44
struct libusb_context * usb_ctx
Definition: ftdi.h:223
double currentRate
Definition: ftdi.h:439
int usb_read_timeout
Definition: ftdi.h:227
FTDIStreamCallback * callback
Definition: ftdi_stream.c:50
double totalTime
Definition: ftdi.h:437
struct libusb_device_handle * usb_dev
Definition: ftdi.h:225
unsigned int max_packet_size
Definition: ftdi.h:249
uint64_t totalBytes
Definition: ftdi.h:428
char * ftdi_get_error_string(struct ftdi_context *ftdi)
Definition: ftdi.c:4476
int ftdi_usb_purge_buffers(struct ftdi_context *ftdi)
Definition: ftdi.c:1019