Added skeleton for effect engine development

Former-commit-id: e1fb69fd4de4b8968075660e3ba7f7add021c152
This commit is contained in:
johan 2013-11-24 16:10:48 +01:00
parent 333cecdca8
commit 5454ddb375
19 changed files with 304 additions and 12 deletions

View File

@ -0,0 +1,29 @@
#pragma once
#include <hyperion/Hyperion.h>
class EffectEngine : public QObject
{
Q_OBJECT
public:
EffectEngine(Hyperion * hyperion);
virtual ~EffectEngine();
std::list<std::string> getEffects() const;
public slots:
/// Run the specified effect on the given priority channel and optionally specify a timeout
int runEffect(const std::string &effectName, int priority, int timeout = -1);
/// Clear any effect running on the provided channel
void channelCleared(int priority);
/// Clear all effects
void allChannelsCleared();
private:
Hyperion * _hyperion;
std::map<std::string, std::string> _availableEffects;
};

View File

@ -18,6 +18,7 @@
// Forward class declaration
class HsvTransform;
class ColorTransform;
class EffectEngine;
///
/// The main class of Hyperion. This gives other 'users' access to the attached LedDevice through
@ -141,6 +142,17 @@ public:
///
const InputInfo& getPriorityInfo(const int priority) const;
/// Get the list of available effects
/// @return The list of available effects
std::list<std::string> 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
/// @param timout The timeout of the effect (after the timout, the effect will be cleared)
int setEffect(const std::string & effectName, int priority, int timeout = -1);
public:
static LedDevice * createDevice(const Json::Value & deviceConfig);
static ColorOrder createColorOrder(const Json::Value & deviceConfig);
static LedString createLedString(const Json::Value & ledsConfig);
@ -148,6 +160,15 @@ public:
static ColorTransform * createColorTransform(const Json::Value & colorConfig);
static LedDevice * createColorSmoothing(const Json::Value & smoothingConfig, LedDevice * ledDevice);
signals:
/// Signal which is emitted when a priority channel is actively cleared
/// This signal will not be emitted when a priority channel time out
void channelCleared(int priority);
/// Signal which is emitted when all priority channels are actively cleared
/// This signal will not be emitted when a priority channel time out
void allChannelsCleared();
private slots:
///
/// Updates the priority muxer with the current time and (re)writes the led color with applied
@ -185,6 +206,9 @@ private:
/// The actual LedDevice
LedDevice * _device;
/// Effect engine
EffectEngine * _effectEngine;
/// The timer for handling priority channel timeouts
QTimer _timer;
};

View File

@ -10,6 +10,7 @@ add_subdirectory(protoserver)
add_subdirectory(boblightserver)
add_subdirectory(utils)
add_subdirectory(xbmcvideochecker)
add_subdirectory(effectengine)
if (ENABLE_DISPMANX)
add_subdirectory(dispmanx-grabber)

View File

@ -0,0 +1,31 @@
# Define the current source locations
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/effectengine)
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/effectengine)
# Group the headers that go through the MOC compiler
SET(EffectEngineQT_HEADERS
${CURRENT_HEADER_DIR}/EffectEngine.h
${CURRENT_SOURCE_DIR}/Effect.h
)
SET(EffectEngineHEADERS
)
SET(EffectEngineSOURCES
${CURRENT_SOURCE_DIR}/EffectEngine.cpp
${CURRENT_SOURCE_DIR}/Effect.cpp
)
QT4_WRAP_CPP(EffectEngineHEADERS_MOC ${EffectEngineQT_HEADERS})
add_library(effectengine
${EffectEngineHEADERS}
${EffectEngineQT_HEADERS}
${EffectEngineHEADERS_MOC}
${EffectEngineSOURCES}
)
target_link_libraries(effectengine
hyperion
${QT_LIBRARIES})

View File

