Intra2net AG

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 
52 typedef struct
53 {
54  FTDIStreamCallback *callback;
55  void *userdata;
56  int packetsize;
57  int activity;
58  int result;
59  FTDIProgressInfo progress;
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  */
68 static void LIBUSB_CALL
69 ftdi_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 
124 static double
125 TimevalDiff(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 
150 int
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",
230  ftdi_get_error_string(ftdi));
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 
294 cleanup:
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 
FTDIProgressInfo
Definition: ftdi.h:484
FTDIProgressInfo::totalRate
double totalRate
Definition: ftdi.h:490
FTDIStreamState::userdata
void * userdata
Definition: ftdi_stream.c:67
ftdi.h
FTDIStreamState::progress
FTDIProgressInfo progress
Definition: ftdi_stream.c:71
FTDIStreamState::activity
int activity
Definition: ftdi_stream.c:69
FTDIProgressInfo::prev
struct size_and_time prev
Definition: ftdi.h:487
size_and_time::totalBytes
uint64_t totalBytes
Definition: ftdi.h:480
ftdi_tcioflush
int ftdi_tcioflush(struct ftdi_context *ftdi)
Definition: ftdi.c:1137
ftdi_context::type
enum ftdi_chip_type type
Definition: ftdi.h:285
ftdi_context::out_ep
int out_ep
Definition: ftdi.h:311
FTDIStreamState::result
int result
Definition: ftdi_stream.c:70
FTDIProgressInfo::currentRate
double currentRate
Definition: ftdi.h:491
TYPE_2232H
@ TYPE_2232H
Definition: ftdi.h:52
ftdi_set_bitmode
int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode)
Definition: ftdi.c:2191
FTDIProgressInfo::current
struct size_and_time current
Definition: ftdi.h:488
FTDIProgressInfo::first
struct size_and_time first
Definition: ftdi.h:486
ftdi_context::usb_ctx
struct libusb_context * usb_ctx
Definition: ftdi.h:275
TYPE_232H
@ TYPE_232H
Definition: ftdi.h:54
FTDIStreamCallback
int() FTDIStreamCallback(uint8_t *buffer, int length, FTDIProgressInfo *progress, void *userdata)
Definition: ftdi.h:494
FTDIProgressInfo::totalTime
double totalTime
Definition: ftdi.h:489
ftdi_get_error_string
const char * ftdi_get_error_string(struct ftdi_context *ftdi)
Definition: ftdi.c:4731
ftdi_context::usb_dev
struct libusb_device_handle * usb_dev
Definition: ftdi.h:277
FTDIStreamState::packetsize
int packetsize
Definition: ftdi_stream.c:68
FTDIStreamState::callback
FTDIStreamCallback * callback
Definition: ftdi_stream.c:66
FTDIStreamState
Definition: ftdi_stream.c:52
BITMODE_RESET
@ BITMODE_RESET
Definition: ftdi.h:69
ftdi_context
Main context structure for all libftdi functions.
Definition: ftdi.h:271
size_and_time::time
struct timeval time
Definition: ftdi.h:481
ftdi_readstream
int ftdi_readstream(struct ftdi_context *ftdi, FTDIStreamCallback *callback, void *userdata, int packetsPerTransfer, int numTransfers)
Definition: ftdi_stream.c:151
ftdi_context::max_packet_size
unsigned int max_packet_size
Definition: ftdi.h:301
BITMODE_SYNCFF
@ BITMODE_SYNCFF
Definition: ftdi.h:77
ftdi_context::usb_read_timeout
int usb_read_timeout
Definition: ftdi.h:279
© Intra2net AG 2024 | Legal | Contact