diff --git a/CHANGELOG.md b/CHANGELOG.md index 094b2e0d9..fa8cd1184 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ - 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/utils/Logger.h b/include/utils/Logger.h index 8681cfed6..bed3f67a7 100644 --- a/include/utils/Logger.h +++ b/include/utils/Logger.h @@ -1,6 +1,7 @@ #pragma once #include +#include // QT includes #include 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/sources/api/API.cpp b/sources/api/API.cpp index 1b4fa36ee..f11cce85e 100644 --- a/sources/api/API.cpp +++ b/sources/api/API.cpp @@ -337,26 +337,22 @@ 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; - if (_instanceManager->thread() != this->thread()) - QMetaObject::invokeMethod(_instanceManager, "getAverageColor", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QJsonObject, res), Q_ARG(quint8, index)); - else - res = _instanceManager->getAverageColor(index); + SAFE_CALL_1_RET(_instanceManager, getAverageColor, QJsonObject, res, quint8, index); return res; } diff --git a/sources/base/HyperHdrIManager.cpp b/sources/base/HyperHdrIManager.cpp index 857452754..34aeec8bc 100644 --- a/sources/base/HyperHdrIManager.cpp +++ b/sources/base/HyperHdrIManager.cpp @@ -106,10 +106,7 @@ QJsonObject HyperHdrIManager::getAverageColor(quint8 index) HyperHdrInstance* instance = HyperHdrIManager::getHyperHdrInstance(index); QJsonObject res; - if (instance->thread() != this->thread()) - QMetaObject::invokeMethod(instance, "getAverageColor", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QJsonObject, res)); - else - res = instance->getAverageColor(); + SAFE_CALL_0_RET(instance, getAverageColor, QJsonObject, res); return res; } diff --git a/sources/base/HyperHdrInstance.cpp b/sources/base/HyperHdrInstance.cpp index 698ab71f2..5d74684c5 100644 --- a/sources/base/HyperHdrInstance.cpp +++ b/sources/base/HyperHdrInstance.cpp @@ -331,6 +331,11 @@ QJsonObject HyperHdrInstance::getAverageColor() count++; } + if (!_ledDeviceWrapper->enabled()) + { + red = green = blue = 0; + } + if (count > 0) { ret["red"] = static_cast(red / count); 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/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;