@ -0,0 +1,10 @@
#include "Effect.h"
Effect::Effect()
{
}
Effect::~Effect()
{
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <QObject>
class Effect : public QObject
{
Q_OBJECT
public:
Effect();
virtual ~Effect();
};

View File

@ -0,0 +1,42 @@
#include <effectengine/EffectEngine.h>
EffectEngine::EffectEngine(Hyperion * hyperion) :
_hyperion(hyperion),
_availableEffects()
{
// connect the Hyperion channel clear feedback
connect(_hyperion, SIGNAL(channelCleared(int)), this, SLOT(channelCleared(int)));
connect(_hyperion, SIGNAL(allChannelsCleared()), this, SLOT(allChannelsCleared()));
// read all effects
_availableEffects["test"] = "test.py";
}
EffectEngine::~EffectEngine()
{
}
std::list<std::string> EffectEngine::getEffects() const
{
std::list<std::string> effectNames;
foreach (auto entry, _availableEffects) {
effectNames.push_back(entry.first);
}
return effectNames;
}
int EffectEngine::runEffect(const std::string &effectName, int priority, int timeout)
{
std::cout << "run effect " << effectName << " on channel " << priority << std::endl;
return 0;
}
void EffectEngine::channelCleared(int priority)
{
std::cout << "clear effect on channel " << priority << std::endl;
}
void EffectEngine::allChannelsCleared()
{
std::cout << "clear effect on every channel" << std::endl;
}

View File

@ -77,6 +77,7 @@ add_library(hyperion
target_link_libraries(hyperion
hyperion-utils
effectengine
serialport
${QT_LIBRARIES}
${LIBUSB_1_LIBRARIES}

View File

@ -27,6 +27,9 @@
#include <utils/ColorTransform.h>
#include <utils/HsvTransform.h>
// effect engine includes
#include <effectengine/EffectEngine.h>
LedDevice* Hyperion::createDevice(const Json::Value& deviceConfig)
{
std::cout << "Device configuration: " << deviceConfig << std::endl;
@ -252,6 +255,7 @@ Hyperion::Hyperion(const Json::Value &jsonConfig) :
_blueTransform(createColorTransform(jsonConfig["color"]["blue"])),
_colorOrder(createColorOrder(jsonConfig["device"])),
_device(createDevice(jsonConfig["device"])),
_effectEngine(nullptr),
_timer()
{
// initialize the image processor factory
@ -264,6 +268,9 @@ Hyperion::Hyperion(const Json::Value &jsonConfig) :
_timer.setSingleShot(true);
QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
// create the effect engine
_effectEngine = new EffectEngine(this);
// initialize the leds
update();
}
@ -275,6 +282,9 @@ Hyperion::~Hyperion()
clearall();
_device->switchOff();
// delete the effect engine
delete _effectEngine;
// Delete the Led-String
delete _device;
@ -382,6 +392,9 @@ void Hyperion::clear(int priority)
{
update();
}
// send clear signal to the effect engine
_effectEngine->channelCleared(priority);
}
}
@ -391,6 +404,9 @@ void Hyperion::clearall()
// update leds
update();
// send clearall signal to the effect engine
_effectEngine->allChannelsCleared();
}
double Hyperion::getTransform(Hyperion::Transform transform, Hyperion::Color color) const
@ -448,6 +464,16 @@ const Hyperion::InputInfo &Hyperion::getPriorityInfo(const int priority) const
return _muxer.getInputInfo(priority);
}
std::list<std::string> Hyperion::getEffects() const
{
return _effectEngine->getEffects();
}
int Hyperion::setEffect(const std::string &effectName, int priority, int timeout)
{
return _effectEngine->runEffect(effectName, priority, timeout);
}
void Hyperion::update()
{
// Update the muxer, cleaning obsolete priorities

View File

@ -94,6 +94,8 @@ void JsonClientConnection::handleMessage(const std::string &messageString)
handleColorCommand(message);
else if (command == "image")
handleImageCommand(message);
else if (command == "effect")
handleEffectCommand(message);
else if (command == "serverinfo")
handleServerInfoCommand(message);
else if (command == "clear")
@ -151,7 +153,22 @@ void JsonClientConnection::handleImageCommand(const Json::Value &message)
sendSuccessReply();
}
void JsonClientConnection::handleServerInfoCommand(const Json::Value &message)
void JsonClientConnection::handleEffectCommand(const Json::Value &message)
{
// extract parameters
int priority = message["priority"].asInt();
int duration = message.get("duration", -1).asInt();
const Json::Value & effect = message["effect"];
const std::string & effectName = effect["name"].asString();
// set output
_hyperion->setEffect(effectName, priority, duration);
// send reply
sendSuccessReply();
}
void JsonClientConnection::handleServerInfoCommand(const Json::Value &)
{
// create result
Json::Value result;
@ -193,6 +210,17 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &message)
whitelevel.append(_hyperion->getTransform(Hyperion::WHITELEVEL, Hyperion::GREEN));
whitelevel.append(_hyperion->getTransform(Hyperion::WHITELEVEL, Hyperion::BLUE));
// collect effect info
Json::Value & effects = info["effects"];
std::list<std::string> effectNames = _hyperion->getEffects();
for (const std::string & name : effectNames)
{
Json::Value effect;
effect["name"] = name;
effects.append(effect);
}
// send the result
sendMessage(result);
}

View File

@ -78,6 +78,13 @@ private:
///
void handleImageCommand(const Json::Value & message);
///
/// Handle an incoming JSON Effect message
///
/// @param message the incoming message
///
void handleEffectCommand(const Json::Value & message);
///
/// Handle an incoming JSON Server info message
///

View File

@ -7,5 +7,6 @@
<file alias="schema-clear">schema/schema-clear.json</file>
<file alias="schema-clearall">schema/schema-clearall.json</file>
<file alias="schema-transform">schema/schema-transform.json</file>
<file alias="schema-effect">schema/schema-effect.json</file>
</qresource>
</RCC>

View File

