Disentangle LedDevice/LinearColorSmoothing, Bug Fixes & Test support (#654)

* Handle Exceptions in main & Pythoninit

* Have SSDPDiscover generic again

* Have SSDPDiscover generic again

* Change Info- to Debug logs as technical service messages

* Nanoleaf - When switched on, ensure UDP mode

* Include SQL Database in Cross-Compile instructions

* Fix Clazy (QT code checker) and clang Warnings

* Stop LedDevice:write for disabled device

* Nanoleaf: Fix uint printfs

* NanoLeaf: Fix indents to tabs

* NanoLeaf - Add debug verbosity switches

* Device switchability support, FileDevice with timestamp support

* Nanoleaf Light Panels now support External Control V2

* Enhance LedDeviceFile by Timestamp + fix readyness

* Stop color stream, if LedDevice disabled

* Nanoleaf - remove switchability

* Fix MultiColorAdjustment, if led-range is greater lednum

* Fix logging

* LedFileDevice/LedDevice - add testing support

* New "Led Test" effect

* LedDeviceFile - Add chrono include + Allow Led rewrites for testing

* Stabilize Effects for LedDevices where latchtime = 0

* Update LedDeviceFile, allow latchtime = 0

* Distangle LinearColorSmoothing and LEDDevice, Fix Effect configuration updates

* Updates LedDeviceFile - Initialize via Open

* Updates LedDeviceNanoleaf - Initialize via Open, Remove throwing exceptions

* Updates ProviderUDP - Remove throwing exceptions

* Framebuffer - Use precise timer

* TestSpi - Align to LedDevice updates

* Pretty Print CrossCompileHowTo as markdown-file

* Ensure that output is only written when LedDevice is ready

* Align APA102 Device to new device staging

* Logger - Remove clang warnings on extra semicolon

* Devices SPI - Align to Device stages and methods

* Fix cppcheck and clang findings

* Add Code-Template for new Devices

* Align devices to stages and methods, clean-up some code

* Allow to reopen LedDevice without restart

* Revert change "Remove Connect (PriorityMuxer::visiblePriorityChanged -> Hyperion::update) due to double writes"

* Remove visiblePriorityChanged from LedDevice to decouple LedDevice from hyperion logic

* Expose LedDevice getLedCount and align signedness
This commit is contained in:
LordGrey
2020-02-10 15:21:58 +01:00
committed by GitHub
parent 1aba51e85c
commit ed5455458b
107 changed files with 2980 additions and 1551 deletions

View File

@@ -6,6 +6,8 @@
#include <QStringList>
#include <QDir>
#include <QDateTime>
#include <QEventLoop>
#include <QTimer>
#include "hyperion/Hyperion.h"
#include <utils/JsonUtils.h>
@@ -15,32 +17,62 @@ LedDevice::LedDevice(const QJsonObject& config, QObject* parent)
, _devConfig(config)
, _log(Logger::getInstance("LEDDEVICE"))
, _ledBuffer(0)
, _deviceReady(true)
, _refresh_timer()
, _deviceReady(false)
, _deviceInError(false)
, _refresh_timer(new QTimer(this))
, _refresh_timer_interval(0)
, _last_write_time(QDateTime::currentMSecsSinceEpoch())
, _latchTime_ms(0)
, _componentRegistered(false)
, _enabled(true)
, _enabled(false)
, _refresh_enabled (false)
{
// setup timer
_refresh_timer.setInterval(0);
connect(&_refresh_timer, SIGNAL(timeout()), this, SLOT(rewriteLeds()));
// setup refreshTimer
_refresh_timer->setTimerType(Qt::PreciseTimer);
_refresh_timer->setInterval( _refresh_timer_interval );
connect(_refresh_timer, SIGNAL(timeout()), this, SLOT(rewriteLeds()));
}
LedDevice::~LedDevice()
{
_refresh_timer->deleteLater();
}
// dummy implemention
int LedDevice::open()
{
setEnable (true);
return 0;
}
void LedDevice::setInError(const QString& errorMsg)
{
_deviceInError = true;
_deviceReady = false;
_enabled = false;
this->stopRefreshTimer();
Error(_log, "Device disabled, device '%s' signals error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(errorMsg));
emit enableStateChanged(_enabled);
}
void LedDevice::close()
{
switchOff();
this->stopRefreshTimer();
}
void LedDevice::setEnable(bool enable)
{
if (!_deviceReady && enable)
{
Debug(_log, "Device '%s' was not ready! Trying to re-open.", QSTRING_CSTR(_activeDeviceType));
if ( open() < 0 )
{
Error(_log, "Device '%s' cannot be enabled, as it is not ready!", QSTRING_CSTR(_activeDeviceType));
return;
}
}
// emit signal when state changed
if (_enabled != enable)
{
@@ -62,7 +94,7 @@ void LedDevice::setEnable(bool enable)
_enabled = enable;
}
void LedDevice::setActiveDeviceType(QString deviceType)
void LedDevice::setActiveDeviceType(const QString& deviceType)
{
_activeDeviceType = deviceType;
}
@@ -71,50 +103,100 @@ bool LedDevice::init(const QJsonObject &deviceConfig)
{
_colorOrder = deviceConfig["colorOrder"].toString("RGB");
_activeDeviceType = deviceConfig["type"].toString("file").toLower();
setLedCount(deviceConfig["currentLedCount"].toInt(1)); // property injected to reflect real led count
setLedCount(static_cast<unsigned int>( deviceConfig["currentLedCount"].toInt(1) )); // property injected to reflect real led count
_latchTime_ms = deviceConfig["latchTime"].toInt(_latchTime_ms);
_refresh_timer.setInterval( deviceConfig["rewriteTime"].toInt( _refresh_timer_interval) );
if (_refresh_timer.interval() <= (signed)_latchTime_ms )
_latchTime_ms =deviceConfig["latchTime"].toInt( _latchTime_ms );
_refresh_timer_interval = deviceConfig["rewriteTime"].toInt( _refresh_timer_interval);
if ( _refresh_timer_interval > 0 )
{
Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d)", _refresh_timer.interval(), _latchTime_ms);
_refresh_timer.setInterval(_latchTime_ms+10);
}
_refresh_enabled = true;
if (_refresh_timer_interval <= _latchTime_ms )
{
int new_refresh_timer_interval = _latchTime_ms + 10;
Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d), set rewriteTime to %dms", _latchTime_ms, _refresh_timer_interval, new_refresh_timer_interval);
_refresh_timer_interval = new_refresh_timer_interval;
_refresh_timer->setInterval( _refresh_timer_interval );
}
//Debug(_log, "Refresh interval = %dms",_refresh_timer_interval );
_refresh_timer->setInterval( _refresh_timer_interval );
_last_write_time = QDateTime::currentMSecsSinceEpoch();
this->startRefreshTimer();
}
return true;
}
int LedDevice::setLedValues(const std::vector<ColorRgb>& ledValues)
void LedDevice::startRefreshTimer()
{
if ( _deviceReady)
{
_refresh_timer->start();
}
}
void LedDevice::stopRefreshTimer()
{
_refresh_timer->stop();
}
int LedDevice::updateLeds(const std::vector<ColorRgb>& ledValues)
{
int retval = 0;
if (!_deviceReady || !_enabled)
if ( !_deviceReady )
{
std::cout << "LedDevice::updateLeds(), LedDevice NOT ready!" << std::endl;
return -1;
// restart the timer
if (_refresh_timer.interval() > 0)
{
_refresh_timer.start();
}
if (_latchTime_ms == 0 || QDateTime::currentMSecsSinceEpoch()-_last_write_time >= _latchTime_ms)
else
{
_ledValues = ledValues;
retval = write(ledValues);
_last_write_time = QDateTime::currentMSecsSinceEpoch();
}
//else Debug(_log, "latch %d", QDateTime::currentMSecsSinceEpoch()-_last_write_time);
qint64 elapsedTime = QDateTime::currentMSecsSinceEpoch() - _last_write_time;
if (_latchTime_ms == 0 || elapsedTime >= _latchTime_ms)
{
//std::cout << "LedDevice::updateLeds(), Elapsed time since last write (" << elapsedTime << ") ms > _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
retval = write(ledValues);
_last_write_time = QDateTime::currentMSecsSinceEpoch();
// if device requires refreshing, save Led-Values and restart the timer
if ( _refresh_enabled )
{
this->startRefreshTimer();
_last_ledValues = ledValues;
}
}
else
{
//std::cout << "LedDevice::updateLeds(), Skip write. _latchTime_ms (" << _latchTime_ms << ") ms > elapsedTime (" << elapsedTime << ") ms" << std::endl;
if ( _refresh_enabled )
{
//Stop timer to allow for next non-refresh update
this->stopRefreshTimer();
}
}
}
return retval;
}
int LedDevice::writeBlack()
{
return _deviceReady ? write(std::vector<ColorRgb>(_ledCount, ColorRgb::BLACK )) : -1;
return _deviceReady ? updateLeds(std::vector<ColorRgb>(static_cast<unsigned long>(_ledCount), ColorRgb::BLACK )) : -1;
}
int LedDevice::switchOff()
{
// Stop refresh timer to ensure that "write Black" is executed
this->stopRefreshTimer();
if ( _latchTime_ms > 0 )
{
// Wait latchtime before writing black
QEventLoop loop;
QTimer::singleShot( _latchTime_ms, &loop, SLOT( quit() ) );
loop.exec();
}
int rc = writeBlack();
return rc;
}
@@ -124,7 +206,7 @@ int LedDevice::switchOn()
return 0;
}
void LedDevice::setLedCount(int ledCount)
void LedDevice::setLedCount(unsigned int ledCount)
{
_ledCount = ledCount;
_ledRGBCount = _ledCount * sizeof(ColorRgb);
@@ -133,6 +215,35 @@ void LedDevice::setLedCount(int ledCount)
int LedDevice::rewriteLeds()
{
return _enabled ? write(_ledValues) : -1;
int retval = -1;
if ( _deviceReady )
{
//qint64 elapsedTime = QDateTime::currentMSecsSinceEpoch() - _last_write_time;
//std::cout << "LedDevice::rewriteLeds(): Rewrite Leds now, elapsedTime [" << elapsedTime << "] ms" << std::endl;
// //:TESTING: Inject "white" output records to differentiate from normal writes
// _last_ledValues.clear();
// _last_ledValues.resize(static_cast<unsigned long>(_ledCount), ColorRgb::WHITE);
// printLedValues(_last_ledValues);
// //:TESTING:
retval = write(_last_ledValues);
_last_write_time = QDateTime::currentMSecsSinceEpoch();
}
else
{
// If Device is not ready stop timer
this->stopRefreshTimer();
}
return retval;
}
void LedDevice::printLedValues(const std::vector<ColorRgb>& ledValues )
{
std::cout << "LedValues [" << ledValues.size() <<"] [";
for (const ColorRgb& color : ledValues)
{
std::cout << color;
}
std::cout << "]" << std::endl;
}