Changed bootsequence to use the effect engine exclusively

Former-commit-id: 8953ef5fb4a0dfd12a4d94f69af6dbdd40aa20f7
This commit is contained in:
johan 2013-12-01 16:35:45 +01:00
parent 9954cb3e0d
commit 068a98b84f
15 changed files with 96 additions and 330 deletions

View File

@ -33,6 +33,9 @@ public slots:
/// Run the specified effect on the given priority channel and optionally specify a timeout
int runEffect(const std::string &effectName, const Json::Value & args, int priority, int timeout = -1);
/// Run the specified effect on the given priority channel and optionally specify a timeout
int runEffectScript(const std::string &script, const Json::Value & args, int priority, int timeout = -1);
/// Clear any effect running on the provided channel
void channelCleared(int priority);

View File

@ -158,10 +158,18 @@ public slots:
/// 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 timout The timeout of the effect (after the timout, the effect will be cleared)
int setEffect(const std::string & effectName, const Json::Value & args, int priority, int timeout = -1);
/// Run the specified effect script on the given priority channel and optionally specify a timeout
/// @param script path of the effect script
/// @param args arguments of the effect script
/// @param priority The priority channel of the effect
/// @param timout The timeout of the effect (after the timout, the effect will be cleared)
int setEffectScript(const std::string &script, const Json::Value &args, int priority, int timeout);
public:
static LedDevice * createDevice(const Json::Value & deviceConfig);
static ColorOrder createColorOrder(const Json::Value & deviceConfig);

View File

@ -1,35 +0,0 @@
#include "AbstractBootSequence.h"
AbstractBootSequence::AbstractBootSequence(Hyperion * hyperion, const int64_t interval, const unsigned iterationCnt) :
_timer(),
_hyperion(hyperion),
_priority(0),
_iterationCounter(iterationCnt)
{
_timer.setInterval(interval);
_timer.setSingleShot(false);
QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
}
void AbstractBootSequence::start()
{
_timer.start();
}
void AbstractBootSequence::update()
{
if (_iterationCounter == 0)
{
_timer.stop();
_hyperion->clear(_priority);
return;
}
// Obtain the next led-colors from the child-class
const std::vector<ColorRgb>& colors = nextColors();
// Write the colors to hyperion
_hyperion->setColors(_priority, colors, -1);
// Decrease the loop count
--_iterationCounter;
}

View File

@ -1,62 +0,0 @@
#pragma once
// QT includes
#include <QTimer>
// Bootsequence includes
#include <bootsequence/BootSequence.h>
// Hyperion includes
#include <hyperion/Hyperion.h>
///
/// The AbstractBootSequence is an 'abstract' implementation of the BootSequence that handles the
/// event generation and Hyperion connection. Subclasses only need to specify the interval and
/// return the colors for the leds for each iteration.
///
class AbstractBootSequence : public QObject, public BootSequence
{
Q_OBJECT
public:
///
/// Constructs the AbstractBootSequence with the given parameters
///
/// @param hyperion The Hyperion instance
/// @param interval The interval between new led colors
/// @param iterationCnt The number of iteration performed by the boot sequence
///
AbstractBootSequence(Hyperion * hyperion, const int64_t interval, const unsigned iterationCnt);
///
/// Starts the boot-sequence
///
virtual void start();
protected slots:
///
/// Timer slot for handling each interval of the boot-sequence
///
void update();
protected:
///
/// Child-classes must implement this by returning the next led colors in the sequence
///
/// @return The next led colors in the boot sequence
///
virtual const std::vector<ColorRgb>& nextColors() = 0;
private:
/// The timer used to generate an 'update' signal every interval
QTimer _timer;
/// The Hyperion instance
Hyperion * _hyperion;
/// The priority of the boot sequence
int _priority;
/// The counter of the number of iterations left
int _iterationCounter;
};

View File

@ -6,31 +6,12 @@
#include <bootsequence/BootSequenceFactory.h>
// Local Bootsequence includes
#include "RainbowBootSequence.h"
#include "KittBootSequence.h"
#include "EffectBootSequence.h"
BootSequence * BootSequenceFactory::createBootSequence(Hyperion * hyperion, const Json::Value & jsonConfig)
{
std::string type = jsonConfig["type"].asString();
std::transform(type.begin(), type.end(), type.begin(), ::tolower);
if (type == "none")
{
return nullptr;
}
else if (type == "rainbow")
{
std::cout << "SELECTED BOOT SEQUENCE: " << "RAINBOW" << std::endl;
const unsigned duration_ms = jsonConfig["duration_ms"].asUInt();
return new RainbowBootSequence(hyperion, duration_ms);
}
else if (type == "knightrider" || type == "knight rider" || "knight_rider")
{
std::cout << "SELECTED BOOT SEQUENCE: " << "KITT" << std::endl;
const unsigned duration_ms = jsonConfig["duration_ms"].asUInt();
return new KittBootSequence(hyperion, duration_ms);
}
std::cerr << "Unknown boot-sequence selected; boot-sequence disabled." << std::endl;
return nullptr;
const std::string script = jsonConfig["script"].asString();
const Json::Value args = jsonConfig.get("args", Json::Value(Json::objectValue));
const unsigned duration = jsonConfig["duration_ms"].asUInt();
return new EffectBootSequence(hyperion, script, args, duration);
}