@ -0,0 +1,31 @@
{
"type":"object",
"required":true,
"properties":{
"command": {
"type" : "string",
"required" : true,
"enum" : ["effect"]
},
"priority": {
"type": "integer",
"required": true
},
"duration": {
"type": "integer",
"required": false
},
"effect": {
"type": "object",
"required": true,
"properties" :{
"name" : {
"type" : "string",
"required" : true
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}

View File

@ -5,7 +5,7 @@
"command": {
"type" : "string",
"required" : true,
"enum" : ["color", "image", "serverinfo", "clear", "clearall", "transform"]
"enum" : ["color", "image", "effect", "serverinfo", "clear", "clearall", "transform"]
}
}
}

View File

@ -102,6 +102,27 @@ void JsonConnection::setImage(QImage image, int priority, int duration)
parseReply(reply);
}
void JsonConnection::setEffect(const std::string &effectName, int priority, int duration)
{
std::cout << "Start effect " << effectName << std::endl;
// create command
Json::Value command;
command["command"] = "effect";
command["priority"] = priority;
Json::Value & effect = command["effect"];
effect["name"] = effectName;
if (duration > 0)
{
command["duration"] = duration;
}
// send command message
Json::Value reply = sendMessage(command);
// parse reply message
parseReply(reply);
}
QString JsonConnection::getServerInfo()
{

View File

@ -52,6 +52,15 @@ public:
///
void setImage(QImage image, int priority, int duration);
///
/// Start the given effect
///
/// @param effect The name of the effect
/// @param priority The priority
/// @param duration The duration in milliseconds
///
void setEffect(const std::string & effectName, int priority, int duration);
///
/// Retrieve a list of all occupied priority channels
///

View File

@ -42,6 +42,7 @@ int main(int argc, char * argv[])
IntParameter & argDuration = parameters.add<IntParameter> ('d', "duration" , "Specify how long the leds should be switched on in millseconds [default: infinity]");
ColorParameter & argColor = parameters.add<ColorParameter> ('c', "color" , "Set all leds to a constant color (either RRGGBB hex value or a color name)");
ImageParameter & argImage = parameters.add<ImageParameter> ('i', "image" , "Set the leds to the colors according to the given image file");
StringParameter & argEffect = parameters.add<StringParameter> ('e', "effect" , "Enable the effect with the given name");
SwitchParameter<> & argServerInfo = parameters.add<SwitchParameter<> >('l', "list" , "List server info");
SwitchParameter<> & argClear = parameters.add<SwitchParameter<> >('x', "clear" , "Clear data for the priority channel provided by the -p option");
SwitchParameter<> & argClearAll = parameters.add<SwitchParameter<> >(0x0, "clearall" , "Clear data for all active priority channels");
@ -73,12 +74,13 @@ int main(int argc, char * argv[])
bool colorTransform = argSaturation.isSet() || argValue.isSet() || argThreshold.isSet() || argGamma.isSet() || argBlacklevel.isSet() || argWhitelevel.isSet();
// check that exactly one command was given
int commandCount = count({argColor.isSet(), argImage.isSet(), argServerInfo.isSet(), argClear.isSet(), argClearAll.isSet(), colorTransform});
int commandCount = count({argColor.isSet(), argImage.isSet(), argEffect.isSet(), argServerInfo.isSet(), argClear.isSet(), argClearAll.isSet(), colorTransform});
if (commandCount != 1)
{
std::cerr << (commandCount == 0 ? "No command found." : "Multiple commands found.") << " Provide exactly one of the following options:" << std::endl;
std::cerr << " " << argColor.usageLine() << std::endl;
std::cerr << " " << argImage.usageLine() << std::endl;
std::cerr << " " << argEffect.usageLine() << std::endl;
std::cerr << " " << argServerInfo.usageLine() << std::endl;
std::cerr << " " << argClear.usageLine() << std::endl;
std::cerr << " " << argClearAll.usageLine() << std::endl;
@ -104,6 +106,10 @@ int main(int argc, char * argv[])
{
connection.setImage(argImage.getValue(), argPriority.getValue(), argDuration.getValue());
}
else if (argEffect.isSet())
{
connection.setEffect(argEffect.getValue(), argPriority.getValue(), argDuration.getValue());
}
else if (argServerInfo.isSet())
{
QString info = connection.getServerInfo();

View File

@ -6,6 +6,7 @@ target_link_libraries(hyperiond
bootsequence
hyperion
xbmcvideochecker
effectengine
jsonserver
protoserver
boblightserver)

View File

@ -26,6 +26,9 @@
// XBMC Video checker includes
#include <xbmcvideochecker/XBMCVideoChecker.h>
// Effect engine includes
#include <effectengine/EffectEngine.h>
// JsonServer includes
#include <jsonserver/JsonServer.h>
@ -150,6 +153,13 @@ 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"))
@ -187,8 +197,10 @@ int main(int argc, char** argv)
delete dispmanx;
#endif
delete xbmcVideoChecker;
delete effectEngine;
delete jsonServer;
delete protoServer;
delete boblightServer;
// leave application
return rc;