]> git.zarvox.org Git - libtouchmouse.git/commitdiff
Make the timeouts behave as they ought.
authorDrew Fisher <drew.m.fisher@gmail.com>
Mon, 31 Oct 2011 06:24:34 +0000 (23:24 -0700)
committerDrew Fisher <drew.m.fisher@gmail.com>
Mon, 31 Oct 2011 06:38:00 +0000 (23:38 -0700)
Each platform has its own API for high resolution timers, so I added an
abstraction function that returns a monotonically increasing number in
nanoseconds.

On Windows, we use QueryPerformanceCounter()
On OSX, we use mach_absolute_time()
On Linux, we use clock_gettime() with CLOCK_MONOTONIC

Signed-off-by: Drew Fisher <drew.m.fisher@gmail.com>
CMakeLists.txt
src/mono_timer.c [new file with mode: 0644]
src/mono_timer.h [new file with mode: 0644]
src/touchmouse.c

index 51853b4cfaeeefea16fd15d2cb144e66b668a701..a799fe487a44e28971449dea25e4255fb5bcf7dc 100644 (file)
@@ -28,7 +28,7 @@ else()
        include_directories(/usr/include/libusb-1.0)
        list(APPEND LIBSRC hidapi/linux/hid-libusb.c)
 endif()
-list(APPEND LIBSRC src/touchmouse.c)
+list(APPEND LIBSRC src/touchmouse.c src/mono_timer.c)
 
 set(CMAKE_C_FLAGS "-Wall -ggdb")
 
diff --git a/src/mono_timer.c b/src/mono_timer.c
new file mode 100644 (file)
index 0000000..bdea504
--- /dev/null
@@ -0,0 +1,52 @@
+/* This file is intended to make it easier to work with monotonic timers on
+ * multiple platforms, since there's no single API for doing so.
+ *
+ * On Windows, we use QueryPerformanceCounter and QueryPerformanceFrequency
+ * On OSX, we use mach_absolute_time()
+ * On Linux, we use clock_gettime() with CLOCK_MONOTONIC
+ *
+ * Since I find this problem worth solving somewhat permanently:
+ *
+ * I hereby release this file into the public domain.
+ */
+
+#include "mono_timer.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#ifdef __APPLE__
+#include <mach/mach_time.h>
+#endif
+
+#ifdef __linux__
+#include <time.h>
+#endif
+
+#ifdef _WIN32
+uint64_t mono_timer_nanos() {
+       LARGE_INTEGER freq;
+       LARGE_INTEGER count;
+       if (!QueryPerformanceFrequency(&freq)) return 0;
+       if (!QueryPerformanceCounter(&count)) return 0;
+       // count / freq = seconds, so count / freq * 1e9 = nanoseconds
+       return (uint64_t)(count.QuadPart * 1000000000 / freq.QuadPart);
+}
+#endif // _WIN32
+#ifdef __APPLE__
+uint64_t mono_timer_nanos() {
+       mach_timebase_info_data_t info;
+       mach_timebase_info(&info);
+       return mach_absolute_time() * info.numer / info.denom;
+}
+#endif // APPLE
+#ifdef __linux__
+uint64_t mono_timer_nanos() {
+       struct timespec ts;
+       if(clock_gettime(CLOCK_MONOTONIC, &ts) != 0) return 0;
+       uint64_t nanos = (uint64_t)ts.tv_sec * 1000000000;
+       nanos += ts.tv_nsec;
+       return nanos;
+}
+#endif // __linux__
diff --git a/src/mono_timer.h b/src/mono_timer.h
new file mode 100644 (file)
index 0000000..cc539b0
--- /dev/null
@@ -0,0 +1,25 @@
+/* This file is intended to make it easier to work with monotonic timers on
+ * multiple platforms, since there's no single API for doing so.
+ *
+ * On Windows, we use QueryPerformanceCounter and QueryPerformanceFrequency
+ * On OSX, we use mach_absolute_time()
+ * On Linux, we use clock_gettime() with CLOCK_MONOTONIC
+ * Other platforms are currently unsupported.
+ *
+ * Since I find this problem worth solving somewhat permanently:
+ *
+ * I hereby release this file into the public domain.
+ */
+#ifndef __MONO_TIMER_H__
+#define __MONO_TIMER_H__
+
+#include <stdint.h>
+
+// Returns the current time in nanoseconds since an arbitrary epoch.  This
+// value is supposed to be stable and increase monotonically when called from
+// the same process, up to the maximum guarantee that can be provided by the
+// underlying OS.
+// Returns 0 on error.
+uint64_t mono_timer_nanos();
+
+#endif // __MONO_TIMER_H__
index 17108bbb9cb83ca2875ed61348fc8ae79e01a63a..30c0189ff3f1e03ad65c7832849d69f12adf62d0 100644 (file)
@@ -31,6 +31,7 @@
 #include <stdint.h>
 
 #include "touchmouse-internal.h"
+#include "mono_timer.h"
 
 #pragma pack(1)
 //  The USB HID reports that contain our data are always 32 bytes, with the
@@ -335,12 +336,21 @@ int touchmouse_set_device_userdata(touchmouse_device *dev, void *userdata)
 int touchmouse_process_events_timeout(touchmouse_device *dev, int milliseconds) {
        unsigned char data[256] = {};
        int res;
-       int millisleft = milliseconds;
        uint8_t first_timestamp_read = 0;
        uint8_t last_timestamp = 0;
-       while(millisleft) { // TODO: make this TIME_NOT_YET_EXPIRED
-               res = hid_read_timeout(dev->dev, data, 255, millisleft); // TODO: fix this to be
-               // the right number of milliseconds
+       uint64_t deadline;
+       if(milliseconds == -1) {
+               deadline = (uint64_t)(-1);
+       } else {
+               deadline = mono_timer_nanos() + (milliseconds * 1000000);
+       }
+       uint64_t nanos = mono_timer_nanos();
+       if (nanos == 0 || deadline == 0) {
+               fprintf(stderr, "timer function returned an error, erroring out since we have no timer\n");
+               return -1;
+       }
+       do {
+               res = hid_read_timeout(dev->dev, data, 255, (deadline - nanos) / 1000000 );
                if (res < 0 ) {
                        fprintf(stderr, "hid_read() failed: %d\n", res);
                        return -1;
@@ -405,7 +415,8 @@ int touchmouse_process_events_timeout(touchmouse_device *dev, int milliseconds)
                                }
                        }
                }
-       }
+               nanos = mono_timer_nanos();
+       } while(nanos < deadline);
        return 0;
 }