mirror of
https://github.com/PixlOne/logiops.git
synced 2025-07-14 21:32:33 +08:00
I/O fixes, ensure sync and responses are proper
This commit is contained in:
parent
9d15610596
commit
adcb173e4c
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
namespace logid {
|
namespace logid {
|
||||||
namespace defaults {
|
namespace defaults {
|
||||||
static constexpr double io_timeout = 500;
|
static constexpr double io_timeout = 1000;
|
||||||
static constexpr int gesture_threshold = 50;
|
static constexpr int gesture_threshold = 50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,10 +51,10 @@ Device::InvalidDevice::Reason Device::InvalidDevice::code() const noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Device::Device(const std::string& path, DeviceIndex index,
|
Device::Device(const std::string& path, DeviceIndex index,
|
||||||
std::shared_ptr<raw::DeviceMonitor> monitor, double timeout) :
|
const std::shared_ptr<raw::DeviceMonitor>& monitor, double timeout) :
|
||||||
io_timeout(duration_cast<milliseconds>(
|
io_timeout(duration_cast<milliseconds>(
|
||||||
duration<double, std::milli>(timeout))),
|
duration<double, std::milli>(timeout))),
|
||||||
_raw_device(std::make_shared<raw::RawDevice>(path, std::move(monitor))),
|
_raw_device(std::make_shared<raw::RawDevice>(path, monitor)),
|
||||||
_receiver(nullptr), _path(path), _index(index) {
|
_receiver(nullptr), _path(path), _index(index) {
|
||||||
_init();
|
_init();
|
||||||
}
|
}
|
||||||
@ -133,7 +133,7 @@ void Device::_init() {
|
|||||||
auto rsp = sendReport(
|
auto rsp = sendReport(
|
||||||
{ReportType::Short, _index,
|
{ReportType::Short, _index,
|
||||||
hidpp20::FeatureID::ROOT, hidpp20::Root::Ping,
|
hidpp20::FeatureID::ROOT, hidpp20::Root::Ping,
|
||||||
LOGID_HIDPP_SOFTWARE_ID});
|
hidpp::softwareID});
|
||||||
if (rsp.deviceIndex() != _index) {
|
if (rsp.deviceIndex() != _index) {
|
||||||
throw InvalidDevice(InvalidDevice::VirtualNode);
|
throw InvalidDevice(InvalidDevice::VirtualNode);
|
||||||
}
|
}
|
||||||
@ -152,12 +152,9 @@ void Device::_init() {
|
|||||||
|
|
||||||
[index = this->_index](
|
[index = this->_index](
|
||||||
const std::vector<uint8_t>& report) -> bool {
|
const std::vector<uint8_t>& report) -> bool {
|
||||||
return (report[Offset::Type] ==
|
return (report[Offset::Type] == Report::Type::Short ||
|
||||||
Report::Type::Short ||
|
report[Offset::Type] == Report::Type::Long) &&
|
||||||
report[Offset::Type] ==
|
(report[Offset::DeviceIndex] == index);
|
||||||
Report::Type::Long) &&
|
|
||||||
(report[Offset::DeviceIndex] ==
|
|
||||||
index);
|
|
||||||
},
|
},
|
||||||
[this](const std::vector<uint8_t>& report) -> void {
|
[this](const std::vector<uint8_t>& report) -> void {
|
||||||
Report _report(report);
|
Report _report(report);
|
||||||
@ -212,13 +209,13 @@ Device::~Device() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Device::EvHandlerId Device::addEventHandler(EventHandler handler) {
|
Device::EvHandlerId Device::addEventHandler(EventHandler handler) {
|
||||||
std::lock_guard<std::mutex> lock(_event_handler_lock);
|
std::unique_lock lock(_event_handler_mutex);
|
||||||
_event_handlers.emplace_front(std::move(handler));
|
_event_handlers.emplace_front(std::move(handler));
|
||||||
return _event_handlers.cbegin();
|
return _event_handlers.cbegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::removeEventHandler(EvHandlerId id) {
|
void Device::removeEventHandler(EvHandlerId id) {
|
||||||
std::lock_guard<std::mutex> lock(_event_handler_lock);
|
std::unique_lock lock(_event_handler_mutex);
|
||||||
_event_handlers.erase(id);
|
_event_handlers.erase(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,66 +223,82 @@ void Device::handleEvent(Report& report) {
|
|||||||
if (responseReport(report))
|
if (responseReport(report))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(_event_handler_lock);
|
std::shared_lock lock(_event_handler_mutex);
|
||||||
for (auto& handler: _event_handlers)
|
for (auto& handler: _event_handlers)
|
||||||
if (handler.condition(report))
|
if (handler.condition(report))
|
||||||
handler.callback(report);
|
handler.callback(report);
|
||||||
}
|
}
|
||||||
|
|
||||||
Report Device::sendReport(const Report& report) {
|
Report Device::sendReport(const Report& report) {
|
||||||
std::lock_guard<std::mutex> lock(_send_lock);
|
/* Must complete transaction before next send */
|
||||||
{
|
std::lock_guard send_lock(_send_mutex);
|
||||||
std::lock_guard<std::mutex> sl(_slot_lock);
|
_sent_sub_id = report.subId();
|
||||||
_report_slot = {};
|
std::unique_lock lock(_response_mutex);
|
||||||
}
|
_sendReport(report);
|
||||||
sendReportNoResponse(report);
|
|
||||||
std::unique_lock<std::mutex> wait(_resp_wait_lock);
|
bool valid = _response_cv.wait_for(
|
||||||
bool valid = _resp_cv.wait_for(
|
lock, io_timeout, [this]() {
|
||||||
wait, io_timeout, [this]() {
|
return _response.has_value();
|
||||||
std::lock_guard<std::mutex> sl(_slot_lock);
|
|
||||||
return _report_slot.has_value();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!valid)
|
if (!valid) {
|
||||||
|
_sent_sub_id.reset();
|
||||||
throw TimeoutError();
|
throw TimeoutError();
|
||||||
|
|
||||||
std::lock_guard<std::mutex> sl(_slot_lock);
|
|
||||||
|
|
||||||
{
|
|
||||||
Report::Hidpp10Error error{};
|
|
||||||
if (_report_slot.value().isError10(&error))
|
|
||||||
throw hidpp10::Error(error.error_code);
|
|
||||||
}
|
}
|
||||||
{
|
|
||||||
Report::Hidpp20Error error{};
|
Response response = _response.value();
|
||||||
if (_report_slot.value().isError20(&error))
|
_response.reset();
|
||||||
throw hidpp20::Error(error.error_code);
|
_sent_sub_id.reset();
|
||||||
|
|
||||||
|
if (std::holds_alternative<Report>(response)) {
|
||||||
|
return std::get<Report>(response);
|
||||||
|
} else if(std::holds_alternative<Report::Hidpp10Error>(response)) {
|
||||||
|
throw hidpp20::Error(std::get<Report::Hidpp10Error>(response).error_code);
|
||||||
|
} else if(std::holds_alternative<Report::Hidpp20Error>(response)) {
|
||||||
|
throw hidpp20::Error(std::get<Report::Hidpp20Error>(response).error_code);
|
||||||
}
|
}
|
||||||
return _report_slot.value();
|
|
||||||
|
// Should not be reached
|
||||||
|
throw std::runtime_error("unhandled variant type");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Device::responseReport(const Report& report) {
|
bool Device::responseReport(const Report& report) {
|
||||||
if (_send_lock.try_lock()) {
|
std::lock_guard lock(_response_mutex);
|
||||||
_send_lock.unlock();
|
Response response = report;
|
||||||
return false;
|
uint8_t sub_id;
|
||||||
|
|
||||||
|
Report::Hidpp10Error hidpp10_error{};
|
||||||
|
Report::Hidpp20Error hidpp20_error{};
|
||||||
|
if (report.isError10(&hidpp10_error)) {
|
||||||
|
sub_id = hidpp10_error.sub_id;
|
||||||
|
response = hidpp10_error;
|
||||||
|
} else if (report.isError20(&hidpp20_error)) {
|
||||||
|
sub_id = hidpp20_error.feature_index;
|
||||||
|
response = hidpp20_error;
|
||||||
|
} else {
|
||||||
|
sub_id = report.subId();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic check to see if the report is a response
|
if (sub_id == _sent_sub_id) {
|
||||||
if ((report.swId() != LOGID_HIDPP_SOFTWARE_ID)
|
_response = response;
|
||||||
&& report.subId() < 0x80)
|
_response_cv.notify_all();
|
||||||
return false;
|
|
||||||
|
|
||||||
std::lock_guard lock(_slot_lock);
|
|
||||||
_report_slot = report;
|
|
||||||
_resp_cv.notify_all();
|
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::sendReportNoResponse(Report report) {
|
}
|
||||||
|
|
||||||
|
void Device::_sendReport(Report report) {
|
||||||
reportFixup(report);
|
reportFixup(report);
|
||||||
_raw_device->sendReport(report.rawReport());
|
_raw_device->sendReport(report.rawReport());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Device::sendReportNoACK(const Report& report) {
|
||||||
|
std::lock_guard lock(_send_mutex);
|
||||||
|
_sendReport(report);
|
||||||
|
}
|
||||||
|
|
||||||
void Device::reportFixup(Report& report) const {
|
void Device::reportFixup(Report& report) const {
|
||||||
switch (report.type()) {
|
switch (report.type()) {
|
||||||
case Report::Type::Short:
|
case Report::Type::Short:
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#define LOGID_BACKEND_HIDPP_DEVICE_H
|
#define LOGID_BACKEND_HIDPP_DEVICE_H
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <variant>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -64,7 +65,7 @@ namespace logid::backend::hidpp {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Device(const std::string& path, DeviceIndex index,
|
Device(const std::string& path, DeviceIndex index,
|
||||||
std::shared_ptr<raw::DeviceMonitor> monitor, double timeout);
|
const std::shared_ptr<raw::DeviceMonitor>& monitor, double timeout);
|
||||||
|
|
||||||
Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index,
|
Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index,
|
||||||
double timeout);
|
double timeout);
|
||||||
@ -93,7 +94,7 @@ namespace logid::backend::hidpp {
|
|||||||
|
|
||||||
virtual Report sendReport(const Report& report);
|
virtual Report sendReport(const Report& report);
|
||||||
|
|
||||||
void sendReportNoResponse(Report report);
|
virtual void sendReportNoACK(const Report& report);
|
||||||
|
|
||||||
void handleEvent(Report& report);
|
void handleEvent(Report& report);
|
||||||
|
|
||||||
@ -101,10 +102,15 @@ namespace logid::backend::hidpp {
|
|||||||
// Returns whether the report is a response
|
// Returns whether the report is a response
|
||||||
virtual bool responseReport(const Report& report);
|
virtual bool responseReport(const Report& report);
|
||||||
|
|
||||||
|
void _sendReport(Report report);
|
||||||
|
|
||||||
void reportFixup(Report& report) const;
|
void reportFixup(Report& report) const;
|
||||||
|
|
||||||
const std::chrono::milliseconds io_timeout;
|
const std::chrono::milliseconds io_timeout;
|
||||||
uint8_t supported_reports;
|
uint8_t supported_reports{};
|
||||||
|
|
||||||
|
std::mutex _response_mutex;
|
||||||
|
std::condition_variable _response_cv;
|
||||||
private:
|
private:
|
||||||
void _init();
|
void _init();
|
||||||
|
|
||||||
@ -115,16 +121,17 @@ namespace logid::backend::hidpp {
|
|||||||
DeviceIndex _index;
|
DeviceIndex _index;
|
||||||
|
|
||||||
std::tuple<uint8_t, uint8_t> _version;
|
std::tuple<uint8_t, uint8_t> _version;
|
||||||
uint16_t _pid;
|
uint16_t _pid{};
|
||||||
std::string _name;
|
std::string _name;
|
||||||
|
|
||||||
std::mutex _send_lock;
|
std::mutex _send_mutex;
|
||||||
std::mutex _resp_wait_lock;
|
|
||||||
std::condition_variable _resp_cv;
|
|
||||||
std::mutex _slot_lock;
|
|
||||||
std::optional<Report> _report_slot;
|
|
||||||
|
|
||||||
std::mutex _event_handler_lock;
|
typedef std::variant<Report, Report::Hidpp10Error, Report::Hidpp20Error> Response;
|
||||||
|
|
||||||
|
std::optional<Response> _response;
|
||||||
|
std::optional<uint8_t> _sent_sub_id{};
|
||||||
|
|
||||||
|
std::shared_mutex _event_handler_mutex;
|
||||||
std::list<EventHandler> _event_handlers;
|
std::list<EventHandler> _event_handlers;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,6 @@
|
|||||||
#ifndef LOGID_BACKEND_HIDPP_DEFS_H
|
#ifndef LOGID_BACKEND_HIDPP_DEFS_H
|
||||||
#define LOGID_BACKEND_HIDPP_DEFS_H
|
#define LOGID_BACKEND_HIDPP_DEFS_H
|
||||||
|
|
||||||
#define LOGID_HIDPP_SOFTWARE_ID 2
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace logid::backend::hidpp {
|
namespace logid::backend::hidpp {
|
||||||
@ -42,6 +40,10 @@ namespace logid::backend::hidpp {
|
|||||||
WirelessDevice6 = 6,
|
WirelessDevice6 = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static constexpr uint8_t softwareID = 2;
|
||||||
|
/* For sending reports with no response, use a different SW ID */
|
||||||
|
static constexpr uint8_t noAckSoftwareID = 1;
|
||||||
|
|
||||||
static constexpr std::size_t ShortParamLength = 3;
|
static constexpr std::size_t ShortParamLength = 3;
|
||||||
static constexpr std::size_t LongParamLength = 16;
|
static constexpr std::size_t LongParamLength = 16;
|
||||||
}
|
}
|
||||||
|
@ -25,15 +25,13 @@
|
|||||||
using namespace logid::backend;
|
using namespace logid::backend;
|
||||||
using namespace logid::backend::hidpp10;
|
using namespace logid::backend::hidpp10;
|
||||||
|
|
||||||
Device::Device(const std::string& path,
|
Device::Device(const std::string& path, hidpp::DeviceIndex index,
|
||||||
hidpp::DeviceIndex index,
|
const std::shared_ptr<raw::DeviceMonitor>& monitor, double timeout) :
|
||||||
std::shared_ptr<raw::DeviceMonitor> monitor, double timeout) :
|
hidpp::Device(path, index, monitor, timeout) {
|
||||||
hidpp::Device(path, index, std::move(monitor), timeout) {
|
|
||||||
assert(version() == std::make_tuple(1, 0));
|
assert(version() == std::make_tuple(1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::Device(std::shared_ptr<raw::RawDevice> raw_dev,
|
Device::Device(std::shared_ptr<raw::RawDevice> raw_dev, hidpp::DeviceIndex index,
|
||||||
hidpp::DeviceIndex index,
|
|
||||||
double timeout) : hidpp::Device(std::move(raw_dev), index, timeout) {
|
double timeout) : hidpp::Device(std::move(raw_dev), index, timeout) {
|
||||||
assert(version() == std::make_tuple(1, 0));
|
assert(version() == std::make_tuple(1, 0));
|
||||||
}
|
}
|
||||||
@ -45,44 +43,34 @@ Device::Device(const std::shared_ptr<dj::Receiver>& receiver,
|
|||||||
assert(version() == std::make_tuple(1, 0));
|
assert(version() == std::make_tuple(1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
hidpp::Report Device::sendReport(const hidpp::Report& report) {
|
void Device::ResponseSlot::reset() {
|
||||||
decltype(_responses)::iterator response_slot;
|
response.reset();
|
||||||
while (true) {
|
sub_id.reset();
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(_response_lock);
|
|
||||||
response_slot = _responses.find(report.subId());
|
|
||||||
if (response_slot == _responses.end()) {
|
|
||||||
response_slot = _responses.emplace(
|
|
||||||
report.subId(), std::optional<Response>()).first;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::unique_lock<std::mutex> lock(_response_wait_lock);
|
|
||||||
_response_cv.wait(lock, [this, sub_id = report.subId()]() {
|
|
||||||
std::lock_guard<std::mutex> lock(_response_lock);
|
|
||||||
return _responses.find(sub_id) != _responses.end();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sendReportNoResponse(report);
|
hidpp::Report Device::sendReport(const hidpp::Report& report) {
|
||||||
std::unique_lock<std::mutex> wait(_response_wait_lock);
|
auto& response_slot = _responses[report.subId() % SubIDCount];
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(_response_mutex);
|
||||||
|
_response_cv.wait(lock, [&response_slot]() {
|
||||||
|
return !response_slot.sub_id.has_value();
|
||||||
|
});
|
||||||
|
response_slot.sub_id = report.subId();
|
||||||
|
|
||||||
|
_sendReport(report);
|
||||||
bool valid = _response_cv.wait_for(
|
bool valid = _response_cv.wait_for(
|
||||||
wait, io_timeout,
|
lock, io_timeout,
|
||||||
[this, &response_slot]() {
|
[&response_slot]() {
|
||||||
std::lock_guard<std::mutex> lock(_response_lock);
|
return response_slot.response.has_value();
|
||||||
return response_slot->second.has_value();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
std::lock_guard<std::mutex> lock(_response_lock);
|
response_slot.reset();
|
||||||
_responses.erase(response_slot);
|
|
||||||
throw TimeoutError();
|
throw TimeoutError();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(_response_lock);
|
auto response = response_slot.response.value();
|
||||||
assert(response_slot->second.has_value());
|
response_slot.reset();
|
||||||
auto response = response_slot->second.value();
|
|
||||||
_responses.erase(response_slot);
|
|
||||||
if (std::holds_alternative<hidpp::Report>(response))
|
if (std::holds_alternative<hidpp::Report>(response))
|
||||||
return std::get<hidpp::Report>(response);
|
return std::get<hidpp::Report>(response);
|
||||||
else // if(std::holds_alternative<Error::ErrorCode>(response))
|
else // if(std::holds_alternative<Error::ErrorCode>(response))
|
||||||
@ -90,7 +78,7 @@ hidpp::Report Device::sendReport(const hidpp::Report& report) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Device::responseReport(const hidpp::Report& report) {
|
bool Device::responseReport(const hidpp::Report& report) {
|
||||||
std::lock_guard<std::mutex> lock(_response_lock);
|
std::lock_guard<std::mutex> lock(_response_mutex);
|
||||||
uint8_t sub_id;
|
uint8_t sub_id;
|
||||||
|
|
||||||
bool is_error = false;
|
bool is_error = false;
|
||||||
@ -102,15 +90,15 @@ bool Device::responseReport(const hidpp::Report& report) {
|
|||||||
sub_id = report.subId();
|
sub_id = report.subId();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto response_slot = _responses.find(sub_id);
|
auto& response_slot = _responses[sub_id % SubIDCount];
|
||||||
if (response_slot == _responses.end())
|
|
||||||
|
if (!response_slot.sub_id.has_value() || response_slot.sub_id.value() != sub_id)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (is_error) {
|
if (is_error) {
|
||||||
response_slot->second = static_cast<Error::ErrorCode>(
|
response_slot.response = static_cast<Error::ErrorCode>(hidpp10_error.error_code);
|
||||||
hidpp10_error.error_code);
|
|
||||||
} else {
|
} else {
|
||||||
response_slot->second = report;
|
response_slot.response = report;
|
||||||
}
|
}
|
||||||
|
|
||||||
_response_cv.notify_all();
|
_response_cv.notify_all();
|
||||||
|
@ -24,12 +24,13 @@
|
|||||||
|
|
||||||
#include "../hidpp/Device.h"
|
#include "../hidpp/Device.h"
|
||||||
#include "Error.h"
|
#include "Error.h"
|
||||||
|
#include "defs.h"
|
||||||
|
|
||||||
namespace logid::backend::hidpp10 {
|
namespace logid::backend::hidpp10 {
|
||||||
class Device : public hidpp::Device {
|
class Device : public hidpp::Device {
|
||||||
public:
|
public:
|
||||||
Device(const std::string& path, hidpp::DeviceIndex index,
|
Device(const std::string& path, hidpp::DeviceIndex index,
|
||||||
std::shared_ptr<raw::DeviceMonitor> monitor, double timeout);
|
const std::shared_ptr<raw::DeviceMonitor>& monitor, double timeout);
|
||||||
|
|
||||||
Device(std::shared_ptr<raw::RawDevice> raw_dev,
|
Device(std::shared_ptr<raw::RawDevice> raw_dev,
|
||||||
hidpp::DeviceIndex index, double timeout);
|
hidpp::DeviceIndex index, double timeout);
|
||||||
@ -51,15 +52,16 @@ namespace logid::backend::hidpp10 {
|
|||||||
bool responseReport(const hidpp::Report& report) final;
|
bool responseReport(const hidpp::Report& report) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::mutex _response_lock;
|
|
||||||
std::mutex _response_wait_lock;
|
|
||||||
std::condition_variable _response_cv;
|
|
||||||
|
|
||||||
typedef std::variant<hidpp::Report, Error::ErrorCode> Response;
|
typedef std::variant<hidpp::Report, Error::ErrorCode> Response;
|
||||||
std::map<uint8_t, std::optional<Response>> _responses;
|
struct ResponseSlot {
|
||||||
|
std::optional<Response> response;
|
||||||
|
std::optional<uint8_t> sub_id;
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
std::array<ResponseSlot, SubIDCount> _responses;
|
||||||
|
|
||||||
std::vector<uint8_t> accessRegister(uint8_t sub_id,
|
std::vector<uint8_t> accessRegister(
|
||||||
uint8_t address, const std::vector<uint8_t>& params);
|
uint8_t sub_id, uint8_t address, const std::vector<uint8_t>& params);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,10 @@ namespace logid::backend::hidpp10 {
|
|||||||
SetRegisterShort = 0x80,
|
SetRegisterShort = 0x80,
|
||||||
GetRegisterShort = 0x81,
|
GetRegisterShort = 0x81,
|
||||||
SetRegisterLong = 0x82,
|
SetRegisterLong = 0x82,
|
||||||
GetRegisterLong = 0x83
|
GetRegisterLong = 0x83,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static constexpr size_t SubIDCount = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //LOGID_BACKEND_HIDPP10_DEFS_H
|
#endif //LOGID_BACKEND_HIDPP10_DEFS_H
|
@ -26,9 +26,8 @@ using namespace logid::backend;
|
|||||||
using namespace logid::backend::hidpp20;
|
using namespace logid::backend::hidpp20;
|
||||||
|
|
||||||
Device::Device(const std::string& path, hidpp::DeviceIndex index,
|
Device::Device(const std::string& path, hidpp::DeviceIndex index,
|
||||||
std::shared_ptr<raw::DeviceMonitor> monitor, double timeout) :
|
const std::shared_ptr<raw::DeviceMonitor>& monitor, double timeout) :
|
||||||
hidpp::Device(path, index,
|
hidpp::Device(path, index, monitor, timeout) {
|
||||||
std::move(monitor), timeout) {
|
|
||||||
// TODO: Fix version check
|
// TODO: Fix version check
|
||||||
if (std::get<0>(version()) < 2)
|
if (std::get<0>(version()) < 2)
|
||||||
throw std::runtime_error("Invalid HID++ version");
|
throw std::runtime_error("Invalid HID++ version");
|
||||||
@ -68,7 +67,7 @@ std::vector<uint8_t> Device::callFunction(uint8_t feature_index,
|
|||||||
throw hidpp::Report::InvalidReportID();
|
throw hidpp::Report::InvalidReportID();
|
||||||
|
|
||||||
hidpp::Report request(type, deviceIndex(), feature_index, function,
|
hidpp::Report request(type, deviceIndex(), feature_index, function,
|
||||||
LOGID_HIDPP_SOFTWARE_ID);
|
hidpp::softwareID);
|
||||||
std::copy(params.begin(), params.end(), request.paramBegin());
|
std::copy(params.begin(), params.end(), request.paramBegin());
|
||||||
|
|
||||||
auto response = this->sendReport(request);
|
auto response = this->sendReport(request);
|
||||||
@ -87,101 +86,85 @@ void Device::callFunctionNoResponse(uint8_t feature_index, uint8_t function,
|
|||||||
else
|
else
|
||||||
throw hidpp::Report::InvalidReportID();
|
throw hidpp::Report::InvalidReportID();
|
||||||
|
|
||||||
hidpp::Report request(type, deviceIndex(), feature_index, function,
|
hidpp::Report request(type, deviceIndex(), feature_index, function, hidpp::softwareID);
|
||||||
LOGID_HIDPP_SOFTWARE_ID);
|
|
||||||
std::copy(params.begin(), params.end(), request.paramBegin());
|
std::copy(params.begin(), params.end(), request.paramBegin());
|
||||||
|
|
||||||
this->sendReportNoResponse(request);
|
this->sendReportNoACK(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
hidpp::Report Device::sendReport(const hidpp::Report& report) {
|
hidpp::Report Device::sendReport(const hidpp::Report& report) {
|
||||||
decltype(_responses)::iterator response_slot;
|
auto& response_slot = _responses[report.feature() % _responses.size()];
|
||||||
|
|
||||||
while (true) {
|
std::unique_lock<std::mutex> response_lock(_response_mutex);
|
||||||
{
|
_response_cv.wait(response_lock, [&response_slot]() {
|
||||||
std::lock_guard lock(_response_lock);
|
return !response_slot.feature.has_value();
|
||||||
if (_responses.empty()) {
|
|
||||||
response_slot = _responses.emplace(
|
|
||||||
2, std::optional<Response>()).first;
|
|
||||||
break;
|
|
||||||
} else if (_responses.size() < response_slots) {
|
|
||||||
uint8_t i = 0;
|
|
||||||
for (auto& x: _responses) {
|
|
||||||
if (x.first != i + 1) {
|
|
||||||
++i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i = x.first;
|
|
||||||
}
|
|
||||||
assert(_responses.count(i) == 0);
|
|
||||||
|
|
||||||
response_slot = _responses.emplace(
|
|
||||||
i, std::optional<Response>()).first;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(_response_wait_lock);
|
|
||||||
_response_cv.wait(lock, [this, sub_id = report.subId()]() {
|
|
||||||
std::lock_guard<std::mutex> lock(_response_lock);
|
|
||||||
return _responses.size() < response_slots;
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
{
|
response_slot.feature = report.feature();
|
||||||
std::lock_guard<std::mutex> lock(_response_lock);
|
|
||||||
hidpp::Report mod_report{report};
|
|
||||||
mod_report.setSwId(response_slot->first);
|
|
||||||
sendReportNoResponse(std::move(mod_report));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_lock<std::mutex> wait(_response_wait_lock);
|
_sendReport(report);
|
||||||
bool valid = _response_cv.wait_for(wait, io_timeout,
|
|
||||||
[this, &response_slot]() {
|
bool valid = _response_cv.wait_for(
|
||||||
std::lock_guard<std::mutex> lock(_response_lock);
|
response_lock, io_timeout,
|
||||||
return response_slot->second.has_value();
|
[&response_slot]() {
|
||||||
|
return response_slot.response.has_value();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
std::lock_guard<std::mutex> lock(_response_lock);
|
response_slot.reset();
|
||||||
_responses.erase(response_slot);
|
|
||||||
throw TimeoutError();
|
throw TimeoutError();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(_response_lock);
|
assert(response_slot.response.has_value());
|
||||||
assert(response_slot->second.has_value());
|
auto response = response_slot.response.value();
|
||||||
auto response = response_slot->second.value();
|
response_slot.reset();
|
||||||
_responses.erase(response_slot);
|
|
||||||
if (std::holds_alternative<hidpp::Report>(response))
|
if (std::holds_alternative<hidpp::Report>(response))
|
||||||
return std::get<hidpp::Report>(response);
|
return std::get<hidpp::Report>(response);
|
||||||
else // if(std::holds_alternative<Error::ErrorCode>(response))
|
else // if(std::holds_alternative<Error::ErrorCode>(response))
|
||||||
throw Error(std::get<Error::ErrorCode>(response));
|
throw Error(std::get<Error::ErrorCode>(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Device::sendReportNoACK(const hidpp::Report& report) {
|
||||||
|
hidpp::Report no_ack_report(report);
|
||||||
|
no_ack_report.setSwId(hidpp::noAckSoftwareID);
|
||||||
|
_sendReport(std::move(no_ack_report));
|
||||||
|
}
|
||||||
|
|
||||||
bool Device::responseReport(const hidpp::Report& report) {
|
bool Device::responseReport(const hidpp::Report& report) {
|
||||||
std::lock_guard<std::mutex> lock(_response_lock);
|
auto& response_slot = _responses[report.feature() % _responses.size()];
|
||||||
uint8_t sw_id;
|
std::lock_guard<std::mutex> lock(_response_mutex);
|
||||||
|
uint8_t sw_id, feature;
|
||||||
|
|
||||||
bool is_error = false;
|
bool is_error = false;
|
||||||
hidpp::Report::Hidpp20Error hidpp20_error{};
|
hidpp::Report::Hidpp20Error hidpp20_error{};
|
||||||
if (report.isError20(&hidpp20_error)) {
|
if (report.isError20(&hidpp20_error)) {
|
||||||
is_error = true;
|
is_error = true;
|
||||||
sw_id = hidpp20_error.software_id;
|
sw_id = hidpp20_error.software_id;
|
||||||
|
feature = hidpp20_error.feature_index;
|
||||||
} else {
|
} else {
|
||||||
sw_id = report.swId();
|
sw_id = report.swId();
|
||||||
|
feature = report.feature();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto response_slot = _responses.find(sw_id);
|
if (sw_id != hidpp::softwareID)
|
||||||
if (response_slot == _responses.end())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!response_slot.feature || response_slot.feature.value() != feature) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_error) {
|
if (is_error) {
|
||||||
response_slot->second = static_cast<Error::ErrorCode>(
|
response_slot.response = static_cast<Error::ErrorCode>(hidpp20_error.error_code);
|
||||||
hidpp20_error.error_code);
|
|
||||||
} else {
|
} else {
|
||||||
response_slot->second = report;
|
response_slot.response = report;
|
||||||
}
|
}
|
||||||
|
|
||||||
_response_cv.notify_all();
|
_response_cv.notify_all();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Device::ResponseSlot::reset() {
|
||||||
|
response.reset();
|
||||||
|
feature.reset();
|
||||||
|
}
|
||||||
|
@ -30,7 +30,7 @@ namespace logid::backend::hidpp20 {
|
|||||||
class Device : public hidpp::Device {
|
class Device : public hidpp::Device {
|
||||||
public:
|
public:
|
||||||
Device(const std::string& path, hidpp::DeviceIndex index,
|
Device(const std::string& path, hidpp::DeviceIndex index,
|
||||||
std::shared_ptr<raw::DeviceMonitor> monitor, double timeout);
|
const std::shared_ptr<raw::DeviceMonitor>& monitor, double timeout);
|
||||||
|
|
||||||
Device(std::shared_ptr<raw::RawDevice> raw_device,
|
Device(std::shared_ptr<raw::RawDevice> raw_device,
|
||||||
hidpp::DeviceIndex index, double timeout);
|
hidpp::DeviceIndex index, double timeout);
|
||||||
@ -51,17 +51,21 @@ namespace logid::backend::hidpp20 {
|
|||||||
|
|
||||||
hidpp::Report sendReport(const hidpp::Report& report) final;
|
hidpp::Report sendReport(const hidpp::Report& report) final;
|
||||||
|
|
||||||
|
void sendReportNoACK(const hidpp::Report& report) final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool responseReport(const hidpp::Report& report) final;
|
bool responseReport(const hidpp::Report& report) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::mutex _response_lock;
|
|
||||||
std::mutex _response_wait_lock;
|
|
||||||
std::condition_variable _response_cv;
|
|
||||||
|
|
||||||
static constexpr int response_slots = 14;
|
|
||||||
typedef std::variant<hidpp::Report, Error::ErrorCode> Response;
|
typedef std::variant<hidpp::Report, Error::ErrorCode> Response;
|
||||||
std::map<uint8_t, std::optional<Response>> _responses;
|
struct ResponseSlot {
|
||||||
|
std::optional<Response> response;
|
||||||
|
std::optional<uint8_t> feature;
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Multiplex responses on lower nibble of SubID, ignore upper nibble for space */
|
||||||
|
std::array<ResponseSlot, 16> _responses;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,8 +36,7 @@ std::vector<uint8_t> EssentialFeature::callFunction(uint8_t function_id,
|
|||||||
else
|
else
|
||||||
throw hidpp::Report::InvalidReportID();
|
throw hidpp::Report::InvalidReportID();
|
||||||
|
|
||||||
hidpp::Report request(type, _device->deviceIndex(), _index, function_id,
|
hidpp::Report request(type, _device->deviceIndex(), _index, function_id, hidpp::softwareID);
|
||||||
LOGID_HIDPP_SOFTWARE_ID);
|
|
||||||
std::copy(params.begin(), params.end(), request.paramBegin());
|
std::copy(params.begin(), params.end(), request.paramBegin());
|
||||||
|
|
||||||
auto response = _device->sendReport(request);
|
auto response = _device->sendReport(request);
|
||||||
|
@ -86,8 +86,8 @@ void IOMonitor::_listen() {
|
|||||||
_is_running = true;
|
_is_running = true;
|
||||||
|
|
||||||
while (_is_running) {
|
while (_is_running) {
|
||||||
{
|
if (_interrupting) {
|
||||||
std::unique_lock<std::mutex> lock(_interrupt_lock);
|
std::unique_lock<std::mutex> lock(_interrupt_mutex);
|
||||||
_interrupt_cv.wait(lock, [this]() {
|
_interrupt_cv.wait(lock, [this]() {
|
||||||
return !(bool) _interrupting;
|
return !(bool) _interrupting;
|
||||||
});
|
});
|
||||||
|
@ -64,7 +64,7 @@ namespace logid::backend::raw {
|
|||||||
std::atomic_bool _is_running;
|
std::atomic_bool _is_running;
|
||||||
|
|
||||||
std::atomic_bool _interrupting;
|
std::atomic_bool _interrupting;
|
||||||
std::mutex _interrupt_lock;
|
std::mutex _interrupt_mutex;
|
||||||
std::condition_variable _interrupt_cv;
|
std::condition_variable _interrupt_cv;
|
||||||
|
|
||||||
const int _epoll_fd;
|
const int _epoll_fd;
|
||||||
|
@ -155,13 +155,13 @@ void RawDevice::sendReport(const std::vector<uint8_t>& report) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RawDevice::EvHandlerId RawDevice::addEventHandler(RawEventHandler handler) {
|
RawDevice::EvHandlerId RawDevice::addEventHandler(RawEventHandler handler) {
|
||||||
std::lock_guard<std::mutex> lock(_event_handler_lock);
|
std::unique_lock<std::shared_mutex> lock(_event_handler_mutex);
|
||||||
_event_handlers.emplace_front(std::move(handler));
|
_event_handlers.emplace_front(std::move(handler));
|
||||||
return _event_handlers.cbegin();
|
return _event_handlers.cbegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RawDevice::removeEventHandler(RawDevice::EvHandlerId id) {
|
void RawDevice::removeEventHandler(RawDevice::EvHandlerId id) {
|
||||||
std::lock_guard<std::mutex> lock(_event_handler_lock);
|
std::unique_lock<std::shared_mutex> lock(_event_handler_mutex);
|
||||||
_event_handlers.erase(id);
|
_event_handlers.erase(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +185,7 @@ void RawDevice::_readReports() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RawDevice::_handleEvent(const std::vector<uint8_t>& report) {
|
void RawDevice::_handleEvent(const std::vector<uint8_t>& report) {
|
||||||
std::unique_lock<std::mutex> lock(_event_handler_lock);
|
std::shared_lock<std::shared_mutex> lock(_event_handler_mutex);
|
||||||
for (auto& handler: _event_handlers)
|
for (auto& handler: _event_handlers)
|
||||||
if (handler.condition(report))
|
if (handler.condition(report))
|
||||||
handler.callback(report);
|
handler.callback(report);
|
||||||
|
@ -21,8 +21,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <mutex>
|
#include <shared_mutex>
|
||||||
#include <map>
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -85,7 +84,7 @@ namespace logid::backend::raw {
|
|||||||
std::shared_ptr<IOMonitor> _io_monitor;
|
std::shared_ptr<IOMonitor> _io_monitor;
|
||||||
|
|
||||||
std::list<RawEventHandler> _event_handlers;
|
std::list<RawEventHandler> _event_handlers;
|
||||||
std::mutex _event_handler_lock;
|
std::shared_mutex _event_handler_mutex;
|
||||||
|
|
||||||
void _handleEvent(const std::vector<uint8_t>& report);
|
void _handleEvent(const std::vector<uint8_t>& report);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user