2013-10-27 18:04:37 +01:00
|
|
|
// Qt includes
|
|
|
|
#include <QDateTime>
|
|
|
|
|
|
|
|
#include "LinearColorSmoothing.h"
|
|
|
|
|
2016-08-11 07:13:55 +02:00
|
|
|
using namespace hyperion;
|
|
|
|
|
2016-07-13 11:18:12 +02:00
|
|
|
LinearColorSmoothing::LinearColorSmoothing( LedDevice * ledDevice, double ledUpdateFrequency_hz, int settlingTime_ms, unsigned updateDelay, bool continuousOutput)
|
2016-08-14 10:46:44 +02:00
|
|
|
: LedDevice()
|
2016-07-13 11:18:12 +02:00
|
|
|
, _ledDevice(ledDevice)
|
|
|
|
, _updateInterval(1000 / ledUpdateFrequency_hz)
|
|
|
|
, _settlingTime(settlingTime_ms)
|
|
|
|
, _timer()
|
|
|
|
, _outputDelay(updateDelay)
|
|
|
|
, _writeToLedsEnable(true)
|
|
|
|
, _continuousOutput(continuousOutput)
|
2016-08-11 07:13:55 +02:00
|
|
|
, _bypass(false)
|
2013-10-27 18:04:37 +01:00
|
|
|
{
|
2016-08-11 07:13:55 +02:00
|
|
|
_log = Logger::getInstance("Smoothing");
|
2013-10-27 18:04:37 +01:00
|
|
|
_timer.setSingleShot(false);
|
|
|
|
_timer.setInterval(_updateInterval);
|
|
|
|
|
|
|
|
connect(&_timer, SIGNAL(timeout()), this, SLOT(updateLeds()));
|
2014-09-25 22:31:20 +02:00
|
|
|
|
2016-08-11 07:13:55 +02:00
|
|
|
Info( _log, "Created linear-smoothing with interval: %d ms, settlingTime: %d ms, updateDelay: %d frames",
|
|
|
|
_updateInterval, settlingTime_ms, _outputDelay );
|
2013-10-27 18:04:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
LinearColorSmoothing::~LinearColorSmoothing()
|
|
|
|
{
|
2014-09-30 21:00:42 +02:00
|
|
|
// Make sure to switch off the underlying led-device (because switchOff is no longer forwarded)
|
|
|
|
_ledDevice->switchOff();
|
2013-10-27 18:04:37 +01:00
|
|
|
delete _ledDevice;
|
|
|
|
}
|
|
|
|
|
2013-11-11 10:00:37 +01:00
|
|
|
int LinearColorSmoothing::write(const std::vector<ColorRgb> &ledValues)
|
2013-10-27 18:04:37 +01:00
|
|
|
{
|
2016-08-11 07:13:55 +02:00
|
|
|
if (_bypass)
|
2013-10-27 18:04:37 +01:00
|
|
|
{
|
2016-08-11 07:13:55 +02:00
|
|
|
_ledDevice->write(ledValues);
|
2013-10-27 18:04:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-08-11 07:13:55 +02:00
|
|
|
// received a new target color
|
|
|
|
if (_previousValues.empty())
|
|
|
|
{
|
|
|
|
// not initialized yet
|
|
|
|
_targetTime = QDateTime::currentMSecsSinceEpoch() + _settlingTime;
|
|
|
|
_targetValues = ledValues;
|
|
|
|
|
|
|
|
_previousTime = QDateTime::currentMSecsSinceEpoch();
|
|
|
|
_previousValues = ledValues;
|
|
|
|
_timer.start();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_targetTime = QDateTime::currentMSecsSinceEpoch() + _settlingTime;
|
|
|
|
memcpy(_targetValues.data(), ledValues.data(), ledValues.size() * sizeof(ColorRgb));
|
|
|
|
}
|
2013-10-27 18:04:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int LinearColorSmoothing::switchOff()
|
|
|
|
{
|
2014-09-25 22:05:01 +02:00
|
|
|
// We will keep updating the leds (but with pure-black)
|
|
|
|
|
2014-09-22 21:28:38 +02:00
|
|
|
// Clear the smoothing parameters
|
|
|
|
std::fill(_targetValues.begin(), _targetValues.end(), ColorRgb::BLACK);
|
2013-10-27 18:04:37 +01:00
|
|
|
_targetTime = 0;
|
|
|
|
|
2014-09-22 21:28:38 +02:00
|
|
|
// Erase the output-queue
|
|
|
|
for (unsigned i=0; i<_outputQueue.size(); ++i)
|
|
|
|
{
|
|
|
|
_outputQueue.push_back(_targetValues);
|
|
|
|
_outputQueue.pop_front();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2013-10-27 18:04:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void LinearColorSmoothing::updateLeds()
|
|
|
|
{
|
|
|
|
int64_t now = QDateTime::currentMSecsSinceEpoch();
|
|
|
|
int deltaTime = _targetTime - now;
|
|
|
|
|
|
|
|
if (deltaTime < 0)
|
|
|
|
{
|
2013-11-11 10:00:37 +01:00
|
|
|
memcpy(_previousValues.data(), _targetValues.data(), _targetValues.size() * sizeof(ColorRgb));
|
2013-10-27 18:04:37 +01:00
|
|
|
_previousTime = now;
|
|
|
|
|
2014-09-22 21:28:38 +02:00
|
|
|
queueColors(_previousValues);
|
2016-07-13 11:18:12 +02:00
|
|
|
_writeToLedsEnable = _continuousOutput;
|
2013-10-27 18:04:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-05-26 07:01:10 +02:00
|
|
|
_writeToLedsEnable = true;
|
2013-10-27 18:04:37 +01:00
|
|
|
float k = 1.0f - 1.0f * deltaTime / (_targetTime - _previousTime);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < _previousValues.size(); ++i)
|
|
|
|
{
|
2013-11-11 10:00:37 +01:00
|
|
|
ColorRgb & prev = _previousValues[i];
|
|
|
|
ColorRgb & target = _targetValues[i];
|
2013-10-27 18:04:37 +01:00
|
|
|
|
|
|
|
prev.red += k * (target.red - prev.red);
|
|
|
|
prev.green += k * (target.green - prev.green);
|
|
|
|
prev.blue += k * (target.blue - prev.blue);
|
|
|
|
}
|
|
|
|
_previousTime = now;
|
|
|
|
|
2014-09-22 21:28:38 +02:00
|
|
|
queueColors(_previousValues);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LinearColorSmoothing::queueColors(const std::vector<ColorRgb> & ledColors)
|
|
|
|
{
|
|
|
|
if (_outputDelay == 0)
|
|
|
|
{
|
2014-09-25 22:05:01 +02:00
|
|
|
// No output delay => immediate write
|
2016-05-26 07:01:10 +02:00
|
|
|
if ( _writeToLedsEnable )
|
|
|
|
_ledDevice->write(ledColors);
|
2014-09-22 21:28:38 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-07-13 11:18:12 +02:00
|
|
|
// Push new colors in the delay-buffer
|
|
|
|
if ( _writeToLedsEnable )
|
|
|
|
_outputQueue.push_back(ledColors);
|
|
|
|
|
2014-09-25 22:05:01 +02:00
|
|
|
// If the delay-buffer is filled pop the front and write to device
|
2016-07-13 11:18:12 +02:00
|
|
|
if (_outputQueue.size() > 0 )
|
2014-09-22 21:28:38 +02:00
|
|
|
{
|
2016-07-13 11:18:12 +02:00
|
|
|
if ( _outputQueue.size() > _outputDelay || !_writeToLedsEnable )
|
|
|
|
{
|
2016-05-26 07:01:10 +02:00
|
|
|
_ledDevice->write(_outputQueue.front());
|
2016-07-13 11:18:12 +02:00
|
|
|
_outputQueue.pop_front();
|
|
|
|
}
|
2014-09-22 21:28:38 +02:00
|
|
|
}
|
2013-10-27 18:04:37 +01:00
|
|
|
}
|
|
|
|
}
|
2016-08-11 07:13:55 +02:00
|
|
|
|
|
|
|
void LinearColorSmoothing::componentStateChanged(const hyperion::Components component, bool enable)
|
|
|
|
{
|
|
|
|
if (component == COMP_SMOOTHING && _bypass == enable)
|
|
|
|
{
|
|
|
|
_bypass = !enable;
|
|
|
|
Info(_log, "change state to %s", (enable ? "enabled" : "disabled") );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|