mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Merge branch 'HEAD' of https://github.com/tvdzwan/hyperion.git
This commit is contained in:
commit
decc41965d
@ -12,11 +12,14 @@
|
|||||||
},
|
},
|
||||||
"color" :
|
"color" :
|
||||||
{
|
{
|
||||||
|
"hsv" : {
|
||||||
|
"saturationGain" : 1.0,
|
||||||
|
"valueGain" : 1.0
|
||||||
|
},
|
||||||
"red" :
|
"red" :
|
||||||
{
|
{
|
||||||
"threshold" : 0.0,
|
"threshold" : 0.0,
|
||||||
"gamma" : 1.0,
|
"gamma" : 1.0,
|
||||||
"adjust" : 1.0,
|
|
||||||
"blacklevel" : 0.0,
|
"blacklevel" : 0.0,
|
||||||
"whitelevel" : 1.0
|
"whitelevel" : 1.0
|
||||||
},
|
},
|
||||||
@ -24,7 +27,6 @@
|
|||||||
{
|
{
|
||||||
"threshold" : 0.0,
|
"threshold" : 0.0,
|
||||||
"gamma" : 1.0,
|
"gamma" : 1.0,
|
||||||
"adjust" : 1.0,
|
|
||||||
"blacklevel" : 0.0,
|
"blacklevel" : 0.0,
|
||||||
"whitelevel" : 1.0
|
"whitelevel" : 1.0
|
||||||
},
|
},
|
||||||
@ -32,7 +34,6 @@
|
|||||||
{
|
{
|
||||||
"threshold" : 0.0,
|
"threshold" : 0.0,
|
||||||
"gamma" : 1.0,
|
"gamma" : 1.0,
|
||||||
"adjust" : 1.0,
|
|
||||||
"blacklevel" : 0.0,
|
"blacklevel" : 0.0,
|
||||||
"whitelevel" : 1.0
|
"whitelevel" : 1.0
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ public slots:
|
|||||||
private:
|
private:
|
||||||
const int _updateInterval_ms;
|
const int _updateInterval_ms;
|
||||||
const int _timeout_ms;
|
const int _timeout_ms;
|
||||||
|
const int _priority;
|
||||||
|
|
||||||
QTimer _timer;
|
QTimer _timer;
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// stl includes
|
||||||
|
#include <list>
|
||||||
|
|
||||||
// QT includes
|
// QT includes
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
@ -14,13 +16,27 @@
|
|||||||
#include <hyperion/PriorityMuxer.h>
|
#include <hyperion/PriorityMuxer.h>
|
||||||
|
|
||||||
// Forward class declaration
|
// Forward class declaration
|
||||||
namespace hyperion { class ColorTransform; }
|
namespace hyperion {
|
||||||
|
class HsvTransform;
|
||||||
|
class ColorTransform;
|
||||||
|
}
|
||||||
|
|
||||||
class Hyperion : public QObject
|
class Hyperion : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
typedef PriorityMuxer::InputInfo InputInfo;
|
||||||
|
|
||||||
|
enum Color
|
||||||
|
{
|
||||||
|
RED, GREEN, BLUE, INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Transform
|
||||||
|
{
|
||||||
|
SATURATION_GAIN, VALUE_GAIN, THRESHOLD, GAMMA, BLACKLEVEL, WHITELEVEL
|
||||||
|
};
|
||||||
|
|
||||||
static LedString createLedString(const Json::Value& ledsConfig);
|
static LedString createLedString(const Json::Value& ledsConfig);
|
||||||
|
|
||||||
static Json::Value loadConfig(const std::string& configFile);
|
static Json::Value loadConfig(const std::string& configFile);
|
||||||
@ -32,7 +48,21 @@ public:
|
|||||||
|
|
||||||
unsigned getLedCount() const;
|
unsigned getLedCount() const;
|
||||||
|
|
||||||
void setValue(int priority, std::vector<RgbColor> &ledColors, const int timeout_ms);
|
void setColor(int priority, RgbColor &ledColor, const int timeout_ms);
|
||||||
|
|
||||||
|
void setColors(int priority, std::vector<RgbColor> &ledColors, const int timeout_ms);
|
||||||
|
|
||||||
|
void setTransform(Transform transform, Color color, double value);
|
||||||
|
|
||||||
|
void clear(int priority);
|
||||||
|
|
||||||
|
void clearall();
|
||||||
|
|
||||||
|
double getTransform(Transform transform, Color color) const;
|
||||||
|
|
||||||
|
QList<int> getActivePriorities() const;
|
||||||
|
|
||||||
|
const InputInfo& getPriorityInfo(const int priority) const;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void update();
|
void update();
|
||||||
@ -40,15 +70,16 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
void applyTransform(std::vector<RgbColor>& colors) const;
|
void applyTransform(std::vector<RgbColor>& colors) const;
|
||||||
|
|
||||||
LedString mLedString;
|
LedString _ledString;
|
||||||
|
|
||||||
PriorityMuxer mMuxer;
|
PriorityMuxer _muxer;
|
||||||
|
|
||||||
hyperion::ColorTransform* mRedTransform;
|
hyperion::HsvTransform * _hsvTransform;
|
||||||
hyperion::ColorTransform* mGreenTransform;
|
hyperion::ColorTransform * _redTransform;
|
||||||
hyperion::ColorTransform* mBlueTransform;
|
hyperion::ColorTransform * _greenTransform;
|
||||||
|
hyperion::ColorTransform * _blueTransform;
|
||||||
|
|
||||||
LedDevice* mDevice;
|
LedDevice* _device;
|
||||||
|
|
||||||
QTimer _timer;
|
QTimer _timer;
|
||||||
};
|
};
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
#include <hyperion/ImageProcessorFactory.h>
|
#include <hyperion/ImageProcessorFactory.h>
|
||||||
|
|
||||||
// Forward class declaration
|
// Forward class declaration
|
||||||
namespace hyperion { class ImageToLedsMap;
|
namespace hyperion { class ImageToLedsMap; }
|
||||||
class ColorTransform; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ImageProcessor translates an RGB-image to RGB-values for the leds. The processing is
|
* The ImageProcessor translates an RGB-image to RGB-values for the leds. The processing is
|
||||||
|
@ -26,7 +26,7 @@ public:
|
|||||||
std::vector<RgbColor> ledColors;
|
std::vector<RgbColor> ledColors;
|
||||||
};
|
};
|
||||||
|
|
||||||
PriorityMuxer();
|
PriorityMuxer(int ledCount);
|
||||||
|
|
||||||
~PriorityMuxer();
|
~PriorityMuxer();
|
||||||
|
|
||||||
@ -47,9 +47,11 @@ public:
|
|||||||
void setCurrentTime(const int64_t& now);
|
void setCurrentTime(const int64_t& now);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int mCurrentPriority;
|
int _currentPriority;
|
||||||
|
|
||||||
QMap<int, InputInfo> mActiveInputs;
|
QMap<int, InputInfo> _activeInputs;
|
||||||
|
|
||||||
const static int MAX_PRIORITY = std::numeric_limits<int>::max();
|
InputInfo _lowestPriorityInfo;
|
||||||
|
|
||||||
|
const static int LOWEST_PRIORITY = std::numeric_limits<int>::max();
|
||||||
};
|
};
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
DispmanxWrapper::DispmanxWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, Hyperion * hyperion) :
|
DispmanxWrapper::DispmanxWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, Hyperion * hyperion) :
|
||||||
_updateInterval_ms(1000/updateRate_Hz),
|
_updateInterval_ms(1000/updateRate_Hz),
|
||||||
_timeout_ms(2 * _updateInterval_ms),
|
_timeout_ms(2 * _updateInterval_ms),
|
||||||
|
_priority(128),
|
||||||
_timer(),
|
_timer(),
|
||||||
_image(grabWidth, grabHeight),
|
_image(grabWidth, grabHeight),
|
||||||
_frameGrabber(new DispmanxFrameGrabber(grabWidth, grabHeight)),
|
_frameGrabber(new DispmanxFrameGrabber(grabWidth, grabHeight)),
|
||||||
@ -52,8 +53,7 @@ void DispmanxWrapper::action()
|
|||||||
|
|
||||||
_processor->process(_image, _ledColors);
|
_processor->process(_image, _ledColors);
|
||||||
|
|
||||||
const int _priority = 100;
|
_hyperion->setColors(_priority, _ledColors, _timeout_ms);
|
||||||
_hyperion->setValue(_priority, _ledColors, _timeout_ms);
|
|
||||||
}
|
}
|
||||||
void DispmanxWrapper::stop()
|
void DispmanxWrapper::stop()
|
||||||
{
|
{
|
||||||
|
@ -21,6 +21,7 @@ SET(Hyperion_HEADERS
|
|||||||
${CURRENT_SOURCE_DIR}/BlackBorderProcessor.h
|
${CURRENT_SOURCE_DIR}/BlackBorderProcessor.h
|
||||||
${CURRENT_SOURCE_DIR}/BlackBorderDetector.h
|
${CURRENT_SOURCE_DIR}/BlackBorderDetector.h
|
||||||
${CURRENT_SOURCE_DIR}/ColorTransform.h
|
${CURRENT_SOURCE_DIR}/ColorTransform.h
|
||||||
|
${CURRENT_SOURCE_DIR}/HsvTransform.h
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(Hyperion_SOURCES
|
SET(Hyperion_SOURCES
|
||||||
@ -36,6 +37,7 @@ SET(Hyperion_SOURCES
|
|||||||
${CURRENT_SOURCE_DIR}/BlackBorderProcessor.cpp
|
${CURRENT_SOURCE_DIR}/BlackBorderProcessor.cpp
|
||||||
${CURRENT_SOURCE_DIR}/BlackBorderDetector.cpp
|
${CURRENT_SOURCE_DIR}/BlackBorderDetector.cpp
|
||||||
${CURRENT_SOURCE_DIR}/ColorTransform.cpp
|
${CURRENT_SOURCE_DIR}/ColorTransform.cpp
|
||||||
|
${CURRENT_SOURCE_DIR}/HsvTransform.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(Hyperion_RESOURCES
|
set(Hyperion_RESOURCES
|
||||||
|
134
libsrc/hyperion/HsvTransform.cpp
Normal file
134
libsrc/hyperion/HsvTransform.cpp
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#include "HsvTransform.h"
|
||||||
|
|
||||||
|
using namespace hyperion;
|
||||||
|
|
||||||
|
HsvTransform::HsvTransform() :
|
||||||
|
_saturationGain(1.0),
|
||||||
|
_valueGain(1.0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HsvTransform::HsvTransform(double saturationGain, double valueGain) :
|
||||||
|
_saturationGain(saturationGain),
|
||||||
|
_valueGain(valueGain)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HsvTransform::~HsvTransform()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void HsvTransform::setSaturationGain(double saturationGain)
|
||||||
|
{
|
||||||
|
_saturationGain = saturationGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
double HsvTransform::getSaturationGain() const
|
||||||
|
{
|
||||||
|
return _saturationGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HsvTransform::setValueGain(double valueGain)
|
||||||
|
{
|
||||||
|
_valueGain = valueGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
double HsvTransform::getValueGain() const
|
||||||
|
{
|
||||||
|
return _valueGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HsvTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue) const
|
||||||
|
{
|
||||||
|
if (_saturationGain != 1.0 || _valueGain != 1.0)
|
||||||
|
{
|
||||||
|
uint8_t hue, saturation, value;
|
||||||
|
rgb2hsv(red, green, blue, hue, saturation, value);
|
||||||
|
|
||||||
|
int s = saturation * _saturationGain;
|
||||||
|
if (s > 255)
|
||||||
|
saturation = 255;
|
||||||
|
else
|
||||||
|
saturation = s;
|
||||||
|
|
||||||
|
int v = value * _valueGain;
|
||||||
|
if (v > 255)
|
||||||
|
value = 255;
|
||||||
|
else
|
||||||
|
value = v;
|
||||||
|
|
||||||
|
hsv2rgb(hue, saturation, value, red, green, blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HsvTransform::rgb2hsv(uint8_t red, uint8_t green, uint8_t blue, uint8_t & hue, uint8_t & saturation, uint8_t & value)
|
||||||
|
{
|
||||||
|
uint8_t rgbMin, rgbMax;
|
||||||
|
|
||||||
|
rgbMin = red < green ? (red < blue ? red : blue) : (green < blue ? green : blue);
|
||||||
|
rgbMax = red > green ? (red > blue ? red : blue) : (green > blue ? green : blue);
|
||||||
|
|
||||||
|
value = rgbMax;
|
||||||
|
if (value == 0)
|
||||||
|
{
|
||||||
|
hue = 0;
|
||||||
|
saturation = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
saturation = 255 * long(rgbMax - rgbMin) / value;
|
||||||
|
if (saturation == 0)
|
||||||
|
{
|
||||||
|
hue = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rgbMax == red)
|
||||||
|
hue = 0 + 43 * (green - blue) / (rgbMax - rgbMin);
|
||||||
|
else if (rgbMax == green)
|
||||||
|
hue = 85 + 43 * (blue - red) / (rgbMax - rgbMin);
|
||||||
|
else
|
||||||
|
hue = 171 + 43 * (red - green) / (rgbMax - rgbMin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HsvTransform::hsv2rgb(uint8_t hue, uint8_t saturation, uint8_t value, uint8_t & red, uint8_t & green, uint8_t & blue)
|
||||||
|
{
|
||||||
|
uint8_t region, remainder, p, q, t;
|
||||||
|
|
||||||
|
if (saturation == 0)
|
||||||
|
{
|
||||||
|
red = value;
|
||||||
|
green = value;
|
||||||
|
blue = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
region = hue / 43;
|
||||||
|
remainder = (hue - (region * 43)) * 6;
|
||||||
|
|
||||||
|
p = (value * (255 - saturation)) >> 8;
|
||||||
|
q = (value * (255 - ((saturation * remainder) >> 8))) >> 8;
|
||||||
|
t = (value * (255 - ((saturation * (255 - remainder)) >> 8))) >> 8;
|
||||||
|
|
||||||
|
switch (region)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
red = value; green = t; blue = p;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
red = q; green = value; blue = p;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
red = p; green = value; blue = t;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
red = p; green = q; blue = value;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
red = t; green = p; blue = value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
red = value; green = p; blue = q;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
33
libsrc/hyperion/HsvTransform.h
Normal file
33
libsrc/hyperion/HsvTransform.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace hyperion
|
||||||
|
{
|
||||||
|
|
||||||
|
class HsvTransform
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HsvTransform();
|
||||||
|
HsvTransform(double saturationGain, double valueGain);
|
||||||
|
~HsvTransform();
|
||||||
|
|
||||||
|
void setSaturationGain(double saturationGain);
|
||||||
|
double getSaturationGain() const;
|
||||||
|
|
||||||
|
void setValueGain(double valueGain);
|
||||||
|
double getValueGain() const;
|
||||||
|
|
||||||
|
void transform(uint8_t & red, uint8_t & green, uint8_t & blue) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// integer version of the conversion are faster, but a little less accurate
|
||||||
|
static void rgb2hsv(uint8_t red, uint8_t green, uint8_t blue, uint8_t & hue, uint8_t & saturation, uint8_t & value);
|
||||||
|
static void hsv2rgb(uint8_t hue, uint8_t saturation, uint8_t value, uint8_t & red, uint8_t & green, uint8_t & blue);
|
||||||
|
|
||||||
|
private:
|
||||||
|
double _saturationGain;
|
||||||
|
double _valueGain;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace hyperion
|
@ -14,6 +14,7 @@
|
|||||||
#include "LedDeviceWs2801.h"
|
#include "LedDeviceWs2801.h"
|
||||||
#include "LedDeviceTest.h"
|
#include "LedDeviceTest.h"
|
||||||
#include "ColorTransform.h"
|
#include "ColorTransform.h"
|
||||||
|
#include "HsvTransform.h"
|
||||||
|
|
||||||
using namespace hyperion;
|
using namespace hyperion;
|
||||||
|
|
||||||
@ -44,6 +45,11 @@ LedDevice* constructDevice(const Json::Value& deviceConfig)
|
|||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HsvTransform * createHsvTransform(const Json::Value & hsvConfig)
|
||||||
|
{
|
||||||
|
return new HsvTransform(hsvConfig["saturationGain"].asDouble(), hsvConfig["valueGain"].asDouble());
|
||||||
|
}
|
||||||
|
|
||||||
ColorTransform* createColorTransform(const Json::Value& colorConfig)
|
ColorTransform* createColorTransform(const Json::Value& colorConfig)
|
||||||
{
|
{
|
||||||
const double threshold = colorConfig["threshold"].asDouble();
|
const double threshold = colorConfig["threshold"].asDouble();
|
||||||
@ -102,74 +108,221 @@ Hyperion::Hyperion(const std::string& configFile) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
Hyperion::Hyperion(const Json::Value &jsonConfig) :
|
Hyperion::Hyperion(const Json::Value &jsonConfig) :
|
||||||
mLedString(createLedString(jsonConfig["leds"])),
|
_ledString(createLedString(jsonConfig["leds"])),
|
||||||
mRedTransform( createColorTransform(jsonConfig["color"]["red"])),
|
_muxer(_ledString.leds().size()),
|
||||||
mGreenTransform(createColorTransform(jsonConfig["color"]["green"])),
|
_hsvTransform(createHsvTransform(jsonConfig["color"]["hsv"])),
|
||||||
mBlueTransform( createColorTransform(jsonConfig["color"]["blue"])),
|
_redTransform(createColorTransform(jsonConfig["color"]["red"])),
|
||||||
mDevice(constructDevice(jsonConfig["device"])),
|
_greenTransform(createColorTransform(jsonConfig["color"]["green"])),
|
||||||
|
_blueTransform(createColorTransform(jsonConfig["color"]["blue"])),
|
||||||
|
_device(constructDevice(jsonConfig["device"])),
|
||||||
_timer()
|
_timer()
|
||||||
{
|
{
|
||||||
ImageProcessorFactory::getInstance().init(mLedString);
|
ImageProcessorFactory::getInstance().init(_ledString);
|
||||||
|
|
||||||
_timer.setSingleShot(true);
|
_timer.setSingleShot(true);
|
||||||
QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
|
QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
|
||||||
|
|
||||||
|
// initialize the leds
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Hyperion::~Hyperion()
|
Hyperion::~Hyperion()
|
||||||
{
|
{
|
||||||
// Delete the Led-String
|
// Delete the Led-String
|
||||||
delete mDevice;
|
delete _device;
|
||||||
|
|
||||||
|
// delete he hsv transform
|
||||||
|
delete _hsvTransform;
|
||||||
|
|
||||||
// Delete the color-transform
|
// Delete the color-transform
|
||||||
delete mBlueTransform;
|
delete _blueTransform;
|
||||||
delete mGreenTransform;
|
delete _greenTransform;
|
||||||
delete mRedTransform;
|
delete _redTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned Hyperion::getLedCount() const
|
unsigned Hyperion::getLedCount() const
|
||||||
{
|
{
|
||||||
return mLedString.leds().size();
|
return _ledString.leds().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Hyperion::setValue(int priority, std::vector<RgbColor>& ledColors, const int timeout_ms)
|
void Hyperion::setColor(int priority, RgbColor & color, const int timeout_ms)
|
||||||
{
|
{
|
||||||
// Apply the transform to each led and color-channel
|
// create led output
|
||||||
for (RgbColor& color : ledColors)
|
std::vector<RgbColor> ledColors(_ledString.leds().size(), color);
|
||||||
{
|
|
||||||
color.red = mRedTransform->transform(color.red);
|
|
||||||
color.green = mGreenTransform->transform(color.green);
|
|
||||||
color.blue = mBlueTransform->transform(color.blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// set colors
|
||||||
|
setColors(priority, ledColors, timeout_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hyperion::setColors(int priority, std::vector<RgbColor>& ledColors, const int timeout_ms)
|
||||||
|
{
|
||||||
if (timeout_ms > 0)
|
if (timeout_ms > 0)
|
||||||
{
|
{
|
||||||
const uint64_t timeoutTime = QDateTime::currentMSecsSinceEpoch() + timeout_ms;
|
const uint64_t timeoutTime = QDateTime::currentMSecsSinceEpoch() + timeout_ms;
|
||||||
mMuxer.setInput(priority, ledColors, timeoutTime);
|
_muxer.setInput(priority, ledColors, timeoutTime);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mMuxer.setInput(priority, ledColors);
|
_muxer.setInput(priority, ledColors);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priority == mMuxer.getCurrentPriority())
|
if (priority == _muxer.getCurrentPriority())
|
||||||
{
|
{
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Hyperion::setTransform(Hyperion::Transform transform, Hyperion::Color color, double value)
|
||||||
|
{
|
||||||
|
// select the transform of the requested color
|
||||||
|
ColorTransform * t = nullptr;
|
||||||
|
switch (color)
|
||||||
|
{
|
||||||
|
case RED:
|
||||||
|
t = _redTransform;
|
||||||
|
break;
|
||||||
|
case GREEN:
|
||||||
|
t = _greenTransform;
|
||||||
|
break;
|
||||||
|
case BLUE:
|
||||||
|
t = _blueTransform;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set transform value
|
||||||
|
switch (transform)
|
||||||
|
{
|
||||||
|
case SATURATION_GAIN:
|
||||||
|
_hsvTransform->setSaturationGain(value);
|
||||||
|
break;
|
||||||
|
case VALUE_GAIN:
|
||||||
|
_hsvTransform->setValueGain(value);
|
||||||
|
break;
|
||||||
|
case THRESHOLD:
|
||||||
|
assert (t != nullptr);
|
||||||
|
t->setThreshold(value);
|
||||||
|
break;
|
||||||
|
case GAMMA:
|
||||||
|
assert (t != nullptr);
|
||||||
|
t->setGamma(value);
|
||||||
|
break;
|
||||||
|
case BLACKLEVEL:
|
||||||
|
assert (t != nullptr);
|
||||||
|
t->setBlacklevel(value);
|
||||||
|
break;
|
||||||
|
case WHITELEVEL:
|
||||||
|
assert (t != nullptr);
|
||||||
|
t->setWhitelevel(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the led output
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hyperion::clear(int priority)
|
||||||
|
{
|
||||||
|
if (_muxer.hasPriority(priority))
|
||||||
|
{
|
||||||
|
_muxer.clearInput(priority);
|
||||||
|
|
||||||
|
// update leds if necessary
|
||||||
|
if (priority < _muxer.getCurrentPriority());
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hyperion::clearall()
|
||||||
|
{
|
||||||
|
_muxer.clearAll();
|
||||||
|
|
||||||
|
// update leds
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
double Hyperion::getTransform(Hyperion::Transform transform, Hyperion::Color color) const
|
||||||
|
{
|
||||||
|
// select the transform of the requested color
|
||||||
|
ColorTransform * t = nullptr;
|
||||||
|
switch (color)
|
||||||
|
{
|
||||||
|
case RED:
|
||||||
|
t = _redTransform;
|
||||||
|
break;
|
||||||
|
case GREEN:
|
||||||
|
t = _greenTransform;
|
||||||
|
break;
|
||||||
|
case BLUE:
|
||||||
|
t = _blueTransform;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set transform value
|
||||||
|
switch (transform)
|
||||||
|
{
|
||||||
|
case SATURATION_GAIN:
|
||||||
|
return _hsvTransform->getSaturationGain();
|
||||||
|
case VALUE_GAIN:
|
||||||
|
return _hsvTransform->getValueGain();
|
||||||
|
case THRESHOLD:
|
||||||
|
assert (t != nullptr);
|
||||||
|
return t->getThreshold();
|
||||||
|
case GAMMA:
|
||||||
|
assert (t != nullptr);
|
||||||
|
return t->getGamma();
|
||||||
|
case BLACKLEVEL:
|
||||||
|
assert (t != nullptr);
|
||||||
|
return t->getBlacklevel();
|
||||||
|
case WHITELEVEL:
|
||||||
|
assert (t != nullptr);
|
||||||
|
return t->getWhitelevel();
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 999.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<int> Hyperion::getActivePriorities() const
|
||||||
|
{
|
||||||
|
return _muxer.getPriorities();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Hyperion::InputInfo &Hyperion::getPriorityInfo(const int priority) const
|
||||||
|
{
|
||||||
|
return _muxer.getInputInfo(priority);
|
||||||
|
}
|
||||||
|
|
||||||
void Hyperion::update()
|
void Hyperion::update()
|
||||||
{
|
{
|
||||||
// Update the muxer, cleaning obsolete priorities
|
// Update the muxer, cleaning obsolete priorities
|
||||||
mMuxer.setCurrentTime(QDateTime::currentMSecsSinceEpoch());
|
_muxer.setCurrentTime(QDateTime::currentMSecsSinceEpoch());
|
||||||
|
|
||||||
// Obtain the current priority channel
|
// Obtain the current priority channel
|
||||||
int priority = mMuxer.getCurrentPriority();
|
int priority = _muxer.getCurrentPriority();
|
||||||
const PriorityMuxer::InputInfo & priorityInfo = mMuxer.getInputInfo(priority);
|
const PriorityMuxer::InputInfo & priorityInfo = _muxer.getInputInfo(priority);
|
||||||
|
|
||||||
|
// Apply the transform to each led and color-channel
|
||||||
|
std::vector<RgbColor> ledColors(priorityInfo.ledColors);
|
||||||
|
for (RgbColor& color : ledColors)
|
||||||
|
{
|
||||||
|
_hsvTransform->transform(color.red, color.green, color.blue);
|
||||||
|
color.red = _redTransform->transform(color.red);
|
||||||
|
color.green = _greenTransform->transform(color.green);
|
||||||
|
color.blue = _blueTransform->transform(color.blue);
|
||||||
|
}
|
||||||
|
|
||||||
// Write the data to the device
|
// Write the data to the device
|
||||||
mDevice->write(priorityInfo.ledColors);
|
_device->write(ledColors);
|
||||||
|
|
||||||
// Start the timeout-timer
|
// Start the timeout-timer
|
||||||
if (priorityInfo.timeoutTime_ms == -1)
|
if (priorityInfo.timeoutTime_ms == -1)
|
||||||
|
@ -6,10 +6,14 @@
|
|||||||
// Hyperion includes
|
// Hyperion includes
|
||||||
#include <hyperion/PriorityMuxer.h>
|
#include <hyperion/PriorityMuxer.h>
|
||||||
|
|
||||||
PriorityMuxer::PriorityMuxer() :
|
PriorityMuxer::PriorityMuxer(int ledCount) :
|
||||||
mCurrentPriority(MAX_PRIORITY)
|
_currentPriority(LOWEST_PRIORITY),
|
||||||
|
_activeInputs(),
|
||||||
|
_lowestPriorityInfo()
|
||||||
{
|
{
|
||||||
// empty
|
_lowestPriorityInfo.priority = LOWEST_PRIORITY;
|
||||||
|
_lowestPriorityInfo.timeoutTime_ms = -1;
|
||||||
|
_lowestPriorityInfo.ledColors = std::vector<RgbColor>(ledCount, {0, 0, 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
PriorityMuxer::~PriorityMuxer()
|
PriorityMuxer::~PriorityMuxer()
|
||||||
@ -19,23 +23,28 @@ PriorityMuxer::~PriorityMuxer()
|
|||||||
|
|
||||||
int PriorityMuxer::getCurrentPriority() const
|
int PriorityMuxer::getCurrentPriority() const
|
||||||
{
|
{
|
||||||
return mCurrentPriority;
|
return _currentPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<int> PriorityMuxer::getPriorities() const
|
QList<int> PriorityMuxer::getPriorities() const
|
||||||
{
|
{
|
||||||
return mActiveInputs.keys();
|
return _activeInputs.keys();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PriorityMuxer::hasPriority(const int priority) const
|
bool PriorityMuxer::hasPriority(const int priority) const
|
||||||
{
|
{
|
||||||
return mActiveInputs.contains(priority);
|
return _activeInputs.contains(priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PriorityMuxer::InputInfo& PriorityMuxer::getInputInfo(const int priority) const
|
const PriorityMuxer::InputInfo& PriorityMuxer::getInputInfo(const int priority) const
|
||||||
{
|
{
|
||||||
auto elemIt = mActiveInputs.find(priority);
|
if (priority == LOWEST_PRIORITY)
|
||||||
if (elemIt == mActiveInputs.end())
|
{
|
||||||
|
return _lowestPriorityInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto elemIt = _activeInputs.find(priority);
|
||||||
|
if (elemIt == _activeInputs.end())
|
||||||
{
|
{
|
||||||
throw std::runtime_error("no such priority");
|
throw std::runtime_error("no such priority");
|
||||||
}
|
}
|
||||||
@ -44,50 +53,50 @@ const PriorityMuxer::InputInfo& PriorityMuxer::getInputInfo(const int priority)
|
|||||||
|
|
||||||
void PriorityMuxer::setInput(const int priority, const std::vector<RgbColor>& ledColors, const int64_t timeoutTime_ms)
|
void PriorityMuxer::setInput(const int priority, const std::vector<RgbColor>& ledColors, const int64_t timeoutTime_ms)
|
||||||
{
|
{
|
||||||
InputInfo& input = mActiveInputs[priority];
|
InputInfo& input = _activeInputs[priority];
|
||||||
input.priority = priority;
|
input.priority = priority;
|
||||||
input.timeoutTime_ms = timeoutTime_ms;
|
input.timeoutTime_ms = timeoutTime_ms;
|
||||||
input.ledColors = ledColors;
|
input.ledColors = ledColors;
|
||||||
|
|
||||||
mCurrentPriority = std::min(mCurrentPriority, priority);
|
_currentPriority = std::min(_currentPriority, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PriorityMuxer::clearInput(const int priority)
|
void PriorityMuxer::clearInput(const int priority)
|
||||||
{
|
{
|
||||||
mActiveInputs.remove(priority);
|
_activeInputs.remove(priority);
|
||||||
if (mCurrentPriority == priority)
|
if (_currentPriority == priority)
|
||||||
{
|
{
|
||||||
if (mActiveInputs.empty())
|
if (_activeInputs.empty())
|
||||||
{
|
{
|
||||||
mCurrentPriority = MAX_PRIORITY;
|
_currentPriority = LOWEST_PRIORITY;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QList<int> keys = mActiveInputs.keys();
|
QList<int> keys = _activeInputs.keys();
|
||||||
mCurrentPriority = *std::min_element(keys.begin(), keys.end());
|
_currentPriority = *std::min_element(keys.begin(), keys.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PriorityMuxer::clearAll()
|
void PriorityMuxer::clearAll()
|
||||||
{
|
{
|
||||||
mActiveInputs.clear();
|
_activeInputs.clear();
|
||||||
mCurrentPriority = MAX_PRIORITY;
|
_currentPriority = LOWEST_PRIORITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PriorityMuxer::setCurrentTime(const int64_t& now)
|
void PriorityMuxer::setCurrentTime(const int64_t& now)
|
||||||
{
|
{
|
||||||
mCurrentPriority = MAX_PRIORITY;
|
_currentPriority = LOWEST_PRIORITY;
|
||||||
|
|
||||||
for (auto infoIt = mActiveInputs.begin(); infoIt != mActiveInputs.end();)
|
for (auto infoIt = _activeInputs.begin(); infoIt != _activeInputs.end();)
|
||||||
{
|
{
|
||||||
if (infoIt->timeoutTime_ms != -1 && infoIt->timeoutTime_ms <= now)
|
if (infoIt->timeoutTime_ms != -1 && infoIt->timeoutTime_ms <= now)
|
||||||
{
|
{
|
||||||
infoIt = mActiveInputs.erase(infoIt);
|
infoIt = _activeInputs.erase(infoIt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mCurrentPriority = std::min(mCurrentPriority, infoIt->priority);
|
_currentPriority = std::min(_currentPriority, infoIt->priority);
|
||||||
++infoIt;
|
++infoIt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,23 @@
|
|||||||
"type":"object",
|
"type":"object",
|
||||||
"required":true,
|
"required":true,
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"hsv" : {
|
||||||
|
"type" : "object",
|
||||||
|
"required" : true,
|
||||||
|
"properties" : {
|
||||||
|
"saturationGain" : {
|
||||||
|
"type" : "number",
|
||||||
|
"required" : true,
|
||||||
|
"minimum" : 0.0
|
||||||
|
},
|
||||||
|
"valueGain" : {
|
||||||
|
"type" : "number",
|
||||||
|
"required" : true,
|
||||||
|
"minimum" : 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties" : false
|
||||||
|
},
|
||||||
"red": {
|
"red": {
|
||||||
"type":"object",
|
"type":"object",
|
||||||
"required":true,
|
"required":true,
|
||||||
@ -41,10 +58,6 @@
|
|||||||
"type":"number",
|
"type":"number",
|
||||||
"required":true
|
"required":true
|
||||||
},
|
},
|
||||||
"adjust": {
|
|
||||||
"type":"number",
|
|
||||||
"required":true
|
|
||||||
},
|
|
||||||
"blacklevel": {
|
"blacklevel": {
|
||||||
"type":"number",
|
"type":"number",
|
||||||
"required":true
|
"required":true
|
||||||
@ -55,7 +68,9 @@
|
|||||||
},
|
},
|
||||||
"threshold": {
|
"threshold": {
|
||||||
"type":"number",
|
"type":"number",
|
||||||
"required":true
|
"required":true,
|
||||||
|
"minimum" : 0.0,
|
||||||
|
"maximum" : 1.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -67,13 +82,19 @@
|
|||||||
"type":"number",
|
"type":"number",
|
||||||
"required":true
|
"required":true
|
||||||
},
|
},
|
||||||
"adjust": {
|
|
||||||
"type":"number",
|
|
||||||
"required":true
|
|
||||||
},
|
|
||||||
"blacklevel": {
|
"blacklevel": {
|
||||||
"type":"number",
|
"type":"number",
|
||||||
"required":true
|
"required":true
|
||||||
|
},
|
||||||
|
"whitelevel": {
|
||||||
|
"type":"number",
|
||||||
|
"required":true
|
||||||
|
},
|
||||||
|
"threshold": {
|
||||||
|
"type":"number",
|
||||||
|
"required":true,
|
||||||
|
"minimum" : 0.0,
|
||||||
|
"maximum" : 1.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -85,13 +106,19 @@
|
|||||||
"type":"number",
|
"type":"number",
|
||||||
"required":true
|
"required":true
|
||||||
},
|
},
|
||||||
"adjust": {
|
"whitelevel": {
|
||||||
"type":"number",
|
"type":"number",
|
||||||
"required":true
|
"required":true
|
||||||
},
|
},
|
||||||
"blacklevel": {
|
"blacklevel": {
|
||||||
"type":"number",
|
"type":"number",
|
||||||
"required":true
|
"required":true
|
||||||
|
},
|
||||||
|
"threshold": {
|
||||||
|
"type":"number",
|
||||||
|
"required":true,
|
||||||
|
"minimum" : 0.0,
|
||||||
|
"maximum" : 1.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,27 +9,23 @@
|
|||||||
|
|
||||||
// Qt includes
|
// Qt includes
|
||||||
#include <QResource>
|
#include <QResource>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
// hyperion util includes
|
||||||
|
#include "hyperion/ImageProcessorFactory.h"
|
||||||
|
#include "hyperion/ImageProcessor.h"
|
||||||
|
#include "utils/RgbColor.h"
|
||||||
|
|
||||||
// project includes
|
// project includes
|
||||||
#include "JsonClientConnection.h"
|
#include "JsonClientConnection.h"
|
||||||
|
|
||||||
JsonClientConnection::JsonClientConnection(QTcpSocket *socket) :
|
JsonClientConnection::JsonClientConnection(QTcpSocket *socket, Hyperion * hyperion) :
|
||||||
QObject(),
|
QObject(),
|
||||||
_socket(socket),
|
_socket(socket),
|
||||||
_schemaChecker(),
|
_imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor()),
|
||||||
|
_hyperion(hyperion),
|
||||||
_receiveBuffer()
|
_receiveBuffer()
|
||||||
{
|
{
|
||||||
// read the json schema from the resource
|
|
||||||
QResource schemaData(":/schema.json");
|
|
||||||
assert(schemaData.isValid());
|
|
||||||
Json::Reader jsonReader;
|
|
||||||
Json::Value schemaJson;
|
|
||||||
if (!jsonReader.parse(reinterpret_cast<const char *>(schemaData.data()), reinterpret_cast<const char *>(schemaData.data()) + schemaData.size(), schemaJson, false))
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Schema error: " + jsonReader.getFormattedErrorMessages()) ;
|
|
||||||
}
|
|
||||||
_schemaChecker.setSchema(schemaJson);
|
|
||||||
|
|
||||||
// connect internal signals and slots
|
// connect internal signals and slots
|
||||||
connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
|
connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
|
||||||
connect(_socket, SIGNAL(readyRead()), this, SLOT(readData()));
|
connect(_socket, SIGNAL(readyRead()), this, SLOT(readData()));
|
||||||
@ -64,33 +60,211 @@ void JsonClientConnection::socketClosed()
|
|||||||
emit connectionClosed(this);
|
emit connectionClosed(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonClientConnection::handleMessage(const std::string &message)
|
void JsonClientConnection::handleMessage(const std::string &messageString)
|
||||||
{
|
{
|
||||||
Json::Reader reader;
|
Json::Reader reader;
|
||||||
Json::Value messageRoot;
|
Json::Value message;
|
||||||
if (!reader.parse(message, messageRoot, false))
|
if (!reader.parse(messageString, message, false))
|
||||||
{
|
{
|
||||||
sendErrorReply("Error while parsing json: " + reader.getFormattedErrorMessages());
|
sendErrorReply("Error while parsing json: " + reader.getFormattedErrorMessages());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_schemaChecker.validate(messageRoot))
|
// check basic message
|
||||||
|
std::string errors;
|
||||||
|
if (!checkJson(message, ":schema", errors))
|
||||||
{
|
{
|
||||||
const std::list<std::string> & errors = _schemaChecker.getMessages();
|
sendErrorReply("Error while validating json: " + errors);
|
||||||
std::stringstream ss;
|
|
||||||
ss << "Error while validating json: {";
|
|
||||||
foreach (const std::string & error, errors) {
|
|
||||||
ss << error << ", ";
|
|
||||||
}
|
|
||||||
ss << "}";
|
|
||||||
sendErrorReply(ss.str());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNotImplemented(messageRoot);
|
// check specific message
|
||||||
|
const std::string command = message["command"].asString();
|
||||||
|
if (!checkJson(message, QString(":schema-%1").arg(QString::fromStdString(command)), errors))
|
||||||
|
{
|
||||||
|
sendErrorReply("Error while validating json: " + errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch over all possible commands and handle them
|
||||||
|
if (command == "color")
|
||||||
|
handleColorCommand(message);
|
||||||
|
else if (command == "image")
|
||||||
|
handleImageCommand(message);
|
||||||
|
else if (command == "serverinfo")
|
||||||
|
handleServerInfoCommand(message);
|
||||||
|
else if (command == "clear")
|
||||||
|
handleClearCommand(message);
|
||||||
|
else if (command == "clearall")
|
||||||
|
handleClearallCommand(message);
|
||||||
|
else if (command == "transform")
|
||||||
|
handleTransformCommand(message);
|
||||||
|
else
|
||||||
|
handleNotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonClientConnection::handleNotImplemented(const Json::Value & message)
|
void JsonClientConnection::handleColorCommand(const Json::Value &message)
|
||||||
|
{
|
||||||
|
// extract parameters
|
||||||
|
int priority = message["priority"].asInt();
|
||||||
|
int duration = message.get("duration", -1).asInt();
|
||||||
|
RgbColor color = {uint8_t(message["color"][0u].asInt()), uint8_t(message["color"][1u].asInt()), uint8_t(message["color"][2u].asInt())};
|
||||||
|
|
||||||
|
// set output
|
||||||
|
_hyperion->setColor(priority, color, duration);
|
||||||
|
|
||||||
|
// send reply
|
||||||
|
sendSuccessReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonClientConnection::handleImageCommand(const Json::Value &message)
|
||||||
|
{
|
||||||
|
// extract parameters
|
||||||
|
int priority = message["priority"].asInt();
|
||||||
|
int duration = message.get("duration", -1).asInt();
|
||||||
|
int width = message["imagewidth"].asInt();
|
||||||
|
int height = message["imageheight"].asInt();
|
||||||
|
QByteArray data = QByteArray::fromBase64(QByteArray(message["imagedata"].asCString()));
|
||||||
|
|
||||||
|
// check consistency of the size of the received data
|
||||||
|
if (data.size() != width*height*3)
|
||||||
|
{
|
||||||
|
sendErrorReply("Size of image data does not match with the width and height");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set width and height of the image processor
|
||||||
|
_imageProcessor->setSize(width, height);
|
||||||
|
|
||||||
|
// create RgbImage
|
||||||
|
RgbImage image(width, height);
|
||||||
|
memcpy(image.memptr(), data.data(), data.size());
|
||||||
|
|
||||||
|
// process the image
|
||||||
|
std::vector<RgbColor> ledColors = _imageProcessor->process(image);
|
||||||
|
_hyperion->setColors(priority, ledColors, duration);
|
||||||
|
|
||||||
|
// send reply
|
||||||
|
sendSuccessReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonClientConnection::handleServerInfoCommand(const Json::Value &message)
|
||||||
|
{
|
||||||
|
// create result
|
||||||
|
Json::Value result;
|
||||||
|
result["success"] = true;
|
||||||
|
Json::Value & info = result["info"];
|
||||||
|
|
||||||
|
// collect priority information
|
||||||
|
Json::Value & priorities = info["priorities"];
|
||||||
|
uint64_t now = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
QList<int> activePriorities = _hyperion->getActivePriorities();
|
||||||
|
foreach (int priority, activePriorities) {
|
||||||
|
const Hyperion::InputInfo & priorityInfo = _hyperion->getPriorityInfo(priority);
|
||||||
|
Json::Value & item = priorities[priorities.size()];
|
||||||
|
item["priority"] = priority;
|
||||||
|
if (priorityInfo.timeoutTime_ms != -1)
|
||||||
|
{
|
||||||
|
item["duration_ms"] = priorityInfo.timeoutTime_ms - now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect transform information
|
||||||
|
Json::Value & transform = info["transform"];
|
||||||
|
transform["saturationGain"] = _hyperion->getTransform(Hyperion::SATURATION_GAIN, Hyperion::INVALID);
|
||||||
|
transform["valueGain"] = _hyperion->getTransform(Hyperion::VALUE_GAIN, Hyperion::INVALID);
|
||||||
|
Json::Value & threshold = transform["threshold"];
|
||||||
|
threshold.append(_hyperion->getTransform(Hyperion::THRESHOLD, Hyperion::RED));
|
||||||
|
threshold.append(_hyperion->getTransform(Hyperion::THRESHOLD, Hyperion::GREEN));
|
||||||
|
threshold.append(_hyperion->getTransform(Hyperion::THRESHOLD, Hyperion::BLUE));
|
||||||
|
Json::Value & gamma = transform["gamma"];
|
||||||
|
gamma.append(_hyperion->getTransform(Hyperion::GAMMA, Hyperion::RED));
|
||||||
|
gamma.append(_hyperion->getTransform(Hyperion::GAMMA, Hyperion::GREEN));
|
||||||
|
gamma.append(_hyperion->getTransform(Hyperion::GAMMA, Hyperion::BLUE));
|
||||||
|
Json::Value & blacklevel = transform["blacklevel"];
|
||||||
|
blacklevel.append(_hyperion->getTransform(Hyperion::BLACKLEVEL, Hyperion::RED));
|
||||||
|
blacklevel.append(_hyperion->getTransform(Hyperion::BLACKLEVEL, Hyperion::GREEN));
|
||||||
|
blacklevel.append(_hyperion->getTransform(Hyperion::BLACKLEVEL, Hyperion::BLUE));
|
||||||
|
Json::Value & whitelevel = transform["whitelevel"];
|
||||||
|
whitelevel.append(_hyperion->getTransform(Hyperion::WHITELEVEL, Hyperion::RED));
|
||||||
|
whitelevel.append(_hyperion->getTransform(Hyperion::WHITELEVEL, Hyperion::GREEN));
|
||||||
|
whitelevel.append(_hyperion->getTransform(Hyperion::WHITELEVEL, Hyperion::BLUE));
|
||||||
|
|
||||||
|
// send the result
|
||||||
|
sendMessage(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonClientConnection::handleClearCommand(const Json::Value &message)
|
||||||
|
{
|
||||||
|
// extract parameters
|
||||||
|
int priority = message["priority"].asInt();
|
||||||
|
|
||||||
|
// clear priority
|
||||||
|
_hyperion->clear(priority);
|
||||||
|
|
||||||
|
// send reply
|
||||||
|
sendSuccessReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonClientConnection::handleClearallCommand(const Json::Value &)
|
||||||
|
{
|
||||||
|
// clear priority
|
||||||
|
_hyperion->clearall();
|
||||||
|
|
||||||
|
// send reply
|
||||||
|
sendSuccessReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonClientConnection::handleTransformCommand(const Json::Value &message)
|
||||||
|
{
|
||||||
|
const Json::Value & transform = message["transform"];
|
||||||
|
|
||||||
|
if (transform.isMember("saturationGain"))
|
||||||
|
{
|
||||||
|
_hyperion->setTransform(Hyperion::SATURATION_GAIN, Hyperion::INVALID, transform["saturationGain"].asDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transform.isMember("valueGain"))
|
||||||
|
{
|
||||||
|
_hyperion->setTransform(Hyperion::VALUE_GAIN, Hyperion::INVALID, transform["valueGain"].asDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transform.isMember("threshold"))
|
||||||
|
{
|
||||||
|
const Json::Value & threshold = transform["threshold"];
|
||||||
|
_hyperion->setTransform(Hyperion::THRESHOLD, Hyperion::RED, threshold[0u].asDouble());
|
||||||
|
_hyperion->setTransform(Hyperion::THRESHOLD, Hyperion::GREEN, threshold[1u].asDouble());
|
||||||
|
_hyperion->setTransform(Hyperion::THRESHOLD, Hyperion::BLUE, threshold[2u].asDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transform.isMember("gamma"))
|
||||||
|
{
|
||||||
|
const Json::Value & threshold = transform["gamma"];
|
||||||
|
_hyperion->setTransform(Hyperion::GAMMA, Hyperion::RED, threshold[0u].asDouble());
|
||||||
|
_hyperion->setTransform(Hyperion::GAMMA, Hyperion::GREEN, threshold[1u].asDouble());
|
||||||
|
_hyperion->setTransform(Hyperion::GAMMA, Hyperion::BLUE, threshold[2u].asDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transform.isMember("blacklevel"))
|
||||||
|
{
|
||||||
|
const Json::Value & threshold = transform["blacklevel"];
|
||||||
|
_hyperion->setTransform(Hyperion::BLACKLEVEL, Hyperion::RED, threshold[0u].asDouble());
|
||||||
|
_hyperion->setTransform(Hyperion::BLACKLEVEL, Hyperion::GREEN, threshold[1u].asDouble());
|
||||||
|
_hyperion->setTransform(Hyperion::BLACKLEVEL, Hyperion::BLUE, threshold[2u].asDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transform.isMember("whitelevel"))
|
||||||
|
{
|
||||||
|
const Json::Value & threshold = transform["whitelevel"];
|
||||||
|
_hyperion->setTransform(Hyperion::WHITELEVEL, Hyperion::RED, threshold[0u].asDouble());
|
||||||
|
_hyperion->setTransform(Hyperion::WHITELEVEL, Hyperion::GREEN, threshold[1u].asDouble());
|
||||||
|
_hyperion->setTransform(Hyperion::WHITELEVEL, Hyperion::BLUE, threshold[2u].asDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
sendSuccessReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JsonClientConnection::handleNotImplemented()
|
||||||
{
|
{
|
||||||
sendErrorReply("Command not implemented");
|
sendErrorReply("Command not implemented");
|
||||||
}
|
}
|
||||||
@ -102,6 +276,16 @@ void JsonClientConnection::sendMessage(const Json::Value &message)
|
|||||||
_socket->write(serializedReply.data(), serializedReply.length());
|
_socket->write(serializedReply.data(), serializedReply.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JsonClientConnection::sendSuccessReply()
|
||||||
|
{
|
||||||
|
// create reply
|
||||||
|
Json::Value reply;
|
||||||
|
reply["success"] = true;
|
||||||
|
|
||||||
|
// send reply
|
||||||
|
sendMessage(reply);
|
||||||
|
}
|
||||||
|
|
||||||
void JsonClientConnection::sendErrorReply(const std::string &error)
|
void JsonClientConnection::sendErrorReply(const std::string &error)
|
||||||
{
|
{
|
||||||
// create reply
|
// create reply
|
||||||
@ -112,3 +296,36 @@ void JsonClientConnection::sendErrorReply(const std::string &error)
|
|||||||
// send reply
|
// send reply
|
||||||
sendMessage(reply);
|
sendMessage(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool JsonClientConnection::checkJson(const Json::Value & message, const QString & schemaResource, std::string & errorMessage)
|
||||||
|
{
|
||||||
|
// read the json schema from the resource
|
||||||
|
QResource schemaData(schemaResource);
|
||||||
|
assert(schemaData.isValid());
|
||||||
|
Json::Reader jsonReader;
|
||||||
|
Json::Value schemaJson;
|
||||||
|
if (!jsonReader.parse(reinterpret_cast<const char *>(schemaData.data()), reinterpret_cast<const char *>(schemaData.data()) + schemaData.size(), schemaJson, false))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Schema error: " + jsonReader.getFormattedErrorMessages()) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create schema checker
|
||||||
|
JsonSchemaChecker schema;
|
||||||
|
schema.setSchema(schemaJson);
|
||||||
|
|
||||||
|
// check the message
|
||||||
|
if (!schema.validate(message))
|
||||||
|
{
|
||||||
|
const std::list<std::string> & errors = schema.getMessages();
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "{";
|
||||||
|
foreach (const std::string & error, errors) {
|
||||||
|
ss << error << " ";
|
||||||
|
}
|
||||||
|
ss << "}";
|
||||||
|
errorMessage = ss.str();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -10,15 +10,20 @@
|
|||||||
// jsoncpp includes
|
// jsoncpp includes
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
|
// Hyperion includes
|
||||||
|
#include <hyperion/Hyperion.h>
|
||||||
|
|
||||||
// util includes
|
// util includes
|
||||||
#include <utils/jsonschema/JsonSchemaChecker.h>
|
#include <utils/jsonschema/JsonSchemaChecker.h>
|
||||||
|
|
||||||
|
class ImageProcessor;
|
||||||
|
|
||||||
class JsonClientConnection : public QObject
|
class JsonClientConnection : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JsonClientConnection(QTcpSocket * socket);
|
JsonClientConnection(QTcpSocket * socket, Hyperion * hyperion);
|
||||||
~JsonClientConnection();
|
~JsonClientConnection();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@ -30,15 +35,27 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void handleMessage(const std::string & message);
|
void handleMessage(const std::string & message);
|
||||||
void handleNotImplemented(const Json::Value & message);
|
void handleColorCommand(const Json::Value & message);
|
||||||
|
void handleImageCommand(const Json::Value & message);
|
||||||
|
void handleServerInfoCommand(const Json::Value & message);
|
||||||
|
void handleClearCommand(const Json::Value & message);
|
||||||
|
void handleClearallCommand(const Json::Value & message);
|
||||||
|
void handleTransformCommand(const Json::Value & message);
|
||||||
|
void handleNotImplemented();
|
||||||
|
|
||||||
void sendMessage(const Json::Value & message);
|
void sendMessage(const Json::Value & message);
|
||||||
|
void sendSuccessReply();
|
||||||
void sendErrorReply(const std::string & error);
|
void sendErrorReply(const std::string & error);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool checkJson(const Json::Value & message, const QString &schemaResource, std::string & errors);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTcpSocket * _socket;
|
QTcpSocket * _socket;
|
||||||
|
|
||||||
JsonSchemaChecker _schemaChecker;
|
ImageProcessor * _imageProcessor;
|
||||||
|
|
||||||
|
Hyperion * _hyperion;
|
||||||
|
|
||||||
QByteArray _receiveBuffer;
|
QByteArray _receiveBuffer;
|
||||||
};
|
};
|
||||||
|
@ -37,12 +37,12 @@ uint16_t JsonServer::getPort() const
|
|||||||
|
|
||||||
void JsonServer::newConnection()
|
void JsonServer::newConnection()
|
||||||
{
|
{
|
||||||
std::cout << "New incoming json connection" << std::endl;
|
|
||||||
QTcpSocket * socket = _server.nextPendingConnection();
|
QTcpSocket * socket = _server.nextPendingConnection();
|
||||||
|
|
||||||
if (socket != nullptr)
|
if (socket != nullptr)
|
||||||
{
|
{
|
||||||
JsonClientConnection * connection = new JsonClientConnection(socket);
|
std::cout << "New json connection" << std::endl;
|
||||||
|
JsonClientConnection * connection = new JsonClientConnection(socket, _hyperion);
|
||||||
_openConnections.insert(connection);
|
_openConnections.insert(connection);
|
||||||
|
|
||||||
// register slot for cleaning up after the connection closed
|
// register slot for cleaning up after the connection closed
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file>schema.json</file>
|
<file alias="schema">schema/schema.json</file>
|
||||||
</qresource>
|
<file alias="schema-color">schema/schema-color.json</file>
|
||||||
|
<file alias="schema-image">schema/schema-image.json</file>
|
||||||
|
<file alias="schema-serverinfo">schema/schema-serverinfo.json</file>
|
||||||
|
<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>
|
||||||
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
16
libsrc/jsonserver/schema/schema-clear.json
Normal file
16
libsrc/jsonserver/schema/schema-clear.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"type":"object",
|
||||||
|
"required":true,
|
||||||
|
"properties":{
|
||||||
|
"command": {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : true,
|
||||||
|
"enum" : ["clear"]
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"type": "integer",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
12
libsrc/jsonserver/schema/schema-clearall.json
Normal file
12
libsrc/jsonserver/schema/schema-clearall.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"type":"object",
|
||||||
|
"required":true,
|
||||||
|
"properties":{
|
||||||
|
"command": {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : true,
|
||||||
|
"enum" : ["clearall"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
29
libsrc/jsonserver/schema/schema-color.json
Normal file
29
libsrc/jsonserver/schema/schema-color.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"type":"object",
|
||||||
|
"required":true,
|
||||||
|
"properties":{
|
||||||
|
"command": {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : true,
|
||||||
|
"enum" : ["color"]
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"type": "integer",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": "integer",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"type": "array",
|
||||||
|
"required": true,
|
||||||
|
"items" :{
|
||||||
|
"type" : "integer"
|
||||||
|
},
|
||||||
|
"minItems": 3,
|
||||||
|
"maxItems": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
34
libsrc/jsonserver/schema/schema-image.json
Normal file
34
libsrc/jsonserver/schema/schema-image.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"type":"object",
|
||||||
|
"required":true,
|
||||||
|
"properties":{
|
||||||
|
"command": {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : true,
|
||||||
|
"enum" : ["image"]
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"type": "integer",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"duration": {
|
||||||
|
"type": "integer",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
|
"imagewidth": {
|
||||||
|
"type" : "integer",
|
||||||
|
"required": true,
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"imageheight": {
|
||||||
|
"type" : "integer",
|
||||||
|
"required": true,
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"imagedata": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
12
libsrc/jsonserver/schema/schema-serverinfo.json
Normal file
12
libsrc/jsonserver/schema/schema-serverinfo.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"type":"object",
|
||||||
|
"required":true,
|
||||||
|
"properties":{
|
||||||
|
"command": {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : true,
|
||||||
|
"enum" : ["serverinfo"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
@ -5,43 +5,22 @@
|
|||||||
"command": {
|
"command": {
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"enum" : ["color", "image", "serverinfo", "clear", "clearall", "transform"]
|
"enum" : ["transform"]
|
||||||
},
|
|
||||||
"priority": {
|
|
||||||
"type": "integer",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
"duration": {
|
|
||||||
"type": "integer",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
"color": {
|
|
||||||
"type": "array",
|
|
||||||
"required": false,
|
|
||||||
"items" :{
|
|
||||||
"type" : "integer"
|
|
||||||
},
|
|
||||||
"minItems": 3,
|
|
||||||
"maxItems": 3
|
|
||||||
},
|
|
||||||
"imagewidth": {
|
|
||||||
"type" : "integer",
|
|
||||||
"required": false,
|
|
||||||
"minimum": 0
|
|
||||||
},
|
|
||||||
"imageheight": {
|
|
||||||
"type" : "integer",
|
|
||||||
"required": false,
|
|
||||||
"minimum": 0
|
|
||||||
},
|
|
||||||
"imagedata": {
|
|
||||||
"type": "string",
|
|
||||||
"required": false
|
|
||||||
},
|
},
|
||||||
"transform": {
|
"transform": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": false,
|
"required": true,
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"saturationGain" : {
|
||||||
|
"type" : "double",
|
||||||
|
"required" : false,
|
||||||
|
"minimum" : 0.0
|
||||||
|
},
|
||||||
|
"valueGain" : {
|
||||||
|
"type" : "double",
|
||||||
|
"required" : false,
|
||||||
|
"minimum" : 0.0
|
||||||
|
},
|
||||||
"threshold": {
|
"threshold": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"required": false,
|
"required": false,
|
11
libsrc/jsonserver/schema/schema.json
Normal file
11
libsrc/jsonserver/schema/schema.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"type":"object",
|
||||||
|
"required":true,
|
||||||
|
"properties":{
|
||||||
|
"command": {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : true,
|
||||||
|
"enum" : ["color", "image", "serverinfo", "clear", "clearall", "transform"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,5 +30,5 @@ qt4_use_modules(hyperion-remote
|
|||||||
Network)
|
Network)
|
||||||
|
|
||||||
target_link_libraries(hyperion-remote
|
target_link_libraries(hyperion-remote
|
||||||
hyperion-utils
|
jsoncpp
|
||||||
getoptPlusPlus)
|
getoptPlusPlus)
|
||||||
|
@ -160,7 +160,7 @@ void JsonConnection::clearAll()
|
|||||||
parseReply(reply);
|
parseReply(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonConnection::setTransform(ColorTransformValues *threshold, ColorTransformValues *gamma, ColorTransformValues *blacklevel, ColorTransformValues *whitelevel)
|
void JsonConnection::setTransform(double * saturation, double * value, ColorTransformValues *threshold, ColorTransformValues *gamma, ColorTransformValues *blacklevel, ColorTransformValues *whitelevel)
|
||||||
{
|
{
|
||||||
std::cout << "Set color transforms" << std::endl;
|
std::cout << "Set color transforms" << std::endl;
|
||||||
|
|
||||||
@ -169,6 +169,16 @@ void JsonConnection::setTransform(ColorTransformValues *threshold, ColorTransfor
|
|||||||
command["command"] = "transform";
|
command["command"] = "transform";
|
||||||
Json::Value & transform = command["transform"];
|
Json::Value & transform = command["transform"];
|
||||||
|
|
||||||
|
if (saturation != nullptr)
|
||||||
|
{
|
||||||
|
transform["saturationGain"] = *saturation;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != nullptr)
|
||||||
|
{
|
||||||
|
transform["valueGain"] = *value;
|
||||||
|
}
|
||||||
|
|
||||||
if (threshold != nullptr)
|
if (threshold != nullptr)
|
||||||
{
|
{
|
||||||
Json::Value & v = transform["threshold"];
|
Json::Value & v = transform["threshold"];
|
||||||
@ -180,25 +190,25 @@ void JsonConnection::setTransform(ColorTransformValues *threshold, ColorTransfor
|
|||||||
if (gamma != nullptr)
|
if (gamma != nullptr)
|
||||||
{
|
{
|
||||||
Json::Value & v = transform["gamma"];
|
Json::Value & v = transform["gamma"];
|
||||||
v.append(threshold->valueRed);
|
v.append(gamma->valueRed);
|
||||||
v.append(threshold->valueGreen);
|
v.append(gamma->valueGreen);
|
||||||
v.append(threshold->valueBlue);
|
v.append(gamma->valueBlue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blacklevel != nullptr)
|
if (blacklevel != nullptr)
|
||||||
{
|
{
|
||||||
Json::Value & v = transform["blacklevel"];
|
Json::Value & v = transform["blacklevel"];
|
||||||
v.append(threshold->valueRed);
|
v.append(blacklevel->valueRed);
|
||||||
v.append(threshold->valueGreen);
|
v.append(blacklevel->valueGreen);
|
||||||
v.append(threshold->valueBlue);
|
v.append(blacklevel->valueBlue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (whitelevel != nullptr)
|
if (whitelevel != nullptr)
|
||||||
{
|
{
|
||||||
Json::Value & v = transform["whitelevel"];
|
Json::Value & v = transform["whitelevel"];
|
||||||
v.append(threshold->valueRed);
|
v.append(whitelevel->valueRed);
|
||||||
v.append(threshold->valueGreen);
|
v.append(whitelevel->valueGreen);
|
||||||
v.append(threshold->valueBlue);
|
v.append(whitelevel->valueBlue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send command message
|
// send command message
|
||||||
@ -275,7 +285,7 @@ bool JsonConnection::parseReply(const Json::Value &reply)
|
|||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Error while executing command: " + reason);
|
throw std::runtime_error("Error: " + reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
@ -39,7 +39,13 @@ public:
|
|||||||
|
|
||||||
/// Set the color transform of the leds
|
/// Set the color transform of the leds
|
||||||
/// Note that providing a NULL will leave the settings on the server unchanged
|
/// Note that providing a NULL will leave the settings on the server unchanged
|
||||||
void setTransform(ColorTransformValues * threshold, ColorTransformValues * gamma, ColorTransformValues * blacklevel, ColorTransformValues * whitelevel);
|
void setTransform(
|
||||||
|
double * saturation,
|
||||||
|
double * value,
|
||||||
|
ColorTransformValues * threshold,
|
||||||
|
ColorTransformValues * gamma,
|
||||||
|
ColorTransformValues * blacklevel,
|
||||||
|
ColorTransformValues * whitelevel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Send a json command message and receive its reply
|
/// Send a json command message and receive its reply
|
||||||
|
@ -42,9 +42,11 @@ 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]");
|
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)");
|
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");
|
ImageParameter & argImage = parameters.add<ImageParameter> ('i', "image" , "Set the leds to the colors according to the given image file");
|
||||||
SwitchParameter<> & argServerInfo = parameters.add<SwitchParameter<> >('s', "info" , "List server info");
|
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<> & argClear = parameters.add<SwitchParameter<> >('x', "clear" , "Clear data for the priority channel provided by the -p option");
|
||||||
SwitchParameter<> & argClearAll = parameters.add<SwitchParameter<> >(0x0, "clear-all" , "Clear data for all priority channels");
|
SwitchParameter<> & argClearAll = parameters.add<SwitchParameter<> >(0x0, "clearall" , "Clear data for all active priority channels");
|
||||||
|
DoubleParameter & argSaturation = parameters.add<DoubleParameter> ('s', "saturation", "Set the HSV saturation gain of the leds");
|
||||||
|
DoubleParameter & argValue = parameters.add<DoubleParameter> ('v', "value ", "Set the HSV value gain of the leds");
|
||||||
TransformParameter & argGamma = parameters.add<TransformParameter>('g', "gamma" , "Set the gamma of the leds (requires 3 space seperated values)");
|
TransformParameter & argGamma = parameters.add<TransformParameter>('g', "gamma" , "Set the gamma of the leds (requires 3 space seperated values)");
|
||||||
TransformParameter & argThreshold = parameters.add<TransformParameter>('t', "threshold" , "Set the threshold of the leds (requires 3 space seperated values between 0.0 and 1.0)");
|
TransformParameter & argThreshold = parameters.add<TransformParameter>('t', "threshold" , "Set the threshold of the leds (requires 3 space seperated values between 0.0 and 1.0)");
|
||||||
TransformParameter & argBlacklevel = parameters.add<TransformParameter>('b', "blacklevel", "Set the blacklevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)");
|
TransformParameter & argBlacklevel = parameters.add<TransformParameter>('b', "blacklevel", "Set the blacklevel of the leds (requires 3 space seperated values which are normally between 0.0 and 1.0)");
|
||||||
@ -68,7 +70,7 @@ int main(int argc, char * argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if at least one of the available color transforms is set
|
// check if at least one of the available color transforms is set
|
||||||
bool colorTransform = argThreshold.isSet() || argGamma.isSet() || argBlacklevel.isSet() || argWhitelevel.isSet();
|
bool colorTransform = argSaturation.isSet() || argValue.isSet() || argThreshold.isSet() || argGamma.isSet() || argBlacklevel.isSet() || argWhitelevel.isSet();
|
||||||
|
|
||||||
// check that exactly one command was given
|
// 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(), argServerInfo.isSet(), argClear.isSet(), argClearAll.isSet(), colorTransform});
|
||||||
@ -81,6 +83,8 @@ int main(int argc, char * argv[])
|
|||||||
std::cerr << " " << argClear.usageLine() << std::endl;
|
std::cerr << " " << argClear.usageLine() << std::endl;
|
||||||
std::cerr << " " << argClearAll.usageLine() << std::endl;
|
std::cerr << " " << argClearAll.usageLine() << std::endl;
|
||||||
std::cerr << "or one or more of the available color transformations:" << std::endl;
|
std::cerr << "or one or more of the available color transformations:" << std::endl;
|
||||||
|
std::cerr << " " << argSaturation.usageLine() << std::endl;
|
||||||
|
std::cerr << " " << argValue.usageLine() << std::endl;
|
||||||
std::cerr << " " << argThreshold.usageLine() << std::endl;
|
std::cerr << " " << argThreshold.usageLine() << std::endl;
|
||||||
std::cerr << " " << argGamma.usageLine() << std::endl;
|
std::cerr << " " << argGamma.usageLine() << std::endl;
|
||||||
std::cerr << " " << argBlacklevel.usageLine() << std::endl;
|
std::cerr << " " << argBlacklevel.usageLine() << std::endl;
|
||||||
@ -115,14 +119,19 @@ int main(int argc, char * argv[])
|
|||||||
}
|
}
|
||||||
else if (colorTransform)
|
else if (colorTransform)
|
||||||
{
|
{
|
||||||
|
double saturation, value;
|
||||||
ColorTransformValues threshold, gamma, blacklevel, whitelevel;
|
ColorTransformValues threshold, gamma, blacklevel, whitelevel;
|
||||||
|
|
||||||
|
if (argSaturation.isSet()) saturation = argSaturation.getValue();
|
||||||
|
if (argValue.isSet()) value = argValue.getValue();
|
||||||
if (argThreshold.isSet()) threshold = argThreshold.getValue();
|
if (argThreshold.isSet()) threshold = argThreshold.getValue();
|
||||||
if (argGamma.isSet()) gamma = argGamma.getValue();
|
if (argGamma.isSet()) gamma = argGamma.getValue();
|
||||||
if (argBlacklevel.isSet()) blacklevel = argBlacklevel.getValue();
|
if (argBlacklevel.isSet()) blacklevel = argBlacklevel.getValue();
|
||||||
if (argWhitelevel.isSet()) whitelevel = argWhitelevel.getValue();
|
if (argWhitelevel.isSet()) whitelevel = argWhitelevel.getValue();
|
||||||
|
|
||||||
connection.setTransform(
|
connection.setTransform(
|
||||||
|
argSaturation.isSet() ? &saturation : nullptr,
|
||||||
|
argValue.isSet() ? &value : nullptr,
|
||||||
argThreshold.isSet() ? &threshold : nullptr,
|
argThreshold.isSet() ? &threshold : nullptr,
|
||||||
argGamma.isSet() ? &gamma : nullptr,
|
argGamma.isSet() ? &gamma : nullptr,
|
||||||
argBlacklevel.isSet() ? &blacklevel : nullptr,
|
argBlacklevel.isSet() ? &blacklevel : nullptr,
|
||||||
|
Loading…
Reference in New Issue
Block a user