libftdi Archives

Subject: libftdi: Make ftdi_read_data() honor usb_read_timeout

From: Uwe Bonnes <bon@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>
To: libftdi@xxxxxxxxxxxxxxxxxxxxxxx
Date: Fri, 25 Jun 2010 18:03:07 +0200
Hello,

I think there is some unexpected behaviour in ftdi_read_data(). 

I would expect that the ftdi_read_data() call returns when either the
requested number of bytes has been read or when zero of fewer then the
requested number of bytes has been read _and_ the timeout happened.

However the present implementation returns immediate, without waiting the
usb_read_timeout. This happens as

           ret = libusb_bulk_transfer (ftdi->usb_dev, ftdi->out_ep,\
                 ftdi->readbuffer, ftdi->readbuffer_chunksize,
                 &actual_length, ftdi->usb_read_timeout);

will immediate return the two status bytes and 

           else if (actual_length <= 2)
           {
               // no more data to read?
               return offset;

will always return, even when there is no data.

The while loop
       // do the actual USB read
       while (offset < size && actual_length > 0)

should only be exited when the requested number of bytes has been read or a
timeout has happens. 

Appended patch for libusb-0 now loops until the timeout has been hit or all
bytes read or a hard error happened.

I don't know about the exact status of gettimeofday on WIN32  outside of
MINGW, so I have ifdef'd some gettimeofday implementation inspired by notes
on the net. I tested with Linux and XP/Mingw32.

If found usefull and acceptable, it should be applied to libusb-1 too.
   
-- 
Uwe Bonnes                bon@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Institut fuer Kernphysik  Schlossgartenstrasse 9  64289 Darmstadt
--------- Tel. 06151 162516 -------- Fax. 06151 164321 ----------
>From 2c5490e5279bc86256da8e8de39ffd27ed910b5d Mon Sep 17 00:00:00 2001
From: Uwe Bonnes <bon@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 25 Jun 2010 17:41:28 +0200
Subject: Let ftdi_read_data() honor usb_read_timeout

---
 src/ftdi.c |   44 +++++++++++++++++++++++++++++++++++---------
 1 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/src/ftdi.c b/src/ftdi.c
index 4d10b73..fe0ad54 100644
--- a/src/ftdi.c
+++ b/src/ftdi.c
@@ -51,6 +51,35 @@
    } while(0);
 
 
+#if defined( __WIN32__) && !defined(__MINGW32__)
+#include <windows.h>
+#define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
+struct timeval {
+        long    tv_sec;
+        long    tv_usec;
+};
+int gettimeofday(  struct timeval *tv, void null)
+{
+    FILETIME ft;
+    unsigned __int64 tmpres = 0;
+    if(tv)
+    {
+        GetSystemTimeAsFileTime(&ft);
+        tmpres |= ft.dwHighDateTime;
+        tmpres <<= 32;
+        tmpres |= ft.dwLowDateTime;
+        
+        /*converting file time to unix epoch*/
+        tmpres /= 10;  /*convert into microseconds*/
+        tmpres -= DELTA_EPOCH_IN_MICROSECS; 
+        tv->tv_sec = (LONG)(tmpres / 1000000UL);
+        tv->tv_usec = (LONG)(tmpres % 1000000UL);
+    }
+    /* Warning: Timezone not handled ( and not nneded here) */
+    return 0;
+}
+#endif
+
 /**
     Internal function to close usb device pointer.
     Sets ftdi->usb_dev to NULL.
@@ -1528,6 +1557,7 @@ int ftdi_read_data(struct ftdi_context *ftdi, unsigned 
char *buf, int size)
 {
     int offset = 0, ret = 1, i, num_of_chunks, chunk_remains;
     int packet_size;
+    struct timeval tv_start, tv_current;
 
     if (ftdi == NULL || ftdi->usb_dev == NULL)
         ftdi_error_return(-666, "USB device unavailable");
@@ -1559,6 +1589,7 @@ int ftdi_read_data(struct ftdi_context *ftdi, unsigned 
char *buf, int size)
         offset += ftdi->readbuffer_remaining;
     }
     // do the actual USB read
+    gettimeofday(&tv_start,NULL);
     while (offset < size && ret > 0)
     {
         ftdi->readbuffer_remaining = 0;
@@ -1595,14 +1626,6 @@ int ftdi_read_data(struct ftdi_context *ftdi, unsigned 
char *buf, int size)
                 else
                     ret -= 2*(num_of_chunks-1)+chunk_remains;
             }
-        }
-        else if (ret <= 2)
-        {
-            // no more data to read?
-            return offset;
-        }
-        if (ret > 0)
-        {
             // data still fits in buf?
             if (offset+ret <= size)
             {
@@ -1629,9 +1652,12 @@ int ftdi_read_data(struct ftdi_context *ftdi, unsigned 
char *buf, int size)
                 /* printf("Returning part: %d - size: %d - offset: %d - ret: 
%d - remaining: %d\n",
                 part_size, size, offset, ret, ftdi->readbuffer_remaining); */
 
-                return offset;
             }
         }
+        gettimeofday(&tv_current,NULL);
+        if(((tv_current.tv_sec - tv_start.tv_sec)*1000000+(tv_current.tv_usec 
- tv_start.tv_usec)) 
+           > ftdi->usb_read_timeout)
+            return offset;
     }
     // never reached
     return -127;
-- 
1.6.4.2


--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+unsubscribe@xxxxxxxxxxxxxxxxxxxxxxx   

Current Thread