From 4c23a0e1dcec46a78785961b6e8b544cf3821ffd Mon Sep 17 00:00:00 2001
From: Ingo Ruhnke <grumbel@gmx.de>
Date: Fri, 26 Dec 2008 00:06:02 +0100
Subject: [PATCH] Added timeout to ::read()

---
 xbox360_controller.cpp          | 11 ++++++++---
 xbox360_controller.hpp          |  2 +-
 xbox360_wireless_controller.cpp | 12 ++++++++----
 xbox360_wireless_controller.hpp |  2 +-
 xbox_controller.cpp             | 13 +++++++++----
 xbox_controller.hpp             |  2 +-
 xbox_generic_controller.hpp     |  4 +++-
 xboxdrv.cpp                     |  9 +++++++--
 8 files changed, 38 insertions(+), 17 deletions(-)

diff --git a/xbox360_controller.cpp b/xbox360_controller.cpp
index 6e0fbf8..d7cf8a1 100644
--- a/xbox360_controller.cpp
+++ b/xbox360_controller.cpp
@@ -16,6 +16,7 @@
 **  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <errno.h>
 #include <stdexcept>
 #include <sstream>
 #include <iostream>
@@ -91,12 +92,16 @@ Xbox360Controller::set_led(uint8_t status)
 }
 
 bool
