Details coming soon.

This commit is contained in:
Paulchen-Panther
2018-12-27 23:11:32 +01:00
parent e3be03ea73
commit d762aa2f3e
186 changed files with 6156 additions and 5444 deletions

View File

@@ -4,30 +4,28 @@
// QT includes
#include <QJsonObject>
// util
#include <utils/Logger.h>
#include <utils/settings.h>
#include <utils/Components.h>
// Local Hyperion includes
#include "BlackBorderDetector.h"
class Hyperion;
namespace hyperion
{
///
/// The BlackBorder processor is a wrapper around the black-border detector for keeping track of
/// detected borders and count of the type and size of detected borders.
///
class BlackBorderProcessor
class BlackBorderProcessor : public QObject
{
Q_OBJECT
public:
///
/// Constructor for the BlackBorderProcessor
/// @param unknownFrameCnt The number of frames(images) that need to contain an unknown
/// border before the current border is set to unknown
/// @param borderFrameCnt The number of frames(images) that need to contain a vertical or
/// horizontal border becomes the current border
/// @param blurRemoveCnt The size to add to a horizontal or vertical border (because the
/// outer pixels is blurred (black and color combined due to image scaling))
/// @param[in] blackborderThreshold The threshold which the blackborder detector should use
///
BlackBorderProcessor(const QJsonObject &blackborderConfig);
BlackBorderProcessor(Hyperion* hyperion, QObject* parent);
~BlackBorderProcessor();
///
/// Return the current (detected) border
/// @return The current border
@@ -46,6 +44,13 @@ namespace hyperion
///
void setEnabled(bool enable);
///
/// Sets the _hardDisabled state, if True prevents the enable from COMP_BLACKBORDER state emit (mimiks wrong state to external!)
/// It's not possible to enable bb from this method, if the user requsted a disable!
/// @param disable The new state
///
void setHardDisable(const bool& disable);
///
/// Processes the image. This performs detecion of black-border on the given image and
/// updates the current border accordingly. If the current border is updated the method call
@@ -70,11 +75,11 @@ namespace hyperion
}
if (_detectionMode == "default") {
imageBorder = _detector.process(image);
imageBorder = _detector->process(image);
} else if (_detectionMode == "classic") {
imageBorder = _detector.process_classic(image);
imageBorder = _detector->process_classic(image);
} else if (_detectionMode == "osd") {
imageBorder = _detector.process_osd(image);
imageBorder = _detector->process_osd(image);
}
// add blur to the border
if (imageBorder.horizontalSize > 0)
@@ -89,8 +94,23 @@ namespace hyperion
const bool borderUpdated = updateBorder(imageBorder);
return borderUpdated;
}
private slots:
///
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
/// @param type settingyType from enum
/// @param config configuration object
///
void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config);
///
/// @brief Handle component state changes, it's not possible for BB to be enabled, when a hardDisable is active
///
void componentStateChanged(const hyperion::Components component, bool enable);
private:
/// Hyperion instance
Hyperion* _hyperion;
///
/// Updates the current border based on the newly detected border. Returns true if the
/// current border has changed.
@@ -102,24 +122,24 @@ namespace hyperion
/// flag for blackborder detector usage
bool _enabled;
/// The number of unknown-borders detected before it becomes the current border
const unsigned _unknownSwitchCnt;
unsigned _unknownSwitchCnt;
/// The number of horizontal/vertical borders detected before it becomes the current border
const unsigned _borderSwitchCnt;
unsigned _borderSwitchCnt;
// The number of frames that are "ignored" before a new border gets set as _previousDetectedBorder
const unsigned _maxInconsistentCnt;
unsigned _maxInconsistentCnt;
/// The number of pixels to increase a detected border for removing blury pixels
unsigned _blurRemoveCnt;
/// The border detection mode
const QString _detectionMode;
QString _detectionMode;
/// The blackborder detector
BlackBorderDetector _detector;
BlackBorderDetector* _detector;
/// The current detected border
BlackBorder _currentBorder;
@@ -131,5 +151,12 @@ namespace hyperion
unsigned _consistentCnt;
/// The number of frame the previous detected border NOT matched the incomming border
unsigned _inconsistentCnt;
/// old threshold
double _oldThreshold;
/// True when disabled in specific situations, this prevents to enable BB when the visible priority requested a disable
bool _hardDisabled;
/// Reflect the last component state request from user (comp change)
bool _userEnabled;
};
} // end namespace hyperion

View File

@@ -4,15 +4,19 @@
#include <cstdint>
// Qt includes
#include <QTcpServer>
#include <QSet>
#include <QJsonDocument>
// Hyperion includes
#include <hyperion/Hyperion.h>
#include <utils/Logger.h>
#include <utils/Components.h>
// settings
#include <utils/settings.h>
class BoblightClientConnection;
class Hyperion;
class QTcpServer;
///
/// This class creates a TCP server which accepts connections from boblight clients.
@@ -27,25 +31,24 @@ public:
/// @param hyperion Hyperion instance
/// @param port port number on which to start listening for connections
///
BoblightServer(const int priority, uint16_t port = 19333);
BoblightServer(const QJsonDocument& config);
~BoblightServer();
///
/// @return the port number on which this TCP listens for incoming connections
///
uint16_t getPort() const;
/// @return true if server is active (bind to a port)
///
bool active() { return _isActive; };
bool componentState() { return active(); };
bool active();
public slots:
///
/// bind server to network
///
void start();
///
/// close server
///
@@ -53,8 +56,12 @@ public slots:
void componentStateChanged(const hyperion::Components component, bool enable);
signals:
void statusChanged(bool isActive);
///
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
/// @param type settingyType from enum
/// @param config configuration object
///
void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config);
private slots:
///
@@ -73,19 +80,17 @@ private:
Hyperion * _hyperion;
/// The TCP server object
QTcpServer _server;
QTcpServer * _server;
/// List with open connections
QSet<BoblightClientConnection *> _openConnections;
/// hyperion priority
const int _priority;
int _priority;
/// Logger instance
Logger * _log;
/// state of connection
bool _isActive;
// current port
uint16_t _port;
};

View File

@@ -0,0 +1,68 @@
#pragma once
// qt incl
#include <QObject>
#include <QMap>
#include <QHostInfo>
#include <bonjour/bonjourrecord.h>
class BonjourServiceBrowser;
class BonjourServiceResolver;
class QTimer;
class BonjourBrowserWrapper : public QObject
{
Q_OBJECT
private:
friend class HyperionDaemon;
///
/// @brief Browse for hyperion services in bonjour, constructed from HyperionDaemon
/// Searching for hyperion http service by default
///
BonjourBrowserWrapper(QObject * parent = 0);
public:
///
/// @brief Browse for a service
///
bool browseForServiceType(const QString &serviceType);
///
/// @brief Get all available sessions
///
QMap<QString,BonjourRecord> getAllServices() { return _hyperionSessions; };
static BonjourBrowserWrapper* instance;
static BonjourBrowserWrapper* getInstance(){ return instance; };
signals:
///
/// @brief Emits whenever a change happend
///
void browserChange(const QMap<QString,BonjourRecord>& bRegisters);
private:
/// map of service names and browsers
QMap< QString, BonjourServiceBrowser* > _browsedServices;
/// Resolver
BonjourServiceResolver* _bonjourResolver;
// contains all current active service sessions
QMap<QString,BonjourRecord> _hyperionSessions;
QString _bonjourCurrentServiceToResolve;
/// timer to resolve changes
QTimer* _timerBonjourResolver;
private slots:
///
/// @brief is called whenever a BonjourServiceBrowser emits change
void currentBonjourRecordsChanged(const QList<BonjourRecord> &list);
/// @brief new record resolved
void bonjourRecordResolved(const QHostInfo &hostInfo, int port);
///
/// @brief timer slot which updates regularly entries
///
void bonjourResolve();
};

View File

@@ -43,7 +43,8 @@ public:
BonjourServiceRegister(QObject *parent = 0);
~BonjourServiceRegister();
void registerService(const BonjourRecord &record, quint16 servicePort, std::vector<std::pair<std::string, std::string>> txt);
void registerService(const QString& service, const int& port);
void registerService(const BonjourRecord &record, quint16 servicePort, std::vector<std::pair<std::string, std::string>> txt = std::vector<std::pair<std::string, std::string>>());
inline BonjourRecord registeredRecord() const {return finalRecord; }
signals:

View File

@@ -0,0 +1,89 @@
#pragma once
// Python includes
// collide of qt slots macro
#undef slots
#include "Python.h"
#define slots
// Qt includes
#include <QThread>
#include <QJsonObject>
#include <QSize>
#include <QImage>
#include <QPainter>
#include <QMap>
// Hyperion includes
#include <utils/Components.h>
#include <utils/Image.h>
class Hyperion;
class Logger;
class Effect : public QThread
{
Q_OBJECT
public:
friend class EffectModule;
Effect(Hyperion* hyperion, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args = QJsonObject());
virtual ~Effect();
virtual void run();
int getPriority() const { return _priority; };
///
/// @brief Set manual interuption to true,
/// Note: DO NOT USE QThread::interuption!
///
void setInteruptionFlag() { _interupt = true; };
///
/// @brief Check if the interuption flag has been set
/// @return The flag state
///
bool hasInteruptionFlag() { return _interupt; };
QString getScript() const { return _script; }
QString getName() const { return _name; }
int getTimeout() const {return _timeout; }
QJsonObject getArgs() const { return _args; }
signals:
void setInput(const int priority, const std::vector<ColorRgb>& ledColors, const int timeout_ms, const bool& clearEffect);
void setInputImage(const int priority, const Image<ColorRgb>& image, const int timeout_ms, const bool& clearEffect);
private:
void addImage();
Hyperion* _hyperion;
const int _priority;
const int _timeout;
const QString _script;
const QString _name;
const QJsonObject _args;
int64_t _endTime;
/// Buffer for colorData
QVector<ColorRgb> _colors;
Logger* _log;
// Reflects whenever this effects should interupt (timeout or external request)
bool _interupt = false;
QSize _imageSize;
QImage _image;
QPainter* _painter;
QVector<QImage> _imageStack;
};

View File

@@ -19,7 +19,6 @@
// pre-declarioation
class Effect;
typedef struct _ts PyThreadState;
class EffectEngine : public QObject
{
@@ -43,6 +42,20 @@ public:
return _effectSchemas;
};
///
/// @brief Get all init data of the running effects and stop them
///
void cacheRunningEffects();
///
/// @brief Start all cached effects, origin and smooth cfg is default
///
void startCachedEffects();
signals:
/// Emit when the effect list has been updated
void effectListUpdated();
public slots:
/// Run the specified effect on the given priority channel and optionally specify a timeout
int runEffect(const QString &effectName, int priority, int timeout = -1, const QString &origin="System");
@@ -78,9 +91,9 @@ private:
std::list<ActiveEffectDefinition> _availableActiveEffects;
std::list<ActiveEffectDefinition> _cachedActiveEffects;
std::list<EffectSchema> _effectSchemas;
Logger * _log;
PyThreadState* _mainThreadState;
};

View File

@@ -0,0 +1,53 @@
#pragma once
#undef slots
#include <Python.h>
#define slots
#include <QJsonValue>
class Effect;
class EffectModule
{
public:
// Python 3 module def
static struct PyModuleDef moduleDef;
// Init module
static PyObject* PyInit_hyperion();
// Register module once
static void registerHyperionExtensionModule();
// json 2 python
static PyObject * json2python(const QJsonValue & jsonData);
// Wrapper methods for Python interpreter extra buildin methods
static PyMethodDef effectMethods[];
static PyObject* wrapSetColor (PyObject *self, PyObject *args);
static PyObject* wrapSetImage (PyObject *self, PyObject *args);
static PyObject* wrapGetImage (PyObject *self, PyObject *args);
static PyObject* wrapAbort (PyObject *self, PyObject *args);
static PyObject* wrapImageShow (PyObject *self, PyObject *args);
static PyObject* wrapImageLinearGradient (PyObject *self, PyObject *args);
static PyObject* wrapImageConicalGradient (PyObject *self, PyObject *args);
static PyObject* wrapImageRadialGradient (PyObject *self, PyObject *args);
static PyObject* wrapImageSolidFill (PyObject *self, PyObject *args);
static PyObject* wrapImageDrawLine (PyObject *self, PyObject *args);
static PyObject* wrapImageDrawPoint (PyObject *self, PyObject *args);
static PyObject* wrapImageDrawRect (PyObject *self, PyObject *args);
static PyObject* wrapImageDrawPolygon (PyObject *self, PyObject *args);
static PyObject* wrapImageDrawPie (PyObject *self, PyObject *args);
static PyObject* wrapImageSetPixel (PyObject *self, PyObject *args);
static PyObject* wrapImageGetPixel (PyObject *self, PyObject *args);
static PyObject* wrapImageSave (PyObject *self, PyObject *args);
static PyObject* wrapImageMinSize (PyObject *self, PyObject *args);
static PyObject* wrapImageWidth (PyObject *self, PyObject *args);
static PyObject* wrapImageHeight (PyObject *self, PyObject *args);
static PyObject* wrapImageCRotate (PyObject *self, PyObject *args);
static PyObject* wrapImageCOffset (PyObject *self, PyObject *args);
static PyObject* wrapImageCShear (PyObject *self, PyObject *args);
static PyObject* wrapImageResetT (PyObject *self, PyObject *args);
static Effect * getEffect();
};

View File

@@ -18,9 +18,8 @@ public:
/// @param[in] grabWidth The width of the grabbed image [pixels]
/// @param[in] grabHeight The height of the grabbed images [pixels]
/// @param[in] updateRate_Hz The image grab rate [Hz]
/// @param[in] hyperion The instance of Hyperion used to write the led values
///
AmlogicWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, const int priority);
AmlogicWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz);
///
/// Destructor of this dispmanx frame grabber. Releases any claimed resources.

