mirror of
https://github.com/PixlOne/logiops.git
synced 2025-07-14 05:12:34 +08:00
Add exponential backoff to device monitor
This commit is contained in:
parent
ffd5e054a1
commit
47e4ba2b44
@ -18,9 +18,7 @@
|
||||
|
||||
#include <DeviceManager.h>
|
||||
#include <backend/Error.h>
|
||||
#include <backend/hidpp10/Error.h>
|
||||
#include <util/log.h>
|
||||
#include <ipcgull/function.h>
|
||||
#include <thread>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
@ -100,24 +98,29 @@ void DeviceManager::addDevice(std::string path) {
|
||||
hidpp::Device device(path, hidpp::DefaultDevice, _self.lock(),
|
||||
config()->io_timeout.value_or(defaults::io_timeout));
|
||||
isReceiver = device.version() == std::make_tuple(1, 0);
|
||||
} catch (hidpp20::Error& e) {
|
||||
if (e.code() != hidpp20::Error::UnknownDevice)
|
||||
throw DeviceNotReady();
|
||||
defaultExists = false;
|
||||
} catch (hidpp10::Error& e) {
|
||||
if (e.code() != hidpp10::Error::UnknownDevice)
|
||||
throw;
|
||||
throw DeviceNotReady();
|
||||
defaultExists = false;
|
||||
} catch (hidpp::Device::InvalidDevice& e) {
|
||||
if (e.code() == hidpp::Device::InvalidDevice::VirtualNode) {
|
||||
logPrintf(DEBUG, "Ignoring virtual node on %s",
|
||||
path.c_str());
|
||||
return;
|
||||
logPrintf(DEBUG, "Ignoring virtual node on %s", path.c_str());
|
||||
} else if (e.code() == hidpp::Device::InvalidDevice::Asleep) {
|
||||
/* May be a valid device, wait */
|
||||
throw DeviceNotReady();
|
||||
}
|
||||
|
||||
defaultExists = false;
|
||||
return;
|
||||
} catch (std::system_error& e) {
|
||||
logPrintf(WARN, "I/O error on %s: %s, skipping device.",
|
||||
path.c_str(), e.what());
|
||||
logPrintf(WARN, "I/O error on %s: %s, skipping device.", path.c_str(), e.what());
|
||||
return;
|
||||
} catch (TimeoutError& e) {
|
||||
logPrintf(WARN, "Device %s timed out.", path.c_str());
|
||||
defaultExists = false;
|
||||
/* Ready and valid non-default devices should throw an UnknownDevice error */
|
||||
throw DeviceNotReady();
|
||||
}
|
||||
|
||||
if (isReceiver) {
|
||||
@ -130,28 +133,30 @@ void DeviceManager::addDevice(std::string path) {
|
||||
/* TODO: Can non-receivers only contain 1 device?
|
||||
* If the device exists, it is guaranteed to be an HID++ 2.0 device */
|
||||
if (defaultExists) {
|
||||
auto device = Device::make(path, hidpp::DefaultDevice,
|
||||
_self.lock());
|
||||
auto device = Device::make(path, hidpp::DefaultDevice, _self.lock());
|
||||
std::lock_guard<std::mutex> lock(_map_lock);
|
||||
_devices.emplace(path, device);
|
||||
_ipc_devices->deviceAdded(device);
|
||||
} else {
|
||||
try {
|
||||
auto device = Device::make(path,
|
||||
hidpp::CordedDevice, _self.lock());
|
||||
auto device = Device::make(path, hidpp::CordedDevice, _self.lock());
|
||||
std::lock_guard<std::mutex> lock(_map_lock);
|
||||
_devices.emplace(path, device);
|
||||
_ipc_devices->deviceAdded(device);
|
||||
} catch (hidpp10::Error& e) {
|
||||
if (e.code() != hidpp10::Error::UnknownDevice)
|
||||
throw;
|
||||
else
|
||||
logPrintf(WARN, "HID++ 1.0 error while trying to initialize %s: %s",
|
||||
path.c_str(), e.what());
|
||||
} catch (hidpp::Device::InvalidDevice& e) { // Ignore
|
||||
throw DeviceNotReady();
|
||||
} catch (hidpp20::Error& e) {
|
||||
if (e.code() != hidpp20::Error::UnknownDevice)
|
||||
throw DeviceNotReady();
|
||||
} catch (hidpp::Device::InvalidDevice& e) {
|
||||
if (e.code() == hidpp::Device::InvalidDevice::Asleep)
|
||||
throw DeviceNotReady();
|
||||
} catch (std::system_error& e) {
|
||||
// This error should have been thrown previously
|
||||
logPrintf(WARN, "I/O error on %s: %s", path.c_str(), e.what());
|
||||
} catch (TimeoutError& e) {
|
||||
throw DeviceNotReady();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,12 @@
|
||||
|
||||
#include <backend/Error.h>
|
||||
|
||||
const char* logid::backend::TimeoutError::what() const noexcept {
|
||||
using namespace logid::backend;
|
||||
|
||||
const char* DeviceNotReady::what() const noexcept {
|
||||
return "device not ready";
|
||||
}
|
||||
|
||||
const char* TimeoutError::what() const noexcept {
|
||||
return "Device timed out";
|
||||
}
|
||||
|
@ -22,6 +22,11 @@
|
||||
#include <stdexcept>
|
||||
|
||||
namespace logid::backend {
|
||||
class DeviceNotReady : std::exception {
|
||||
public:
|
||||
[[nodiscard]] const char* what() const noexcept override;
|
||||
};
|
||||
|
||||
class TimeoutError : public std::exception {
|
||||
public:
|
||||
TimeoutError() = default;
|
||||
|
@ -55,7 +55,7 @@ Device::Device(const std::string& path, DeviceIndex index,
|
||||
duration<double, std::milli>(timeout))),
|
||||
_raw_device(std::make_shared<raw::RawDevice>(path, monitor)),
|
||||
_receiver(nullptr), _path(path), _index(index) {
|
||||
_init();
|
||||
_setupReportsAndInit();
|
||||
}
|
||||
|
||||
Device::Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index,
|
||||
@ -64,7 +64,7 @@ Device::Device(std::shared_ptr<raw::RawDevice> raw_device, DeviceIndex index,
|
||||
duration<double, std::milli>(timeout))),
|
||||
_raw_device(std::move(raw_device)), _receiver(nullptr),
|
||||
_path(_raw_device->rawPath()), _index(index) {
|
||||
_init();
|
||||
_setupReportsAndInit();
|
||||
}
|
||||
|
||||
Device::Device(const std::shared_ptr<hidpp10::Receiver>& receiver,
|
||||
@ -81,7 +81,7 @@ Device::Device(const std::shared_ptr<hidpp10::Receiver>& receiver,
|
||||
_pid = event.pid;
|
||||
else
|
||||
_pid = receiver->getPairingInfo(_index).pid;
|
||||
_init();
|
||||
_setupReportsAndInit();
|
||||
}
|
||||
|
||||
Device::Device(const std::shared_ptr<hidpp10::Receiver>& receiver,
|
||||
@ -92,7 +92,7 @@ Device::Device(const std::shared_ptr<hidpp10::Receiver>& receiver,
|
||||
_receiver(receiver), _path(receiver->rawDevice()->rawPath()),
|
||||
_index(index) {
|
||||
_pid = receiver->getPairingInfo(_index).pid;
|
||||
_init();
|
||||
_setupReportsAndInit();
|
||||
}
|
||||
|
||||
const std::string& Device::devicePath() const {
|
||||
@ -107,7 +107,8 @@ const std::tuple<uint8_t, uint8_t>& Device::version() const {
|
||||
return _version;
|
||||
}
|
||||
|
||||
void Device::_init() {
|
||||
|
||||
void Device::_setupReportsAndInit() {
|
||||
_event_handlers = std::make_shared<EventHandlerList<Device>>();
|
||||
|
||||
supported_reports = getSupportedReports(_raw_device->reportDescriptor());
|
||||
@ -132,11 +133,17 @@ void Device::_init() {
|
||||
auto rsp = sendReport({ReportType::Short, _index,
|
||||
hidpp20::FeatureID::ROOT, hidpp20::Root::Ping,
|
||||
hidpp::softwareID});
|
||||
if (rsp.deviceIndex() != _index) {
|
||||
if (rsp.deviceIndex() != _index)
|
||||
throw InvalidDevice(InvalidDevice::VirtualNode);
|
||||
}
|
||||
} catch (hidpp10::Error& e) {
|
||||
// Ignore
|
||||
if (e.deviceIndex() != _index)
|
||||
throw InvalidDevice(InvalidDevice::VirtualNode);
|
||||
} catch (hidpp20::Error& e) {
|
||||
/* This shouldn't happen, the device must not be ready */
|
||||
if (e.deviceIndex() != _index)
|
||||
throw InvalidDevice(InvalidDevice::VirtualNode);
|
||||
else
|
||||
throw DeviceNotReady();
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,6 +159,10 @@ void Device::_init() {
|
||||
this->handleEvent(_report);
|
||||
}});
|
||||
|
||||
_init();
|
||||
}
|
||||
|
||||
void Device::_init() {
|
||||
try {
|
||||
hidpp20::Root root(this);
|
||||
_version = root.getVersion();
|
||||
@ -162,6 +173,20 @@ void Device::_init() {
|
||||
|
||||
// HID++ 2.0 is not supported, assume HID++ 1.0
|
||||
_version = std::make_tuple(1, 0);
|
||||
} catch (hidpp20::Error& e) {
|
||||
/* Should never happen, device not ready? */
|
||||
throw DeviceNotReady();
|
||||
}
|
||||
|
||||
/* Do a stability test before going further */
|
||||
if (std::get<0>(_version) >= 2) {
|
||||
if (!isStable20()) {
|
||||
throw DeviceNotReady();
|
||||
}
|
||||
} else {
|
||||
if (!isStable10()) {
|
||||
throw DeviceNotReady();
|
||||
}
|
||||
}
|
||||
|
||||
if (!_receiver) {
|
||||
@ -230,9 +255,11 @@ Report Device::sendReport(const Report& report) {
|
||||
if (std::holds_alternative<Report>(response)) {
|
||||
return std::get<Report>(response);
|
||||
} else if (std::holds_alternative<Report::Hidpp10Error>(response)) {
|
||||
throw hidpp10::Error(std::get<Report::Hidpp10Error>(response).error_code);
|
||||
auto error = std::get<Report::Hidpp10Error>(response);
|
||||
throw hidpp10::Error(error.error_code, error.device_index);
|
||||
} else if (std::holds_alternative<Report::Hidpp20Error>(response)) {
|
||||
throw hidpp20::Error(std::get<Report::Hidpp20Error>(response).error_code);
|
||||
auto error = std::get<Report::Hidpp20Error>(response);
|
||||
throw hidpp20::Error(error.error_code, error.device_index);
|
||||
}
|
||||
|
||||
// Should not be reached
|
||||
@ -246,10 +273,10 @@ bool Device::responseReport(const Report& report) {
|
||||
|
||||
Report::Hidpp10Error hidpp10_error{};
|
||||
Report::Hidpp20Error hidpp20_error{};
|
||||
if (report.isError10(&hidpp10_error)) {
|
||||
if (report.isError10(hidpp10_error)) {
|
||||
sub_id = hidpp10_error.sub_id;
|
||||
response = hidpp10_error;
|
||||
} else if (report.isError20(&hidpp20_error)) {
|
||||
} else if (report.isError20(hidpp20_error)) {
|
||||
sub_id = hidpp20_error.feature_index;
|
||||
response = hidpp20_error;
|
||||
} else {
|
||||
@ -280,6 +307,27 @@ void Device::sendReportNoACK(const Report& report) {
|
||||
_sendReport(report);
|
||||
}
|
||||
|
||||
bool Device::isStable10() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Device::isStable20() {
|
||||
static constexpr std::string ping_seq = "hello";
|
||||
|
||||
hidpp20::Root root(this);
|
||||
|
||||
try {
|
||||
for (auto c: ping_seq) {
|
||||
if (root.ping(c) != c)
|
||||
return false;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Device::reportFixup(Report& report) const {
|
||||
switch (report.type()) {
|
||||
case Report::Type::Short:
|
||||
|
@ -19,16 +19,16 @@
|
||||
#ifndef LOGID_BACKEND_HIDPP_DEVICE_H
|
||||
#define LOGID_BACKEND_HIDPP_DEVICE_H
|
||||
|
||||
#include <backend/raw/RawDevice.h>
|
||||
#include <backend/hidpp/Report.h>
|
||||
#include <backend/hidpp/defs.h>
|
||||
#include <backend/EventHandlerList.h>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <backend/raw/RawDevice.h>
|
||||
#include <backend/hidpp/Report.h>
|
||||
#include <backend/hidpp/defs.h>
|
||||
#include <backend/EventHandlerList.h>
|
||||
|
||||
namespace logid::backend::hidpp10 {
|
||||
// Need to define here for a constructor
|
||||
@ -100,6 +100,10 @@ namespace logid::backend::hidpp {
|
||||
// Returns whether the report is a response
|
||||
virtual bool responseReport(const Report& report);
|
||||
|
||||
bool isStable20();
|
||||
|
||||
bool isStable10();
|
||||
|
||||
void _sendReport(Report report);
|
||||
|
||||
void reportFixup(Report& report) const;
|
||||
@ -110,6 +114,8 @@ namespace logid::backend::hidpp {
|
||||
std::mutex _response_mutex;
|
||||
std::condition_variable _response_cv;
|
||||
private:
|
||||
void _setupReportsAndInit();
|
||||
|
||||
void _init();
|
||||
|
||||
std::shared_ptr<raw::RawDevice> _raw_device;
|
||||
|
@ -265,31 +265,29 @@ void Report::setParams(const std::vector<uint8_t>& _params) {
|
||||
_data[Offset::Parameters + i] = _params[i];
|
||||
}
|
||||
|
||||
bool Report::isError10(Report::Hidpp10Error* error) const {
|
||||
assert(error != nullptr);
|
||||
|
||||
bool Report::isError10(Report::Hidpp10Error& error) const {
|
||||
if (_data[Offset::Type] != Type::Short ||
|
||||
_data[Offset::SubID] != hidpp10::ErrorID)
|
||||
return false;
|
||||
|
||||
error->sub_id = _data[3];
|
||||
error->address = _data[4];
|
||||
error->error_code = _data[5];
|
||||
error.device_index = deviceIndex();
|
||||
error.sub_id = _data[3];
|
||||
error.address = _data[4];
|
||||
error.error_code = _data[5];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Report::isError20(Report::Hidpp20Error* error) const {
|
||||
assert(error != nullptr);
|
||||
|
||||
bool Report::isError20(Report::Hidpp20Error& error) const {
|
||||
if (_data[Offset::Type] != Type::Long ||
|
||||
_data[Offset::Feature] != hidpp20::ErrorID)
|
||||
return false;
|
||||
|
||||
error->feature_index = _data[3];
|
||||
error->function = (_data[4] >> 4) & 0x0f;
|
||||
error->software_id = _data[4] & 0x0f;
|
||||
error->error_code = _data[5];
|
||||
error.device_index = deviceIndex();
|
||||
error.feature_index = _data[3];
|
||||
error.function = (_data[4] >> 4) & 0x0f;
|
||||
error.software_id = _data[4] & 0x0f;
|
||||
error.error_code = _data[5];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -111,16 +111,18 @@ namespace logid::backend::hidpp {
|
||||
void setParams(const std::vector<uint8_t>& _params);
|
||||
|
||||
struct Hidpp10Error {
|
||||
hidpp::DeviceIndex device_index;
|
||||
uint8_t sub_id, address, error_code;
|
||||
};
|
||||
|
||||
bool isError10(Hidpp10Error* error) const;
|
||||
bool isError10(Hidpp10Error& error) const;
|
||||
|
||||
struct Hidpp20Error {
|
||||
hidpp::DeviceIndex device_index;
|
||||
uint8_t feature_index, function, software_id, error_code;
|
||||
};
|
||||
|
||||
bool isError20(Hidpp20Error* error) const;
|
||||
bool isError20(Hidpp20Error& error) const;
|
||||
|
||||
[[nodiscard]] const std::vector<uint8_t>& rawReport() const;
|
||||
|
||||
|
@ -58,9 +58,9 @@ hidpp::Report Device::sendReport(const hidpp::Report& report) {
|
||||
|
||||
_sendReport(report);
|
||||
bool valid = _response_cv.wait_for(lock, io_timeout,
|
||||
[&response_slot]() {
|
||||
return response_slot.response.has_value();
|
||||
});
|
||||
[&response_slot]() {
|
||||
return response_slot.response.has_value();
|
||||
});
|
||||
|
||||
if (!valid) {
|
||||
response_slot.reset();
|
||||
@ -69,10 +69,13 @@ hidpp::Report Device::sendReport(const hidpp::Report& report) {
|
||||
|
||||
auto response = response_slot.response.value();
|
||||
response_slot.reset();
|
||||
if (std::holds_alternative<hidpp::Report>(response))
|
||||
|
||||
if (std::holds_alternative<hidpp::Report>(response)) {
|
||||
return std::get<hidpp::Report>(response);
|
||||
else // if(std::holds_alternative<Error::ErrorCode>(response))
|
||||
throw Error(std::get<Error::ErrorCode>(response));
|
||||
} else { // if(std::holds_alternative<hidpp::Report::Hidpp10Error>(response))
|
||||
auto error = std::get<hidpp::Report::Hidpp10Error>(response);
|
||||
throw Error(error.error_code, error.device_index);
|
||||
}
|
||||
}
|
||||
|
||||
bool Device::responseReport(const hidpp::Report& report) {
|
||||
@ -81,7 +84,7 @@ bool Device::responseReport(const hidpp::Report& report) {
|
||||
|
||||
bool is_error = false;
|
||||
hidpp::Report::Hidpp10Error hidpp10_error{};
|
||||
if (report.isError10(&hidpp10_error)) {
|
||||
if (report.isError10(hidpp10_error)) {
|
||||
sub_id = hidpp10_error.sub_id;
|
||||
is_error = true;
|
||||
} else {
|
||||
@ -94,7 +97,7 @@ bool Device::responseReport(const hidpp::Report& report) {
|
||||
return false;
|
||||
|
||||
if (is_error) {
|
||||
response_slot.response = static_cast<Error::ErrorCode>(hidpp10_error.error_code);
|
||||
response_slot.response = hidpp10_error;
|
||||
} else {
|
||||
response_slot.response = report;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ namespace logid::backend::hidpp10 {
|
||||
bool responseReport(const hidpp::Report& report) final;
|
||||
|
||||
private:
|
||||
typedef std::variant<hidpp::Report, Error::ErrorCode> Response;
|
||||
typedef std::variant<hidpp::Report, hidpp::Report::Hidpp10Error> Response;
|
||||
struct ResponseSlot {
|
||||
std::optional<Response> response;
|
||||
std::optional<uint8_t> sub_id;
|
||||
|
@ -19,9 +19,10 @@
|
||||
#include <backend/hidpp10/Error.h>
|
||||
#include <cassert>
|
||||
|
||||
using namespace logid::backend;
|
||||
using namespace logid::backend::hidpp10;
|
||||
|
||||
Error::Error(uint8_t code) : _code(code) {
|
||||
Error::Error(uint8_t code, hidpp::DeviceIndex index) : _code(code), _index(index) {
|
||||
assert(code != Success);
|
||||
}
|
||||
|
||||
@ -60,4 +61,8 @@ const char* Error::what() const noexcept {
|
||||
|
||||
uint8_t Error::code() const noexcept {
|
||||
return _code;
|
||||
}
|
||||
}
|
||||
|
||||
hidpp::DeviceIndex Error::deviceIndex() const noexcept {
|
||||
return _index;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#ifndef LOGID_BACKEND_HIDPP10_ERROR_H
|
||||
#define LOGID_BACKEND_HIDPP10_ERROR_H
|
||||
|
||||
#include <backend/hidpp/defs.h>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
|
||||
@ -43,14 +44,17 @@ namespace logid::backend::hidpp10 {
|
||||
WrongPINCode = 0x0C
|
||||
};
|
||||
|
||||
explicit Error(uint8_t code);
|
||||
Error(uint8_t code, hidpp::DeviceIndex index);
|
||||
|
||||
[[nodiscard]] const char* what() const noexcept override;
|
||||
|
||||
[[nodiscard]] uint8_t code() const noexcept;
|
||||
|
||||
[[nodiscard]] hidpp::DeviceIndex deviceIndex() const noexcept;
|
||||
|
||||
private:
|
||||
uint8_t _code;
|
||||
hidpp::DeviceIndex _index;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -118,10 +118,12 @@ hidpp::Report Device::sendReport(const hidpp::Report& report) {
|
||||
auto response = response_slot.response.value();
|
||||
response_slot.reset();
|
||||
|
||||
if (std::holds_alternative<hidpp::Report>(response))
|
||||
if (std::holds_alternative<hidpp::Report>(response)) {
|
||||
return std::get<hidpp::Report>(response);
|
||||
else // if(std::holds_alternative<Error::ErrorCode>(response))
|
||||
throw Error(std::get<Error::ErrorCode>(response));
|
||||
} else { // if(std::holds_alternative<Error::ErrorCode>(response))
|
||||
auto error = std::get<hidpp::Report::Hidpp20Error>(response);
|
||||
throw Error(error.error_code, error.device_index);
|
||||
}
|
||||
}
|
||||
|
||||
void Device::sendReportNoACK(const hidpp::Report& report) {
|
||||
@ -137,7 +139,7 @@ bool Device::responseReport(const hidpp::Report& report) {
|
||||
|
||||
bool is_error = false;
|
||||
hidpp::Report::Hidpp20Error hidpp20_error{};
|
||||
if (report.isError20(&hidpp20_error)) {
|
||||
if (report.isError20(hidpp20_error)) {
|
||||
is_error = true;
|
||||
sw_id = hidpp20_error.software_id;
|
||||
feature = hidpp20_error.feature_index;
|
||||
@ -154,7 +156,7 @@ bool Device::responseReport(const hidpp::Report& report) {
|
||||
}
|
||||
|
||||
if (is_error) {
|
||||
response_slot.response = static_cast<Error::ErrorCode>(hidpp20_error.error_code);
|
||||
response_slot.response = hidpp20_error;
|
||||
} else {
|
||||
response_slot.response = report;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ namespace logid::backend::hidpp20 {
|
||||
bool responseReport(const hidpp::Report& report) final;
|
||||
|
||||
private:
|
||||
typedef std::variant<hidpp::Report, Error::ErrorCode> Response;
|
||||
typedef std::variant<hidpp::Report, hidpp::Report::Hidpp20Error> Response;
|
||||
struct ResponseSlot {
|
||||
std::optional<Response> response;
|
||||
std::optional<uint8_t> feature;
|
||||
|
@ -19,9 +19,10 @@
|
||||
#include <backend/hidpp20/Error.h>
|
||||
#include <cassert>
|
||||
|
||||
using namespace logid::backend;
|
||||
using namespace logid::backend::hidpp20;
|
||||
|
||||
Error::Error(uint8_t code) : _code(code) {
|
||||
Error::Error(uint8_t code, hidpp::DeviceIndex index) : _code(code), _index (index) {
|
||||
assert(_code != NoError);
|
||||
}
|
||||
|
||||
@ -56,4 +57,8 @@ const char* Error::what() const noexcept {
|
||||
|
||||
uint8_t Error::code() const noexcept {
|
||||
return _code;
|
||||
}
|
||||
|
||||
hidpp::DeviceIndex Error::deviceIndex() const noexcept {
|
||||
return _index;
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
#ifndef LOGID_BACKEND_HIDPP20_ERROR_H
|
||||
#define LOGID_BACKEND_HIDPP20_ERROR_H
|
||||
|
||||
#include <backend/hidpp/defs.h>
|
||||
#include <stdexcept>
|
||||
#include <cstdint>
|
||||
|
||||
@ -41,14 +42,17 @@ namespace logid::backend::hidpp20 {
|
||||
UnknownDevice = 10
|
||||
};
|
||||
|
||||
explicit Error(uint8_t code);
|
||||
Error(uint8_t code, hidpp::DeviceIndex index);
|
||||
|
||||
[[nodiscard]] const char* what() const noexcept override;
|
||||
|
||||
[[nodiscard]] uint8_t code() const noexcept;
|
||||
|
||||
[[nodiscard]] hidpp::DeviceIndex deviceIndex() const noexcept;
|
||||
|
||||
private:
|
||||
uint8_t _code;
|
||||
hidpp::DeviceIndex _index;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -40,8 +40,7 @@ namespace logid::backend::hidpp20 {
|
||||
std::vector<uint8_t> callFunction(uint8_t function_id,
|
||||
std::vector<uint8_t>& params);
|
||||
|
||||
private:
|
||||
hidpp::Device* _device;
|
||||
hidpp::Device* const _device;
|
||||
uint8_t _index;
|
||||
};
|
||||
}
|
||||
|
@ -55,8 +55,7 @@ namespace logid::backend::hidpp20 {
|
||||
|
||||
void callFunctionNoResponse(uint8_t function_id, std::vector<uint8_t>& params);
|
||||
|
||||
private:
|
||||
Device* _device;
|
||||
Device* const _device;
|
||||
uint8_t _index;
|
||||
};
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
*
|
||||
*/
|
||||
#include <backend/hidpp20/features/ChangeHost.h>
|
||||
#include <backend/hidpp20/Device.h>
|
||||
#include <backend/hidpp20/Error.h>
|
||||
|
||||
using namespace logid::backend::hidpp20;
|
||||
@ -48,7 +49,7 @@ void ChangeHost::setHost(uint8_t host) {
|
||||
getHostInfo();
|
||||
|
||||
if (host >= _host_count)
|
||||
throw hidpp20::Error(hidpp20::Error::InvalidArgument);
|
||||
throw Error(hidpp20::Error::InvalidArgument, _device->deviceIndex());
|
||||
|
||||
std::vector<uint8_t> params = {host};
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
#include <backend/hidpp20/features/ReprogControls.h>
|
||||
#include <backend/hidpp20/Error.h>
|
||||
#include <backend/hidpp20/Device.h>
|
||||
#include <cassert>
|
||||
|
||||
using namespace logid::backend::hidpp20;
|
||||
@ -106,7 +107,7 @@ ReprogControls::ControlInfo ReprogControls::getControlIdInfo(uint16_t cid) {
|
||||
|
||||
auto it = _cids.find(cid);
|
||||
if (it == _cids.end())
|
||||
throw Error(Error::InvalidArgument);
|
||||
throw Error(Error::InvalidArgument, _device->deviceIndex());
|
||||
else
|
||||
return it->second;
|
||||
}
|
||||
|
@ -61,6 +61,15 @@ feature_info Root::getFeature(uint16_t feature_id) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Root::ping(uint8_t byte) {
|
||||
std::vector<uint8_t> params(3);
|
||||
params[2] = byte;
|
||||
|
||||
auto response = this->callFunction(Root::Function::Ping, params);
|
||||
|
||||
return response[2];
|
||||
}
|
||||
|
||||
std::tuple<uint8_t, uint8_t> Root::getVersion() {
|
||||
std::vector<uint8_t> params(0);
|
||||
auto response = this->callFunction(Root::Function::Ping, params);
|
||||
|
@ -39,6 +39,8 @@ namespace logid::backend::hidpp20 {
|
||||
|
||||
feature_info getFeature(uint16_t feature_id);
|
||||
|
||||
uint8_t ping(uint8_t byte);
|
||||
|
||||
std::tuple<uint8_t, uint8_t> getVersion();
|
||||
|
||||
enum FeatureFlag : uint8_t {
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <backend/raw/IOMonitor.h>
|
||||
#include <backend/raw/RawDevice.h>
|
||||
#include <backend/hidpp/Device.h>
|
||||
#include <backend/Error.h>
|
||||
#include <util/task.h>
|
||||
#include <util/log.h>
|
||||
#include <system_error>
|
||||
@ -95,15 +96,7 @@ void DeviceMonitor::ready() {
|
||||
std::string dev_node = udev_device_get_devnode(device);
|
||||
|
||||
if (action == "add")
|
||||
spawn_task([this, dev_node]() {
|
||||
/* Device was just connected, may not be ready yet.
|
||||
* Sleep for 2 seconds to ensure device is ready before attempting to add.
|
||||
* This is a bit of a hack and this time was determined through a bit of
|
||||
* experimentation.
|
||||
*/
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ready_wait));
|
||||
_addHandler(dev_node);
|
||||
});
|
||||
spawn_task([this, dev_node]() { _addHandler(dev_node); });
|
||||
else if (action == "remove")
|
||||
spawn_task([this, dev_node]() { _removeHandler(dev_node); });
|
||||
|
||||
@ -144,24 +137,37 @@ void DeviceMonitor::enumerate() {
|
||||
std::string dev_node = udev_device_get_devnode(device);
|
||||
udev_device_unref(device);
|
||||
|
||||
_addHandler(dev_node);
|
||||
spawn_task([this, dev_node]() { _addHandler(dev_node); });
|
||||
}
|
||||
|
||||
udev_enumerate_unref(udev_enum);
|
||||
}
|
||||
|
||||
void DeviceMonitor::_addHandler(const std::string& device) {
|
||||
try {
|
||||
auto supported_reports = backend::hidpp::getSupportedReports(
|
||||
RawDevice::getReportDescriptor(device));
|
||||
if (supported_reports)
|
||||
this->addDevice(device);
|
||||
else
|
||||
logPrintf(DEBUG, "Unsupported device %s ignored",
|
||||
device.c_str());
|
||||
} catch (std::exception& e) {
|
||||
logPrintf(WARN, "Error adding device %s: %s",
|
||||
device.c_str(), e.what());
|
||||
int tries;
|
||||
for (tries = 0; tries < max_tries; ++tries) {
|
||||
try {
|
||||
auto supported_reports = backend::hidpp::getSupportedReports(
|
||||
RawDevice::getReportDescriptor(device));
|
||||
if (supported_reports)
|
||||
this->addDevice(device);
|
||||
else
|
||||
logPrintf(DEBUG, "Unsupported device %s ignored", device.c_str());
|
||||
break;
|
||||
} catch (backend::DeviceNotReady& e) {
|
||||
/* Do exponential backoff for 2^tries * backoff ms. */
|
||||
std::chrono::milliseconds timeout((1 << tries) * ready_backoff);
|
||||
logPrintf(DEBUG, "Failed to add device %s on try %d, backing off for %dms",
|
||||
device.c_str(), tries + 1, timeout.count());
|
||||
std::this_thread::sleep_for(timeout);
|
||||
} catch (std::exception& e) {
|
||||
logPrintf(WARN, "Error adding device %s: %s", device.c_str(), e.what());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tries == max_tries) {
|
||||
logPrintf(WARN, "Failed to add device %s after %d tries. Treating as failure.",
|
||||
device.c_str(), max_tries);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,8 @@ struct udev_monitor;
|
||||
namespace logid::backend::raw {
|
||||
class IOMonitor;
|
||||
|
||||
static constexpr int ready_wait = 2000;
|
||||
static constexpr int max_tries = 5;
|
||||
static constexpr int ready_backoff = 500;
|
||||
|
||||
class DeviceMonitor {
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user