summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUwe Klotz <uklotz@mixxx.org>2020-10-04 22:26:59 +0200
committerGitHub <noreply@github.com>2020-10-04 22:26:59 +0200
commitdc30a520b271d097098b1da9abc2781f357495ec (patch)
tree3aae6a9a2a5a372f08994dda2f6c864b5d9d0c63
parent6704a1ad9ee56b6c5ae8071d27e1332cbb7be51a (diff)
parentdff0202ca7a15d4543c80de30836b2b27ce500be (diff)
Merge pull request #2970 from Be-ing/hid_polling
HidController: loop until no more messages are available on poll
-rw-r--r--src/controllers/controllermanager.cpp10
-rw-r--r--src/controllers/controllermanager.h2
-rw-r--r--src/controllers/hid/hidcontroller.cpp49
-rw-r--r--src/controllers/hid/hidcontroller.h5
4 files changed, 51 insertions, 15 deletions
diff --git a/src/controllers/controllermanager.cpp b/src/controllers/controllermanager.cpp
index a232fbfa29..b6ab1f485e 100644
--- a/src/controllers/controllermanager.cpp
+++ b/src/controllers/controllermanager.cpp
@@ -27,18 +27,18 @@
#include "controllers/bulk/bulkenumerator.h"
#endif
-namespace {
// http://developer.qt.nokia.com/wiki/Threads_Events_QObjects
// Poll every 1ms (where possible) for good controller response
#ifdef __LINUX__
// Many Linux distros ship with the system tick set to 250Hz so 1ms timer
// reportedly causes CPU hosage. See Bug #990992 rryan 6/2012
-const int kPollIntervalMillis = 5;
+const mixxx::Duration ControllerManager::kPollInterval = mixxx::Duration::fromMillis(5);
#else
-const int kPollIntervalMillis = 1;
+const mixxx::Duration ControllerManager::kPollInterval = mixxx::Duration::fromMillis(1);
#endif
+namespace {
/// Strip slashes and spaces from device name, so that it can be used as config
/// key or a filename.
QString sanitizeDeviceName(QString name) {
@@ -97,7 +97,7 @@ ControllerManager::ControllerManager(UserSettingsPointer pConfig)
QDir().mkpath(userPresets);
}
- m_pollTimer.setInterval(kPollIntervalMillis);
+ m_pollTimer.setInterval(kPollInterval.toIntegerMillis());
connect(&m_pollTimer, SIGNAL(timeout()),
this, SLOT(pollDevices()));
@@ -359,7 +359,7 @@ void ControllerManager::pollDevices() {
}
mixxx::Duration duration = mixxx::Time::elapsed() - start;
- if (duration > mixxx::Duration::fromMillis(kPollIntervalMillis)) {
+ if (duration > kPollInterval) {
m_skipPoll = true;
}
//qDebug() << "ControllerManager::pollDevices()" << duration << start;
diff --git a/src/controllers/controllermanager.h b/src/controllers/controllermanager.h
index 8837d90358..fba7f70462 100644
--- a/src/controllers/controllermanager.h
+++ b/src/controllers/controllermanager.h
@@ -30,6 +30,8 @@ class ControllerManager : public QObject {
ControllerManager(UserSettingsPointer pConfig);
virtual ~ControllerManager();
+ static const mixxx::Duration kPollInterval;
+
QList<Controller*> getControllers() const;
QList<Controller*> getControllerList(bool outputDevices=true, bool inputDevices=true);
ControllerLearningEventFilter* getControllerLearningEventFilter() const;
diff --git a/src/controllers/hid/hidcontroller.cpp b/src/controllers/hid/hidcontroller.cpp
index 08bff7ef12..1b1ca2bec5 100644
--- a/src/controllers/hid/hidcontroller.cpp
+++ b/src/controllers/hid/hidcontroller.cpp
@@ -18,7 +18,8 @@
HidController::HidController(const hid_device_info& deviceInfo, UserSettingsPointer pConfig)
: Controller(pConfig),
- m_pHidDevice(NULL) {
+ m_pHidDevice(nullptr),
+ m_iPollingBufferIndex(0) {
// Copy required variables from deviceInfo, which will be freed after
// this class is initialized by caller.
hid_vendor_id = deviceInfo.vendor_id;
@@ -215,6 +216,10 @@ int HidController::open() {
return -1;
}
+ for (int i = 0; i < kNumBuffers; i++) {
+ memset(m_pPollData[i], 0, kBufferSize);
+ }
+
setOpen(true);
startEngine();
@@ -243,16 +248,42 @@ int HidController::close() {
bool HidController::poll() {
Trace hidRead("HidController poll");
- int result = hid_read(m_pHidDevice, m_pPollData, sizeof(m_pPollData) / sizeof(m_pPollData[0]));
- if (result == -1) {
- return false;
- } else if (result > 0) {
+ // This loop risks becoming a high priority endless loop in case processing
+ // the mapping JS code takes longer than the controller polling rate.
+ // This could stall other low priority tasks.
+ // There is no safety net for this because it has not been demonstrated to be
+ // a problem in practice.
+ while (true) {
+ // Cycle between buffers so the memcmp below does not require deep copying to another buffer.
+ unsigned char* pPreviousBuffer = m_pPollData[m_iPollingBufferIndex];
+ m_iPollingBufferIndex = (m_iPollingBufferIndex + 1) % kNumBuffers;
+ unsigned char* pCurrentBuffer = m_pPollData[m_iPollingBufferIndex];
+
+ int bytesRead = hid_read(m_pHidDevice, pCurrentBuffer, kBufferSize);
+ if (bytesRead < 0) {
+ // -1 is the only error value according to hidapi documentation.
+ DEBUG_ASSERT(bytesRead == -1);
+ return false;
+ } else if (bytesRead == 0) {
+ return true;
+ }
+
Trace process("HidController process packet");
- QByteArray outData(reinterpret_cast<char*>(m_pPollData), result);
- receive(outData, mixxx::Time::elapsed());
+ // Some controllers such as the Gemini GMX continuously send input packets even if it
+ // is identical to the previous packet. If this loop processed all those redundant
+ // packets, it would be a big performance problem to run JS code for every packet and
+ // would be unnecessary.
+ // This assumes that the redundant packets all use the same report ID. In practice we
+ // have not encountered any controllers that send redundant packets with different report
+ // IDs. If any such devices exist, this may be changed to use a separate buffer to store
+ // the last packet for each report ID.
+ if (memcmp(pCurrentBuffer, pPreviousBuffer, kBufferSize) == 0) {
+ continue;
+ }
+ auto incomingData = QByteArray::fromRawData(
+ reinterpret_cast<char*>(pCurrentBuffer), bytesRead);
+ receive(incomingData, mixxx::Time::elapsed());
}
-
- return true;
}
bool HidController::isPolling() const {
diff --git a/src/controllers/hid/hidcontroller.h b/src/controllers/hid/hidcontroller.h
index 543684ee76..65e06fd4f2 100644
--- a/src/controllers/hid/hidcontroller.h
+++ b/src/controllers/hid/hidcontroller.h
@@ -89,7 +89,10 @@ class HidController final : public Controller {
hid_device* m_pHidDevice;
HidControllerPreset m_preset;
- unsigned char m_pPollData[255];
+ static constexpr int kNumBuffers = 2;
+ static constexpr int kBufferSize = 255;
+ unsigned char m_pPollData[kNumBuffers][kBufferSize];
+ int m_iPollingBufferIndex;
};
#endif