View File

@@ -40,14 +40,23 @@ public:
///
int grabFrame(Image<ColorRgb> & image);
///
///@brief Set new width and height for dispmanx, overwrite Grabber.h impl
virtual void setWidthHeight(int width, int height);
private:
///
///
/// Updates the frame-grab flags as used by the VC library for frame grabbing
///
/// @param vc_flags The snapshot grabbing mask
///
void setFlags(const int vc_flags);
///
/// @brief free _vc_resource and captureBuffer
///
void freeResources();
/// Handle to the display that is being captured
DISPMANX_DISPLAY_HANDLE_T _vc_display;

View File

@@ -7,8 +7,7 @@
///
/// The DispmanxWrapper uses an instance of the DispmanxFrameGrabber to obtain ImageRgb's from the
/// displayed content. This ImageRgb is processed to a ColorRgb for each led and commmited to the
/// attached Hyperion.
/// displayed content. This ImageRgb is forwarded to all Hyperion instances via HyperionDaemon
///
class DispmanxWrapper: public GrabberWrapper
{
@@ -20,9 +19,8 @@ public:
/// @param[in] grabWidth The width of the grabbed image [pixels]
/// @param[in] grabHeight The height of the grabbed images [pixels]
/// @param[in] updateRate_Hz The image grab rate [Hz]
/// @param[in] hyperion The instance of Hyperion used to write the led values
///
DispmanxWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, const int priority);
DispmanxWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz);
///
/// Destructor of this dispmanx frame grabber. Releases any claimed resources.

View File

@@ -5,7 +5,7 @@
#include <hyperion/Grabber.h>
///
/// The FramebufferFrameGrabber is used for creating snapshots of the display (screenshots)
/// The FramebufferFrameGrabber is used for creating snapshots of the display (screenshots)
///
class FramebufferFrameGrabber : public Grabber
{
@@ -30,13 +30,18 @@ public:
///
int grabFrame(Image<ColorRgb> & image);
///
/// @brief Overwrite Grabber.h implememtation
///
virtual void setDevicePath(const QString& path);
private:
/// Framebuffer file descriptor
int _fbfd;
/// Pointer to framebuffer
unsigned char * _fbp;
/// Framebuffer device e.g. /dev/fb0
const QString _fbDevice;
QString _fbDevice;
};

View File

@@ -20,7 +20,7 @@ public:
/// @param[in] grabHeight The height of the grabbed images [pixels]
/// @param[in] updateRate_Hz The image grab rate [Hz]
///
FramebufferWrapper(const QString & device, const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, const int priority);
FramebufferWrapper(const QString & device, const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz);
///
/// Destructor of this framebuffer frame grabber. Releases any claimed resources.

View File

@@ -12,7 +12,7 @@
#include <hyperion/Grabber.h>
///
/// The OsxFrameGrabber is used for creating snapshots of the display (screenshots)
/// The OsxFrameGrabber is used for creating snapshots of the display (screenshots)
///
class OsxFrameGrabber : public Grabber
{
@@ -37,10 +37,15 @@ public:
///
int grabFrame(Image<ColorRgb> & image);
private:
///
/// @brief Overwrite Grabber.h implementation
///
virtual void setDisplayIndex(int index);
private:
/// display
const unsigned _screenIndex;
unsigned _screenIndex;
/// Reference to the captured diaplay
CGDirectDisplayID _display;
};

View File

@@ -19,9 +19,8 @@ public:
/// @param[in] grabWidth The width of the grabbed image [pixels]
/// @param[in] grabHeight The height of the grabbed images [pixels]
/// @param[in] updateRate_Hz The image grab rate [Hz]
/// @param[in] hyperion The instance of Hyperion used to write the led values
///
OsxWrapper(const unsigned display, const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, const int priority);
OsxWrapper(const unsigned display, const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz);
///
/// Destructor of this osx frame grabber. Releases any claimed resources.

View File

@@ -24,12 +24,9 @@ class V4L2Grabber : public Grabber
public:
V4L2Grabber(const QString & device,
int input,
VideoStandard videoStandard, PixelFormat pixelFormat,
unsigned width,
unsigned height,
int frameDecimation,
int horizontalPixelDecimation,
int verticalPixelDecimation
VideoStandard videoStandard,
PixelFormat pixelFormat,
int pixelDecimation
);
virtual ~V4L2Grabber();
@@ -37,21 +34,46 @@ public:
bool getSignalDetectionEnabled();
int grabFrame(Image<ColorRgb> &);
public slots:
void setSignalThreshold(
///
/// @brief overwrite Grabber.h implementation, as v4l doesn't use width/height
///
virtual void setWidthHeight(){};
///
/// @brief set new PixelDecimation value to ImageResampler
/// @param pixelDecimation The new pixelDecimation value
///
virtual void setPixelDecimation(int pixelDecimation);
///
/// @brief overwrite Grabber.h implementation
///
virtual void setSignalThreshold(
double redSignalThreshold,
double greenSignalThreshold,
double blueSignalThreshold,
int noSignalCounterThreshold);
int noSignalCounterThreshold = 50);
void setSignalDetectionOffset(
///
/// @brief overwrite Grabber.h implementation
///
virtual void setSignalDetectionOffset(
double verticalMin,
double horizontalMin,
double verticalMax,
double horizontalMax);
///
/// @brief overwrite Grabber.h implementation
///
virtual void setSignalDetectionEnable(bool enable);
void setSignalDetectionEnable(bool enable);
///
/// @brief overwrite Grabber.h implementation
///
virtual void setInputVideoStandard(int input, VideoStandard videoStandard);
public slots:
bool start();
@@ -66,7 +88,7 @@ private slots:
private:
void getV4Ldevices();
bool init();
void uninit();
@@ -120,9 +142,9 @@ private:
std::vector<buffer> _buffers;
PixelFormat _pixelFormat;
int _pixelDecimation;
int _lineLength;
int _frameByteSize;
int _frameDecimation;
// signal detection
int _noSignalCounterThreshold;
@@ -134,7 +156,6 @@ private:
double _y_frac_min;
double _x_frac_max;
double _y_frac_max;
int _currentFrame;
QSocketNotifier * _streamNotifier;

View File

@@ -12,14 +12,7 @@ public:
int input,
VideoStandard videoStandard,
PixelFormat pixelFormat,
unsigned width,
unsigned height,
int frameDecimation,
int pixelDecimation,
double redSignalThreshold,
double greenSignalThreshold,
double blueSignalThreshold,
const int priority);
int pixelDecimation );
virtual ~V4L2Wrapper() {};
bool getSignalDetectionEnable();
@@ -28,19 +21,16 @@ public slots:
bool start();
void stop();
void setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold);
void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom);
void setSignalDetectionOffset(double verticalMin, double horizontalMin, double verticalMax, double horizontalMax);
void setSignalDetectionEnable(bool enable);
// signals:
// void emitColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms);
private slots:
void newFrame(const Image<ColorRgb> & image);
void readError(const char* err);
virtual void action();
void checkSources();
private:
/// The V4L2 grabber

View File

@@ -17,12 +17,12 @@ class X11Grabber : public Grabber
{
public:
X11Grabber(bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation);
X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation);
virtual ~X11Grabber();
bool Setup();
///
/// Captures a single snapshot of the display and writes the data to the given image. The
/// provided image should have the same dimensions as the configured values (_width and
@@ -32,15 +32,34 @@ public:
/// height)
///
virtual int grabFrame(Image<ColorRgb> & image, bool forceUpdate=false);
///
/// update dimension according current screen
int updateScreenDimensions(bool force=false);
virtual void setVideoMode(VideoMode mode);
///
/// @brief Apply new width/height values, overwrite Grabber.h implementation as X11 doesn't use width/height, just pixelDecimation to calc dimensions
///
virtual void setWidthHeight(int width, int height);
///
/// @brief Apply new pixelDecimation
///
virtual void setPixelDecimation(int pixelDecimation);
///
/// Set the crop values
/// @param cropLeft Left pixel crop
/// @param cropRight Right pixel crop
/// @param cropTop Top pixel crop
/// @param cropBottom Bottom pixel crop
///
virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom);
private:
bool _useXGetImage, _XShmAvailable, _XShmPixmapAvailable, _XRenderAvailable;
bool _XShmAvailable, _XShmPixmapAvailable, _XRenderAvailable;
XImage* _xImage;
XShmSegmentInfo _shminfo;
@@ -49,17 +68,16 @@ private:
Display* _x11Display;
Window _window;
XWindowAttributes _windowAttr;
Pixmap _pixmap;
XRenderPictFormat* _srcFormat;
XRenderPictFormat* _dstFormat;
XRenderPictureAttributes _pictAttr;
Picture _srcPicture;
Picture _dstPicture;
XTransform _transform;
int _horizontalDecimation;
int _verticalDecimation;
int _pixelDecimation;
unsigned _screenWidth;
unsigned _screenHeight;
@@ -67,7 +85,7 @@ private:
unsigned _src_y;
Image<ColorRgb> _image;
void freeResources();
void setupResources();
};

View File

@@ -24,7 +24,7 @@ public:
/// @param[in] grabHeight The height of the grabbed images [pixels]
/// @param[in] updateRate_Hz The image grab rate [Hz]
///
X11Wrapper(bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation, const unsigned updateRate_Hz, const int priority);
X11Wrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, const unsigned updateRate_Hz);
///
/// Destructor of this framebuffer frame grabber. Releases any claimed resources.
@@ -43,4 +43,3 @@ private:
bool _init;
};

View File

@@ -0,0 +1,71 @@
#pragma once
#include <utils/Logger.h>
#include <hyperion/Hyperion.h>
#include <utils/settings.h>
///
/// @brief Handle the background Effect settings, reacts on runtime to settings changes
///
class BGEffectHandler : public QObject
{
Q_OBJECT
public:
BGEffectHandler(Hyperion* hyperion)
: QObject(hyperion)
, _hyperion(hyperion)
{
// listen for config changes
connect(_hyperion, &Hyperion::settingsChanged, this, &BGEffectHandler::handleSettingsUpdate);
// init
handleSettingsUpdate(settings::BGEFFECT, _hyperion->getSetting(settings::BGEFFECT));
};
private slots:
///
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
/// @param type settingyType from enum
/// @param config configuration object
///
void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config)
{
if(type == settings::BGEFFECT)
{
const QJsonObject& BGEffectConfig = config.object();
#define BGCONFIG_ARRAY bgColorConfig.toArray()
// clear bg prioritiy
_hyperion->clear(254);
// initial background effect/color
if (BGEffectConfig["enable"].toBool(true))
{
const QString bgTypeConfig = BGEffectConfig["type"].toString("effect");
const QString bgEffectConfig = BGEffectConfig["effect"].toString("Warm mood blobs");
const QJsonValue bgColorConfig = BGEffectConfig["color"];
if (bgTypeConfig.contains("color"))
{
ColorRgb bg_color = {
(uint8_t)BGCONFIG_ARRAY.at(0).toInt(0),
(uint8_t)BGCONFIG_ARRAY.at(1).toInt(0),
(uint8_t)BGCONFIG_ARRAY.at(2).toInt(0)
};
_hyperion->setColor(254, bg_color);
Info(Logger::getInstance("HYPERION"),"Inital background color set (%d %d %d)",bg_color.red,bg_color.green,bg_color.blue);
}
else
{
int result = _hyperion->setEffect(bgEffectConfig, 254);
Info(Logger::getInstance("HYPERION"),"Inital background effect '%s' %s", QSTRING_CSTR(bgEffectConfig), ((result == 0) ? "started" : "failed"));
}
}
#undef BGCONFIG_ARRAY
}
};
private:
/// Hyperion instance pointer
Hyperion* _hyperion;
};

View File

@@ -0,0 +1,62 @@
#pragma once
#include <utils/Logger.h>
#include <utils/settings.h>
#include <utils/Components.h>
#include <utils/Image.h>
class Hyperion;
///
/// @brief Capture Control class which is a interface to the HyperionDaemon native capture classes.
/// It controls the instance based enable/disable of capture feeds and PriorityMuxer registrations
///
class CaptureCont : public QObject
{
Q_OBJECT
public:
CaptureCont(Hyperion* hyperion);
~CaptureCont();
void setSystemCaptureEnable(const bool& enable);
void setV4LCaptureEnable(const bool& enable);
private slots:
///
/// @brief Handle component state change of V4L and SystemCapture
/// @param component The component from enum
/// @param enable The new state
///
void componentStateChanged(const hyperion::Components component, bool enable);
///
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
/// @param type settingyType from enum
/// @param config configuration object
///
void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config);
///
/// @brief forward system image
/// @param image The image
///
void handleSystemImage(const Image<ColorRgb>& image);
///
/// @brief forward v4l image
/// @param image The image
///
void handleV4lImage(const Image<ColorRgb> & image);
private:
/// Hyperion instance
Hyperion* _hyperion;
/// Reflect state of System capture and prio
bool _systemCaptEnabled;
quint8 _systemCaptPrio;
/// Reflect state of v4l capture and prio
bool _v4lCaptEnabled;
quint8 _v4lCaptPrio;
};

View File

