From a2db590d2a1547882c0aba3ee3cc2e0965cc1823 Mon Sep 17 00:00:00 2001
From: LordGrey <48840279+Lord-Grey@users.noreply.github.com>
Date: Sun, 27 Nov 2022 15:47:54 +0100
Subject: [PATCH] Fixes - Smoothing, Color-Calibration (#1532)
* Smoothing Remove ouputrate as duplicate to update frequency
* Serial LDEDDevices -Increase writeBlack to overcome issues on high baud rates
* Serial LED-Devices - Support device feedback, show statistics provided by HyperSerial
* Fix - Update Color Calibration on Remote Control when settings saved
* Serial LED-Devices - Support device feedback, show statistics provided by HyperSerial
---
assets/webconfig/i18n/en.json | 2 -
assets/webconfig/js/content_remote.js | 115 ++++++++++--------
config/hyperion.config.json.default | 1 -
include/hyperion/LinearColorSmoothing.h | 8 +-
libsrc/hyperion/LinearColorSmoothing.cpp | 13 +-
libsrc/hyperion/schema/schema-smoothing.json | 14 ---
.../dev_serial/LedDeviceAdalight.cpp | 27 +++-
.../leddevice/dev_serial/LedDeviceAdalight.h | 8 ++
libsrc/leddevice/dev_serial/ProviderRs232.cpp | 24 +++-
libsrc/leddevice/dev_serial/ProviderRs232.h | 5 +
10 files changed, 130 insertions(+), 87 deletions(-)
diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json
index aa3251d4..1ae5e0e4 100644
--- a/assets/webconfig/i18n/en.json
+++ b/assets/webconfig/i18n/en.json
@@ -443,8 +443,6 @@
"edt_conf_smooth_heading_title": "Smoothing",
"edt_conf_smooth_interpolationRate_expl": "Speed of the calculation of smooth intermediate frames.",
"edt_conf_smooth_interpolationRate_title": "Interpolation Rate",
- "edt_conf_smooth_outputRate_expl": "The output speed to your LED controller.",
- "edt_conf_smooth_outputRate_title": "Output Rate",
"edt_conf_smooth_time_ms_expl": "How long should the smoothing gather pictures?",
"edt_conf_smooth_time_ms_title": "Time",
"edt_conf_smooth_type_expl": "Type of smoothing.",
diff --git a/assets/webconfig/js/content_remote.js b/assets/webconfig/js/content_remote.js
index d0b21285..d0c1d9c2 100644
--- a/assets/webconfig/js/content_remote.js
+++ b/assets/webconfig/js/content_remote.js
@@ -19,7 +19,6 @@ $(document).ready(function () {
$('.ssthead').html(createTableRow([$.i18n('remote_input_origin'), $.i18n('remote_input_owner'), $.i18n('remote_input_priority'), $.i18n('remote_input_status')], true, true));
createTable('crthead', 'crtbody', 'adjust_content', true);
-
//create introduction
if (window.showOptHelp) {
createHint("intro", $.i18n('remote_color_intro', $.i18n('remote_losthint')), "color_intro");
@@ -30,56 +29,6 @@ $(document).ready(function () {
createHint("intro", $.i18n('remote_videoMode_intro', $.i18n('remote_losthint')), "videomode_intro");
}
- //color adjustment
- var sColor = sortProperties(window.serverSchema.properties.color.properties.channelAdjustment.items.properties);
- var values = window.serverInfo.adjustment[0];
-
- for (var key in sColor) {
- if (sColor[key].key != "id" && sColor[key].key != "leds") {
- var title = '';
- var property;
- var value = values[sColor[key].key];
-
- if (sColor[key].type == "array") {
- property = '
';
- $('.crtbody').append(createTableRow([title, property], false, true));
- createCP('cr_' + sColor[key].key, value, function (rgb, hex, e) {
- requestAdjustment(e.target.id.substr(e.target.id.indexOf("_") + 1), '[' + rgb.r + ',' + rgb.g + ',' + rgb.b + ']');
- });
- }
- else if (sColor[key].type == "boolean") {
- property = '';
- $('.crtbody').append(createTableRow([title, property], false, true));
-
- $('#cr_' + sColor[key].key).off().on('change', function (e) {
- requestAdjustment(e.target.id.substr(e.target.id.indexOf("_") + 1), e.currentTarget.checked);
- });
- }
- else {
- if (sColor[key].key == "brightness" ||
- sColor[key].key == "brightnessCompensation" ||
- sColor[key].key == "backlightThreshold" ||
- sColor[key].key == "saturationGain" ||
- sColor[key].key == "brightnessGain") {
-
- property = '';
- if (sColor[key].append === "edt_append_percent") {
- property = '' + property + '' + $.i18n("edt_append_percent") + '
';
- }
- }
- else {
- property = '';
- }
-
- $('.crtbody').append(createTableRow([title, property], false, true));
- $('#cr_' + sColor[key].key).off().on('change', function (e) {
- valValue(this.id, this.value, this.min, this.max);
- requestAdjustment(e.target.id.substr(e.target.id.indexOf("_") + 1), e.currentTarget.value);
- });
- }
- }
- }
-
function sendEffect() {
var efx = $("#effect_select").val();
if (efx != "__none__") {
@@ -94,6 +43,59 @@ $(document).ready(function () {
requestSetColor(rgb.r, rgb.g, rgb.b, duration);
}
+ function updateChannelAdjustments() {
+
+ $('.crtbody').html("");
+ var sColor = sortProperties(window.serverSchema.properties.color.properties.channelAdjustment.items.properties);
+ var values = window.serverInfo.adjustment[0];
+
+ for (var key in sColor) {
+ if (sColor[key].key != "id" && sColor[key].key != "leds") {
+ var title = '';
+ var property;
+ var value = values[sColor[key].key];
+
+ if (sColor[key].type == "array") {
+ property = '
';
+ $('.crtbody').append(createTableRow([title, property], false, true));
+ createCP('cr_' + sColor[key].key, value, function (rgb, hex, e) {
+ requestAdjustment(e.target.id.substr(e.target.id.indexOf("_") + 1), '[' + rgb.r + ',' + rgb.g + ',' + rgb.b + ']');
+ });
+ }
+ else if (sColor[key].type == "boolean") {
+ property = '';
+ $('.crtbody').append(createTableRow([title, property], false, true));
+
+ $('#cr_' + sColor[key].key).off().on('change', function (e) {
+ requestAdjustment(e.target.id.substr(e.target.id.indexOf("_") + 1), e.currentTarget.checked);
+ });
+ }
+ else {
+ if (sColor[key].key == "brightness" ||
+ sColor[key].key == "brightnessCompensation" ||
+ sColor[key].key == "backlightThreshold" ||
+ sColor[key].key == "saturationGain" ||
+ sColor[key].key == "brightnessGain") {
+
+ property = '';
+ if (sColor[key].append === "edt_append_percent") {
+ property = '' + property + '' + $.i18n("edt_append_percent") + '
';
+ }
+ }
+ else {
+ property = '';
+ }
+
+ $('.crtbody').append(createTableRow([title, property], false, true));
+ $('#cr_' + sColor[key].key).off().on('change', function (e) {
+ valValue(this.id, this.value, this.min, this.max);
+ requestAdjustment(e.target.id.substr(e.target.id.indexOf("_") + 1), e.currentTarget.value);
+ });
+ }
+ }
+ }
+ }
+
function updateInputSelect() {
$('.sstbody').html("");
var prios = window.serverInfo.priorities;
@@ -389,6 +391,7 @@ $(document).ready(function () {
updateInputSelect();
updateLedMapping();
updateVideoMode();
+ updateChannelAdjustments();
if (EFFECTENGINE_ENABLED) {
updateEffectlist();
} else {
@@ -421,6 +424,16 @@ $(document).ready(function () {
updateEffectlist();
});
+ $(window.hyperion).on("cmd-settings-update", function (event) {
+ if (event.response.data.color) {
+ window.serverInfo.imageToLedMappingType = event.response.data.color.imageToLedMappingType;
+ updateLedMapping();
+
+ window.serverInfo.adjustment = event.response.data.color.channelAdjustment;
+ updateChannelAdjustments();
+ }
+ });
+
removeOverlay();
});
diff --git a/config/hyperion.config.json.default b/config/hyperion.config.json.default
index c54cb28f..a52f64ba 100644
--- a/config/hyperion.config.json.default
+++ b/config/hyperion.config.json.default
@@ -60,7 +60,6 @@
"time_ms" : 200,
"updateFrequency" : 25.0000,
"interpolationRate" : 25.0000,
- "outputRate" : 25.0000,
"decay" : 1,
"dithering" : false,
"updateDelay" : 0
diff --git a/include/hyperion/LinearColorSmoothing.h b/include/hyperion/LinearColorSmoothing.h
index c80188b0..5636c278 100644
--- a/include/hyperion/LinearColorSmoothing.h
+++ b/include/hyperion/LinearColorSmoothing.h
@@ -230,9 +230,6 @@ private:
/// Flag for pausing
bool _pause;
- /// The rate at which color frames should be written to LED device.
- double _outputRate;
-
/// The interval time in microseconds for writing of LED Frames.
int64_t _outputIntervalMicros;
@@ -268,9 +265,6 @@ private:
/// The type of smoothing to perform
SmoothingType _type;
- /// The rate at which color frames should be written to LED device.
- double _outputRate;
-
/// The rate at which interpolation of LED frames should be performed.
double _interpolationRate;
@@ -284,7 +278,7 @@ private:
double _decay;
SmoothingCfg();
- SmoothingCfg(bool pause, int64_t settlingTime, int updateInterval, SmoothingType type = SmoothingType::Linear, double outputRate = 0, double interpolationRate = 0, unsigned outputDelay = 0, bool dithering = false, double decay = 1);
+ SmoothingCfg(bool pause, int64_t settlingTime, int updateInterval, SmoothingType type = SmoothingType::Linear, double interpolationRate = 0, unsigned outputDelay = 0, bool dithering = false, double decay = 1);
static QString EnumToString(SmoothingType type);
};
diff --git a/libsrc/hyperion/LinearColorSmoothing.cpp b/libsrc/hyperion/LinearColorSmoothing.cpp
index d5850134..c91309b0 100644
--- a/libsrc/hyperion/LinearColorSmoothing.cpp
+++ b/libsrc/hyperion/LinearColorSmoothing.cpp
@@ -47,7 +47,6 @@ const char* SETTINGS_KEY_OUTPUT_DELAY = "updateDelay";
const char* SETTINGS_KEY_DECAY = "decay";
const char* SETTINGS_KEY_INTERPOLATION_RATE = "interpolationRate";
-const char* SETTINGS_KEY_OUTPUT_RATE = "outputRate";
const char* SETTINGS_KEY_DITHERING = "dithering";
const int64_t DEFAULT_SETTLINGTIME = 200; // in ms
@@ -133,7 +132,6 @@ void LinearColorSmoothing::handleSettingsUpdate(settings::type type, const QJson
cfg._pause = false;
cfg._outputDelay = static_cast(obj[SETTINGS_KEY_OUTPUT_DELAY].toInt(DEFAULT_OUTPUTDEPLAY));
- cfg._outputRate = obj[SETTINGS_KEY_OUTPUT_RATE].toDouble(DEFAULT_UPDATEFREQUENCY);
cfg._interpolationRate = obj[SETTINGS_KEY_INTERPOLATION_RATE].toDouble(DEFAULT_UPDATEFREQUENCY);
cfg._dithering = obj[SETTINGS_KEY_DITHERING].toBool(false);
cfg._decay = obj[SETTINGS_KEY_DECAY].toDouble(1.0);
@@ -584,7 +582,6 @@ unsigned LinearColorSmoothing::addConfig(int settlingTime_ms, double ledUpdateFr
static_cast(MS_PER_MICRO / ledUpdateFrequency_hz),
SmoothingType::Linear,
ledUpdateFrequency_hz,
- ledUpdateFrequency_hz,
updateDelay
};
_cfgList.append(cfg);
@@ -605,7 +602,6 @@ unsigned LinearColorSmoothing::updateConfig(int cfgID, int settlingTime_ms, doub
static_cast(MS_PER_MICRO / ledUpdateFrequency_hz),
SmoothingType::Linear,
ledUpdateFrequency_hz,
- ledUpdateFrequency_hz,
updateDelay
};
_cfgList[updatedCfgID] = cfg;
@@ -631,8 +627,7 @@ bool LinearColorSmoothing::selectConfig(int cfgID, bool force)
_settlingTime = _cfgList[cfgID]._settlingTime;
_outputDelay = _cfgList[cfgID]._outputDelay;
_pause = _cfgList[cfgID]._pause;
- _outputRate = _cfgList[cfgID]._outputRate;
- _outputIntervalMicros = int64_t(1000000.0 / _outputRate); // 1s = 1e6 µs
+ _outputIntervalMicros = int64_t(1000000.0 / _updateInterval); // 1s = 1e6 µs
_interpolationRate = _cfgList[cfgID]._interpolationRate;
_interpolationIntervalMicros = int64_t(1000000.0 / _interpolationRate);
_dithering = _cfgList[cfgID]._dithering;
@@ -711,8 +706,7 @@ QString LinearColorSmoothing::getConfig(int cfgID)
case SmoothingType::Decay:
{
const double thalf = (1.0-std::pow(1.0/2, 1.0/_decay))*_settlingTime;
- configText += QString (", outputRate %1Hz, interpolationRate: %2Hz, dithering: %3, decay: %4 -> halftime: %5ms")
- .arg(cfg._outputRate,0,'f',2)
+ configText += QString (", interpolationRate: %1Hz, dithering: %2, decay: %3 -> halftime: %4ms")
.arg(cfg._interpolationRate,0,'f',2)
.arg((cfg._dithering) ? "true" : "false")
.arg(cfg._decay,0,'f',2)
@@ -732,12 +726,11 @@ LinearColorSmoothing::SmoothingCfg::SmoothingCfg() :
{
}
-LinearColorSmoothing::SmoothingCfg::SmoothingCfg(bool pause, int64_t settlingTime, int updateInterval, SmoothingType type, double outputRate, double interpolationRate, unsigned outputDelay, bool dithering, double decay) :
+LinearColorSmoothing::SmoothingCfg::SmoothingCfg(bool pause, int64_t settlingTime, int updateInterval, SmoothingType type, double interpolationRate, unsigned outputDelay, bool dithering, double decay) :
_pause(pause),
_settlingTime(settlingTime),
_updateInterval(updateInterval),
_type(type),
- _outputRate(outputRate),
_interpolationRate(interpolationRate),
_outputDelay(outputDelay),
_dithering(dithering),
diff --git a/libsrc/hyperion/schema/schema-smoothing.json b/libsrc/hyperion/schema/schema-smoothing.json
index 3f51c214..b5aea7b2 100644
--- a/libsrc/hyperion/schema/schema-smoothing.json
+++ b/libsrc/hyperion/schema/schema-smoothing.json
@@ -50,20 +50,6 @@
}
}
},
- "outputRate": {
- "type": "number",
- "title": "edt_conf_smooth_outputRate_title",
- "minimum": 1.0,
- "maximum": 1000.0,
- "default": 1.0,
- "append": "edt_append_hz",
- "propertyOrder": 6,
- "options": {
- "dependencies": {
- "type": "decay"
- }
- }
- },
"decay": {
"type": "number",
"title": "edt_conf_smooth_decay_title",
diff --git a/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp b/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp
index 109e76ff..1fdc11b3 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp
+++ b/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp
@@ -119,7 +119,7 @@ void LedDeviceAdalight::prepareHeader()
qToBigEndian(static_cast(totalLedCount), &_ledBuffer[3]);
_ledBuffer[5] = _ledBuffer[3] ^ _ledBuffer[4] ^ 0x55; // Checksum
- Debug( _log, "Adalight header for %d leds: %c%c%c 0x%02x 0x%02x 0x%02x", _ledCount,
+ Debug( _log, "Adalight header for %d leds (size: %d): %c%c%c 0x%02x 0x%02x 0x%02x", _ledCount, _ledBuffer.size(),
_ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3], _ledBuffer[4], _ledBuffer[5] );
}
@@ -179,6 +179,31 @@ int LedDeviceAdalight::write(const std::vector & ledValues)
return rc;
}
+void LedDeviceAdalight::readFeedback()
+{
+ if (_streamProtocol == Adalight::AWA)
+ {
+ bool continuousLines {true};
+ while ( _rs232Port.canReadLine() )
+ {
+ QByteArray record = _rs232Port.readLine();
+ if (record.startsWith("FPS:"))
+ {
+ if (continuousLines)
+ {
+ continuousLines = false;
+ }
+ Debug(_log, "Statistics %s", record.trimmed().constData());
+ }
+ else
+ {
+ std::cout << record.toStdString() << std::flush;
+ continuousLines = true;
+ }
+ }
+ }
+}
+
void LedDeviceAdalight::whiteChannelExtension(uint8_t*& writer)
{
if (_streamProtocol == Adalight::AWA && _white_channel_calibration)
diff --git a/libsrc/leddevice/dev_serial/LedDeviceAdalight.h b/libsrc/leddevice/dev_serial/LedDeviceAdalight.h
index 2507bad8..56065127 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceAdalight.h
+++ b/libsrc/leddevice/dev_serial/LedDeviceAdalight.h
@@ -37,6 +37,14 @@ public:
/// @return LedDevice constructed
static LedDevice* construct(const QJsonObject &deviceConfig);
+private slots:
+
+ ///
+ /// @brief Handle feedback provided by the device
+ /// Allows to show statistics and error for the "Awa" protocol, if configured in the ESP-sketch
+ ///
+ void readFeedback() override;
+
private:
///
diff --git a/libsrc/leddevice/dev_serial/ProviderRs232.cpp b/libsrc/leddevice/dev_serial/ProviderRs232.cpp
index f1298d2e..bd4349db 100644
--- a/libsrc/leddevice/dev_serial/ProviderRs232.cpp
+++ b/libsrc/leddevice/dev_serial/ProviderRs232.cpp
@@ -18,7 +18,7 @@ namespace {
constexpr std::chrono::milliseconds WRITE_TIMEOUT{ 1000 }; // device write timeout in ms
constexpr std::chrono::milliseconds OPEN_TIMEOUT{ 5000 }; // device open timeout in ms
const int MAX_WRITE_TIMEOUTS = 5; // Maximum number of allowed timeouts
- const int NUM_POWEROFF_WRITE_BLACK = 2; // Number of write "BLACK" during powering off
+ const int NUM_POWEROFF_WRITE_BLACK = 5; // Number of write "BLACK" during powering off
constexpr std::chrono::milliseconds DEFAULT_IDENTIFY_TIME{ 500 };
@@ -86,6 +86,8 @@ int ProviderRs232::open()
// open device physically
if ( tryOpen(_delayAfterConnect_ms) )
{
+ connect(&_rs232Port, &QSerialPort::readyRead, this, &ProviderRs232::readFeedback);
+
// Everything is OK, device is ready
_isDeviceReady = true;
retval = 0;
@@ -106,6 +108,9 @@ int ProviderRs232::close()
{
Debug(_log,"Flush was successful");
}
+
+ disconnect(&_rs232Port, &QSerialPort::readyRead, this, &ProviderRs232::readFeedback);
+
Debug(_log,"Close UART: %s", QSTRING_CSTR(_deviceName) );
_rs232Port.close();
// Everything is OK -> device is closed
@@ -261,6 +266,23 @@ int ProviderRs232::writeBytes(const qint64 size, const uint8_t *data)
return rc;
}
+void ProviderRs232::readFeedback()
+{
+ QByteArray readData = _rs232Port.readAll();
+ if (!readData.isEmpty())
+ {
+ //Output as received
+ std::cout << readData.toStdString();
+
+ //Output as Hex
+//#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
+// std::cout << readData.toHex(':').toStdString();
+//#else
+// std::cout << readData.toHex().toStdString();
+//#endif
+ }
+}
+
QString ProviderRs232::discoverFirst()
{
// take first available USB serial port - currently no probing!
diff --git a/libsrc/leddevice/dev_serial/ProviderRs232.h b/libsrc/leddevice/dev_serial/ProviderRs232.h
index 2cb94398..36348b55 100644
--- a/libsrc/leddevice/dev_serial/ProviderRs232.h
+++ b/libsrc/leddevice/dev_serial/ProviderRs232.h
@@ -123,6 +123,11 @@ protected slots:
///
void setInError( const QString& errorMsg) override;
+ ///
+ /// @brief Handle any feedback provided by the device
+ ///
+ virtual void readFeedback();
+
private:
///