diff --git a/assets/firmware/arduino/adalight_mega_pwm/hyperion_mega.ino b/assets/firmware/arduino/adalight_mega_pwm/hyperion_mega.ino new file mode 100644 index 00000000..519cdb33 --- /dev/null +++ b/assets/firmware/arduino/adalight_mega_pwm/hyperion_mega.ino @@ -0,0 +1,250 @@ + +#include "FastLED.h" + +#define ANALOG_MODE_AVERAGE 0 +#define ANALOG_MODE_LAST_LED 1 + +/************************************** + S E T U P + + set following values to your needs + **************************************/ + +// Number of leds in your strip. set to 1 and ANALOG_OUTPUT_ENABLED to true to activate analog only +#define NUM_LEDS 100 + +#define LED_TYPE WS2812B // type of your led controller, possible values, see below + +// 3 wire (pwm): NEOPIXEL BTM1829 TM1812 TM1809 TM1804 TM1803 UCS1903 UCS1903B UCS1904 UCS2903 WS2812 WS2852 +// S2812B SK6812 SK6822 APA106 PL9823 WS2811 WS2813 APA104 WS2811_40 GW6205 GW6205_40 LPD1886 LPD1886_8BIT +// 4 wire (spi): LPD8806 WS2801 WS2803 SM16716 P9813 APA102 SK9822 DOTSTAR + +// For 3 wire led stripes line Neopixel/Ws2812, which have a data line, ground, and power, you just need to define DATA_PIN. +// For led chipsets that are SPI based (four wires - data, clock, ground, and power), both defines DATA_PIN and CLOCK_PIN are needed + +// DATA_PIN, or DATA_PIN, CLOCK_PIN +#define LED_PINS MOSI // 3 wire leds +//#define LED_PINS MOSI, SCK // 4 wire leds + +#define COLOR_ORDER GRB // colororder of the stripe, set RGB in hyperion + +#define OFF_TIMEOUT 15000 // ms to switch off after no data was received, set 0 to deactivate + +// analog rgb uni color led stripe - using of hyperion smoothing is recommended +#define ANALOG_MODE ANALOG_MODE_LAST_LED // use ANALOG_MODE_AVERAGE or ANALOG_MODE_LAST_LED + + +// overall color adjustments +#define ANALOG_BRIGHTNESS_RED 255 // maximum brightness for analog 0-255 +#define ANALOG_BRIGHTNESS_GREEN 255 // maximum brightness for analog 0-255 +#define ANALOG_BRIGHTNESS_BLUE 255 // maximum brightness for analog 0-255 + +#define BRIGHTNESS 128 // maximum brightness 0-255 +#define DITHER_MODE BINARY_DITHER // BINARY_DITHER or DISABLE_DITHER +#define COLOR_TEMPERATURE CRGB(255,255,255) // RGB value describing the color temperature +#define COLOR_CORRECTION TypicalLEDStrip // predefined fastled color correction +//#define COLOR_CORRECTION CRGB(255,255,255) // or RGB value describing the color correction + + +// Baudrate, higher rate allows faster refresh rate and more LEDs (defined in /etc/boblight.conf) + #define serialRate 115200 // use 115200 for ftdi based boards +//#define serialRate 460800 // use 115200 for ftdi based boards + +// ATTENTION this pin config is default for atmega328 based arduinos, others might work to +// if you have flickering analog leds this might be caused by unsynced pwm signals +// try other pins is more or less the only thing that helps + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + // 2 3 4 5 6 7 8 9 10 11 12 13 44 45 46 + // R B G R B G R B G R B G R B G + #define ANALOG_PINS_MAX 15 + #define ANALOG_RGB_STRIPES 4 + const byte ANALOG_PINS[ANALOG_PINS_MAX] = {2,4,3,5,7,6,8,10,9,11,13,12,44,46,45}; +#else +// 9 10 11 +// R B G + #define ANALOG_PINS_MAX 3 + #define ANALOG_RGB_STRIPES 1 + const byte ANALOG_PINS[ANALOG_PINS_MAX] = {9,11,10}; +#endif + +/************************************** + A D A L I G H T C O D E + + no user changes needed + **************************************/ + +// Adalight sends a "Magic Word" (defined in /etc/boblight.conf) before sending the pixel data +uint8_t prefix[] = {'A', 'd', 'a'}, hi, lo, chk, i; + +unsigned long endTime; + +// Define the array of leds +CRGB leds[NUM_LEDS]; + +// set rgb to analog led stripe +void showAnalogRGB(const CRGB& led, const short stripeId=-1) { + if (ANALOG_RGB_STRIPES > 0) { + byte r = map(led.r, 0,255,0,ANALOG_BRIGHTNESS_RED); + byte g = map(led.g, 0,255,0,ANALOG_BRIGHTNESS_GREEN); + byte b = map(led.b, 0,255,0,ANALOG_BRIGHTNESS_BLUE); + if (stripeId<0) { + for (byte i=0;i ANALOG_RGB_STRIPES + LEDS.showColor(led); + #endif + showAnalogRGB(led); +} + + +// function to check if serial data is available +// if timeout occured leds switch of, if configured +bool checkIncommingData() { + boolean dataAvailable = true; + while (!Serial.available()) { + if ( OFF_TIMEOUT > 0 && endTime < millis()) { + showColor(CRGB(0,0,0)); // leds off + dataAvailable = false; + endTime = millis() + OFF_TIMEOUT; + } + } + + return dataAvailable; +} + +// main function that setups and runs the code +void setup() { + + // analog output + if (ANALOG_RGB_STRIPES > 0) { + for (byte i=0;i ANALOG_RGB_STRIPES + FastLED.addLeds(leds, ledCount); + #endif + + // color adjustments + FastLED.setBrightness ( BRIGHTNESS ); + FastLED.setTemperature( COLOR_TEMPERATURE ); + FastLED.setCorrection ( COLOR_CORRECTION ); + FastLED.setDither ( DITHER_MODE ); + + // initial RGB flash + showColor(CRGB(255, 0, 0)); delay(400); + showColor(CRGB(0, 255, 0)); delay(400); + showColor(CRGB(0, 0, 255)); delay(400); + showColor(CRGB(0, 0, 0)); + + Serial.begin(serialRate); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB + } + Serial.print("Ada\n"); // Send "Magic Word" string to host + + boolean transmissionSuccess; + unsigned long sum_r, sum_g, sum_b; + + // loop() is avoided as even that small bit of function overhead + // has a measurable impact on this code's overall throughput. + while (true) { + // wait for first byte of Magic Word + for (i = 0; i < sizeof prefix; ++i) { + // If next byte is not in Magic Word, the start over + if (!checkIncommingData() || prefix[i] != Serial.read()) { + i = 0; + } + } + // Hi, Lo, Checksum + if (!checkIncommingData()) continue; + hi = Serial.read(); + if (!checkIncommingData()) continue; + lo = Serial.read(); + if (!checkIncommingData()) continue; + chk = Serial.read(); + + // if checksum does not match go back to wait + if (chk != (hi ^ lo ^ 0x55)) continue; + + memset(leds, 0, NUM_LEDS * sizeof(struct CRGB)); + transmissionSuccess = true; + sum_r = 0; + sum_g = 0; + sum_b = 0; + + // read the transmission data and set LED values + for (uint8_t idx = 0; idx < NUM_LEDS; idx++) { + byte r, g, b; + if (!checkIncommingData()) { + transmissionSuccess = false; + break; + } + r = Serial.read(); + if (!checkIncommingData()) { + transmissionSuccess = false; + break; + } + g = Serial.read(); + if (!checkIncommingData()) { + transmissionSuccess = false; + break; + } + b = Serial.read(); + leds[idx].r = r; + leds[idx].g = g; + leds[idx].b = b; + #if ANALOG_OUTPUT_ENABLED == true && ANALOG_MODE == ANALOG_MODE_AVERAGE + sum_r += r; + sum_g += g; + sum_b += b; + #endif + } + + // shows new values + if (transmissionSuccess) { + endTime = millis() + OFF_TIMEOUT; + #if NUM_LEDS > ANALOG_RGB_STRIPES + FastLED.show(); + #endif + + #if ANALOG_RGB_STRIPES > 0 + #if ANALOG_MODE == ANALOG_MODE_LAST_LED + for ( byte x=1; x<=ANALOG_RGB_STRIPES; x++) { + showAnalogRGB(leds[NUM_LEDS-x], x-1); + } + #else + showAnalogRGB(CRGB(sum_r/NUM_LEDS, sum_g/NUM_LEDS, sum_b/NUM_LEDS)); + #endif + #endif + } + } +} // end of setup + + +void loop() { + // Not used. See note in setup() function. +} + diff --git a/include/boblightserver/BoblightServer.h b/include/boblightserver/BoblightServer.h index 647f889f..42ed587c 100644 --- a/include/boblightserver/BoblightServer.h +++ b/include/boblightserver/BoblightServer.h @@ -87,5 +87,5 @@ private: /// state of connection bool _isActive; - uint16_t _port; + uint16_t _port; }; diff --git a/include/effectengine/EffectEngine.h b/include/effectengine/EffectEngine.h index 6fcf3808..0a070d9e 100644 --- a/include/effectengine/EffectEngine.h +++ b/include/effectengine/EffectEngine.h @@ -45,13 +45,10 @@ public: 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) - { - return runEffect(effectName, QJsonObject(), priority, timeout); - }; + int runEffect(const QString &effectName, int priority, int timeout = -1, const QString &origin="System"); /// Run the specified effect on the given priority channel and optionally specify a timeout - int runEffect(const QString &effectName, const QJsonObject & args, int priority, int timeout = -1, QString pythonScript = ""); + int runEffect(const QString &effectName, const QJsonObject & args, int priority, int timeout = -1, const QString &pythonScript = "", const QString &origin = "System"); /// Clear any effect running on the provided channel void channelCleared(int priority); @@ -68,7 +65,7 @@ private: bool loadEffectSchema(const QString & path, const QString & effectSchemaFile, EffectSchema &effectSchema); /// Run the specified effect on the given priority channel and optionally specify a timeout - int runEffectScript(const QString &script, const QString &name, const QJsonObject & args, int priority, int timeout = -1); + int runEffectScript(const QString &script, const QString &name, const QJsonObject & args, int priority, int timeout = -1, const QString & origin="System"); private: Hyperion * _hyperion; diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index fb492e79..6e817284 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -52,7 +52,7 @@ class Hyperion : public QObject public: /// Type definition of the info structure used by the priority muxer typedef PriorityMuxer::InputInfo InputInfo; - typedef std::map PriorityRegister; + typedef std::map PriorityRegister; /// /// RGB-Color channel enumeration @@ -132,12 +132,13 @@ public: /// 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 std::string name, const int priority); + void registerPriority(const QString &name, const int priority); /// unregister a input source to a priority channel /// @param name uniq name of input source - void unRegisterPriority(const std::string name); + void unRegisterPriority(const QString &name); /// gets current priority register /// @return the priority register @@ -243,14 +244,15 @@ public slots: /// @param effectName Name of the effec to run /// @param priority The priority channel of the effect /// @param timeout The timeout of the effect (after the timout, the effect will be cleared) - int setEffect(const QString & effectName, int priority, int timeout = -1); + int setEffect(const QString & effectName, int priority, int timeout = -1, const QString & origin="System"); /// Run the specified effect on the given priority channel and optionally specify a timeout /// @param effectName Name of the effec to run /// @param args arguments of the effect script /// @param priority The priority channel of the effect /// @param timeout The timeout of the effect (after the timout, the effect will be cleared) - int setEffect(const QString & effectName, const QJsonObject & args, int priority, int timeout = -1, QString pythonScript = ""); + 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); diff --git a/include/udplistener/UDPListener.h b/include/udplistener/UDPListener.h index 6fdec310..2e7c9e64 100644 --- a/include/udplistener/UDPListener.h +++ b/include/udplistener/UDPListener.h @@ -63,7 +63,7 @@ private slots: /// Slot which is called when a client tries to create a new connection /// void readPendingDatagrams(); - void processTheDatagram(const QByteArray * _datagram); + void processTheDatagram(const QByteArray * datagram, const QHostAddress * sender); private: /// Hyperion instance @@ -78,7 +78,7 @@ private: /// hyperion priority int _priority; - /// hyperion priority + /// hyperion timeout int _timeout; /// Logger instance @@ -88,7 +88,7 @@ private: bool _isActive; /// address to bind - QHostAddress _listenAddress; - quint16 _listenPort; + QHostAddress _listenAddress; + quint16 _listenPort; QAbstractSocket::BindFlag _bondage; }; diff --git a/include/utils/Components.h b/include/utils/Components.h index 297a1c63..37165a6e 100644 --- a/include/utils/Components.h +++ b/include/utils/Components.h @@ -18,7 +18,8 @@ enum Components COMP_GRABBER, COMP_V4L, COMP_COLOR, - COMP_EFFECT + COMP_EFFECT, + COMP_PROTOSERVER }; inline const char* componentToString(Components c) @@ -35,6 +36,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_PROTOSERVER: return "Proto Server"; default: return ""; } } @@ -53,6 +55,7 @@ inline const char* componentToIdString(Components c) case COMP_V4L: return "V4L"; case COMP_COLOR: return "COLOR"; case COMP_EFFECT: return "EFFECT"; + case COMP_PROTOSERVER: return "PROTOSERVER"; default: return ""; } } @@ -70,8 +73,9 @@ 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 == "PROTOSERVER") return COMP_PROTOSERVER; return COMP_INVALID; } -} +}; // end of namespace diff --git a/include/utils/Logger.h b/include/utils/Logger.h index 0b1a58b2..504f6901 100644 --- a/include/utils/Logger.h +++ b/include/utils/Logger.h @@ -11,7 +11,7 @@ #include #include - +#include // standard log messages //#define _FUNCNAME_ __PRETTY_FUNCTION__ @@ -99,3 +99,5 @@ protected: QVector _logMessageBuffer; const int _loggerMaxMsgBufferSize; }; + +Q_DECLARE_METATYPE(Logger::T_LOG_MESSAGE); diff --git a/include/utils/global_defines.h b/include/utils/global_defines.h new file mode 100644 index 00000000..eb75d339 --- /dev/null +++ b/include/utils/global_defines.h @@ -0,0 +1,4 @@ +#pragma once + +#define QSTRING_CSTR(str) str.toLocal8Bit().constData() + diff --git a/libsrc/boblightserver/BoblightClientConnection.cpp b/libsrc/boblightserver/BoblightClientConnection.cpp index b8734ea3..17dc3491 100644 --- a/libsrc/boblightserver/BoblightClientConnection.cpp +++ b/libsrc/boblightserver/BoblightClientConnection.cpp @@ -12,6 +12,7 @@ // Qt includes #include #include +#include // hyperion util includes #include "hyperion/ImageProcessorFactory.h" @@ -32,6 +33,7 @@ BoblightClientConnection::BoblightClientConnection(QTcpSocket *socket, const int , _priority(priority) , _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb::BLACK) , _log(Logger::getInstance("BOBLIGHT")) + , _clientAddress(QHostInfo::fromName(socket->peerAddress().toString()).hostName()) { // initalize the locale. Start with the default C-locale _locale.setNumberOptions(QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator); @@ -165,16 +167,16 @@ void BoblightClientConnection::handleMessage(const QString & message) // send current color values to hyperion if this is the last led assuming leds values are send in order of id if ((ledIndex == _ledColors.size() -1) && _priority < 255) { - _hyperion->setColors(_priority, _ledColors, -1, hyperion::COMP_BOBLIGHTSERVER); + _hyperion->setColors(_priority, _ledColors, -1, true, hyperion::COMP_BOBLIGHTSERVER, _clientAddress); } return; } } else if(messageParts[3] == "speed" || - messageParts[3] == "interpolation" || - messageParts[3] == "use" || - messageParts[3] == "singlechange") + messageParts[3] == "interpolation" || + messageParts[3] == "use" || + messageParts[3] == "singlechange") { // these message are ignored by Hyperion return; @@ -203,38 +205,33 @@ void BoblightClientConnection::handleMessage(const QString & message) // send current color values to hyperion if (_priority < 255) { - _hyperion->setColors(_priority, _ledColors, -1, hyperion::COMP_BOBLIGHTSERVER); + _hyperion->setColors(_priority, _ledColors, -1, true, hyperion::COMP_BOBLIGHTSERVER, _clientAddress); } return; } } - Debug(_log, "unknown boblight message: %s", message.toStdString().c_str()); + Debug(_log, "unknown boblight message: %s", QSTRING_CSTR(message)); } -void BoblightClientConnection::sendMessage(const std::string & message) +void BoblightClientConnection::sendMessage(const QByteArray & message) { //std::cout << "send boblight message: " << message; - _socket->write(message.c_str(), message.size()); -} - -void BoblightClientConnection::sendMessage(const char * message, int size) -{ - //std::cout << "send boblight message: " << std::string(message, size); - _socket->write(message, size); + _socket->write(message); } void BoblightClientConnection::sendLightMessage() { char buffer[256]; - int n = snprintf(buffer, sizeof(buffer), "lights %d\n", _hyperion->getLedCount()); - sendMessage(buffer, n); + int n = snprintf(buffer, sizeof(buffer), "lights %d\n", _hyperion->getLedCount()); + sendMessage(QByteArray(buffer, n)); + + double h0, h1, v0, v1; for (unsigned i = 0; i < _hyperion->getLedCount(); ++i) { - double h0, h1, v0, v1; _imageProcessor->getScanParameters(i, h0, h1, v0, v1); n = snprintf(buffer, sizeof(buffer), "light %03d scan %f %f %f %f\n", i, 100*v0, 100*v1, 100*h0, 100*h1); - sendMessage(buffer, n); + sendMessage(QByteArray(buffer, n)); } } diff --git a/libsrc/boblightserver/BoblightClientConnection.h b/libsrc/boblightserver/BoblightClientConnection.h index 6f91060c..d4baffa6 100644 --- a/libsrc/boblightserver/BoblightClientConnection.h +++ b/libsrc/boblightserver/BoblightClientConnection.h @@ -1,8 +1,5 @@ #pragma once -// stl includes -#include - // Qt includes #include #include @@ -65,15 +62,7 @@ private: /// /// @param message The boblight message to send /// - void sendMessage(const std::string &message); - - /// - /// Send a message to the connected client - /// - /// @param message The boblight message to send - /// @param size The size of the message - /// - void sendMessage(const char * message, int size); + void sendMessage(const QByteArray &message); /// /// Send a lights message the to connected client @@ -104,4 +93,7 @@ private: /// logger instance Logger * _log; + + /// address of client + QString _clientAddress; }; diff --git a/libsrc/effectengine/Effect.cpp b/libsrc/effectengine/Effect.cpp index 7d17d0ed..74e17ee9 100644 --- a/libsrc/effectengine/Effect.cpp +++ b/libsrc/effectengine/Effect.cpp @@ -66,7 +66,7 @@ void Effect::registerHyperionExtensionModule() PyImport_AppendInittab("hyperion", &PyInit_hyperion); } -Effect::Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args) +Effect::Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args, const QString & origin) : QThread() , _mainThreadState(mainThreadState) , _priority(priority) @@ -79,6 +79,7 @@ Effect::Effect(PyThreadState * mainThreadState, int priority, int timeout, const , _abortRequested(false) , _imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor()) , _colors() + , _origin(origin) { _colors.resize(_imageProcessor->getLedCount(), ColorRgb::BLACK); @@ -146,7 +147,7 @@ void Effect::run() } else { - Error(Logger::getInstance("EFFECTENGINE"), "Unable to open script file %s", _script.toUtf8().constData()); + Error(Logger::getInstance("EFFECTENGINE"), "Unable to open script file %s.", QSTRING_CSTR(_script)); } file.close(); @@ -265,7 +266,7 @@ PyObject* Effect::wrapSetColor(PyObject *self, PyObject *args) if (PyArg_ParseTuple(args, "bbb", &color.red, &color.green, &color.blue)) { std::fill(effect->_colors.begin(), effect->_colors.end(), color); - effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT); + effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT, effect->_origin); return Py_BuildValue(""); } else @@ -286,7 +287,7 @@ PyObject* Effect::wrapSetColor(PyObject *self, PyObject *args) { char * data = PyByteArray_AS_STRING(bytearray); memcpy(effect->_colors.data(), data, length); - effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT); + effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT, effect->_origin); return Py_BuildValue(""); } else @@ -356,7 +357,7 @@ PyObject* Effect::wrapSetImage(PyObject *self, PyObject *args) memcpy(image.memptr(), data, length); effect->_imageProcessor->process(image, effect->_colors); - effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT); + effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT, effect->_origin); return Py_BuildValue(""); } else @@ -432,7 +433,7 @@ PyObject* Effect::wrapImageShow(PyObject *self, PyObject *args) memcpy(image.memptr(), binaryImage.data(), binaryImage.size()); effect->_imageProcessor->process(image, effect->_colors); - effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT); + effect->setColors(effect->_priority, effect->_colors, timeout, false, hyperion::COMP_EFFECT, effect->_origin); return Py_BuildValue(""); } diff --git a/libsrc/effectengine/Effect.h b/libsrc/effectengine/Effect.h index 0eb3ea08..7fbf26e9 100644 --- a/libsrc/effectengine/Effect.h +++ b/libsrc/effectengine/Effect.h @@ -18,7 +18,7 @@ class Effect : public QThread Q_OBJECT public: - Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args = QJsonObject()); + Effect(PyThreadState * mainThreadState, int priority, int timeout, const QString & script, const QString & name, const QJsonObject & args = QJsonObject(), const QString & origin="System"); virtual ~Effect(); virtual void run(); @@ -43,7 +43,7 @@ public slots: signals: void effectFinished(Effect * effect); - void setColors(int priority, const std::vector &ledColors, const int timeout_ms, bool clearEffects, hyperion::Components component); + void setColors(int priority, const std::vector &ledColors, const int timeout_ms, bool clearEffects, hyperion::Components componentconst, QString origin); private slots: void effectFinished(); @@ -102,5 +102,6 @@ private: QImage * _image; QPainter * _painter; + QString _origin; }; diff --git a/libsrc/effectengine/EffectEngine.cpp b/libsrc/effectengine/EffectEngine.cpp index dd148a61..414e6f19 100644 --- a/libsrc/effectengine/EffectEngine.cpp +++ b/libsrc/effectengine/EffectEngine.cpp @@ -342,11 +342,16 @@ void EffectEngine::readEffects() } } -int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, QString pythonScript) +int EffectEngine::runEffect(const QString &effectName, int priority, int timeout, const QString &origin) +{ + return runEffect(effectName, QJsonObject(), priority, timeout, "", origin); +} + +int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin) { Info( _log, "run effect %s on channel %d", effectName.toUtf8().constData(), priority); - if (pythonScript == "") + if (pythonScript.isEmpty()) { const EffectDefinition * effectDefinition = nullptr; for (const EffectDefinition & e : _availableEffects) @@ -364,24 +369,24 @@ int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, return -1; } - return runEffectScript(effectDefinition->script, effectName, args.isEmpty() ? effectDefinition->args : args, priority, timeout); - } else - return runEffectScript(pythonScript, effectName, args, priority, timeout); + return runEffectScript(effectDefinition->script, effectName, (args.isEmpty() ? effectDefinition->args : args), priority, timeout, origin); + } + return runEffectScript(pythonScript, effectName, args, priority, timeout, origin); } -int EffectEngine::runEffectScript(const QString &script, const QString &name, const QJsonObject &args, int priority, int timeout) +int EffectEngine::runEffectScript(const QString &script, const QString &name, const QJsonObject &args, int priority, int timeout, const QString & origin) { // clear current effect on the channel channelCleared(priority); // create the effect - Effect * effect = new Effect(_mainThreadState, priority, timeout, script, name, args); - connect(effect, SIGNAL(setColors(int,std::vector,int,bool,hyperion::Components)), _hyperion, SLOT(setColors(int,std::vector,int,bool,hyperion::Components)), Qt::QueuedConnection); + Effect * effect = new Effect(_mainThreadState, priority, timeout, script, name, args, origin); + connect(effect, SIGNAL(setColors(int,std::vector,int,bool,hyperion::Components,const QString)), _hyperion, SLOT(setColors(int,std::vector,int,bool,hyperion::Components,const QString)), Qt::QueuedConnection); connect(effect, SIGNAL(effectFinished(Effect*)), this, SLOT(effectFinished(Effect*))); _activeEffects.push_back(effect); // start the effect - _hyperion->registerPriority(name.toStdString(), priority); + _hyperion->registerPriority(name, priority); effect->start(); return 0; @@ -426,5 +431,5 @@ void EffectEngine::effectFinished(Effect *effect) // cleanup the effect effect->deleteLater(); - _hyperion->unRegisterPriority(effect->getName().toStdString()); + _hyperion->unRegisterPriority(effect->getName()); } diff --git a/libsrc/hyperion/GrabberWrapper.cpp b/libsrc/hyperion/GrabberWrapper.cpp index 3647cc03..734fb539 100644 --- a/libsrc/hyperion/GrabberWrapper.cpp +++ b/libsrc/hyperion/GrabberWrapper.cpp @@ -4,7 +4,6 @@ #include #include -#define QSTRING_CSTR(str) str.toLocal8Bit().constData() GrabberWrapper::GrabberWrapper(QString grabberName, const int priority, hyperion::Components grabberComponentId) : _grabberName(grabberName) , _hyperion(Hyperion::getInstance()) @@ -37,7 +36,7 @@ bool GrabberWrapper::start() { // Start the timer with the pre configured interval _timer.start(); - _hyperion->registerPriority(_grabberName.toStdString(), _priority); + _hyperion->registerPriority(_grabberName, _priority); return _timer.isActive(); } @@ -46,7 +45,7 @@ void GrabberWrapper::stop() { // Stop the timer, effectivly stopping the process _timer.stop(); - _hyperion->unRegisterPriority(_grabberName.toStdString()); + _hyperion->unRegisterPriority(_grabberName); } void GrabberWrapper::componentStateChanged(const hyperion::Components component, bool enable) diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index 6fc65b6a..2cf31447 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -504,22 +504,22 @@ bool Hyperion::configWriteable() } -void Hyperion::registerPriority(const std::string name, const int priority) +void Hyperion::registerPriority(const QString &name, const int priority/*, const QString &origin*/) { - Info(_log, "Register new input source named '%s' for priority channel '%d'", name.c_str(), priority ); + Info(_log, "Register new input source named '%s' for priority channel '%d'", QSTRING_CSTR(name), priority ); for(auto const &entry : _priorityRegister) { WarningIf( ( entry.first != name && entry.second == priority), _log, - "Input source '%s' uses same priority channel (%d) as '%s'.", name.c_str(), priority, entry.first.c_str()); + "Input source '%s' uses same priority channel (%d) as '%s'.", QSTRING_CSTR(name), priority, QSTRING_CSTR(entry.first)); } _priorityRegister.emplace(name,priority); } -void Hyperion::unRegisterPriority(const std::string name) +void Hyperion::unRegisterPriority(const QString &name) { - Info(_log, "Unregister input source named '%s' from priority register", name.c_str()); + Info(_log, "Unregister input source named '%s' from priority register", QSTRING_CSTR(name)); _priorityRegister.erase(name); } @@ -688,14 +688,14 @@ const std::list & Hyperion::getEffectSchemas() return _effectEngine->getEffectSchemas(); } -int Hyperion::setEffect(const QString &effectName, int priority, int timeout) +int Hyperion::setEffect(const QString &effectName, int priority, int timeout, const QString & origin) { - return _effectEngine->runEffect(effectName, priority, timeout); + return _effectEngine->runEffect(effectName, priority, timeout, origin); } -int Hyperion::setEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, QString pythonScript) +int Hyperion::setEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString & pythonScript, const QString & origin) { - return _effectEngine->runEffect(effectName, args, priority, timeout, pythonScript); + return _effectEngine->runEffect(effectName, args, priority, timeout, pythonScript, origin); } void Hyperion::setLedMappingType(int mappingType) diff --git a/libsrc/jsonserver/JsonClientConnection.cpp b/libsrc/jsonserver/JsonClientConnection.cpp index c17dd422..84bea379 100644 --- a/libsrc/jsonserver/JsonClientConnection.cpp +++ b/libsrc/jsonserver/JsonClientConnection.cpp @@ -27,6 +27,7 @@ #include #include #include +#include // hyperion util includes #include @@ -57,6 +58,7 @@ JsonClientConnection::JsonClientConnection(QTcpSocket *socket) , _forwarder_enabled(true) , _streaming_logging_activated(false) , _image_stream_timeout(0) + , _clientAddress(socket->peerAddress()) { // connect internal signals and slots connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed())); @@ -365,7 +367,7 @@ void JsonClientConnection::handleColorCommand(const QJsonObject& message, const // extract parameters int priority = message["priority"].toInt(); int duration = message["duration"].toInt(-1); - QString origin = message["origin"].toString(); + QString origin = message["origin"].toString() + "@"+QHostInfo::fromName(_clientAddress.toString()).hostName(); std::vector colorData(_hyperion->getLedCount()); const QJsonArray & jsonColor = message["color"].toArray(); @@ -438,18 +440,19 @@ void JsonClientConnection::handleEffectCommand(const QJsonObject& message, const // extract parameters int priority = message["priority"].toInt(); int duration = message["duration"].toInt(-1); - QString pythonScript = message["pythonScript"].toString(""); + QString pythonScript = message["pythonScript"].toString(); + QString origin = message["origin"].toString() + "@"+_clientAddress.toString(); const QJsonObject & effect = message["effect"].toObject(); const QString & effectName = effect["name"].toString(); // set output if (effect.contains("args")) { - _hyperion->setEffect(effectName, effect["args"].toObject(), priority, duration, pythonScript); + _hyperion->setEffect(effectName, effect["args"].toObject(), priority, duration, pythonScript, origin); } else { - _hyperion->setEffect(effectName, priority, duration); + _hyperion->setEffect(effectName, priority, duration, origin); } // send reply @@ -607,7 +610,7 @@ void JsonClientConnection::handleServerInfoCommand(const QJsonObject&, const QSt { if (entry.second == priority) { - item["owner"] = QString::fromStdString(entry.first); + item["owner"] = entry.first; priorityRegister.erase(entry.first); break; } @@ -665,7 +668,7 @@ void JsonClientConnection::handleServerInfoCommand(const QJsonObject&, const QSt item["priority"] = entry.second; item["active"] = false; item["visible"] = false; - item["owner"] = QString::fromStdString(entry.first); + item["owner"] = entry.first; priorities.append(item); } diff --git a/libsrc/jsonserver/JsonClientConnection.h b/libsrc/jsonserver/JsonClientConnection.h index 5adc067c..7decad84 100644 --- a/libsrc/jsonserver/JsonClientConnection.h +++ b/libsrc/jsonserver/JsonClientConnection.h @@ -7,6 +7,7 @@ #include #include #include +#include // Hyperion includes #include @@ -348,7 +349,10 @@ private: /// timeout for live video refresh volatile qint64 _image_stream_timeout; - + + /// address of client + QHostAddress _clientAddress; + // masks for fields in the basic header static uint8_t const BHB0_OPCODE = 0x0F; static uint8_t const BHB0_RSV3 = 0x10; diff --git a/libsrc/jsonserver/schema/schema-image.json b/libsrc/jsonserver/schema/schema-image.json index 62b0922f..50674717 100644 --- a/libsrc/jsonserver/schema/schema-image.json +++ b/libsrc/jsonserver/schema/schema-image.json @@ -16,6 +16,10 @@ "maximum" : 253, "required": true }, + "origin": { + "type": "string", + "required": true + }, "duration": { "type": "integer", "required": false diff --git a/libsrc/protoserver/ProtoClientConnection.cpp b/libsrc/protoserver/ProtoClientConnection.cpp index 72cb6325..533b918d 100644 --- a/libsrc/protoserver/ProtoClientConnection.cpp +++ b/libsrc/protoserver/ProtoClientConnection.cpp @@ -11,6 +11,7 @@ #include #include #include +#include // hyperion util includes #include "hyperion/ImageProcessorFactory.h" @@ -27,13 +28,13 @@ ProtoClientConnection::ProtoClientConnection(QTcpSocket *socket) , _hyperion(Hyperion::getInstance()) , _receiveBuffer() , _priority(-1) + , _priorityChannelName("Proto-Server") + , _clientAddress(QHostInfo::fromName(socket->peerAddress().toString()).hostName()) { // connect internal signals and slots connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed())); connect(_socket, SIGNAL(readyRead()), this, SLOT(readData())); connect(_hyperion, SIGNAL(imageToLedsMappingChanged(int)), _imageProcessor, SLOT(setLedMappingType(int))); - - _priorityChannelName = "proto@"+ _socket->peerAddress().toString().toStdString(); } ProtoClientConnection::~ProtoClientConnection() @@ -198,7 +199,7 @@ void ProtoClientConnection::handleImageCommand(const proto::ImageRequest &messag // process the image std::vector ledColors = _imageProcessor->process(image); - _hyperion->setColors(_priority, ledColors, duration); + _hyperion->setColors(_priority, ledColors, duration, true, hyperion::COMP_PROTOSERVER , "proto@"+_clientAddress); _hyperion->setImage(_priority, image, duration); // send reply diff --git a/libsrc/protoserver/ProtoClientConnection.h b/libsrc/protoserver/ProtoClientConnection.h index f2777d4c..ce39e734 100644 --- a/libsrc/protoserver/ProtoClientConnection.h +++ b/libsrc/protoserver/ProtoClientConnection.h @@ -7,6 +7,7 @@ #include #include #include +#include // Hyperion includes #include @@ -140,5 +141,8 @@ private: int _priority; - std::string _priorityChannelName; + QString _priorityChannelName; + + /// address of client + QString _clientAddress; }; diff --git a/libsrc/udplistener/UDPListener.cpp b/libsrc/udplistener/UDPListener.cpp index 1a7a98a7..9ebc146f 100644 --- a/libsrc/udplistener/UDPListener.cpp +++ b/libsrc/udplistener/UDPListener.cpp @@ -109,27 +109,29 @@ void UDPListener::readPendingDatagrams() _server->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); - processTheDatagram(&datagram); + processTheDatagram(&datagram, &sender); } } -void UDPListener::processTheDatagram(const QByteArray * datagram) +void UDPListener::processTheDatagram(const QByteArray * datagram, const QHostAddress * sender) { int packetLedCount = datagram->size()/3; int hyperionLedCount = Hyperion::getInstance()->getLedCount(); DebugIf( (packetLedCount != hyperionLedCount), _log, "packetLedCount (%d) != hyperionLedCount (%d)", packetLedCount, hyperionLedCount); - std::vector _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb::BLACK); + std::vector _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb::BLACK); - for (int ledIndex=0; ledIndex < std::min(packetLedCount, hyperionLedCount); ledIndex++) { + for (int ledIndex=0; ledIndex < std::min(packetLedCount, hyperionLedCount); ledIndex++) { ColorRgb & rgb = _ledColors[ledIndex]; - rgb.red = datagram->at(ledIndex*3+0); + rgb.red = datagram->at(ledIndex*3+0); rgb.green = datagram->at(ledIndex*3+1); - rgb.blue = datagram->at(ledIndex*3+2); + rgb.blue = datagram->at(ledIndex*3+2); } - _hyperion->setColors(_priority, _ledColors, _timeout, -1, hyperion::COMP_UDPLISTENER); - + _hyperion->setColors(_priority, _ledColors, _timeout, -1, hyperion::COMP_UDPLISTENER, sender->toString()); } + + + diff --git a/libsrc/utils/CMakeLists.txt b/libsrc/utils/CMakeLists.txt index 9b31f2c1..9aef0dee 100644 --- a/libsrc/utils/CMakeLists.txt +++ b/libsrc/utils/CMakeLists.txt @@ -25,6 +25,7 @@ SET(Utils_HEADERS ${CURRENT_HEADER_DIR}/RgbToRgbw.h ${CURRENT_HEADER_DIR}/jsonschema/QJsonFactory.h ${CURRENT_HEADER_DIR}/jsonschema/QJsonSchemaChecker.h + ${CURRENT_HEADER_DIR}/global_defines.h ) SET(Utils_SOURCES diff --git a/libsrc/utils/Logger.cpp b/libsrc/utils/Logger.cpp index 76e8e74e..3c134538 100644 --- a/libsrc/utils/Logger.cpp +++ b/libsrc/utils/Logger.cpp @@ -18,6 +18,7 @@ LoggerManager* LoggerManager::_instance = nullptr; Logger* Logger::getInstance(QString name, Logger::LogLevel minLevel) { + qRegisterMetaType(); std::string loggerName = name.toStdString(); Logger* log = nullptr; if (LoggerMap == nullptr) diff --git a/src/hyperion-remote/JsonConnection.cpp b/src/hyperion-remote/JsonConnection.cpp index 9f93a539..25b0738e 100644 --- a/src/hyperion-remote/JsonConnection.cpp +++ b/src/hyperion-remote/JsonConnection.cpp @@ -9,6 +9,7 @@ #include #include #include +#include // hyperion-remote includes #include "JsonConnection.h" @@ -51,6 +52,7 @@ void JsonConnection::setColor(std::vector colors, int priority, int dura // create command QJsonObject command; command["command"] = QString("color"); + command["origin"] = QString("hyperion-remote"); command["priority"] = priority; QJsonArray rgbValue; for (const QColor & color : colors) @@ -97,6 +99,7 @@ void JsonConnection::setImage(QImage &image, int priority, int duration) QJsonObject command; command["command"] = QString("image"); command["priority"] = priority; + command["origin"] = QString("hyperion-remote"); command["imagewidth"] = image.width(); command["imageheight"] = image.height(); command["imagedata"] = QString(base64Image.data()); @@ -119,6 +122,7 @@ void JsonConnection::setEffect(const QString &effectName, const QString & effect // create command QJsonObject command, effect; command["command"] = QString("effect"); + command["origin"] = QString("hyperion-remote"); command["priority"] = priority; effect["name"] = effectName;