@@ -1,6 +1,6 @@
#pragma once
#include <utils/Components.h>
#include <utils/Components.h>
#include <utils/Logger.h>
// STL includes
@@ -8,21 +8,61 @@
#include <QObject>
class Hyperion;
///
/// @brief The component register reflects and manages the current state of all components and Hyperion as a whole
/// It emits also real component state changes (triggert from the specific component), which can be used for listening APIs (Network Clients/Plugins)
///
class ComponentRegister : public QObject
{
Q_OBJECT
public:
ComponentRegister();
ComponentRegister(Hyperion* hyperion);
~ComponentRegister();
///
/// @brief Enable or disable Hyperion (all components)
/// @param state The new state of Hyperion
///
/// @return Returns true on success, false when Hyperion is already at the requested state
///
bool setHyperionEnable(const bool& state);
///
/// @brief Check if a component is currently enabled
/// @param comp The component from enum
/// @return True if component is running else false
///
bool isComponentEnabled(const hyperion::Components& comp) const;
/// contains all components and their state
std::map<hyperion::Components, bool> getRegister() { return _componentStates; };
signals:
///
/// @brief Emits whenever a component changed (really) the state
/// @param comp The component
/// @param state The new state of the component
///
void updatedComponentState(const hyperion::Components comp, const bool state);
public slots:
///
/// @brief is called whenever a component change a state, DO NOT CALL FROM API (use hyperion->setComponentState() instead)
/// @param comp The component
/// @param state The new state of the component
///
void componentStateChanged(const hyperion::Components comp, const bool activated);
private:
std::map<hyperion::Components, bool> _componentStates;
/// Hyperion instance
Hyperion * _hyperion;
/// Logger instance
Logger * _log;
/// current state of all components
std::map<hyperion::Components, bool> _componentStates;
/// on hyperion off we save the previous states of all components
std::map<hyperion::Components, bool> _prevComponentStates;
};

View File

@@ -6,10 +6,14 @@
#include <utils/ColorRgb.h>
#include <utils/Image.h>
#include <utils/VideoMode.h>
#include <grabber/VideoStandard.h>
#include <utils/ImageResampler.h>
#include <utils/Logger.h>
///
/// @brief The Grabber class is responsible to apply image resizes (with or without ImageResampler)
/// Overwrite the videoMode with setVideoMode()
/// Overwrite setCropping()
class Grabber : public QObject
{
Q_OBJECT
@@ -24,14 +28,71 @@ public:
///
virtual void setVideoMode(VideoMode mode);
///
/// @brief Apply new crop values, on errors reject the values
///
virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom);
/// gets resulting height of image
///
/// @brief Apply new width/height values, on errors (collide with cropping) reject the values
///
virtual void setWidthHeight(int width, int height);
///
/// @brief Apply new pixelDecimation (used from x11)
///
virtual void setPixelDecimation(int pixelDecimation) {};
///
/// @brief Apply new signalThreshold (used from v4l)
///
virtual void setSignalThreshold(
double redSignalThreshold,
double greenSignalThreshold,
double blueSignalThreshold,
int noSignalCounterThreshold = 50) {};
///
/// @brief Apply new SignalDetectionOffset (used from v4l)
///
virtual void setSignalDetectionOffset(
double verticalMin,
double horizontalMin,
double verticalMax,
double horizontalMax) {};
///
/// @brief Apply SignalDetectionEnable (used from v4l)
///
virtual void setSignalDetectionEnable(bool enable) {};
///
/// @brief Apply input and videoStanded (used from v4l)
///
virtual void setInputVideoStandard(int input, VideoStandard videoStandard) {};
///
/// @brief Apply display index (used from x11)
///
virtual void setDisplayIndex(int index) {};
///
/// @brief Apply path for device (used from framebuffer)
///
virtual void setDevicePath(const QString& path) {};
///
/// @brief get current resulting height of image (after crop)
///
virtual const int getImageWidth() { return _width; };
/// gets resulting width of image
///
/// @brief get current resulting width of image (after crop)
///
virtual const int getImageHeight() { return _height; };
///
/// @brief Prevent the real capture implementation from capturing if disabled
///
void setEnabled(bool enable);
protected:

View File

@@ -1,27 +1,29 @@
#pragma once
#include <QObject>
#include <QTimer>
#include <QString>
#include <QStringList>
#include <utils/Logger.h>
#include <utils/Components.h>
#include <hyperion/Hyperion.h>
#include <hyperion/ImageProcessor.h>
#include <utils/Image.h>
#include <utils/ColorRgb.h>
#include <utils/VideoMode.h>
#include <utils/settings.h>
class ImageProcessor;
class Grabber;
class DispmanxFrameGrabber;
class QTimer;
///
/// This class will be inherted by FramebufferWrapper and others which contains the real capture interface
///
class GrabberWrapper : public QObject
{
Q_OBJECT
public:
GrabberWrapper(QString grabberName, Grabber * ggrabber, unsigned width, unsigned height, const unsigned updateRate_Hz, const int priority, hyperion::Components grabberComponentId=hyperion::COMP_GRABBER);
GrabberWrapper(QString grabberName, Grabber * ggrabber, unsigned width, unsigned height, const unsigned updateRate_Hz);
virtual ~GrabberWrapper();
@@ -35,8 +37,6 @@ public:
///
virtual void stop();
void setImageProcessorEnabled(bool enable);
static QStringList availableGrabbers();
public:
@@ -45,18 +45,15 @@ public:
{
unsigned w = grabber.getImageWidth();
unsigned h = grabber.getImageHeight();
if (_imageProcessorEnabled && ( _image.width() != w || _image.height() != h))
if ( _image.width() != w || _image.height() != h)
{
_processor->setSize(w, h);
_image.resize(w, h);
}
int ret = grabber.grabFrame(_image);
if (ret >= 0)
{
emit emitImage(_priority, _image, _timeout_ms);
_processor->process(_image, _ledColors);
setColors(_ledColors, _timeout_ms);
emit systemImage(_image);
return true;
}
return false;
@@ -64,46 +61,51 @@ public:
public slots:
void componentStateChanged(const hyperion::Components component, bool enable);
///
/// virtual method, should perform single frame grab and computes the led-colors
///
virtual void action() = 0;
void actionWrapper();
///
/// Set the video mode (2D/3D)
/// @param[in] mode The new video mode
///
virtual void setVideoMode(const VideoMode videoMode);
virtual void setVideoMode(const VideoMode& videoMode);
///
/// Set the crop values
/// @param cropLeft Left pixel crop
/// @param cropRight Right pixel crop
/// @param cropTop Top pixel crop
/// @param cropBottom Bottom pixel crop
///
virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom);
///
/// @brief Handle settings update from HyperionDaemon Settingsmanager emit
/// @param type settingyType from enum
/// @param config configuration object
///
virtual void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config);
signals:
void emitImage(int priority, const Image<ColorRgb> & image, const int timeout_ms);
///
/// @brief Emit the final processed image
///
void systemImage(const Image<ColorRgb>& image);
protected:
void setColors(const std::vector<ColorRgb> &ledColors, const int timeout_ms);
QString _grabberName;
/// Pointer to Hyperion for writing led values
Hyperion * _hyperion;
/// The priority of the led colors
const int _priority;
/// The timer for generating events with the specified update rate
QTimer _timer;
QTimer* _timer;
/// The update rate [Hz]
const int _updateInterval_ms;
/// The timeout of the led colors [ms]
const int _timeout_ms;
/// The calced update rate [ms]
int _updateInterval_ms;
/// The Logger instance
Logger * _log;
@@ -111,18 +113,8 @@ protected:
// forwarding enabled
bool _forward;
/// The processor for transforming images to led colors
ImageProcessor * _processor;
hyperion::Components _grabberComponentId;
Grabber *_ggrabber;
/// The image used for grabbing frames
Image<ColorRgb> _image;
/// The list with computed led colors
std::vector<ColorRgb> _ledColors;
bool _imageProcessorEnabled;
};

View File