-Xbox360Controller::read(XboxGenericMsg& msg, bool verbose)
+Xbox360Controller::read(XboxGenericMsg& msg, bool verbose, int timeout)
 {
   uint8_t data[32];
-  int ret = usb_interrupt_read(handle, 1 /*EndPoint*/, (char*)data, sizeof(data), 0 /*Timeout*/);
+  int ret = usb_interrupt_read(handle, 1 /*EndPoint*/, (char*)data, sizeof(data), timeout);
 
-  if (ret < 0)
+  if (ret == -ETIMEDOUT)
+    {
+      return false;
+    }
+  else if (ret < 0)
     { // Error
       std::ostringstream str;
       str << "USBError: " << ret << "\n" << usb_strerror();
diff --git a/xbox360_controller.hpp b/xbox360_controller.hpp
index 9987fe6..048d5cb 100644
--- a/xbox360_controller.hpp
+++ b/xbox360_controller.hpp
@@ -40,7 +40,7 @@ public:
   void set_rumble(uint8_t left, uint8_t right);
   void set_led(uint8_t status);
   void send_raw(char* buffer, int len);
-  bool read(XboxGenericMsg& msg, bool verbose);
+  bool read(XboxGenericMsg& msg, bool verbose, int timeout);
 
 private:
   Xbox360Controller (const Xbox360Controller&);
diff --git a/xbox360_wireless_controller.cpp b/xbox360_wireless_controller.cpp
index 4d05532..6d4b326 100644
--- a/xbox360_wireless_controller.cpp
+++ b/xbox360_wireless_controller.cpp
@@ -76,12 +76,16 @@ Xbox360WirelessController::set_led(uint8_t status)
 }
 
 bool
-Xbox360WirelessController::read(XboxGenericMsg& msg, bool verbose)
+Xbox360WirelessController::read(XboxGenericMsg& msg, bool verbose, int timeout)
 {
   uint8_t data[32];
-  int ret = usb_interrupt_read(handle, endpoint, (char*)data, sizeof(data), 0 /*Timeout*/);
-  
-  if (ret < 0)
+  int ret = usb_interrupt_read(handle, endpoint, (char*)data, sizeof(data), timeout);
+
+  if (ret == -ETIMEDOUT)
+    {
+      return false;
+    }
+  else  if (ret < 0)
     { // Error
       std::ostringstream str;
       str << "USBError: " << ret << "\n" << usb_strerror();
diff --git a/xbox360_wireless_controller.hpp b/xbox360_wireless_controller.hpp
index e73e3aa..f74f2c7 100644
--- a/xbox360_wireless_controller.hpp
+++ b/xbox360_wireless_controller.hpp
@@ -41,7 +41,7 @@ public:
 
   void set_rumble(uint8_t left, uint8_t right);
   void set_led(uint8_t status);
-  bool read(XboxGenericMsg& msg, bool verbose);
+  bool read(XboxGenericMsg& msg, bool verbose, int timeout);
   uint8_t get_battery_status() const;
 private:
   Xbox360WirelessController (const Xbox360WirelessController&);
diff --git a/xbox_controller.cpp b/xbox_controller.cpp
index b1e6c50..ecd8ca5 100644
--- a/xbox_controller.cpp
+++ b/xbox_controller.cpp
@@ -16,6 +16,7 @@
 **  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <errno.h>
 #include <stdexcept>
 #include <sstream>
 #include "xboxmsg.hpp"
@@ -58,13 +59,17 @@ XboxController::set_led(uint8_t status)
 }
 
 bool
-XboxController::read(XboxGenericMsg& msg, bool verbose)
+XboxController::read(XboxGenericMsg& msg, bool verbose, int timeout)
 {
   // FIXME: Add tracking for duplicate data packages (send by logitech controller)
   uint8_t data[32];
-  int ret = usb_interrupt_read(handle, 1 /*EndPoint*/, (char*)data, sizeof(data), 0 /*Timeout*/);
-  
-  if (ret < 0)
+  int ret = usb_interrupt_read(handle, 1 /*EndPoint*/, (char*)data, sizeof(data), timeout);
+
+  if (ret == -ETIMEDOUT)
+    {
+      return false;
+    }
+  else if (ret < 0)
     { // Error
       std::ostringstream str;
       str << "USBError: " << ret << "\n" << usb_strerror();
diff --git a/xbox_controller.hpp b/xbox_controller.hpp
index ec5be6d..992829f 100644
--- a/xbox_controller.hpp
+++ b/xbox_controller.hpp
@@ -37,7 +37,7 @@ public:
 
   void set_rumble(uint8_t left, uint8_t right);
   void set_led(uint8_t status);
-  bool read(XboxGenericMsg& msg, bool verbose);
+  bool read(XboxGenericMsg& msg, bool verbose, int timeout);
 
 private:
   XboxController (const XboxController&);
diff --git a/xbox_generic_controller.hpp b/xbox_generic_controller.hpp
index 9772d68..5fc4772 100644
--- a/xbox_generic_controller.hpp
+++ b/xbox_generic_controller.hpp
@@ -30,7 +30,9 @@ public:
   virtual void set_rumble(uint8_t left, uint8_t right) =0;
   virtual void set_led(uint8_t status)   =0;
   virtual void send_raw(char* buffer, int len) {}
-  virtual bool read(XboxGenericMsg& msg, bool verbose) =0;
+
+  /** @param timeout   timeout in msec, 0 means forever */
+  virtual bool read(XboxGenericMsg& msg, bool verbose, int timeout) =0;
 
 private:
   XboxGenericController (const XboxGenericController&);
diff --git a/xboxdrv.cpp b/xboxdrv.cpp
index 76d44cc..270cd1e 100644
--- a/xboxdrv.cpp
+++ b/xboxdrv.cpp
@@ -851,15 +851,17 @@ void squarify_axis_(int16_t& x_inout, int16_t& y_inout)
 {
   if (x_inout != 0 || y_inout != 0)
     {
+      // Convert values to float
       float x = (x_inout < 0) ? x_inout / 32768.0f : x_inout / 32767.0f;
       float y = (y_inout < 0) ? y_inout / 32768.0f : y_inout / 32767.0f;
 
+      // Transform values to square range
       float l = sqrtf(x*x + y*y);
       float v = fabs((fabsf(x) > fabsf(y)) ? l/x : l/y);
-
       x *= v;
       y *= v;
 
+      // Convert values to int16_t
       x_inout = static_cast<int16_t>(Math::clamp(-32768, static_cast<int>((x < 0) ? x * 32768 : x * 32767), 32767));
       y_inout = static_cast<int16_t>(Math::clamp(-32768, static_cast<int>((y < 0) ? y * 32768 : y * 32767), 32767));
     }
@@ -934,13 +936,16 @@ void apply_deadzone(XboxGenericMsg& msg, int deadzone)
 
 void controller_loop(uInput* uinput, XboxGenericController* controller, CommandLineOptions& opts)
 {
+  int timeout = 0; // 0 == no timeout
   XboxGenericMsg oldmsg;
+
   memset(&oldmsg, 0, sizeof(oldmsg));
+
   while(!global_exit_xboxdrv)
     {
       XboxGenericMsg msg;
 
-      if (controller->read(msg, opts.verbose))
+      if (controller->read(msg, opts.verbose, timeout))
         {
           apply_deadzone(msg, opts.deadzone);