From 722d4eb357904ae88d6a3ef72028185f668cf2f8 Mon Sep 17 00:00:00 2001 From: redPanther Date: Sun, 31 Jul 2016 22:21:35 +0200 Subject: [PATCH] Manual input source select via json (#143) * implement manual source select via json interface fix schema error * refactoring * add visible value to all listed prios --- include/hyperion/Hyperion.h | 26 ++++++++++ include/jsonserver/JsonServer.h | 6 +-- libsrc/hyperion/Hyperion.cpp | 33 ++++++++++-- libsrc/hyperion/PriorityMuxer.cpp | 9 ++-- libsrc/hyperion/hyperion.schema.json | 15 ++++-- libsrc/jsonserver/JsonClientConnection.cpp | 51 ++++++++++++++----- libsrc/jsonserver/JsonClientConnection.h | 12 ++++- libsrc/jsonserver/JsonSchemas.qrc | 1 + libsrc/jsonserver/JsonServer.cpp | 15 +++--- .../schema/schema-sourceselect.json | 18 +++++++ libsrc/jsonserver/schema/schema.json | 2 +- src/hyperion-remote/JsonConnection.cpp | 34 +++++++++++-- src/hyperion-remote/JsonConnection.h | 9 ++++ src/hyperion-remote/hyperion-remote.cpp | 24 ++++++--- 14 files changed, 208 insertions(+), 47 deletions(-) create mode 100644 libsrc/jsonserver/schema/schema-sourceselect.json diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index 81420a25..ec1e26b3 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -128,7 +128,22 @@ public: /// @param name uniq name of input source void unRegisterPriority(const std::string name); + /// gets current priority register + /// @return the priority register const PriorityRegister& getPriorityRegister() { return _priorityRegister; } + + /// enable/disable automatic/priorized source selection + /// @param enable the state + void setSourceAutoSelectEnabled(bool enabled); + + /// set current input source to visible + /// @param priority the priority channel which should be vidible + /// @return true if success, false on error + bool setCurrentSourcePriority(int priority ); + + /// gets current state of automatic/priorized source selection + /// @return the state + bool sourceAutoSelectEnabled() { return _sourceAutoSelectEnabled; }; public slots: /// /// Writes a single color to all the leds for the given time and priority @@ -326,7 +341,18 @@ private: /// register of input sources and it's prio channel PriorityRegister _priorityRegister; + /// flag for color transform enable bool _transformEnabled; + + /// flag for color adjustment enable bool _adjustmentEnabled; + + /// flag for color temperature enable bool _temperatureEnabled; + + /// flag indicates state for autoselection of input source + bool _sourceAutoSelectEnabled; + + /// holds the current priority channel that is manualy selected + int _currentSourcePriority; }; diff --git a/include/jsonserver/JsonServer.h b/include/jsonserver/JsonServer.h index 57a47ec8..9cbc3deb 100644 --- a/include/jsonserver/JsonServer.h +++ b/include/jsonserver/JsonServer.h @@ -49,14 +49,12 @@ private slots: void closedConnection(JsonClientConnection * connection); private: - /// Hyperion instance - Hyperion * _hyperion; - /// The TCP server object QTcpServer _server; /// List with open connections QSet _openConnections; - + + /// the logger instance Logger * _log; }; diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index fe65b75d..09fc6546 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -555,6 +555,7 @@ Hyperion::Hyperion(const Json::Value &jsonConfig, const std::string configFile) , _timer() , _log(Logger::getInstance("Core")) , _hwLedCount(_ledString.leds().size()) + , _sourceAutoSelectEnabled(true) { if (!_raw2ledAdjustment->verifyAdjustments()) { @@ -643,6 +644,31 @@ void Hyperion::unRegisterPriority(const std::string name) _priorityRegister.erase(name); } +void Hyperion::setSourceAutoSelectEnabled(bool enabled) +{ + _sourceAutoSelectEnabled = enabled; + if (! _sourceAutoSelectEnabled) + { + setCurrentSourcePriority(_muxer.getCurrentPriority()); + } + DebugIf( !_sourceAutoSelectEnabled, _log, "source auto select is disabled"); + InfoIf(_sourceAutoSelectEnabled, _log, "set current input source to auto select"); +} + +bool Hyperion::setCurrentSourcePriority(int priority ) +{ + bool priorityValid = _muxer.hasPriority(priority); + if (priorityValid) + { + DebugIf(_sourceAutoSelectEnabled, _log, "source auto select is disabled"); + _sourceAutoSelectEnabled = false; + _currentSourcePriority = priority; + Info(_log, "set current input source to priority channel %d", _currentSourcePriority); + } + + return priorityValid; +} + void Hyperion::setColor(int priority, const ColorRgb &color, const int timeout_ms, bool clearEffects) { @@ -758,7 +784,8 @@ void Hyperion::clearall() int Hyperion::getCurrentPriority() const { - return _muxer.getCurrentPriority(); + + return _sourceAutoSelectEnabled || !_muxer.hasPriority(_currentSourcePriority) ? _muxer.getCurrentPriority() : _currentSourcePriority; } QList Hyperion::getActivePriorities() const @@ -797,8 +824,8 @@ void Hyperion::update() _muxer.setCurrentTime(QDateTime::currentMSecsSinceEpoch()); // Obtain the current priority channel - int priority = _muxer.getCurrentPriority(); - const PriorityMuxer::InputInfo & priorityInfo = _muxer.getInputInfo(priority); + int priority = _sourceAutoSelectEnabled || !_muxer.hasPriority(_currentSourcePriority) ? _muxer.getCurrentPriority() : _currentSourcePriority; + const PriorityMuxer::InputInfo & priorityInfo = _muxer.getInputInfo(priority); // copy ledcolors to local buffer _ledBuffer.reserve(_hwLedCount); diff --git a/libsrc/hyperion/PriorityMuxer.cpp b/libsrc/hyperion/PriorityMuxer.cpp index e3c265b1..39718891 100644 --- a/libsrc/hyperion/PriorityMuxer.cpp +++ b/libsrc/hyperion/PriorityMuxer.cpp @@ -6,10 +6,10 @@ // Hyperion includes #include -PriorityMuxer::PriorityMuxer(int ledCount) : - _currentPriority(LOWEST_PRIORITY), - _activeInputs(), - _lowestPriorityInfo() +PriorityMuxer::PriorityMuxer(int ledCount) + : _currentPriority(LOWEST_PRIORITY) + , _activeInputs() + , _lowestPriorityInfo() { _lowestPriorityInfo.priority = LOWEST_PRIORITY; _lowestPriorityInfo.timeoutTime_ms = -1; @@ -46,6 +46,7 @@ const PriorityMuxer::InputInfo& PriorityMuxer::getInputInfo(const int priority) auto elemIt = _activeInputs.find(priority); if (elemIt == _activeInputs.end()) { + std::cout << "error " << priority << std::endl; throw std::runtime_error("HYPERION (prioritymux) ERROR: no such priority"); } return elemIt.value(); diff --git a/libsrc/hyperion/hyperion.schema.json b/libsrc/hyperion/hyperion.schema.json index 227a6f67..b89236f7 100644 --- a/libsrc/hyperion/hyperion.schema.json +++ b/libsrc/hyperion/hyperion.schema.json @@ -58,7 +58,10 @@ "required" : true, "properties": { - "channelAdjustment_enable" : "boolean", + "channelAdjustment_enable" : + { + "type" : "boolean" + }, "channelAdjustment" : { "type" : "array", @@ -173,7 +176,10 @@ "additionalProperties" : false } }, - "temperature_enable" : "boolean", + "temperature_enable" : + { + "type" : "boolean" + }, "temperature" : { "type" : "array", @@ -228,7 +234,10 @@ "additionalProperties" : false } }, - "transform_enable" : "boolean", + "transform_enable" : + { + "type" : "boolean" + }, "transform" : { "type" : "array", diff --git a/libsrc/jsonserver/JsonClientConnection.cpp b/libsrc/jsonserver/JsonClientConnection.cpp index c67e65a5..1f9f070c 100644 --- a/libsrc/jsonserver/JsonClientConnection.cpp +++ b/libsrc/jsonserver/JsonClientConnection.cpp @@ -27,14 +27,14 @@ // project includes #include "JsonClientConnection.h" -JsonClientConnection::JsonClientConnection(QTcpSocket *socket, Hyperion * hyperion) : - QObject(), - _socket(socket), - _imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor()), - _hyperion(hyperion), - _receiveBuffer(), - _webSocketHandshakeDone(false), - _log(Logger::getInstance("JSONCLIENTCONNECTION")) +JsonClientConnection::JsonClientConnection(QTcpSocket *socket) + : QObject() + , _socket(socket) + , _imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor()) + , _hyperion(Hyperion::getInstance()) + , _receiveBuffer() + , _webSocketHandshakeDone(false) + , _log(Logger::getInstance("JSONCLIENTCONNECTION")) { // connect internal signals and slots connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed())); @@ -256,6 +256,8 @@ void JsonClientConnection::handleMessage(const std::string &messageString) handleTemperatureCommand(message); else if (command == "adjustment") handleAdjustmentCommand(message); + else if (command == "sourceselect") + handleSourceSelectCommand(message); else handleNotImplemented(); } @@ -388,7 +390,7 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &) uint64_t now = QDateTime::currentMSecsSinceEpoch(); QList activePriorities = _hyperion->getActivePriorities(); Hyperion::PriorityRegister priorityRegister = _hyperion->getPriorityRegister(); - + int currentPriority = _hyperion->getCurrentPriority(); foreach (int priority, activePriorities) { const Hyperion::InputInfo & priorityInfo = _hyperion->getPriorityInfo(priority); Json::Value & item = priorities[priorities.size()]; @@ -399,7 +401,8 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &) } item["owner"] = "unknown"; - item["active"] = "true"; + item["active"] = true; + item["visible"] = (priority == currentPriority); foreach(auto const &entry, priorityRegister) { if (entry.second == priority) @@ -414,7 +417,8 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &) { Json::Value & item = priorities[priorities.size()]; item["priority"] = entry.second; - item["active"] = "false"; + item["active"] = false; + item["visible"] = false; item["owner"] = entry.first; } @@ -773,7 +777,30 @@ void JsonClientConnection::handleAdjustmentCommand(const Json::Value &message) sendSuccessReply(); } - + +void JsonClientConnection::handleSourceSelectCommand(const Json::Value & message) +{ + bool success = false; + if (message.get("auto",false).asBool()) + { + _hyperion->setSourceAutoSelectEnabled(true); + success = true; + } + else if (message.isMember("priority")) + { + success = _hyperion->setCurrentSourcePriority(message["priority"].asInt()); + } + + if (success) + { + sendSuccessReply(); + } + else + { + sendErrorReply("setting current priority failed"); + } +} + void JsonClientConnection::handleNotImplemented() { sendErrorReply("Command not implemented"); diff --git a/libsrc/jsonserver/JsonClientConnection.h b/libsrc/jsonserver/JsonClientConnection.h index bc809725..12080ddd 100644 --- a/libsrc/jsonserver/JsonClientConnection.h +++ b/libsrc/jsonserver/JsonClientConnection.h @@ -32,7 +32,7 @@ public: /// @param socket The Socket object for this connection /// @param hyperion The Hyperion server /// - JsonClientConnection(QTcpSocket * socket, Hyperion * hyperion); + JsonClientConnection(QTcpSocket * socket); /// /// Destructor @@ -128,6 +128,13 @@ private: /// void handleAdjustmentCommand(const Json::Value & message); + /// + /// Handle an incoming JSON SourceSelect message + /// + /// @param message the incoming message + /// + void handleSourceSelectCommand(const Json::Value & message); + /// /// Handle an incoming JSON message of unknown type /// @@ -195,6 +202,7 @@ private: /// used for WebSocket detection and connection handling bool _webSocketHandshakeDone; - + + /// the logger instance Logger * _log; }; diff --git a/libsrc/jsonserver/JsonSchemas.qrc b/libsrc/jsonserver/JsonSchemas.qrc index 6556bf32..a61322d3 100644 --- a/libsrc/jsonserver/JsonSchemas.qrc +++ b/libsrc/jsonserver/JsonSchemas.qrc @@ -11,5 +11,6 @@ schema/schema-temperature.json schema/schema-adjustment.json schema/schema-effect.json + schema/schema-sourceselect.json diff --git a/libsrc/jsonserver/JsonServer.cpp b/libsrc/jsonserver/JsonServer.cpp index 41ff0c67..c6ef055d 100644 --- a/libsrc/jsonserver/JsonServer.cpp +++ b/libsrc/jsonserver/JsonServer.cpp @@ -5,19 +5,18 @@ #include #include "JsonClientConnection.h" -JsonServer::JsonServer(uint16_t port) : - QObject(), - _hyperion(Hyperion::getInstance()), - _server(), - _openConnections(), - _log(Logger::getInstance("JSONSERVER")) +JsonServer::JsonServer(uint16_t port) + : QObject() + , _server() + , _openConnections() + , _log(Logger::getInstance("JSONSERVER")) { if (!_server.listen(QHostAddress::Any, port)) { throw std::runtime_error("JSONSERVER ERROR: could not bind to port"); } - QList list = _hyperion->getForwarder()->getJsonSlaves(); + QList list = Hyperion::getInstance()->getForwarder()->getJsonSlaves(); for ( int i=0; i ('d', "duration" , "Specify how long the leds should be switched on in millseconds [default: infinity]"); ColorParameter & argColor = parameters.add ('c', "color" , "Set all leds to a constant color (either RRGGBB hex value or a color name. The color may be repeated multiple time like: RRGGBBRRGGBB)"); ImageParameter & argImage = parameters.add ('i', "image" , "Set the leds to the colors according to the given image file"); - StringParameter & argEffect = parameters.add ('e', "effect" , "Enable the effect with the given name"); + StringParameter & argEffect = parameters.add ('e', "effect" , "Enable the effect with the given name"); StringParameter & argEffectArgs = parameters.add (0x0, "effectArgs", "Arguments to use in combination with the specified effect. Should be a Json object string."); SwitchParameter<> & argServerInfo = parameters.add >('l', "list" , "List server info and active effects with priority and duration"); SwitchParameter<> & argClear = parameters.add >('x', "clear" , "Clear data for the priority channel provided by the -p option"); @@ -65,8 +65,8 @@ int main(int argc, char * argv[]) DoubleParameter & argSaturation = parameters.add ('s', "saturation", "!DEPRECATED! Will be removed soon! Set the HSV saturation gain of the leds"); DoubleParameter & argValue = parameters.add ('v', "value" , "!DEPRECATED! Will be removed soon! Set the HSV value gain of the leds"); DoubleParameter & argSaturationL = parameters.add ('u', "saturationL", "Set the HSL saturation gain of the leds"); - DoubleParameter & argLuminance = parameters.add ('m', "luminance" , "Set the HSL luminance gain of the leds"); - DoubleParameter & argLuminanceMin = parameters.add ('n', "luminanceMin" , "Set the HSL luminance minimum of the leds (backlight)"); + DoubleParameter & argLuminance = parameters.add ('m', "luminance" , "Set the HSL luminance gain of the leds"); + DoubleParameter & argLuminanceMin= parameters.add ('n', "luminanceMin" , "Set the HSL luminance minimum of the leds (backlight)"); TransformParameter & argGamma = parameters.add('g', "gamma" , "Set the gamma of the leds (requires 3 space seperated values)"); TransformParameter & argThreshold = parameters.add('t', "threshold" , "Set the threshold of the leds (requires 3 space seperated values between 0.0 and 1.0)"); TransformParameter & argBlacklevel = parameters.add('b', "blacklevel", "!DEPRECATED! Will be removed soon! Set the blacklevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)"); @@ -74,13 +74,15 @@ int main(int argc, char * argv[]) SwitchParameter<> & argPrint = parameters.add >(0x0, "print" , "Print the json input and output messages on stdout"); SwitchParameter<> & argHelp = parameters.add >('h', "help" , "Show this help message and exit"); StringParameter & argIdC = parameters.add ('y', "qualifier" , "!DEPRECATED! Will be removed soon! Identifier(qualifier) of the correction to set"); - CorrectionParameter & argCorrection = parameters.add('Y', "correction" , "!DEPRECATED! Will be removed soon! Set the correction of the leds (requires 3 space seperated values between 0 and 255)"); + CorrectionParameter & argCorrection= parameters.add('Y', "correction" , "!DEPRECATED! Will be removed soon! Set the correction of the leds (requires 3 space seperated values between 0 and 255)"); StringParameter & argIdT = parameters.add ('z', "qualifier" , "Identifier(qualifier) of the temperature correction to set"); - CorrectionParameter & argTemperature = parameters.add('Z', "temperature" , "Set the temperature correction of the leds (requires 3 space seperated values between 0 and 255)"); - StringParameter & argIdA = parameters.add ('j', "qualifier" , "Identifier(qualifier) of the adjustment to set"); + CorrectionParameter & argTemperature= parameters.add('Z', "temperature" , "Set the temperature correction of the leds (requires 3 space seperated values between 0 and 255)"); + StringParameter & argIdA = parameters.add ('j', "qualifier" , "Identifier(qualifier) of the adjustment to set"); AdjustmentParameter & argRAdjust = parameters.add('R', "redAdjustment" , "Set the adjustment of the red color (requires 3 space seperated values between 0 and 255)"); AdjustmentParameter & argGAdjust = parameters.add('G', "greenAdjustment", "Set the adjustment of the green color (requires 3 space seperated values between 0 and 255)"); AdjustmentParameter & argBAdjust = parameters.add('B', "blueAdjustment", "Set the adjustment of the blue color (requires 3 space seperated values between 0 and 255)"); + IntParameter & argSource = parameters.add (0x0, "sourceSelect" , "Set current active priority channel and deactivate auto source switching"); + SwitchParameter<> & argSourceAuto = parameters.add >(0x0, "sourceAutoSelect", "Enables auto source, if disabled prio by manual selecting input source"); // set the default values argAddress.setDefault(defaultServerAddress.toStdString()); @@ -104,7 +106,7 @@ int main(int argc, char * argv[]) bool colorModding = colorTransform || colorAdjust || argCorrection.isSet() || argTemperature.isSet(); // check that exactly one command was given - int commandCount = count({argColor.isSet(), argImage.isSet(), argEffect.isSet(), argServerInfo.isSet(), argClear.isSet(), argClearAll.isSet(), colorModding}); + int commandCount = count({argColor.isSet(), argImage.isSet(), argEffect.isSet(), argServerInfo.isSet(), argClear.isSet(), argClearAll.isSet(), colorModding, argSource.isSet(), argSourceAuto.isSet()}); if (commandCount != 1) { std::cerr << (commandCount == 0 ? "No command found." : "Multiple commands found.") << " Provide exactly one of the following options:" << std::endl; @@ -165,6 +167,14 @@ int main(int argc, char * argv[]) { connection.clearAll(); } + else if (argSource.isSet()) + { + connection.setSource(argSource.getValue()); + } + else if (argSourceAuto.isSet()) + { + connection.setSourceAutoSelect(); + } else if (colorModding) { if (argCorrection.isSet())