@@ -8,12 +8,10 @@
#include <QObject>
#include <QString>
#include <QStringList>
#include <QTimer>
#include <QSize>
#include <QJsonObject>
#include <QJsonValue>
#include <QJsonArray>
#include <QTimer>
#include <QFileSystemWatcher>
// hyperion-utils includes
@@ -27,7 +25,6 @@
#include <hyperion/LedString.h>
#include <hyperion/PriorityMuxer.h>
#include <hyperion/ColorAdjustment.h>
#include <hyperion/MessageForwarder.h>
#include <hyperion/ComponentRegister.h>
// Effect engine includes
@@ -35,17 +32,23 @@
#include <effectengine/ActiveEffectDefinition.h>
#include <effectengine/EffectSchema.h>
// bonjour includes
#include <bonjour/bonjourservicebrowser.h>
#include <bonjour/bonjourserviceresolver.h>
// settings utils
#include <utils/settings.h>
// Forward class declaration
class QTimer;
class HyperionDaemon;
class ImageProcessor;
class MessageForwarder;
class LedDevice;
class LinearColorSmoothing;
class RgbTransform;
class EffectEngine;
class RgbChannelAdjustment;
class MultiColorAdjustment;
class ColorAdjustment;
class SettingsManager;
class BGEffectHandler;
class CaptureCont;
///
/// The main class of Hyperion. This gives other 'users' access to the attached LedDevice through
@@ -57,8 +60,6 @@ class Hyperion : public QObject
public:
/// Type definition of the info structure used by the priority muxer
typedef PriorityMuxer::InputInfo InputInfo;
typedef QMap<QString,int> PriorityRegister;
typedef QMap<QString,BonjourRecord> BonjourRegister;
///
/// RGB-Color channel enumeration
///
@@ -79,23 +80,54 @@ public:
///
/// @brief creates a new Hyperion instance, usually called from the Hyperion Daemon
/// @param[in] qjsonConfig The configuration file
/// @param[in] daemon The Hyperion daemon parent
/// @param[in] instance The instance id
/// @param[in] rootPath Root path of all hyperion userdata
/// @return Hyperion instance pointer
///
static Hyperion* initInstance(const QJsonObject& qjsonConfig, const QString configFile, const QString rootPath);
static Hyperion* initInstance(HyperionDaemon* daemon, const quint8& instance, const QString configFile, const QString rootPath);
///
/// @brief Get a pointer of this Hyperion instance
/// @return Hyperion instance pointer
/// @return Hyperion instance pointer
///
static Hyperion* getInstance();
///
/// @brief Get a pointer to the effect engine
/// @return EffectEngine instance pointer
///
EffectEngine* getEffectEngineInstance() { return _effectEngine; };
///
/// @brief Get a pointer to the priorityMuxer instance
/// @return PriorityMuxer instance pointer
///
PriorityMuxer* getMuxerInstance() { return &_muxer; };
///
/// @brief Get a setting by settings::type from SettingsManager
/// @param type The settingsType from enum
/// @return Data Document
///
QJsonDocument getSetting(const settings::type& type);
///
/// @brief Save a complete json config
/// @param config The entire config object
/// @param correct If true will correct json against schema before save
/// @return True on success else false
///
bool saveSettings(QJsonObject config, const bool& correct = false);
///
/// Returns the number of attached leds
///
unsigned getLedCount() const;
///
/// @brief Return the size of led grid
///
QSize getLedGridSize() const { return _ledGridSize; };
///
@@ -124,11 +156,9 @@ public:
///
/// @param[in] priority The priority channel
///
/// @return The information of the given
/// @return The information of the given, a not found priority will return lowest priority as fallback
///
/// @throw std::runtime_error when the priority channel does not exist
///
const InputInfo& getPriorityInfo(const int priority) const;
const InputInfo getPriorityInfo(const int priority) const;
/// Reload the list of available effects
void reloadEffects();
@@ -145,27 +175,29 @@ public:
/// @return The list of available effect schema files
const std::list<EffectSchema> &getEffectSchemas();
/// gets the current json config object
/// gets the current json config object from SettingsManager
/// @return json config
const QJsonObject& getQJsonConfig() { return _qjsonConfig; };
const QJsonObject& getQJsonConfig();
/// get path+filename of configfile
/// @return the current config path+filename
QString getConfigFilePath() { return _configFile; };
/// get filename of configfile
/// @return the current config filename
QString getConfigFileName() { return _configFile; };
QString getConfigFileName() const;
/// register a input source to a priority channel
/// @param name uniq name of input source
/// @param origin External setter
/// @param priority priority channel
void registerPriority(const QString &name, const int priority);
///
/// @brief Register a new input by priority, the priority is not active (timeout -100 isn't muxer recognized) until you start to update the data with setInput()
/// A repeated call to update the base data of a known priority won't overwrite their current timeout
/// @param[in] priority The priority of the channel
/// @param[in] component The component of the channel
/// @param[in] origin Who set the channel (CustomString@IP)
/// @param[in] owner Speicifc owner string, might be empty
/// @param[in] smooth_cfg The smooth id to use
///
void registerInput(const int priority, const hyperion::Components& component, const QString& origin = "System", const QString& owner = "", unsigned smooth_cfg = 0);
/// unregister a input source to a priority channel
/// @param name uniq name of input source
void unRegisterPriority(const QString &name);
/// gets current priority register
/// @return the priority register
const PriorityRegister& getPriorityRegister() { return _priorityRegister; }
/// enable/disable automatic/priorized source selection
/// @param enabled the state
@@ -178,12 +210,18 @@ public:
/// gets current state of automatic/priorized source selection
/// @return the state
bool sourceAutoSelectEnabled() { return _sourceAutoSelectEnabled; };
bool sourceAutoSelectEnabled();
///
/// Enable/Disable components during runtime
/// @brief Get the last untransformed/unadjusted led colors
/// @return The _rawLedBuffer leds
///
/// @param component The component [SMOOTHING, BLACKBORDER, FORWARDER, UDPLISTENER, BOBLIGHT_SERVER, GRABBER]
const std::vector<ColorRgb>& getRawLedBuffer() { return _rawLedBuffer; };
///
/// @brief Enable/Disable components during runtime, called from external API (requests)
///
/// @param component The component from enum
/// @param state The state of the component [true | false]
///
void setComponentState(const hyperion::Components component, const bool state);
@@ -195,54 +233,63 @@ public:
bool configWriteable() { return _configWrite; };
/// gets the methode how image is maped to leds
int getLedMappingType() { return _ledMAppingType; };
/// get the configuration
QJsonObject getConfig() { return _qjsonConfig; };
const int & getLedMappingType();
/// get the root path for all hyperion user data files
QString getRootPath() { return _rootPath; };
const QString &getRootPath() { return _rootPath; };
/// unique id per instance
QString id;
/// get unique id per instance
const QString &getId(){ return _id; };
/// set unique id
void setId(QString id){ _id = id; };
int getLatchTime() const;
/// forward smoothing config
unsigned addSmoothingConfig(int settlingTime_ms, double ledUpdateFrequency_hz=25.0, unsigned updateDelay=0);
VideoMode getCurrentVideoMode() { return _videoMode; };
const VideoMode & getCurrentVideoMode();
///
/// @brief Get the current active led device
/// @return The device nam
/// e
const QString & getActiveDevice();
public slots:
///
/// @brief Update the current color of a priority (prev registered with registerInput())
/// DO NOT use this together with setInputImage() at the same time!
/// @param priority The priority to update
/// @param ledColors The colors
/// @param timeout_ms The new timeout (defaults to -1 endless)
/// @param clearEffect Should be true when NOT called from an effect
/// @return True on success, false when priority is not found
///
const bool setInput(const int priority, const std::vector<ColorRgb>& ledColors, const int timeout_ms = -1, const bool& clearEffect = true);
///
/// @brief Update the current image of a priority (prev registered with registerInput())
/// DO NOT use this together with setInput() at the same time!
/// @param priority The priority to update
/// @param image The new image
/// @param timeout_ms The new timeout (defaults to -1 endless)
/// @param clearEffect Should be true when NOT called from an effect
/// @return True on success, false when priority is not found
///
const bool setInputImage(const int priority, const Image<ColorRgb>& image, int64_t timeout_ms = -1, const bool& clearEffect = true);
///
/// Writes a single color to all the leds for the given time and priority
/// Registers comp color or provided type against muxer
/// Should be never used to update leds continuous
///
/// @param[in] priority The priority of the written color
/// @param[in] ledColor The color to write to the leds
/// @param[in] origin The setter
/// @param[in] timeout_ms The time the leds are set to the given color [ms]
///
void setColor(int priority, const ColorRgb &ledColor, const int timeout_ms, bool clearEffects = true);
///
/// Writes the given colors to all leds for the given time and priority
///
/// @param[in] priority The priority of the written colors
/// @param[in] ledColors The colors to write to the leds
/// @param[in] timeout_ms The time the leds are set to the given colors [ms]
/// @param[in] component The current component
/// @param[in] origin Who set it
/// @param[in] smoothCfg smoothing config id
///
void setColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms, bool clearEffects = true, hyperion::Components component=hyperion::COMP_INVALID, const QString origin="System", unsigned smoothCfg=SMOOTHING_MODE_DEFAULT);
///
/// Writes the given colors to all leds for the given time and priority
///
/// @param[in] priority The priority of the written colors
/// @param[in] ledColors The colors to write to the leds
/// @param[in] timeout_ms The time the leds are set to the given colors [ms]
///
void setImage(int priority, const Image<ColorRgb> & image, int duration_ms);
void setColor(int priority, const ColorRgb &ledColor, const int timeout_ms = -1, const QString& origin = "System" ,bool clearEffects = true);
///
/// Returns the list with unique adjustment identifiers
@@ -270,8 +317,9 @@ public slots:
/// lower priority channel (or off if no more channels are set)
///
/// @param[in] priority The priority channel
/// @return True on success else false (not found)
///
void clear(int priority);
const bool clear(int priority);
///
/// Clears all priority channels. This will switch the leds off until a new priority is written.
@@ -292,44 +340,18 @@ public slots:
int setEffect(const QString & effectName, const QJsonObject & args, int priority,
int timeout = -1, const QString & pythonScript = "", const QString & origin="System");
/// sets the methode how image is maped to leds
void setLedMappingType(int mappingType);
///
Hyperion::BonjourRegister getHyperionSessions();
/// Slot which is called, when state of hyperion has been changed
void hyperionStateChanged();
/// sets the methode how image is maped to leds at ImageProcessor
void setLedMappingType(const int& mappingType);
///
/// Set the video mode (2D/3D)
/// @param[in] mode The new video mode
///
void setVideoMode(VideoMode mode);
void setVideoMode(const VideoMode& mode);
public:
static Hyperion *_hyperion;
static ColorOrder createColorOrder(const QJsonObject & deviceConfig);
/**
* Construct the 'led-string' with the integration area definition per led and the color
* ordering of the RGB channels
* @param ledsConfig The configuration of the led areas
* @param deviceOrder The default RGB channel ordering
* @return The constructed ledstring
*/
static LedString createLedString(const QJsonValue & ledsConfig, const ColorOrder deviceOrder);
static LedString createLedStringClone(const QJsonValue & ledsConfig, const ColorOrder deviceOrder);
static MultiColorAdjustment * createLedColorsAdjustment(const unsigned ledCnt, const QJsonObject & colorAdjustmentConfig);
static ColorAdjustment * createColorAdjustment(const QJsonObject & adjustmentConfig);
static RgbTransform * createRgbTransform(const QJsonObject& colorConfig);
static RgbChannelAdjustment * createRgbChannelAdjustment(const QJsonObject & colorConfig, const QString channelName, const int defaultR, const int defaultG, const int defaultB);
static LinearColorSmoothing * createColorSmoothing(const QJsonObject & smoothingConfig, LedDevice* leddevice);
static MessageForwarder * createMessageForwarder(const QJsonObject & forwarderConfig);
static QSize getLedLayoutGridSize(const QJsonValue& ledsConfig);
signals:
/// Signal which is emitted when a priority channel is actively cleared
/// This signal will not be emitted when a priority channel time out
@@ -339,25 +361,67 @@ signals:
/// This signal will not be emitted when a priority channel time out
void allChannelsCleared();
///
/// @brief Emits whenever a user request a component state change, it's up the component to listen
/// and update the component state at the componentRegister
/// @param component The component from enum
/// @param enabled The new state of the component
///
void componentStateChanged(const hyperion::Components component, bool enabled);
void imageToLedsMappingChanged(int mappingType);
void emitImage(int priority, const Image<ColorRgb> & image, const int timeout_ms);
///
/// @brief Emits whenever the imageToLedsMapping has changed
/// @param mappingType The new mapping type
///
void imageToLedsMappingChanged(const int& mappingType);
///
/// @brief Emits whenever the visible priority delivers a image which is applied in update()
/// priorities with ledColors won't emit this signal
/// @param image The current image
///
void currentImage(const Image<ColorRgb> & image);
void closing();
/// Signal which is emitted, when a new json message should be forwarded
void forwardJsonMessage(QJsonObject);
/// Signal which is emitted, after the hyperionStateChanged has been processed with a emit count blocker (250ms interval)
void sendServerInfo();
/// Signal emitted when a 3D movie is detected
void videoMode(VideoMode mode);
///
/// @brief Is emitted from clients who request a videoMode change
///
void videoMode(const VideoMode& mode);
///
/// @brief Emits whenever new untransformed ledColos data is available, reflects the current visible device
/// @brief A new videoMode was requested (called from Daemon!)
///
void rawLedColors(const std::vector<ColorRgb>& ledValues);
void newVideoMode(const VideoMode& mode);
///
/// @brief Emits whenever a config part changed. SIGNAL PIPE helper for SettingsManager -> HyperionDaemon
/// @param type The settings type from enum
/// @param data The data as QJsonDocument
///
void settingsChanged(const settings::type& type, const QJsonDocument& data);
///
/// @brief Emits whenever the adjustments have been updated
///
void adjustmentChanged();
///
/// @brief Signal pipe from EffectEngine to external, emits when effect list has been updated
///
void effectListUpdated();
///
/// @brief systemImage from the parent HyperionDaemon SystemCapture
///
void systemImage(const Image<ColorRgb>& image);
///
/// @brief v4lImage from the parent HyperionDaemon V4lCapture
///
void v4lImage(const Image<ColorRgb> & image);
private slots:
///
@@ -366,13 +430,23 @@ private slots:
///
void update();
void currentBonjourRecordsChanged(const QList<BonjourRecord> &list);
void bonjourRecordResolved(const QHostInfo &hostInfo, int port);
void bonjourResolve();
/// check for configWriteable and modified changes, called by _fsWatcher or fallback _cTimer
void checkConfigState(QString cfile = NULL);
///
/// @brief Apply ComponentRegister emits for COMP_ALL. Enables/Disables core timers
/// @param comp The component
/// @param state The new state of the component
///
void updatedComponentState(const hyperion::Components comp, const bool state);
///
/// @brief Apply settings updates for LEDS and COLOR
/// @param type The type from enum
/// @param config The configuration
///
void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config);
private:
///
@@ -380,7 +454,16 @@ private:
///
/// @param[in] qjsonConfig The Json configuration
///
Hyperion(const QJsonObject& qjsonConfig, const QString configFile, const QString rootPath);
Hyperion(HyperionDaemon* daemon, const quint8& instance, const QString configFile, const QString rootPath);
/// The parent Hyperion Daemon
HyperionDaemon* _daemon;
/// Settings manager of this instance
SettingsManager* _settingsManager;
/// Register that holds component states
ComponentRegister _componentRegister;
/// The specifiation of the led frame construction and picture integration
LedString _ledString;
@@ -388,6 +471,9 @@ private:
/// specifiation of cloned leds
LedString _ledStringClone;
/// Image Processor
ImageProcessor* _imageProcessor;
std::vector<ColorOrder> _ledStringColorOrder;
/// The priority muxer
@@ -408,21 +494,14 @@ private:
// proto and json Message forwarder
MessageForwarder * _messageForwarder;
// json configuration
const QJsonObject& _qjsonConfig;
/// the name of config file
QString _configFile;
/// root path for all hyperion user data files
QString _rootPath;
/// The timer for handling priority channel timeouts
QTimer _timer;
QTimer _timerBonjourResolver;
/// buffer for leds (with adjustment)
std::vector<ColorRgb> _ledBuffer;
/// unique id per instance
QString _id;
/// Logger instance
Logger * _log;
@@ -430,32 +509,16 @@ private:
/// count of hardware leds
unsigned _hwLedCount;
ComponentRegister _componentRegister;
/// register of input sources and it's prio channel
PriorityRegister _priorityRegister;
/// flag indicates state for autoselection of input source
bool _sourceAutoSelectEnabled;
/// holds the current priority channel that is manualy selected
int _currentSourcePriority;
QByteArray _configHash;
QSize _ledGridSize;
int _ledMAppingType;
/// Store the previous compID for smarter update()
hyperion::Components _prevCompId;
BonjourServiceBrowser _bonjourBrowser;
BonjourServiceResolver _bonjourResolver;
BonjourRegister _hyperionSessions;
QString _bonjourCurrentServiceToResolve;
/// Observe filesystem changes (_configFile), if failed use Timer
QFileSystemWatcher _fsWatcher;
QTimer _cTimer;
QTimer* _cTimer;
/// holds the prev states of configWriteable and modified
bool _prevConfigMod = false;
@@ -465,9 +528,16 @@ private:
bool _configMod = false;
bool _configWrite = true;
/// timers to handle severinfo blocking
QTimer _fsi_timer;
QTimer _fsi_blockTimer;
/// Background effect instance, kept active to react on setting changes
BGEffectHandler* _BGEffectHandler;
/// Capture control for Daemon native capture
CaptureCont* _captureCont;
VideoMode _videoMode;
// lock Hyperion::update() for exec
bool _lockUpdate = false;
/// buffer for leds (with adjustment)
std::vector<ColorRgb> _ledBuffer;
/// buffer for leds (without adjustment)
std::vector<ColorRgb> _rawLedBuffer;
};

View File

