Don't #include <libusb.h> from ftdi.h
[libftdi] / src / ftdi_stream.c
index 3f12ebc..cf3acf5 100644 (file)
@@ -41,6 +41,7 @@
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <libusb.h>
 
 #include "ftdi.h"
 
@@ -49,66 +50,64 @@ typedef struct
     FTDIStreamCallback *callback;
     void *userdata;
     int packetsize;
+    int activity;
     int result;
     FTDIProgressInfo progress;
 } FTDIStreamState;
 
+/* Handle callbacks
+ * 
+ * With Exit request, free memory and release the transfer
+ *
+ * state->result is only set when some error happens 
+ */
 static void
 ftdi_readstream_cb(struct libusb_transfer *transfer)
 {
    FTDIStreamState *state = transfer->user_data;
    int packet_size = state->packetsize;
 
-   if(transfer->status & LIBUSB_TRANSFER_CANCELLED)
-   {
-       free(transfer->buffer);
-       libusb_free_transfer(transfer);
-       return;
-   }
-   if (state->result == 0)
+   state->activity++;
+   if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
    {
-       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;
-
-           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;
-           }
-
+       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
        {
-           fprintf(stderr, "unknown status %d\n",transfer->status); 
-           state->result = LIBUSB_ERROR_IO;
+           transfer->status = -1;
+           state->result = libusb_submit_transfer(transfer);
        }
    }
    else
-       fprintf(stderr,"state->result %d\n", state->result);
-
-   if (state->result == 0)
    {
-       transfer->status = -1;
-       state->result = libusb_submit_transfer(transfer);
+       fprintf(stderr, "unknown status %d\n",transfer->status); 
+       state->result = LIBUSB_ERROR_IO;
    }
 }
 
@@ -126,7 +125,7 @@ TimevalDiff(const struct timeval *a, const struct timeval *b)
 
 /**
     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
@@ -150,43 +149,63 @@ ftdi_readstream(struct ftdi_context *ftdi,
                       int packetsPerTransfer, int numTransfers)
 {
     struct libusb_transfer **transfers;
-    FTDIStreamState state = { callback, userdata, ftdi->max_packet_size };
+    FTDIStreamState state = { callback, userdata, ftdi->max_packet_size, 1 };
     int bufferSize = packetsPerTransfer * ftdi->max_packet_size;
     int xferIndex;
     int err = 0;
 
-    fprintf(stderr, "ftdi_readstream\n");
+    /* Only FT2232H and FT232H know about the synchronous FIFO Mode*/
+    if ((ftdi->type != TYPE_2232H) && (ftdi->type != TYPE_232H))
+    {
+        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)
+    {
+        fprintf(stderr,"Can't Purge\n");
+        return 1;
+    }
+
     /*
      * 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)
@@ -200,7 +219,7 @@ ftdi_readstream(struct ftdi_context *ftdi,
      */
     if (ftdi_set_bitmode(ftdi,  0xff, BITMODE_SYNCFF) < 0)
     {
-        fprintf(stderr,"Can't set synchronous fifo mode\n",
+        fprintf(stderr,"Can't set synchronous fifo mode: %s\n",
                 ftdi_get_error_string(ftdi));
         goto cleanup;
     }
@@ -208,22 +227,29 @@ ftdi_readstream(struct ftdi_context *ftdi,
     /*
      * 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(NULL, &timeout);
+        
+        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);  
         if (!state.result)
         {
             state.result = err;
         }
-
+        if (state.activity == 0)
+            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)
@@ -231,49 +257,37 @@ ftdi_readstream(struct ftdi_context *ftdi,
             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);
+            
+            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) {
-                    libusb_cancel_transfer(transfer);
-            }
-        }
-            libusb_handle_events(NULL);
-        free(transfers);
-    }
-
+    if (transfers)
+       free(transfers);
     if (err)
         return err;
     else