diff --git a/src/logid/CMakeLists.txt b/src/logid/CMakeLists.txt index 610c109..8fb86a9 100644 --- a/src/logid/CMakeLists.txt +++ b/src/logid/CMakeLists.txt @@ -55,6 +55,7 @@ add_executable(logid backend/hidpp20/features/SmartShift.cpp backend/hidpp20/features/ReprogControls.cpp backend/hidpp20/features/HiresScroll.cpp + backend/hidpp20/features/ChangeHost.cpp backend/dj/Report.cpp util/mutex_queue.h util/workqueue.cpp diff --git a/src/logid/backend/hidpp/Device.cpp b/src/logid/backend/hidpp/Device.cpp index 2a5045a..746487e 100644 --- a/src/logid/backend/hidpp/Device.cpp +++ b/src/logid/backend/hidpp/Device.cpp @@ -189,6 +189,22 @@ Report Device::sendReport(Report& report) return response; } +void Device::sendReportNoResponse(Report &report) +{ + switch(report.type()) + { + case Report::Type::Short: + if(!(_supported_reports & HIDPP_REPORT_SHORT_SUPPORTED)) + report.setType(Report::Type::Long); + break; + case Report::Type::Long: + /* Report can be truncated, but that isn't a good idea. */ + assert(_supported_reports & HIDPP_REPORT_LONG_SUPPORTED); + } + + _raw_device->sendReportNoResponse(report.rawReport()); +} + std::string Device::name() const { return _name; diff --git a/src/logid/backend/hidpp/Device.h b/src/logid/backend/hidpp/Device.h index 0ea2062..f6378a5 100644 --- a/src/logid/backend/hidpp/Device.h +++ b/src/logid/backend/hidpp/Device.h @@ -85,6 +85,7 @@ namespace hidpp eventHandlers(); Report sendReport(Report& report); + void sendReportNoResponse(Report& report); void handleEvent(Report& report); private: diff --git a/src/logid/backend/hidpp20/Device.cpp b/src/logid/backend/hidpp20/Device.cpp index 691cc34..9d82d25 100644 --- a/src/logid/backend/hidpp20/Device.cpp +++ b/src/logid/backend/hidpp20/Device.cpp @@ -54,4 +54,24 @@ std::vector Device::callFunction(uint8_t feature_index, auto response = this->sendReport(request); return std::vector(response.paramBegin(), response.paramEnd()); +} + +void Device::callFunctionNoResponse(uint8_t feature_index, uint8_t function, + std::vector ¶ms) +{ + 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; + else + throw hidpp::Report::InvalidReportID(); + + hidpp::Report request(type, deviceIndex(), feature_index, function, + LOGID_HIDPP_SOFTWARE_ID); + std::copy(params.begin(), params.end(), request.paramBegin()); + + this->sendReportNoResponse(request); } \ No newline at end of file diff --git a/src/logid/backend/hidpp20/Device.h b/src/logid/backend/hidpp20/Device.h index 747d36d..770cb8f 100644 --- a/src/logid/backend/hidpp20/Device.h +++ b/src/logid/backend/hidpp20/Device.h @@ -34,6 +34,10 @@ namespace hidpp20 { std::vector callFunction(uint8_t feature_index, uint8_t function, std::vector& params); + + void callFunctionNoResponse(uint8_t feature_index, + uint8_t function, + std::vector& params); }; }}} diff --git a/src/logid/backend/hidpp20/Feature.cpp b/src/logid/backend/hidpp20/Feature.cpp index 18c30b1..1fc62b5 100644 --- a/src/logid/backend/hidpp20/Feature.cpp +++ b/src/logid/backend/hidpp20/Feature.cpp @@ -33,11 +33,18 @@ uint16_t UnsupportedFeature::code() const noexcept return _f_id; } -std::vector Feature::callFunction(uint8_t function_id, std::vector& params) +std::vector Feature::callFunction(uint8_t function_id, + std::vector& params) { return _device->callFunction(_index, function_id, params); } +void Feature::callFunctionNoResponse(uint8_t function_id, + std::vector& params) +{ + _device->callFunctionNoResponse(_index, function_id, params); +} + Feature::Feature(Device* dev, uint16_t _id) : _device (dev) { _index = hidpp20::FeatureID::ROOT; diff --git a/src/logid/backend/hidpp20/Feature.h b/src/logid/backend/hidpp20/Feature.h index 06ec38f..9f11e0c 100644 --- a/src/logid/backend/hidpp20/Feature.h +++ b/src/logid/backend/hidpp20/Feature.h @@ -45,6 +45,8 @@ namespace hidpp20 { explicit Feature(Device* dev, uint16_t _id); std::vector callFunction(uint8_t function_id, std::vector& params); + void callFunctionNoResponse(uint8_t function_id, + std::vector& params); private: Device* _device; uint8_t _index; diff --git a/src/logid/backend/hidpp20/features/ChangeHost.cpp b/src/logid/backend/hidpp20/features/ChangeHost.cpp new file mode 100644 index 0000000..3083718 --- /dev/null +++ b/src/logid/backend/hidpp20/features/ChangeHost.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2019-2020 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include "ChangeHost.h" +#include "../Error.h" + +using namespace logid::backend::hidpp20; + +ChangeHost::ChangeHost(Device *dev) : Feature(dev, ID), _host_count (0) +{ +} + +ChangeHost::HostInfo ChangeHost::getHostInfo() +{ + std::vector params(0); + auto response = callFunction(GetHostInfo, params); + + HostInfo info{}; + info.hostCount = response[0]; + info.currentHost = response[1]; + info.enhancedHostSwitch = response[2] & 1; + + if(!_host_count) + _host_count = info.hostCount; + + return info; +} + +void ChangeHost::setHost(uint8_t host) +{ + /* Expect connection to be severed here, send without response + * + * Since there is no response, we have to emulate any kind of + * error that may be returned (i.e. InvalidArgument as per the docs) + */ + if(!_host_count) + getHostInfo(); + + if(host >= _host_count) + throw hidpp20::Error(hidpp20::Error::InvalidArgument); + + std::vector params = {host}; + + callFunctionNoResponse(SetCurrentHost, params); +} + +std::vector ChangeHost::getCookies() +{ + if(!_host_count) + getHostInfo(); + + std::vector params(0); + auto response = callFunction(GetCookies, params); + + response.resize(_host_count); + + return response; +} + +void ChangeHost::setCookie(uint8_t host, uint8_t cookie) +{ + std::vector params = {host, cookie}; + callFunction(SetCookie, params); +} \ No newline at end of file diff --git a/src/logid/backend/hidpp20/features/ChangeHost.h b/src/logid/backend/hidpp20/features/ChangeHost.h new file mode 100644 index 0000000..094cfb1 --- /dev/null +++ b/src/logid/backend/hidpp20/features/ChangeHost.h @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2020 PixlOne + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#ifndef LOGID_BACKEND_HIDPP20_FEATURE_CHANGEHOST_H +#define LOGID_BACKEND_HIDPP20_FEATURE_CHANGEHOST_H + +#include "../feature_defs.h" +#include "../Feature.h" + +namespace logid { +namespace backend { +namespace hidpp20 +{ + class ChangeHost : public Feature + { + public: + static const uint16_t ID = FeatureID::CHANGE_HOST; + virtual uint16_t getID() { return ID; } + + ChangeHost(Device* dev); + + enum Function { + GetHostInfo = 0, + SetCurrentHost = 1, + GetCookies = 2, + SetCookie = 3 + }; + + struct HostInfo + { + uint8_t hostCount; + uint8_t currentHost; + bool enhancedHostSwitch; + }; + + HostInfo getHostInfo(); + void setHost(uint8_t host); + + std::vector getCookies(); + void setCookie(uint8_t host, uint8_t cookie); + private: + uint8_t _host_count; + }; +}}} + + +#endif //LOGID_BACKEND_HIDPP20_FEATURE_CHANGEHOST_H