Hi Uwe,

  I would love to see the verilog code it sounds interesting.

Regards,
 George

On Tue, Apr 27, 2010 at 1:18 PM, Uwe Bonnes <
[email protected]> wrote:

> Hello,
>
> appended patch adds a streaming read for libftdi-1. It's mostly taken from
> Micah Dowty <[email protected]> fastftdi.c|h.
>
> I have a testboard with an FT2232H connected to an Spartan-3, with the
> Spartan programmed to start sending some sequence when synchronous fifo
> mode
> is switched on. I can read about 36 MiByte/s with that setup. If the
> verilog
> code is of interest, I can provide to.
>
> The patch adds libusb_context to the ftdi_context structure, but otherwise
> touches none of the existing code. libusb_context is needed for handling
> libusb_handle_events_timeout().
>
> Feedback welcome.
> --
> Uwe Bonnes                [email protected]
>
> Institut fuer Kernphysik  Schlossgartenstrasse 9  64289 Darmstadt
> --------- Tel. 06151 162516 -------- Fax. 06151 164321 ----------
> From cfdcda29202875a8327799ef992a160d883569d5 Mon Sep 17 00:00:00 2001
> From: Uwe Bonnes <[email protected]>
> Date: Tue, 27 Apr 2010 19:06:59 +0200
> Subject: Add streaming read from  Micah Dowty <[email protected]>
> fastftdi.c
>
> ---
>  CMakeLists.txt          |    1 +
>  examples/CMakeLists.txt |    2 +
>  examples/stream_test.c  |  168 ++++++++++++++++++++++++++++++++++++
>  src/ftdi.c              |  217
> ++++++++++++++++++++++++++++++++++++++++++++++-
>  src/ftdi.h              |   20 +++++
>  5 files changed, 407 insertions(+), 1 deletions(-)
>  create mode 100644 examples/stream_test.c
>
> diff --git a/CMakeLists.txt b/CMakeLists.txt
> index 3e6c96d..b561418 100644
> --- a/CMakeLists.txt
> +++ b/CMakeLists.txt
> @@ -15,6 +15,7 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "")
>    set(CMAKE_BUILD_TYPE     Debug)
>  endif("${CMAKE_BUILD_TYPE}" STREQUAL "")
>  set(CMAKE_COLOR_MAKEFILE ON)
> +set(CMAKE_CXX_FLAGS "-g -Wall")
>  cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
>
>  # Debug build
> diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
> index d2aeecb..7b702c2 100644
> --- a/examples/CMakeLists.txt
> +++ b/examples/CMakeLists.txt
> @@ -20,6 +20,7 @@ if (EXAMPLES)
>     add_executable(find_all find_all.c)
>     add_executable(serial_read serial_read.c)
>     add_executable(baud_test baud_test.c)
> +    add_executable(stream_test stream_test.c)
>
>     # Linkage
>     target_link_libraries(simple ftdi)
> @@ -30,6 +31,7 @@ if (EXAMPLES)
>     target_link_libraries(find_all ftdi)
>     target_link_libraries(serial_read ftdi)
>     target_link_libraries(baud_test ftdi)
> +    target_link_libraries(stream_test ftdi)
>
>     # libftdi++ examples
>     if(FTDI_BUILD_CPP)
> diff --git a/examples/stream_test.c b/examples/stream_test.c
> new file mode 100644
> index 0000000..33c26e2
> --- /dev/null
> +++ b/examples/stream_test.c
> @@ -0,0 +1,168 @@
> +/* stream_test.c
> + *
> + * Test reading  from FT2232H in synchronous FIFO mode.
> + *
> + * The FT2232H must supply data due to an appropriate circuit
> + *
> + * After start, data will be read in streaming until the program is
> aborted
> + * Progess information wil be prointed out
> + * If a filename is given on the command line, the data read will be
> + * written to that file
> + *
> + */
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <getopt.h>
> +#include <signal.h>
> +#include <errno.h>
> +#include <ftdi.h>
> +
> +static FILE *outputFile;
> +
> +static int exitRequested;
> +/*
> + * sigintHandler --
> + *
> + *    SIGINT handler, so we can gracefully exit when the user hits ctrl-C.
> + */
> +
> +static void
> +sigintHandler(int signum)
> +{
> +   exitRequested = 1;
> +}
> +
> +static void
> +usage(const char *argv0)
> +{
> +   fprintf(stderr,
> +           "Usage: %s [options...] \n"
> +           "Test streaming read from FT2232H\n"
> +           "\n"
> +           "If some filename is given, write data read to that file\n"
> +           "Progess information is printed each second\n"
> +           "Abort with ^C\n"
> +           "\n"
> +           "Options:\n"
> +           "\n"
> +           "Copyright (C) 2009 Micah Dowty <[email protected]>\n",
> +           "Adapted for use with libftdi (C) 2010 Uwe Bonnes <
> [email protected]>\n",
> +           argv0);
> +   exit(1);
> +}
> +
> +static int
> +readCallback(uint8_t *buffer, int length, FTDIProgressInfo *progress, void
> *userdata)
> +{
> +   if (length) {
> +      if (outputFile) {
> +         if (fwrite(buffer, length, 1, outputFile) != 1) {
> +            perror("Write error");
> +            return 1;
> +         }
> +      }
> +   }
> +   if (progress) {
> +     fprintf(stderr, "%10.02fs total time %9.3f MiB captured %7.1f kB/s
> curr rate %7.1f kB/s totalrate \n",
> +             progress->totalTime,
> +             progress->current.totalBytes / (1024.0 * 1024.0),
> +             progress->currentRate / 1024.0,
> +             progress->totalRate / 1024.0);
> +   }
> +   return exitRequested ? 1 : 0;
> +}
> +
> +int main(int argc, char **argv)
> +{
> +   struct ftdi_context ftdic;
> +   int err, c;
> +   char const *outfile  = 0;
> +   outputFile =0;
> +
> +   exitRequested = 0;
> +
> +   while (1) {
> +      int option_index;
> +      static struct option long_options[] = {
> +          {NULL},
> +      };
> +
> +      c = getopt_long(argc, argv, "", long_options, &option_index);
> +      if (c == -1)
> +         break;
> +
> +      switch (c) {
> +
> +      default:
> +         usage(argv[0]);
> +      }
> +   }
> +
> +   if (optind == argc - 1) {
> +      // Exactly one extra argument- a trace file
> +      outfile = argv[optind];
> +   } else if (optind < argc) {
> +      // Too many extra args
> +      usage(argv[0]);
> +   }
> +
> +    if (ftdi_init(&ftdic) < 0)
> +    {
> +        fprintf(stderr, "ftdi_init failed\n");
> +        return EXIT_FAILURE;
> +    }
> +
> +    if (ftdi_set_interface(&ftdic, INTERFACE_A) < 0)
> +    {
> +        fprintf(stderr, "ftdi_set_interface failed\n");
> +        return EXIT_FAILURE;
> +    }
> +
> +    if (ftdi_usb_open_desc(&ftdic, 0x0403, 0x6010, NULL, NULL) < 0)
> +    {
> +        fprintf(stderr,"Can't open ftdi device:
> %s\n",ftdi_get_error_string(&ftdic));
> +        return EXIT_FAILURE;
> +    }
> +
> +    if(ftdi_usb_purge_buffers(&ftdic) < 0)
> +    {
> +        fprintf(stderr,"Can't purge\n",ftdi_get_error_string(&ftdic));
> +        return EXIT_FAILURE;
> +    }
> +
> +    usleep(10000);
> +    if (ftdi_set_bitmode(&ftdic,  0xff, BITMODE_SYNCFF) < 0)
> +    {
> +        fprintf(stderr,"Can't set synchronous fifo
> mode\n",ftdi_get_error_string(&ftdic));
> +        return EXIT_FAILURE;
> +    }
> +
> +    if (outfile)
> +      if ((outputFile = fopen(outfile,"w+")) == 0)
> +        fprintf(stderr,"Can't open logfile %s, Error %s\n", outfile,
> strerror(errno));
> +
> +    signal(SIGINT, sigintHandler);
> +
> +    err = ftdi_readstream(&ftdic, readCallback, NULL, 8, 256);
> +    if (err < 0 && !exitRequested)
> +        exit(1);
> +
> +    if (outputFile) {
> +      fclose(outputFile);
> +      outputFile = NULL;
> +    }
> +    fprintf(stderr, "Capture ended.\n");
> +
> +    if (ftdi_set_bitmode(&ftdic,  0xff, BITMODE_RESET) < 0)
> +      {
> +        fprintf(stderr,"Can't set synchronous fifo
> mode\n",ftdi_get_error_string(&ftdic));
> +        return EXIT_FAILURE;
> +      }
> +    ftdi_usb_close(&ftdic);
> +    ftdi_deinit(&ftdic);
> +    exit (0);
> +}
> +
> +
> +
> diff --git a/src/ftdi.c b/src/ftdi.c
> index 5c25abd..8c6dab6 100644
> --- a/src/ftdi.c
> +++ b/src/ftdi.c
> @@ -236,7 +236,7 @@ int ftdi_usb_find_all(struct ftdi_context *ftdi, struct
> ftdi_device_list **devli
>     int count = 0;
>     int i = 0;
>
> -    if (libusb_init(NULL) < 0)
> +    if (libusb_init(&ftdi->libusb) < 0)
>         ftdi_error_return(-4, "libusb_init() failed");
>
>     if (libusb_get_device_list(NULL, &devs) < 0)
> @@ -477,6 +477,11 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi,
> libusb_device *dev)
>     // set configuration (needed especially for windows)
>     // tolerate EBUSY: one device with one configuration, but two
> interfaces
>     //    and libftdi sessions to both interfaces (e.g. FT2232)
> +        if (libusb_set_configuration(ftdi->usb_dev, cfg0) < 0)
> +        {
> +            ftdi_usb_close_internal (ftdi);
> +            ftdi_error_return(-3, "unable to set usb configuration. Make
> sure ftdi_sio is unloaded!");
> +        }
>     if (desc.bNumConfigurations > 0 && cfg != cfg0)
>     {
>         if (libusb_set_configuration(ftdi->usb_dev, cfg0) < 0)
> @@ -1736,6 +1741,216 @@ int ftdi_read_data_get_chunksize(struct
> ftdi_context *ftdi, unsigned int *chunks
>     return 0;
>  }
>
> +typedef struct {
> +   FTDIStreamCallback *callback;
> +   void *userdata;
> +   int packetsize;
> +   int result;
> +   FTDIProgressInfo progress;
> +} FTDIStreamState;
> +
> +static void
> +ftdi_readstream_cb(struct libusb_transfer *transfer)
> +{
> +   FTDIStreamState *state = transfer->user_data;
> +   int packet_size = state->packetsize;
> +
> +   if (state->result == 0) {
> +      if (transfer->status == LIBUSB_TRANSFER_COMPLETED
> +          || transfer->status == LIBUSB_TRANSFER_CANCELLED) {
> +
> +         int i;
> +         uint8_t *ptr = transfer->buffer;
> +         int length = transfer->actual_length;
> +         int numPackets = (length + packet_size - 1) / packet_size;
> +
> +         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;
> +
> +            state->result = state->callback(ptr + 2, payloadLen,
> +                                            NULL, state->userdata);
> +            if (state->result)
> +               break;
> +
> +            ptr += packetLen;
> +            length -= packetLen;
> +         }
> +         if(transfer->status == LIBUSB_TRANSFER_CANCELLED) {
> +            free(transfer->buffer);
> +            libusb_free_transfer(transfer);
> +            return;
> +         }
> +
> +
> +      } else {
> +         state->result = LIBUSB_ERROR_IO;
> +      }
> +   }
> +
> +   if (state->result == 0) {
> +      transfer->status = -1;
> +      state->result = libusb_submit_transfer(transfer);
> +   }
> +}
> +
> +/**
> +   Helper function to calculate (unix) time differences
> +
> +   \param a timeval
> +   \param b timeval
> +*/
> +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);
> +}
> +
> +/**
> +    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
> +    or the callback returns a nonzero value. This function returns
> +    a libusb error code or the callback's return value.
> +
> +    For every contiguous block of received data, the callback will
> +    be invoked.
> +
> +    \param  ftdi pointer to ftdi_context
> +    \param  callback to user supplied function for one block of data
> +    \param  userdata
> +    \param  packetsPerTransfer number of packets per transfer
> +    \param  numTransfers Number of transfers per callback
> +
> +*/
> +
> +int
> +ftdi_readstream(struct ftdi_context *ftdi,
> +                      FTDIStreamCallback *callback, void *userdata,
> +                      int packetsPerTransfer, int numTransfers)
> +{
> +   struct libusb_transfer **transfers;
> +   FTDIStreamState state = { callback, userdata, ftdi->max_packet_size };
> +   int bufferSize = packetsPerTransfer * ftdi->max_packet_size;
> +   int xferIndex;
> +   int err = 0;
> +
> +   fprintf(stderr, "ftdi_readstream\n");
> +   /*
> +    * Set up all transfers
> +    */
> +
> +   transfers = calloc(numTransfers, sizeof *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) {
> +         err = LIBUSB_ERROR_NO_MEM;
> +         goto cleanup;
> +      }
> +
> +      libusb_fill_bulk_transfer(transfer, ftdi->usb_dev, ftdi->out_ep,
> +                                malloc(bufferSize), bufferSize,
> ftdi_readstream_cb,
> +                                &state, 0);
> +
> +      if (!transfer->buffer) {
> +         err = LIBUSB_ERROR_NO_MEM;
> +         goto cleanup;
> +      }
> +
> +      transfer->status = -1;
> +      err = libusb_submit_transfer(transfer);
> +      if (err)
> +         goto cleanup;
> +   }
> +
> +   /*
> +    * 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 now;
> +
> +      int err = libusb_handle_events_timeout(ftdi->libusb, &timeout);
> +      if (!state.result) {
> +         state.result = err;
> +      }
> +
> +      // 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;
> +         }
> +
> +         state.result = state.callback(NULL, 0, progress, state.userdata);
> +         progress->prev = progress->current;
> +
> +      }
> +   } while (!state.result);
> +
> +   /*
> +    * Cancel any outstanding transfers, and free memory.
> +    */
> +
> + cleanup:
> +  fprintf(stderr, "cleanup\n");
> +  if (transfers) {
> +      int i;
> +      for (xferIndex = 0; xferIndex < numTransfers; xferIndex++) {
> +         struct libusb_transfer *transfer = transfers[xferIndex];
> +
> +         if (transfer) {
> +            if (transfer->status == -1)
> +                libusb_cancel_transfer(transfer);
> +         }
> +      }
> +      for(i=0; i<numTransfers; i++) {
> +        libusb_handle_events(ftdi->libusb);
> +      }
> +      free(transfers);
> +   }
> +
> +   if (err)
> +      return err;
> +   else
> +      return state.result;
> +}
> +
>
>  /**
>     Enable bitbang mode.
> diff --git a/src/ftdi.h b/src/ftdi.h
> index 179d3ca..a148133 100644
> --- a/src/ftdi.h
> +++ b/src/ftdi.h
> @@ -175,6 +175,8 @@ struct ftdi_transfer_control
>  struct ftdi_context
>  {
>     /* USB specific */
> +    /** libusb's context */
> +    struct libusb_context *libusb;
>     /** libusb's usb_dev_handle */
>     struct libusb_device_handle *usb_dev;
>     /** usb read timeout */
> @@ -278,6 +280,24 @@ struct ftdi_eeprom
>     int size;
>  };
>
> +/**
> +    \brief Progress Info for streaming read
> +*/
> +typedef struct {
> +   struct {
> +      uint64_t       totalBytes;
> +      struct timeval time;
> +   } first, prev, current;
> +
> +   double totalTime;
> +   double totalRate;
> +   double currentRate;
> +} FTDIProgressInfo;
> +
> +typedef int (FTDIStreamCallback)(uint8_t *buffer, int length,
> +                                 FTDIProgressInfo *progress, void
> *userdata);
> +
> +
>  #ifdef __cplusplus
>  extern "C"
>  {
> --
> 1.6.4.2
>
>
> --
> libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
> To unsubscribe send a mail to 
> [email protected]<libftdi%[email protected]>
>
>


--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to [email protected]   

Reply via email to