From c21a923ab244a70fc29c7dbd64d74246e3888597 Mon Sep 17 00:00:00 2001 From: pixl Date: Thu, 18 Jun 2020 01:34:25 -0400 Subject: [PATCH] Print version number of device 1 on each raw dev. Only works on HID++ >=2.0 so far. Also solves a race condition where the wrong response can be sent to a request. --- src/logid/CMakeLists.txt | 4 + src/logid/DeviceMonitor.cpp | 3 + src/logid/backend/dj/defs.h | 20 ++ src/logid/backend/hidpp/Device.cpp | 19 +- src/logid/backend/hidpp/Device.h | 3 + src/logid/backend/hidpp/Report.cpp | 23 ++- src/logid/backend/hidpp/Report.h | 21 ++- src/logid/backend/hidpp/defs.h | 9 + src/logid/backend/hidpp20/Device.cpp | 25 +++ src/logid/backend/hidpp20/Device.h | 19 ++ src/logid/backend/hidpp20/Error.cpp | 46 +++++ src/logid/backend/hidpp20/Error.h | 39 ++++ src/logid/backend/hidpp20/Feature.cpp | 28 +++ src/logid/backend/hidpp20/Feature.h | 37 ++++ src/logid/backend/hidpp20/feature_defs.h | 191 +++++++++++--------- src/logid/backend/hidpp20/features/Root.cpp | 25 +++ src/logid/backend/hidpp20/features/Root.h | 37 ++++ src/logid/backend/raw/RawDevice.cpp | 86 ++++++++- src/logid/backend/raw/RawDevice.h | 6 +- 19 files changed, 518 insertions(+), 123 deletions(-) create mode 100644 src/logid/backend/dj/defs.h create mode 100644 src/logid/backend/hidpp20/Device.cpp create mode 100644 src/logid/backend/hidpp20/Device.h create mode 100644 src/logid/backend/hidpp20/Error.cpp create mode 100644 src/logid/backend/hidpp20/Error.h create mode 100644 src/logid/backend/hidpp20/Feature.cpp create mode 100644 src/logid/backend/hidpp20/Feature.h create mode 100644 src/logid/backend/hidpp20/features/Root.cpp create mode 100644 src/logid/backend/hidpp20/features/Root.h diff --git a/src/logid/CMakeLists.txt b/src/logid/CMakeLists.txt index e1c0924..e4e10d9 100644 --- a/src/logid/CMakeLists.txt +++ b/src/logid/CMakeLists.txt @@ -17,6 +17,10 @@ add_executable(logid backend/raw/RawDevice.cpp backend/hidpp/Device.cpp backend/hidpp/Report.cpp + backend/hidpp20/Device.cpp + backend/hidpp20/Error.cpp + backend/hidpp20/Feature.cpp + backend/hidpp20/features/Root.cpp backend/dj/Report.cpp util/mutex_queue.h) diff --git a/src/logid/DeviceMonitor.cpp b/src/logid/DeviceMonitor.cpp index 3027e6d..7c4c235 100644 --- a/src/logid/DeviceMonitor.cpp +++ b/src/logid/DeviceMonitor.cpp @@ -105,6 +105,9 @@ void DeviceMonitor::addDevice(std::string path) auto device = std::make_shared(path, hidpp::DeviceIndex::WirelessDevice1); log_printf(DEBUG, "Detected HID++ device at %s", path.c_str()); + auto version = device->version(); + log_printf(DEBUG, "HID++ version: %d.%d", std::get<0>(version), std::get<1>(version)); + auto eventHandler = std::make_shared(); eventHandler->condition = [device](backend::hidpp::Report& report)->bool { diff --git a/src/logid/backend/dj/defs.h b/src/logid/backend/dj/defs.h new file mode 100644 index 0000000..3f373c2 --- /dev/null +++ b/src/logid/backend/dj/defs.h @@ -0,0 +1,20 @@ +#ifndef LOGID_BACKEND_DJ_DEFS_H +#define LOGID_BACKEND_DJ_DEFS_H + +#include + +namespace logid { +namespace backend { +namespace dj +{ + namespace ReportType + { + enum ReportType : uint8_t + { + Short = 0x20, + Long = 0x21 + }; + } +}}} + +#endif //LOGID_BACKEND_DJ_DEFS_H \ No newline at end of file diff --git a/src/logid/backend/hidpp/Device.cpp b/src/logid/backend/hidpp/Device.cpp index 680ff91..d135045 100644 --- a/src/logid/backend/hidpp/Device.cpp +++ b/src/logid/backend/hidpp/Device.cpp @@ -1,6 +1,7 @@ #include #include "Device.h" #include "Report.h" +#include "../hidpp20/features/Root.h" using namespace logid::backend; using namespace logid::backend::hidpp; @@ -29,12 +30,20 @@ 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); + + ///TODO: Catch error + auto versionResponse = sendReport(versionRequest); + auto versionResponse_params = versionResponse.paramBegin(); + _version = std::make_tuple(versionResponse_params[0], versionResponse_params[1]); + // Pass all HID++ events with device index to this device. RawEventHandler rawEventHandler; rawEventHandler.condition = [index](std::vector& report)->bool { - return (report[Offset::Type] == Report::Short || - report[Offset::Type] == Report::Long) && (report[Offset::DeviceIndex] == index); + return (report[Offset::Type] == Report::Type::Short || + report[Offset::Type] == Report::Type::Long) && (report[Offset::DeviceIndex] == index); }; rawEventHandler.callback = [this](std::vector& report)->void { @@ -69,11 +78,11 @@ Report Device::sendReport(Report& report) { switch(report.type()) { - case Report::Short: + case Report::Type::Short: if(!(supported_reports & HIDPP_REPORT_SHORT_SUPPORTED)) - report.setType(Report::Long); + report.setType(Report::Type::Long); break; - case Report::Long: + case Report::Type::Long: /* Report can be truncated, but that isn't a good idea. */ assert(supported_reports & HIDPP_REPORT_LONG_SUPPORTED); } diff --git a/src/logid/backend/hidpp/Device.h b/src/logid/backend/hidpp/Device.h index 8d5aa95..0e91b76 100644 --- a/src/logid/backend/hidpp/Device.h +++ b/src/logid/backend/hidpp/Device.h @@ -40,6 +40,7 @@ namespace hidpp std::string devicePath() const { return path; } DeviceIndex deviceIndex() const { return index; } + std::tuple version() const { return _version; } void listen(); // Runs asynchronously void stopListening(); @@ -56,6 +57,8 @@ namespace hidpp DeviceIndex index; uint8_t supported_reports; + std::tuple _version; + std::map> event_handlers; }; } } } diff --git a/src/logid/backend/hidpp/Report.cpp b/src/logid/backend/hidpp/Report.cpp index 0666db7..22274c1 100644 --- a/src/logid/backend/hidpp/Report.cpp +++ b/src/logid/backend/hidpp/Report.cpp @@ -96,15 +96,15 @@ const char *Report::InvalidReportLength::what() const noexcept Report::Report(Report::Type type, DeviceIndex device_index, uint8_t feature_index, uint8_t function, uint8_t sw_id) { - assert(!(function & functionMask)); - assert(!(sw_id & swIdMask)); + assert(function <= functionMask); + assert(sw_id <= swIdMask); switch(type) { - case Short: + case Type::Short: _data.resize(HeaderLength + ShortParamLength); break; - case Long: + case Type::Long: _data.resize(HeaderLength + LongParamLength); break; default: @@ -123,10 +123,10 @@ Report::Report(const std::vector& data) switch(_data[Offset::Type]) { - case Short: + case Type::Short: _data.resize(HeaderLength + ShortParamLength); break; - case Long: + case Type::Long: _data.resize(HeaderLength + LongParamLength); break; default: @@ -138,10 +138,10 @@ void Report::setType(Report::Type type) { switch(type) { - case Short: + case Type::Short: _data.resize(HeaderLength + ShortParamLength); break; - case Long: + case Type::Long: _data.resize(HeaderLength + LongParamLength); break; default: @@ -158,3 +158,10 @@ void Report::setParams(const std::vector& _params) for(std::size_t i = 0; i < _params.size(); i++) _data[Offset::Parameters + i] = _params[i]; } + +bool Report::isError20(Report::hidpp20_error* error) +{ + if(_data[Offset::Type] != Type::Long || + _data[Offset::Feature] != 0xff) + return false; +} \ No newline at end of file diff --git a/src/logid/backend/hidpp/Report.h b/src/logid/backend/hidpp/Report.h index 90e10b7..1ad7f92 100644 --- a/src/logid/backend/hidpp/Report.h +++ b/src/logid/backend/hidpp/Report.h @@ -26,11 +26,7 @@ namespace logid::backend::hidpp class Report { public: - enum Type: uint8_t - { - Short = 0x10, - Long = 0x11 - }; + typedef ReportType::ReportType Type; class InvalidReportID: public std::exception { @@ -50,19 +46,26 @@ namespace logid::backend::hidpp static constexpr uint8_t swIdMask = 0x0f; static constexpr uint8_t functionMask = 0x0f; - Report(Type type, DeviceIndex device_index, + Report(Report::Type type, DeviceIndex device_index, uint8_t feature_index, uint8_t function, uint8_t sw_id); explicit Report(const std::vector& data); - Type type() const { return static_cast(_data[Offset::Type]); }; + Report::Type type() const { return static_cast(_data[Offset::Type]); }; void setType(Report::Type type); - std::vector::const_iterator paramBegin() const { return _data.begin() + Offset::Parameters; } - std::vector::const_iterator paramEnd() const { return _data.end(); } + std::vector::iterator paramBegin() { return _data.begin() + Offset::Parameters; } + std::vector::iterator paramEnd() { return _data.end(); } void setParams(const std::vector& _params); + struct hidpp20_error + { + uint8_t feature_index, function, software_id, error_code; + }; + + bool isError20(hidpp20_error* error); + logid::backend::hidpp::DeviceIndex deviceIndex() { return static_cast(_data[Offset::DeviceIndex]); diff --git a/src/logid/backend/hidpp/defs.h b/src/logid/backend/hidpp/defs.h index 5539587..d03b347 100644 --- a/src/logid/backend/hidpp/defs.h +++ b/src/logid/backend/hidpp/defs.h @@ -5,6 +5,15 @@ namespace logid::backend::hidpp { + namespace ReportType + { + enum ReportType : uint8_t + { + Short = 0x10, + Long = 0x11 + }; + } + enum DeviceIndex: uint8_t { DefaultDevice = 0, diff --git a/src/logid/backend/hidpp20/Device.cpp b/src/logid/backend/hidpp20/Device.cpp new file mode 100644 index 0000000..917601c --- /dev/null +++ b/src/logid/backend/hidpp20/Device.cpp @@ -0,0 +1,25 @@ +#include + +#include "Device.h" +#include "../hidpp/defs.h" + +using namespace logid::backend::hidpp20; + +std::vector Device::callFunction(uint8_t feature_index, + uint8_t function, std::vector& 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, deviceIndex(), feature_index, function, + LOGID_HIDPP_SOFTWARE_ID); + std::copy(params.begin(), params.end(), request.paramBegin()); + + auto response = this->sendReport(request); + return std::vector(response.paramBegin(), response.paramEnd()); +} \ No newline at end of file diff --git a/src/logid/backend/hidpp20/Device.h b/src/logid/backend/hidpp20/Device.h new file mode 100644 index 0000000..38f42eb --- /dev/null +++ b/src/logid/backend/hidpp20/Device.h @@ -0,0 +1,19 @@ +#ifndef LOGID_HIDPP20_DEVICE_H +#define LOGID_HIDPP20_DEVICE_H + +#include "../hidpp/Device.h" +#include + +namespace logid { +namespace backend { +namespace hidpp20 { + class Device : public hidpp::Device + { + public: + std::vector callFunction(uint8_t feature_index, + uint8_t function, + std::vector& params); + }; +}}} + +#endif //LOGID_HIDPP20_DEVICE_H \ No newline at end of file diff --git a/src/logid/backend/hidpp20/Error.cpp b/src/logid/backend/hidpp20/Error.cpp new file mode 100644 index 0000000..33fdfe1 --- /dev/null +++ b/src/logid/backend/hidpp20/Error.cpp @@ -0,0 +1,46 @@ +#include +#include +#include "Error.h" + +using namespace logid::backend::hidpp20; + +Error::Error(uint8_t code) : _code (code) +{ + assert(_code != NoError); +} + +const char* Error::what() const noexcept +{ + switch(_code) + { + case NoError: + return "No error"; + case Unknown: + return "Unknown"; + case InvalidArgument: + return "Invalid argument"; + case OutOfRange: + return "Out of range"; + case HardwareError: + return "Hardware error"; + case LogitechInternal: + return "Logitech internal feature"; + case InvalidFeatureIndex: + return "Invalid feature index"; + case InvalidFunctionID: + return "Invalid function ID"; + case Busy: + return "Busy"; + case Unsupported: + return "Unsupported"; + case UnknownDevice: + return "Unknown device"; + 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/hidpp20/Error.h b/src/logid/backend/hidpp20/Error.h new file mode 100644 index 0000000..53fec65 --- /dev/null +++ b/src/logid/backend/hidpp20/Error.h @@ -0,0 +1,39 @@ +#ifndef LOGID_BACKEND_HIDPP20_ERROR_H +#define LOGID_BACKEND_HIDPP20_ERROR_H + +#include +#include + +namespace logid { +namespace backend { +namespace hidpp20 { + static constexpr uint8_t ErrorID = 0xFF; + + class Error: public std::exception + { + public: + enum ErrorCode: uint8_t { + NoError = 0, + Unknown = 1, + InvalidArgument = 2, + OutOfRange = 3, + HardwareError = 4, + LogitechInternal = 5, + InvalidFeatureIndex = 6, + InvalidFunctionID = 7, + Busy = 8, + Unsupported = 9, + UnknownDevice = 10 + }; + + Error(uint8_t code); + + virtual const char* what() const noexcept; + uint8_t code() const noexcept; + + private: + uint8_t _code; + }; +}}} + +#endif //LOGID_BACKEND_HIDPP20_ERROR_H \ No newline at end of file diff --git a/src/logid/backend/hidpp20/Feature.cpp b/src/logid/backend/hidpp20/Feature.cpp new file mode 100644 index 0000000..58abb57 --- /dev/null +++ b/src/logid/backend/hidpp20/Feature.cpp @@ -0,0 +1,28 @@ +#include "Feature.h" + +using namespace logid::backend::hidpp20; + +const char* Feature::UnsupportedFeature::what() const noexcept +{ + return "Unsupported feature"; +} + +uint16_t Feature::UnsupportedFeature::code() const noexcept +{ + return _f_id; +} + +std::vector Feature::callFunction(uint8_t function_id, std::vector& params) +{ + return _device->callFunction(_index, function_id, params); +} + +Feature::Feature(Device* dev, uint16_t _id) : _device (dev), _index (0xff) +{ + ///TODO: Set index +} + +Feature::Feature(Device* dev, uint8_t _index) : _device (dev), _index (_index) +{ + +} diff --git a/src/logid/backend/hidpp20/Feature.h b/src/logid/backend/hidpp20/Feature.h new file mode 100644 index 0000000..dcea923 --- /dev/null +++ b/src/logid/backend/hidpp20/Feature.h @@ -0,0 +1,37 @@ +#ifndef LOGID_HIDPP20_FEATURE_H +#define LOGID_HIDPP20_FEATURE_H + +#include +#include "Device.h" + +namespace logid { +namespace backend { +namespace hidpp20 { + class Feature + { + class UnsupportedFeature : public std::exception + { + public: + explicit UnsupportedFeature(uint16_t ID) : _f_id (ID) {} + virtual const char* what() const noexcept; + uint16_t code() const noexcept; + private: + uint16_t _f_id; + }; + + public: + static const uint16_t ID; + virtual uint16_t getID() = 0; + + protected: + explicit Feature(Device* dev, uint16_t _id); + explicit Feature(Device* dev, uint8_t _index); + std::vector callFunction(uint8_t function_id, + std::vector& params); + private: + Device* _device; + uint8_t _index; + }; +}}} + +#endif //LOGID_HIDPP20_FEATURE_H \ No newline at end of file diff --git a/src/logid/backend/hidpp20/feature_defs.h b/src/logid/backend/hidpp20/feature_defs.h index 72de1e1..f72db8f 100644 --- a/src/logid/backend/hidpp20/feature_defs.h +++ b/src/logid/backend/hidpp20/feature_defs.h @@ -6,97 +6,108 @@ namespace logid { namespace backend { namespace hidpp20 { - enum FeatureID : uint16_t - { - ROOT = 0x0000, - FEATURE_SET = 0x0001, - FEATURE_INFO = 0x0002, - FW_VERSION = 0x0003, - DEVICE_NAME = 0x0005, - DEVICE_GROUPS = 0x0006, - DEVICE_FRIENDLY_NAME = 0x0007, - RESET = 0x0020, - CRYPTO_IDENTIFIER = 0x0021, - DFUCONTROL = 0x00c0, - DFUCONTROL_V2 = 0x00c1, - DFUCONTROL_V3 = 0x00c2, - DFU = 0xd000, - BATTERY_STATUS = 0x1000, - BATTERY_VOLTAGE = 0x1001, - CHARGING_CONTROL = 0x1010, - LED_CONTROL = 0x1300, - GENERIC_TEST = 0x1800, - DEVICE_RESET = 0x1802, - OOB_STATE = 0x1805, - CONFIGURABLE_DEVICE_PROPERTIES = 0x1806, - CHANGE_HOST = 0x1814, - HOSTS_INFO = 0x1815, - BACKLIGHT = 0x1981, - BACKLIGHT_V2 = 0x1982, - BACKLIGHT_V3 = 0x1983, - PRESENTER_CONTROL = 0x1a00, - SENSOR_3D = 0x1a01, - REPROG_CONTROLS = 0x1b00, - REPROG_CONTROLS_V2 = 0x1b01, - REPROG_CONTROLS_V2_2 = 0x1b02, - REPROG_CONTROLS_V3 = 0x1b03, - REPROG_CONTROLS_V4 = 0x1b04, - PERSISTENT_REMAPPABLE_ACTION = 0x1bc0, - WIRELESS_DEVICE_STATUS = 0x1d4b, - ENABLE_HIDDEN_FEATURE = 0x1e00, - FIRMWARE_PROPERTIES = 0x1f1f, - ADC_MEASUREMENT = 0x1f20, - LEFT_RIGHT_SWAP = 0x2001, - SWAP_BUTTON = 0x2005, - POINTER_AXES_ORIENTATION = 0x2006, - VERTICAL_SCROLLING = 0x2100, - SMART_SHIFT = 0x2110, - HIRES_SCROLLING = 0x2120, - HIRES_SCROLLING_V2 = 0x2121, // Referred to as Hi-res wheel in cvuchener/hidpp, seems to be V2? - LORES_SCROLLING = 0x2130, - MOUSE_POINTER = 0x2200, // Possibly predecessor to 0x2201? - ADJUSTABLE_DPI = 0x2201, - ANGLE_SNAPPING = 0x2230, - SURFACE_TUNING = 0x2240, - HYBRID_TRACKING = 0x2400, - FN_INVERSION = 0x40a0, - FN_INVERSION_V2 = 0x40a2, // Is 0x40a1 skipped? - FN_INVERSION_V3 = 0x40a3, - ENCRYPTION = 0x4100, - LOCK_KEY_STATE = 0x4220, - SOLAR_DASHBOARD = 0x4301, - KEYBOARD_LAYOUT = 0x4520, - KEYBOARD_DISABLE = 0x4521, - DISABLE_KEYS = 0x4522, - MULTIPLATFORM = 0x4530, // Dual platform only? - MULTIPLATFORM_V2 = 0x4531, - KEYBOARD_LAYOUT_V2 = 0x4540, - CROWN = 0x4600, - TOUCHPAD_FW = 0x6010, - TOUCHPAD_SW = 0x6011, - TOUCHPAD_FW_WIN8 = 0x6012, - TOUCHMOUSE_RAW = 0x6100, - // TOUCHMOUSE_6120 = 0x6120, (Keeping this commented out until a better name is found) - GESTURE = 0x6500, - GESTURE_V2 = 0x6501, - G_KEY = 0x8010, - M_KEY = 0x8020, - // MR = 0x8030, (Keeping this commented out until a better name is found) - BRIGHTNESS_CONTROL = 0x8040, - REPORT_RATE = 0x8060, - RGB_EFFECTS = 0x8070, - RGB_EFFECTS_V2 = 0x8071, - PER_KEY_LIGHTING = 0x8080, - PER_KEY_LIGHTING_V2 = 0x8081, - MODE_STATUS = 0x8100, - MOUSE_BUTTON_SPY = 0x8110, - LATENCY_MONITORING = 0x8111, - GAMING_ATTACHMENTS = 0x8120, - FORCE_FEEDBACK = 0x8123, - SIDETONE = 0x8300, - EQUALIZER = 0x8310, - HEADSET_OUT = 0x8320 + struct feature_info { + uint16_t feature_id; + bool obsolete; + bool internal; + bool hidden; }; + + namespace FeatureID + { + enum FeatureID : uint16_t + { + ROOT = 0x0000, + FEATURE_SET = 0x0001, + FEATURE_INFO = 0x0002, + FW_VERSION = 0x0003, + DEVICE_NAME = 0x0005, + DEVICE_GROUPS = 0x0006, + DEVICE_FRIENDLY_NAME = 0x0007, + RESET = 0x0020, + CRYPTO_IDENTIFIER = 0x0021, + DFUCONTROL = 0x00c0, + DFUCONTROL_V2 = 0x00c1, + DFUCONTROL_V3 = 0x00c2, + DFU = 0xd000, + BATTERY_STATUS = 0x1000, + BATTERY_VOLTAGE = 0x1001, + CHARGING_CONTROL = 0x1010, + LED_CONTROL = 0x1300, + GENERIC_TEST = 0x1800, + DEVICE_RESET = 0x1802, + OOB_STATE = 0x1805, + CONFIGURABLE_DEVICE_PROPERTIES = 0x1806, + CHANGE_HOST = 0x1814, + HOSTS_INFO = 0x1815, + BACKLIGHT = 0x1981, + BACKLIGHT_V2 = 0x1982, + BACKLIGHT_V3 = 0x1983, + PRESENTER_CONTROL = 0x1a00, + SENSOR_3D = 0x1a01, + REPROG_CONTROLS = 0x1b00, + REPROG_CONTROLS_V2 = 0x1b01, + REPROG_CONTROLS_V2_2 = 0x1b02, + REPROG_CONTROLS_V3 = 0x1b03, + REPROG_CONTROLS_V4 = 0x1b04, + PERSISTENT_REMAPPABLE_ACTION = 0x1bc0, + WIRELESS_DEVICE_STATUS = 0x1d4b, + ENABLE_HIDDEN_FEATURE = 0x1e00, + FIRMWARE_PROPERTIES = 0x1f1f, + ADC_MEASUREMENT = 0x1f20, + LEFT_RIGHT_SWAP = 0x2001, + SWAP_BUTTON = 0x2005, + POINTER_AXES_ORIENTATION = 0x2006, + VERTICAL_SCROLLING = 0x2100, + SMART_SHIFT = 0x2110, + HIRES_SCROLLING = 0x2120, + HIRES_SCROLLING_V2 = 0x2121, // Referred to as Hi-res wheel in cvuchener/hidpp, seems to be V2? + LORES_SCROLLING = 0x2130, + MOUSE_POINTER = 0x2200, // Possibly predecessor to 0x2201? + ADJUSTABLE_DPI = 0x2201, + ANGLE_SNAPPING = 0x2230, + SURFACE_TUNING = 0x2240, + HYBRID_TRACKING = 0x2400, + FN_INVERSION = 0x40a0, + FN_INVERSION_V2 = 0x40a2, // Is 0x40a1 skipped? + FN_INVERSION_V3 = 0x40a3, + ENCRYPTION = 0x4100, + LOCK_KEY_STATE = 0x4220, + SOLAR_DASHBOARD = 0x4301, + KEYBOARD_LAYOUT = 0x4520, + KEYBOARD_DISABLE = 0x4521, + DISABLE_KEYS = 0x4522, + MULTIPLATFORM = 0x4530, // Dual platform only? + MULTIPLATFORM_V2 = 0x4531, + KEYBOARD_LAYOUT_V2 = 0x4540, + CROWN = 0x4600, + TOUCHPAD_FW = 0x6010, + TOUCHPAD_SW = 0x6011, + TOUCHPAD_FW_WIN8 = 0x6012, + TOUCHMOUSE_RAW = 0x6100, + // TOUCHMOUSE_6120 = 0x6120, (Keeping this commented out until a better name is found) + GESTURE = 0x6500, + GESTURE_V2 = 0x6501, + G_KEY = 0x8010, + M_KEY = 0x8020, + // MR = 0x8030, (Keeping this commented out until a better name is found) + BRIGHTNESS_CONTROL = 0x8040, + REPORT_RATE = 0x8060, + RGB_EFFECTS = 0x8070, + RGB_EFFECTS_V2 = 0x8071, + PER_KEY_LIGHTING = 0x8080, + PER_KEY_LIGHTING_V2 = 0x8081, + MODE_STATUS = 0x8100, + MOUSE_BUTTON_SPY = 0x8110, + LATENCY_MONITORING = 0x8111, + GAMING_ATTACHMENTS = 0x8120, + FORCE_FEEDBACK = 0x8123, + SIDETONE = 0x8300, + EQUALIZER = 0x8310, + HEADSET_OUT = 0x8320 + }; + } + }}} #endif //LOGID_BACKEND_HIDPP20_FEATUREDEFS \ No newline at end of file diff --git a/src/logid/backend/hidpp20/features/Root.cpp b/src/logid/backend/hidpp20/features/Root.cpp new file mode 100644 index 0000000..8e06874 --- /dev/null +++ b/src/logid/backend/hidpp20/features/Root.cpp @@ -0,0 +1,25 @@ +#include "Root.h" + +using namespace logid::backend::hidpp20; + +Root::Root(Device* dev) : Feature(dev, ID) +{ + +} + +feature_info Root::getFeature(uint16_t feature_id) +{ + feature_info info; + std::vector params(2); + params[0] = feature_id & 0xff; + params[1] = (feature_id >> 8) & 0xff; + + auto response = this->callFunction(Function::Ping, params); + + info.feature_id = response[0]; + info.hidden = response[1] & FeatureFlag::Hidden; + info.obsolete = response[1] & FeatureFlag::Obsolete; + info.internal = response[1] & FeatureFlag::Internal; + + return info; +} \ No newline at end of file diff --git a/src/logid/backend/hidpp20/features/Root.h b/src/logid/backend/hidpp20/features/Root.h new file mode 100644 index 0000000..59a41ea --- /dev/null +++ b/src/logid/backend/hidpp20/features/Root.h @@ -0,0 +1,37 @@ +#ifndef LOGID_BACKEND_HIDPP20_FEATURE_ROOT_H +#define LOGID_BACKEND_HIDPP20_FEATURE_ROOT_H + +#include "../Feature.h" +#include "../feature_defs.h" + +namespace logid { +namespace backend { +namespace hidpp20 +{ + class Root : public Feature + { + public: + static const uint16_t ID = FeatureID::ROOT; + virtual uint16_t getID() { return ID; } + + enum Function : uint8_t + { + GetFeature = 0, + Ping = 1 + }; + + Root(Device* device); + + feature_info getFeature (uint16_t feature_id); + void ping(); + private: + enum FeatureFlag : uint8_t + { + Obsolete = 1<<7, + Hidden = 1<<6, + Internal = 1<<5 + }; + }; +}}} + +#endif //LOGID_BACKEND_HIDPP20_FEATURE_ROOT_H \ No newline at end of file diff --git a/src/logid/backend/raw/RawDevice.cpp b/src/logid/backend/raw/RawDevice.cpp index 473ad25..0def59c 100644 --- a/src/logid/backend/raw/RawDevice.cpp +++ b/src/logid/backend/raw/RawDevice.cpp @@ -1,5 +1,7 @@ #include "RawDevice.h" #include "../Error.h" +#include "../hidpp/defs.h" +#include "../dj/defs.h" #include #include @@ -16,9 +18,16 @@ extern "C" } using namespace logid::backend::raw; +using namespace logid::backend; using namespace std::chrono; -RawDevice::RawDevice(std::string path) : path (path) +bool RawDevice::supportedReportID(uint8_t id) +{ + return (hidpp::ReportType::Short == id) || (hidpp::ReportType::Long == id) || + (dj::ReportType::Short == id) || (dj::ReportType::Long == id); +} + +RawDevice::RawDevice(std::string path) : path (path), continue_listen (false) { int ret; @@ -80,24 +89,81 @@ RawDevice::~RawDevice() std::vector RawDevice::sendReport(const std::vector& report) { - std::packaged_task()> task( - [=]() { - _sendReport(report); - std::vector response; - _readReport(response, MAX_DATA_LENGTH); - return response; - }); + 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. */ if(continue_listen) { + std::packaged_task()> task( [this, report]() { + return this->_respondToReport(report); + }); auto f = task.get_future(); write_queue.push(&task); return f.get(); } else - return task.get_future().get(); + return _respondToReport(report); +} + +std::vector RawDevice::_respondToReport + (const std::vector& request) +{ + _sendReport(request); + while(true) + { + std::vector response; + _readReport(response, MAX_DATA_LENGTH); + + // All reports have the device index at byte 2 + if(response[1] != request[1]) + { + std::thread([this](std::vector report) { + this->handleEvent(report); + }, request).detach(); + continue; + } + + if(hidpp::ReportType::Short == request[0] || + hidpp::ReportType::Long == request[0]) + { + if(hidpp::ReportType::Short != response[0] && + hidpp::ReportType::Long != response[0]) + { + std::thread([this](std::vector report) { + this->handleEvent(report); + }, request).detach(); + continue; + } + + // Error; leave to device to handle + if(response[2] == 0x8f || response[2] == 0xff) + return response; + + bool others_match = true; + for(int i = 2; i < 4; i++) + { + if(response[i] != request[i]) + others_match = false; + } + + if(others_match) + return response; + } + else if(dj::ReportType::Short == request[0] || + dj::ReportType::Long == request[0]) + { + //Error; leave to device ot handle + if(0x7f == response[2]) + return response; + else if(response[2] == request[2]) + return response; + } + + std::thread([this](std::vector report) { + this->handleEvent(report); + }, request).detach(); + } } int RawDevice::_sendReport(const std::vector& report) diff --git a/src/logid/backend/raw/RawDevice.h b/src/logid/backend/raw/RawDevice.h index e7baba6..8e78003 100644 --- a/src/logid/backend/raw/RawDevice.h +++ b/src/logid/backend/raw/RawDevice.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "../defs.h" #include "../../util/mutex_queue.h" @@ -20,12 +21,13 @@ namespace raw class RawDevice { public: + static bool supportedReportID(uint8_t id); + RawDevice(std::string path); ~RawDevice(); std::string hidrawPath() const { return path; } std::vector reportDescriptor() const { return rdesc; } - /// TODO: Process reports in a queue. std::vector sendReport(const std::vector& report); void interruptRead(); @@ -55,6 +57,8 @@ namespace raw int _sendReport(const std::vector& report); int _readReport(std::vector& report, std::size_t maxDataLength); + std::vector _respondToReport(const std::vector& request); + mutex_queue()>*> write_queue; }; }}}