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:
parent
b05e525bbc
commit
e40da5f0c0
|
@ -27,7 +27,9 @@ add_executable(logid
|
||||||
backend/hidpp20/Device.cpp
|
backend/hidpp20/Device.cpp
|
||||||
backend/hidpp20/Error.cpp
|
backend/hidpp20/Error.cpp
|
||||||
backend/hidpp20/Feature.cpp
|
backend/hidpp20/Feature.cpp
|
||||||
|
backend/hidpp20/EssentialFeature.cpp
|
||||||
backend/hidpp20/features/Root.cpp
|
backend/hidpp20/features/Root.cpp
|
||||||
|
backend/hidpp20/features/DeviceName.cpp
|
||||||
backend/dj/Report.cpp
|
backend/dj/Report.cpp
|
||||||
util/mutex_queue.h)
|
util/mutex_queue.h)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "Device.h"
|
#include "Device.h"
|
||||||
|
|
||||||
using namespace logid;
|
using namespace logid;
|
||||||
|
using namespace logid::backend;
|
||||||
|
|
||||||
Device::Device(std::string path, backend::hidpp::DeviceIndex index) :
|
Device::Device(std::string path, backend::hidpp::DeviceIndex index) :
|
||||||
_hidpp20 (path, index), _path (path), _index (index)
|
_hidpp20 (path, index), _path (path), _index (index)
|
||||||
|
@ -9,6 +10,13 @@ Device::Device(std::string path, backend::hidpp::DeviceIndex index) :
|
||||||
log_printf(DEBUG, "logid::Device created on %s:%d", _path.c_str(), _index);
|
log_printf(DEBUG, "logid::Device created on %s:%d", _path.c_str(), _index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Device::Device(const std::shared_ptr<backend::raw::RawDevice>& raw_device,
|
||||||
|
hidpp::DeviceIndex index) : _hidpp20(raw_device, index), _path
|
||||||
|
(raw_device->hidrawPath()), _index (index)
|
||||||
|
{
|
||||||
|
log_printf(DEBUG, "logid::Device created on %s:%d", _path.c_str(), _index);
|
||||||
|
}
|
||||||
|
|
||||||
void Device::sleep()
|
void Device::sleep()
|
||||||
{
|
{
|
||||||
log_printf(INFO, "%s:%d fell asleep.", _path.c_str(), _index);
|
log_printf(INFO, "%s:%d fell asleep.", _path.c_str(), _index);
|
||||||
|
|
|
@ -14,6 +14,8 @@ namespace logid
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Device(std::string path, backend::hidpp::DeviceIndex index);
|
Device(std::string path, backend::hidpp::DeviceIndex index);
|
||||||
|
Device(const std::shared_ptr<backend::raw::RawDevice>& raw_device,
|
||||||
|
backend::hidpp::DeviceIndex index);
|
||||||
void wakeup();
|
void wakeup();
|
||||||
void sleep();
|
void sleep();
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -33,6 +33,7 @@ void DeviceManager::addDevice(std::string path)
|
||||||
if(isReceiver) {
|
if(isReceiver) {
|
||||||
log_printf(INFO, "Detected receiver at %s", path.c_str());
|
log_printf(INFO, "Detected receiver at %s", path.c_str());
|
||||||
auto receiver = std::make_shared<Receiver>(path);
|
auto receiver = std::make_shared<Receiver>(path);
|
||||||
|
receiver->run();
|
||||||
_receivers.emplace(path, receiver);
|
_receivers.emplace(path, receiver);
|
||||||
} else {
|
} else {
|
||||||
/* TODO: Error check?
|
/* TODO: Error check?
|
||||||
|
@ -48,6 +49,9 @@ void DeviceManager::addDevice(std::string path)
|
||||||
} catch(hidpp10::Error &e) {
|
} catch(hidpp10::Error &e) {
|
||||||
if(e.code() != hidpp10::Error::UnknownDevice)
|
if(e.code() != hidpp10::Error::UnknownDevice)
|
||||||
throw;
|
throw;
|
||||||
|
else
|
||||||
|
log_printf(WARN, "HID++ 1.0 error while trying to initialize"
|
||||||
|
" %s: %s", path.c_str(), e.what());
|
||||||
} catch(hidpp::Device::InvalidDevice &e) { // Ignore
|
} catch(hidpp::Device::InvalidDevice &e) { // Ignore
|
||||||
} catch(std::system_error &e) {
|
} catch(std::system_error &e) {
|
||||||
// This error should have been thrown previously
|
// This error should have been thrown previously
|
||||||
|
|
|
@ -1,9 +1,50 @@
|
||||||
|
#include <cassert>
|
||||||
#include "Receiver.h"
|
#include "Receiver.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "backend/hidpp10/Error.h"
|
||||||
|
#include "backend/hidpp20/Error.h"
|
||||||
|
|
||||||
using namespace logid;
|
using namespace logid;
|
||||||
|
using namespace logid::backend;
|
||||||
|
|
||||||
Receiver::Receiver(std::string path) : _path (path)
|
Receiver::Receiver(std::string path) : dj::ReceiverMonitor(path)
|
||||||
{
|
{
|
||||||
log_printf(DEBUG, "logid::Receiver created on %s", path.c_str());
|
log_printf(DEBUG, "logid::Receiver created on %s", path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Receiver::addDevice(hidpp::DeviceConnectionEvent event)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if(!event.linkEstablished)
|
||||||
|
return; // Device is probably asleep, wait until it wakes up
|
||||||
|
|
||||||
|
hidpp::Device hidpp_device(receiver(), event);
|
||||||
|
|
||||||
|
auto version = hidpp_device.version();
|
||||||
|
|
||||||
|
if(std::get<0>(version) < 2) {
|
||||||
|
log_printf(INFO, "Unsupported HID++ 1.0 device on %s:%d connected.",
|
||||||
|
_path.c_str(), event.index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Device> device = std::make_shared<Device>(
|
||||||
|
receiver()->rawDevice(), event.index);
|
||||||
|
|
||||||
|
assert(_devices.find(event.index) == _devices.end());
|
||||||
|
|
||||||
|
_devices.emplace(event.index, device);
|
||||||
|
|
||||||
|
} catch(hidpp10::Error &e) {
|
||||||
|
log_printf(ERROR, "Caught HID++ 1.0 error while trying to initialize "
|
||||||
|
"%s:%d: %s", _path.c_str(), event.index, e.what());
|
||||||
|
} catch(hidpp20::Error &e) {
|
||||||
|
log_printf(ERROR, "Caught HID++ 2.0 error while trying to initialize "
|
||||||
|
"%s:%d: %s", _path.c_str(), event.index, e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Receiver::removeDevice(hidpp::DeviceIndex index)
|
||||||
|
{
|
||||||
|
_devices.erase(index);
|
||||||
|
}
|
|
@ -2,14 +2,21 @@
|
||||||
#define LOGID_RECEIVER_H
|
#define LOGID_RECEIVER_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "backend/dj/ReceiverMonitor.h"
|
||||||
|
#include "Device.h"
|
||||||
|
|
||||||
namespace logid
|
namespace logid
|
||||||
{
|
{
|
||||||
class Receiver
|
class Receiver : public backend::dj::ReceiverMonitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Receiver(std::string path);
|
Receiver(std::string path);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void addDevice(backend::hidpp::DeviceConnectionEvent event);
|
||||||
|
virtual void removeDevice(backend::hidpp::DeviceIndex index);
|
||||||
private:
|
private:
|
||||||
|
std::map<backend::hidpp::DeviceIndex, std::shared_ptr<Device>> _devices;
|
||||||
std::string _path;
|
std::string _path;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,47 +32,17 @@ Receiver::Receiver(std::string path) :
|
||||||
{
|
{
|
||||||
if(!supportsDjReports(raw_device->reportDescriptor()))
|
if(!supportsDjReports(raw_device->reportDescriptor()))
|
||||||
throw InvalidReceiver(InvalidReceiver::NoDJReports);
|
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,{});
|
sendDjRequest(hidpp::DefaultDevice, GetPairedDevices,{});
|
||||||
}
|
}
|
||||||
|
|
||||||
Receiver::notification_flags Receiver::getHidppNotifications()
|
Receiver::notification_flags Receiver::getHidppNotifications()
|
||||||
{
|
{
|
||||||
auto response = _hidpp10_device.getRegister(EnableHidppNotifications, {});
|
auto response = _hidpp10_device.getRegister(EnableHidppNotifications, {},
|
||||||
|
hidpp::ReportType::Short);
|
||||||
|
|
||||||
notification_flags flags{};
|
notification_flags flags{};
|
||||||
flags.device_battery_status = response[0] & (1 << 4);
|
flags.device_battery_status = response[0] & (1 << 4);
|
||||||
|
@ -89,17 +59,28 @@ void Receiver::enableHidppNotifications(notification_flags flags)
|
||||||
if(flags.device_battery_status)
|
if(flags.device_battery_status)
|
||||||
request[0] |= (1 << 4);
|
request[0] |= (1 << 4);
|
||||||
if(flags.receiver_wireless_notifications)
|
if(flags.receiver_wireless_notifications)
|
||||||
request[1] |= (1 << 0);
|
request[1] |= 1;
|
||||||
if(flags.receiver_software_present)
|
if(flags.receiver_software_present)
|
||||||
request[1] |= (1 << 3);
|
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
|
///TODO: Investigate usage
|
||||||
uint8_t Receiver::getConnectionState(hidpp::DeviceIndex index)
|
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];
|
return response[0];
|
||||||
}
|
}
|
||||||
|
@ -113,7 +94,8 @@ void Receiver::startPairing(uint8_t timeout)
|
||||||
request[1] = hidpp::DefaultDevice;
|
request[1] = hidpp::DefaultDevice;
|
||||||
request[2] = timeout;
|
request[2] = timeout;
|
||||||
|
|
||||||
_hidpp10_device.setRegister(DevicePairing, request);
|
_hidpp10_device.setRegister(DevicePairing, request,
|
||||||
|
hidpp::ReportType::Short);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Receiver::stopPairing()
|
void Receiver::stopPairing()
|
||||||
|
@ -124,7 +106,8 @@ void Receiver::stopPairing()
|
||||||
request[0] = 2;
|
request[0] = 2;
|
||||||
request[1] = hidpp::DefaultDevice;
|
request[1] = hidpp::DefaultDevice;
|
||||||
|
|
||||||
_hidpp10_device.setRegister(DevicePairing, request);
|
_hidpp10_device.setRegister(DevicePairing, request,
|
||||||
|
hidpp::ReportType::Short);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Receiver::disconnect(hidpp::DeviceIndex index)
|
void Receiver::disconnect(hidpp::DeviceIndex index)
|
||||||
|
@ -135,12 +118,14 @@ void Receiver::disconnect(hidpp::DeviceIndex index)
|
||||||
request[0] = 3;
|
request[0] = 3;
|
||||||
request[1] = index;
|
request[1] = index;
|
||||||
|
|
||||||
_hidpp10_device.setRegister(DevicePairing, request);
|
_hidpp10_device.setRegister(DevicePairing, request,
|
||||||
|
hidpp::ReportType::Short);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<hidpp::DeviceIndex, uint8_t> Receiver::getDeviceActivity()
|
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;
|
std::map<hidpp::DeviceIndex, uint8_t> device_activity;
|
||||||
for(uint8_t i = hidpp::WirelessDevice1; i <= hidpp::WirelessDevice6; i++)
|
for(uint8_t i = hidpp::WirelessDevice1; i <= hidpp::WirelessDevice6; i++)
|
||||||
|
@ -156,7 +141,8 @@ struct Receiver::PairingInfo
|
||||||
request[0] = index;
|
request[0] = index;
|
||||||
request[0] += 0x19;
|
request[0] += 0x19;
|
||||||
|
|
||||||
auto response = _hidpp10_device.getRegister(PairingInfo, request);
|
auto response = _hidpp10_device.getRegister(PairingInfo, request,
|
||||||
|
hidpp::ReportType::Long);
|
||||||
|
|
||||||
struct PairingInfo info{};
|
struct PairingInfo info{};
|
||||||
info.destinationId = response[0];
|
info.destinationId = response[0];
|
||||||
|
@ -175,7 +161,8 @@ struct Receiver::ExtendedPairingInfo
|
||||||
request[0] = index;
|
request[0] = index;
|
||||||
request[0] += 0x29;
|
request[0] += 0x29;
|
||||||
|
|
||||||
auto response = _hidpp10_device.getRegister(PairingInfo, request);
|
auto response = _hidpp10_device.getRegister(PairingInfo, request,
|
||||||
|
hidpp::ReportType::Long);
|
||||||
|
|
||||||
ExtendedPairingInfo info{};
|
ExtendedPairingInfo info{};
|
||||||
|
|
||||||
|
@ -197,7 +184,8 @@ std::string Receiver::getDeviceName(hidpp::DeviceIndex index)
|
||||||
request[0] = index;
|
request[0] = index;
|
||||||
request[0] += 0x39;
|
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];
|
uint8_t size = response[0];
|
||||||
assert(size <= 14);
|
assert(size <= 14);
|
||||||
|
@ -215,12 +203,12 @@ hidpp::DeviceIndex Receiver::deviceDisconnectionEvent(hidpp::Report& report)
|
||||||
return report.deviceIndex();
|
return report.deviceIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
Receiver::DeviceConnectionEvent Receiver::deviceConnectionEvent(
|
hidpp::DeviceConnectionEvent Receiver::deviceConnectionEvent(
|
||||||
hidpp::Report &report)
|
hidpp::Report &report)
|
||||||
{
|
{
|
||||||
assert(report.subId() == DeviceConnection);
|
assert(report.subId() == DeviceConnection);
|
||||||
|
|
||||||
DeviceConnectionEvent event{};
|
hidpp::DeviceConnectionEvent event{};
|
||||||
|
|
||||||
event.index = report.deviceIndex();
|
event.index = report.deviceIndex();
|
||||||
event.unifying = ((report.paramBegin()[0] & 0b111) == 0x04);
|
event.unifying = ((report.paramBegin()[0] & 0b111) == 0x04);
|
||||||
|
@ -240,23 +228,54 @@ Receiver::DeviceConnectionEvent Receiver::deviceConnectionEvent(
|
||||||
|
|
||||||
void Receiver::handleDjEvent(Report& report)
|
void Receiver::handleDjEvent(Report& report)
|
||||||
{
|
{
|
||||||
if(report.feature() == DeviceConnection ||
|
for(auto& handler : dj_event_handlers)
|
||||||
report.feature() == DeviceDisconnection ||
|
if(handler.second->condition(report))
|
||||||
report.feature() == ConnectionStatus)
|
handler.second->callback(report);
|
||||||
{
|
|
||||||
printf("%s DJ IN: ", raw_device->hidrawPath().c_str());
|
|
||||||
for(auto &i: report.rawData())
|
|
||||||
printf("%02x ", i);
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Receiver::handleHidppEvent(hidpp::Report &report)
|
void Receiver::handleHidppEvent(hidpp::Report &report)
|
||||||
{
|
{
|
||||||
printf("%s HID++ IN: ", raw_device->hidrawPath().c_str());
|
for(auto& handler : hidpp_event_handlers)
|
||||||
for(auto &i: report.rawReport())
|
if(handler.second->condition(report))
|
||||||
printf("%02x ", i);
|
handler.second->callback(report);
|
||||||
printf("\n");
|
}
|
||||||
|
|
||||||
|
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,
|
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()
|
void Receiver::listen()
|
||||||
{
|
{
|
||||||
|
if(!raw_device->isListening())
|
||||||
std::thread{[=]() { raw_device->listen(); }}.detach();
|
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()
|
void Receiver::stopListening()
|
||||||
{
|
{
|
||||||
|
raw_device->removeEventHandler("RECV_HIDPP");
|
||||||
|
raw_device->removeEventHandler("RECV_DJ");
|
||||||
|
|
||||||
|
if(raw_device->eventHandlers().empty())
|
||||||
raw_device->stopListener();
|
raw_device->stopListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<raw::RawDevice> Receiver::rawDevice() const
|
||||||
|
{
|
||||||
|
return raw_device;
|
||||||
|
}
|
|
@ -11,6 +11,12 @@ namespace logid {
|
||||||
namespace backend {
|
namespace backend {
|
||||||
namespace dj
|
namespace dj
|
||||||
{
|
{
|
||||||
|
struct EventHandler
|
||||||
|
{
|
||||||
|
std::function<bool(Report&)> condition;
|
||||||
|
std::function<void(Report&)> callback;
|
||||||
|
};
|
||||||
|
|
||||||
class InvalidReceiver : public std::exception
|
class InvalidReceiver : public std::exception
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -43,7 +49,7 @@ namespace dj
|
||||||
GetPairedDevices = 0x81
|
GetPairedDevices = 0x81
|
||||||
};
|
};
|
||||||
|
|
||||||
void enumerate();
|
void enumerateDj();
|
||||||
|
|
||||||
/* The following functions deal with HID++ 1.0 features.
|
/* The following functions deal with HID++ 1.0 features.
|
||||||
* While these are not technically DJ functions, it is redundant
|
* While these are not technically DJ functions, it is redundant
|
||||||
|
@ -77,7 +83,7 @@ namespace dj
|
||||||
notification_flags getHidppNotifications();
|
notification_flags getHidppNotifications();
|
||||||
void enableHidppNotifications(notification_flags flags);
|
void enableHidppNotifications(notification_flags flags);
|
||||||
|
|
||||||
///TODO: Understand output of this function
|
void enumerateHidpp();
|
||||||
uint8_t getConnectionState(hidpp::DeviceIndex index);
|
uint8_t getConnectionState(hidpp::DeviceIndex index);
|
||||||
|
|
||||||
void startPairing(uint8_t timeout = 0);
|
void startPairing(uint8_t timeout = 0);
|
||||||
|
@ -107,35 +113,57 @@ namespace dj
|
||||||
|
|
||||||
std::string getDeviceName(hidpp::DeviceIndex index);
|
std::string getDeviceName(hidpp::DeviceIndex index);
|
||||||
|
|
||||||
|
static hidpp::DeviceIndex deviceDisconnectionEvent(
|
||||||
|
hidpp::Report& report);
|
||||||
|
static hidpp::DeviceConnectionEvent deviceConnectionEvent(
|
||||||
|
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
|
struct DeviceConnectionEvent
|
||||||
{
|
{
|
||||||
hidpp::DeviceIndex index;
|
hidpp::DeviceIndex index;
|
||||||
uint16_t pid;
|
uint16_t pid;
|
||||||
DeviceType::DeviceType deviceType;
|
dj::DeviceType::DeviceType deviceType;
|
||||||
bool unifying;
|
bool unifying;
|
||||||
bool softwarePresent;
|
bool softwarePresent;
|
||||||
bool encrypted;
|
bool encrypted;
|
||||||
bool linkEstablished;
|
bool linkEstablished;
|
||||||
bool withPayload;
|
bool withPayload;
|
||||||
};
|
};
|
||||||
|
|
||||||
static hidpp::DeviceIndex deviceDisconnectionEvent(
|
|
||||||
hidpp::Report& report);
|
|
||||||
static DeviceConnectionEvent deviceConnectionEvent(
|
|
||||||
hidpp::Report& report);
|
|
||||||
|
|
||||||
void handleDjEvent(dj::Report& report);
|
|
||||||
void handleHidppEvent(hidpp::Report& report);
|
|
||||||
|
|
||||||
void listen();
|
|
||||||
void stopListening();
|
|
||||||
private:
|
|
||||||
void sendDjRequest(hidpp::DeviceIndex index, uint8_t function,
|
|
||||||
const std::vector<uint8_t>&& params);
|
|
||||||
|
|
||||||
std::shared_ptr<raw::RawDevice> raw_device;
|
|
||||||
hidpp10::Device _hidpp10_device;
|
|
||||||
};
|
|
||||||
}}}
|
}}}
|
||||||
|
|
||||||
#endif //LOGID_BACKEND_DJ_RECEIVER_H
|
#endif //LOGID_BACKEND_DJ_RECEIVER_H
|
|
@ -1,30 +1,70 @@
|
||||||
#include "ReceiverMonitor.h"
|
#include "ReceiverMonitor.h"
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
using namespace logid::backend::dj;
|
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{
|
Receiver::notification_flags notification_flags{
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
true};
|
true};
|
||||||
_reciever.enableHidppNotifications(notification_flags);
|
_receiver->enableHidppNotifications(notification_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiverMonitor::run()
|
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();
|
enumerate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiverMonitor::stop()
|
void ReceiverMonitor::stop()
|
||||||
{
|
{
|
||||||
_reciever.stopListening();
|
_receiver->stopListening();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiverMonitor::enumerate()
|
void ReceiverMonitor::enumerate()
|
||||||
{
|
{
|
||||||
_reciever.enumerate();
|
_receiver->enumerateHidpp();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Receiver> ReceiverMonitor::receiver() const
|
||||||
|
{
|
||||||
|
return _receiver;
|
||||||
}
|
}
|
|
@ -21,7 +21,7 @@ namespace dj
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
protected:
|
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;
|
virtual void removeDevice(hidpp::DeviceIndex index) = 0;
|
||||||
|
|
||||||
// Internal methods for derived class
|
// Internal methods for derived class
|
||||||
|
@ -29,8 +29,10 @@ namespace dj
|
||||||
void _stopPairing();
|
void _stopPairing();
|
||||||
|
|
||||||
void _unpair();
|
void _unpair();
|
||||||
|
|
||||||
|
std::shared_ptr<Receiver> receiver() const;
|
||||||
private:
|
private:
|
||||||
Receiver _reciever;
|
std::shared_ptr<Receiver> _receiver;
|
||||||
};
|
};
|
||||||
|
|
||||||
}}}
|
}}}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
#include <assert.h>
|
#include <cassert>
|
||||||
|
#include <utility>
|
||||||
#include "Device.h"
|
#include "Device.h"
|
||||||
#include "Report.h"
|
#include "Report.h"
|
||||||
#include "../hidpp20/features/Root.h"
|
#include "../hidpp20/features/Root.h"
|
||||||
|
#include "../hidpp20/features/DeviceName.h"
|
||||||
#include "../hidpp20/Error.h"
|
#include "../hidpp20/Error.h"
|
||||||
#include "../hidpp10/Error.h"
|
#include "../hidpp10/Error.h"
|
||||||
|
#include "../dj/Receiver.h"
|
||||||
|
|
||||||
using namespace logid::backend;
|
using namespace logid::backend;
|
||||||
using namespace logid::backend::hidpp;
|
using namespace logid::backend::hidpp;
|
||||||
|
@ -16,6 +19,10 @@ const char* Device::InvalidDevice::what() const noexcept
|
||||||
return "Invalid HID++ device";
|
return "Invalid HID++ device";
|
||||||
case InvalidRawDevice:
|
case InvalidRawDevice:
|
||||||
return "Invalid raw device";
|
return "Invalid raw device";
|
||||||
|
case Asleep:
|
||||||
|
return "Device asleep";
|
||||||
|
default:
|
||||||
|
return "Invalid device";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,36 +33,41 @@ Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept
|
||||||
|
|
||||||
/// TODO: Initialize a single RawDevice for each path.
|
/// TODO: Initialize a single RawDevice for each path.
|
||||||
Device::Device(const std::string& path, DeviceIndex index):
|
Device::Device(const std::string& path, DeviceIndex index):
|
||||||
raw_device (std::make_shared<raw::RawDevice>(path)), path (path),
|
_raw_device (std::make_shared<raw::RawDevice>(path)), _receiver (nullptr),
|
||||||
_index (index)
|
_path (path), _index (index)
|
||||||
{
|
{
|
||||||
_init();
|
_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index) :
|
Device::Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index) :
|
||||||
raw_device (raw_device), _index (index)
|
_raw_device (std::move(raw_device)), _receiver (nullptr),
|
||||||
|
_path (_raw_device->hidrawPath()), _index (index)
|
||||||
{
|
{
|
||||||
_init();
|
_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Device::Device(std::shared_ptr<dj::Receiver> receiver,
|
||||||
|
hidpp::DeviceConnectionEvent event) :
|
||||||
|
_raw_device (receiver->rawDevice()), _index (event.index)
|
||||||
|
{
|
||||||
|
// Device will throw an error soon, just do it now
|
||||||
|
if(!event.linkEstablished)
|
||||||
|
throw InvalidDevice(InvalidDevice::Asleep);
|
||||||
|
|
||||||
|
_pid = event.pid;
|
||||||
|
_init();
|
||||||
|
}
|
||||||
|
|
||||||
void Device::_init()
|
void Device::_init()
|
||||||
{
|
{
|
||||||
supported_reports = getSupportedReports(raw_device->reportDescriptor());
|
supported_reports = getSupportedReports(_raw_device->reportDescriptor());
|
||||||
if(!supported_reports)
|
if(!supported_reports)
|
||||||
throw InvalidDevice(InvalidDevice::NoHIDPPReport);
|
throw InvalidDevice(InvalidDevice::NoHIDPPReport);
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
hidpp20::EssentialRoot root(this);
|
||||||
Report versionRequest(Report::Type::Short, _index,
|
_version = root.getVersion();
|
||||||
hidpp20::FeatureID::ROOT,hidpp20::Root::Ping,
|
} catch(hidpp10::Error &e) {
|
||||||
LOGID_HIDPP_SOFTWARE_ID);
|
|
||||||
|
|
||||||
auto versionResponse = sendReport(versionRequest);
|
|
||||||
auto versionResponse_params = versionResponse.paramBegin();
|
|
||||||
_version = std::make_tuple(versionResponse_params[0], versionResponse_params[1]);
|
|
||||||
}
|
|
||||||
catch(hidpp10::Error &e)
|
|
||||||
{
|
|
||||||
// Valid HID++ 1.0 devices should send an InvalidSubID error
|
// Valid HID++ 1.0 devices should send an InvalidSubID error
|
||||||
if(e.code() != hidpp10::Error::InvalidSubID)
|
if(e.code() != hidpp10::Error::InvalidSubID)
|
||||||
throw;
|
throw;
|
||||||
|
@ -64,29 +76,30 @@ void Device::_init()
|
||||||
_version = std::make_tuple(1, 0);
|
_version = std::make_tuple(1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass all HID++ events with device index to this device.
|
if(!_receiver) {
|
||||||
RawEventHandler rawEventHandler;
|
_pid = _raw_device->productId();
|
||||||
rawEventHandler.condition = [this](std::vector<uint8_t>& report)->bool
|
if(std::get<0>(_version) >= 2) {
|
||||||
{
|
try {
|
||||||
return (report[Offset::Type] == Report::Type::Short ||
|
hidpp20::EssentialDeviceName deviceName(this);
|
||||||
report[Offset::Type] == Report::Type::Long) &&
|
_name = deviceName.getName();
|
||||||
(report[Offset::DeviceIndex] == this->_index);
|
} catch(hidpp20::UnsupportedFeature &e) {
|
||||||
};
|
_name = _raw_device->name();
|
||||||
rawEventHandler.callback = [this](std::vector<uint8_t>& report)->void
|
}
|
||||||
{
|
} else {
|
||||||
Report _report(report);
|
_name = _raw_device->name();
|
||||||
this->handleEvent(_report);
|
}
|
||||||
};
|
} else {
|
||||||
|
_name = _receiver->getDeviceName(_index);
|
||||||
raw_device->addEventHandler("DEV_" + std::to_string(_index), rawEventHandler);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::~Device()
|
Device::~Device()
|
||||||
{
|
{
|
||||||
raw_device->removeEventHandler("DEV_" + std::to_string(_index));
|
_raw_device->removeEventHandler("DEV_" + std::to_string(_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::addEventHandler(const std::string& nickname, const std::shared_ptr<EventHandler>& handler)
|
void Device::addEventHandler(const std::string& nickname,
|
||||||
|
const std::shared_ptr<EventHandler>& handler)
|
||||||
{
|
{
|
||||||
auto it = event_handlers.find(nickname);
|
auto it = event_handlers.find(nickname);
|
||||||
assert(it == event_handlers.end());
|
assert(it == event_handlers.end());
|
||||||
|
@ -119,7 +132,7 @@ Report Device::sendReport(Report& report)
|
||||||
assert(supported_reports & HIDPP_REPORT_LONG_SUPPORTED);
|
assert(supported_reports & HIDPP_REPORT_LONG_SUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto raw_response = raw_device->sendReport(report.rawReport());
|
auto raw_response = _raw_device->sendReport(report.rawReport());
|
||||||
|
|
||||||
Report response(raw_response);
|
Report response(raw_response);
|
||||||
|
|
||||||
|
@ -136,5 +149,30 @@ Report Device::sendReport(Report& report)
|
||||||
|
|
||||||
void Device::listen()
|
void Device::listen()
|
||||||
{
|
{
|
||||||
raw_device->listen();
|
if(!_raw_device->isListening())
|
||||||
|
std::thread{[=]() { _raw_device->listen(); }}.detach();
|
||||||
|
|
||||||
|
// Pass all HID++ events with device index to this device.
|
||||||
|
std::shared_ptr<RawEventHandler> rawEventHandler;
|
||||||
|
rawEventHandler->condition = [this](std::vector<uint8_t>& report)->bool
|
||||||
|
{
|
||||||
|
return (report[Offset::Type] == Report::Type::Short ||
|
||||||
|
report[Offset::Type] == Report::Type::Long) &&
|
||||||
|
(report[Offset::DeviceIndex] == this->_index);
|
||||||
|
};
|
||||||
|
rawEventHandler->callback = [this](std::vector<uint8_t>& report)->void
|
||||||
|
{
|
||||||
|
Report _report(report);
|
||||||
|
this->handleEvent(_report);
|
||||||
|
};
|
||||||
|
|
||||||
|
_raw_device->addEventHandler("DEV_" + std::to_string(_index), rawEventHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::stopListening()
|
||||||
|
{
|
||||||
|
_raw_device->removeEventHandler("DEV_" + std::to_string(_index));
|
||||||
|
|
||||||
|
if(!_raw_device->eventHandlers().empty())
|
||||||
|
_raw_device->stopListener();
|
||||||
}
|
}
|
|
@ -11,8 +11,14 @@
|
||||||
|
|
||||||
namespace logid {
|
namespace logid {
|
||||||
namespace backend {
|
namespace backend {
|
||||||
|
namespace dj
|
||||||
|
{
|
||||||
|
// Need to define here for a constructor
|
||||||
|
class Receiver;
|
||||||
|
}
|
||||||
namespace hidpp
|
namespace hidpp
|
||||||
{
|
{
|
||||||
|
struct DeviceConnectionEvent;
|
||||||
struct EventHandler
|
struct EventHandler
|
||||||
{
|
{
|
||||||
std::function<bool(Report&)> condition;
|
std::function<bool(Report&)> condition;
|
||||||
|
@ -27,7 +33,8 @@ namespace hidpp
|
||||||
enum Reason
|
enum Reason
|
||||||
{
|
{
|
||||||
NoHIDPPReport,
|
NoHIDPPReport,
|
||||||
InvalidRawDevice
|
InvalidRawDevice,
|
||||||
|
Asleep
|
||||||
};
|
};
|
||||||
InvalidDevice(Reason reason) : _reason (reason) {}
|
InvalidDevice(Reason reason) : _reason (reason) {}
|
||||||
virtual const char *what() const noexcept;
|
virtual const char *what() const noexcept;
|
||||||
|
@ -36,18 +43,21 @@ namespace hidpp
|
||||||
Reason _reason;
|
Reason _reason;
|
||||||
};
|
};
|
||||||
|
|
||||||
Device(const std::string& path, DeviceIndex index);
|
explicit Device(const std::string& path, DeviceIndex index);
|
||||||
Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index);
|
explicit Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index);
|
||||||
|
explicit Device(std::shared_ptr<dj::Receiver> receiver,
|
||||||
|
hidpp::DeviceConnectionEvent event);
|
||||||
~Device();
|
~Device();
|
||||||
|
|
||||||
std::string devicePath() const { return path; }
|
std::string devicePath() const { return _path; }
|
||||||
DeviceIndex deviceIndex() const { return _index; }
|
DeviceIndex deviceIndex() const { return _index; }
|
||||||
std::tuple<uint8_t, uint8_t> version() const { return _version; }
|
std::tuple<uint8_t, uint8_t> version() const { return _version; }
|
||||||
|
|
||||||
void listen(); // Runs asynchronously
|
void listen(); // Runs asynchronously
|
||||||
void stopListening();
|
void stopListening();
|
||||||
|
|
||||||
void addEventHandler(const std::string& nickname, const std::shared_ptr<EventHandler>& handler);
|
void addEventHandler(const std::string& nickname,
|
||||||
|
const std::shared_ptr<EventHandler>& handler);
|
||||||
void removeEventHandler(const std::string& nickname);
|
void removeEventHandler(const std::string& nickname);
|
||||||
|
|
||||||
Report sendReport(Report& report);
|
Report sendReport(Report& report);
|
||||||
|
@ -56,12 +66,15 @@ namespace hidpp
|
||||||
private:
|
private:
|
||||||
void _init();
|
void _init();
|
||||||
|
|
||||||
std::shared_ptr<raw::RawDevice> raw_device;
|
std::shared_ptr<raw::RawDevice> _raw_device;
|
||||||
std::string path;
|
std::shared_ptr<dj::Receiver> _receiver;
|
||||||
|
std::string _path;
|
||||||
DeviceIndex _index;
|
DeviceIndex _index;
|
||||||
uint8_t supported_reports;
|
uint8_t supported_reports;
|
||||||
|
|
||||||
std::tuple<uint8_t, uint8_t> _version;
|
std::tuple<uint8_t, uint8_t> _version;
|
||||||
|
uint16_t _pid;
|
||||||
|
std::string _name;
|
||||||
|
|
||||||
std::map<std::string, std::shared_ptr<EventHandler>> event_handlers;
|
std::map<std::string, std::shared_ptr<EventHandler>> event_handlers;
|
||||||
};
|
};
|
||||||
|
|
|
@ -180,6 +180,16 @@ void Report::setType(Report::Type type)
|
||||||
_data[Offset::Type] = type;
|
_data[Offset::Type] = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hidpp::DeviceIndex Report::deviceIndex()
|
||||||
|
{
|
||||||
|
return static_cast<hidpp::DeviceIndex>(_data[Offset::DeviceIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Report::setDeviceIndex(hidpp::DeviceIndex index)
|
||||||
|
{
|
||||||
|
_data[Offset::DeviceIndex] = index;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t Report::feature() const
|
uint8_t Report::feature() const
|
||||||
{
|
{
|
||||||
return _data[Offset::Feature];
|
return _data[Offset::Feature];
|
||||||
|
|
|
@ -60,6 +60,9 @@ namespace logid::backend::hidpp
|
||||||
Report::Type type() const;
|
Report::Type type() const;
|
||||||
void setType(Report::Type type);
|
void setType(Report::Type type);
|
||||||
|
|
||||||
|
logid::backend::hidpp::DeviceIndex deviceIndex();
|
||||||
|
void setDeviceIndex(hidpp::DeviceIndex index);
|
||||||
|
|
||||||
uint8_t feature() const;
|
uint8_t feature() const;
|
||||||
void setFeature(uint8_t feature);
|
void setFeature(uint8_t feature);
|
||||||
|
|
||||||
|
@ -96,11 +99,6 @@ namespace logid::backend::hidpp
|
||||||
|
|
||||||
bool isError20(hidpp20_error* error);
|
bool isError20(hidpp20_error* error);
|
||||||
|
|
||||||
logid::backend::hidpp::DeviceIndex deviceIndex()
|
|
||||||
{
|
|
||||||
return static_cast<DeviceIndex>(_data[Offset::DeviceIndex]);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> rawReport () const { return _data; }
|
std::vector<uint8_t> rawReport () const { return _data; }
|
||||||
private:
|
private:
|
||||||
static constexpr std::size_t HeaderLength = 4;
|
static constexpr std::size_t HeaderLength = 4;
|
||||||
|
|
|
@ -19,13 +19,10 @@ Device::Device(std::shared_ptr<raw::RawDevice> raw_dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> Device::getRegister(uint8_t address,
|
std::vector<uint8_t> Device::getRegister(uint8_t address,
|
||||||
const std::vector<uint8_t>& params)
|
const std::vector<uint8_t>& params, hidpp::Report::Type type)
|
||||||
{
|
{
|
||||||
assert(params.size() <= hidpp::LongParamLength);
|
assert(params.size() <= hidpp::LongParamLength);
|
||||||
|
|
||||||
hidpp::Report::Type type = params.size() <= hidpp::ShortParamLength ?
|
|
||||||
hidpp::Report::Type::Short : hidpp::Report::Type::Long;
|
|
||||||
|
|
||||||
uint8_t sub_id = type == hidpp::Report::Type::Short ?
|
uint8_t sub_id = type == hidpp::Report::Type::Short ?
|
||||||
GetRegisterShort : GetRegisterLong;
|
GetRegisterShort : GetRegisterLong;
|
||||||
|
|
||||||
|
@ -33,13 +30,11 @@ std::vector<uint8_t> Device::getRegister(uint8_t address,
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> Device::setRegister(uint8_t address,
|
std::vector<uint8_t> Device::setRegister(uint8_t address,
|
||||||
const std::vector<uint8_t>& params)
|
const std::vector<uint8_t>& params,
|
||||||
|
hidpp::Report::Type type)
|
||||||
{
|
{
|
||||||
assert(params.size() <= hidpp::LongParamLength);
|
assert(params.size() <= hidpp::LongParamLength);
|
||||||
|
|
||||||
hidpp::Report::Type type = params.size() <= hidpp::ShortParamLength ?
|
|
||||||
hidpp::Report::Type::Short : hidpp::Report::Type::Long;
|
|
||||||
|
|
||||||
uint8_t sub_id = type == hidpp::Report::Type::Short ?
|
uint8_t sub_id = type == hidpp::Report::Type::Short ?
|
||||||
SetRegisterShort : SetRegisterLong;
|
SetRegisterShort : SetRegisterLong;
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,10 @@ namespace hidpp10
|
||||||
hidpp::DeviceIndex index);
|
hidpp::DeviceIndex index);
|
||||||
|
|
||||||
std::vector<uint8_t> getRegister(uint8_t address,
|
std::vector<uint8_t> getRegister(uint8_t address,
|
||||||
const std::vector<uint8_t>& params);
|
const std::vector<uint8_t>& params, hidpp::Report::Type type);
|
||||||
|
|
||||||
std::vector<uint8_t> setRegister(uint8_t address,
|
std::vector<uint8_t> setRegister(uint8_t address,
|
||||||
const std::vector<uint8_t>& params);
|
const std::vector<uint8_t>& params, hidpp::Report::Type type);
|
||||||
private:
|
private:
|
||||||
std::vector<uint8_t> accessRegister(uint8_t sub_id,
|
std::vector<uint8_t> accessRegister(uint8_t sub_id,
|
||||||
uint8_t address, const std::vector<uint8_t>& params);
|
uint8_t address, const std::vector<uint8_t>& params);
|
||||||
|
|
44
src/logid/backend/hidpp20/EssentialFeature.cpp
Normal file
44
src/logid/backend/hidpp20/EssentialFeature.cpp
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#include <cassert>
|
||||||
|
#include "EssentialFeature.h"
|
||||||
|
#include "feature_defs.h"
|
||||||
|
#include "features/Root.h"
|
||||||
|
|
||||||
|
using namespace logid::backend::hidpp20;
|
||||||
|
|
||||||
|
std::vector<uint8_t> EssentialFeature::callFunction(uint8_t function_id,
|
||||||
|
std::vector<uint8_t>& params)
|
||||||
|
{
|
||||||
|
hidpp::Report::Type type;
|
||||||
|
|
||||||
|
assert(params.size() <= hidpp::LongParamLength);
|
||||||
|
if(params.size() <= hidpp::ShortParamLength)
|
||||||
|
type = hidpp::Report::Type::Short;
|
||||||
|
else if(params.size() <= hidpp::LongParamLength)
|
||||||
|
type = hidpp::Report::Type::Long;
|
||||||
|
|
||||||
|
hidpp::Report request(type, _device->deviceIndex(), _index, function_id,
|
||||||
|
LOGID_HIDPP_SOFTWARE_ID);
|
||||||
|
std::copy(params.begin(), params.end(), request.paramBegin());
|
||||||
|
|
||||||
|
auto response = _device->sendReport(request);
|
||||||
|
return std::vector<uint8_t>(response.paramBegin(), response.paramEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
EssentialFeature::EssentialFeature(hidpp::Device* dev, uint16_t _id) :
|
||||||
|
_device (dev)
|
||||||
|
{
|
||||||
|
_index = hidpp20::FeatureID::ROOT;
|
||||||
|
|
||||||
|
if(_id)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> getFunc_req(2);
|
||||||
|
getFunc_req[0] = (_id >> 8) & 0xff;
|
||||||
|
getFunc_req[1] = _id & 0xff;
|
||||||
|
auto getFunc_resp = this->callFunction(Root::GetFeature, getFunc_req);
|
||||||
|
_index = getFunc_resp[0];
|
||||||
|
|
||||||
|
// 0 if not found
|
||||||
|
if(!_index)
|
||||||
|
throw UnsupportedFeature(_id);
|
||||||
|
}
|
||||||
|
}
|
32
src/logid/backend/hidpp20/EssentialFeature.h
Normal file
32
src/logid/backend/hidpp20/EssentialFeature.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef LOGID_HIDPP20_ESSENTIAL_FEATURE_H
|
||||||
|
#define LOGID_HIDPP20_ESSENTIAL_FEATURE_H
|
||||||
|
|
||||||
|
// WARNING: UNSAFE
|
||||||
|
|
||||||
|
/* This class is only meant to provide essential HID++ 2.0 features to the
|
||||||
|
* hidpp::Device class. No version checks are provided here
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Device.h"
|
||||||
|
|
||||||
|
namespace logid {
|
||||||
|
namespace backend {
|
||||||
|
namespace hidpp20
|
||||||
|
{
|
||||||
|
class EssentialFeature
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const uint16_t ID;
|
||||||
|
virtual uint16_t getID() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
EssentialFeature(hidpp::Device* dev, uint16_t _id);
|
||||||
|
std::vector<uint8_t> callFunction(uint8_t function_id,
|
||||||
|
std::vector<uint8_t>& params);
|
||||||
|
private:
|
||||||
|
hidpp::Device* _device;
|
||||||
|
uint8_t _index;
|
||||||
|
};
|
||||||
|
}}}
|
||||||
|
|
||||||
|
#endif //LOGID_HIDPP20_ESSENTIAL_FEATURE_H
|
68
src/logid/backend/hidpp20/features/DeviceName.cpp
Normal file
68
src/logid/backend/hidpp20/features/DeviceName.cpp
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#include <cmath>
|
||||||
|
#include "DeviceName.h"
|
||||||
|
|
||||||
|
using namespace logid::backend;
|
||||||
|
using namespace logid::backend::hidpp20;
|
||||||
|
|
||||||
|
DeviceName::DeviceName(Device* dev) : Feature(dev, ID)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t DeviceName::getNameLength()
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> params(0);
|
||||||
|
|
||||||
|
auto response = this->callFunction(Function::GetLength, params);
|
||||||
|
return response[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string _getName(uint8_t length,
|
||||||
|
const std::function<std::vector<uint8_t>(std::vector<uint8_t>)>& fcall)
|
||||||
|
{
|
||||||
|
uint8_t function_calls = length/hidpp::LongParamLength;
|
||||||
|
if(length % hidpp::LongParamLength)
|
||||||
|
function_calls++;
|
||||||
|
std::vector<uint8_t> params(1);
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < function_calls; i++) {
|
||||||
|
params[0] = i*hidpp::LongParamLength;
|
||||||
|
auto name_section = fcall(params);
|
||||||
|
for(std::size_t j = 0; j < hidpp::LongParamLength; j++) {
|
||||||
|
if(params[0] + j >= length)
|
||||||
|
return name;
|
||||||
|
name += name_section[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DeviceName::getName()
|
||||||
|
{
|
||||||
|
return _getName(getNameLength(), [this]
|
||||||
|
(std::vector<uint8_t> params)->std::vector<uint8_t> {
|
||||||
|
return this->callFunction(Function::GetDeviceName, params);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
EssentialDeviceName::EssentialDeviceName(hidpp::Device* dev) :
|
||||||
|
EssentialFeature(dev, ID)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t EssentialDeviceName::getNameLength()
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> params(0);
|
||||||
|
|
||||||
|
auto response = this->callFunction(DeviceName::Function::GetLength, params);
|
||||||
|
return response[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string EssentialDeviceName::getName()
|
||||||
|
{
|
||||||
|
return _getName(getNameLength(), [this]
|
||||||
|
(std::vector<uint8_t> params)->std::vector<uint8_t> {
|
||||||
|
return this->callFunction(DeviceName::Function::GetDeviceName, params);
|
||||||
|
});
|
||||||
|
}
|
43
src/logid/backend/hidpp20/features/DeviceName.h
Normal file
43
src/logid/backend/hidpp20/features/DeviceName.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef LOGID_BACKEND_HIDPP20_FEATURE_DEVICENAME_H
|
||||||
|
#define LOGID_BACKEND_HIDPP20_FEATURE_DEVICENAME_H
|
||||||
|
|
||||||
|
#include "../Feature.h"
|
||||||
|
#include "../feature_defs.h"
|
||||||
|
#include "../EssentialFeature.h"
|
||||||
|
|
||||||
|
namespace logid {
|
||||||
|
namespace backend {
|
||||||
|
namespace hidpp20
|
||||||
|
{
|
||||||
|
class DeviceName : public Feature
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const uint16_t ID = FeatureID::DEVICE_NAME;
|
||||||
|
virtual uint16_t getID() { return ID; }
|
||||||
|
|
||||||
|
enum Function : uint8_t
|
||||||
|
{
|
||||||
|
GetLength = 0,
|
||||||
|
GetDeviceName = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
DeviceName(Device* device);
|
||||||
|
|
||||||
|
uint8_t getNameLength();
|
||||||
|
std::string getName();
|
||||||
|
};
|
||||||
|
|
||||||
|
class EssentialDeviceName : public EssentialFeature
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const uint16_t ID = FeatureID::DEVICE_NAME;
|
||||||
|
virtual uint16_t getID() { return ID; }
|
||||||
|
|
||||||
|
EssentialDeviceName(hidpp::Device* device);
|
||||||
|
|
||||||
|
uint8_t getNameLength();
|
||||||
|
std::string getName();
|
||||||
|
};
|
||||||
|
}}}
|
||||||
|
|
||||||
|
#endif //LOGID_BACKEND_HIDPP20_FEATURE_DEVICENAME_H
|
|
@ -6,27 +6,36 @@ Root::Root(Device* dev) : Feature(dev, ID)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
feature_info Root::getFeature(uint16_t feature_id)
|
std::vector<uint8_t> _genGetFeatureParams(uint16_t feature_id)
|
||||||
{
|
{
|
||||||
feature_info info{};
|
|
||||||
std::vector<uint8_t> params(2);
|
std::vector<uint8_t> params(2);
|
||||||
params[0] = feature_id & 0xff;
|
params[0] = feature_id & 0xff;
|
||||||
params[1] = (feature_id >> 8) & 0xff;
|
params[1] = (feature_id >> 8) & 0xff;
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
auto response = this->callFunction(Function::GetFeature, params);
|
feature_info _genGetFeatureInfo(uint16_t feature_id, std::vector<uint8_t> response)
|
||||||
|
{
|
||||||
|
feature_info info{};
|
||||||
info.feature_id = response[0];
|
info.feature_id = response[0];
|
||||||
|
|
||||||
if(!info.feature_id)
|
if(!info.feature_id)
|
||||||
throw UnsupportedFeature(feature_id);
|
throw UnsupportedFeature(feature_id);
|
||||||
|
|
||||||
info.hidden = response[1] & FeatureFlag::Hidden;
|
info.hidden = response[1] & Root::FeatureFlag::Hidden;
|
||||||
info.obsolete = response[1] & FeatureFlag::Obsolete;
|
info.obsolete = response[1] & Root::FeatureFlag::Obsolete;
|
||||||
info.internal = response[1] & FeatureFlag::Internal;
|
info.internal = response[1] & Root::FeatureFlag::Internal;
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
feature_info Root::getFeature(uint16_t feature_id)
|
||||||
|
{
|
||||||
|
auto params = _genGetFeatureParams(feature_id);
|
||||||
|
auto response = this->callFunction(Function::GetFeature, params);
|
||||||
|
return _genGetFeatureInfo(feature_id, response);
|
||||||
|
}
|
||||||
|
|
||||||
std::tuple<uint8_t, uint8_t> Root::getVersion()
|
std::tuple<uint8_t, uint8_t> Root::getVersion()
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> params(0);
|
std::vector<uint8_t> params(0);
|
||||||
|
@ -34,3 +43,22 @@ std::tuple<uint8_t, uint8_t> Root::getVersion()
|
||||||
|
|
||||||
return std::make_tuple(response[0], response[1]);
|
return std::make_tuple(response[0], response[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EssentialRoot::EssentialRoot(hidpp::Device* dev) : EssentialFeature(dev, ID)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
feature_info EssentialRoot::getFeature(uint16_t feature_id)
|
||||||
|
{
|
||||||
|
auto params = _genGetFeatureParams(feature_id);
|
||||||
|
auto response = this->callFunction(Root::Function::GetFeature, params);
|
||||||
|
return _genGetFeatureInfo(feature_id, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<uint8_t, uint8_t> EssentialRoot::getVersion()
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> params(0);
|
||||||
|
auto response = this->callFunction(Root::Function::Ping, params);
|
||||||
|
|
||||||
|
return std::make_tuple(response[0], response[1]);
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
#define LOGID_BACKEND_HIDPP20_FEATURE_ROOT_H
|
#define LOGID_BACKEND_HIDPP20_FEATURE_ROOT_H
|
||||||
|
|
||||||
#include "../Feature.h"
|
#include "../Feature.h"
|
||||||
|
#include "../EssentialFeature.h"
|
||||||
#include "../feature_defs.h"
|
#include "../feature_defs.h"
|
||||||
|
|
||||||
namespace logid {
|
namespace logid {
|
||||||
|
@ -24,7 +25,7 @@ namespace hidpp20
|
||||||
|
|
||||||
feature_info getFeature (uint16_t feature_id);
|
feature_info getFeature (uint16_t feature_id);
|
||||||
std::tuple<uint8_t, uint8_t> getVersion();
|
std::tuple<uint8_t, uint8_t> getVersion();
|
||||||
private:
|
|
||||||
enum FeatureFlag : uint8_t
|
enum FeatureFlag : uint8_t
|
||||||
{
|
{
|
||||||
Obsolete = 1<<7,
|
Obsolete = 1<<7,
|
||||||
|
@ -32,6 +33,18 @@ namespace hidpp20
|
||||||
Internal = 1<<5
|
Internal = 1<<5
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EssentialRoot : public EssentialFeature
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const uint16_t ID = FeatureID::ROOT;
|
||||||
|
virtual uint16_t getID() { return ID; }
|
||||||
|
|
||||||
|
EssentialRoot(hidpp::Device* device);
|
||||||
|
|
||||||
|
feature_info getFeature (uint16_t feature_id);
|
||||||
|
std::tuple<uint8_t, uint8_t> getVersion();
|
||||||
|
};
|
||||||
}}}
|
}}}
|
||||||
|
|
||||||
#endif //LOGID_BACKEND_HIDPP20_FEATURE_ROOT_H
|
#endif //LOGID_BACKEND_HIDPP20_FEATURE_ROOT_H
|
|
@ -24,8 +24,8 @@ using namespace std::chrono;
|
||||||
|
|
||||||
bool RawDevice::supportedReportID(uint8_t id)
|
bool RawDevice::supportedReportID(uint8_t id)
|
||||||
{
|
{
|
||||||
return (hidpp::ReportType::Short == id) || (hidpp::ReportType::Long == id) ||
|
return (hidpp::ReportType::Short == id) || (hidpp::ReportType::Long == id)
|
||||||
(dj::ReportType::Short == id) || (dj::ReportType::Long == id);
|
|| (dj::ReportType::Short == id) || (dj::ReportType::Long == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
|
RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
|
||||||
|
@ -34,14 +34,16 @@ RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
|
||||||
|
|
||||||
fd = ::open(path.c_str(), O_RDWR);
|
fd = ::open(path.c_str(), O_RDWR);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
throw std::system_error(errno, std::system_category(), "RawDevice open failed");
|
throw std::system_error(errno, std::system_category(),
|
||||||
|
"RawDevice open failed");
|
||||||
|
|
||||||
hidraw_devinfo devinfo{};
|
hidraw_devinfo devinfo{};
|
||||||
if (-1 == ::ioctl(fd, HIDIOCGRAWINFO, &devinfo))
|
if (-1 == ::ioctl(fd, HIDIOCGRAWINFO, &devinfo))
|
||||||
{
|
{
|
||||||
int err = errno;
|
int err = errno;
|
||||||
::close(fd);
|
::close(fd);
|
||||||
throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRAWINFO failed");
|
throw std::system_error(err, std::system_category(),
|
||||||
|
"RawDevice HIDIOCGRAWINFO failed");
|
||||||
}
|
}
|
||||||
vid = devinfo.vendor;
|
vid = devinfo.vendor;
|
||||||
pid = devinfo.product;
|
pid = devinfo.product;
|
||||||
|
@ -51,22 +53,25 @@ RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
|
||||||
{
|
{
|
||||||
int err = errno;
|
int err = errno;
|
||||||
::close(fd);
|
::close(fd);
|
||||||
throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRAWNAME failed");
|
throw std::system_error(err, std::system_category(),
|
||||||
|
"RawDevice HIDIOCGRAWNAME failed");
|
||||||
}
|
}
|
||||||
name.assign(name_buf, ret - 1);
|
_name.assign(name_buf, ret - 1);
|
||||||
|
|
||||||
hidraw_report_descriptor _rdesc{};
|
hidraw_report_descriptor _rdesc{};
|
||||||
if (-1 == ::ioctl(fd, HIDIOCGRDESCSIZE, &_rdesc.size))
|
if (-1 == ::ioctl(fd, HIDIOCGRDESCSIZE, &_rdesc.size))
|
||||||
{
|
{
|
||||||
int err = errno;
|
int err = errno;
|
||||||
::close(fd);
|
::close(fd);
|
||||||
throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRDESCSIZE failed");
|
throw std::system_error(err, std::system_category(),
|
||||||
|
"RawDevice HIDIOCGRDESCSIZE failed");
|
||||||
}
|
}
|
||||||
if (-1 == ::ioctl(fd, HIDIOCGRDESC, &_rdesc))
|
if (-1 == ::ioctl(fd, HIDIOCGRDESC, &_rdesc))
|
||||||
{
|
{
|
||||||
int err = errno;
|
int err = errno;
|
||||||
::close(fd);
|
::close(fd);
|
||||||
throw std::system_error(err, std::system_category(), "RawDevice HIDIOCGRDESC failed");
|
throw std::system_error(err, std::system_category(),
|
||||||
|
"RawDevice HIDIOCGRDESC failed");
|
||||||
}
|
}
|
||||||
rdesc = std::vector<uint8_t>(_rdesc.value, _rdesc.value + _rdesc.size);
|
rdesc = std::vector<uint8_t>(_rdesc.value, _rdesc.value + _rdesc.size);
|
||||||
|
|
||||||
|
@ -74,7 +79,8 @@ RawDevice::RawDevice(std::string path) : path (path), continue_listen (false)
|
||||||
{
|
{
|
||||||
int err = errno;
|
int err = errno;
|
||||||
close(fd);
|
close(fd);
|
||||||
throw std::system_error(err, std::system_category(), "RawDevice pipe open failed");
|
throw std::system_error(err, std::system_category(),
|
||||||
|
"RawDevice pipe open failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
continue_listen = false;
|
continue_listen = false;
|
||||||
|
@ -92,8 +98,6 @@ RawDevice::~RawDevice()
|
||||||
|
|
||||||
std::vector<uint8_t> RawDevice::sendReport(const std::vector<uint8_t>& report)
|
std::vector<uint8_t> RawDevice::sendReport(const std::vector<uint8_t>& report)
|
||||||
{
|
{
|
||||||
assert(supportedReportID(report[0]));
|
|
||||||
|
|
||||||
/* If the listener will stop, handle I/O manually.
|
/* If the listener will stop, handle I/O manually.
|
||||||
* Otherwise, push to queue and wait for result. */
|
* Otherwise, push to queue and wait for result. */
|
||||||
if(continue_listen)
|
if(continue_listen)
|
||||||
|
@ -189,11 +193,6 @@ std::vector<uint8_t> RawDevice::_respondToReport
|
||||||
|
|
||||||
int RawDevice::_sendReport(const std::vector<uint8_t>& report)
|
int RawDevice::_sendReport(const std::vector<uint8_t>& report)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(dev_io);
|
|
||||||
int ret = ::write(fd, report.data(), report.size());
|
|
||||||
if(ret == -1)
|
|
||||||
throw std::system_error(errno, std::system_category(), "_sendReport write failed");
|
|
||||||
|
|
||||||
if(logid::global_verbosity == LogLevel::RAWREPORT) {
|
if(logid::global_verbosity == LogLevel::RAWREPORT) {
|
||||||
printf("[RAWREPORT] %s OUT: ", path.c_str());
|
printf("[RAWREPORT] %s OUT: ", path.c_str());
|
||||||
for(auto &i : report)
|
for(auto &i : report)
|
||||||
|
@ -201,6 +200,14 @@ int RawDevice::_sendReport(const std::vector<uint8_t>& report)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(supportedReportID(report[0]));
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(dev_io);
|
||||||
|
int ret = ::write(fd, report.data(), report.size());
|
||||||
|
if(ret == -1)
|
||||||
|
throw std::system_error(errno, std::system_category(),
|
||||||
|
"_sendReport write failed");
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,13 +232,15 @@ int RawDevice::_readReport(std::vector<uint8_t>& report, std::size_t maxDataLeng
|
||||||
} while(ret == -1 && errno == EINTR);
|
} while(ret == -1 && errno == EINTR);
|
||||||
|
|
||||||
if(ret == -1)
|
if(ret == -1)
|
||||||
throw std::system_error(errno, std::system_category(), "_readReport select failed");
|
throw std::system_error(errno, std::system_category(),
|
||||||
|
"_readReport select failed");
|
||||||
|
|
||||||
if(FD_ISSET(fd, &fds))
|
if(FD_ISSET(fd, &fds))
|
||||||
{
|
{
|
||||||
ret = read(fd, report.data(), report.size());
|
ret = read(fd, report.data(), report.size());
|
||||||
if(ret == -1)
|
if(ret == -1)
|
||||||
throw std::system_error(errno, std::system_category(), "_readReport read failed");
|
throw std::system_error(errno, std::system_category(),
|
||||||
|
"_readReport read failed");
|
||||||
report.resize(ret);
|
report.resize(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,7 +249,8 @@ int RawDevice::_readReport(std::vector<uint8_t>& report, std::size_t maxDataLeng
|
||||||
char c;
|
char c;
|
||||||
ret = read(dev_pipe[0], &c, sizeof(char));
|
ret = read(dev_pipe[0], &c, sizeof(char));
|
||||||
if(ret == -1)
|
if(ret == -1)
|
||||||
throw std::system_error(errno, std::system_category(), "_readReport read pipe failed");
|
throw std::system_error(errno, std::system_category(),
|
||||||
|
"_readReport read pipe failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(0 == ret)
|
if(0 == ret)
|
||||||
|
@ -260,7 +270,8 @@ void RawDevice::interruptRead()
|
||||||
{
|
{
|
||||||
char c = 0;
|
char c = 0;
|
||||||
if(-1 == write(dev_pipe[1], &c, sizeof(char)))
|
if(-1 == write(dev_pipe[1], &c, sizeof(char)))
|
||||||
throw std::system_error(errno, std::system_category(), "interruptRead write pipe failed");
|
throw std::system_error(errno, std::system_category(),
|
||||||
|
"interruptRead write pipe failed");
|
||||||
|
|
||||||
// Ensure I/O has halted
|
// Ensure I/O has halted
|
||||||
std::lock_guard<std::mutex> lock(dev_io);
|
std::lock_guard<std::mutex> lock(dev_io);
|
||||||
|
@ -302,7 +313,8 @@ void RawDevice::stopListener()
|
||||||
interruptRead();
|
interruptRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RawDevice::addEventHandler(const std::string& nickname, RawEventHandler& handler)
|
void RawDevice::addEventHandler(const std::string& nickname,
|
||||||
|
const std::shared_ptr<RawEventHandler>& handler)
|
||||||
{
|
{
|
||||||
auto it = event_handlers.find(nickname);
|
auto it = event_handlers.find(nickname);
|
||||||
assert(it == event_handlers.end());
|
assert(it == event_handlers.end());
|
||||||
|
@ -314,11 +326,17 @@ void RawDevice::removeEventHandler(const std::string &nickname)
|
||||||
event_handlers.erase(nickname);
|
event_handlers.erase(nickname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::map<std::string, std::shared_ptr<RawEventHandler>>&
|
||||||
|
RawDevice::eventHandlers()
|
||||||
|
{
|
||||||
|
return event_handlers;
|
||||||
|
}
|
||||||
|
|
||||||
void RawDevice::handleEvent(std::vector<uint8_t> &report)
|
void RawDevice::handleEvent(std::vector<uint8_t> &report)
|
||||||
{
|
{
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RawDevice::isListening()
|
bool RawDevice::isListening()
|
||||||
|
@ -328,5 +346,5 @@ bool RawDevice::isListening()
|
||||||
if(ret)
|
if(ret)
|
||||||
listening.unlock();
|
listening.unlock();
|
||||||
|
|
||||||
return ret;
|
return !ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,14 @@ namespace raw
|
||||||
public:
|
public:
|
||||||
static bool supportedReportID(uint8_t id);
|
static bool supportedReportID(uint8_t id);
|
||||||
|
|
||||||
RawDevice(std::string path);
|
explicit RawDevice(std::string path);
|
||||||
~RawDevice();
|
~RawDevice();
|
||||||
std::string hidrawPath() const { return path; }
|
std::string hidrawPath() const { return path; }
|
||||||
|
|
||||||
|
std::string name() const { return _name; }
|
||||||
|
uint16_t vendorId() const { return vid; }
|
||||||
|
uint16_t productId() const { return pid; }
|
||||||
|
|
||||||
std::vector<uint8_t> reportDescriptor() const { return rdesc; }
|
std::vector<uint8_t> reportDescriptor() const { return rdesc; }
|
||||||
|
|
||||||
std::vector<uint8_t> sendReport(const std::vector<uint8_t>& report);
|
std::vector<uint8_t> sendReport(const std::vector<uint8_t>& report);
|
||||||
|
@ -36,8 +41,11 @@ namespace raw
|
||||||
void stopListener();
|
void stopListener();
|
||||||
bool isListening();
|
bool isListening();
|
||||||
|
|
||||||
void addEventHandler(const std::string& nickname, RawEventHandler& handler);
|
void addEventHandler(const std::string& nickname,
|
||||||
|
const std::shared_ptr<backend::RawEventHandler>& handler);
|
||||||
void removeEventHandler(const std::string& nickname);
|
void removeEventHandler(const std::string& nickname);
|
||||||
|
const std::map<std::string, std::shared_ptr<backend::RawEventHandler>>&
|
||||||
|
eventHandlers();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::mutex dev_io, listening;
|
std::mutex dev_io, listening;
|
||||||
|
@ -46,12 +54,13 @@ namespace raw
|
||||||
int dev_pipe[2];
|
int dev_pipe[2];
|
||||||
uint16_t vid;
|
uint16_t vid;
|
||||||
uint16_t pid;
|
uint16_t pid;
|
||||||
std::string name;
|
std::string _name;
|
||||||
std::vector<uint8_t> rdesc;
|
std::vector<uint8_t> rdesc;
|
||||||
|
|
||||||
std::atomic<bool> continue_listen;
|
std::atomic<bool> continue_listen;
|
||||||
|
|
||||||
std::map<std::string, backend::RawEventHandler> event_handlers;
|
std::map<std::string, std::shared_ptr<backend::RawEventHandler>>
|
||||||
|
event_handlers;
|
||||||
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 */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user