@@ -6,14 +6,18 @@
#include <utils/Image.h>
// Hyperion includes
#include <hyperion/ImageProcessorFactory.h>
#include <hyperion/LedString.h>
#include <hyperion/ImageToLedsMap.h>
#include <utils/Logger.h>
// settings
#include <utils/settings.h>
// Black border includes
#include <blackborder/BlackBorderProcessor.h>
class Hyperion;
///
/// The ImageProcessor translates an RGB-image to RGB-values for the leds. The processing is
/// performed in two steps. First the average color per led-region is computed. Second a
@@ -24,14 +28,16 @@ class ImageProcessor : public QObject
Q_OBJECT
public:
///
/// Constructs an image-processor for translating an image to led-color values based on the
/// given led-string specification
/// @param[in] ledString LedString data
/// @param[in] hyperion Hyperion instance pointer
///
ImageProcessor(const LedString& ledString, Hyperion* hyperion);
~ImageProcessor();
///
/// Returns the number of attached leds
///
unsigned getLedCount() const;
///
/// Specifies the width and height of 'incomming' images. This will resize the buffer-image to
/// match the given size.
@@ -42,20 +48,39 @@ public:
///
void setSize(const unsigned width, const unsigned height);
///
/// @brief Update the led string (eg on settings change)
///
void setLedString(const LedString& ledString);
/// Returns starte of black border detector
bool blackBorderDetectorEnabled();
/// Returns starte of black border detector
int ledMappingType();
/// Returns the current _userMappingType, this may not be the current applied type!
const int & getUserLedMappingType() { return _userMappingType; };
/// Returns the current _mappingType
const int & ledMappingType() { return _mappingType; };
static int mappingTypeToInt(QString mappingType);
static QString mappingTypeToStr(int mappingType);
public slots:
/// Enable or disable the black border detector
void enableBlackBorderDetector(bool enable);
///
/// @brief Set the Hyperion::update() requestes led mapping type. This type is used in favour of type set with setLedMappingType.
/// If you don't want to force a mapType set this to -1 (user choice will be set)
/// @param mapType The new mapping type
///
void setHardLedMappingType(int mapType);
/// Enable or disable the black border detector
public slots:
/// Enable or disable the black border detector based on component
void setBlackbarDetectDisable(bool enable);
///
/// @brief Set the user requested led mapping.
/// The type set with setHardLedMappingType() will be used in favour to respect comp specific settings
/// @param mapType The new mapping type
///
void setLedMappingType(int mapType);
public:
@@ -101,7 +126,7 @@ public:
}
else
{
Warning(_log, "ImageProcessor::process called without image size 0");
Warning(_log, "ImageProcessor::process called with image size 0");
}
// return the computed colors
@@ -134,7 +159,7 @@ public:
}
else
{
Warning(_log, "ImageProcessor::process called without image size 0");
Warning(_log, "Called with image size 0");
}
}
@@ -150,18 +175,6 @@ public:
bool getScanParameters(size_t led, double & hscanBegin, double & hscanEnd, double & vscanBegin, double & vscanEnd) const;
private:
/// Friend declaration of the factory for creating ImageProcessor's
friend class ImageProcessorFactory;
///
/// Constructs an image-processor for translating an image to led-color values based on the
/// given led-string specification
///
/// @param[in] ledString The led-string specification
/// @param[in] blackborderThreshold The threshold which the blackborder detector should use
///
ImageProcessor(const LedString &ledString, const QJsonObject &blackborderConfig);
///
/// Performs black-border detection (if enabled) on the given image
///
@@ -172,7 +185,7 @@ private:
{
if (!_borderProcessor->enabled() && ( _imageToLeds->horizontalBorder()!=0 || _imageToLeds->verticalBorder()!=0 ))
{
Debug(Logger::getInstance("BLACKBORDER"), "disabled, reset border");
Debug(_log, "Reset border");
_borderProcessor->process(image);
delete _imageToLeds;
_imageToLeds = new hyperion::ImageToLedsMap(image.width(), image.height(), 0, 0, _ledString.leds());
@@ -180,8 +193,6 @@ private:
if(_borderProcessor->enabled() && _borderProcessor->process(image))
{
//Debug(Logger::getInstance("BLACKBORDER"), "BORDER SWITCH REQUIRED!!");
const hyperion::BlackBorder border = _borderProcessor->getCurrentBorder();
// Clean up the old mapping
@@ -203,10 +214,13 @@ private:
}
}
private slots:
void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config);
private:
Logger * _log;
/// The Led-string specification
const LedString _ledString;
LedString _ledString;
/// The processor for black border detection
hyperion::BlackBorderProcessor * _borderProcessor;
@@ -216,4 +230,11 @@ private:
/// Type of image 2 led mapping
int _mappingType;
/// Type of last requested user type
int _userMappingType;
/// Type of last requested hard type
int _hardMappingType;
/// Hyperion instance pointer
Hyperion* _hyperion;
};

View File

@@ -1,53 +0,0 @@
#pragma once
// STL includes
#include <memory>
// QT includes
#include <QJsonObject>
#include <hyperion/LedString.h>
// Forward class declaration
class ImageProcessor;
///
/// The ImageProcessor is a singleton factor for creating ImageProcessors that translate images to
/// led color values.
///
class ImageProcessorFactory
{
public:
///
/// Returns the 'singleton' instance (creates the singleton if it does not exist)
///
/// @return The singleton instance of the ImageProcessorFactory
///
static ImageProcessorFactory& getInstance();
public:
///
/// Initialises this factory with the given led-configuration
///
/// @param[in] ledString The led configuration
/// @param[in] blackborderConfig Contains the blackborder configuration
///
void init(const LedString& ledString, const QJsonObject &blackborderConfig, int mappingType);
///
/// Creates a new ImageProcessor. The onwership of the processor is transferred to the caller.
///
/// @return The newly created ImageProcessor
///
ImageProcessor* newImageProcessor() const;
private:
/// The Led-string specification
LedString _ledString;
/// Reference to the blackborder json configuration values
QJsonObject _blackborderConfig;
// image 2 led mapping type
int _mappingType;
};

View File

@@ -7,6 +7,7 @@
// hyperion-utils includes
#include <utils/Image.h>
#include <utils/Logger.h>
// hyperion includes
#include <hyperion/LedString.h>
@@ -58,7 +59,7 @@ namespace hyperion
const unsigned horizontalBorder() const { return _horizontalBorder; };
const unsigned verticalBorder() const { return _verticalBorder; };
///
/// Determines the mean-color for each led using the mapping the image given
/// at construction.
@@ -86,7 +87,12 @@ namespace hyperion
void getMeanLedColor(const Image<Pixel_T> & image, std::vector<ColorRgb> & ledColors) const
{
// Sanity check for the number of leds
assert(_colorsMap.size() == ledColors.size());
//assert(_colorsMap.size() == ledColors.size());
if(_colorsMap.size() != ledColors.size())
{
Debug(Logger::getInstance("HYPERION"), "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size());
return;
}
// Iterate each led and compute the mean
auto led = ledColors.begin();
@@ -96,7 +102,7 @@ namespace hyperion
*led = color;
}
}
///
/// Determines the mean-color for each led using the mapping the image given
/// at construction.
@@ -124,7 +130,13 @@ namespace hyperion
void getUniLedColor(const Image<Pixel_T> & image, std::vector<ColorRgb> & ledColors) const
{
// Sanity check for the number of leds
assert(_colorsMap.size() == ledColors.size());
// assert(_colorsMap.size() == ledColors.size());
if(_colorsMap.size() != ledColors.size())
{
Debug(Logger::getInstance("HYPERION"), "ImageToLedsMap: colorsMap.size != ledColors.size -> %d != %d", _colorsMap.size(), ledColors.size());
return;
}
// calculate uni color
const ColorRgb color = calcMeanColor(image);
@@ -136,11 +148,11 @@ namespace hyperion
const unsigned _width;
/// The height of the indexed image
const unsigned _height;
const unsigned _horizontalBorder;
const unsigned _verticalBorder;
/// The absolute indices into the image for each led
std::vector<std::vector<unsigned>> _colorsMap;

View File

@@ -10,31 +10,45 @@
#include <QList>
#include <QStringList>
#include <QHostAddress>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
// Utils includes
#include <utils/ColorRgb.h>
class MessageForwarder
#include <utils/settings.h>
#include <utils/Logger.h>
class Hyperion;
class MessageForwarder : public QObject
{
Q_OBJECT
public:
struct JsonSlaveAddress {
QHostAddress addr;
quint16 port;
};
MessageForwarder();
MessageForwarder(Hyperion* hyperion, const QJsonDocument & config);
~MessageForwarder();
void addJsonSlave(QString slave);
void addProtoSlave(QString slave);
bool protoForwardingEnabled();
bool jsonForwardingEnabled();
bool forwardingEnabled() { return jsonForwardingEnabled() || protoForwardingEnabled(); };
QStringList getProtoSlaves();
QList<MessageForwarder::JsonSlaveAddress> getJsonSlaves();
QStringList getProtoSlaves() const { return _protoSlaves; };
QStringList getJsonSlaves() const { return _jsonSlaves; };
private slots:
///
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
/// @param type settingyType from enum
/// @param config configuration object
///
void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config);
private:
QStringList _protoSlaves;
QList<MessageForwarder::JsonSlaveAddress> _jsonSlaves;
Hyperion* _hyperion;
Logger* _log;
QStringList _protoSlaves;
QStringList _jsonSlaves;
};

View File

@@ -0,0 +1,69 @@
#pragma once
// STL includes
#include <vector>
#include <QStringList>
#include <QString>
// Hyperion includes
#include <utils/ColorRgb.h>
#include <hyperion/ColorAdjustment.h>
///
/// The LedColorTransform is responsible for performing color transformation from 'raw' colors
/// received as input to colors mapped to match the color-properties of the leds.
///
class MultiColorAdjustment
{
public:
MultiColorAdjustment(const unsigned ledCnt);
~MultiColorAdjustment();
/**
* Adds a new ColorAdjustment to this MultiColorTransform
*
* @param adjustment The new ColorAdjustment (ownership is transfered)
*/
void addAdjustment(ColorAdjustment * adjustment);
void setAdjustmentForLed(const QString& id, const unsigned startLed, unsigned endLed);
bool verifyAdjustments() const;
void setBacklightEnabled(bool enable);
///
/// Returns the identifier of all the unique ColorAdjustment
///
/// @return The list with unique id's of the ColorAdjustment
const QStringList & getAdjustmentIds();
///
/// Returns the pointer to the ColorAdjustment with the given id
///
/// @param id The identifier of the ColorAdjustment
///
/// @return The ColorAdjustment with the given id (or nullptr if it does not exist)
///
ColorAdjustment* getAdjustment(const QString& id);
///
/// Performs the color adjustment from raw-color to led-color
///
/// @param ledColors The list with raw colors
///
void applyAdjustment(std::vector<ColorRgb>& ledColors);
private:
/// List with transform ids
QStringList _adjustmentIds;
/// List with unique ColorTransforms
std::vector<ColorAdjustment*> _adjustment;
/// List with a pointer to the ColorAdjustment for each individual led
std::vector<ColorAdjustment*> _ledAdjustments;
// logger instance
Logger * _log;
};

View File

@@ -7,23 +7,25 @@
// QT includes
#include <QMap>
#include <QObject>
#include <QTimer>
#include <QMap>
#include <QVector>
// Utils includes
#include <utils/ColorRgb.h>
#include <utils/Image.h>
#include <utils/Components.h>
// global defines
#define SMOOTHING_MODE_DEFAULT 0
#define SMOOTHING_MODE_PAUSE 1
class QTimer;
class Logger;
///
/// The PriorityMuxer handles the priority channels. Led values input is written to the priority map
/// The PriorityMuxer handles the priority channels. Led values input/ images are written to the priority map
/// and the muxer keeps track of all active priorities. The current priority can be queried and per
/// priority the led colors.
/// priority the led colors. Handles also manual/auto selection mode, provides a lot of signals to hook into priority related events
///
class PriorityMuxer : public QObject
{
@@ -36,17 +38,20 @@ public:
{
/// The priority of this channel
int priority;
/// The absolute timeout of the channel
int64_t timeoutTime_ms;
/// The colors for each led of the channel
std::vector<ColorRgb> ledColors;
/// The raw Image (size should be preprocessed!)
Image<ColorRgb> image;
/// The component
hyperion::Components componentId;
/// Who set it
QString origin;
/// id fo smoothing config
/// id of smoothing config
unsigned smooth_cfg;
/// specific owner description
QString owner;
};
/// The lowest possible priority, which is used when no priority channels are active
@@ -65,6 +70,38 @@ public:
///
~PriorityMuxer();
///
/// @brief Start/Stop the PriorityMuxer update timer; On disabled no priority and timeout updates will be performend
/// @param enable The new state
///
void setEnable(const bool& enable);
/// @brief Enable or disable auto source selection
/// @param enable True if it should be enabled else false
/// @param update True to update _currentPriority - INTERNAL usage.
/// @return True if changed has been applied, false if the state is unchanged
///
bool setSourceAutoSelectEnabled(const bool& enabel, const bool& update = true);
///
/// @brief Get the state of source auto selection
/// @return True if enabled, else false
///
bool isSourceAutoSelectEnabled() const { return _sourceAutoSelectEnabled; };
///
/// @brief Overwrite current lowest piority with manual selection; On success disables aito selection
/// @param priority The
/// @return True on success, false if priority not found
///
bool setPriority(const uint8_t priority);
///
/// @brief Update all ledColos with min length of >= 1 to fit the new led length
/// @param[in] ledCount The count of leds
///
void updateLedColorsLength(const int& ledCount);
///
/// Returns the current priority
///
@@ -87,69 +124,134 @@ public:
QList<int> getPriorities() const;
///
/// Returns the information of a specified priority channel
/// Returns the information of a specified priority channel.
/// If a priority is no longer available the _lowestPriorityInfo (255) is returned
///
/// @param priority The priority channel
///
/// @return The information for the specified priority channel
///
/// @throws std::runtime_error if the priority channel does not exist
///
const InputInfo& getInputInfo(const int priority) const;
const InputInfo getInputInfo(const int priority) const;
///
/// Sets/Updates the data for a priority channel
/// @brief Register a new input by priority, the priority is not active (timeout -100 isn't muxer recognized) until you start to update the data with setInput()
/// A repeated call to update the base data of a known priority won't overwrite their current timeout
/// @param[in] priority The priority of the channel
/// @param[in] component The component of the channel
/// @param[in] origin Who set the channel (CustomString@IP)
/// @param[in] owner Speicifc owner string, might be empty
/// @param[in] smooth_cfg The smooth id to use
///
/// @param[in] priority The priority of the channel
/// @param[in] ledColors The led colors of the priority channel
/// @param[in] timeoutTime_ms The absolute timeout time of the channel
/// @param[in] component The component of the channel
/// @param[in] origin Who set the channel
///
void setInput(const int priority, const std::vector<ColorRgb>& ledColors, const int64_t timeoutTime_ms=-1, hyperion::Components component=hyperion::COMP_INVALID, const QString origin="System", unsigned smooth_cfg=SMOOTHING_MODE_DEFAULT);
void registerInput(const int priority, const hyperion::Components& component, const QString& origin = "System", const QString& owner = "", unsigned smooth_cfg = SMOOTHING_MODE_DEFAULT);
///
/// Clears the specified priority channel
/// @brief Update the current color of a priority (prev registered with registerInput())
/// @param priority The priority to update
/// @param ledColors The colors
/// @param timeout_ms The new timeout (defaults to -1 endless)
/// @return True on success, false when priority is not found
///
const bool setInput(const int priority, const std::vector<ColorRgb>& ledColors, int64_t timeout_ms = -1);
///
/// @brief Update the current image of a priority (prev registered with registerInput())
/// @param priority The priority to update
/// @param image The new image
/// @param timeout_ms The new timeout (defaults to -1 endless)
/// @return True on success, false when priority is not found
///
const bool setInputImage(const int priority, const Image<ColorRgb>& image, int64_t timeout_ms = -1);
///
/// Clears the specified priority channel and update _currentPriority on success
///
/// @param[in] priority The priority of the channel to clear
/// @return True if priority has been cleared else false (not found)
///
void clearInput(const int priority);
const bool clearInput(const uint8_t priority);
///
/// Clears all priority channels
///
void clearAll(bool forceClearAll=false);
signals:
///
/// @brief Signal which emits when a effect or color with timeout > -1 is running, once per second
///
void timeRunner();
///
/// @brief A priority has been added (registerInput()) or deleted, method clear or timeout clear
/// @param priority The priority which has changed
/// @param state If true it was added else it was removed!
///
void priorityChanged(const quint8& priority, const bool& state);
///
/// @brief Emits whenever the visible priority has changed
/// @param priority The new visible prioritiy
///
void visiblePriorityChanged(const quint8& priority);
///
/// @brief Emits whenever a priority changes active state
/// @param priority The priority who changed the active state
/// @param state The new state, state true = active else false
///
void activeStateChanged(const quint8& priority, const bool& state);
///
/// @brief Emits whenever the auto selection state has been changed
/// @param state The new state of auto selection; True enabled else false
///
void autoSelectChanged(const bool& state);
///
/// @brief Emits whenever something changes which influences the priorities listing
/// Emits also in 1s interval when a COLOR or EFFECT is running with a timeout > -1
///
void prioritiesChanged(void);
///
/// internal used signal to resolve treading issues with timer
///
void signalTimeTrigger();
private slots:
///
/// Slot which is called to adapt to 1s interval for signal timeRunner() / prioritiesChanged()
///
void timeTrigger();
///
/// Updates the current time. Channels with a configured time out will be checked and cleared if
/// required.
///
/// @param[in] now The current time
///
void setCurrentTime(const int64_t& now);
signals:
///
/// Signal which is called, when a effect or color with timeout is running, once per second
///
void timerunner();
private slots:
///
/// Slots which is called to adapt to 1s interval for signal timerunner()
///
void emitReq();
void setCurrentTime(void);
private:
/// Logger instance
Logger* _log;
/// The current priority (lowest value in _activeInputs)
int _currentPriority;
/// The manual select priority set with setPriority
int _manualSelectedPriority;
/// The mapping from priority channel to led-information
QMap<int, InputInfo> _activeInputs;
/// The information of the lowest priority channel
InputInfo _lowestPriorityInfo;
QTimer _timer;
QTimer _blockTimer;
// Reflect the state of auto select
bool _sourceAutoSelectEnabled;
// Timer to update Muxer times independent
QTimer* _updateTimer;
QTimer* _timer;
QTimer* _blockTimer;
};