View File

@ -4,30 +4,19 @@ SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/bootsequence)
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/bootsequence)
# Group the headers that go through the MOC compiler
SET(BootsequenceQT_HEADERS
${CURRENT_SOURCE_DIR}/AbstractBootSequence.h
)
SET(BootsequenceHEADERS
${CURRENT_HEADER_DIR}/BootSequence.h
${CURRENT_HEADER_DIR}/BootSequenceFactory.h
${CURRENT_SOURCE_DIR}/RainbowBootSequence.h
${CURRENT_SOURCE_DIR}/KittBootSequence.h
${CURRENT_SOURCE_DIR}/EffectBootSequence.h
)
SET(BootsequenceSOURCES
${CURRENT_SOURCE_DIR}/AbstractBootSequence.cpp
${CURRENT_SOURCE_DIR}/BootSequenceFactory.cpp
${CURRENT_SOURCE_DIR}/RainbowBootSequence.cpp
${CURRENT_SOURCE_DIR}/KittBootSequence.cpp
${CURRENT_SOURCE_DIR}/EffectBootSequence.cpp
)
QT4_WRAP_CPP(BootsequenceHEADERS_MOC ${BootsequenceQT_HEADERS})
add_library(bootsequence
${BootsequenceHEADERS}
${BootsequenceQT_HEADERS}
${BootsequenceHEADERS_MOC}
${BootsequenceSOURCES}
)

View File

@ -0,0 +1,19 @@
#include "EffectBootSequence.h"
EffectBootSequence::EffectBootSequence(Hyperion *hyperion, const std::string &script, const Json::Value &args, const unsigned duration_ms) :
BootSequence(),
_hyperion(hyperion),
_script(script),
_args(args),
_duration_ms(duration_ms)
{
}
EffectBootSequence::~EffectBootSequence()
{
}
void EffectBootSequence::start()
{
_hyperion->setEffectScript(_script, _args, 0, _duration_ms);
}

View File

@ -0,0 +1,40 @@
#pragma once
// Bootsequence include
#include <bootsequence/BootSequence.h>
// Hyperion includes
#include <hyperion/Hyperion.h>
///
/// The EffectBootSequence runs a script using the effect engine at startup
///
class EffectBootSequence : public BootSequence
{
public:
///
/// Constructs the effect boot-sequence. The effect engine is used for executing the boot effect. The given
/// duration is the length the effect will run.
///
/// @param[in] hyperion The Hyperion instance
/// @param[in] duration_ms The length of the sequence [ms]
///
EffectBootSequence(Hyperion * hyperion, const std::string & script, const Json::Value & args, const unsigned duration_ms);
virtual ~EffectBootSequence();
virtual void start();
private:
/// The Hyperion instance
Hyperion * _hyperion;
/// The script to execute
const std::string _script;
/// The arguments of the script
const Json::Value _args;
/// Duration of the boot sequence
const unsigned _duration_ms;
};

View File

@ -1,67 +0,0 @@
// Hyperion includes
#include <hyperion/ImageProcessorFactory.h>
// Local-Bootsequence includes
#include "KittBootSequence.h"
KittBootSequence::KittBootSequence(Hyperion * hyperion, const unsigned duration_ms) :
AbstractBootSequence(hyperion, 100, duration_ms/100),
_processor(ImageProcessorFactory::getInstance().newImageProcessor()),
_image(9, 1, ColorRgb{0,0,0}),
_ledColors(hyperion->getLedCount(), ColorRgb{0,0,0}),
_forwardMove(false),
_currentLight(0)
{
// empty
}
KittBootSequence::~KittBootSequence()
{
delete _processor;
}
const std::vector<ColorRgb>& KittBootSequence::nextColors()
{
// Switch the previous light 'off'
_image(_currentLight, 0) = ColorRgb{0,0,0};
// Move the current to the next light
moveNextLight();
// Switch the current light 'on'
_image(_currentLight, 0) = ColorRgb{255,0,0};
// Translate the 'image' to led colors
_processor->process(_image, _ledColors);
// Return the colors
return _ledColors;
}
void KittBootSequence::moveNextLight()
{
// Increase/Decrease the current light
if (_forwardMove)
{
++_currentLight;
if (_currentLight == _image.width())
{
_forwardMove = false;
--_currentLight;
}
}
else
{
if (_currentLight == 0)
{
_forwardMove = true;
}
else
{
--_currentLight;
}
}
}

View File

