From 4ce76f5927245f7ae10f1817bd0d316459898767 Mon Sep 17 00:00:00 2001 From: pixl Date: Sun, 12 Jul 2020 04:42:44 -0400 Subject: [PATCH] Listen for events on receiver device on timeout Previously, if a receiver device didn't respond during the initial scan, logid would not recognize it until it sent a wakeup/connect event. This makes it so if the device times out, logid will listen for the next event from the device and try detecting it. (e.g. shaking the mouse will make it become detected) --- src/logid/Receiver.cpp | 6 +++++ src/logid/backend/dj/Receiver.cpp | 1 + src/logid/backend/dj/Receiver.h | 1 + src/logid/backend/dj/ReceiverMonitor.cpp | 31 ++++++++++++++++++++++++ src/logid/backend/dj/ReceiverMonitor.h | 2 ++ src/logid/backend/raw/RawDevice.cpp | 4 +++ src/logid/backend/raw/RawDevice.h | 1 + 7 files changed, 46 insertions(+) diff --git a/src/logid/Receiver.cpp b/src/logid/Receiver.cpp index bdfa178..a3f8adb 100644 --- a/src/logid/Receiver.cpp +++ b/src/logid/Receiver.cpp @@ -21,6 +21,7 @@ #include "util/log.h" #include "backend/hidpp10/Error.h" #include "backend/hidpp20/Error.h" +#include "backend/Error.h" using namespace logid; using namespace logid::backend; @@ -67,6 +68,11 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event) } catch(hidpp20::Error &e) { logPrintf(ERROR, "Caught HID++ 2.0 error while trying to initialize " "%s:%d: %s", _path.c_str(), event.index, e.what()); + } catch(TimeoutError &e) { + if(!event.fromTimeoutCheck) + logPrintf(DEBUG, "%s:%d timed out, waiting for input from device to" + " initialize.", _path.c_str(), event.index); + waitForDevice(event.index); } } diff --git a/src/logid/backend/dj/Receiver.cpp b/src/logid/backend/dj/Receiver.cpp index 64118f5..a79c5bf 100644 --- a/src/logid/backend/dj/Receiver.cpp +++ b/src/logid/backend/dj/Receiver.cpp @@ -238,6 +238,7 @@ hidpp::DeviceConnectionEvent Receiver::deviceConnectionEvent(const event.encrypted = report.paramBegin()[0] & (1<<5); event.linkEstablished = !(report.paramBegin()[0] & (1<<6)); event.withPayload = report.paramBegin()[0] & (1<<7); + event.fromTimeoutCheck = false; event.pid =(report.paramBegin()[2] << 8); event.pid |= report.paramBegin()[1]; diff --git a/src/logid/backend/dj/Receiver.h b/src/logid/backend/dj/Receiver.h index 86430b2..12d1e1b 100644 --- a/src/logid/backend/dj/Receiver.h +++ b/src/logid/backend/dj/Receiver.h @@ -189,6 +189,7 @@ namespace hidpp bool encrypted; bool linkEstablished; bool withPayload; + bool fromTimeoutCheck = false; // Fake field }; }}} diff --git a/src/logid/backend/dj/ReceiverMonitor.cpp b/src/logid/backend/dj/ReceiverMonitor.cpp index d483475..d3f9fb2 100644 --- a/src/logid/backend/dj/ReceiverMonitor.cpp +++ b/src/logid/backend/dj/ReceiverMonitor.cpp @@ -95,6 +95,37 @@ void ReceiverMonitor::enumerate() _receiver->enumerateHidpp(); } +void ReceiverMonitor::waitForDevice(hidpp::DeviceIndex index) +{ + std::string nickname = "WAIT_DEV_" + std::to_string(index); + auto handler = std::make_shared(); + handler->condition = [index](std::vector& report)->bool { + return report[Offset::DeviceIndex] == index; + }; + + handler->callback = [this, index, nickname](std::vector& report) { + (void)report; // Suppress unused warning + + hidpp::DeviceConnectionEvent event{}; + event.withPayload = false; + event.linkEstablished = true; + event.index = index; + event.fromTimeoutCheck = true; + + task::spawn({[this, event, nickname]() { + _receiver->rawDevice()->removeEventHandler(nickname); + this->addDevice(event); + }}, {[path=_receiver->rawDevice()->hidrawPath(), event] + (std::exception& e) { + logPrintf(ERROR, "Failed to add device %d to receiver " + "on %s: %s", event.index, + path.c_str(), e.what()); + }}); + }; + + _receiver->rawDevice()->addEventHandler(nickname, handler); +} + std::shared_ptr ReceiverMonitor::receiver() const { return _receiver; diff --git a/src/logid/backend/dj/ReceiverMonitor.h b/src/logid/backend/dj/ReceiverMonitor.h index 73d7938..d5deb98 100644 --- a/src/logid/backend/dj/ReceiverMonitor.h +++ b/src/logid/backend/dj/ReceiverMonitor.h @@ -42,6 +42,8 @@ namespace dj virtual void addDevice(hidpp::DeviceConnectionEvent event) = 0; virtual void removeDevice(hidpp::DeviceIndex index) = 0; + void waitForDevice(hidpp::DeviceIndex index); + // Internal methods for derived class void _pair(uint8_t timeout = 0); void _stopPairing(); diff --git a/src/logid/backend/raw/RawDevice.cpp b/src/logid/backend/raw/RawDevice.cpp index 6859271..882396c 100644 --- a/src/logid/backend/raw/RawDevice.cpp +++ b/src/logid/backend/raw/RawDevice.cpp @@ -404,6 +404,7 @@ void RawDevice::stopListener() void RawDevice::addEventHandler(const std::string& nickname, const std::shared_ptr& handler) { + std::unique_lock lock(_event_handler_lock); auto it = _event_handlers.find(nickname); assert(it == _event_handlers.end()); assert(handler); @@ -412,17 +413,20 @@ void RawDevice::addEventHandler(const std::string& nickname, void RawDevice::removeEventHandler(const std::string &nickname) { + std::unique_lock lock(_event_handler_lock); _event_handlers.erase(nickname); } const std::map>& RawDevice::eventHandlers() { + std::unique_lock lock(_event_handler_lock); return _event_handlers; } void RawDevice::_handleEvent(std::vector &report) { + std::unique_lock lock(_event_handler_lock); for(auto& handler : _event_handlers) if(handler.second->condition(report)) handler.second->callback(report); diff --git a/src/logid/backend/raw/RawDevice.h b/src/logid/backend/raw/RawDevice.h index dca622e..d675e34 100644 --- a/src/logid/backend/raw/RawDevice.h +++ b/src/logid/backend/raw/RawDevice.h @@ -80,6 +80,7 @@ namespace raw std::map> _event_handlers; + std::mutex _event_handler_lock; void _handleEvent(std::vector& report); /* These will only be used internally and processed with a queue */