View File

@@ -0,0 +1,72 @@
#pragma once
#include <utils/Logger.h>
#include <utils/settings.h>
// qt incl
#include <QJsonObject>
class SettingsTable;
class Hyperion;
///
/// @brief Manage the settings read write from/to database, on settings changed will emit a signal to update components accordingly
///
class SettingsManager : public QObject
{
Q_OBJECT
public:
///
/// @brief Construct a settings manager and assign a hyperion instance
/// @params hyperion The parent hyperion instance
/// @params instance Instance number of Hyperion
///
SettingsManager(Hyperion* hyperion, const quint8& instance, const QString& configFile);
///
/// @brief Construct a settings manager for HyperionDaemon
///
SettingsManager(const quint8& instance, const QString& configFile);
~SettingsManager();
///
/// @brief Save a complete json config
/// @param config The entire config object
/// @param correct If true will correct json against schema before save
/// @return True on success else false
///
const bool saveSettings(QJsonObject config, const bool& correct = false);
///
/// @brief get a single setting json from database
/// @param type The settings::type from enum
/// @return The requested json data as QJsonDocument
///
const QJsonDocument getSetting(const settings::type& type);
///
/// @brief get the full settings object of this instance (with global settings)
/// @return The requested json
///
const QJsonObject & getSettings() { return _qconfig; };
signals:
///
/// @brief Emits whenever a config part changed. Comparison of database and new data to prevent false positive
/// @param type The settings type from enum
/// @param data The data as QJsonDocument
///
void settingsChanged(const settings::type& type, const QJsonDocument& data);
private:
/// Hyperion instance
Hyperion* _hyperion;
/// Logger instance
Logger* _log;
/// instance of database table interface
SettingsTable* _sTable;
/// the schema
static QJsonObject schemaJson;
/// the current config of this instance
QJsonObject _qconfig;
};

View File

@@ -1,14 +1,20 @@
#pragma once
// Qt includes
#include <QTcpServer>
#include <QSet>
// Hyperion includes
#include <hyperion/Hyperion.h>
#include <utils/Components.h>
#include <utils/Logger.h>
#include <utils/settings.h>
class Hyperion;
class QTcpServer;
class QTcpSocket;
class JsonClientConnection;
class BonjourServiceRegister;
class ComponentRegister;
class NetOrigin;
///
/// This class creates a TCP server which accepts connections wich can then send
@@ -22,10 +28,9 @@ class JsonServer : public QObject
public:
///
/// JsonServer constructor
/// @param hyperion Hyperion instance
/// @param port port number on which to start listening for connections
/// @param The configuration
///
JsonServer(uint16_t port = 19444);
JsonServer(const QJsonDocument& config);
~JsonServer();
///
@@ -59,9 +64,16 @@ public slots:
///
void sendMessage(const QJsonObject & message, QTcpSocket * socket);
///
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
/// @param type settingyType from enum
/// @param config configuration object
///
void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config);
private:
/// The TCP server object
QTcpServer _server;
QTcpServer * _server;
/// Link to Hyperion to get config state emiter
Hyperion * _hyperion;
@@ -72,6 +84,16 @@ private:
/// the logger instance
Logger * _log;
/// Flag if forwarder is enabled
bool _forwarder_enabled = true;
/// Component Register pointer
ComponentRegister* _componentRegister;
NetOrigin* _netOrigin;
/// port
uint16_t _port = 0;
BonjourServiceRegister * _serviceRegister = nullptr;
void start();
void stop();
};

View File

@@ -55,13 +55,19 @@ public:
///
virtual int open();
///
/// @brief Get color order of device
/// @return The color order
///
const QString & getColorOrder() { return _colorOrder; };
static int addToDeviceMap(QString name, LedDeviceCreateFuncType funcPtr);
static const LedDeviceRegistry& getDeviceMap();
static void setActiveDevice(QString dev);
static QString activeDevice() { return _activeDevice; }
void setActiveDevice(QString dev);
const QString & getActiveDevice() { return _activeDevice; };
static QJsonObject getLedDeviceSchemas();
static void setLedCount(int ledCount);
static int getLedCount() { return _ledCount; }
void setLedCount(int ledCount);
int getLedCount() { return _ledCount; }
void setEnable(bool enable);
bool enabled() { return _enabled; };
@@ -95,12 +101,12 @@ protected:
bool _deviceReady;
static QString _activeDevice;
QString _activeDevice;
static LedDeviceRegistry _ledDeviceMap;
static int _ledCount;
static int _ledRGBCount;
static int _ledRGBWCount;
int _ledCount;
int _ledRGBCount;
int _ledRGBWCount;
/// Timer object which makes sure that led data is written at a minimum rate
/// e.g. Adalight device will switch off when it does not receive data at least every 15 seconds
@@ -116,4 +122,5 @@ private:
std::vector<ColorRgb> _ledValues;
bool _componentRegistered;
bool _enabled;
QString _colorOrder;
};

View File

@@ -4,7 +4,6 @@
// Leddevice includes
#include <leddevice/LedDevice.h>
///
/// The LedDeviceFactory is responsible for constructing 'LedDevices'
///
@@ -20,5 +19,5 @@ public:
/// @return The constructed LedDevice or nullptr if configuration is invalid. The ownership of
/// the constructed LedDevice is tranferred to the caller
///
static LedDevice * construct(const QJsonObject & deviceConfig, const int ledCount);
static LedDevice * construct(const QJsonObject & deviceConfig);
};

View File

@@ -4,23 +4,29 @@
#include <cstdint>
// Qt includes
#include <QTcpServer>
#include <QSet>
#include <QList>
#include <QStringList>
// Hyperion includes
#include <hyperion/Hyperion.h>
#include <QJsonDocument>
// hyperion includes
#include <utils/Image.h>
#include <utils/ColorRgb.h>
#include <utils/VideoMode.h>
#include <utils/Logger.h>
#include <utils/Components.h>
// settings
#include <utils/settings.h>
// forward decl
class ProtoClientConnection;
class ProtoConnection;
class QTcpServer;
class Hyperion;
class BonjourServiceRegister;
class ComponentRegister;
class NetOrigin;
namespace proto {
class HyperionRequest;
@@ -38,10 +44,9 @@ class ProtoServer : public QObject
public:
///
/// ProtoServer constructor
/// @param hyperion Hyperion instance
/// @param port port number on which to start listening for connections
/// @param config the configuration
///
ProtoServer(uint16_t port = 19445);
ProtoServer(const QJsonDocument& config);
~ProtoServer();
///
@@ -53,6 +58,13 @@ public slots:
void sendImageToProtoSlaves(int priority, const Image<ColorRgb> & image, int duration_ms);
void componentStateChanged(const hyperion::Components component, bool enable);
///
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
/// @param type settingyType from enum
/// @param config configuration object
///
void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config);
signals:
///
/// Forwarding videoMode
@@ -78,7 +90,7 @@ private:
Hyperion * _hyperion;
/// The TCP server object
QTcpServer _server;
QTcpServer * _server;
/// List with open connections
QSet<ProtoClientConnection *> _openConnections;
@@ -90,6 +102,22 @@ private:
/// Logger instance
Logger * _log;
/// Component Register
ComponentRegister* _componentRegister;
/// Network Origin Check
NetOrigin* _netOrigin;
/// Service register
BonjourServiceRegister * _serviceRegister = nullptr;
/// flag if forwarder is enabled
bool _forwarder_enabled;
uint16_t _port = 0;
/// Start server
void start();
/// Stop server
void stop();
};

View File

@@ -0,0 +1,13 @@
#pragma once
///
/// @brief Handle the PythonInit, module registers and DeInit
///
class PythonInit
{
private:
friend class HyperionDaemon;
PythonInit();
~PythonInit();
};

View File

@@ -0,0 +1,15 @@
#pragma once
#undef slots
#include <Python.h>
#define slots
// decl
extern PyThreadState* mainThreadState;
// py path seperator
#ifdef TARGET_WINDOWS
#define PY_PATH_SEP ";";
#else // not windows
#define PY_PATH_SEP ":";
#endif

View File

@@ -4,16 +4,22 @@
#include <cstdint>
// Qt includes
#include <QUdpSocket>
#include <QSet>
#include <QHostAddress>
#include <QJsonDocument>
// Hyperion includes
#include <hyperion/Hyperion.h>
#include <utils/Logger.h>
#include <utils/Components.h>
// settings
#include <utils/settings.h>
class Hyperion;
class UDPClientConnection;
class BonjourServiceRegister;
class QUdpSocket;
class NetOrigin;
///
/// This class creates a UDP server which accepts connections from boblight clients.
@@ -28,26 +34,25 @@ public:
/// @param hyperion Hyperion instance
/// @param port port number on which to start listening for connections
///
UDPListener(const int priority, const int timeout, const QString& address, quint16 listenPort, bool shared);
UDPListener(const QJsonDocument& config);
~UDPListener();
///
/// @return the port number on which this UDP listens for incoming connections
///
uint16_t getPort() const;
///
/// @return true if server is active (bind to a port)
///
bool active() { return _isActive; };
bool componentState() { return active(); };
public slots:
///
/// bind server to network
///
void start();
///
/// close server
///
@@ -55,8 +60,12 @@ public slots:
void componentStateChanged(const hyperion::Components component, bool enable);
signals:
void statusChanged(bool isActive);
///
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
/// @param type settingyType from enum
/// @param config configuration object
///
void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config);
private slots:
///
@@ -83,12 +92,18 @@ private:
/// Logger instance
Logger * _log;
/// Bonjour Service Register
BonjourServiceRegister* _bonjourService = nullptr;
/// state of connection
bool _isActive;
/// address to bind
QHostAddress _listenAddress;
quint16 _listenPort;
uint16_t _listenPort;
QAbstractSocket::BindFlag _bondage;
/// Check Network Origin
NetOrigin* _netOrigin;
};

View File

