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 */