From 3bd1789c4290a52cdf3be6f4ad738184abcb9b97 Mon Sep 17 00:00:00 2001 From: johan Date: Fri, 29 Nov 2013 23:22:49 +0100 Subject: [PATCH] Fix bug: Only 1 EffectEngine allowed; SetColors implemented for EffectEngine Former-commit-id: ae8141ebd530b7735ffa7818dc3c690913769070 --- include/effectengine/EffectEngine.h | 3 + include/hyperion/Hyperion.h | 69 ++++++------ libsrc/effectengine/Effect.cpp | 102 +++++++++++++++++- libsrc/effectengine/Effect.h | 4 +- libsrc/effectengine/EffectEngine.cpp | 18 ++-- libsrc/hyperion/Hyperion.cpp | 8 +- libsrc/utils/jsonschema/JsonSchemaChecker.cpp | 4 +- src/hyperiond/hyperiond.cpp | 8 -- 8 files changed, 157 insertions(+), 59 deletions(-) diff --git a/include/effectengine/EffectEngine.h b/include/effectengine/EffectEngine.h index b3b38a96..f1aa0106 100644 --- a/include/effectengine/EffectEngine.h +++ b/include/effectengine/EffectEngine.h @@ -4,6 +4,7 @@ // pre-declarioation class Effect; +typedef struct _ts PyThreadState; class EffectEngine : public QObject { @@ -34,4 +35,6 @@ private: std::map _availableEffects; std::list _activeEffects; + + PyThreadState * _mainThreadState; }; diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index f03c9db6..46b2245f 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -70,6 +70,41 @@ public: /// unsigned getLedCount() const; + /// + /// Returns the value of a specific color transform + /// + /// @param[in] transform The type of transform + /// @param[in] color The color channel to which the transform applies (only applicable for + /// Transform::THRESHOLD, Transform::GAMMA, Transform::BLACKLEVEL, + /// Transform::WHITELEVEL) + /// + /// @return The value of the specified color transform + /// + double getTransform(Transform transform, Color color) const; + + /// + /// Returns a list of active priorities + /// + /// @return The list with priorities + /// + QList getActivePriorities() const; + + /// + /// Returns the information of a specific priorrity channel + /// + /// @param[in] priority The priority channel + /// + /// @return The information of the given + /// + /// @throw std::runtime_error when the priority channel does not exist + /// + const InputInfo& getPriorityInfo(const int priority) const; + + /// Get the list of available effects + /// @return The list of available effects + std::list getEffects() const; + +public slots: /// /// Writes a single color to all the leds for the given time and priority /// @@ -112,40 +147,6 @@ public: /// void clearall(); - /// - /// Returns the value of a specific color transform - /// - /// @param[in] transform The type of transform - /// @param[in] color The color channel to which the transform applies (only applicable for - /// Transform::THRESHOLD, Transform::GAMMA, Transform::BLACKLEVEL, - /// Transform::WHITELEVEL) - /// - /// @return The value of the specified color transform - /// - double getTransform(Transform transform, Color color) const; - - /// - /// Returns a list of active priorities - /// - /// @return The list with priorities - /// - QList getActivePriorities() const; - - /// - /// Returns the information of a specific priorrity channel - /// - /// @param[in] priority The priority channel - /// - /// @return The information of the given - /// - /// @throw std::runtime_error when the priority channel does not exist - /// - const InputInfo& getPriorityInfo(const int priority) const; - - /// Get the list of available effects - /// @return The list of available effects - std::list getEffects() const; - /// Run the specified effect on the given priority channel and optionally specify a timeout /// @param effectName Name of the effec to run /// @param priority The priority channel of the effect diff --git a/libsrc/effectengine/Effect.cpp b/libsrc/effectengine/Effect.cpp index 7d4184f0..51ec3249 100644 --- a/libsrc/effectengine/Effect.cpp +++ b/libsrc/effectengine/Effect.cpp @@ -43,7 +43,7 @@ void Effect::run() // add methods extra builtin methods to the interpreter PyObject * thisCapsule = PyCapsule_New(this, nullptr, nullptr); PyObject * module = Py_InitModule4("hyperion", effectMethods, nullptr, thisCapsule, PYTHON_API_VERSION); - + // add ledCount variable to the interpreter PyObject_SetAttrString(module, "ledCount", Py_BuildValue("i", _imageProcessor->getLedCount())); @@ -81,14 +81,106 @@ void Effect::effectFinished() PyObject* Effect::wrapSetColor(PyObject *self, PyObject *args) { + // get the effect Effect * effect = getEffect(self); - return Py_BuildValue("i", 42); + + // check if we have aborted already + if (effect->_abortRequested) + { + return Py_BuildValue(""); + } + + // determine the timeout + int timeout = effect->_timeout; + if (timeout > 0) + { + timeout = effect->_endTime - QDateTime::currentMSecsSinceEpoch(); + + // we are done if the time has passed + if (timeout <= 0) + { + return Py_BuildValue(""); + } + } + + // check the number of arguments + int argCount = PyTuple_Size(args); + if (argCount == 3) + { + // three seperate arguments for red, green, and blue + ColorRgb color; + if (PyArg_ParseTuple(args, "bbb", &color.red, &color.green, &color.blue)) + { + effect->setColors(effect->_priority, std::vector(effect->_imageProcessor->getLedCount(), color), timeout); + return Py_BuildValue(""); + } + else + { + return nullptr; + } + } + else if (argCount == 1) + { + // bytearray of values + PyObject * bytearray = nullptr; + if (PyArg_ParseTuple(args, "O", &bytearray)) + { + if (PyByteArray_Check(bytearray)) + { + size_t length = PyByteArray_Size(bytearray); + if (length == 3 * effect->_imageProcessor->getLedCount()) + { + std::vector colors(effect->_imageProcessor->getLedCount()); + char * data = PyByteArray_AS_STRING(bytearray); + for (size_t i = 0; i < colors.size(); ++i) + { + ColorRgb & color = colors[i]; + color.red = data [3*i]; + color.green = data [3*i+1]; + color.blue = data [3*i+2]; + } + effect->setColors(effect->_priority, colors, timeout); + return Py_BuildValue(""); + } + else + { + PyErr_SetString(PyExc_RuntimeError, "Length of bytearray argument should be 3*ledCount"); + return nullptr; + } + } + else + { + PyErr_SetString(PyExc_RuntimeError, "Argument is not a bytearray"); + return nullptr; + } + } + else + { + return nullptr; + } + } + else + { + PyErr_SetString(PyExc_RuntimeError, "Function expect 1 or 3 arguments"); + return nullptr; + } + + // error + PyErr_SetString(PyExc_RuntimeError, "Unknown error"); + return nullptr; } PyObject* Effect::wrapSetImage(PyObject *self, PyObject *args) { Effect * effect = getEffect(self); - return Py_BuildValue("i", 42); + + // check if we have aborted already + if (effect->_abortRequested) + { + return Py_BuildValue(""); + } + + return Py_BuildValue(""); } PyObject* Effect::wrapAbort(PyObject *self, PyObject *) @@ -101,13 +193,13 @@ Effect * Effect::getEffect(PyObject *self) { // Get the effect from the capsule in the self pointer Effect * effect = reinterpret_cast(PyCapsule_GetPointer(self, nullptr)); - + // Test if the effect has reached it end time if (effect->_timeout > 0 && QDateTime::currentMSecsSinceEpoch() > effect->_endTime) { effect->_abortRequested = true; } - + // return the effect return effect; } diff --git a/libsrc/effectengine/Effect.h b/libsrc/effectengine/Effect.h index 1199967e..220ec4a6 100644 --- a/libsrc/effectengine/Effect.h +++ b/libsrc/effectengine/Effect.h @@ -27,6 +27,8 @@ public slots: signals: void effectFinished(Effect * effect); + void setColors(int priority, const std::vector &ledColors, const int timeout_ms); + private slots: void effectFinished(); @@ -42,7 +44,7 @@ private: const int _priority; const int _timeout; - + int64_t _endTime; PyThreadState * _interpreterThreadState; diff --git a/libsrc/effectengine/EffectEngine.cpp b/libsrc/effectengine/EffectEngine.cpp index c34891b0..74fdf6c5 100644 --- a/libsrc/effectengine/EffectEngine.cpp +++ b/libsrc/effectengine/EffectEngine.cpp @@ -1,3 +1,6 @@ +// Qt includes +#include + // Python includes #include @@ -10,8 +13,11 @@ EffectEngine::EffectEngine(Hyperion * hyperion) : _hyperion(hyperion), _availableEffects(), - _activeEffects() + _activeEffects(), + _mainThreadState(nullptr) { + qRegisterMetaType>("std::vector"); + // connect the Hyperion channel clear feedback connect(_hyperion, SIGNAL(channelCleared(int)), this, SLOT(channelCleared(int))); connect(_hyperion, SIGNAL(allChannelsCleared()), this, SLOT(allChannelsCleared())); @@ -23,17 +29,16 @@ EffectEngine::EffectEngine(Hyperion * hyperion) : std::cout << "Initializing Python interpreter" << std::endl; Py_InitializeEx(0); PyEval_InitThreads(); // Create the GIL - //_mainThreadState = PyEval_SaveThread(); - PyEval_ReleaseLock(); // Release the GIL + PyRun_SimpleString("print 'test'"); + _mainThreadState = PyEval_SaveThread(); } EffectEngine::~EffectEngine() { // clean up the Python interpreter std::cout << "Cleaning up Python interpreter" << std::endl; - PyEval_AcquireLock(); // Get the Gil - //PyEval_RestoreThread(_mainThreadState); - //Py_Finalize(); + PyEval_RestoreThread(_mainThreadState); + Py_Finalize(); } std::list EffectEngine::getEffects() const @@ -54,6 +59,7 @@ int EffectEngine::runEffect(const std::string &effectName, int priority, int tim // create the effect Effect * effect = new Effect(priority, timeout); + connect(effect, SIGNAL(setColors(int,std::vector,int)), _hyperion, SLOT(setColors(int,std::vector,int)), Qt::QueuedConnection); connect(effect, SIGNAL(effectFinished(Effect*)), this, SLOT(effectFinished(Effect*))); _activeEffects.push_back(effect); diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index dbb8c991..2ac94674 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -4,6 +4,7 @@ // QT includes #include +#include // JsonSchema include #include @@ -392,10 +393,11 @@ void Hyperion::clear(int priority) { update(); } - - // send clear signal to the effect engine - _effectEngine->channelCleared(priority); } + + // send clear signal to the effect engine + // (outside the check so the effect gets cleared even when the effect is not sending colors) + _effectEngine->channelCleared(priority); } void Hyperion::clearall() diff --git a/libsrc/utils/jsonschema/JsonSchemaChecker.cpp b/libsrc/utils/jsonschema/JsonSchemaChecker.cpp index 2ace25a5..65f9a5c2 100644 --- a/libsrc/utils/jsonschema/JsonSchemaChecker.cpp +++ b/libsrc/utils/jsonschema/JsonSchemaChecker.cpp @@ -164,8 +164,8 @@ void JsonSchemaChecker::checkType(const Json::Value & value, const Json::Value & wrongType = !value.isNull(); else if (type == "any") wrongType = false; - else - assert(false); +// else +// assert(false); if (wrongType) { diff --git a/src/hyperiond/hyperiond.cpp b/src/hyperiond/hyperiond.cpp index 331f5342..ab4932c6 100644 --- a/src/hyperiond/hyperiond.cpp +++ b/src/hyperiond/hyperiond.cpp @@ -153,13 +153,6 @@ int main(int argc, char** argv) } #endif - // Create the effect engine - EffectEngine * effectEngine = nullptr; - if (true) - { - effectEngine = new EffectEngine(&hyperion); - } - // Create Json server if configuration is present JsonServer * jsonServer = nullptr; if (config.isMember("jsonServer")) @@ -197,7 +190,6 @@ int main(int argc, char** argv) delete dispmanx; #endif delete xbmcVideoChecker; - delete effectEngine; delete jsonServer; delete protoServer; delete boblightServer;