@@ -3,12 +3,14 @@
namespace hyperion
{
/**
* Enumeration of components in Hyperion.
*/
enum Components
{
COMP_INVALID,
COMP_ALL,
COMP_SMOOTHING,
COMP_BLACKBORDER,
COMP_FORWARDER,
@@ -17,6 +19,7 @@ enum Components
COMP_GRABBER,
COMP_V4L,
COMP_COLOR,
COMP_IMAGE,
COMP_EFFECT,
COMP_PROTOSERVER,
COMP_LEDDEVICE
@@ -26,6 +29,7 @@ inline const char* componentToString(Components c)
{
switch (c)
{
case COMP_ALL: return "Hyperion";
case COMP_SMOOTHING: return "Smoothing";
case COMP_BLACKBORDER: return "Blackborder detector";
case COMP_FORWARDER: return "Json/Proto forwarder";
@@ -35,6 +39,7 @@ inline const char* componentToString(Components c)
case COMP_V4L: return "V4L capture device";
case COMP_COLOR: return "Solid color";
case COMP_EFFECT: return "Effect";
case COMP_IMAGE: return "Image";
case COMP_PROTOSERVER: return "Proto Server";
case COMP_LEDDEVICE: return "LED device";
default: return "";
@@ -45,6 +50,7 @@ inline const char* componentToIdString(Components c)
{
switch (c)
{
case COMP_ALL: return "ALL";
case COMP_SMOOTHING: return "SMOOTHING";
case COMP_BLACKBORDER: return "BLACKBORDER";
case COMP_FORWARDER: return "FORWARDER";
@@ -54,6 +60,7 @@ inline const char* componentToIdString(Components c)
case COMP_V4L: return "V4L";
case COMP_COLOR: return "COLOR";
case COMP_EFFECT: return "EFFECT";
case COMP_IMAGE: return "IMAGE";
case COMP_PROTOSERVER: return "PROTOSERVER";
case COMP_LEDDEVICE: return "LEDDEVICE";
default: return "";
@@ -63,6 +70,7 @@ inline const char* componentToIdString(Components c)
inline Components stringToComponent(QString component)
{
component = component.toUpper();
if (component == "ALL") return COMP_ALL;
if (component == "SMOOTHING") return COMP_SMOOTHING;
if (component == "BLACKBORDER") return COMP_BLACKBORDER;
if (component == "FORWARDER") return COMP_FORWARDER;
@@ -72,6 +80,7 @@ inline Components stringToComponent(QString component)
if (component == "V4L") return COMP_V4L;
if (component == "COLOR") return COMP_COLOR;
if (component == "EFFECT") return COMP_EFFECT;
if (component == "IMAGE") return COMP_IMAGE;
if (component == "PROTOSERVER") return COMP_PROTOSERVER;
if (component == "LEDDEVICE") return COMP_LEDDEVICE;

View File

@@ -13,6 +13,11 @@ namespace FileUtils {
QString getBaseName( QString sourceFile);
QString getDirName( QString sourceFile);
///
/// @brief remove directory recursive given by path
/// @param[in] path Path to directory
bool removeDir(const QString& path, Logger* log);
///
/// @brief check if the file exists
/// @param[in] path The file path to check
@@ -45,9 +50,10 @@ QString getDirName( QString sourceFile);
/// @brief delete a file by given path
/// @param[in] path The file path to delete
/// @param[in] log The logger of the caller to print errors
/// @param[in] ignError Ignore errors during file delete (no log output)
/// @return true on success else false
///
bool removeFile(const QString& path, Logger* log);
bool removeFile(const QString& path, Logger* log, bool ignError=false);
///
/// @brief Convert a path that may contain special placeholders

View File

@@ -71,6 +71,38 @@ public:
memcpy(_pixels, other._pixels, other._width * other._height * sizeof(Pixel_T));
}
// Define assignment operator in terms of the copy constructor
// More to read: https://stackoverflow.com/questions/255612/dynamically-allocating-an-array-of-objects?answertab=active#tab-top
Image& operator=(Image rhs)
{
rhs.swap(*this);
return *this;
}
void swap(Image& s) noexcept
{
using std::swap;
swap(this->_width, s._width);
swap(this->_height, s._height);
swap(this->_pixels, s._pixels);
swap(this->_endOfPixels, s._endOfPixels);
}
// C++11
Image(Image&& src) noexcept
: _width(0)
, _height(0)
, _pixels(NULL)
, _endOfPixels(NULL)
{
src.swap(*this);
}
Image& operator=(Image&& src) noexcept
{
src.swap(*this);
return *this;
}
///
/// Destructor
///

View File

@@ -1,280 +0,0 @@
#pragma once
// hyperion includes
#include <utils/Logger.h>
#include <utils/jsonschema/QJsonSchemaChecker.h>
#include <utils/Components.h>
#include <hyperion/Hyperion.h>
// qt includess
#include <QJsonObject>
#include <QMutex>
#include <QString>
// createEffect helper
struct find_schema: std::unary_function<EffectSchema, bool>
{
QString pyFile;
find_schema(QString pyFile):pyFile(pyFile) { }
bool operator()(EffectSchema const& schema) const
{
return schema.pyFile == pyFile;
}
};
// deleteEffect helper
struct find_effect: std::unary_function<EffectDefinition, bool>
{
QString effectName;
find_effect(QString effectName) :effectName(effectName) { }
bool operator()(EffectDefinition const& effectDefinition) const
{
return effectDefinition.name == effectName;
}
};
class ImageProcessor;
class JsonProcessor : public QObject
{
Q_OBJECT
public:
///
/// Constructor
///
/// @param peerAddress provide the Address of the peer
/// @param log The Logger class of the creator
/// @param parent Parent QObject
/// @param noListener if true, this instance won't listen for hyperion push events
///
JsonProcessor(QString peerAddress, Logger* log, QObject* parent, bool noListener = false);
///
/// Handle an incoming JSON message
///
/// @param message the incoming message as string
///
void handleMessage(const QString & message);
///
/// send a forced serverinfo to a client
///
void forceServerInfo();
public slots:
///
/// @brief is called whenever the current Hyperion instance pushes new led raw values (if enabled)
/// @param ledColors The current ledColors
///
void streamLedcolorsUpdate(const std::vector<ColorRgb>& ledColors);
/// push images whenever hyperion emits (if enabled)
void setImage(int priority, const Image<ColorRgb> & image, int duration_ms);
/// process and push new log messages from logger (if enabled)
void incommingLogMessage(Logger::T_LOG_MESSAGE);
signals:
///
/// Signal which is emitted when a sendSuccessReply() has been executed
///
void pushReq();
///
/// Signal emits with the reply message provided with handleMessage()
///
void callbackMessage(QJsonObject);
///
/// Signal emits whenever a jsonmessage should be forwarded
///
void forwardJsonMessage(QJsonObject);
private:
/// The peer address of the client
QString _peerAddress;
/// Log instance
Logger* _log;
/// Hyperion instance
Hyperion* _hyperion;
/// The processor for translating images to led-values
ImageProcessor * _imageProcessor;
/// holds the state before off state
static std::map<hyperion::Components, bool> _componentsPrevState;
/// returns if hyperion is on or off
inline bool hyperionIsActive() { return JsonProcessor::_componentsPrevState.empty(); };
// streaming buffers
QJsonObject _streaming_leds_reply;
QJsonObject _streaming_image_reply;
QJsonObject _streaming_logging_reply;
bool _ledcolorsLedsActive = false;
/// flag to determine state of log streaming
bool _streaming_logging_activated;
/// mutex to determine state of image streaming
QMutex _image_stream_mutex;
/// mutex to determine state of led color streaming
QMutex _led_stream_mutex;
/// timeout for live video refresh
volatile qint64 _image_stream_timeout;
/// timeout for led color refresh
volatile qint64 _led_stream_timeout;
///
/// Handle an incoming JSON Color message
///
/// @param message the incoming message
///
void handleColorCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON Image message
///
/// @param message the incoming message
///
void handleImageCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON Effect message
///
/// @param message the incoming message
///
void handleEffectCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON Effect message (Write JSON Effect)
///
/// @param message the incoming message
///
void handleCreateEffectCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON Effect message (Delete JSON Effect)
///
/// @param message the incoming message
///
void handleDeleteEffectCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON System info message
///
/// @param message the incoming message
///
void handleSysInfoCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON Server info message
///
/// @param message the incoming message
///
void handleServerInfoCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON Clear message
///
/// @param message the incoming message
///
void handleClearCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON Clearall message
///
/// @param message the incoming message
///
void handleClearallCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON Adjustment message
///
/// @param message the incoming message
///
void handleAdjustmentCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON SourceSelect message
///
/// @param message the incoming message
///
void handleSourceSelectCommand(const QJsonObject & message, const QString &command, const int tan);
/// Handle an incoming JSON GetConfig message and check subcommand
///
/// @param message the incoming message
///
void handleConfigCommand(const QJsonObject & message, const QString &command, const int tan);
/// Handle an incoming JSON GetConfig message from handleConfigCommand()
///
/// @param message the incoming message
///
void handleSchemaGetCommand(const QJsonObject & message, const QString &command, const int tan);
/// Handle an incoming JSON GetConfig message from handleConfigCommand()
///
/// @param message the incoming message
///
void handleConfigGetCommand(const QJsonObject & message, const QString &command, const int tan);
/// Handle an incoming JSON SetConfig message from handleConfigCommand()
///
/// @param message the incoming message
///
void handleConfigSetCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON Component State message
///
/// @param message the incoming message
///
void handleComponentStateCommand(const QJsonObject & message, const QString &command, const int tan);
/// Handle an incoming JSON Led Colors message
///
/// @param message the incoming message
///
void handleLedColorsCommand(const QJsonObject & message, const QString &command, const int tan);
/// Handle an incoming JSON Logging message
///
/// @param message the incoming message
///
void handleLoggingCommand(const QJsonObject & message, const QString &command, const int tan);
/// Handle an incoming JSON Proccessing message
///
/// @param message the incoming message
///
void handleProcessingCommand(const QJsonObject & message, const QString &command, const int tan);
/// Handle an incoming JSON VideoMode message
///
/// @param message the incoming message
///
void handleVideoModeCommand(const QJsonObject & message, const QString &command, const int tan);
///
/// Handle an incoming JSON message of unknown type
///
void handleNotImplemented();
///
/// Send a standard reply indicating success
///
void sendSuccessReply(const QString &command="", const int tan=0);
///
/// Send an error message back to the client
///
/// @param error String describing the error
///
void sendErrorReply(const QString & error, const QString &command="", const int tan=0);
};

View File

@@ -26,7 +26,7 @@ namespace JsonUtils{
bool readSchema(const QString& path, QJsonObject& obj, Logger* log);
///
/// @brief parse a json QString and get the result on success
/// @brief parse a json QString and get a QJsonObject. Overloaded funtion
/// @param[in] path The file path/name just used for log messages
/// @param[in] data Data to parse
/// @param[out] obj Retuns the parsed QJsonObject
@@ -35,6 +35,26 @@ namespace JsonUtils{
///
bool parse(const QString& path, const QString& data, QJsonObject& obj, Logger* log);
///
/// @brief parse a json QString and get a QJsonArray. Overloaded function
/// @param[in] path The file path/name just used for log messages
/// @param[in] data Data to parse
/// @param[out] arr Retuns the parsed QJsonArray
/// @param[in] log The logger of the caller to print errors
/// @return true on success else false
///
bool parse(const QString& path, const QString& data, QJsonArray& arr, Logger* log);
///
/// @brief parse a json QString and get a QJsonDocument
/// @param[in] path The file path/name just used for log messages
/// @param[in] data Data to parse
/// @param[out] doc Retuns the parsed QJsonDocument
/// @param[in] log The logger of the caller to print errors
/// @return true on success else false
///
bool parse(const QString& path, const QString& data, QJsonDocument& doc, Logger* log);
///
/// @brief Validate json data against a schema
/// @param[in] file The path/name of json file just used for log messages
@@ -45,6 +65,16 @@ namespace JsonUtils{
///
bool validate(const QString& file, const QJsonObject& json, const QString& schemaPath, Logger* log);
///
/// @brief Validate json data against a schema
/// @param[in] file The path/name of json file just used for log messages
/// @param[in] json The json data
/// @param[in] schema The schema object
/// @param[in] log The logger of the caller to print errors
/// @return true on success else false
///
bool validate(const QString& file, const QJsonObject& json, const QJsonObject& schema, Logger* log);
///
/// @brief Write json data to file
/// @param[in] filenameThe file path to write

320
include/utils/hyperion.h Normal file
View File

@@ -0,0 +1,320 @@
#pragma once
#include <hyperion/ColorAdjustment.h>
#include <hyperion/MultiColorAdjustment.h>
#include <hyperion/LedString.h>
// fg effect
#include <hyperion/Hyperion.h>
///
/// @brief Provide utility methods for Hyperion class
///
namespace hyperion {
void handleInitialEffect(Hyperion* hyperion, const QJsonObject& FGEffectConfig)
{
#define FGCONFIG_ARRAY fgColorConfig.toArray()
const int FG_PRIORITY = 0;
const int DURATION_INFINITY = 0;
// initial foreground effect/color
if (FGEffectConfig["enable"].toBool(true))
{
const QString fgTypeConfig = FGEffectConfig["type"].toString("effect");
const QString fgEffectConfig = FGEffectConfig["effect"].toString("Rainbow swirl fast");
const QJsonValue fgColorConfig = FGEffectConfig["color"];
int default_fg_duration_ms = 3000;
int fg_duration_ms = FGEffectConfig["duration_ms"].toInt(default_fg_duration_ms);
if (fg_duration_ms == DURATION_INFINITY)
{
fg_duration_ms = default_fg_duration_ms;
Warning(Logger::getInstance("HYPERION"), "foreground effect duration 'infinity' is forbidden, set to default value %d ms",default_fg_duration_ms);
}
if ( fgTypeConfig.contains("color") )
{
ColorRgb fg_color = {
(uint8_t)FGCONFIG_ARRAY.at(0).toInt(0),
(uint8_t)FGCONFIG_ARRAY.at(1).toInt(0),
(uint8_t)FGCONFIG_ARRAY.at(2).toInt(0)
};
hyperion->setColor(FG_PRIORITY, fg_color, fg_duration_ms);
Info(Logger::getInstance("HYPERION"),"Inital foreground color set (%d %d %d)",fg_color.red,fg_color.green,fg_color.blue);
}
else
{
int result = hyperion->setEffect(fgEffectConfig, FG_PRIORITY, fg_duration_ms);
Info(Logger::getInstance("HYPERION"),"Inital foreground effect '%s' %s", QSTRING_CSTR(fgEffectConfig), ((result == 0) ? "started" : "failed"));
}
}
#undef FGCONFIG_ARRAY
}
ColorOrder createColorOrder(const QJsonObject &deviceConfig)
{
return stringToColorOrder(deviceConfig["colorOrder"].toString("rgb"));
}
RgbTransform* createRgbTransform(const QJsonObject& colorConfig)
{
const double backlightThreshold = colorConfig["backlightThreshold"].toDouble(0.0);
const bool backlightColored = colorConfig["backlightColored"].toBool(false);
const double brightness = colorConfig["brightness"].toInt(100);
const double brightnessComp= colorConfig["brightnessCompensation"].toInt(100);
const double gammaR = colorConfig["gammaRed"].toDouble(1.0);
const double gammaG = colorConfig["gammaGreen"].toDouble(1.0);
const double gammaB = colorConfig["gammaBlue"].toDouble(1.0);
RgbTransform* transform = new RgbTransform(gammaR, gammaG, gammaB, backlightThreshold, backlightColored, brightness, brightnessComp);
return transform;
}
RgbChannelAdjustment* createRgbChannelAdjustment(const QJsonObject& colorConfig, const QString channelName, const int defaultR, const int defaultG, const int defaultB)
{
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()
);
return adjustment;
}
ColorAdjustment * createColorAdjustment(const QJsonObject & adjustmentConfig)
{
const QString id = adjustmentConfig["id"].toString("default");
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);
RgbTransform * rgbTransform = createRgbTransform(adjustmentConfig);
ColorAdjustment * adjustment = new ColorAdjustment();
adjustment->_id = id;
adjustment->_rgbBlackAdjustment = *blackAdjustment;
adjustment->_rgbWhiteAdjustment = *whiteAdjustment;
adjustment->_rgbRedAdjustment = *redAdjustment;
adjustment->_rgbGreenAdjustment = *greenAdjustment;
adjustment->_rgbBlueAdjustment = *blueAdjustment;
adjustment->_rgbCyanAdjustment = *cyanAdjustment;
adjustment->_rgbMagentaAdjustment = *magentaAdjustment;
adjustment->_rgbYellowAdjustment = *yellowAdjustment;
adjustment->_rgbTransform = *rgbTransform;
// Cleanup the allocated individual adjustments
delete blackAdjustment;
delete whiteAdjustment;
delete redAdjustment;
delete greenAdjustment;
delete blueAdjustment;
delete cyanAdjustment;
delete magentaAdjustment;
delete yellowAdjustment;
delete rgbTransform;
return adjustment;
}
MultiColorAdjustment * createLedColorsAdjustment(const unsigned ledCnt, const QJsonObject & colorConfig)
{
// Create the result, the transforms are added to this
MultiColorAdjustment * adjustment = new MultiColorAdjustment(ledCnt);
const QJsonValue adjustmentConfig = colorConfig["channelAdjustment"];
const QRegExp overallExp("([0-9]+(\\-[0-9]+)?)(,[ ]*([0-9]+(\\-[0-9]+)?))*");
const QJsonArray & adjustmentConfigArray = adjustmentConfig.toArray();
for (signed i = 0; i < adjustmentConfigArray.size(); ++i)
{
const QJsonObject & config = adjustmentConfigArray.at(i).toObject();
ColorAdjustment * colorAdjustment = createColorAdjustment(config);
adjustment->addAdjustment(colorAdjustment);
const QString ledIndicesStr = config["leds"].toString("").trimmed();
if (ledIndicesStr.compare("*") == 0)
{
// Special case for indices '*' => all leds
adjustment->setAdjustmentForLed(colorAdjustment->_id, 0, ledCnt-1);
//Info(_log, "ColorAdjustment '%s' => [0; %d]", QSTRING_CSTR(colorAdjustment->_id), ledCnt-1);
continue;
}
if (!overallExp.exactMatch(ledIndicesStr))
{
//Error(_log, "Given led indices %d not correct format: %s", i, QSTRING_CSTR(ledIndicesStr));
continue;
}
std::stringstream ss;
const QStringList ledIndexList = ledIndicesStr.split(",");
for (int i=0; i<ledIndexList.size(); ++i) {
if (i > 0)
{
ss << ", ";
}
if (ledIndexList[i].contains("-"))
{
QStringList ledIndices = ledIndexList[i].split("-");
int startInd = ledIndices[0].toInt();
int endInd = ledIndices[1].toInt();
adjustment->setAdjustmentForLed(colorAdjustment->_id, startInd, endInd);
ss << startInd << "-" << endInd;
}
else
{
int index = ledIndexList[i].toInt();
adjustment->setAdjustmentForLed(colorAdjustment->_id, index, index);
ss << index;
}
}
//Info(_log, "ColorAdjustment '%s' => [%s]", QSTRING_CSTR(colorAdjustment->_id), ss.str().c_str());
}
return adjustment;
}
/**
* Construct the 'led-string' with the integration area definition per led and the color
* ordering of the RGB channels
* @param ledsConfig The configuration of the led areas
* @param deviceOrder The default RGB channel ordering
* @return The constructed ledstring
*/
LedString createLedString(const QJsonArray& ledConfigArray, const ColorOrder deviceOrder)
{
LedString ledString;
const QString deviceOrderStr = colorOrderToString(deviceOrder);
int maxLedId = ledConfigArray.size();
for (signed i = 0; i < ledConfigArray.size(); ++i)
{
const QJsonObject& index = ledConfigArray[i].toObject();
Led led;
led.index = index["index"].toInt();
led.clone = index["clone"].toInt(-1);
if ( led.clone < -1 || led.clone >= maxLedId )
{
//Warning(_log, "LED %d: clone index of %d is out of range, clone ignored", led.index, led.clone);
led.clone = -1;
}
if ( led.clone < 0 )
{
const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["hscan"].toObject();
const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["vscan"].toObject();
led.minX_frac = qMax(0.0, qMin(1.0, hscanConfig["minimum"].toDouble()));
led.maxX_frac = qMax(0.0, qMin(1.0, hscanConfig["maximum"].toDouble()));
led.minY_frac = qMax(0.0, qMin(1.0, vscanConfig["minimum"].toDouble()));
led.maxY_frac = qMax(0.0, qMin(1.0, vscanConfig["maximum"].toDouble()));
// 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)
led.colorOrder = stringToColorOrder(index["colorOrder"].toString(deviceOrderStr));
ledString.leds().push_back(led);
}
}
// 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;
}
LedString createLedStringClone(const QJsonArray& ledConfigArray, const ColorOrder deviceOrder)
{
LedString ledString;
const QString deviceOrderStr = colorOrderToString(deviceOrder);
int maxLedId = ledConfigArray.size();
for (signed i = 0; i < ledConfigArray.size(); ++i)
{
const QJsonObject& index = ledConfigArray[i].toObject();
Led led;
led.index = index["index"].toInt();
led.clone = index["clone"].toInt(-1);
if ( led.clone < -1 || led.clone >= maxLedId )
{
//Warning(_log, "LED %d: clone index of %d is out of range, clone ignored", led.index, led.clone);
led.clone = -1;
}
if ( led.clone >= 0 )
{
//Debug(_log, "LED %d: clone from led %d", led.index, led.clone);
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)
led.colorOrder = stringToColorOrder(index["colorOrder"].toString(deviceOrderStr));
ledString.leds().push_back(led);
}
}
// 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;
}
QSize getLedLayoutGridSize(const QJsonArray& ledConfigArray)
{
std::vector<int> midPointsX;
std::vector<int> midPointsY;
for (signed i = 0; i < ledConfigArray.size(); ++i)
{
const QJsonObject& index = ledConfigArray[i].toObject();
if (index["clone"].toInt(-1) < 0 )
{
const QJsonObject& hscanConfig = ledConfigArray[i].toObject()["hscan"].toObject();
const QJsonObject& vscanConfig = ledConfigArray[i].toObject()["vscan"].toObject();
double minX_frac = qMax(0.0, qMin(1.0, hscanConfig["minimum"].toDouble()));
double maxX_frac = qMax(0.0, qMin(1.0, hscanConfig["maximum"].toDouble()));
double minY_frac = qMax(0.0, qMin(1.0, vscanConfig["minimum"].toDouble()));
double maxY_frac = qMax(0.0, qMin(1.0, vscanConfig["maximum"].toDouble()));
// 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() );
//Debug(_log, "led layout grid: %dx%d", gridSize.width(), gridSize.height());
return gridSize;
}
};

99
include/utils/settings.h Normal file
View File

@@ -0,0 +1,99 @@
#pragma once
#include <QString>
#include <QJsonDocument>
///
/// @brief Provide util methods to work with SettingsManager class
///
namespace settings {
// all available settings sections
enum type {
BGEFFECT,
FGEFFECT,
BLACKBORDER,
BOBLSERVER,
COLOR,
DEVICE,
EFFECTS,
NETFORWARD,
SYSTEMCAPTURE,
GENERAL,
V4L2,
JSONSERVER,
LEDCONFIG,
LEDS,
LOGGER,
PROTOSERVER,
SMOOTHING,
UDPLISTENER,
WEBSERVER,
INSTCAPTURE,
NETWORK,
INVALID
};
///
/// @brief Convert settings::type to string representation
/// @param type The settings::type from enum
/// @return The settings type as string
///
inline QString typeToString(const type& type)
{
switch (type)
{
case BGEFFECT: return "backgroundEffect";
case FGEFFECT: return "foregroundEffect";
case BLACKBORDER: return "blackborderdetector";
case BOBLSERVER: return "boblightServer";
case COLOR: return "color";
case DEVICE: return "device";
case EFFECTS: return "effects";
case NETFORWARD: return "forwarder";
case SYSTEMCAPTURE: return "framegrabber";
case GENERAL: return "general";
case V4L2: return "grabberV4L2";
case JSONSERVER: return "jsonServer";
case LEDCONFIG: return "ledConfig";
case LEDS: return "leds";
case LOGGER: return "logger";
case PROTOSERVER: return "protoServer";
case SMOOTHING: return "smoothing";
case UDPLISTENER: return "udpListener";
case WEBSERVER: return "webConfig";
case INSTCAPTURE: return "instCapture";
case NETWORK: return "network";
default: return "invalid";
}
}
///
/// @brief Convert string to settings::type representation
/// @param type The string to convert
/// @return The settings type from enum
///
inline type stringToType(const QString& type)
{
if (type == "backgroundEffect") return BGEFFECT;
else if (type == "foregroundEffect") return FGEFFECT;
else if (type == "blackborderdetector") return BLACKBORDER;
else if (type == "boblightServer") return BOBLSERVER;
else if (type == "color") return COLOR;
else if (type == "device") return DEVICE;
else if (type == "effects") return EFFECTS;
else if (type == "forwarder") return NETFORWARD;
else if (type == "framegrabber") return SYSTEMCAPTURE;
else if (type == "general") return GENERAL;
else if (type == "grabberV4L2") return V4L2;
else if (type == "jsonServer") return JSONSERVER;
else if (type == "ledConfig") return LEDCONFIG;
else if (type == "leds") return LEDS;
else if (type == "logger") return LOGGER;
else if (type == "protoServer") return PROTOSERVER;
else if (type == "smoothing") return SMOOTHING;
else if (type == "udpListener") return UDPLISTENER;
else if (type == "webConfig") return WEBSERVER;
else if (type == "instCapture") return INSTCAPTURE;
else if (type == "network") return NETWORK;
else return INVALID;
}
};

View File

@@ -1,34 +0,0 @@
#ifndef WEBCONFIG_H
#define WEBCONFIG_H
#include <QObject>
#include <QString>
#include <hyperion/Hyperion.h>
class StaticFileServing;
class WebConfig : public QObject {
Q_OBJECT
public:
WebConfig (QObject * parent = NULL);
virtual ~WebConfig (void);
void start();
void stop();
quint16 getPort() { return _port; };
private:
Hyperion* _hyperion;
QString _baseUrl;
quint16 _port;
StaticFileServing* _server;
const QString WEBCONFIG_DEFAULT_PATH = ":/webconfig";
const quint16 WEBCONFIG_DEFAULT_PORT = 8099;
};
#endif // WEBCONFIG_H

View File

@@ -0,0 +1,55 @@
#ifndef WEBSERVER_H
#define WEBSERVER_H
#include <QObject>
#include <QString>
#include <QJsonDocument>
// hyperion / utils
#include <hyperion/Hyperion.h>
#include <utils/Logger.h>
// settings
#include <utils/settings.h>
class StaticFileServing;
class QtHttpServer;
class WebServer : public QObject {
Q_OBJECT
public:
WebServer (const QJsonDocument& config, QObject * parent = 0);
virtual ~WebServer (void);
void start();
void stop();
quint16 getPort() { return _port; };
public slots:
void onServerStopped (void);
void onServerStarted (quint16 port);
void onServerError (QString msg);
///
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
/// @param type settingyType from enum
/// @param config configuration object
///
void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config);
private:
Logger* _log;
Hyperion* _hyperion;
QString _baseUrl;
quint16 _port;
StaticFileServing* _staticFileServing;
QtHttpServer* _server;
const QString WEBSERVER_DEFAULT_PATH = ":/webconfig";
const quint16 WEBSERVER_DEFAULT_PORT = 8090;
};
#endif // WEBSERVER_H