@ -1,56 +0,0 @@
#pragma once
// Bootsequence includes
#include "AbstractBootSequence.h"
// Hyperion includes
#include <hyperion/Hyperion.h>
#include <hyperion/ImageProcessor.h>
///
/// The KITT BootSequence is a boot sequence inspired by the Knight Rider car: Knight Industries Two
/// Thousand (aka KITT)
///
class KittBootSequence : public AbstractBootSequence
{
public:
///
/// Constructs the KITT BootSequence
///
/// @param[in] hyperion The Hyperion instance
/// @param[in] duration_ms The length of the sequence [ms]
///
KittBootSequence(Hyperion * hyperion, const unsigned duration_ms);
///
/// Destructor, deletes the processor
///
virtual ~KittBootSequence();
///
/// Returns the next led color sequence
///
/// @return The next colors for the leds
///
virtual const std::vector<ColorRgb>& nextColors();
private:
/// Image processor to compute led-colors from the image
ImageProcessor * _processor;
/// 1D-Image of the KITT-grill contains a single red pixel and the rest black
Image<ColorRgb> _image;
/// The vector with led-colors
std::vector<ColorRgb> _ledColors;
/// Direction the red-light is currently moving
bool _forwardMove = true;
/// The location of the current red-light
unsigned _currentLight = 0;
/// Moves the current light to the next (increase or decrease depending on direction)
void moveNextLight();
};

View File

@ -1,30 +0,0 @@
// Utils includes
#include <utils/HsvTransform.h>
// Local-Bootsequence include
#include "RainbowBootSequence.h"
RainbowBootSequence::RainbowBootSequence(Hyperion * hyperion, const unsigned duration_ms) :
AbstractBootSequence(hyperion, duration_ms/hyperion->getLedCount(), hyperion->getLedCount()),
_ledColors(hyperion->getLedCount())
{
for (unsigned iLed=0; iLed<hyperion->getLedCount(); ++iLed)
{
ColorRgb& color = _ledColors[iLed];
HsvTransform::hsv2rgb(iLed*360/hyperion->getLedCount(), 255, 255, color.red, color.green, color.blue);
}
}
const std::vector<ColorRgb>& RainbowBootSequence::nextColors()
{
// Rotate the colors left
const ColorRgb headColor = _ledColors.front();
for (unsigned i=1; i<_ledColors.size(); ++i)
{
_ledColors[i-1] = _ledColors[i];
}
_ledColors.back() = headColor;
return _ledColors;
}

View File

@ -1,38 +0,0 @@
#pragma once
// QT includes
#include <QTimer>
// Bootsequence include
#include "AbstractBootSequence.h"
///
/// The RainborBootSequence shows a 'rainbow' (all lights have a different color). The rainbow is
/// rotated over each led during the length of the sequence.
///
class RainbowBootSequence : public AbstractBootSequence
{
public:
///
/// Constructs the rainbow boot-sequence. Hyperion is used for writing the led colors. The given
/// duration is the length of the sequence.
///
/// @param[in] hyperion The Hyperion instance
/// @param[in] duration_ms The length of the sequence [ms]
///
RainbowBootSequence(Hyperion * hyperion, const unsigned duration_ms);
protected:
///
/// Moves the rainbow one led further
///
const std::vector<ColorRgb>& nextColors();
private:
/// The current color of the boot sequence (the rainbow)
std::vector<ColorRgb> _ledColors;
/// The counter of the number of iterations left
int _iterationCounter;
};

View File

@ -73,11 +73,16 @@ int EffectEngine::runEffect(const std::string &effectName, const Json::Value &ar
return -1;
}
return runEffectScript(effectDefinition->script, args.isNull() ? effectDefinition->args : args, priority, timeout);
}
int EffectEngine::runEffectScript(const std::string &script, const Json::Value &args, int priority, int timeout)
{
// clear current effect on the channel
channelCleared(priority);
// create the effect
Effect * effect = new Effect(priority, timeout, effectDefinition->script, args.isNull() ? effectDefinition->args : args);
Effect * effect = new Effect(priority, timeout, script, args);
connect(effect, SIGNAL(setColors(int,std::vector<ColorRgb>,int)), _hyperion, SLOT(setColors(int,std::vector<ColorRgb>,int)), Qt::QueuedConnection);
connect(effect, SIGNAL(effectFinished(Effect*)), this, SLOT(effectFinished(Effect*)));
_activeEffects.push_back(effect);

View File

@ -481,6 +481,11 @@ int Hyperion::setEffect(const std::string &effectName, const Json::Value &args,
return _effectEngine->runEffect(effectName, args, priority, timeout);
}
int Hyperion::setEffectScript(const std::string &script, const Json::Value &args, int priority, int timeout)
{
return _effectEngine->runEffectScript(script, args, priority, timeout);
}
void Hyperion::update()
{
// Update the muxer, cleaning obsolete priorities

View File

@ -270,13 +270,17 @@
"type" : "object",
"required" : false,
"properties" : {
"type" : {
"type" : "string",
"required" : true
},
"duration_ms" : {
"type" : "integer",
"required" : true
},
"script" : {
"type" : "string",
"required" : true
},
"args" : {
"type" : "object",
"required" : false
}
},
"additionalProperties" : false