diff --git a/src/logid/CMakeLists.txt b/src/logid/CMakeLists.txt index e4e10d9..89d2422 100644 --- a/src/logid/CMakeLists.txt +++ b/src/logid/CMakeLists.txt @@ -17,6 +17,7 @@ add_executable(logid backend/raw/RawDevice.cpp backend/hidpp/Device.cpp backend/hidpp/Report.cpp + backend/hidpp10/Error.cpp backend/hidpp20/Device.cpp backend/hidpp20/Error.cpp backend/hidpp20/Feature.cpp diff --git a/src/logid/DeviceMonitor.cpp b/src/logid/DeviceMonitor.cpp index 7c4c235..90b4cdd 100644 --- a/src/logid/DeviceMonitor.cpp +++ b/src/logid/DeviceMonitor.cpp @@ -3,6 +3,7 @@ #include "DeviceMonitor.h" #include "util.h" +#include "backend/hidpp10/Error.h" #define NON_WIRELESS_DEV(index) (index) == HIDPP::DefaultDevice ? "default" : "corded" @@ -128,7 +129,13 @@ void DeviceMonitor::addDevice(std::string path) std::thread([device]() { device->listen(); }).detach(); } - catch(backend::hidpp::Device::InvalidDevice &e) + catch(hidpp10::Error &e) + { + if(e.code() == hidpp10::Error::UnknownDevice) {} + else + throw; + } + catch(hidpp::Device::InvalidDevice &e) { log_printf(DEBUG, "Detected device at %s but %s", path.c_str(), e.what()); } diff --git a/src/logid/backend/hidpp/Device.cpp b/src/logid/backend/hidpp/Device.cpp index d135045..6134475 100644 --- a/src/logid/backend/hidpp/Device.cpp +++ b/src/logid/backend/hidpp/Device.cpp @@ -2,6 +2,8 @@ #include "Device.h" #include "Report.h" #include "../hidpp20/features/Root.h" +#include "../hidpp20/Error.h" +#include "../hidpp10/Error.h" using namespace logid::backend; using namespace logid::backend::hidpp; @@ -30,13 +32,24 @@ Device::Device(const std::string& path, DeviceIndex index): if(!supported_reports) throw InvalidDevice(InvalidDevice::NoHIDPPReport); - Report versionRequest(Report::Type::Short, index, hidpp20::FeatureID::ROOT, - hidpp20::Root::Ping, LOGID_HIDPP_SOFTWARE_ID); + try + { + Report versionRequest(Report::Type::Short, index, hidpp20::FeatureID::ROOT, + hidpp20::Root::Ping, LOGID_HIDPP_SOFTWARE_ID); - ///TODO: Catch error - auto versionResponse = sendReport(versionRequest); - auto versionResponse_params = versionResponse.paramBegin(); - _version = std::make_tuple(versionResponse_params[0], versionResponse_params[1]); + 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 + if(e.code() != hidpp10::Error::InvalidSubID) + throw; + + // HID++ 2.0 is not supported, assume HID++ 1.0 + _version = std::make_tuple(1, 0); + } // Pass all HID++ events with device index to this device. RawEventHandler rawEventHandler; @@ -88,7 +101,18 @@ Report Device::sendReport(Report& report) } auto raw_response = raw_device->sendReport(report.rawReport()); - return Report(raw_response); + + Report response(raw_response); + + Report::hidpp10_error hidpp10Error{}; + if(response.isError10(&hidpp10Error)) + throw hidpp10::Error(hidpp10Error.error_code); + + Report::hidpp20_error hidpp20Error{}; + if(response.isError20(&hidpp20Error)) + throw hidpp10::Error(hidpp20Error.error_code); + + return response; } void Device::listen() diff --git a/src/logid/backend/hidpp/Report.cpp b/src/logid/backend/hidpp/Report.cpp index 22274c1..99e32ea 100644 --- a/src/logid/backend/hidpp/Report.cpp +++ b/src/logid/backend/hidpp/Report.cpp @@ -2,6 +2,8 @@ #include #include #include "Report.h" +#include "../hidpp10/Error.h" +#include "../hidpp20/Error.h" using namespace logid::backend::hidpp; using namespace logid::backend; @@ -159,9 +161,31 @@ void Report::setParams(const std::vector& _params) _data[Offset::Parameters + i] = _params[i]; } +bool Report::isError10(Report::hidpp10_error *error) +{ + assert(error != nullptr); + + 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]; + + return true; +} + bool Report::isError20(Report::hidpp20_error* error) { if(_data[Offset::Type] != Type::Long || - _data[Offset::Feature] != 0xff) + _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]; + + return true; } \ No newline at end of file diff --git a/src/logid/backend/hidpp/Report.h b/src/logid/backend/hidpp/Report.h index 1ad7f92..929f783 100644 --- a/src/logid/backend/hidpp/Report.h +++ b/src/logid/backend/hidpp/Report.h @@ -18,6 +18,7 @@ namespace logid::backend::hidpp { static constexpr uint8_t Type = 0; static constexpr uint8_t DeviceIndex = 1; + static constexpr uint8_t SubID = 2; static constexpr uint8_t Feature = 2; static constexpr uint8_t Function = 3; static constexpr uint8_t Parameters = 4; @@ -59,6 +60,13 @@ namespace logid::backend::hidpp std::vector::iterator paramEnd() { return _data.end(); } void setParams(const std::vector& _params); + struct hidpp10_error + { + uint8_t sub_id, address, error_code; + }; + + bool isError10(hidpp10_error* error); + struct hidpp20_error { uint8_t feature_index, function, software_id, error_code; diff --git a/src/logid/backend/hidpp/defs.h b/src/logid/backend/hidpp/defs.h index d03b347..c026ba3 100644 --- a/src/logid/backend/hidpp/defs.h +++ b/src/logid/backend/hidpp/defs.h @@ -1,7 +1,7 @@ #ifndef LOGID_HIDPP_DEFS_H #define LOGID_HIDPP_DEFS_H -#define LOGID_HIDPP_SOFTWARE_ID 1 +#define LOGID_HIDPP_SOFTWARE_ID 0 namespace logid::backend::hidpp { diff --git a/src/logid/backend/hidpp10/Error.cpp b/src/logid/backend/hidpp10/Error.cpp new file mode 100644 index 0000000..30f6b3f --- /dev/null +++ b/src/logid/backend/hidpp10/Error.cpp @@ -0,0 +1,50 @@ +#include +#include +#include "Error.h" + +using namespace logid::backend::hidpp10; + +Error::Error(uint8_t code): _code(code) +{ + assert(code != Success); +} + +const char* Error::what() const noexcept +{ + switch(_code) + { + case Success: + return "Success"; + case InvalidSubID: + return "Invalid sub ID"; + case InvalidAddress: + return "Invalid address"; + case InvalidValue: + return "Invalid value"; + case ConnectFail: + return "Connection failure"; + case TooManyDevices: + return "Too many devices"; + case AlreadyExists: + return "Already exists"; + case Busy: + return "Busy"; + case UnknownDevice: + return "Unknown device"; + case ResourceError: + return "Resource error"; + case RequestUnavailable: + return "Request unavailable"; + case InvalidParameterValue: + return "Invalid parameter value"; + case WrongPINCode: + return "Wrong PIN code"; + default: + return std::string("Unknown error code " + std::to_string(_code)).c_str(); + } +} + +uint8_t Error::code() const noexcept +{ + return _code; +} \ No newline at end of file diff --git a/src/logid/backend/hidpp10/Error.h b/src/logid/backend/hidpp10/Error.h new file mode 100644 index 0000000..71488b0 --- /dev/null +++ b/src/logid/backend/hidpp10/Error.h @@ -0,0 +1,41 @@ +#ifndef LOGID_BACKEND_HIDPP10_ERROR_H +#define LOGID_BACKEND_HIDPP10_ERROR_H + +#include + +namespace logid { +namespace backend { +namespace hidpp10 { + static constexpr uint8_t ErrorID = 0x8f; + + class Error: public std::exception + { + public: + enum ErrorCode: uint8_t + { + Success = 0x00, + InvalidSubID = 0x01, + InvalidAddress = 0x02, + InvalidValue = 0x03, + ConnectFail = 0x04, + TooManyDevices = 0x05, + AlreadyExists = 0x06, + Busy = 0x07, + UnknownDevice = 0x08, + ResourceError = 0x09, + RequestUnavailable = 0x0A, + InvalidParameterValue = 0x0B, + WrongPINCode = 0x0C + }; + + Error(uint8_t code); + + virtual const char* what() const noexcept; + uint8_t code() const noexcept; + + private: + uint8_t _code; + }; +}}} + +#endif //LOGID_BACKEND_HIDPP10_ERROR_H \ No newline at end of file