diff --git a/CHANGELOG.md b/CHANGELOG.md index a79c236d7..bd16c3197 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ - Add support for HD108 led strip, 16/48bits colors #527 (v20 beta 🆕) - Use optional system libs for compiling #541 (v20 beta 🆕) - Update mbedtls to 3.4.0 #589 (v20 beta 🆕) -- Add Ubuntu support to HyperHDR and Github Pages APT repository #522 (v20 beta 🆕) +- Add Ubuntu support to HyperHDR and Github Pages APT repository #522 (v20 beta 🆕) +- New JsonAPI method to calculate average color of selected instance #611 (v20 beta 🆕) - Workaround for critical Rpi udev bug affecting serial ports #583 (v20 beta 🆕) - Add Arch Linux support #520 (v20 beta 🆕) - Fix chrome/edge fullscreen detection #519 (v20 beta 🆕) diff --git a/include/api/API.h b/include/api/API.h index a4b9ff021..6f8e5a879 100644 --- a/include/api/API.h +++ b/include/api/API.h @@ -212,6 +212,8 @@ class API : public QObject /// void stopInstance(quint8 index); + QJsonObject getAverageColor(quint8 index); + ////////////////////////////////// /// AUTH / ADMINISTRATION METHODS ////////////////////////////////// @@ -365,6 +367,8 @@ class API : public QObject /// bool isUserAuthorized(const QString& password); + bool isUserBlocked(); + /// /// @brief Test if Hyperhdr has the default PW /// @return The result diff --git a/include/api/JsonAPI.h b/include/api/JsonAPI.h index 4433bee96..cab0d9a00 100644 --- a/include/api/JsonAPI.h +++ b/include/api/JsonAPI.h @@ -308,6 +308,8 @@ private slots: void handleSmoothingCommand(const QJsonObject& message, const QString& command, int tan); + void handleCurrentStateCommand(const QJsonObject& message, const QString& command, int tan); + void handleTunnel(const QJsonObject& message, const QString& command, int tan); /// diff --git a/include/base/AuthManager.h b/include/base/AuthManager.h index ce8dcb448..d1aae4e04 100644 --- a/include/base/AuthManager.h +++ b/include/base/AuthManager.h @@ -69,7 +69,7 @@ class AuthManager : public QObject /// @brief Check if user auth is temporary blocked due to failed attempts /// @return True on blocked and no further Auth requests will be accepted /// - bool isUserAuthBlocked() const; + /// /// @brief Check if token auth is temporary blocked due to failed attempts @@ -92,6 +92,8 @@ public slots: /// bool isUserAuthorized(const QString& user, const QString& pw); + bool isUserAuthBlocked() const; + /// /// @brief Check if token is authorized /// @param token The token diff --git a/include/base/HyperHdrIManager.h b/include/base/HyperHdrIManager.h index 7bc771cbb..da4ed10de 100644 --- a/include/base/HyperHdrIManager.h +++ b/include/base/HyperHdrIManager.h @@ -84,6 +84,8 @@ public slots: /// bool stopInstance(quint8 inst); + QJsonObject getAverageColor(quint8 index); + /// /// @brief Toggle the state of all HyperHDR instances /// @param pause If true all instances toggle to pause, else to resume diff --git a/include/base/HyperHdrInstance.h b/include/base/HyperHdrInstance.h index f4dfbf3ae..c6a31cf34 100644 --- a/include/base/HyperHdrInstance.h +++ b/include/base/HyperHdrInstance.h @@ -109,7 +109,10 @@ class HyperHdrInstance : public QObject public slots: + QJsonObject getAverageColor(); + void setSmoothing(int time); + void identifyLed(const QJsonObject& params); bool getReadOnlyMode() { return _readOnlyMode; }; diff --git a/include/utils/Logger.h b/include/utils/Logger.h index 8681cfed6..69caa691b 100644 --- a/include/utils/Logger.h +++ b/include/utils/Logger.h @@ -1,6 +1,7 @@ #pragma once #include +#include // QT includes #include @@ -74,6 +75,7 @@ class Logger : public QObject static void deleteInstance(const QString& name = ""); static void setLogLevel(LogLevel level, const QString& name = ""); static LogLevel getLogLevel(const QString& name = ""); + static QString getLastError(); void Message(LogLevel level, const char* sourceFile, const char* func, unsigned int line, const char* fmt, ...); void setMinLevel(LogLevel level); @@ -97,6 +99,7 @@ class Logger : public QObject static QMutex _mapLock; static QMap _loggerMap; static QAtomicInteger GLOBAL_MIN_LOG_LEVEL; + static QString _lastError; const QString _name; const QString _appname; diff --git a/include/utils/Macros.h b/include/utils/Macros.h new file mode 100644 index 000000000..1d83c098d --- /dev/null +++ b/include/utils/Macros.h @@ -0,0 +1,123 @@ +#pragma once + +/* Macros.h +* +* MIT License +* +* Copyright (c) 2023 awawa-dev +* +* Project homesite: https://github.com/awawa-dev/HyperHDR +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. + +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. + */ + +inline void SAFE_CALL_TEST_FUN() {}; + +#define SAFE_CALL_0_RET(target, method, returnType, result, ...) \ +{ \ + SAFE_CALL_TEST_FUN(__VA_ARGS__); \ + if (target->thread() != this->thread()) \ + QMetaObject::invokeMethod(target, #method, Qt::BlockingQueuedConnection, Q_RETURN_ARG(returnType, result)); \ + else \ + result = target->method(); \ +} + +#define SAFE_CALL_1_RET(target, method, returnType, result, p1type, p1value, ...) \ +{ \ + SAFE_CALL_TEST_FUN(__VA_ARGS__); \ + if (target->thread() != this->thread()) \ + QMetaObject::invokeMethod(target, #method, Qt::BlockingQueuedConnection, Q_RETURN_ARG(returnType, result), Q_ARG(p1type, p1value)); \ + else \ + result = target->method(p1value); \ +} + +#define SAFE_CALL_2_RET(target, method, returnType, result, p1type, p1value, p2type, p2value, ...) \ +{ \ + SAFE_CALL_TEST_FUN(__VA_ARGS__); \ + if (target->thread() != this->thread()) \ + QMetaObject::invokeMethod(target, #method, Qt::BlockingQueuedConnection, Q_RETURN_ARG(returnType, result), Q_ARG(p1type, p1value), Q_ARG(p2type, p2value)); \ + else \ + result = target->method(p1value, p2value); \ +} + +#define SAFE_CALL_3_RET(target, method, returnType, result, p1type, p1value, p2type, p2value, p3type, p3value, ...) \ +{ \ + SAFE_CALL_TEST_FUN(__VA_ARGS__); \ + if (target->thread() != this->thread()) \ + QMetaObject::invokeMethod(target, #method, Qt::BlockingQueuedConnection, Q_RETURN_ARG(returnType, result), Q_ARG(p1type, p1value), Q_ARG(p2type, p2value), Q_ARG(p3type, p3value)); \ + else \ + result = target->method(p1value, p2value, p3value); \ +} + +#define SAFE_CALL_4_RET(target, method, returnType, result, p1type, p1value, p2type, p2value, p3type, p3value, p4type, p4value , ...) \ +{ \ + SAFE_CALL_TEST_FUN(__VA_ARGS__); \ + if (target->thread() != this->thread()) \ + QMetaObject::invokeMethod(target, #method, Qt::BlockingQueuedConnection, Q_RETURN_ARG(returnType, result), Q_ARG(p1type, p1value), Q_ARG(p2type, p2value), Q_ARG(p3type, p3value), Q_ARG(p4type, p4value)); \ + else \ + result = target->method(p1value, p2value, p3value, p4value); \ +} + +#define SAFE_CALL_0(target, method, ...) \ +{ \ + SAFE_CALL_TEST_FUN(__VA_ARGS__); \ + if (true) \ + QMetaObject::invokeMethod(target, #method, Qt::QueuedConnection); \ + else \ + target->method(); \ +} + +#define SAFE_CALL_1(target, method, p1type, p1value, ...) \ +{ \ + SAFE_CALL_TEST_FUN(__VA_ARGS__); \ + if (true) \ + QMetaObject::invokeMethod(target, #method, Qt::QueuedConnection, Q_ARG(p1type, p1value)); \ + else \ + target->method(p1value); \ +} + +#define SAFE_CALL_2(target, method, p1type, p1value, p2type, p2value, ...) \ +{ \ + SAFE_CALL_TEST_FUN(__VA_ARGS__); \ + if (true) \ + QMetaObject::invokeMethod(target, #method, Qt::QueuedConnection, Q_ARG(p1type, p1value), Q_ARG(p2type, p2value)); \ + else \ + target->method(p1value, p2value); \ +} + +#define SAFE_CALL_3(target, method, p1type, p1value, p2type, p2value, p3type, p3value, ...) \ +{ \ + SAFE_CALL_TEST_FUN(__VA_ARGS__); \ + if (true) \ + QMetaObject::invokeMethod(target, #method, Qt::QueuedConnection, Q_ARG(p1type, p1value), Q_ARG(p2type, p2value), Q_ARG(p3type, p3value)); \ + else \ + target->method(p1value, p2value, p3value); \ +} + +#define SAFE_CALL_4(target, method, p1type, p1value, p2type, p2value, p3type, p3value, p4type, p4value , ...) \ +{ \ + SAFE_CALL_TEST_FUN(__VA_ARGS__); \ + if (true) \ + QMetaObject::invokeMethod(target, #method, Qt::QueuedConnection, Q_ARG(p1type, p1value), Q_ARG(p2type, p2value), Q_ARG(p3type, p3value), Q_ARG(p4type, p4value)); \ + else \ + target->method(p1value, p2value, p3value, p4value); \ +} + + + diff --git a/include/utils/RgbChannelAdjustment.h b/include/utils/RgbChannelAdjustment.h index ebf986cce..4ce8eda7b 100644 --- a/include/utils/RgbChannelAdjustment.h +++ b/include/utils/RgbChannelAdjustment.h @@ -18,7 +18,7 @@ class RgbChannelAdjustment /// @param adjustR /// @param adjustG /// @param adjustB - RgbChannelAdjustment(quint8 instance, uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, QString channelName); + RgbChannelAdjustment(quint8 instance, uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, QString channelName, bool enabled); /// /// Transform the given array value @@ -63,6 +63,8 @@ class RgbChannelAdjustment uint8_t correction(uint8_t input) const; + bool isEnabled(); + static RgbChannelAdjustment createRgbChannelAdjustment(quint8 instance, const QJsonObject& colorConfig, const QString& channelName, int defaultR, int defaultG, int defaultB); private: @@ -104,4 +106,6 @@ class RgbChannelAdjustment /// current brightness value uint8_t _brightness; + + bool _enabled; }; diff --git a/sources/api/API.cpp b/sources/api/API.cpp index 78394f540..593747098 100644 --- a/sources/api/API.cpp +++ b/sources/api/API.cpp @@ -337,16 +337,24 @@ QVector API::getAllInstanceData() bool API::startInstance(quint8 index, int tan) { bool res; - (_instanceManager->thread() != this->thread()) - ? QMetaObject::invokeMethod(_instanceManager, "startInstance", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, res), Q_ARG(quint8, index), Q_ARG(bool, false), Q_ARG(QObject*, this), Q_ARG(int, tan)) - : res = _instanceManager->startInstance(index, false, this, tan); + + SAFE_CALL_4_RET(_instanceManager, startInstance, bool, res, quint8, index, bool, false, QObject*, this, int, tan); return res; } void API::stopInstance(quint8 index) { - QMetaObject::invokeMethod(_instanceManager, "stopInstance", Qt::QueuedConnection, Q_ARG(quint8, index)); + SAFE_CALL_1(_instanceManager, stopInstance, quint8, index); +} + +QJsonObject API::getAverageColor(quint8 index) +{ + QJsonObject res; + + SAFE_CALL_1_RET(_instanceManager, getAverageColor, QJsonObject, res, quint8, index); + + return res; } void API::requestActiveRegister(QObject* callerInstance) @@ -557,6 +565,13 @@ bool API::isUserAuthorized(const QString& password) return res; } +bool API::isUserBlocked() +{ + bool res; + SAFE_CALL_0_RET(_authManager, isUserAuthBlocked, bool, res); + return res; +} + bool API::hasHyperhdrDefaultPw() { bool res; diff --git a/sources/api/JSONRPC_schema/schema-current-state.json b/sources/api/JSONRPC_schema/schema-current-state.json new file mode 100644 index 000000000..acae70648 --- /dev/null +++ b/sources/api/JSONRPC_schema/schema-current-state.json @@ -0,0 +1,26 @@ +{ + "type":"object", + "required":true, + "properties":{ + "command": { + "type" : "string", + "required" : true, + "enum" : ["current-state"] + }, + "subcommand" : { + "type" : "string", + "required" : true, + "enum" : ["average-color"] + }, + "tan" : { + "type" : "integer" + }, + "instance": { + "type": "integer", + "minimum" : 0, + "maximum" : 255, + "required": true + } + }, + "additionalProperties": false +} diff --git a/sources/api/JSONRPC_schema/schema.json b/sources/api/JSONRPC_schema/schema.json index 4078c063d..a6b969690 100644 --- a/sources/api/JSONRPC_schema/schema.json +++ b/sources/api/JSONRPC_schema/schema.json @@ -5,7 +5,7 @@ "command": { "type" : "string", "required" : true, - "enum": [ "color", "tunnel", "smoothing", "benchmark", "lut-install", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "load-db", "save-db", "logging", "performance-counters", "lut-calibration", "signal-calibration", "processing", "sysinfo", "videomodehdr", "video-crop", "videomode", "authorize", "instance", "leddevice", "transform", "correction", "temperature", "help", "video-controls" ] + "enum": [ "color", "tunnel", "smoothing", "benchmark", "lut-install", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "current-state", "ledcolors", "load-db", "save-db", "logging", "performance-counters", "lut-calibration", "signal-calibration", "processing", "sysinfo", "videomodehdr", "video-crop", "videomode", "authorize", "instance", "leddevice", "transform", "correction", "temperature", "help", "video-controls" ] } } } diff --git a/sources/api/JSONRPC_schemas.qrc b/sources/api/JSONRPC_schemas.qrc index d4e7c8050..7fe0b6e9b 100644 --- a/sources/api/JSONRPC_schemas.qrc +++ b/sources/api/JSONRPC_schemas.qrc @@ -34,6 +34,7 @@ JSONRPC_schema/schema-tunnel.json JSONRPC_schema/schema-performance-counters.json JSONRPC_schema/schema-smoothing.json + JSONRPC_schema/schema-current-state.json JSONRPC_schema/schema-classic.json JSONRPC_schema/schema-classic.json diff --git a/sources/api/JsonAPI.cpp b/sources/api/JsonAPI.cpp index ab4b7eaf8..c4c7010c8 100644 --- a/sources/api/JsonAPI.cpp +++ b/sources/api/JsonAPI.cpp @@ -225,6 +225,8 @@ void JsonAPI::handleMessage(const QString& messageString, const QString& httpAut handleLutInstallCommand(message, command, tan); else if (command == "smoothing") handleSmoothingCommand(message, command, tan); + else if (command == "current-state") + handleCurrentStateCommand(message, command, tan); else if (command == "transform" || command == "correction" || command == "temperature") sendErrorReply("The command " + command + "is deprecated, please use the HyperHDR Web Interface to configure", command, tan); // END @@ -378,382 +380,403 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString& { try { - QJsonObject info; - // collect priority information - QJsonArray priorities; - uint64_t now = InternalClock::now(); + bool subscribeOnly = false; + if (message.contains("subscribe")) + { + QJsonArray subsArr = message["subscribe"].toArray(); + for (const QJsonValueRef entry : subsArr) + { + if (entry == "performance-update" || entry == "lut-calibration-update") + subscribeOnly = true; + } + } - int currentPriority = -1; - if (QThread::currentThread() == _hyperhdr->thread()) - currentPriority = _hyperhdr->getCurrentPriority(); - else - QMetaObject::invokeMethod(_hyperhdr, "getCurrentPriority", Qt::ConnectionType::BlockingQueuedConnection, Q_RETURN_ARG(int, currentPriority)); + if (!subscribeOnly) + { + QJsonObject info; - QList activePriorities = _hyperhdr->getActivePriorities(); - activePriorities.removeAll(255); - + // collect priority information + QJsonArray priorities; + uint64_t now = InternalClock::now(); - for (int priority : activePriorities) - { - const HyperHdrInstance::InputInfo& priorityInfo = _hyperhdr->getPriorityInfo(priority); - QJsonObject item; - item["priority"] = priority; - if (priorityInfo.timeoutTime_ms > 0) - item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now); + int currentPriority = -1; + if (QThread::currentThread() == _hyperhdr->thread()) + currentPriority = _hyperhdr->getCurrentPriority(); + else + QMetaObject::invokeMethod(_hyperhdr, "getCurrentPriority", Qt::ConnectionType::BlockingQueuedConnection, Q_RETURN_ARG(int, currentPriority)); - // owner has optional informations to the component - if (!priorityInfo.owner.isEmpty()) - item["owner"] = priorityInfo.owner; + QList activePriorities = _hyperhdr->getActivePriorities(); + activePriorities.removeAll(255); - item["componentId"] = QString(hyperhdr::componentToIdString(priorityInfo.componentId)); - item["origin"] = priorityInfo.origin; - item["active"] = (priorityInfo.timeoutTime_ms >= -1); - item["visible"] = (priority == currentPriority); - if (priorityInfo.componentId == hyperhdr::COMP_COLOR && !priorityInfo.ledColors.empty()) + for (int priority : activePriorities) { - QJsonObject LEDcolor; + const HyperHdrInstance::InputInfo& priorityInfo = _hyperhdr->getPriorityInfo(priority); + QJsonObject item; + item["priority"] = priority; + if (priorityInfo.timeoutTime_ms > 0) + item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now); + + // owner has optional informations to the component + if (!priorityInfo.owner.isEmpty()) + item["owner"] = priorityInfo.owner; + + item["componentId"] = QString(hyperhdr::componentToIdString(priorityInfo.componentId)); + item["origin"] = priorityInfo.origin; + item["active"] = (priorityInfo.timeoutTime_ms >= -1); + item["visible"] = (priority == currentPriority); + + if (priorityInfo.componentId == hyperhdr::COMP_COLOR && !priorityInfo.ledColors.empty()) + { + QJsonObject LEDcolor; + + // add RGB Value to Array + QJsonArray RGBValue; + RGBValue.append(priorityInfo.ledColors.begin()->red); + RGBValue.append(priorityInfo.ledColors.begin()->green); + RGBValue.append(priorityInfo.ledColors.begin()->blue); + LEDcolor.insert("RGB", RGBValue); + + uint16_t Hue; + float Saturation, Luminace; + + // add HSL Value to Array + QJsonArray HSLValue; + ColorSys::rgb2hsl(priorityInfo.ledColors.begin()->red, + priorityInfo.ledColors.begin()->green, + priorityInfo.ledColors.begin()->blue, + Hue, Saturation, Luminace); + + HSLValue.append(Hue); + HSLValue.append(Saturation); + HSLValue.append(Luminace); + LEDcolor.insert("HSL", HSLValue); + + item["value"] = LEDcolor; + } - // add RGB Value to Array - QJsonArray RGBValue; - RGBValue.append(priorityInfo.ledColors.begin()->red); - RGBValue.append(priorityInfo.ledColors.begin()->green); - RGBValue.append(priorityInfo.ledColors.begin()->blue); - LEDcolor.insert("RGB", RGBValue); - - uint16_t Hue; - float Saturation, Luminace; - - // add HSL Value to Array - QJsonArray HSLValue; - ColorSys::rgb2hsl(priorityInfo.ledColors.begin()->red, - priorityInfo.ledColors.begin()->green, - priorityInfo.ledColors.begin()->blue, - Hue, Saturation, Luminace); - - HSLValue.append(Hue); - HSLValue.append(Saturation); - HSLValue.append(Luminace); - LEDcolor.insert("HSL", HSLValue); - - item["value"] = LEDcolor; + + (priority == currentPriority) + ? priorities.prepend(item) + : priorities.append(item); } + info["priorities"] = priorities; + info["priorities_autoselect"] = _hyperhdr->sourceAutoSelectEnabled(); - (priority == currentPriority) - ? priorities.prepend(item) - : priorities.append(item); - } + // collect adjustment information + QJsonArray adjustmentArray; + for (const QString& adjustmentId : _hyperhdr->getAdjustmentIds()) + { + const ColorAdjustment* colorAdjustment = _hyperhdr->getAdjustment(adjustmentId); + if (colorAdjustment == nullptr) + { + Error(_log, "Incorrect color adjustment id: %s", QSTRING_CSTR(adjustmentId)); + continue; + } + + QJsonObject adjustment; + adjustment["id"] = adjustmentId; + + QJsonArray whiteAdjust; + whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentR()); + whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentG()); + whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentB()); + adjustment.insert("white", whiteAdjust); + + QJsonArray redAdjust; + redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentR()); + redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentG()); + redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentB()); + adjustment.insert("red", redAdjust); + + QJsonArray greenAdjust; + greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentR()); + greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentG()); + greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentB()); + adjustment.insert("green", greenAdjust); + + QJsonArray blueAdjust; + blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentR()); + blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentG()); + blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentB()); + adjustment.insert("blue", blueAdjust); + + QJsonArray cyanAdjust; + cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentR()); + cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentG()); + cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentB()); + adjustment.insert("cyan", cyanAdjust); + + QJsonArray magentaAdjust; + magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentR()); + magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentG()); + magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentB()); + adjustment.insert("magenta", magentaAdjust); + + QJsonArray yellowAdjust; + yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentR()); + yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentG()); + yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentB()); + adjustment.insert("yellow", yellowAdjust); + + adjustment["backlightThreshold"] = colorAdjustment->_rgbTransform.getBacklightThreshold(); + adjustment["backlightColored"] = colorAdjustment->_rgbTransform.getBacklightColored(); + adjustment["brightness"] = colorAdjustment->_rgbTransform.getBrightness(); + adjustment["brightnessCompensation"] = colorAdjustment->_rgbTransform.getBrightnessCompensation(); + adjustment["gammaRed"] = colorAdjustment->_rgbTransform.getGammaR(); + adjustment["gammaGreen"] = colorAdjustment->_rgbTransform.getGammaG(); + adjustment["gammaBlue"] = colorAdjustment->_rgbTransform.getGammaB(); + adjustment["temperatureRed"] = colorAdjustment->_rgbRedAdjustment.getCorrection(); + adjustment["temperatureGreen"] = colorAdjustment->_rgbGreenAdjustment.getCorrection(); + adjustment["temperatureBlue"] = colorAdjustment->_rgbBlueAdjustment.getCorrection(); + adjustment["saturationGain"] = colorAdjustment->_rgbTransform.getSaturationGain(); + adjustment["luminanceGain"] = colorAdjustment->_rgbTransform.getLuminanceGain(); + adjustment["classic_config"] = colorAdjustment->_rgbTransform.getClassicConfig(); + + adjustmentArray.append(adjustment); + } - info["priorities"] = priorities; - info["priorities_autoselect"] = _hyperhdr->sourceAutoSelectEnabled(); + info["adjustment"] = adjustmentArray; - // collect adjustment information - QJsonArray adjustmentArray; - for (const QString& adjustmentId : _hyperhdr->getAdjustmentIds()) - { - const ColorAdjustment* colorAdjustment = _hyperhdr->getAdjustment(adjustmentId); - if (colorAdjustment == nullptr) + // collect effect info + QJsonArray effects; + const std::list& effectsDefinitions = _hyperhdr->getEffects(); + for (const EffectDefinition& effectDefinition : effectsDefinitions) { - Error(_log, "Incorrect color adjustment id: %s", QSTRING_CSTR(adjustmentId)); - continue; + QJsonObject effect; + effect["name"] = effectDefinition.name; + effect["args"] = effectDefinition.args; + effects.append(effect); } - QJsonObject adjustment; - adjustment["id"] = adjustmentId; - - QJsonArray whiteAdjust; - whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentR()); - whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentG()); - whiteAdjust.append(colorAdjustment->_rgbWhiteAdjustment.getAdjustmentB()); - adjustment.insert("white", whiteAdjust); - - QJsonArray redAdjust; - redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentR()); - redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentG()); - redAdjust.append(colorAdjustment->_rgbRedAdjustment.getAdjustmentB()); - adjustment.insert("red", redAdjust); - - QJsonArray greenAdjust; - greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentR()); - greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentG()); - greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getAdjustmentB()); - adjustment.insert("green", greenAdjust); - - QJsonArray blueAdjust; - blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentR()); - blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentG()); - blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getAdjustmentB()); - adjustment.insert("blue", blueAdjust); - - QJsonArray cyanAdjust; - cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentR()); - cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentG()); - cyanAdjust.append(colorAdjustment->_rgbCyanAdjustment.getAdjustmentB()); - adjustment.insert("cyan", cyanAdjust); - - QJsonArray magentaAdjust; - magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentR()); - magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentG()); - magentaAdjust.append(colorAdjustment->_rgbMagentaAdjustment.getAdjustmentB()); - adjustment.insert("magenta", magentaAdjust); - - QJsonArray yellowAdjust; - yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentR()); - yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentG()); - yellowAdjust.append(colorAdjustment->_rgbYellowAdjustment.getAdjustmentB()); - adjustment.insert("yellow", yellowAdjust); - - adjustment["backlightThreshold"] = colorAdjustment->_rgbTransform.getBacklightThreshold(); - adjustment["backlightColored"] = colorAdjustment->_rgbTransform.getBacklightColored(); - adjustment["brightness"] = colorAdjustment->_rgbTransform.getBrightness(); - adjustment["brightnessCompensation"] = colorAdjustment->_rgbTransform.getBrightnessCompensation(); - adjustment["gammaRed"] = colorAdjustment->_rgbTransform.getGammaR(); - adjustment["gammaGreen"] = colorAdjustment->_rgbTransform.getGammaG(); - adjustment["gammaBlue"] = colorAdjustment->_rgbTransform.getGammaB(); - adjustment["temperatureRed"] = colorAdjustment->_rgbRedAdjustment.getCorrection(); - adjustment["temperatureGreen"] = colorAdjustment->_rgbGreenAdjustment.getCorrection(); - adjustment["temperatureBlue"] = colorAdjustment->_rgbBlueAdjustment.getCorrection(); - adjustment["saturationGain"] = colorAdjustment->_rgbTransform.getSaturationGain(); - adjustment["luminanceGain"] = colorAdjustment->_rgbTransform.getLuminanceGain(); - adjustment["classic_config"] = colorAdjustment->_rgbTransform.getClassicConfig(); - - adjustmentArray.append(adjustment); - } - - info["adjustment"] = adjustmentArray; + info["effects"] = effects; - // collect effect info - QJsonArray effects; - const std::list& effectsDefinitions = _hyperhdr->getEffects(); - for (const EffectDefinition& effectDefinition : effectsDefinitions) - { - QJsonObject effect; - effect["name"] = effectDefinition.name; - effect["args"] = effectDefinition.args; - effects.append(effect); - } + // get available led devices + QJsonObject ledDevices; + QJsonArray availableLedDevices; + for (auto dev : LedDeviceWrapper::getDeviceMap()) + { + availableLedDevices.append(dev.first); + } - info["effects"] = effects; + ledDevices["available"] = availableLedDevices; + info["ledDevices"] = ledDevices; - // get available led devices - QJsonObject ledDevices; - QJsonArray availableLedDevices; - for (auto dev : LedDeviceWrapper::getDeviceMap()) - { - availableLedDevices.append(dev.first); - } +#if defined(ENABLE_SOUNDCAPLINUX) || defined(ENABLE_SOUNDCAPWINDOWS) || defined(ENABLE_SOUNDCAPMACOS) + if (SoundCapture::getInstance() != NULL) + { + QJsonObject resultSound; + auto soundInstance = SoundCapture::getInstance(); - ledDevices["available"] = availableLedDevices; - info["ledDevices"] = ledDevices; + if (QThread::currentThread() == soundInstance->thread()) + resultSound = soundInstance->getJsonInfo(); + else + QMetaObject::invokeMethod(soundInstance, "getJsonInfo", Qt::ConnectionType::BlockingQueuedConnection, Q_RETURN_ARG(QJsonObject, resultSound)); - #if defined(ENABLE_SOUNDCAPLINUX) || defined(ENABLE_SOUNDCAPWINDOWS) || defined(ENABLE_SOUNDCAPMACOS) - if (SoundCapture::getInstance() != NULL) - { - QJsonObject resultSound; - auto soundInstance = SoundCapture::getInstance(); + info["sound"] = resultSound; + } +#endif - if (QThread::currentThread() == soundInstance->thread()) - resultSound = soundInstance->getJsonInfo(); - else - QMetaObject::invokeMethod(soundInstance, "getJsonInfo", Qt::ConnectionType::BlockingQueuedConnection, Q_RETURN_ARG(QJsonObject, resultSound)); +#if defined(ENABLE_DX) || defined(ENABLE_MAC_SYSTEM) || defined(ENABLE_X11) || defined(ENABLE_FRAMEBUFFER) + if (SystemWrapper::getInstance() != nullptr) + { + info["systemGrabbers"] = SystemWrapper::getInstance()->getJsonInfo(); + } +#endif - info["sound"] = resultSound; - } - #endif +#if defined(ENABLE_PROTOBUF) + info["hasPROTOBUF"] = 1; +#else + info["hasPROTOBUF"] = 0; +#endif - #if defined(ENABLE_DX) || defined(ENABLE_MAC_SYSTEM) || defined(ENABLE_X11) || defined(ENABLE_FRAMEBUFFER) - if (SystemWrapper::getInstance() != nullptr) - { - info["systemGrabbers"] = SystemWrapper::getInstance()->getJsonInfo(); - } - #endif - - #if defined(ENABLE_PROTOBUF) - info["hasPROTOBUF"] = 1; - #else - info["hasPROTOBUF"] = 0; - #endif - - #if defined(ENABLE_CEC) - info["hasCEC"] = 1; - #else - info["hasCEC"] = 0; - #endif - - QJsonObject grabbers; - #if defined(ENABLE_V4L2) || defined(ENABLE_MF) || defined(ENABLE_AVF) - grabbers = GrabberWrapper::getInstance()->getJsonInfo(); - QString lutPath = QDir::cleanPath(_instanceManager->getRootPath() + QDir::separator() + "lut_lin_tables.3d"); - grabbers["lut_for_hdr_path"] = lutPath; - if (QFile(lutPath).exists()) - { - grabbers["lut_for_hdr_exists"] = 1; - grabbers["lut_for_hdr_modified_date"] = QFileInfo(lutPath).lastModified().toMSecsSinceEpoch(); - } - else - { - grabbers["lut_for_hdr_exists"] = 0; - } - #endif - info["grabbers"] = grabbers; +#if defined(ENABLE_CEC) + info["hasCEC"] = 1; +#else + info["hasCEC"] = 0; +#endif - if (GrabberWrapper::getInstance() != nullptr) - { - info["videomodehdr"] = GrabberWrapper::getInstance()->getHdrToneMappingEnabled(); - } - else - { - if (FlatBufferServer::getInstance() != nullptr) - info["videomodehdr"] = FlatBufferServer::getInstance()->getHdrToneMappingEnabled(); + QJsonObject grabbers; +#if defined(ENABLE_V4L2) || defined(ENABLE_MF) || defined(ENABLE_AVF) + grabbers = GrabberWrapper::getInstance()->getJsonInfo(); + QString lutPath = QDir::cleanPath(_instanceManager->getRootPath() + QDir::separator() + "lut_lin_tables.3d"); + grabbers["lut_for_hdr_path"] = lutPath; + if (QFile(lutPath).exists()) + { + grabbers["lut_for_hdr_exists"] = 1; + grabbers["lut_for_hdr_modified_date"] = QFileInfo(lutPath).lastModified().toMSecsSinceEpoch(); + } else - info["videomodehdr"] = 0; - } + { + grabbers["lut_for_hdr_exists"] = 0; + } +#endif + info["grabbers"] = grabbers; - // get available components - QJsonArray component; - std::map components = _hyperhdr->getComponentRegister().getRegister(); - for (auto comp : components) - { - QJsonObject item; - item["name"] = QString::fromStdString(hyperhdr::componentToIdString(comp.first)); - item["enabled"] = comp.second; + if (GrabberWrapper::getInstance() != nullptr) + { + info["videomodehdr"] = GrabberWrapper::getInstance()->getHdrToneMappingEnabled(); + } + else + { + if (FlatBufferServer::getInstance() != nullptr) + info["videomodehdr"] = FlatBufferServer::getInstance()->getHdrToneMappingEnabled(); + else + info["videomodehdr"] = 0; + } - component.append(item); - } + // get available components + QJsonArray component; + std::map components = _hyperhdr->getComponentRegister().getRegister(); + for (auto comp : components) + { + QJsonObject item; + item["name"] = QString::fromStdString(hyperhdr::componentToIdString(comp.first)); + item["enabled"] = comp.second; - info["components"] = component; - info["imageToLedMappingType"] = ImageProcessor::mappingTypeToStr(_hyperhdr->getLedMappingType()); + component.append(item); + } - // add sessions - QJsonArray sessions; - #ifdef ENABLE_BONJOUR - for (auto session : BonjourBrowserWrapper::getInstance()->getAllServices()) - { - if (session.port < 0) - continue; - QJsonObject item; - item["name"] = session.serviceName; - item["type"] = session.registeredType; - item["domain"] = session.replyDomain; - item["host"] = session.hostName; - item["address"] = session.address; - item["port"] = session.port; - sessions.append(item); - } - info["sessions"] = sessions; - #endif - // add instance info - QJsonArray instanceInfo; - for (const auto& entry : API::getAllInstanceData()) - { - QJsonObject obj; - obj.insert("friendly_name", entry["friendly_name"].toString()); - obj.insert("instance", entry["instance"].toInt()); - //obj.insert("last_use", entry["last_use"].toString()); - obj.insert("running", entry["running"].toBool()); - instanceInfo.append(obj); - } - info["instance"] = instanceInfo; + info["components"] = component; + info["imageToLedMappingType"] = ImageProcessor::mappingTypeToStr(_hyperhdr->getLedMappingType()); - // add leds configs - info["leds"] = _hyperhdr->getSetting(settings::type::LEDS).array(); + info["lastError"] = Logger::getLastError(); - // HOST NAME - info["hostname"] = QHostInfo::localHostName(); + // add sessions + QJsonArray sessions; +#ifdef ENABLE_BONJOUR + for (auto session : BonjourBrowserWrapper::getInstance()->getAllServices()) + { + if (session.port < 0) + continue; + QJsonObject item; + item["name"] = session.serviceName; + item["type"] = session.registeredType; + item["domain"] = session.replyDomain; + item["host"] = session.hostName; + item["address"] = session.address; + item["port"] = session.port; + sessions.append(item); + } + info["sessions"] = sessions; +#endif + // add instance info + QJsonArray instanceInfo; + for (const auto& entry : API::getAllInstanceData()) + { + QJsonObject obj; + obj.insert("friendly_name", entry["friendly_name"].toString()); + obj.insert("instance", entry["instance"].toInt()); + //obj.insert("last_use", entry["last_use"].toString()); + obj.insert("running", entry["running"].toBool()); + instanceInfo.append(obj); + } + info["instance"] = instanceInfo; + if (_hyperhdr != nullptr) + info["currentInstance"] = _hyperhdr->getInstanceIndex(); - // TRANSFORM INFORMATION (DEFAULT VALUES) - QJsonArray transformArray; - for (const QString& transformId : _hyperhdr->getAdjustmentIds()) - { - QJsonObject transform; - QJsonArray blacklevel, whitelevel, gamma, threshold; + // add leds configs + info["leds"] = _hyperhdr->getSetting(settings::type::LEDS).array(); - transform["id"] = transformId; - transform["saturationGain"] = 1.0; - transform["valueGain"] = 1.0; - transform["saturationLGain"] = 1.0; - transform["luminanceGain"] = 1.0; - transform["luminanceMinimum"] = 0.0; + // HOST NAME + info["hostname"] = QHostInfo::localHostName(); - for (int i = 0; i < 3; i++) + // TRANSFORM INFORMATION (DEFAULT VALUES) + QJsonArray transformArray; + for (const QString& transformId : _hyperhdr->getAdjustmentIds()) { - blacklevel.append(0.0); - whitelevel.append(1.0); - gamma.append(2.50); - threshold.append(0.0); - } + QJsonObject transform; + QJsonArray blacklevel, whitelevel, gamma, threshold; - transform.insert("blacklevel", blacklevel); - transform.insert("whitelevel", whitelevel); - transform.insert("gamma", gamma); - transform.insert("threshold", threshold); + transform["id"] = transformId; + transform["saturationGain"] = 1.0; + transform["valueGain"] = 1.0; + transform["saturationLGain"] = 1.0; + transform["luminanceGain"] = 1.0; + transform["luminanceMinimum"] = 0.0; - transformArray.append(transform); - } - info["transform"] = transformArray; + for (int i = 0; i < 3; i++) + { + blacklevel.append(0.0); + whitelevel.append(1.0); + gamma.append(2.50); + threshold.append(0.0); + } - // ACTIVE EFFECT INFO - QJsonArray activeEffects; - for (const ActiveEffectDefinition& activeEffectDefinition : _hyperhdr->getActiveEffects()) - { - if (activeEffectDefinition.priority != PriorityMuxer::LOWEST_PRIORITY - 1) + transform.insert("blacklevel", blacklevel); + transform.insert("whitelevel", whitelevel); + transform.insert("gamma", gamma); + transform.insert("threshold", threshold); + + transformArray.append(transform); + } + info["transform"] = transformArray; + + // ACTIVE EFFECT INFO + QJsonArray activeEffects; + for (const ActiveEffectDefinition& activeEffectDefinition : _hyperhdr->getActiveEffects()) { - QJsonObject activeEffect; - activeEffect["name"] = activeEffectDefinition.name; - activeEffect["priority"] = activeEffectDefinition.priority; - activeEffect["timeout"] = activeEffectDefinition.timeout; - activeEffect["args"] = activeEffectDefinition.args; - activeEffects.append(activeEffect); + if (activeEffectDefinition.priority != PriorityMuxer::LOWEST_PRIORITY - 1) + { + QJsonObject activeEffect; + activeEffect["name"] = activeEffectDefinition.name; + activeEffect["priority"] = activeEffectDefinition.priority; + activeEffect["timeout"] = activeEffectDefinition.timeout; + activeEffect["args"] = activeEffectDefinition.args; + activeEffects.append(activeEffect); + } } - } - info["activeEffects"] = activeEffects; + info["activeEffects"] = activeEffects; - // ACTIVE STATIC LED COLOR - QJsonArray activeLedColors; - const HyperHdrInstance::InputInfo& priorityInfo = _hyperhdr->getPriorityInfo(_hyperhdr->getCurrentPriority()); - if (priorityInfo.componentId == hyperhdr::COMP_COLOR && !priorityInfo.ledColors.empty()) - { - QJsonObject LEDcolor; - // check if LED Color not Black (0,0,0) - if ((priorityInfo.ledColors.begin()->red + - priorityInfo.ledColors.begin()->green + - priorityInfo.ledColors.begin()->blue != - 0)) + // ACTIVE STATIC LED COLOR + QJsonArray activeLedColors; + const HyperHdrInstance::InputInfo& priorityInfo = _hyperhdr->getPriorityInfo(_hyperhdr->getCurrentPriority()); + if (priorityInfo.componentId == hyperhdr::COMP_COLOR && !priorityInfo.ledColors.empty()) { QJsonObject LEDcolor; - - // add RGB Value to Array - QJsonArray RGBValue; - RGBValue.append(priorityInfo.ledColors.begin()->red); - RGBValue.append(priorityInfo.ledColors.begin()->green); - RGBValue.append(priorityInfo.ledColors.begin()->blue); - LEDcolor.insert("RGB Value", RGBValue); - - uint16_t Hue; - float Saturation, Luminace; - - // add HSL Value to Array - QJsonArray HSLValue; - ColorSys::rgb2hsl(priorityInfo.ledColors.begin()->red, - priorityInfo.ledColors.begin()->green, - priorityInfo.ledColors.begin()->blue, - Hue, Saturation, Luminace); - - HSLValue.append(Hue); - HSLValue.append(Saturation); - HSLValue.append(Luminace); - LEDcolor.insert("HSL Value", HSLValue); - - activeLedColors.append(LEDcolor); + // check if LED Color not Black (0,0,0) + if ((priorityInfo.ledColors.begin()->red + + priorityInfo.ledColors.begin()->green + + priorityInfo.ledColors.begin()->blue != + 0)) + { + QJsonObject LEDcolor; + + // add RGB Value to Array + QJsonArray RGBValue; + RGBValue.append(priorityInfo.ledColors.begin()->red); + RGBValue.append(priorityInfo.ledColors.begin()->green); + RGBValue.append(priorityInfo.ledColors.begin()->blue); + LEDcolor.insert("RGB Value", RGBValue); + + uint16_t Hue; + float Saturation, Luminace; + + // add HSL Value to Array + QJsonArray HSLValue; + ColorSys::rgb2hsl(priorityInfo.ledColors.begin()->red, + priorityInfo.ledColors.begin()->green, + priorityInfo.ledColors.begin()->blue, + Hue, Saturation, Luminace); + + HSLValue.append(Hue); + HSLValue.append(Saturation); + HSLValue.append(Luminace); + LEDcolor.insert("HSL Value", HSLValue); + + activeLedColors.append(LEDcolor); + } } - } - info["activeLedColor"] = activeLedColors; + info["activeLedColor"] = activeLedColors; - // END + // END - sendSuccessDataReply(QJsonDocument(info), command, tan); + sendSuccessDataReply(QJsonDocument(info), command, tan); + } + else + sendSuccessReply(command, tan); // AFTER we send the info, the client might want to subscribe to future updates if (message.contains("subscribe")) @@ -904,6 +927,20 @@ void JsonAPI::handleLutInstallCommand(const QJsonObject& message, const QString& sendErrorReply("No Authorization", command, tan); } +void JsonAPI::handleCurrentStateCommand(const QJsonObject& message, const QString& command, int tan) +{ + const QString& subc = message["subcommand"].toString().trimmed(); + int instance = message["instance"].toInt(0); + + if (subc == "average-color") + { + QJsonObject avColor = API::getAverageColor(instance); + sendSuccessDataReply(QJsonDocument(avColor), command + "-" + subc, tan); + } + else + handleNotImplemented(command, tan); +} + void JsonAPI::handleSmoothingCommand(const QJsonObject& message, const QString& command, int tan) { const QString& subc = message["subcommand"].toString().trimmed().toLower(); @@ -1639,6 +1676,8 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject& message, const QString& obj["token"] = userTokenRep; sendSuccessDataReply(QJsonDocument(obj), command + "-" + subc, tan); } + else if (API::isUserBlocked()) + sendErrorReply("Too many login attempts detected. Please restart HyperHDR.", command + "-" + subc, tan); else sendErrorReply("No Authorization", command + "-" + subc, tan); } diff --git a/sources/base/HyperHdrIManager.cpp b/sources/base/HyperHdrIManager.cpp index 160b24308..34aeec8bc 100644 --- a/sources/base/HyperHdrIManager.cpp +++ b/sources/base/HyperHdrIManager.cpp @@ -101,6 +101,16 @@ void HyperHdrIManager::setSmoothing(int time) QTimer::singleShot(0, instance, [=]() { instance->setSmoothing(time); }); } +QJsonObject HyperHdrIManager::getAverageColor(quint8 index) +{ + HyperHdrInstance* instance = HyperHdrIManager::getHyperHdrInstance(index); + QJsonObject res; + + SAFE_CALL_0_RET(instance, getAverageColor, QJsonObject, res); + + return res; +} + bool HyperHdrIManager::isCEC() { QMap instCopy = _runningInstances; diff --git a/sources/base/HyperHdrInstance.cpp b/sources/base/HyperHdrInstance.cpp index 940adc6f8..8a7295799 100644 --- a/sources/base/HyperHdrInstance.cpp +++ b/sources/base/HyperHdrInstance.cpp @@ -315,6 +315,37 @@ void HyperHdrInstance::setSmoothing(int time) _smoothing->updateCurrentConfig(time); } +QJsonObject HyperHdrInstance::getAverageColor() +{ + QJsonObject ret; + + auto copy = _globalLedBuffer; + long red = 0, green = 0, blue = 0, count = 0; + + for (const ColorRgb& c : copy) + { + red += c.red; + green += c.green; + blue += c.blue; + + count++; + } + + if (!_ledDeviceWrapper->enabled()) + { + red = green = blue = 0; + } + + if (count > 0) + { + ret["red"] = static_cast(red / count); + ret["green"] = static_cast(green / count); + ret["blue"] = static_cast(blue / count); + } + + return ret; +} + unsigned HyperHdrInstance::updateSmoothingConfig(unsigned id, int settlingTime_ms, double ledUpdateFrequency_hz, bool directMode) { unsigned retVal = id; @@ -635,7 +666,7 @@ void HyperHdrInstance::handlePriorityChangedLedDevice(const quint8& priority) Info(_log, "New priority[%d], previous [%d]", priority, previousPriority); if (priority == PriorityMuxer::LOWEST_PRIORITY) { - Error(_log, "No source left -> switch LED-Device off"); + Warning(_log, "No source left -> switch LED-Device off"); emit compStateChangeRequest(hyperhdr::COMP_LEDDEVICE, false); emit PerformanceCounters::getInstance()->removeCounter(static_cast(PerformanceReportType::INSTANCE), getInstanceIndex()); diff --git a/sources/base/MultiColorAdjustment.cpp b/sources/base/MultiColorAdjustment.cpp index 98c308b3d..4d26aea09 100644 --- a/sources/base/MultiColorAdjustment.cpp +++ b/sources/base/MultiColorAdjustment.cpp @@ -170,10 +170,32 @@ void MultiColorAdjustment::applyAdjustment(std::vector& ledColors) uint8_t ogreen = color.green; uint8_t oblue = color.blue; uint8_t B_RGB = 0, B_CMY = 0, B_W = 0; + adjustment->_rgbTransform.transform(ored, ogreen, oblue); adjustment->_rgbTransform.getBrightnessComponents(B_RGB, B_CMY, B_W); + if (!adjustment->_rgbBlackAdjustment.isEnabled() && + !adjustment->_rgbRedAdjustment.isEnabled() && + !adjustment->_rgbGreenAdjustment.isEnabled() && + !adjustment->_rgbBlueAdjustment.isEnabled() && + !adjustment->_rgbCyanAdjustment.isEnabled() && + !adjustment->_rgbMagentaAdjustment.isEnabled() && + !adjustment->_rgbYellowAdjustment.isEnabled() && + !adjustment->_rgbWhiteAdjustment.isEnabled()) + { + color.red = ored; + color.green = ogreen; + color.blue = oblue; + if (B_RGB != 255) + { + color.red = ((uint32_t)color.red * B_RGB)/255; + color.green = ((uint32_t)color.green * B_RGB) / 255; + color.blue = ((uint32_t)color.blue * B_RGB) / 255; + } + continue; + } + uint32_t nrng = (uint32_t)(255 - ored) * (255 - ogreen); uint32_t rng = (uint32_t)(ored) * (255 - ogreen); uint32_t nrg = (uint32_t)(255 - ored) * (ogreen); diff --git a/sources/base/schema/schema-color.json b/sources/base/schema/schema-color.json index c8bfa65a0..902c1a65a 100644 --- a/sources/base/schema/schema-color.json +++ b/sources/base/schema/schema-color.json @@ -216,7 +216,12 @@ "title" : "edt_conf_color_backlightColored_title", "required" : true, "default" : true, - "propertyOrder" : 12 + "propertyOrder" : 12, + "options": { + "dependencies": { + "backlightThreshold": true + } + } }, "brightness" : { diff --git a/sources/leddevice/dev_rpi_pwm/LedDeviceWS281x.cpp b/sources/leddevice/dev_rpi_pwm/LedDeviceWS281x.cpp index 2baa1031b..6af71bc0f 100644 --- a/sources/leddevice/dev_rpi_pwm/LedDeviceWS281x.cpp +++ b/sources/leddevice/dev_rpi_pwm/LedDeviceWS281x.cpp @@ -58,6 +58,9 @@ bool LedDeviceWS281x::init(const QJsonObject& deviceConfig) Debug(_log, "ws281x strip type : %d", _led_string.channel[_channel].strip_type); + if (_refreshTimerInterval_ms > 0) + Error(_log, "The refresh timer is enabled ('Refresh time' > 0) and may limit the performance of the LED driver. Ignore this error if you set it on purpose for some reason (but you almost never need it)."); + isInitOK = true; } } diff --git a/sources/leddevice/dev_serial/ProviderRs232.cpp b/sources/leddevice/dev_serial/ProviderRs232.cpp index e4a76dbe3..7bcfcded0 100644 --- a/sources/leddevice/dev_serial/ProviderRs232.cpp +++ b/sources/leddevice/dev_serial/ProviderRs232.cpp @@ -61,6 +61,9 @@ bool ProviderRs232::init(const QJsonObject& deviceConfig) Debug(_log, "Delayed open : %d", _delayAfterConnect_ms); Debug(_log, "Retry limit : %d", _maxRetry); + if (_refreshTimerInterval_ms > 0) + Error(_log, "The refresh timer is enabled ('Refresh time' > 0) and may limit the performance of the LED driver. Ignore this error if you set it on purpose for some reason (but you almost never need it)."); + isInitOK = true; } return isInitOK; diff --git a/sources/leddevice/dev_spi/ProviderSpi.cpp b/sources/leddevice/dev_spi/ProviderSpi.cpp index 97fd4c4ea..e108d4267 100644 --- a/sources/leddevice/dev_spi/ProviderSpi.cpp +++ b/sources/leddevice/dev_spi/ProviderSpi.cpp @@ -48,6 +48,9 @@ bool ProviderSpi::init(const QJsonObject& deviceConfig) Debug(_log, "_baudRate_Hz [%d], _spiType: %s", _baudRate_Hz, QSTRING_CSTR(_spiType)); Debug(_log, "_spiDataInvert [%d], _spiMode [%d]", _spiDataInvert, _spiMode); + if (_refreshTimerInterval_ms > 0) + Error(_log, "The refresh timer is enabled ('Refresh time' > 0) and may limit the performance of the LED driver. Ignore this error if you set it on purpose for some reason (but you almost never need it)."); + isInitOK = true; } return isInitOK; diff --git a/sources/utils/Logger.cpp b/sources/utils/Logger.cpp index cd734c98e..a4ad4a838 100644 --- a/sources/utils/Logger.cpp +++ b/sources/utils/Logger.cpp @@ -251,10 +251,20 @@ void Logger::Message(LogLevel level, const char* sourceFile, const char* func, u if (_syslogEnabled && level >= Logger::WARNING) syslog(LogLevelSysLog[level], "%s", msg); #endif + if (level == Logger::ERRORR) + _lastError = QString("%1 [%2] %3").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")).arg(_name).arg(QString(msg)); + RepeatMessage.setLocalData(logMsg); } } +QString Logger::_lastError; + +QString Logger::getLastError() +{ + return _lastError; +} + void Logger::setMinLevel(Logger::LogLevel level) { _minLevel = static_cast(level); diff --git a/sources/utils/RgbChannelAdjustment.cpp b/sources/utils/RgbChannelAdjustment.cpp index 92c2350cf..290d258f9 100644 --- a/sources/utils/RgbChannelAdjustment.cpp +++ b/sources/utils/RgbChannelAdjustment.cpp @@ -7,15 +7,17 @@ RgbChannelAdjustment::RgbChannelAdjustment(QString channelName) , _log(Logger::getInstance(channelName)) { resetInitialized(); + _enabled = true; } -RgbChannelAdjustment::RgbChannelAdjustment(quint8 instance, uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, QString channelName) +RgbChannelAdjustment::RgbChannelAdjustment(quint8 instance, uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, QString channelName, bool enabled) : _channelName(channelName) , _log(Logger::getInstance(channelName.replace("ChannelAdjust_", "ADJUST_") + QString::number(instance))) { resetInitialized(); setAdjustment(adjustR, adjustG, adjustB); + _enabled = enabled; } void RgbChannelAdjustment::resetInitialized() @@ -89,6 +91,10 @@ uint8_t RgbChannelAdjustment::adjustmentB(uint8_t inputB) const return _mappingAdjB[inputB]; } +bool RgbChannelAdjustment::isEnabled() +{ + return _enabled; +} void RgbChannelAdjustment::apply(uint8_t input, uint8_t brightness, uint8_t& red, uint8_t& green, uint8_t& blue) { @@ -164,13 +170,16 @@ void RgbChannelAdjustment::initializeCorrectionMapping(uint8_t correction) RgbChannelAdjustment RgbChannelAdjustment::createRgbChannelAdjustment(quint8 instance, const QJsonObject& colorConfig, const QString& channelName, int defaultR, int defaultG, int defaultB) { const QJsonArray& channelConfig = colorConfig[channelName].toArray(); - + auto rr = static_cast(channelConfig[0].toInt(defaultR)); + auto gg = static_cast(channelConfig[1].toInt(defaultG)); + auto bb = static_cast(channelConfig[2].toInt(defaultB)); return RgbChannelAdjustment( instance, - static_cast(channelConfig[0].toInt(defaultR)), - static_cast(channelConfig[1].toInt(defaultG)), - static_cast(channelConfig[2].toInt(defaultB)), - "ChannelAdjust_" + channelName.toUpper() + rr, + gg, + bb, + "ChannelAdjust_" + channelName.toUpper(), + (rr != defaultR) || (gg != defaultG) || (bb != defaultB) ); } diff --git a/sources/utils/RgbTransform.cpp b/sources/utils/RgbTransform.cpp index c9efc0eb4..1175015cf 100644 --- a/sources/utils/RgbTransform.cpp +++ b/sources/utils/RgbTransform.cpp @@ -57,8 +57,8 @@ void RgbTransform::init( _backlightColored = true; if (!_silent) - Info(_log, "RGB transform classic_config: %i, saturationGain: %f, luminanceGain: %f, backlightThreshold: %i", - _classic_config, _saturationGain, _luminanceGain, clamp(backlightThreshold)); + Info(_log, "RGB transform classic_config: %i, saturationGain: %f, luminanceGain: %f, backlightThreshold: %i, backlightColored: %s", + _classic_config, _saturationGain, _luminanceGain, clamp(backlightThreshold), (backlightColored) ? "yes" : "no"); setGamma(gammaR, gammaG, gammaB); setBacklightThreshold(backlightThreshold); diff --git a/sources/webserver/WebSocketClient.cpp b/sources/webserver/WebSocketClient.cpp index 1ac39f0fe..d911eb268 100644 --- a/sources/webserver/WebSocketClient.cpp +++ b/sources/webserver/WebSocketClient.cpp @@ -292,7 +292,7 @@ qint64 WebSocketClient::sendMessage(QJsonObject obj) if (obj.contains("isImage")) { - QTimer::singleShot(0, _jsonAPI, &JsonAPI::releaseLock); + SAFE_CALL_0(_jsonAPI, releaseLock); } return payloadWritten; diff --git a/www/content/json_api.html b/www/content/json_api.html index 20bb7e4d4..e84a420c7 100644 --- a/www/content/json_api.html +++ b/www/content/json_api.html @@ -660,6 +660,59 @@

Explanation

+ +
+
+
+
+
+
+
+
+
+

Explanation

+ +
+
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+ +
+
+
+
+
+ +
+ - - - @@ -237,7 +234,20 @@

HyperHDR Web Configuration requires Javascript. Please enable Javascript in
- +
+
+ +
+