diff --git a/src/libhidpp/CMakeLists.txt b/src/libhidpp/CMakeLists.txt index c096cb1..10e2fa2 100644 --- a/src/libhidpp/CMakeLists.txt +++ b/src/libhidpp/CMakeLists.txt @@ -55,6 +55,7 @@ set(LIBHIDPP_SOURCES hidpp20/ITouchpadRawXY.cpp hidpp20/ILEDControl.cpp hidpp20/IBatteryLevelStatus.cpp + hidpp20/IIllumination.cpp hidpp20/ProfileDirectoryFormat.cpp hidpp20/ProfileFormat.cpp hidpp20/MemoryMapping.cpp diff --git a/src/libhidpp/hidpp20/IIllumination.cpp b/src/libhidpp/hidpp20/IIllumination.cpp new file mode 100644 index 0000000..7b8b944 --- /dev/null +++ b/src/libhidpp/hidpp20/IIllumination.cpp @@ -0,0 +1,156 @@ +/* + * Copyright 2024 Bastien Nocera + * + * 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 +#include + +#include + +#include + +using namespace HIDPP20; + +constexpr uint16_t IIllumination::ID; + +IIllumination::IIllumination (Device *dev): + FeatureInterface (dev, ID, "Illumination") +{ +} + +bool IIllumination::getIllumination(void) +{ + std::vector params (16), results; + results = call (GetIllumination, params); + return readLE (results, 0) != 0; +} + +void IIllumination::setIllumination(bool state) +{ + std::vector params (16); + writeLE (params, 0, state); + call (SetIllumination, params); +} + +IIllumination::Info IIllumination::getBrightnessInfo(void) +{ + std::vector params (16), results; + results = call (GetBrightnessInfo, params); + return Info { + (uint8_t)(readLE (results, 0) & 0x0f), // capabilities + readBE (results, 1), // min + readBE (results, 3), // max + readBE (results, 5), // res + (uint8_t)(readLE (results, 7) & 0x0f), // maxLevels + }; +} + +uint16_t IIllumination::getBrightness(void) +{ + uint16_t value; + std::vector params (16), results; + results = call (GetBrightness, params); + value = readBE (results, 0); + return value; +} + +uint16_t IIllumination::getBrightnessEffectiveMax(void) +{ + uint16_t value; + std::vector params (16), results; + try { + results = call (GetBrightnessEffectiveMax, params); + value = readBE (results, 0); + } + catch (HIDPP20::Error &e) { + if (e.errorCode () == HIDPP20::Error::InvalidFunctionID) + value = 0; + else throw e; + } + return value; +} + +void IIllumination::setBrightness(uint16_t value) +{ + std::vector params (16); + writeBE (params, 0, value); + call (SetBrightness, params); +} + +IIllumination::Info IIllumination::getColorTemperatureInfo(void) +{ + std::vector params (16), results; + results = call (GetColorTemperatureInfo, params); + return Info { + (uint8_t)(readLE (results, 0) & 0x0f), // capabilities + readBE (results, 1), // min + readBE (results, 3), // max + readBE (results, 5), // res + (uint8_t)(readLE (results, 7) & 0x0f), // maxLevels + }; +} + +uint16_t IIllumination::getColorTemperature(void) +{ + uint16_t value; + std::vector params (16), results; + results = call (GetColorTemperature, params); + value = readBE (results, 0); + return value; +} + +void IIllumination::setColorTemperature(uint16_t value) +{ + std::vector params (16); + writeBE (params, 0, value); + call (SetColorTemperature, params); +} + +bool IIllumination::illuminationChangeEvent (const HIDPP::Report &event) +{ + assert (event.function () == IIllumination::IlluminationChangeEvent); + auto params = event.parameterBegin (); + return readLE (params) != 0; +} + +uint16_t IIllumination::brightnessChangeEvent (const HIDPP::Report &event) +{ + assert (event.function () == IIllumination::BrightnessChangeEvent); + auto params = event.parameterBegin (); + return readBE (params); +} + +uint16_t IIllumination::colorTemperatureChangeEvent (const HIDPP::Report &event) +{ + assert (event.function () == IIllumination::ColorTemperatureChangeEvent); + auto params = event.parameterBegin (); + return readBE (params); +} + +uint16_t IIllumination::brightnessEffectiveMaxChangeEvent (const HIDPP::Report &event) +{ + assert (event.function () == IIllumination::BrightnessEffectiveMaxChangeEvent); + auto params = event.parameterBegin (); + return readBE (params); +} + +uint16_t IIllumination::brightnessClampedEvent (const HIDPP::Report &event) +{ + assert (event.function () == IIllumination::BrightnessClampedEvent); + auto params = event.parameterBegin (); + return readBE (params); +} diff --git a/src/libhidpp/hidpp20/IIllumination.h b/src/libhidpp/hidpp20/IIllumination.h new file mode 100644 index 0000000..2789847 --- /dev/null +++ b/src/libhidpp/hidpp20/IIllumination.h @@ -0,0 +1,153 @@ +/* + * Copyright 2024 Bastien Nocera + * + * 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 LIBHIDPP_HIDPP20_IILLUMINATION_H +#define LIBHIDPP_HIDPP20_IILLUMINATION_H + +#include + +namespace HIDPP20 +{ + +/** + * Control non-RGB LED features. + */ +class IIllumination: public FeatureInterface +{ +public: + static constexpr uint16_t ID = 0x1990; + + enum Function { + GetIllumination = 0, + SetIllumination = 1, + GetBrightnessInfo = 2, + GetBrightness = 3, + SetBrightness = 4, + GetBrightnessLevels = 5, + SetBrightnessLevels = 6, + GetColorTemperatureInfo = 7, + GetColorTemperature = 8, + SetColorTemperature = 9, + GetColorTemperatureLevels = 10, + SetColorTemperatureLevels = 11, + GetBrightnessEffectiveMax = 12, + }; + + enum Event { + IlluminationChangeEvent = 0, + BrightnessChangeEvent = 1, + ColorTemperatureChangeEvent = 2, + BrightnessEffectiveMaxChangeEvent = 3, + BrightnessClampedEvent = 4, + }; + + enum Flags { + hasEvents = 1 << 0, + hasLinearLevels = 1 << 1, + hasNonLinearLevels = 1 << 2, + hasDynamicMaximum = 1 << 3, + }; + + struct Info { + uint8_t flags; + uint16_t min; + uint16_t max; + uint16_t res; + unsigned int maxLevels : 4; + }; + + IIllumination (Device *dev); + + /** + * Get the current Illumination state. + */ + bool getIllumination(void); + + /** + * Set the current Illumination state. + */ + void setIllumination(bool state); + + /** + * Get information about brightness. + */ + Info getBrightnessInfo(void); + + /** + * Get the current Illumination brightness. + */ + uint16_t getBrightness(void); + + /** + * Get the maximum brightness based on hardware limits, + * 0 means the max value from getBrightnessInfo(). + */ + uint16_t getBrightnessEffectiveMax(void); + + /** + * Set the Illumination brightness. + */ + void setBrightness(uint16_t value); + + /** + * Get information about color temperature. + */ + Info getColorTemperatureInfo(void); + + /** + * Get the current Illumination color temperature. + */ + uint16_t getColorTemperature(void); + + /** + * Set the Illumination color temperature. + */ + void setColorTemperature(uint16_t value); + + /** + * Parse an illumination change event. + */ + static bool illuminationChangeEvent (const HIDPP::Report &event); + + /** + * Parse a brightness change event. + */ + static uint16_t brightnessChangeEvent (const HIDPP::Report &event); + + /** + * Parse a color temperature change event. + */ + static uint16_t colorTemperatureChangeEvent (const HIDPP::Report &event); + + /** + * Parse a change in the effective maximum brightness. + */ + static uint16_t brightnessEffectiveMaxChangeEvent (const HIDPP::Report &event); + + /** + * Parse a notification of a recent request to set the + * brightness to a value larger than the current effective + * maximum brightness. + */ + static uint16_t brightnessClampedEvent (const HIDPP::Report &event); +}; + +} + +#endif + diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index ffda9de..b7c18fa 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -32,6 +32,7 @@ set(TOOLS hidpp20-onboard-profiles-get-description hidpp20-reprog-controls hidpp20-led-control + hidpp20-illumination-light-control hidpp20-dump-page hidpp20-write-page hidpp20-write-data diff --git a/src/tools/hidpp-list-features.cpp b/src/tools/hidpp-list-features.cpp index 8d36e97..658d370 100644 --- a/src/tools/hidpp-list-features.cpp +++ b/src/tools/hidpp-list-features.cpp @@ -59,6 +59,7 @@ static const std::map HIDPP20Features = { { 0x1981, "Backlight" }, { 0x1982, "Backlight" }, { 0x1983, "Backlight" }, + { 0x1990, "Illumination Light control" }, { 0x1a00, "Presenter control" }, { 0x1a01, "3D sensor" }, { 0x1b00, "Reprog controls" }, diff --git a/src/tools/hidpp20-illumination-light-control.cpp b/src/tools/hidpp20-illumination-light-control.cpp new file mode 100644 index 0000000..0a2fdfe --- /dev/null +++ b/src/tools/hidpp20-illumination-light-control.cpp @@ -0,0 +1,317 @@ +/* + * Copyright 2024 Bastien Nocera + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "common/common.h" +#include "common/Option.h" +#include "common/CommonOptions.h" +#include "common/EventQueue.h" + +extern "C" { +#include +#include +#include +} + +using namespace HIDPP20; + +class EventHandler +{ +public: + virtual const HIDPP20::FeatureInterface *feature () const = 0; + virtual void handleEvent (const HIDPP::Report &event) = 0; +}; + +class IlluminationEventHandler: public EventHandler +{ + HIDPP20::IIllumination _ill; + bool _state; + uint16_t _brightness; + uint16_t _temperature; + uint16_t _eff_max; +public: + IlluminationEventHandler (HIDPP20::Device *dev): + _ill (dev), + _state (_ill.getIllumination ()), + _brightness (_ill.getBrightness()), + _temperature (_ill.getColorTemperature()), + _eff_max (_ill.getBrightnessEffectiveMax()) + { + printf ("Light is %s\n", _state ? "on" : "off"); + } + + const HIDPP20::FeatureInterface *feature () const + { + return &_ill; + } + + void handleEvent (const HIDPP::Report &event) + { + bool new_state; + uint16_t value; + + switch (event.function ()) { + case IIllumination::IlluminationChangeEvent: + new_state = IIllumination::illuminationChangeEvent (event); + if (new_state != _state) { + printf ("Light turned %s\n", new_state ? "on" : "off"); + _state = new_state; + } + break; + case IIllumination::BrightnessChangeEvent: + value = IIllumination::brightnessChangeEvent (event); + if (value != _brightness) { + printf ("Brightness changed from %u to %u\n", _brightness, value); + _brightness = value; + } + break; + case IIllumination::ColorTemperatureChangeEvent: + value = IIllumination::colorTemperatureChangeEvent (event); + if (value != _temperature) { + printf ("Color temperature changed from %u to %u\n", _temperature, value); + _temperature = value; + } + break; + case IIllumination::BrightnessEffectiveMaxChangeEvent: + value = IIllumination::brightnessEffectiveMaxChangeEvent (event); + if (value != _eff_max) { + printf ("Effective max brightness changed from %u to %u\n", _eff_max, value); + _eff_max = value; + } + break; + case IIllumination::BrightnessClampedEvent: + value = IIllumination::brightnessClampedEvent (event); + printf ("Brightness clamped to %u\n", value); + break; + } + } +}; + +class EventListener +{ + HIDPP::Dispatcher *dispatcher; + HIDPP::DeviceIndex index; + std::map> handlers; + std::map iterators; +public: + EventListener (HIDPP::Dispatcher *dispatcher, HIDPP::DeviceIndex index): + dispatcher (dispatcher), + index (index) + { + } + + virtual ~EventListener () + { + removeEventHandlers (); + } + + virtual void addEventHandler (std::unique_ptr &&handler) + { + uint8_t feature = handler->feature ()->index (); + EventHandler *ptr = handler.get (); + handlers.emplace (feature, std::move (handler)); + auto it = dispatcher->registerEventHandler (index, feature, [ptr] (const HIDPP::Report &report) { + ptr->handleEvent (report); + return true; + }); + iterators.emplace (feature, it); + } + + virtual void removeEventHandlers () + { + for (const auto &p: iterators) + dispatcher->unregisterEventHandler (p.second); + handlers.clear (); + iterators.clear (); + } + + virtual void start () = 0; + virtual void stop () = 0; + +protected: + virtual bool event (EventHandler *handler, const HIDPP::Report &report) = 0; +}; + +class SimpleListener: public EventListener +{ + HIDPP::SimpleDispatcher *dispatcher; +public: + SimpleListener (HIDPP::SimpleDispatcher *dispatcher, HIDPP::DeviceIndex index): + EventListener (dispatcher, index), + dispatcher (dispatcher) + { + } + + virtual void start () + { + dispatcher->listen (); + } + + virtual void stop () + { + dispatcher->stop (); + } + +protected: + virtual bool event (EventHandler *handler, const HIDPP::Report &report) + { + handler->handleEvent (report); + return true; + } +}; + +EventListener *listener; + +void sigint (int) +{ + listener->stop (); +} + + + +int main (int argc, char *argv[]) +{ + static const char *args = "device_path state|toggle|brightness|temp [params...]"; + HIDPP::DeviceIndex device_index = HIDPP::DefaultDevice; + + std::vector