From 657fe00211d9d59d4f897c9a57be1e699162c482 Mon Sep 17 00:00:00 2001 From: Paulchen-Panther Date: Sun, 3 Feb 2019 14:36:57 +0100 Subject: [PATCH] Troubleshooting and ... - More i18n - Easy use of mutual exclusion in JsonAPI with QMutexLocker - Smoothing type "linear" hidden in the WebUI, because there is currently only one - Message forwarding implemented again - For compatibility to home assistants and other remote controls, "activeEffects" and "activeLedColor" has been added to the JSON-RPC - FlatBuffer clear now the Priority on disconnect - The information "available V4L2 devices" is now only displayed if the device list is not empty - LED device "PiBlaster" excluded from OSX build --- assets/webconfig/i18n/de.json | 4 +- assets/webconfig/i18n/en.json | 2 + .../js/content_effectsconfigurator.js | 1 - assets/webconfig/js/ui_utils.js | 7 +- include/hyperion/Hyperion.h | 11 +- include/hyperion/MessageForwarder.h | 73 ++++++-- include/hyperion/PriorityMuxer.h | 4 +- include/jsonserver/JsonServer.h | 10 +- include/udplistener/UDPListener.h | 5 - include/utils/hyperion.h | 2 + libsrc/api/JsonAPI.cpp | 77 ++++++-- libsrc/flatbufserver/FlatBufferClient.cpp | 13 +- libsrc/flatbufserver/FlatBufferClient.h | 5 - libsrc/flatbufserver/FlatBufferConnection.cpp | 2 + libsrc/flatbufserver/FlatBufferServer.cpp | 1 - libsrc/grabber/v4l2/V4L2Grabber.cpp | 3 +- libsrc/hyperion/CMakeLists.txt | 6 + libsrc/hyperion/CaptureCont.cpp | 4 +- libsrc/hyperion/Hyperion.cpp | 9 +- libsrc/hyperion/ImageProcessor.cpp | 4 +- libsrc/hyperion/MessageForwarder.cpp | 175 ++++++++++++++++-- libsrc/hyperion/PriorityMuxer.cpp | 7 +- libsrc/hyperion/schema/schema-smoothing.json | 3 +- libsrc/jsonserver/JsonServer.cpp | 40 ---- libsrc/leddevice/CMakeLists.txt | 5 + libsrc/udplistener/UDPListener.cpp | 2 +- src/hyperiond/hyperiond.cpp | 2 + test/TestImage2LedsMap.cpp | 8 +- 28 files changed, 339 insertions(+), 146 deletions(-) diff --git a/assets/webconfig/i18n/de.json b/assets/webconfig/i18n/de.json index b533fd60..440746ad 100644 --- a/assets/webconfig/i18n/de.json +++ b/assets/webconfig/i18n/de.json @@ -565,12 +565,14 @@ "edt_conf_fw_proto_itemtitle" : "Proto Ziel", "edt_conf_js_heading_title" : "JSON Server", "edt_conf_fbs_heading_title" : "Flatbuffers Server", + "edt_conf_fbs_timeout_title" : "Zeitüberschreitung", + "edt_conf_fbs_timeout_expl" : "Wenn für die angegebene Zeit keine Daten empfangen werden, wird die Komponente (vorübergehend) deaktiviert", "edt_conf_bobls_heading_title" : "Boblight Server", "edt_conf_udpl_heading_title" : "UDP Listener", "edt_conf_udpl_address_title" : "Adresse", "edt_conf_udpl_address_expl" : "Die Adresse auf der UDP Pakete akzeptiert werden.", "edt_conf_udpl_timeout_title" : "Zeitüberschreitung", - "edt_conf_udpl_timeout_expl" : "Wenn für die angegeben Zeit keine UDP Pakete empfangen werden, wird die Komponente (vorübergehend) deaktiviert", + "edt_conf_udpl_timeout_expl" : "Wenn für die angegebene Zeit keine UDP Pakete empfangen werden, wird die Komponente (vorübergehend) deaktiviert", "edt_conf_udpl_shared_title" : "Gemeinsam genutzt", "edt_conf_udpl_shared_expl" : "Wird gemeinsam über alle Hyperion Instanzen genutzt.", "edt_conf_webc_heading_title" : "Web Konfiguration", diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json index ef297955..15f5296e 100644 --- a/assets/webconfig/i18n/en.json +++ b/assets/webconfig/i18n/en.json @@ -566,6 +566,8 @@ "edt_conf_fw_proto_itemtitle" : "Proto target", "edt_conf_js_heading_title" : "JSON Server", "edt_conf_fbs_heading_title" : "Flatbuffers Server", + "edt_conf_fbs_timeout_title" : "Timeout", + "edt_conf_fbs_timeout_expl" : "If no data are received for the given period, the component will be (soft) disabled.", "edt_conf_bobls_heading_title" : "Boblight Server", "edt_conf_udpl_heading_title" : "UDP Listener", "edt_conf_udpl_address_title" : "Address", diff --git a/assets/webconfig/js/content_effectsconfigurator.js b/assets/webconfig/js/content_effectsconfigurator.js index 6b3411d9..29cbfd22 100644 --- a/assets/webconfig/js/content_effectsconfigurator.js +++ b/assets/webconfig/js/content_effectsconfigurator.js @@ -50,7 +50,6 @@ $(document).ready( function() { fileReader.onload = function () { imageData = this.result.split(',')[1]; - console.log(imageData); cbs.success(file.name); }; diff --git a/assets/webconfig/js/ui_utils.js b/assets/webconfig/js/ui_utils.js index 4b2c914f..0e9ca232 100644 --- a/assets/webconfig/js/ui_utils.js +++ b/assets/webconfig/js/ui_utils.js @@ -587,6 +587,9 @@ function createHelpTable(list, phead){ { if(list[key].access != 'system') { + // break one iteration (in the loop), if the schema has the entry hidden=true + if ("options" in list[key] && "hidden" in list[key].options && (list[key].options.hidden)) + continue; var text = list[key].title.replace('title', 'expl'); tbody.appendChild(createTableRow([$.i18n(list[key].title), $.i18n(text)], false, false)); @@ -595,7 +598,9 @@ function createHelpTable(list, phead){ var ilist = sortProperties(list[key].items.properties); for (ikey in ilist) { - + // break one iteration (in the loop), if the schema has the entry hidden=true + if ("options" in ilist[ikey] && "hidden" in ilist[ikey].options && (ilist[ikey].options.hidden)) + continue; var itext = ilist[ikey].title.replace('title', 'expl'); tbody.appendChild(createTableRow([$.i18n(ilist[ikey].title), $.i18n(itext)], false, false)); } diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index 413e01b5..7440020b 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -326,12 +326,6 @@ public slots: /// ColorAdjustment * getAdjustment(const QString& id); - /// - /// Returns MessageForwarder Object - /// @return instance of message forwarder object - /// - MessageForwarder * getForwarder(); - /// Tell Hyperion that the corrections have changed and the leds need to be updated void adjustmentsUpdated(); @@ -345,7 +339,7 @@ public slots: const bool clear(int priority); /// - /// Clears all priority channels. This will switch the leds off until a new priority is written. + /// @brief Clears all priority channels. This will switch the leds off until a new priority is written. /// void clearall(bool forceClearAll=false); @@ -416,6 +410,9 @@ signals: /// Signal which is emitted, when a new json message should be forwarded void forwardJsonMessage(QJsonObject); + /// Signal which is emitted, when a new proto image should be forwarded + void forwardProtoMessage(Image); + /// /// @brief Is emitted from clients who request a videoMode change /// diff --git a/include/hyperion/MessageForwarder.h b/include/hyperion/MessageForwarder.h index ea247c53..58b3254f 100644 --- a/include/hyperion/MessageForwarder.h +++ b/include/hyperion/MessageForwarder.h @@ -18,37 +18,86 @@ #include #include #include +#include +#include +// Hyperion includes +#include + +// Forward declaration class Hyperion; +class QTcpSocket; +class FlatBufferConnection; class MessageForwarder : public QObject { Q_OBJECT public: - - MessageForwarder(Hyperion* hyperion, const QJsonDocument & config); + MessageForwarder(Hyperion* hyperion); ~MessageForwarder(); void addJsonSlave(QString slave); void addProtoSlave(QString slave); - bool protoForwardingEnabled(); - bool jsonForwardingEnabled(); - bool forwardingEnabled() { return jsonForwardingEnabled() || protoForwardingEnabled(); }; - 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); + void handleSettingsUpdate(const settings::type &type, const QJsonDocument &config); + + /// + /// @brief Handle component state change MessageForwarder + /// @param component The component from enum + /// @param enable The new state + /// + void componentStateChanged(const hyperion::Components component, bool enable); + + /// + /// @brief Handle priority updates from Priority Muxer + /// @param priority The new visible priority + /// + void handlePriorityChanges(const quint8 &priority); + + /// + /// @brief Forward message to all json slaves + /// @param message The JSON message to send + /// + void forwardJsonMessage(const QJsonObject &message); + + /// + /// @brief Forward image to all proto slaves + /// @param image The PROTO image to send + /// + void forwardProtoMessage(const Image &image); + + /// + /// @brief Forward message to a single json slave + /// @param message The JSON message to send + /// @param socket The TCP-Socket with the connection to the slave + /// + void sendJsonMessage(const QJsonObject &message, QTcpSocket *socket); private: - Hyperion* _hyperion; - Logger* _log; - QStringList _protoSlaves; + /// Hyperion instance + Hyperion *_hyperion; + + /// Logger instance + Logger *_log; + + /// Muxer instance + PriorityMuxer *_muxer; + + // JSON connection for forwarding QStringList _jsonSlaves; + + /// Proto connection for forwarding + QStringList _protoSlaves; + QList _forwardClients; + + /// Flag if forwarder is enabled + bool _forwarder_enabled = true; + + const int _priority; }; diff --git a/include/hyperion/PriorityMuxer.h b/include/hyperion/PriorityMuxer.h index e6a4b0ff..2c9fe96d 100644 --- a/include/hyperion/PriorityMuxer.h +++ b/include/hyperion/PriorityMuxer.h @@ -107,7 +107,7 @@ public: /// /// @return The current priority /// - int getCurrentPriority() const; + int getCurrentPriority() const { return _currentPriority; } /// /// Returns the state (enabled/disabled) of a specific priority channel @@ -197,7 +197,7 @@ signals: /// /// @brief Emits whenever the visible priority has changed - /// @param priority The new visible prioritiy + /// @param priority The new visible priority /// void visiblePriorityChanged(const quint8& priority); diff --git a/include/jsonserver/JsonServer.h b/include/jsonserver/JsonServer.h index a6c55053..19b1e374 100644 --- a/include/jsonserver/JsonServer.h +++ b/include/jsonserver/JsonServer.h @@ -49,17 +49,9 @@ private slots: void closedConnection(void); public slots: - - /// - /// forward message to a single json slaves - /// - /// @param message The JSON message to send - /// - void sendMessage(const QJsonObject & message, QTcpSocket * socket); - /// /// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor - /// @param type settingyType from enum + /// @param type settings type from enum /// @param config configuration object /// void handleSettingsUpdate(const settings::type& type, const QJsonDocument& config); diff --git a/include/udplistener/UDPListener.h b/include/udplistener/UDPListener.h index 0ab01d92..83b50599 100644 --- a/include/udplistener/UDPListener.h +++ b/include/udplistener/UDPListener.h @@ -76,11 +76,6 @@ signals: /// const bool setGlobalInput(const int priority, const std::vector& ledColors, const int timeout_ms = -1, const bool& clearEffect = true); - /// - /// @brief forward clear to HyperionDaemon - /// - void clearGlobalPriority(const int& _priority, const hyperion::Components& component); - private slots: /// /// Slot which is called when a client tries to create a new connection diff --git a/include/utils/hyperion.h b/include/utils/hyperion.h index 3751ec49..d70263cb 100644 --- a/include/utils/hyperion.h +++ b/include/utils/hyperion.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 0a3b1393..025fd9c1 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -14,6 +14,7 @@ #include #include #include +#include // hyperion includes #include @@ -55,9 +56,6 @@ JsonAPI::JsonAPI(QString peerAddress, Logger* log, QObject* parent, bool noListe // notify hyperion about a jsonMessageForward connect(this, &JsonAPI::forwardJsonMessage, _hyperion, &Hyperion::forwardJsonMessage); - - _image_stream_mutex.unlock(); - _led_stream_mutex.unlock(); } void JsonAPI::handleMessage(const QString& messageString) @@ -475,10 +473,10 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString& // BEGIN | The following entries are derecated but used to ensure backward compatibility with hyperion Classic remote control // TODO Output the real transformation information instead of default - // host name + // HOST NAME info["hostname"] = QHostInfo::localHostName(); - // transform information (default values) + // TRANSFORM INFORMATION (DEFAULT VALUES) QJsonArray transformArray; for (const QString& transformId : _hyperion->getAdjustmentIds()) { @@ -507,9 +505,66 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject& message, const QString& transformArray.append(transform); } - info["transform"] = transformArray; + // ACTIVE EFFECT INFO + QJsonArray activeEffects; + const std::list & activeEffectsDefinitions = _hyperion->getActiveEffects(); + for (const ActiveEffectDefinition & activeEffectDefinition : activeEffectsDefinitions) + { + if (activeEffectDefinition.priority != PriorityMuxer::LOWEST_PRIORITY -1) + { + QJsonObject activeEffect; + activeEffect["script"] = activeEffectDefinition.script; + activeEffect["name"] = activeEffectDefinition.name; + activeEffect["priority"] = activeEffectDefinition.priority; + activeEffect["timeout"] = activeEffectDefinition.timeout; + activeEffect["args"] = activeEffectDefinition.args; + activeEffects.append(activeEffect); + } + } + info["activeEffects"] = activeEffects; + + // ACTIVE STATIC LED COLOR + QJsonArray activeLedColors; + const Hyperion::InputInfo & priorityInfo = _hyperion->getPriorityInfo(_hyperion->getCurrentPriority()); + if(priorityInfo.componentId == hyperion::COMP_COLOR && !priorityInfo.ledColors.empty()) + { + QJsonObject LEDcolor; + // check if LED Color not Black (0,0,0) + if ((priorityInfo.ledColors.begin()->red + + priorityInfo.ledColors.begin()->green + + priorityInfo.ledColors.begin()->blue != 0)) + { + QJsonObject LEDcolor; + + // add RGB Value to Array + QJsonArray RGBValue; + RGBValue.append(priorityInfo.ledColors.begin()->red); + RGBValue.append(priorityInfo.ledColors.begin()->green); + RGBValue.append(priorityInfo.ledColors.begin()->blue); + LEDcolor.insert("RGB Value", RGBValue); + + uint16_t Hue; + float Saturation, Luminace; + + // add HSL Value to Array + QJsonArray HSLValue; + ColorSys::rgb2hsl(priorityInfo.ledColors.begin()->red, + priorityInfo.ledColors.begin()->green, + priorityInfo.ledColors.begin()->blue, + Hue, Saturation, Luminace); + + HSLValue.append(Hue); + HSLValue.append(Saturation); + HSLValue.append(Luminace); + LEDcolor.insert("HSL Value", HSLValue); + + activeLedColors.append(LEDcolor); + } + } + info["activeLedColor"] = activeLedColors; + // END sendSuccessDataReply(QJsonDocument(info), command, tan); @@ -952,7 +1007,8 @@ void JsonAPI::sendErrorReply(const QString &error, const QString &command, const void JsonAPI::streamLedcolorsUpdate(const std::vector& ledColors) { - if ( (_led_stream_timeout+100) < QDateTime::currentMSecsSinceEpoch() && _led_stream_mutex.tryLock(0) ) + QMutexLocker lock(&_led_stream_mutex); + if ( (_led_stream_timeout+100) < QDateTime::currentMSecsSinceEpoch() ) { _led_stream_timeout = QDateTime::currentMSecsSinceEpoch(); QJsonObject result; @@ -973,14 +1029,13 @@ void JsonAPI::streamLedcolorsUpdate(const std::vector& ledColors) // send the result emit callbackMessage(_streaming_leds_reply); - - _led_stream_mutex.unlock(); } } void JsonAPI::setImage(const Image & image) { - if ( (_image_stream_timeout+100) < QDateTime::currentMSecsSinceEpoch() && _image_stream_mutex.tryLock(0) ) + QMutexLocker lock(&_image_stream_mutex); + if ( (_image_stream_timeout+100) < QDateTime::currentMSecsSinceEpoch() ) { _image_stream_timeout = QDateTime::currentMSecsSinceEpoch(); @@ -994,8 +1049,6 @@ void JsonAPI::setImage(const Image & image) result["image"] = "data:image/jpg;base64,"+QString(ba.toBase64()); _streaming_image_reply["result"] = result; emit callbackMessage(_streaming_image_reply); - - _image_stream_mutex.unlock(); } } diff --git a/libsrc/flatbufserver/FlatBufferClient.cpp b/libsrc/flatbufserver/FlatBufferClient.cpp index 5ab24d81..f740abf2 100644 --- a/libsrc/flatbufserver/FlatBufferClient.cpp +++ b/libsrc/flatbufserver/FlatBufferClient.cpp @@ -7,7 +7,6 @@ #include #include -#include FlatBufferClient::FlatBufferClient(QTcpSocket* socket, const int &timeout, QObject *parent) : QObject(parent) , _log(Logger::getInstance("FLATBUFSERVER")) @@ -61,14 +60,6 @@ void FlatBufferClient::readyRead() } sendErrorReply("Unable to parse message"); } - //emit newMessage(msgData,messageSize); - - - // Emit this to send a new priority register event to all Hyperion instances, - // emit registerGlobalInput(_priority, hyperion::COMP_FLATBUFSERVER, QString("%1@%2").arg("PLACE_ORIGIN_STRING_FROM_SENDER_HERE",_socket->peerAddress())); - - // Emit this to send the image data event to all Hyperion instances - // emit setGlobalInput(_priority, _image, _timeout); } void FlatBufferClient::forceClose() @@ -78,9 +69,9 @@ void FlatBufferClient::forceClose() void FlatBufferClient::disconnected() { - qDebug()<<"Socket Closed"; - //emit clearGlobalPriority(_priority, hyperion::COMP_FLATBUFSERVER); + Debug(_log, "Socket Closed"); _socket->deleteLater(); + _hyperion->clear(_priority); emit clientDisconnected(); } diff --git a/libsrc/flatbufserver/FlatBufferClient.h b/libsrc/flatbufserver/FlatBufferClient.h index e0157c31..cc934b32 100644 --- a/libsrc/flatbufserver/FlatBufferClient.h +++ b/libsrc/flatbufserver/FlatBufferClient.h @@ -44,11 +44,6 @@ signals: /// const bool setGlobalInputImage(const int priority, const Image& image, const int timeout_ms = -1); - /// - /// @brief forward clear to HyperionDaemon - /// - void clearGlobalPriority(const int& priority, const hyperion::Components& component); - /// /// @brief Emits whenever the client disconnected /// diff --git a/libsrc/flatbufserver/FlatBufferConnection.cpp b/libsrc/flatbufserver/FlatBufferConnection.cpp index 870d6b07..c9cc5834 100644 --- a/libsrc/flatbufserver/FlatBufferConnection.cpp +++ b/libsrc/flatbufserver/FlatBufferConnection.cpp @@ -151,6 +151,7 @@ void FlatBufferConnection::sendMessage(const uint8_t* buffer, uint32_t size) { case QAbstractSocket::UnconnectedState: Info(_log, "No connection to Hyperion: %s:%d", _host.toStdString().c_str(), _port); + _registered = false; break; case QAbstractSocket::ConnectedState: Info(_log, "Connected to Hyperion: %s:%d", _host.toStdString().c_str(), _port); @@ -158,6 +159,7 @@ void FlatBufferConnection::sendMessage(const uint8_t* buffer, uint32_t size) break; default: Debug(_log, "Connecting to Hyperion: %s:%d", _host.toStdString().c_str(), _port); + _registered = false; break; } _prevSocketState = _socket.state(); diff --git a/libsrc/flatbufserver/FlatBufferServer.cpp b/libsrc/flatbufserver/FlatBufferServer.cpp index a84b3537..ab87eb3e 100644 --- a/libsrc/flatbufserver/FlatBufferServer.cpp +++ b/libsrc/flatbufserver/FlatBufferServer.cpp @@ -58,7 +58,6 @@ void FlatBufferServer::newConnection() { if(QTcpSocket* socket = _server->nextPendingConnection()) { - Debug(_log, "New connection from %s", QSTRING_CSTR(socket->peerAddress().toString())); FlatBufferClient *client = new FlatBufferClient(socket, _timeout, this); // internal diff --git a/libsrc/grabber/v4l2/V4L2Grabber.cpp b/libsrc/grabber/v4l2/V4L2Grabber.cpp index dd5b120e..2f17f238 100644 --- a/libsrc/grabber/v4l2/V4L2Grabber.cpp +++ b/libsrc/grabber/v4l2/V4L2Grabber.cpp @@ -92,7 +92,8 @@ bool V4L2Grabber::init() { v4lDevices_str += "\t"+ dev.first + "\t" + dev.second + "\n"; } - Info(_log, "available V4L2 devices:\n%s", QSTRING_CSTR(v4lDevices_str)); + if (!v4lDevices_str.isEmpty()) + Info(_log, "available V4L2 devices:\n%s", QSTRING_CSTR(v4lDevices_str)); } if ( _deviceName == "auto" ) diff --git a/libsrc/hyperion/CMakeLists.txt b/libsrc/hyperion/CMakeLists.txt index 501f4501..eb96a92d 100644 --- a/libsrc/hyperion/CMakeLists.txt +++ b/libsrc/hyperion/CMakeLists.txt @@ -3,6 +3,10 @@ SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/hyperion) SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperion) +include_directories( + ${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/flatbufserver +) + FILE ( GLOB Hyperion_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" ) SET(Hyperion_RESOURCES ${CURRENT_SOURCE_DIR}/resource.qrc) @@ -15,6 +19,8 @@ add_library(hyperion target_link_libraries(hyperion blackborder hyperion-utils + flatbufserver + flatbuffers leddevice bonjour boblightserver diff --git a/libsrc/hyperion/CaptureCont.cpp b/libsrc/hyperion/CaptureCont.cpp index db26931f..12c5cd32 100644 --- a/libsrc/hyperion/CaptureCont.cpp +++ b/libsrc/hyperion/CaptureCont.cpp @@ -39,7 +39,6 @@ CaptureCont::CaptureCont(Hyperion* hyperion) CaptureCont::~CaptureCont() { - } void CaptureCont::handleV4lImage(const Image & image) @@ -54,7 +53,6 @@ void CaptureCont::handleSystemImage(const Image& image) _hyperion->setInputImage(_systemCaptPrio, image); } - void CaptureCont::setSystemCaptureEnable(const bool& enable) { if(_systemCaptEnabled != enable) @@ -63,6 +61,7 @@ void CaptureCont::setSystemCaptureEnable(const bool& enable) { _hyperion->registerInput(_systemCaptPrio, hyperion::COMP_GRABBER); connect(GlobalSignals::getInstance(), &GlobalSignals::setSystemImage, this, &CaptureCont::handleSystemImage); + connect(GlobalSignals::getInstance(), &GlobalSignals::setSystemImage, _hyperion, &Hyperion::forwardProtoMessage); } else { @@ -82,6 +81,7 @@ void CaptureCont::setV4LCaptureEnable(const bool& enable) { _hyperion->registerInput(_v4lCaptPrio, hyperion::COMP_V4L); connect(GlobalSignals::getInstance(), &GlobalSignals::setV4lImage, this, &CaptureCont::handleV4lImage); + connect(GlobalSignals::getInstance(), &GlobalSignals::setSystemImage, _hyperion, &Hyperion::forwardProtoMessage); } else { diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index b45b67ea..c04b2b28 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -68,11 +68,6 @@ Hyperion* Hyperion::getInstance() return Hyperion::_hyperion; } -MessageForwarder * Hyperion::getForwarder() -{ - return _messageForwarder; -} - Hyperion::Hyperion(HyperionDaemon* daemon, const quint8& instance, const QString configFile, const QString rootPath) : _daemon(daemon) , _settingsManager(new SettingsManager(this, instance, configFile)) @@ -83,7 +78,7 @@ Hyperion::Hyperion(HyperionDaemon* daemon, const quint8& instance, const QString , _muxer(_ledString.leds().size()) , _raw2ledAdjustment(hyperion::createLedColorsAdjustment(_ledString.leds().size(), getSetting(settings::COLOR).object())) , _effectEngine(nullptr) - , _messageForwarder(new MessageForwarder(this, getSetting(settings::NETFORWARD))) + , _messageForwarder(new MessageForwarder(this)) , _configFile(configFile) , _rootPath(rootPath) , _log(Logger::getInstance("HYPERION")) @@ -408,9 +403,7 @@ const bool Hyperion::setInputImage(const int priority, const Image& im // if this priority is visible, update immediately if(priority == _muxer.getCurrentPriority()) - { update(); - } return true; } diff --git a/libsrc/hyperion/ImageProcessor.cpp b/libsrc/hyperion/ImageProcessor.cpp index 426328f8..4c6269be 100644 --- a/libsrc/hyperion/ImageProcessor.cpp +++ b/libsrc/hyperion/ImageProcessor.cpp @@ -70,7 +70,7 @@ void ImageProcessor::setSize(const unsigned width, const unsigned height) } // Clean up the old buffer and mapping - delete _imageToLeds; + _imageToLeds = 0; // Construct a new buffer and mapping _imageToLeds = (width>0 && height>0) ? (new ImageToLedsMap(width, height, 0, 0, _ledString.leds())) : nullptr; @@ -85,7 +85,7 @@ void ImageProcessor::setLedString(const LedString& ledString) const unsigned height = _imageToLeds->height(); // Clean up the old buffer and mapping - delete _imageToLeds; + _imageToLeds = 0; // Construct a new buffer and mapping _imageToLeds = new ImageToLedsMap(width, height, 0, 0, _ledString.leds()); diff --git a/libsrc/hyperion/MessageForwarder.cpp b/libsrc/hyperion/MessageForwarder.cpp index 3ba11d99..61e937a5 100644 --- a/libsrc/hyperion/MessageForwarder.cpp +++ b/libsrc/hyperion/MessageForwarder.cpp @@ -1,32 +1,58 @@ // STL includes #include +// project includes #include -#include +// hyperion includes #include -MessageForwarder::MessageForwarder(Hyperion* hyperion, const QJsonDocument & config) +// utils includes +#include + +// qt includes +#include +#include + +#include + +MessageForwarder::MessageForwarder(Hyperion *hyperion) : QObject() , _hyperion(hyperion) , _log(Logger::getInstance("NETFORWARDER")) + , _muxer(_hyperion->getMuxerInstance()) + , _forwarder_enabled(true) + , _priority(140) { - handleSettingsUpdate(settings::NETFORWARD, config); // get settings updates connect(_hyperion, &Hyperion::settingsChanged, this, &MessageForwarder::handleSettingsUpdate); + + // component changes + connect(_hyperion, &Hyperion::componentStateChanged, this, &MessageForwarder::componentStateChanged); + + // connect with Muxer visible priority changes + connect(_muxer, &PriorityMuxer::visiblePriorityChanged, this, &MessageForwarder::handlePriorityChanges); + + // init + handleSettingsUpdate(settings::NETFORWARD, _hyperion->getSetting(settings::NETFORWARD)); } MessageForwarder::~MessageForwarder() { + while (!_forwardClients.isEmpty()) + delete _forwardClients.takeFirst(); } -void MessageForwarder::handleSettingsUpdate(const settings::type& type, const QJsonDocument& config) +void MessageForwarder::handleSettingsUpdate(const settings::type &type, const QJsonDocument &config) { if(type == settings::NETFORWARD) { // clear the current targets _jsonSlaves.clear(); _protoSlaves.clear(); + while (!_forwardClients.isEmpty()) + delete _forwardClients.takeFirst(); + // build new one const QJsonObject &obj = config.object(); if ( !obj["json"].isNull() ) @@ -46,12 +72,64 @@ void MessageForwarder::handleSettingsUpdate(const settings::type& type, const QJ addProtoSlave(entry.toString()); } } - InfoIf(obj["enable"].toBool(true), _log, "Forward now to json targets '%s' and proto targets '%s'", QSTRING_CSTR(_jsonSlaves.join(", ")), QSTRING_CSTR(_protoSlaves.join(", "))) + + if (!_jsonSlaves.isEmpty() && obj["enable"].toBool() && _forwarder_enabled) + { + InfoIf(obj["enable"].toBool(true), _log, "Forward now to json targets '%s'", QSTRING_CSTR(_jsonSlaves.join(", "))); + connect(_hyperion, &Hyperion::forwardJsonMessage, this, &MessageForwarder::forwardJsonMessage, Qt::UniqueConnection); + } else if (_jsonSlaves.isEmpty() || ! obj["enable"].toBool() || !_forwarder_enabled) + disconnect(_hyperion, &Hyperion::forwardJsonMessage, 0, 0); + + if (!_protoSlaves.isEmpty() && obj["enable"].toBool() && _forwarder_enabled) + { + InfoIf(obj["enable"].toBool(true), _log, "Forward now to proto targets '%s'", QSTRING_CSTR(_protoSlaves.join(", "))); + connect(_hyperion, &Hyperion::forwardProtoMessage, this, &MessageForwarder::forwardProtoMessage, Qt::UniqueConnection); + } else if ( _protoSlaves.isEmpty() || ! obj["enable"].toBool() || !_forwarder_enabled) + disconnect(_hyperion, &Hyperion::forwardProtoMessage, 0, 0); + // update comp state _hyperion->getComponentRegister().componentStateChanged(hyperion::COMP_FORWARDER, obj["enable"].toBool(true)); } } +void MessageForwarder::componentStateChanged(const hyperion::Components component, bool enable) +{ + if (component == hyperion::COMP_FORWARDER && _forwarder_enabled != enable) + { + _forwarder_enabled = enable; + handleSettingsUpdate(settings::NETFORWARD, _hyperion->getSetting(settings::NETFORWARD)); + Info(_log, "Message Forwarder change state to %s", (_forwarder_enabled ? "enabled" : "disabled")); + _hyperion->getComponentRegister().componentStateChanged(component, _forwarder_enabled); + } +} + +void MessageForwarder::handlePriorityChanges(const quint8 &priority) +{ + const QJsonObject obj = _hyperion->getSetting(settings::NETFORWARD).object(); + if (priority != 0 && _forwarder_enabled && obj["enable"].toBool()) + { + _protoSlaves.clear(); + while (!_forwardClients.isEmpty()) + delete _forwardClients.takeFirst(); + + hyperion::Components activePrio = _hyperion->getPriorityInfo(priority).componentId; + if (activePrio == hyperion::COMP_GRABBER || activePrio == hyperion::COMP_V4L) + { + if ( !obj["proto"].isNull() ) + { + const QJsonArray & addr = obj["proto"].toArray(); + for (const auto& entry : addr) + { + addProtoSlave(entry.toString()); + } + } + connect(_hyperion, &Hyperion::forwardProtoMessage, this, &MessageForwarder::forwardProtoMessage, Qt::UniqueConnection); + } + else + disconnect(_hyperion, &Hyperion::forwardProtoMessage, 0, 0); + } +} + void MessageForwarder::addJsonSlave(QString slave) { QStringList parts = slave.split(":"); @@ -70,14 +148,15 @@ void MessageForwarder::addJsonSlave(QString slave) } // verify loop with jsonserver - const QJsonObject& obj = _hyperion->getSetting(settings::JSONSERVER).object(); + const QJsonObject &obj = _hyperion->getSetting(settings::JSONSERVER).object(); if(QHostAddress(parts[0]) == QHostAddress::LocalHost && parts[1].toInt() == obj["port"].toInt()) { Error(_log, "Loop between JsonServer and Forwarder! (%s)",QSTRING_CSTR(slave)); return; } - _jsonSlaves << slave; + if (_forwarder_enabled) + _jsonSlaves << slave; } void MessageForwarder::addProtoSlave(QString slave) @@ -98,21 +177,91 @@ void MessageForwarder::addProtoSlave(QString slave) } // verify loop with protoserver - const QJsonObject& obj = _hyperion->getSetting(settings::FLATBUFSERVER).object(); + const QJsonObject &obj = _hyperion->getSetting(settings::FLATBUFSERVER).object(); if(QHostAddress(parts[0]) == QHostAddress::LocalHost && parts[1].toInt() == obj["port"].toInt()) { Error(_log, "Loop between ProtoServer and Forwarder! (%s)",QSTRING_CSTR(slave)); return; } - _protoSlaves << slave; + + if (_forwarder_enabled) + { + _protoSlaves << slave; + FlatBufferConnection* flatbuf = new FlatBufferConnection("Message Forwarder", slave.toLocal8Bit().constData(), _priority, true); + _forwardClients << flatbuf; + } } -bool MessageForwarder::protoForwardingEnabled() +void MessageForwarder::forwardJsonMessage(const QJsonObject &message) { - return ! _protoSlaves.empty(); + if (_forwarder_enabled) + { + QTcpSocket client; + for (int i=0; i<_jsonSlaves.size(); i++) + { + QStringList parts = _jsonSlaves.at(i).split(":"); + client.connectToHost(QHostAddress(parts[0]), parts[1].toUShort()); + if ( client.waitForConnected(500) ) + { + sendJsonMessage(message,&client); + client.close(); + } + } + } } -bool MessageForwarder::jsonForwardingEnabled() +void MessageForwarder::forwardProtoMessage(const Image &image) { - return ! _jsonSlaves.empty(); + if (_forwarder_enabled) + { + for (int i=0; i < _forwardClients.size(); i++) + { + _forwardClients.at(i)->setRegister("Message Forwarder", _priority); + _forwardClients.at(i)->setImage(image); + } + } +} + +void MessageForwarder::sendJsonMessage(const QJsonObject &message, QTcpSocket *socket) +{ + // for hyperion classic compatibility + QJsonObject jsonMessage = message; + if (jsonMessage.contains("tan") && jsonMessage["tan"].isNull()) + jsonMessage["tan"] = 100; + + // serialize message + QJsonDocument writer(jsonMessage); + QByteArray serializedMessage = writer.toJson(QJsonDocument::Compact) + "\n"; + + // write message + socket->write(serializedMessage); + if (!socket->waitForBytesWritten()) + { + Debug(_log, "Error while writing data to host"); + return; + } + + // read reply data + QByteArray serializedReply; + while (!serializedReply.contains('\n')) + { + // receive reply + if (!socket->waitForReadyRead()) + { + Debug(_log, "Error while writing data from host"); + return; + } + + serializedReply += socket->readAll(); + } + + // parse reply data + QJsonParseError error; + QJsonDocument reply = QJsonDocument::fromJson(serializedReply ,&error); + + if (error.error != QJsonParseError::NoError) + { + Error(_log, "Error while parsing reply: invalid json"); + return; + } } diff --git a/libsrc/hyperion/PriorityMuxer.cpp b/libsrc/hyperion/PriorityMuxer.cpp index c348a7c3..b22a1800 100644 --- a/libsrc/hyperion/PriorityMuxer.cpp +++ b/libsrc/hyperion/PriorityMuxer.cpp @@ -108,11 +108,6 @@ void PriorityMuxer::updateLedColorsLength(const int& ledCount) } } -int PriorityMuxer::getCurrentPriority() const -{ - return _currentPriority; -} - QList PriorityMuxer::getPriorities() const { return _activeInputs.keys(); @@ -299,7 +294,7 @@ void PriorityMuxer::setCurrentTime(void) else { // timeoutTime of -100 is awaiting data (inactive); skip - if(infoIt->timeoutTime_ms >= -1) + if(infoIt->timeoutTime_ms >= -100) newPriority = qMin(newPriority, infoIt->priority); // call timeTrigger when effect or color is running with timeout > 0, blacklist prio 255 diff --git a/libsrc/hyperion/schema/schema-smoothing.json b/libsrc/hyperion/schema/schema-smoothing.json index bf7d6e29..9e3f64ad 100644 --- a/libsrc/hyperion/schema/schema-smoothing.json +++ b/libsrc/hyperion/schema/schema-smoothing.json @@ -17,7 +17,8 @@ "enum" : ["linear"], "default" : "linear", "options" : { - "enum_titles" : ["edt_conf_enum_linear"] + "enum_titles" : ["edt_conf_enum_linear"], + "hidden":true }, "propertyOrder" : 2 }, diff --git a/libsrc/jsonserver/JsonServer.cpp b/libsrc/jsonserver/JsonServer.cpp index ffea30d7..4b671d87 100644 --- a/libsrc/jsonserver/JsonServer.cpp +++ b/libsrc/jsonserver/JsonServer.cpp @@ -114,43 +114,3 @@ void JsonServer::closedConnection(void) // schedule to delete the connection object connection->deleteLater(); } - -void JsonServer::sendMessage(const QJsonObject & message, QTcpSocket * socket) -{ - // serialize message - QJsonDocument writer(message); - QByteArray serializedMessage = writer.toJson(QJsonDocument::Compact) + "\n"; - - // write message - socket->write(serializedMessage); - if (!socket->waitForBytesWritten()) - { - Debug(_log, "Error while writing data to host"); - return; - } - - // read reply data - QByteArray serializedReply; - while (!serializedReply.contains('\n')) - { - // receive reply - if (!socket->waitForReadyRead()) - { - Debug(_log, "Error while writing data from host"); - return; - } - - serializedReply += socket->readAll(); - } - - // parse reply data - QJsonParseError error; - QJsonDocument reply = QJsonDocument::fromJson(serializedReply ,&error); - - if (error.error != QJsonParseError::NoError) - { - Error(_log, "Error while parsing reply: invalid json"); - return; - } - -} diff --git a/libsrc/leddevice/CMakeLists.txt b/libsrc/leddevice/CMakeLists.txt index eb82a123..885db01f 100755 --- a/libsrc/leddevice/CMakeLists.txt +++ b/libsrc/leddevice/CMakeLists.txt @@ -27,6 +27,11 @@ FILE ( GLOB Leddevice_SOURCES "${CURRENT_SOURCE_DIR}/dev_other/*.cpp" ) +if ( ENABLE_OSX ) + list(REMOVE_ITEM Leddevice_SOURCES "${CURRENT_SOURCE_DIR}/dev_other/LedDevicePiBlaster.h") + list(REMOVE_ITEM Leddevice_SOURCES "${CURRENT_SOURCE_DIR}/dev_other/LedDevicePiBlaster.cpp") +endif() + if ( ENABLE_USB_HID ) find_package(libusb-1.0 REQUIRED) include_directories( diff --git a/libsrc/udplistener/UDPListener.cpp b/libsrc/udplistener/UDPListener.cpp index 498ead9f..60c4e3cb 100644 --- a/libsrc/udplistener/UDPListener.cpp +++ b/libsrc/udplistener/UDPListener.cpp @@ -80,7 +80,7 @@ void UDPListener::stop() _server->close(); _isActive = false; Info(_log, "Stopped"); - emit clearGlobalPriority(_priority, hyperion::COMP_UDPLISTENER); +// emit clearGlobalPriority(_priority, hyperion::COMP_UDPLISTENER); } void UDPListener::componentStateChanged(const hyperion::Components component, bool enable) diff --git a/src/hyperiond/hyperiond.cpp b/src/hyperiond/hyperiond.cpp index 9b8a8a7a..95852546 100644 --- a/src/hyperiond/hyperiond.cpp +++ b/src/hyperiond/hyperiond.cpp @@ -171,6 +171,8 @@ void HyperionDaemon::freeObjects() _fbGrabber = nullptr; _osxGrabber = nullptr; _qtGrabber = nullptr; + _flatBufferServer = nullptr; + _ssdp = nullptr; _webserver = nullptr; _jsonServer = nullptr; _udpListener = nullptr; diff --git a/test/TestImage2LedsMap.cpp b/test/TestImage2LedsMap.cpp index 65c725f1..aa80926c 100644 --- a/test/TestImage2LedsMap.cpp +++ b/test/TestImage2LedsMap.cpp @@ -4,11 +4,9 @@ #include // Hyperion includes -#include +#include #include -using namespace hyperion; - int main() { QString homeDir = getenv("RASPILIGHT_HOME"); @@ -23,12 +21,12 @@ int main() return -1; } - const LedString ledString = Hyperion::createLedString(config["leds"], Hyperion::createColorOrder(config["device"].toObject())); + const LedString ledString = hyperion::createLedString(config["leds"].toArray(), hyperion::createColorOrder(config["device"].toObject())); const ColorRgb testColor = {64, 123, 12}; Image image(64, 64, testColor); - ImageToLedsMap map(64, 64, 0, 0, ledString.leds()); + hyperion::ImageToLedsMap map(64, 64, 0, 0, ledString.leds()); std::vector ledColors(ledString.leds().size()); map.getMeanLedColor(image, ledColors);