2013-07-26 22:38:34 +02:00
2013-11-11 10:00:37 +01:00
// STL includes
# include <cassert>
2016-06-17 01:25:40 +02:00
# include <exception>
2016-07-01 23:20:41 +02:00
# include <sstream>
2013-11-11 10:00:37 +01:00
2013-08-21 16:25:27 +02:00
// QT includes
2013-08-14 17:02:09 +02:00
# include <QDateTime>
2013-11-29 23:22:49 +01:00
# include <QThread>
2013-11-22 11:48:10 +01:00
# include <QRegExp>
# include <QString>
# include <QStringList>
2016-09-14 13:51:28 +02:00
# include <QCryptographicHash>
# include <QFile>
2016-12-14 22:45:00 +01:00
# include <QFileInfo>
2013-08-14 17:02:09 +02:00
2013-07-26 22:38:34 +02:00
// hyperion include
# include <hyperion/Hyperion.h>
2013-08-15 21:11:02 +02:00
# include <hyperion/ImageProcessorFactory.h>
2016-12-19 23:59:50 +01:00
# include <hyperion/ImageProcessor.h>
2016-04-02 00:04:11 +02:00
# include <hyperion/ColorAdjustment.h>
2013-07-26 22:38:34 +02:00
2013-12-17 19:50:15 +01:00
// Leddevice includes
# include <leddevice/LedDevice.h>
# include <leddevice/LedDeviceFactory.h>
2013-08-13 11:10:45 +02:00
2016-04-02 00:04:11 +02:00
# include "MultiColorAdjustment.h"
2013-10-27 18:04:37 +01:00
# include "LinearColorSmoothing.h"
2013-11-24 16:10:48 +01:00
// effect engine includes
# include <effectengine/EffectEngine.h>
2017-01-10 19:58:41 +01:00
# define CORE_LOGGER Logger::getInstance("Core")
2016-06-17 01:25:40 +02:00
Hyperion * Hyperion : : _hyperion = nullptr ;
2016-12-14 22:45:00 +01:00
Hyperion * Hyperion : : initInstance ( const QJsonObject & qjsonConfig , const QString configFile ) // REMOVE jsonConfig variable when the conversion from jsonCPP to QtJSON is finished
2016-06-17 01:25:40 +02:00
{
if ( Hyperion : : _hyperion ! = nullptr )
throw std : : runtime_error ( " Hyperion::initInstance can be called only one time " ) ;
2016-10-13 21:59:58 +02:00
Hyperion : : _hyperion = new Hyperion ( qjsonConfig , configFile ) ;
2016-06-17 01:25:40 +02:00
return Hyperion : : _hyperion ;
}
Hyperion * Hyperion : : getInstance ( )
{
if ( Hyperion : : _hyperion = = nullptr )
throw std : : runtime_error ( " Hyperion::getInstance used without call of Hyperion::initInstance before " ) ;
return Hyperion : : _hyperion ;
}
2013-07-26 22:38:34 +02:00
2016-09-25 21:59:31 +02:00
ColorOrder Hyperion : : createColorOrder ( const QJsonObject & deviceConfig )
2013-11-04 20:52:57 +01:00
{
2016-09-25 21:59:31 +02:00
return stringToColorOrder ( deviceConfig [ " colorOrder " ] . toString ( " rgb " ) ) ;
2013-11-04 20:52:57 +01:00
}
2016-09-25 21:59:31 +02:00
ColorAdjustment * Hyperion : : createColorAdjustment ( const QJsonObject & adjustmentConfig )
2016-04-02 00:04:11 +02:00
{
2016-09-25 21:59:31 +02:00
const std : : string id = adjustmentConfig [ " id " ] . toString ( " default " ) . toStdString ( ) ;
2017-01-10 19:58:41 +01:00
RgbChannelAdjustment * blackAdjustment = createRgbChannelAdjustment ( adjustmentConfig , " black " , 0 , 0 , 0 ) ;
RgbChannelAdjustment * whiteAdjustment = createRgbChannelAdjustment ( adjustmentConfig , " white " , 255 , 255 , 255 ) ;
RgbChannelAdjustment * redAdjustment = createRgbChannelAdjustment ( adjustmentConfig , " red " , 255 , 0 , 0 ) ;
RgbChannelAdjustment * greenAdjustment = createRgbChannelAdjustment ( adjustmentConfig , " green " , 0 , 255 , 0 ) ;
RgbChannelAdjustment * blueAdjustment = createRgbChannelAdjustment ( adjustmentConfig , " blue " , 0 , 0 , 255 ) ;
RgbChannelAdjustment * cyanAdjustment = createRgbChannelAdjustment ( adjustmentConfig , " cyan " , 0 , 255 , 255 ) ;
RgbChannelAdjustment * magentaAdjustment = createRgbChannelAdjustment ( adjustmentConfig , " magenta " , 255 , 0 , 255 ) ;
RgbChannelAdjustment * yellowAdjustment = createRgbChannelAdjustment ( adjustmentConfig , " yellow " , 255 , 255 , 0 ) ;
2017-01-06 14:25:55 +01:00
RgbTransform * rgbTransform = createRgbTransform ( adjustmentConfig ) ;
2016-04-02 00:04:11 +02:00
ColorAdjustment * adjustment = new ColorAdjustment ( ) ;
adjustment - > _id = id ;
2016-12-29 17:02:37 +01:00
adjustment - > _rgbBlackAdjustment = * blackAdjustment ;
adjustment - > _rgbWhiteAdjustment = * whiteAdjustment ;
adjustment - > _rgbRedAdjustment = * redAdjustment ;
adjustment - > _rgbGreenAdjustment = * greenAdjustment ;
adjustment - > _rgbBlueAdjustment = * blueAdjustment ;
adjustment - > _rgbCyanAdjustment = * cyanAdjustment ;
adjustment - > _rgbMagentaAdjustment = * magentaAdjustment ;
adjustment - > _rgbYellowAdjustment = * yellowAdjustment ;
2017-01-06 14:25:55 +01:00
adjustment - > _rgbTransform = * rgbTransform ;
2016-04-02 00:04:11 +02:00
// Cleanup the allocated individual adjustments
2016-12-29 17:02:37 +01:00
delete blackAdjustment ;
delete whiteAdjustment ;
2016-04-02 00:04:11 +02:00
delete redAdjustment ;
delete greenAdjustment ;
delete blueAdjustment ;
2016-12-29 17:02:37 +01:00
delete cyanAdjustment ;
delete magentaAdjustment ;
delete yellowAdjustment ;
2017-01-06 14:25:55 +01:00
delete rgbTransform ;
2016-04-02 00:04:11 +02:00
return adjustment ;
}
2016-09-25 21:59:31 +02:00
MultiColorAdjustment * Hyperion : : createLedColorsAdjustment ( const unsigned ledCnt , const QJsonObject & colorConfig )
2016-04-02 00:04:11 +02:00
{
// Create the result, the transforms are added to this
MultiColorAdjustment * adjustment = new MultiColorAdjustment ( ledCnt ) ;
2016-09-25 21:59:31 +02:00
const QJsonValue adjustmentConfig = colorConfig [ " channelAdjustment " ] ;
2017-01-14 19:04:58 +01:00
const QRegExp overallExp ( " ([0-9]+( \\ -[0-9]+) ? ) ( , [ ] * ( [ 0 - 9 ] + ( \ \ - [ 0 - 9 ] + ) ? ) ) * " ) ;
const QJsonArray & adjustmentConfigArray = adjustmentConfig . toArray ( ) ;
for ( signed i = 0 ; i < adjustmentConfigArray . size ( ) ; + + i )
2016-04-02 00:04:11 +02:00
{
2017-01-14 19:04:58 +01:00
const QJsonObject & config = adjustmentConfigArray . at ( i ) . toObject ( ) ;
ColorAdjustment * colorAdjustment = createColorAdjustment ( config ) ;
2016-04-02 00:04:11 +02:00
adjustment - > addAdjustment ( colorAdjustment ) ;
2017-01-14 19:04:58 +01:00
const QString ledIndicesStr = config [ " leds " ] . toString ( " " ) . trimmed ( ) ;
if ( ledIndicesStr . compare ( " * " ) = = 0 )
2016-04-02 00:04:11 +02:00
{
2017-01-14 19:04:58 +01:00
// Special case for indices '*' => all leds
adjustment - > setAdjustmentForLed ( colorAdjustment - > _id , 0 , ledCnt - 1 ) ;
Info ( CORE_LOGGER , " ColorAdjustment '%s' => [0; %d] " , colorAdjustment - > _id . c_str ( ) , ledCnt - 1 ) ;
continue ;
}
2016-04-02 00:04:11 +02:00
2017-01-14 19:04:58 +01:00
if ( ! overallExp . exactMatch ( ledIndicesStr ) )
{
Error ( CORE_LOGGER , " Given led indices %d not correct format: %s " , i , ledIndicesStr . toStdString ( ) . c_str ( ) ) ;
continue ;
}
2016-04-02 00:04:11 +02:00
2017-01-14 19:04:58 +01:00
std : : stringstream ss ;
const QStringList ledIndexList = ledIndicesStr . split ( " , " ) ;
for ( int i = 0 ; i < ledIndexList . size ( ) ; + + i ) {
if ( i > 0 )
2016-04-02 00:04:11 +02:00
{
2017-01-14 19:04:58 +01:00
ss < < " , " ;
2016-04-02 00:04:11 +02:00
}
2017-01-14 19:04:58 +01:00
if ( ledIndexList [ i ] . contains ( " - " ) )
{
QStringList ledIndices = ledIndexList [ i ] . split ( " - " ) ;
int startInd = ledIndices [ 0 ] . toInt ( ) ;
int endInd = ledIndices [ 1 ] . toInt ( ) ;
2016-04-02 00:04:11 +02:00
2017-01-14 19:04:58 +01:00
adjustment - > setAdjustmentForLed ( colorAdjustment - > _id , startInd , endInd ) ;
ss < < startInd < < " - " < < endInd ;
}
else
{
int index = ledIndexList [ i ] . toInt ( ) ;
adjustment - > setAdjustmentForLed ( colorAdjustment - > _id , index , index ) ;
ss < < index ;
2016-04-02 00:04:11 +02:00
}
}
2017-01-14 19:04:58 +01:00
Info ( CORE_LOGGER , " ColorAdjustment '%s' => [%s] " , colorAdjustment - > _id . c_str ( ) , ss . str ( ) . c_str ( ) ) ;
2016-04-02 00:04:11 +02:00
}
2017-01-14 19:04:58 +01:00
2016-04-02 00:04:11 +02:00
return adjustment ;
}
2017-01-06 14:25:55 +01:00
RgbTransform * Hyperion : : createRgbTransform ( const QJsonObject & colorConfig )
2013-08-13 11:10:45 +02:00
{
2017-02-11 22:52:47 +01:00
const double backlightThreshold = colorConfig [ " backlightThreshold " ] . toDouble ( 0.0 ) ;
const bool backlightColored = colorConfig [ " backlightColored " ] . toBool ( false ) ;
2017-01-06 14:25:55 +01:00
const double brightness = colorConfig [ " brightness " ] . toDouble ( 0.5 ) ;
const double gammaR = colorConfig [ " gammaRed " ] . toDouble ( 1.0 ) ;
const double gammaG = colorConfig [ " gammaGreen " ] . toDouble ( 1.0 ) ;
const double gammaB = colorConfig [ " gammaBlue " ] . toDouble ( 1.0 ) ;
2013-08-13 11:10:45 +02:00
2017-02-11 22:52:47 +01:00
RgbTransform * transform = new RgbTransform ( gammaR , gammaG , gammaB , backlightThreshold , backlightColored , brightness ) ;
2013-08-13 11:10:45 +02:00
return transform ;
}
2013-10-27 18:04:37 +01:00
2017-01-10 19:58:41 +01:00
RgbChannelAdjustment * Hyperion : : createRgbChannelAdjustment ( const QJsonObject & colorConfig , const QString channelName , const int defaultR , const int defaultG , const int defaultB )
2016-04-02 00:04:11 +02:00
{
2017-01-10 19:58:41 +01:00
const QJsonArray & channelConfig = colorConfig [ channelName ] . toArray ( ) ;
RgbChannelAdjustment * adjustment = new RgbChannelAdjustment (
channelConfig [ 0 ] . toInt ( defaultR ) ,
channelConfig [ 1 ] . toInt ( defaultG ) ,
channelConfig [ 2 ] . toInt ( defaultB ) ,
" ChannelAdjust_ " + channelName . toUpper ( ) ) ;
2016-04-02 00:04:11 +02:00
return adjustment ;
}
2016-09-25 21:59:31 +02:00
LedString Hyperion : : createLedString ( const QJsonValue & ledsConfig , const ColorOrder deviceOrder )
2013-08-13 11:10:45 +02:00
{
LedString ledString ;
2016-09-25 21:59:31 +02:00
const QString deviceOrderStr = colorOrderToString ( deviceOrder ) ;
const QJsonArray & ledConfigArray = ledsConfig . toArray ( ) ;
int maxLedId = ledConfigArray . size ( ) ;
for ( signed i = 0 ; i < ledConfigArray . size ( ) ; + + i )
2013-08-13 11:10:45 +02:00
{
2016-09-25 21:59:31 +02:00
const QJsonObject & index = ledConfigArray [ i ] . toObject ( ) ;
2013-08-13 11:10:45 +02:00
Led led ;
2016-09-25 21:59:31 +02:00
led . index = index [ " index " ] . toInt ( ) ;
led . clone = index [ " clone " ] . toInt ( - 1 ) ;
2016-08-08 00:17:00 +02:00
if ( led . clone < - 1 | | led . clone > = maxLedId )
{
2017-01-10 19:58:41 +01:00
Warning ( CORE_LOGGER , " LED %d: clone index of %d is out of range, clone ignored " , led . index , led . clone ) ;
2016-08-08 00:17:00 +02:00
led . clone = - 1 ;
}
2015-02-23 16:11:33 +01:00
2016-08-08 00:17:00 +02:00
if ( led . clone < 0 )
2013-10-16 23:19:40 +02:00
{
2016-09-25 21:59:31 +02:00
const QJsonObject & hscanConfig = ledConfigArray [ i ] . toObject ( ) [ " hscan " ] . toObject ( ) ;
const QJsonObject & vscanConfig = ledConfigArray [ i ] . toObject ( ) [ " vscan " ] . toObject ( ) ;
led . minX_frac = std : : max ( 0.0 , std : : min ( 1.0 , hscanConfig [ " minimum " ] . toDouble ( ) ) ) ;
led . maxX_frac = std : : max ( 0.0 , std : : min ( 1.0 , hscanConfig [ " maximum " ] . toDouble ( ) ) ) ;
led . minY_frac = std : : max ( 0.0 , std : : min ( 1.0 , vscanConfig [ " minimum " ] . toDouble ( ) ) ) ;
led . maxY_frac = std : : max ( 0.0 , std : : min ( 1.0 , vscanConfig [ " maximum " ] . toDouble ( ) ) ) ;
2016-08-08 00:17:00 +02:00
// Fix if the user swapped min and max
if ( led . minX_frac > led . maxX_frac )
{
std : : swap ( led . minX_frac , led . maxX_frac ) ;
}
if ( led . minY_frac > led . maxY_frac )
{
std : : swap ( led . minY_frac , led . maxY_frac ) ;
}
// Get the order of the rgb channels for this led (default is device order)
2016-09-25 21:59:31 +02:00
led . colorOrder = stringToColorOrder ( index [ " colorOrder " ] . toString ( deviceOrderStr ) ) ;
2016-08-08 00:17:00 +02:00
ledString . leds ( ) . push_back ( led ) ;
2013-10-16 23:19:40 +02:00
}
2016-08-08 00:17:00 +02:00
}
// Make sure the leds are sorted (on their indices)
std : : sort ( ledString . leds ( ) . begin ( ) , ledString . leds ( ) . end ( ) , [ ] ( const Led & lhs , const Led & rhs ) { return lhs . index < rhs . index ; } ) ;
return ledString ;
}
2016-09-25 21:59:31 +02:00
LedString Hyperion : : createLedStringClone ( const QJsonValue & ledsConfig , const ColorOrder deviceOrder )
2016-08-08 00:17:00 +02:00
{
LedString ledString ;
2016-09-25 21:59:31 +02:00
const QString deviceOrderStr = colorOrderToString ( deviceOrder ) ;
const QJsonArray & ledConfigArray = ledsConfig . toArray ( ) ;
int maxLedId = ledConfigArray . size ( ) ;
for ( signed i = 0 ; i < ledConfigArray . size ( ) ; + + i )
2016-08-08 00:17:00 +02:00
{
2016-09-25 21:59:31 +02:00
const QJsonObject & index = ledConfigArray [ i ] . toObject ( ) ;
2016-08-08 00:17:00 +02:00
Led led ;
2016-09-25 21:59:31 +02:00
led . index = index [ " index " ] . toInt ( ) ;
led . clone = index [ " clone " ] . toInt ( - 1 ) ;
2016-08-08 00:17:00 +02:00
if ( led . clone < - 1 | | led . clone > = maxLedId )
2013-10-16 23:19:40 +02:00
{
2017-01-10 19:58:41 +01:00
Warning ( CORE_LOGGER , " LED %d: clone index of %d is out of range, clone ignored " , led . index , led . clone ) ;
2016-08-08 00:17:00 +02:00
led . clone = - 1 ;
2013-10-16 23:19:40 +02:00
}
2016-08-08 00:17:00 +02:00
if ( led . clone > = 0 )
{
2017-01-10 19:58:41 +01:00
Debug ( CORE_LOGGER , " LED %d: clone from led %d " , led . index , led . clone ) ;
2016-08-08 00:17:00 +02:00
led . minX_frac = 0 ;
led . maxX_frac = 0 ;
led . minY_frac = 0 ;
led . maxY_frac = 0 ;
// Get the order of the rgb channels for this led (default is device order)
2016-09-25 21:59:31 +02:00
led . colorOrder = stringToColorOrder ( index [ " colorOrder " ] . toString ( deviceOrderStr ) ) ;
2016-08-08 00:17:00 +02:00
ledString . leds ( ) . push_back ( led ) ;
}
2015-02-23 16:11:33 +01:00
2013-08-13 11:10:45 +02:00
}
2013-11-05 16:05:00 +01:00
// Make sure the leds are sorted (on their indices)
std : : sort ( ledString . leds ( ) . begin ( ) , ledString . leds ( ) . end ( ) , [ ] ( const Led & lhs , const Led & rhs ) { return lhs . index < rhs . index ; } ) ;
2013-08-13 11:10:45 +02:00
return ledString ;
}
2016-09-25 21:59:31 +02:00
QSize Hyperion : : getLedLayoutGridSize ( const QJsonValue & ledsConfig )
2016-09-21 22:01:50 +02:00
{
std : : vector < int > midPointsX ;
std : : vector < int > midPointsY ;
2016-09-25 21:59:31 +02:00
const QJsonArray & ledConfigArray = ledsConfig . toArray ( ) ;
2016-09-21 22:01:50 +02:00
2016-09-25 21:59:31 +02:00
for ( signed i = 0 ; i < ledConfigArray . size ( ) ; + + i )
2016-09-21 22:01:50 +02:00
{
2016-09-25 21:59:31 +02:00
const QJsonObject & index = ledConfigArray [ i ] . toObject ( ) ;
if ( index [ " clone " ] . toInt ( - 1 ) < 0 )
2016-09-21 22:01:50 +02:00
{
2016-09-25 21:59:31 +02:00
const QJsonObject & hscanConfig = ledConfigArray [ i ] . toObject ( ) [ " hscan " ] . toObject ( ) ;
const QJsonObject & vscanConfig = ledConfigArray [ i ] . toObject ( ) [ " vscan " ] . toObject ( ) ;
double minX_frac = std : : max ( 0.0 , std : : min ( 1.0 , hscanConfig [ " minimum " ] . toDouble ( ) ) ) ;
double maxX_frac = std : : max ( 0.0 , std : : min ( 1.0 , hscanConfig [ " maximum " ] . toDouble ( ) ) ) ;
double minY_frac = std : : max ( 0.0 , std : : min ( 1.0 , vscanConfig [ " minimum " ] . toDouble ( ) ) ) ;
double maxY_frac = std : : max ( 0.0 , std : : min ( 1.0 , vscanConfig [ " maximum " ] . toDouble ( ) ) ) ;
2016-09-21 22:01:50 +02:00
// Fix if the user swapped min and max
if ( minX_frac > maxX_frac )
{
std : : swap ( minX_frac , maxX_frac ) ;
}
if ( minY_frac > maxY_frac )
{
std : : swap ( minY_frac , maxY_frac ) ;
}
// calculate mid point and make grid calculation
midPointsX . push_back ( int ( 1000.0 * ( minX_frac + maxX_frac ) / 2.0 ) ) ;
midPointsY . push_back ( int ( 1000.0 * ( minY_frac + maxY_frac ) / 2.0 ) ) ;
}
}
// remove duplicates
std : : sort ( midPointsX . begin ( ) , midPointsX . end ( ) ) ;
midPointsX . erase ( std : : unique ( midPointsX . begin ( ) , midPointsX . end ( ) ) , midPointsX . end ( ) ) ;
std : : sort ( midPointsY . begin ( ) , midPointsY . end ( ) ) ;
midPointsY . erase ( std : : unique ( midPointsY . begin ( ) , midPointsY . end ( ) ) , midPointsY . end ( ) ) ;
QSize gridSize ( midPointsX . size ( ) , midPointsY . size ( ) ) ;
2017-01-10 19:58:41 +01:00
Debug ( CORE_LOGGER , " led layout grid: %dx%d " , gridSize . width ( ) , gridSize . height ( ) ) ;
2016-09-21 22:01:50 +02:00
return gridSize ;
}
2016-09-25 21:59:31 +02:00
LinearColorSmoothing * Hyperion : : createColorSmoothing ( const QJsonObject & smoothingConfig , LedDevice * leddevice )
2016-08-11 07:13:55 +02:00
{
2016-09-25 21:59:31 +02:00
std : : string type = smoothingConfig [ " type " ] . toString ( " linear " ) . toStdString ( ) ;
2013-10-27 21:06:35 +01:00
std : : transform ( type . begin ( ) , type . end ( ) , type . begin ( ) , : : tolower ) ;
2016-09-13 11:51:16 +02:00
LinearColorSmoothing * device = nullptr ;
2016-07-13 11:18:12 +02:00
type = " linear " ; // TODO currently hardcoded type, delete it if we have more types
2016-09-08 16:32:42 +02:00
2016-07-13 11:18:12 +02:00
if ( type = = " linear " )
2013-10-27 21:06:35 +01:00
{
2017-01-10 19:58:41 +01:00
Info ( CORE_LOGGER , " Creating linear smoothing " ) ;
2016-09-08 16:32:42 +02:00
device = new LinearColorSmoothing (
leddevice ,
2016-09-25 21:59:31 +02:00
smoothingConfig [ " updateFrequency " ] . toDouble ( 25.0 ) ,
smoothingConfig [ " time_ms " ] . toInt ( 200 ) ,
smoothingConfig [ " updateDelay " ] . toInt ( 0 ) ,
smoothingConfig [ " continuousOutput " ] . toBool ( true )
2016-07-13 11:18:12 +02:00
) ;
2013-10-27 21:06:35 +01:00
}
2016-09-08 16:32:42 +02:00
else
{
2017-01-10 19:58:41 +01:00
Error ( CORE_LOGGER , " Smoothing disabled, because of unknown type '%s'. " , type . c_str ( ) ) ;
2016-09-08 16:32:42 +02:00
}
2016-09-25 21:59:31 +02:00
device - > setEnable ( smoothingConfig [ " enable " ] . toBool ( true ) ) ;
2017-01-10 19:58:41 +01:00
InfoIf ( ! device - > enabled ( ) , CORE_LOGGER , " Smoothing disabled " ) ;
2013-10-27 21:06:35 +01:00
2016-09-14 17:28:03 +02:00
assert ( device ! = nullptr ) ;
2016-09-08 16:32:42 +02:00
return device ;
2013-10-27 18:04:37 +01:00
}
2016-09-25 21:59:31 +02:00
MessageForwarder * Hyperion : : createMessageForwarder ( const QJsonObject & forwarderConfig )
2016-03-09 19:45:00 +01:00
{
MessageForwarder * forwarder = new MessageForwarder ( ) ;
2016-09-25 21:59:31 +02:00
if ( ! forwarderConfig . isEmpty ( ) & & forwarderConfig [ " enable " ] . toBool ( true ) )
2016-03-09 19:45:00 +01:00
{
2016-09-25 21:59:31 +02:00
if ( ! forwarderConfig [ " json " ] . isNull ( ) & & forwarderConfig [ " json " ] . isArray ( ) )
2016-03-09 19:45:00 +01:00
{
2016-09-25 21:59:31 +02:00
const QJsonArray & addr = forwarderConfig [ " json " ] . toArray ( ) ;
for ( signed i = 0 ; i < addr . size ( ) ; + + i )
2016-03-09 19:45:00 +01:00
{
2017-01-10 19:58:41 +01:00
Info ( CORE_LOGGER , " Json forward to %s " , addr . at ( i ) . toString ( ) . toStdString ( ) . c_str ( ) ) ;
2016-09-25 21:59:31 +02:00
forwarder - > addJsonSlave ( addr [ i ] . toString ( ) . toStdString ( ) ) ;
2016-03-09 19:45:00 +01:00
}
}
2016-09-25 21:59:31 +02:00
if ( ! forwarderConfig [ " proto " ] . isNull ( ) & & forwarderConfig [ " proto " ] . isArray ( ) )
2016-03-09 19:45:00 +01:00
{
2016-09-25 21:59:31 +02:00
const QJsonArray & addr = forwarderConfig [ " proto " ] . toArray ( ) ;
for ( signed i = 0 ; i < addr . size ( ) ; + + i )
2016-03-09 19:45:00 +01:00
{
2017-01-10 19:58:41 +01:00
Info ( CORE_LOGGER , " Proto forward to %s " , addr . at ( i ) . toString ( ) . toStdString ( ) . c_str ( ) ) ;
2016-09-25 21:59:31 +02:00
forwarder - > addProtoSlave ( addr [ i ] . toString ( ) . toStdString ( ) ) ;
2016-03-09 19:45:00 +01:00
}
}
}
return forwarder ;
}
MessageForwarder * Hyperion : : getForwarder ( )
{
return _messageForwarder ;
}
2013-11-04 20:52:57 +01:00
2016-12-14 22:45:00 +01:00
Hyperion : : Hyperion ( const QJsonObject & qjsonConfig , const QString configFile )
2016-09-25 21:59:31 +02:00
: _ledString ( createLedString ( qjsonConfig [ " leds " ] , createColorOrder ( qjsonConfig [ " device " ] . toObject ( ) ) ) )
, _ledStringClone ( createLedStringClone ( qjsonConfig [ " leds " ] , createColorOrder ( qjsonConfig [ " device " ] . toObject ( ) ) ) )
2016-07-15 23:08:55 +02:00
, _muxer ( _ledString . leds ( ) . size ( ) )
2016-09-25 21:59:31 +02:00
, _raw2ledAdjustment ( createLedColorsAdjustment ( _ledString . leds ( ) . size ( ) , qjsonConfig [ " color " ] . toObject ( ) ) )
2016-07-15 23:08:55 +02:00
, _effectEngine ( nullptr )
2016-09-25 21:59:31 +02:00
, _messageForwarder ( createMessageForwarder ( qjsonConfig [ " forwarder " ] . toObject ( ) ) )
2016-10-09 22:22:17 +02:00
, _qjsonConfig ( qjsonConfig )
2016-07-15 23:08:55 +02:00
, _configFile ( configFile )
, _timer ( )
2017-01-10 19:58:41 +01:00
, _log ( CORE_LOGGER )
2016-07-15 23:08:55 +02:00
, _hwLedCount ( _ledString . leds ( ) . size ( ) )
2016-07-31 22:21:35 +02:00
, _sourceAutoSelectEnabled ( true )
2016-09-14 13:51:28 +02:00
, _configHash ( )
2016-09-25 21:59:31 +02:00
, _ledGridSize ( getLedLayoutGridSize ( qjsonConfig [ " leds " ] ) )
2017-02-11 22:52:47 +01:00
, _prevCompId ( hyperion : : COMP_INVALID )
2013-07-26 22:38:34 +02:00
{
2016-08-06 08:28:42 +02:00
registerPriority ( " Off " , PriorityMuxer : : LOWEST_PRIORITY ) ;
2017-01-06 14:25:55 +01:00
2016-04-02 00:04:11 +02:00
if ( ! _raw2ledAdjustment - > verifyAdjustments ( ) )
{
2016-07-15 23:08:55 +02:00
throw std : : runtime_error ( " Color adjustment incorrectly set " ) ;
2016-04-02 00:04:11 +02:00
}
2016-07-30 13:07:53 +02:00
// set color correction activity state
2016-09-25 21:59:31 +02:00
const QJsonObject & color = qjsonConfig [ " color " ] . toObject ( ) ;
2016-07-30 13:07:53 +02:00
2013-10-27 18:04:37 +01:00
// initialize the image processor factory
2016-12-20 19:55:54 +01:00
_ledMAppingType = ImageProcessor : : mappingTypeToInt ( color [ " imageToLedMappingType " ] . toString ( ) ) ;
ImageProcessorFactory : : getInstance ( ) . init ( _ledString , qjsonConfig [ " blackborderdetector " ] . toObject ( ) , _ledMAppingType ) ;
2016-09-07 20:10:37 +02:00
getComponentRegister ( ) . componentStateChanged ( hyperion : : COMP_FORWARDER , _messageForwarder - > forwardingEnabled ( ) ) ;
2016-09-08 16:32:42 +02:00
// initialize leddevices
2016-10-13 21:59:58 +02:00
_device = LedDeviceFactory : : construct ( qjsonConfig [ " device " ] . toObject ( ) , _hwLedCount ) ;
2016-09-25 21:59:31 +02:00
_deviceSmooth = createColorSmoothing ( qjsonConfig [ " smoothing " ] . toObject ( ) , _device ) ;
2016-09-08 16:32:42 +02:00
getComponentRegister ( ) . componentStateChanged ( hyperion : : COMP_SMOOTHING , _deviceSmooth - > componentState ( ) ) ;
2013-10-27 18:04:37 +01:00
// setup the timer
2013-08-14 17:02:09 +02:00
_timer . setSingleShot ( true ) ;
QObject : : connect ( & _timer , SIGNAL ( timeout ( ) ) , this , SLOT ( update ( ) ) ) ;
2013-11-24 16:10:48 +01:00
// create the effect engine
2016-10-09 22:22:17 +02:00
_effectEngine = new EffectEngine ( this , qjsonConfig [ " effects " ] . toObject ( ) ) ;
2016-07-01 23:20:41 +02:00
2016-09-25 21:59:31 +02:00
const QJsonObject & device = qjsonConfig [ " device " ] . toObject ( ) ;
unsigned int hwLedCount = device [ " ledCount " ] . toInt ( getLedCount ( ) ) ;
2016-07-01 23:20:41 +02:00
_hwLedCount = std : : max ( hwLedCount , getLedCount ( ) ) ;
Debug ( _log , " configured leds: %d hw leds: %d " , getLedCount ( ) , _hwLedCount ) ;
WarningIf ( hwLedCount < getLedCount ( ) , _log , " more leds configured than available. check 'ledCount' in 'device' section " ) ;
2013-11-24 16:10:48 +01:00
2016-12-14 22:45:00 +01:00
WarningIf ( ! configWriteable ( ) , _log , " Your config is not writeable - you won't be able to use the web ui for configuration. " ) ;
2016-09-14 13:51:28 +02:00
// initialize hash of current config
configModified ( ) ;
2016-12-23 19:37:35 +01:00
const QJsonObject & generalConfig = qjsonConfig [ " general " ] . toObject ( ) ;
_configVersionId = generalConfig [ " configVersion " ] . toInt ( - 1 ) ;
2013-08-18 13:33:56 +02:00
// initialize the leds
update ( ) ;
2013-07-26 22:38:34 +02:00
}
2017-01-22 19:36:52 +01:00
void Hyperion : : freeObjects ( bool emitCloseSignal )
2013-07-26 22:38:34 +02:00
{
2017-01-22 19:36:52 +01:00
if ( emitCloseSignal )
{
emit closing ( ) ;
}
2017-01-22 14:31:11 +01:00
2013-10-27 18:04:37 +01:00
// switch off all leds
clearall ( ) ;
_device - > switchOff ( ) ;
2016-07-01 23:20:41 +02:00
// delete components on exit of hyperion core
2013-11-24 16:10:48 +01:00
delete _effectEngine ;
2013-08-18 13:33:56 +02:00
delete _device ;
2016-04-02 00:04:11 +02:00
delete _raw2ledAdjustment ;
2016-03-09 19:45:00 +01:00
delete _messageForwarder ;
2013-07-26 22:38:34 +02:00
}
2016-10-10 23:08:01 +02:00
Hyperion : : ~ Hyperion ( )
{
2017-01-22 19:36:52 +01:00
freeObjects ( false ) ;
2016-10-10 23:08:01 +02:00
}
2013-08-14 10:54:49 +02:00
unsigned Hyperion : : getLedCount ( ) const
{
2013-08-18 13:33:56 +02:00
return _ledString . leds ( ) . size ( ) ;
2013-08-14 10:54:49 +02:00
}
2016-09-14 13:51:28 +02:00
bool Hyperion : : configModified ( )
{
2016-09-15 20:42:58 +02:00
bool isModified = false ;
2016-12-14 22:45:00 +01:00
QFile f ( _configFile ) ;
2016-09-14 13:51:28 +02:00
if ( f . open ( QFile : : ReadOnly ) )
{
QCryptographicHash hash ( QCryptographicHash : : Sha1 ) ;
2016-09-15 20:42:58 +02:00
if ( hash . addData ( & f ) )
{
if ( _configHash . size ( ) = = 0 )
2016-09-14 13:51:28 +02:00
{
2016-09-15 20:42:58 +02:00
_configHash = hash . result ( ) ;
2016-09-14 13:51:28 +02:00
}
2016-09-15 20:42:58 +02:00
else
{
isModified = _configHash ! = hash . result ( ) ;
}
}
2016-09-14 13:51:28 +02:00
}
f . close ( ) ;
2016-09-15 20:42:58 +02:00
return isModified ;
2016-09-14 13:51:28 +02:00
}
2016-12-14 22:45:00 +01:00
bool Hyperion : : configWriteable ( )
{
QFile file ( _configFile ) ;
QFileInfo fileInfo ( file ) ;
return fileInfo . isWritable ( ) & & fileInfo . isReadable ( ) ;
}
2016-07-15 23:08:55 +02:00
void Hyperion : : registerPriority ( const std : : string name , const int priority )
{
Info ( _log , " Register new input source named '%s' for priority channel '%d' " , name . c_str ( ) , priority ) ;
for ( auto const & entry : _priorityRegister )
{
WarningIf ( ( entry . first ! = name & & entry . second = = priority ) , _log ,
" Input source '%s' uses same priority channel (%d) as '%s'. " , name . c_str ( ) , priority , entry . first . c_str ( ) ) ;
}
_priorityRegister . emplace ( name , priority ) ;
}
void Hyperion : : unRegisterPriority ( const std : : string name )
{
Info ( _log , " Unregister input source named '%s' from priority register " , name . c_str ( ) ) ;
_priorityRegister . erase ( name ) ;
}
2016-07-31 22:21:35 +02:00
void Hyperion : : setSourceAutoSelectEnabled ( bool enabled )
{
_sourceAutoSelectEnabled = enabled ;
if ( ! _sourceAutoSelectEnabled )
{
setCurrentSourcePriority ( _muxer . getCurrentPriority ( ) ) ;
}
2017-01-10 19:58:41 +01:00
update ( ) ;
2016-07-31 22:21:35 +02:00
DebugIf ( ! _sourceAutoSelectEnabled , _log , " source auto select is disabled " ) ;
InfoIf ( _sourceAutoSelectEnabled , _log , " set current input source to auto select " ) ;
}
bool Hyperion : : setCurrentSourcePriority ( int priority )
{
bool priorityValid = _muxer . hasPriority ( priority ) ;
if ( priorityValid )
{
DebugIf ( _sourceAutoSelectEnabled , _log , " source auto select is disabled " ) ;
_sourceAutoSelectEnabled = false ;
_currentSourcePriority = priority ;
Info ( _log , " set current input source to priority channel %d " , _currentSourcePriority ) ;
}
return priorityValid ;
}
2016-08-11 07:13:55 +02:00
void Hyperion : : setComponentState ( const hyperion : : Components component , const bool state )
2016-08-04 13:10:53 +02:00
{
2016-09-08 16:32:42 +02:00
if ( component = = hyperion : : COMP_SMOOTHING )
{
_deviceSmooth - > setEnable ( state ) ;
getComponentRegister ( ) . componentStateChanged ( hyperion : : COMP_SMOOTHING , _deviceSmooth - > componentState ( ) ) ;
}
else
{
emit componentStateChanged ( component , state ) ;
}
2016-08-04 13:10:53 +02:00
}
2016-07-15 23:08:55 +02:00
2013-12-08 17:45:26 +01:00
void Hyperion : : setColor ( int priority , const ColorRgb & color , const int timeout_ms , bool clearEffects )
2013-07-26 22:38:34 +02:00
{
2013-08-18 13:33:56 +02:00
// create led output
2013-11-11 10:00:37 +01:00
std : : vector < ColorRgb > ledColors ( _ledString . leds ( ) . size ( ) , color ) ;
2013-08-18 13:33:56 +02:00
// set colors
2016-10-10 18:29:54 +02:00
setColors ( priority , ledColors , timeout_ms , clearEffects , hyperion : : COMP_COLOR ) ;
2013-08-18 13:33:56 +02:00
}
2013-07-26 22:38:34 +02:00
2017-02-21 12:02:01 +01:00
void Hyperion : : setColors ( int priority , const std : : vector < ColorRgb > & ledColors , const int timeout_ms , bool clearEffects , hyperion : : Components component , const QString origin )
2013-07-26 22:38:34 +02:00
{
2013-12-08 17:45:26 +01:00
// clear effects if this call does not come from an effect
if ( clearEffects )
{
_effectEngine - > channelCleared ( priority ) ;
}
2013-08-14 17:02:09 +02:00
if ( timeout_ms > 0 )
{
const uint64_t timeoutTime = QDateTime : : currentMSecsSinceEpoch ( ) + timeout_ms ;
2017-02-21 12:02:01 +01:00
_muxer . setInput ( priority , ledColors , timeoutTime , component , origin ) ;
2013-08-14 17:02:09 +02:00
}
else
{
2017-02-21 12:02:01 +01:00
_muxer . setInput ( priority , ledColors , - 1 , component , origin ) ;
2013-08-14 17:02:09 +02:00
}
2013-07-26 22:38:34 +02:00
2016-09-30 19:26:31 +02:00
if ( ! _sourceAutoSelectEnabled | | priority = = _muxer . getCurrentPriority ( ) )
2013-07-26 22:38:34 +02:00
{
2013-08-14 17:02:09 +02:00
update ( ) ;
}
}
2016-12-18 19:00:14 +01:00
void Hyperion : : setImage ( int priority , const Image < ColorRgb > & image , int duration_ms )
{
if ( priority = = getCurrentPriority ( ) )
{
emit emitImage ( priority , image , duration_ms ) ;
}
}
2016-04-02 00:04:11 +02:00
const std : : vector < std : : string > & Hyperion : : getAdjustmentIds ( ) const
{
return _raw2ledAdjustment - > getAdjustmentIds ( ) ;
}
ColorAdjustment * Hyperion : : getAdjustment ( const std : : string & id )
{
return _raw2ledAdjustment - > getAdjustment ( id ) ;
}
void Hyperion : : adjustmentsUpdated ( )
{
update ( ) ;
}
2013-08-18 13:33:56 +02:00
void Hyperion : : clear ( int priority )
{
if ( _muxer . hasPriority ( priority ) )
{
_muxer . clearInput ( priority ) ;
2017-01-09 22:41:44 +01:00
if ( ! _sourceAutoSelectEnabled & & _currentSourcePriority = = priority )
{
setSourceAutoSelectEnabled ( true ) ;
}
2013-08-18 13:33:56 +02:00
// update leds if necessary
2013-12-28 08:41:23 +01:00
if ( priority < _muxer . getCurrentPriority ( ) )
2013-08-18 13:33:56 +02:00
{
update ( ) ;
}
}
2013-11-29 23:22:49 +01:00
// send clear signal to the effect engine
// (outside the check so the effect gets cleared even when the effect is not sending colors)
_effectEngine - > channelCleared ( priority ) ;
2013-08-18 13:33:56 +02:00
}
void Hyperion : : clearall ( )
{
_muxer . clearAll ( ) ;
2017-01-09 22:41:44 +01:00
setSourceAutoSelectEnabled ( true ) ;
2013-08-18 13:33:56 +02:00
// update leds
update ( ) ;
2013-11-24 16:10:48 +01:00
// send clearall signal to the effect engine
_effectEngine - > allChannelsCleared ( ) ;
2013-08-18 13:33:56 +02:00
}
2016-05-30 22:39:12 +02:00
int Hyperion : : getCurrentPriority ( ) const
{
2016-07-31 22:21:35 +02:00
return _sourceAutoSelectEnabled | | ! _muxer . hasPriority ( _currentSourcePriority ) ? _muxer . getCurrentPriority ( ) : _currentSourcePriority ;
2016-05-30 22:39:12 +02:00
}
2013-08-19 20:33:36 +02:00
QList < int > Hyperion : : getActivePriorities ( ) const
{
return _muxer . getPriorities ( ) ;
}
const Hyperion : : InputInfo & Hyperion : : getPriorityInfo ( const int priority ) const
{
return _muxer . getInputInfo ( priority ) ;
}
2016-11-20 18:41:10 +01:00
void Hyperion : : reloadEffects ( )
{
_effectEngine - > readEffects ( ) ;
}
2013-12-01 14:09:01 +01:00
const std : : list < EffectDefinition > & Hyperion : : getEffects ( ) const
2013-11-24 16:10:48 +01:00
{
return _effectEngine - > getEffects ( ) ;
}
2016-04-24 17:07:31 +02:00
const std : : list < ActiveEffectDefinition > & Hyperion : : getActiveEffects ( )
{
return _effectEngine - > getActiveEffects ( ) ;
}
2016-10-24 23:52:53 +02:00
const std : : list < EffectSchema > & Hyperion : : getEffectSchemas ( )
{
return _effectEngine - > getEffectSchemas ( ) ;
}
2016-10-09 22:22:17 +02:00
int Hyperion : : setEffect ( const QString & effectName , int priority , int timeout )
2013-11-24 16:10:48 +01:00
{
return _effectEngine - > runEffect ( effectName , priority , timeout ) ;
}
2016-10-30 22:59:45 +01:00
int Hyperion : : setEffect ( const QString & effectName , const QJsonObject & args , int priority , int timeout , QString pythonScript )
2013-12-01 14:09:01 +01:00
{
2016-10-30 22:59:45 +01:00
return _effectEngine - > runEffect ( effectName , args , priority , timeout , pythonScript ) ;
2013-12-01 14:09:01 +01:00
}
2016-12-19 23:59:50 +01:00
void Hyperion : : setLedMappingType ( int mappingType )
{
2016-12-20 19:55:54 +01:00
_ledMAppingType = mappingType ;
2016-12-19 23:59:50 +01:00
emit imageToLedsMappingChanged ( mappingType ) ;
}
2013-08-14 17:02:09 +02:00
void Hyperion : : update ( )
{
// Update the muxer, cleaning obsolete priorities
2013-08-18 13:33:56 +02:00
_muxer . setCurrentTime ( QDateTime : : currentMSecsSinceEpoch ( ) ) ;
2013-08-14 17:02:09 +02:00
// Obtain the current priority channel
2016-07-31 22:21:35 +02:00
int priority = _sourceAutoSelectEnabled | | ! _muxer . hasPriority ( _currentSourcePriority ) ? _muxer . getCurrentPriority ( ) : _currentSourcePriority ;
const PriorityMuxer : : InputInfo & priorityInfo = _muxer . getInputInfo ( priority ) ;
2013-08-14 17:02:09 +02:00
2016-07-01 23:20:41 +02:00
// copy ledcolors to local buffer
_ledBuffer . reserve ( _hwLedCount ) ;
_ledBuffer = priorityInfo . ledColors ;
2017-02-08 14:36:28 +01:00
if ( priority < PriorityMuxer : : LOWEST_PRIORITY )
2016-10-10 18:29:54 +02:00
{
2017-02-11 22:52:47 +01:00
if ( priorityInfo . componentId ! = _prevCompId )
{
bool backlightEnabled = ( priorityInfo . componentId ! = hyperion : : COMP_COLOR & & priorityInfo . componentId ! = hyperion : : COMP_EFFECT ) ;
_raw2ledAdjustment - > setBacklightEnabled ( backlightEnabled ) ;
_prevCompId = priorityInfo . componentId ;
}
2016-10-10 18:29:54 +02:00
_raw2ledAdjustment - > applyAdjustment ( _ledBuffer ) ;
}
2016-07-01 23:20:41 +02:00
2016-10-08 08:14:36 +02:00
// init colororder vector, if empty
2016-08-08 00:17:00 +02:00
if ( _ledStringColorOrder . empty ( ) )
{
for ( Led & led : _ledString . leds ( ) )
{
_ledStringColorOrder . push_back ( led . colorOrder ) ;
}
for ( Led & led : _ledStringClone . leds ( ) )
{
_ledStringColorOrder . insert ( _ledStringColorOrder . begin ( ) + led . index , led . colorOrder ) ;
}
}
// insert cloned leds into buffer
for ( Led & led : _ledStringClone . leds ( ) )
{
_ledBuffer . insert ( _ledBuffer . begin ( ) + led . index , _ledBuffer . at ( led . clone ) ) ;
}
2015-01-01 19:31:04 +01:00
int i = 0 ;
2016-07-01 23:20:41 +02:00
for ( ColorRgb & color : _ledBuffer )
2013-08-21 21:50:17 +02:00
{
2016-08-08 00:17:00 +02:00
//const ColorOrder ledColorOrder = leds.at(i).colorOrder;
2013-11-04 20:52:57 +01:00
// correct the color byte order
2016-08-08 00:17:00 +02:00
switch ( _ledStringColorOrder . at ( i ) )
2013-10-27 10:18:31 +01:00
{
2013-11-04 20:52:57 +01:00
case ORDER_RGB :
// leave as it is
break ;
case ORDER_BGR :
2013-10-27 10:18:31 +01:00
std : : swap ( color . red , color . blue ) ;
2013-11-04 20:52:57 +01:00
break ;
case ORDER_RBG :
std : : swap ( color . green , color . blue ) ;
break ;
case ORDER_GRB :
std : : swap ( color . red , color . green ) ;
break ;
case ORDER_GBR :
2016-05-22 00:30:53 +02:00
std : : swap ( color . red , color . green ) ;
std : : swap ( color . green , color . blue ) ;
2013-11-04 20:52:57 +01:00
break ;
2017-01-10 19:58:41 +01:00
2013-11-04 20:52:57 +01:00
case ORDER_BRG :
2016-05-22 00:30:53 +02:00
std : : swap ( color . red , color . blue ) ;
std : : swap ( color . green , color . blue ) ;
2013-11-04 20:52:57 +01:00
break ;
}
2015-01-01 19:31:04 +01:00
i + + ;
2013-08-21 21:50:17 +02:00
}
2013-08-14 17:02:09 +02:00
2016-07-01 23:20:41 +02:00
if ( _hwLedCount > _ledBuffer . size ( ) )
{
_ledBuffer . resize ( _hwLedCount , ColorRgb : : BLACK ) ;
}
2013-08-14 17:02:09 +02:00
// Write the data to the device
2016-09-08 16:32:42 +02:00
if ( _deviceSmooth - > enabled ( ) )
2016-09-23 08:49:22 +02:00
_deviceSmooth - > setLedValues ( _ledBuffer ) ;
2016-09-08 16:32:42 +02:00
else
2016-09-23 08:49:22 +02:00
_device - > setLedValues ( _ledBuffer ) ;
2013-08-14 17:02:09 +02:00
// Start the timeout-timer
if ( priorityInfo . timeoutTime_ms = = - 1 )
{
_timer . stop ( ) ;
}
else
{
int timeout_ms = std : : max ( 0 , int ( priorityInfo . timeoutTime_ms - QDateTime : : currentMSecsSinceEpoch ( ) ) ) ;
_timer . start ( timeout_ms ) ;
2013-07-26 22:38:34 +02:00
}
}