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)
This commit is contained in:
pixl 2020-07-12 04:42:44 -04:00
parent 1a056a1ecf
commit 4ce76f5927
No known key found for this signature in database
GPG Key ID: 1866C148CD593B6E
7 changed files with 46 additions and 0 deletions

View File

@ -21,6 +21,7 @@
#include "util/log.h" #include "util/log.h"
#include "backend/hidpp10/Error.h" #include "backend/hidpp10/Error.h"
#include "backend/hidpp20/Error.h" #include "backend/hidpp20/Error.h"
#include "backend/Error.h"
using namespace logid; using namespace logid;
using namespace logid::backend; using namespace logid::backend;
@ -67,6 +68,11 @@ void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
} catch(hidpp20::Error &e) { } catch(hidpp20::Error &e) {
logPrintf(ERROR, "Caught HID++ 2.0 error while trying to initialize " logPrintf(ERROR, "Caught HID++ 2.0 error while trying to initialize "
"%s:%d: %s", _path.c_str(), event.index, e.what()); "%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);
} }
} }

View File

@ -238,6 +238,7 @@ hidpp::DeviceConnectionEvent Receiver::deviceConnectionEvent(const
event.encrypted = report.paramBegin()[0] & (1<<5); event.encrypted = report.paramBegin()[0] & (1<<5);
event.linkEstablished = !(report.paramBegin()[0] & (1<<6)); event.linkEstablished = !(report.paramBegin()[0] & (1<<6));
event.withPayload = report.paramBegin()[0] & (1<<7); event.withPayload = report.paramBegin()[0] & (1<<7);
event.fromTimeoutCheck = false;
event.pid =(report.paramBegin()[2] << 8); event.pid =(report.paramBegin()[2] << 8);
event.pid |= report.paramBegin()[1]; event.pid |= report.paramBegin()[1];

View File

@ -189,6 +189,7 @@ namespace hidpp
bool encrypted; bool encrypted;
bool linkEstablished; bool linkEstablished;
bool withPayload; bool withPayload;
bool fromTimeoutCheck = false; // Fake field
}; };
}}} }}}

View File

@ -95,6 +95,37 @@ void ReceiverMonitor::enumerate()
_receiver->enumerateHidpp(); _receiver->enumerateHidpp();
} }
void ReceiverMonitor::waitForDevice(hidpp::DeviceIndex index)
{
std::string nickname = "WAIT_DEV_" + std::to_string(index);
auto handler = std::make_shared<raw::RawEventHandler>();
handler->condition = [index](std::vector<uint8_t>& report)->bool {
return report[Offset::DeviceIndex] == index;
};
handler->callback = [this, index, nickname](std::vector<uint8_t>& 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<Receiver> ReceiverMonitor::receiver() const std::shared_ptr<Receiver> ReceiverMonitor::receiver() const
{ {
return _receiver; return _receiver;

View File

@ -42,6 +42,8 @@ namespace dj
virtual void addDevice(hidpp::DeviceConnectionEvent event) = 0; virtual void addDevice(hidpp::DeviceConnectionEvent event) = 0;
virtual void removeDevice(hidpp::DeviceIndex index) = 0; virtual void removeDevice(hidpp::DeviceIndex index) = 0;
void waitForDevice(hidpp::DeviceIndex index);
// Internal methods for derived class // Internal methods for derived class
void _pair(uint8_t timeout = 0); void _pair(uint8_t timeout = 0);
void _stopPairing(); void _stopPairing();

View File

@ -404,6 +404,7 @@ void RawDevice::stopListener()
void RawDevice::addEventHandler(const std::string& nickname, void RawDevice::addEventHandler(const std::string& nickname,
const std::shared_ptr<raw::RawEventHandler>& handler) const std::shared_ptr<raw::RawEventHandler>& handler)
{ {
std::unique_lock<std::mutex> lock(_event_handler_lock);
auto it = _event_handlers.find(nickname); auto it = _event_handlers.find(nickname);
assert(it == _event_handlers.end()); assert(it == _event_handlers.end());
assert(handler); assert(handler);
@ -412,17 +413,20 @@ void RawDevice::addEventHandler(const std::string& nickname,
void RawDevice::removeEventHandler(const std::string &nickname) void RawDevice::removeEventHandler(const std::string &nickname)
{ {
std::unique_lock<std::mutex> lock(_event_handler_lock);
_event_handlers.erase(nickname); _event_handlers.erase(nickname);
} }
const std::map<std::string, std::shared_ptr<raw::RawEventHandler>>& const std::map<std::string, std::shared_ptr<raw::RawEventHandler>>&
RawDevice::eventHandlers() RawDevice::eventHandlers()
{ {
std::unique_lock<std::mutex> lock(_event_handler_lock);
return _event_handlers; return _event_handlers;
} }
void RawDevice::_handleEvent(std::vector<uint8_t> &report) void RawDevice::_handleEvent(std::vector<uint8_t> &report)
{ {
std::unique_lock<std::mutex> lock(_event_handler_lock);
for(auto& handler : _event_handlers) for(auto& handler : _event_handlers)
if(handler.second->condition(report)) if(handler.second->condition(report))
handler.second->callback(report); handler.second->callback(report);

View File

@ -80,6 +80,7 @@ namespace raw
std::map<std::string, std::shared_ptr<RawEventHandler>> std::map<std::string, std::shared_ptr<RawEventHandler>>
_event_handlers; _event_handlers;
std::mutex _event_handler_lock;
void _handleEvent(std::vector<uint8_t>& report); void _handleEvent(std::vector<uint8_t>& report);
/* These will only be used internally and processed with a queue */ /* These will only be used internally and processed with a queue */