Implement receiver HID++ connect/disconnect events
Many changes were made here but that was the biggest one. There's currently a bug where std::system_error: Broken pipe is thrown after launching the daemon with a receiver connector. A workaround for this bug is to simply shake the mouse while starting the daemon. I will investigate this soon.
This commit is contained in:
@@ -32,47 +32,17 @@ Receiver::Receiver(std::string path) :
|
||||
{
|
||||
if(!supportsDjReports(raw_device->reportDescriptor()))
|
||||
throw InvalidReceiver(InvalidReceiver::NoDJReports);
|
||||
|
||||
|
||||
// Pass all HID++ events on DefaultDevice to handleHidppEvent
|
||||
RawEventHandler hidppRawEventHandler;
|
||||
hidppRawEventHandler.condition = [this](std::vector<uint8_t>& report)->bool
|
||||
{
|
||||
return (report[hidpp::Offset::Type] == hidpp::Report::Type::Short ||
|
||||
report[hidpp::Offset::Type] == hidpp::Report::Type::Long) &&
|
||||
(report[hidpp::Offset::DeviceIndex] == hidpp::DefaultDevice);
|
||||
};
|
||||
hidppRawEventHandler.callback = [this](std::vector<uint8_t>& report)->void
|
||||
{
|
||||
hidpp::Report _report(report);
|
||||
this->handleHidppEvent(_report);
|
||||
};
|
||||
|
||||
// Pass all DJ events with device index to handleHidppEvent
|
||||
RawEventHandler djRawEventHandler;
|
||||
djRawEventHandler.condition = [this](std::vector<uint8_t>& report)->bool
|
||||
{
|
||||
return (report[Offset::Type] == Report::Type::Short ||
|
||||
report[Offset::Type] == Report::Type::Long);
|
||||
};
|
||||
djRawEventHandler.callback = [this](std::vector<uint8_t>& report)->void
|
||||
{
|
||||
Report _report(report);
|
||||
this->handleDjEvent(_report);
|
||||
};
|
||||
|
||||
raw_device->addEventHandler("RECV_HIDPP", hidppRawEventHandler);
|
||||
raw_device->addEventHandler("RECV_DJ", djRawEventHandler);
|
||||
}
|
||||
|
||||
void Receiver::enumerate()
|
||||
void Receiver::enumerateDj()
|
||||
{
|
||||
sendDjRequest(hidpp::DefaultDevice, GetPairedDevices,{});
|
||||
}
|
||||
|
||||
Receiver::notification_flags Receiver::getHidppNotifications()
|
||||
{
|
||||
auto response = _hidpp10_device.getRegister(EnableHidppNotifications, {});
|
||||
auto response = _hidpp10_device.getRegister(EnableHidppNotifications, {},
|
||||
hidpp::ReportType::Short);
|
||||
|
||||
notification_flags flags{};
|
||||
flags.device_battery_status = response[0] & (1 << 4);
|
||||
@@ -89,17 +59,28 @@ void Receiver::enableHidppNotifications(notification_flags flags)
|
||||
if(flags.device_battery_status)
|
||||
request[0] |= (1 << 4);
|
||||
if(flags.receiver_wireless_notifications)
|
||||
request[1] |= (1 << 0);
|
||||
request[1] |= 1;
|
||||
if(flags.receiver_software_present)
|
||||
request[1] |= (1 << 3);
|
||||
|
||||
_hidpp10_device.setRegister(EnableHidppNotifications, request);
|
||||
_hidpp10_device.setRegister(EnableHidppNotifications, request,
|
||||
hidpp::ReportType::Short);
|
||||
}
|
||||
|
||||
void Receiver::enumerateHidpp()
|
||||
{
|
||||
/* This isn't in the documentation but this is how solaar does it
|
||||
* All I know is that when (p0 & 2), devices are enumerated
|
||||
*/
|
||||
_hidpp10_device.setRegister(ConnectionState, {2},
|
||||
hidpp::ReportType::Short);
|
||||
}
|
||||
|
||||
///TODO: Investigate usage
|
||||
uint8_t Receiver::getConnectionState(hidpp::DeviceIndex index)
|
||||
{
|
||||
auto response = _hidpp10_device.setRegister(ConnectionState, {index});
|
||||
auto response = _hidpp10_device.getRegister(ConnectionState, {index},
|
||||
hidpp::ReportType::Short);
|
||||
|
||||
return response[0];
|
||||
}
|
||||
@@ -113,7 +94,8 @@ void Receiver::startPairing(uint8_t timeout)
|
||||
request[1] = hidpp::DefaultDevice;
|
||||
request[2] = timeout;
|
||||
|
||||
_hidpp10_device.setRegister(DevicePairing, request);
|
||||
_hidpp10_device.setRegister(DevicePairing, request,
|
||||
hidpp::ReportType::Short);
|
||||
}
|
||||
|
||||
void Receiver::stopPairing()
|
||||
@@ -124,7 +106,8 @@ void Receiver::stopPairing()
|
||||
request[0] = 2;
|
||||
request[1] = hidpp::DefaultDevice;
|
||||
|
||||
_hidpp10_device.setRegister(DevicePairing, request);
|
||||
_hidpp10_device.setRegister(DevicePairing, request,
|
||||
hidpp::ReportType::Short);
|
||||
}
|
||||
|
||||
void Receiver::disconnect(hidpp::DeviceIndex index)
|
||||
@@ -135,12 +118,14 @@ void Receiver::disconnect(hidpp::DeviceIndex index)
|
||||
request[0] = 3;
|
||||
request[1] = index;
|
||||
|
||||
_hidpp10_device.setRegister(DevicePairing, request);
|
||||
_hidpp10_device.setRegister(DevicePairing, request,
|
||||
hidpp::ReportType::Short);
|
||||
}
|
||||
|
||||
std::map<hidpp::DeviceIndex, uint8_t> Receiver::getDeviceActivity()
|
||||
{
|
||||
auto response = _hidpp10_device.getRegister(DeviceActivity, {});
|
||||
auto response = _hidpp10_device.getRegister(DeviceActivity, {},
|
||||
hidpp::ReportType::Long);
|
||||
|
||||
std::map<hidpp::DeviceIndex, uint8_t> device_activity;
|
||||
for(uint8_t i = hidpp::WirelessDevice1; i <= hidpp::WirelessDevice6; i++)
|
||||
@@ -156,7 +141,8 @@ struct Receiver::PairingInfo
|
||||
request[0] = index;
|
||||
request[0] += 0x19;
|
||||
|
||||
auto response = _hidpp10_device.getRegister(PairingInfo, request);
|
||||
auto response = _hidpp10_device.getRegister(PairingInfo, request,
|
||||
hidpp::ReportType::Long);
|
||||
|
||||
struct PairingInfo info{};
|
||||
info.destinationId = response[0];
|
||||
@@ -175,7 +161,8 @@ struct Receiver::ExtendedPairingInfo
|
||||
request[0] = index;
|
||||
request[0] += 0x29;
|
||||
|
||||
auto response = _hidpp10_device.getRegister(PairingInfo, request);
|
||||
auto response = _hidpp10_device.getRegister(PairingInfo, request,
|
||||
hidpp::ReportType::Long);
|
||||
|
||||
ExtendedPairingInfo info{};
|
||||
|
||||
@@ -197,7 +184,8 @@ std::string Receiver::getDeviceName(hidpp::DeviceIndex index)
|
||||
request[0] = index;
|
||||
request[0] += 0x39;
|
||||
|
||||
auto response = _hidpp10_device.getRegister(PairingInfo, request);
|
||||
auto response = _hidpp10_device.getRegister(PairingInfo, request,
|
||||
hidpp::ReportType::Long);
|
||||
|
||||
uint8_t size = response[0];
|
||||
assert(size <= 14);
|
||||
@@ -215,12 +203,12 @@ hidpp::DeviceIndex Receiver::deviceDisconnectionEvent(hidpp::Report& report)
|
||||
return report.deviceIndex();
|
||||
}
|
||||
|
||||
Receiver::DeviceConnectionEvent Receiver::deviceConnectionEvent(
|
||||
hidpp::DeviceConnectionEvent Receiver::deviceConnectionEvent(
|
||||
hidpp::Report &report)
|
||||
{
|
||||
assert(report.subId() == DeviceConnection);
|
||||
|
||||
DeviceConnectionEvent event{};
|
||||
hidpp::DeviceConnectionEvent event{};
|
||||
|
||||
event.index = report.deviceIndex();
|
||||
event.unifying = ((report.paramBegin()[0] & 0b111) == 0x04);
|
||||
@@ -240,23 +228,54 @@ Receiver::DeviceConnectionEvent Receiver::deviceConnectionEvent(
|
||||
|
||||
void Receiver::handleDjEvent(Report& report)
|
||||
{
|
||||
if(report.feature() == DeviceConnection ||
|
||||
report.feature() == DeviceDisconnection ||
|
||||
report.feature() == ConnectionStatus)
|
||||
{
|
||||
printf("%s DJ IN: ", raw_device->hidrawPath().c_str());
|
||||
for(auto &i: report.rawData())
|
||||
printf("%02x ", i);
|
||||
printf("\n");
|
||||
}
|
||||
for(auto& handler : dj_event_handlers)
|
||||
if(handler.second->condition(report))
|
||||
handler.second->callback(report);
|
||||
}
|
||||
|
||||
void Receiver::handleHidppEvent(hidpp::Report &report)
|
||||
{
|
||||
printf("%s HID++ IN: ", raw_device->hidrawPath().c_str());
|
||||
for(auto &i: report.rawReport())
|
||||
printf("%02x ", i);
|
||||
printf("\n");
|
||||
for(auto& handler : hidpp_event_handlers)
|
||||
if(handler.second->condition(report))
|
||||
handler.second->callback(report);
|
||||
}
|
||||
|
||||
void Receiver::addDjEventHandler(const std::string& nickname,
|
||||
const std::shared_ptr<EventHandler>& handler)
|
||||
{
|
||||
auto it = dj_event_handlers.find(nickname);
|
||||
assert(it == dj_event_handlers.end());
|
||||
dj_event_handlers.emplace(nickname, handler);
|
||||
}
|
||||
|
||||
void Receiver::removeDjEventHandler(const std::string &nickname)
|
||||
{
|
||||
dj_event_handlers.erase(nickname);
|
||||
}
|
||||
|
||||
const std::map<std::string, std::shared_ptr<EventHandler>>&
|
||||
Receiver::djEventHandlers()
|
||||
{
|
||||
return dj_event_handlers;
|
||||
}
|
||||
|
||||
void Receiver::addHidppEventHandler(const std::string& nickname,
|
||||
const std::shared_ptr<hidpp::EventHandler>& handler)
|
||||
{
|
||||
auto it = hidpp_event_handlers.find(nickname);
|
||||
assert(it == hidpp_event_handlers.end());
|
||||
hidpp_event_handlers.emplace(nickname, handler);
|
||||
}
|
||||
|
||||
void Receiver::removeHidppEventHandler(const std::string &nickname)
|
||||
{
|
||||
hidpp_event_handlers.erase(nickname);
|
||||
}
|
||||
|
||||
const std::map<std::string, std::shared_ptr<hidpp::EventHandler>>&
|
||||
Receiver::hidppEventHandlers()
|
||||
{
|
||||
return hidpp_event_handlers;
|
||||
}
|
||||
|
||||
void Receiver::sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
|
||||
@@ -276,10 +295,56 @@ void Receiver::sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
|
||||
|
||||
void Receiver::listen()
|
||||
{
|
||||
std::thread{[=]() { raw_device->listen(); }}.detach();
|
||||
if(!raw_device->isListening())
|
||||
std::thread{[=]() { raw_device->listen(); }}.detach();
|
||||
|
||||
if(raw_device->eventHandlers().find("RECV_HIDPP") ==
|
||||
raw_device->eventHandlers().end()) {
|
||||
// Pass all HID++ events on DefaultDevice to handleHidppEvent
|
||||
std::shared_ptr<RawEventHandler> hidppRawEventHandler =
|
||||
std::make_shared<RawEventHandler>();
|
||||
hidppRawEventHandler->condition = [](std::vector<uint8_t>& report)->bool
|
||||
{
|
||||
return (report[hidpp::Offset::Type] == hidpp::Report::Type::Short ||
|
||||
report[hidpp::Offset::Type] == hidpp::Report::Type::Long);
|
||||
};
|
||||
hidppRawEventHandler->callback = [this](std::vector<uint8_t>& report)->void
|
||||
{
|
||||
hidpp::Report _report(report);
|
||||
this->handleHidppEvent(_report);
|
||||
};
|
||||
raw_device->addEventHandler("RECV_HIDPP", hidppRawEventHandler);
|
||||
}
|
||||
|
||||
if(raw_device->eventHandlers().find("RECV_DJ") ==
|
||||
raw_device->eventHandlers().end()) {
|
||||
// Pass all DJ events with device index to handleHidppEvent
|
||||
std::shared_ptr<RawEventHandler> djRawEventHandler =
|
||||
std::make_shared<RawEventHandler>();
|
||||
djRawEventHandler->condition = [](std::vector<uint8_t>& report)->bool
|
||||
{
|
||||
return (report[Offset::Type] == Report::Type::Short ||
|
||||
report[Offset::Type] == Report::Type::Long);
|
||||
};
|
||||
djRawEventHandler->callback = [this](std::vector<uint8_t>& report)->void
|
||||
{
|
||||
Report _report(report);
|
||||
this->handleDjEvent(_report);
|
||||
};
|
||||
raw_device->addEventHandler("RECV_DJ", djRawEventHandler);
|
||||
}
|
||||
}
|
||||
|
||||
void Receiver::stopListening()
|
||||
{
|
||||
raw_device->stopListener();
|
||||
raw_device->removeEventHandler("RECV_HIDPP");
|
||||
raw_device->removeEventHandler("RECV_DJ");
|
||||
|
||||
if(raw_device->eventHandlers().empty())
|
||||
raw_device->stopListener();
|
||||
}
|
||||
|
||||
std::shared_ptr<raw::RawDevice> Receiver::rawDevice() const
|
||||
{
|
||||
return raw_device;
|
||||
}
|
@@ -11,6 +11,12 @@ namespace logid {
|
||||
namespace backend {
|
||||
namespace dj
|
||||
{
|
||||
struct EventHandler
|
||||
{
|
||||
std::function<bool(Report&)> condition;
|
||||
std::function<void(Report&)> callback;
|
||||
};
|
||||
|
||||
class InvalidReceiver : public std::exception
|
||||
{
|
||||
public:
|
||||
@@ -43,7 +49,7 @@ namespace dj
|
||||
GetPairedDevices = 0x81
|
||||
};
|
||||
|
||||
void enumerate();
|
||||
void enumerateDj();
|
||||
|
||||
/* The following functions deal with HID++ 1.0 features.
|
||||
* While these are not technically DJ functions, it is redundant
|
||||
@@ -77,7 +83,7 @@ namespace dj
|
||||
notification_flags getHidppNotifications();
|
||||
void enableHidppNotifications(notification_flags flags);
|
||||
|
||||
///TODO: Understand output of this function
|
||||
void enumerateHidpp();
|
||||
uint8_t getConnectionState(hidpp::DeviceIndex index);
|
||||
|
||||
void startPairing(uint8_t timeout = 0);
|
||||
@@ -107,35 +113,57 @@ namespace dj
|
||||
|
||||
std::string getDeviceName(hidpp::DeviceIndex index);
|
||||
|
||||
struct DeviceConnectionEvent
|
||||
{
|
||||
hidpp::DeviceIndex index;
|
||||
uint16_t pid;
|
||||
DeviceType::DeviceType deviceType;
|
||||
bool unifying;
|
||||
bool softwarePresent;
|
||||
bool encrypted;
|
||||
bool linkEstablished;
|
||||
bool withPayload;
|
||||
};
|
||||
|
||||
static hidpp::DeviceIndex deviceDisconnectionEvent(
|
||||
hidpp::Report& report);
|
||||
static DeviceConnectionEvent deviceConnectionEvent(
|
||||
static hidpp::DeviceConnectionEvent deviceConnectionEvent(
|
||||
hidpp::Report& report);
|
||||
|
||||
void handleDjEvent(dj::Report& report);
|
||||
void handleHidppEvent(hidpp::Report& report);
|
||||
|
||||
void listen();
|
||||
void stopListening();
|
||||
|
||||
void addDjEventHandler(const std::string& nickname,
|
||||
const std::shared_ptr<EventHandler>& handler);
|
||||
void removeDjEventHandler(const std::string& nickname);
|
||||
const std::map<std::string, std::shared_ptr<EventHandler>>&
|
||||
djEventHandlers();
|
||||
|
||||
void addHidppEventHandler(const std::string& nickname,
|
||||
const std::shared_ptr<hidpp::EventHandler>& handler);
|
||||
void removeHidppEventHandler(const std::string& nickname);
|
||||
const std::map<std::string, std::shared_ptr<hidpp::EventHandler>>&
|
||||
hidppEventHandlers();
|
||||
|
||||
std::shared_ptr<raw::RawDevice> rawDevice() const;
|
||||
private:
|
||||
void sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
|
||||
const std::vector<uint8_t>&& params);
|
||||
|
||||
void handleDjEvent(dj::Report& report);
|
||||
void handleHidppEvent(hidpp::Report& report);
|
||||
|
||||
std::map<std::string, std::shared_ptr<EventHandler>>
|
||||
dj_event_handlers;
|
||||
std::map<std::string, std::shared_ptr<hidpp::EventHandler>>
|
||||
hidpp_event_handlers;
|
||||
|
||||
std::shared_ptr<raw::RawDevice> raw_device;
|
||||
hidpp10::Device _hidpp10_device;
|
||||
};
|
||||
}
|
||||
|
||||
namespace hidpp
|
||||
{
|
||||
struct DeviceConnectionEvent
|
||||
{
|
||||
hidpp::DeviceIndex index;
|
||||
uint16_t pid;
|
||||
dj::DeviceType::DeviceType deviceType;
|
||||
bool unifying;
|
||||
bool softwarePresent;
|
||||
bool encrypted;
|
||||
bool linkEstablished;
|
||||
bool withPayload;
|
||||
};
|
||||
}}}
|
||||
|
||||
#endif //LOGID_BACKEND_DJ_RECEIVER_H
|
@@ -1,30 +1,70 @@
|
||||
#include "ReceiverMonitor.h"
|
||||
|
||||
#include <utility>
|
||||
#include <cassert>
|
||||
|
||||
using namespace logid::backend::dj;
|
||||
|
||||
ReceiverMonitor::ReceiverMonitor(std::string path) : _reciever (std::move(path))
|
||||
ReceiverMonitor::ReceiverMonitor(std::string path) : _receiver (
|
||||
std::make_shared<Receiver>(std::move(path)))
|
||||
{
|
||||
assert(_receiver->hidppEventHandlers().find("RECVMON") ==
|
||||
_receiver->hidppEventHandlers().end());
|
||||
assert(_receiver->djEventHandlers().find("RECVMON") ==
|
||||
_receiver->djEventHandlers().end());
|
||||
|
||||
Receiver::notification_flags notification_flags{
|
||||
true,
|
||||
true,
|
||||
true};
|
||||
_reciever.enableHidppNotifications(notification_flags);
|
||||
_receiver->enableHidppNotifications(notification_flags);
|
||||
}
|
||||
|
||||
void ReceiverMonitor::run()
|
||||
{
|
||||
_reciever.listen();
|
||||
_receiver->listen();
|
||||
|
||||
if(_receiver->hidppEventHandlers().find("RECVMON") ==
|
||||
_receiver->hidppEventHandlers().end())
|
||||
{
|
||||
std::shared_ptr<hidpp::EventHandler> eventHandler =
|
||||
std::make_shared<hidpp::EventHandler>();
|
||||
eventHandler->condition = [](hidpp::Report &report) -> bool {
|
||||
return (report.subId() == Receiver::DeviceConnection ||
|
||||
report.subId() == Receiver::DeviceDisconnection);
|
||||
};
|
||||
|
||||
eventHandler->callback = [this](hidpp::Report &report) -> void {
|
||||
/* Running in a new thread prevents deadlocks since the
|
||||
* receiver may be enumerating.
|
||||
*/
|
||||
std::thread{[this](hidpp::Report report) {
|
||||
if (report.subId() == Receiver::DeviceConnection)
|
||||
this->addDevice(this->_receiver->deviceConnectionEvent(
|
||||
report));
|
||||
else if (report.subId() == Receiver::DeviceDisconnection)
|
||||
this->removeDevice(this->_receiver->
|
||||
deviceDisconnectionEvent(report));
|
||||
}, report}.detach();
|
||||
};
|
||||
|
||||
_receiver->addHidppEventHandler("RECVMON", eventHandler);
|
||||
}
|
||||
|
||||
enumerate();
|
||||
}
|
||||
|
||||
void ReceiverMonitor::stop()
|
||||
{
|
||||
_reciever.stopListening();
|
||||
_receiver->stopListening();
|
||||
}
|
||||
|
||||
void ReceiverMonitor::enumerate()
|
||||
{
|
||||
_reciever.enumerate();
|
||||
_receiver->enumerateHidpp();
|
||||
}
|
||||
|
||||
std::shared_ptr<Receiver> ReceiverMonitor::receiver() const
|
||||
{
|
||||
return _receiver;
|
||||
}
|
@@ -21,7 +21,7 @@ namespace dj
|
||||
void stop();
|
||||
|
||||
protected:
|
||||
virtual void addDevice(hidpp::DeviceIndex index, uint16_t pid) = 0;
|
||||
virtual void addDevice(hidpp::DeviceConnectionEvent event) = 0;
|
||||
virtual void removeDevice(hidpp::DeviceIndex index) = 0;
|
||||
|
||||
// Internal methods for derived class
|
||||
@@ -29,8 +29,10 @@ namespace dj
|
||||
void _stopPairing();
|
||||
|
||||
void _unpair();
|
||||
|
||||
std::shared_ptr<Receiver> receiver() const;
|
||||
private:
|
||||
Receiver _reciever;
|
||||
std::shared_ptr<Receiver> _receiver;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
Reference in New Issue
Block a user