-------------------
copyright : (C) 2009 Micah Dowty 2010 Uwe Bonnes
email : opensource@intra2net.com
+ SPDX-License-Identifier: (LGPL-2.1-only AND MIT)
***************************************************************************/
-
+
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* *
***************************************************************************/
-/* Adapted from
+/* Adapted from
* fastftdi.c - A minimal FTDI FT232H interface for which supports bit-bang
* mode, but focuses on very high-performance support for
* synchronous FIFO mode. Requires libusb-1.0
#include <stdlib.h>
#include <stdio.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+#include <libusb.h>
#include "ftdi.h"
} FTDIStreamState;
/* Handle callbacks
- *
+ *
* With Exit request, free memory and release the transfer
*
- * state->result is only set when some error happens
+ * state->result is only set when some error happens
*/
-static void
+static void LIBUSB_CALL
ftdi_readstream_cb(struct libusb_transfer *transfer)
{
- FTDIStreamState *state = transfer->user_data;
- int packet_size = state->packetsize;
-
- state->activity++;
- if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
- {
- int i;
- uint8_t *ptr = transfer->buffer;
- int length = transfer->actual_length;
- int numPackets = (length + packet_size - 1) / packet_size;
- int res = 0;
-
- for (i = 0; i < numPackets; i++)
- {
- int payloadLen;
- int packetLen = length;
-
- if (packetLen > packet_size)
- packetLen = packet_size;
-
- payloadLen = packetLen - 2;
- state->progress.current.totalBytes += payloadLen;
-
- res = state->callback(ptr + 2, payloadLen,
- NULL, state->userdata);
-
- ptr += packetLen;
- length -= packetLen;
- }
- if (res)
- {
- free(transfer->buffer);
- libusb_free_transfer(transfer);
- }
- else
- {
- transfer->status = -1;
- state->result = libusb_submit_transfer(transfer);
- }
- }
- else
- {
- fprintf(stderr, "unknown status %d\n",transfer->status);
- state->result = LIBUSB_ERROR_IO;
- }
+ FTDIStreamState *state = transfer->user_data;
+ int packet_size = state->packetsize;
+
+ state->activity++;
+ if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
+ {
+ int i;
+ uint8_t *ptr = transfer->buffer;
+ int length = transfer->actual_length;
+ int numPackets = (length + packet_size - 1) / packet_size;
+ int res = 0;
+
+ for (i = 0; i < numPackets; i++)
+ {
+ int payloadLen;
+ int packetLen = length;
+
+ if (packetLen > packet_size)
+ packetLen = packet_size;
+
+ payloadLen = packetLen - 2;
+ state->progress.current.totalBytes += payloadLen;
+
+ res = state->callback(ptr + 2, payloadLen,
+ NULL, state->userdata);
+
+ ptr += packetLen;
+ length -= packetLen;
+ }
+ if (res)
+ {
+ free(transfer->buffer);
+ libusb_free_transfer(transfer);
+ }
+ else
+ {
+ transfer->status = -1;
+ state->result = libusb_submit_transfer(transfer);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "unknown status %d\n",transfer->status);
+ state->result = LIBUSB_ERROR_IO;
+ }
}
/**
static double
TimevalDiff(const struct timeval *a, const struct timeval *b)
{
- return (a->tv_sec - b->tv_sec) + 1e-6 * (a->tv_usec - b->tv_usec);
+ return (a->tv_sec - b->tv_sec) + 1e-6 * (a->tv_usec - b->tv_usec);
}
/**
Streaming reading of data from the device
-
+
Use asynchronous transfers in libusb-1.0 for high-performance
streaming of data from a device interface back to the PC. This
function continuously transfers data until either an error occurs
int
ftdi_readstream(struct ftdi_context *ftdi,
- FTDIStreamCallback *callback, void *userdata,
- int packetsPerTransfer, int numTransfers)
+ FTDIStreamCallback *callback, void *userdata,
+ int packetsPerTransfer, int numTransfers)
{
struct libusb_transfer **transfers;
FTDIStreamState state = { callback, userdata, ftdi->max_packet_size, 1 };
fprintf(stderr,"Device doesn't support synchronous FIFO mode\n");
return 1;
}
-
+
/* We don't know in what state we are, switch to reset*/
if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_RESET) < 0)
{
fprintf(stderr,"Can't reset mode\n");
return 1;
}
-
+
/* Purge anything remaining in the buffers*/
- if (ftdi_usb_purge_buffers(ftdi) < 0)
+ if (ftdi_tcioflush(ftdi) < 0)
{
- fprintf(stderr,"Can't Purge\n");
+ fprintf(stderr,"Can't flush FIFOs & buffers\n");
return 1;
}
/*
* Set up all transfers
*/
-
+
transfers = calloc(numTransfers, sizeof *transfers);
- if (!transfers) {
+ if (!transfers)
+ {
err = LIBUSB_ERROR_NO_MEM;
goto cleanup;
}
-
+
for (xferIndex = 0; xferIndex < numTransfers; xferIndex++)
{
struct libusb_transfer *transfer;
-
+
transfer = libusb_alloc_transfer(0);
transfers[xferIndex] = transfer;
- if (!transfer) {
+ if (!transfer)
+ {
err = LIBUSB_ERROR_NO_MEM;
goto cleanup;
}
-
+
libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->out_ep,
- malloc(bufferSize), bufferSize,
- ftdi_readstream_cb,
+ malloc(bufferSize), bufferSize,
+ ftdi_readstream_cb,
&state, 0);
-
- if (!transfer->buffer) {
+
+ if (!transfer->buffer)
+ {
err = LIBUSB_ERROR_NO_MEM;
goto cleanup;
}
-
+
transfer->status = -1;
err = libusb_submit_transfer(transfer);
if (err)
}
/* Start the transfers only when everything has been set up.
- * Otherwise the transfers start stuttering and the PC not
- * fetching data for several to several ten milliseconds
+ * Otherwise the transfers start stuttering and the PC not
+ * fetching data for several to several ten milliseconds
* and we skip blocks
*/
if (ftdi_set_bitmode(ftdi, 0xff, BITMODE_SYNCFF) < 0)
/*
* Run the transfers, and periodically assess progress.
*/
-
+
gettimeofday(&state.progress.first.time, NULL);
-
+
do
{
FTDIProgressInfo *progress = &state.progress;
const double progressInterval = 1.0;
- struct timeval timeout = { 0, ftdi->usb_read_timeout };
+ struct timeval timeout = { 0, ftdi->usb_read_timeout * 1000};
struct timeval now;
-
+
int err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout);
if (err == LIBUSB_ERROR_INTERRUPTED)
/* restart interrupted events */
- err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout);
+ err = libusb_handle_events_timeout(ftdi->usb_ctx, &timeout);
if (!state.result)
{
state.result = err;
state.result = 1;
else
state.activity = 0;
-
+
// If enough time has elapsed, update the progress
gettimeofday(&now, NULL);
if (TimevalDiff(&now, &progress->current.time) >= progressInterval)
progress->current.time = now;
progress->totalTime = TimevalDiff(&progress->current.time,
&progress->first.time);
-
+
if (progress->prev.totalBytes)
{
// We have enough information to calculate rates
-
+
double currentTime;
-
+
currentTime = TimevalDiff(&progress->current.time,
&progress->prev.time);
-
- progress->totalRate =
- progress->current.totalBytes /progress->totalTime;
- progress->currentRate =
- (progress->current.totalBytes -
- progress->prev.totalBytes) / currentTime;
+
+ progress->totalRate =
+ progress->current.totalBytes /progress->totalTime;
+ progress->currentRate =
+ (progress->current.totalBytes -
+ progress->prev.totalBytes) / currentTime;
}
-
+
state.callback(NULL, 0, progress, state.userdata);
progress->prev = progress->current;
-
+
}
} while (!state.result);
-
+
/*
* Cancel any outstanding transfers, and free memory.
*/
-
- cleanup:
+
+cleanup:
fprintf(stderr, "cleanup\n");
if (transfers)
- free(transfers);
+ free(transfers);
if (err)
return err;
else