mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
LED Device Features, Fixes and Refactoring (Resubmit PR855) (#875)
* Refactor LedDevices - Initial version * Small renamings * Add WLED as own device * Lpd8806 Remove open() method * remove dependency on Qt 5.10 * Lpd8806 Remove open() method * Update WS281x * Update WS2812SPI * Add writeBlack for WLED powerOff * WLED remove extra bracket * Allow different Nanoleaf panel numbering sequence (Feature req.#827) * build(deps): bump websocket-extensions from 0.1.3 to 0.1.4 in /docs (#826) * Bumps [websocket-extensions](https://github.com/faye/websocket-extensions-node) from 0.1.3 to 0.1.4. - [Release notes](https://github.com/faye/websocket-extensions-node/releases) - [Changelog](https://github.com/faye/websocket-extensions-node/blob/master/CHANGELOG.md) - [Commits](https://github.com/faye/websocket-extensions-node/compare/0.1.3...0.1.4) * Fix typos * Nanoleaf clean-up * Yeelight support, generalize wizard elements * Update Yeelight to handle quota in music mode * Yeelight extend rage for extraTimeDarkness for testing * Clean-up - Add commentary, Remove development debug statements * Fix brightnessSwitchOffOnMinimum typo and default value * Yeelight support restoreOriginalState, additional Fixes * WLED - Remove UDP-Port, as it is not configurable * Fix merging issue * Remove QHostAddress::operator=(const QString&)' is deprecated * Windows compile errors and (Qt 5.15 deprecation) warnings * Fix order includes * LedDeviceFile Support Qt5.7 and greater * Windows compatibility and other Fixes * Fix Qt Version compatability * Rs232 - Resolve portname from unix /dev/ style, fix DMX sub-type support * Disable WLED Wizard Button (until Wizard is available) * Yeelight updates * Add wrong log-type as per #505 * Fixes and Clean-up after clang-tidy report * Fix udpe131 not enabled for generated CID * Change timer into dynamic for Qt Thread-Affinity * Hue clean-up and diyHue workaround * Updates after review feedback by m-seker * Add "chrono" includes
This commit is contained in:
28
libsrc/api/JSONRPC_schema/schema-leddevice.json
Normal file
28
libsrc/api/JSONRPC_schema/schema-leddevice.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"type":"object",
|
||||
"required":true,
|
||||
"properties":{
|
||||
"command": {
|
||||
"type" : "string",
|
||||
"required" : true,
|
||||
"enum" : ["leddevice"]
|
||||
},
|
||||
"tan" : {
|
||||
"type" : "integer"
|
||||
},
|
||||
"subcommand": {
|
||||
"type" : "string",
|
||||
"required" : true,
|
||||
"enum" : ["discover","getProperties","identify"]
|
||||
},
|
||||
"ledDeviceType": {
|
||||
"type" : "string",
|
||||
"required" : true
|
||||
},
|
||||
"params": {
|
||||
"type" : "object",
|
||||
"required" : false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
@@ -5,7 +5,7 @@
|
||||
"command": {
|
||||
"type" : "string",
|
||||
"required" : true,
|
||||
"enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "transform", "correction" , "temperature"]
|
||||
"enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "transform", "correction" , "temperature"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@
|
||||
<file alias="schema-videomode">JSONRPC_schema/schema-videomode.json</file>
|
||||
<file alias="schema-authorize">JSONRPC_schema/schema-authorize.json</file>
|
||||
<file alias="schema-instance">JSONRPC_schema/schema-instance.json</file>
|
||||
<file alias="schema-leddevice">JSONRPC_schema/schema-leddevice.json</file>
|
||||
<!-- The following schemas are derecated but used to ensure backward compatibility with hyperion Classic remote control-->
|
||||
<file alias="schema-transform">JSONRPC_schema/schema-hyperion-classic.json</file>
|
||||
<file alias="schema-correction">JSONRPC_schema/schema-hyperion-classic.json</file>
|
||||
|
@@ -18,6 +18,10 @@
|
||||
|
||||
// hyperion includes
|
||||
#include <leddevice/LedDeviceWrapper.h>
|
||||
|
||||
#include <leddevice/LedDevice.h>
|
||||
#include <leddevice/LedDeviceFactory.h>
|
||||
|
||||
#include <hyperion/GrabberWrapper.h>
|
||||
#include <utils/jsonschema/QJsonFactory.h>
|
||||
#include <utils/jsonschema/QJsonSchemaChecker.h>
|
||||
@@ -192,6 +196,8 @@ proceed:
|
||||
handleVideoModeCommand(message, command, tan);
|
||||
else if (command == "instance")
|
||||
handleInstanceCommand(message, command, tan);
|
||||
else if (command == "leddevice")
|
||||
handleLedDeviceCommand(message, command, tan);
|
||||
|
||||
// BEGIN | The following commands are derecated but used to ensure backward compatibility with hyperion Classic remote control
|
||||
else if (command == "clearall")
|
||||
@@ -1385,6 +1391,80 @@ void JsonAPI::handleInstanceCommand(const QJsonObject &message, const QString &c
|
||||
}
|
||||
}
|
||||
|
||||
void JsonAPI::handleLedDeviceCommand(const QJsonObject &message, const QString &command, const int tan)
|
||||
{
|
||||
Debug(_log, "message: [%s]", QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
const QString &subc = message["subcommand"].toString().trimmed();
|
||||
const QString &devType = message["ledDeviceType"].toString().trimmed();
|
||||
|
||||
QString full_command = command + "-" + subc;
|
||||
|
||||
// TODO: Validate that device type is a valid one
|
||||
/* if ( ! valid type )
|
||||
{
|
||||
sendErrorReply("Unknown device", full_command, tan);
|
||||
}
|
||||
else
|
||||
*/ {
|
||||
if (subc == "discover")
|
||||
{
|
||||
|
||||
QJsonObject config;
|
||||
config.insert("type", devType);
|
||||
|
||||
// Pointer of current led device
|
||||
LedDevice* _ledDevice;
|
||||
_ledDevice = LedDeviceFactory::construct(config);
|
||||
|
||||
QJsonObject devicesDiscovered = _ledDevice->discover();
|
||||
|
||||
Debug(_log, "response: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
sendSuccessDataReply(QJsonDocument(devicesDiscovered), full_command, tan);
|
||||
|
||||
delete _ledDevice;
|
||||
}
|
||||
else if (subc == "getProperties")
|
||||
{
|
||||
const QJsonObject ¶ms = message["params"].toObject();
|
||||
|
||||
QJsonObject config;
|
||||
config.insert("type", devType);
|
||||
|
||||
// Pointer of current led device
|
||||
LedDevice* _ledDevice;
|
||||
_ledDevice = LedDeviceFactory::construct(config);
|
||||
|
||||
QJsonObject deviceProperties = _ledDevice->getProperties(params);
|
||||
|
||||
Debug(_log, "response: [%s]", QString(QJsonDocument(deviceProperties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
sendSuccessDataReply(QJsonDocument(deviceProperties), full_command, tan);
|
||||
|
||||
delete _ledDevice;
|
||||
}
|
||||
else if (subc == "identify")
|
||||
{
|
||||
const QJsonObject ¶ms = message["params"].toObject();
|
||||
|
||||
QJsonObject config;
|
||||
config.insert("type", devType);
|
||||
|
||||
// Pointer of current led device
|
||||
LedDevice* _ledDevice;
|
||||
_ledDevice = LedDeviceFactory::construct(config);
|
||||
|
||||
_ledDevice->identify(params);
|
||||
|
||||
sendSuccessReply(full_command, tan);
|
||||
delete _ledDevice;
|
||||
}
|
||||
else
|
||||
{
|
||||
sendErrorReply("Unknown or missing subcommand", full_command, tan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JsonAPI::handleNotImplemented()
|
||||
{
|
||||
sendErrorReply("Command not implemented");
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include <hyperion/ImageProcessor.h>
|
||||
#include "HyperionConfig.h"
|
||||
#include <hyperion/Hyperion.h>
|
||||
#include <utils/QStringUtils.h>
|
||||
|
||||
// project includes
|
||||
#include "BoblightClientConnection.h"
|
||||
@@ -81,7 +82,7 @@ void BoblightClientConnection::readData()
|
||||
void BoblightClientConnection::socketClosed()
|
||||
{
|
||||
// clear the current channel
|
||||
if (_priority != 0 && _priority >= 128 && _priority < 254)
|
||||
if (_priority >= 128 && _priority < 254)
|
||||
_hyperion->clear(_priority);
|
||||
|
||||
emit connectionClosed(this);
|
||||
@@ -90,12 +91,7 @@ void BoblightClientConnection::socketClosed()
|
||||
void BoblightClientConnection::handleMessage(const QString & message)
|
||||
{
|
||||
//std::cout << "boblight message: " << message.toStdString() << std::endl;
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||
QStringList messageParts = message.split(" ", Qt::SkipEmptyParts);
|
||||
#else
|
||||
QStringList messageParts = message.split(" ", QString::SkipEmptyParts);
|
||||
#endif
|
||||
|
||||
QStringList messageParts = QStringUtils::split(message," ",QStringUtils::SplitBehavior::SkipEmptyParts);
|
||||
if (messageParts.size() > 0)
|
||||
{
|
||||
if (messageParts[0] == "hello")
|
||||
@@ -217,7 +213,7 @@ void BoblightClientConnection::handleMessage(const QString & message)
|
||||
}
|
||||
else if (messageParts[0] == "sync")
|
||||
{
|
||||
if (_priority != 0 && _priority >= 128 && _priority < 254)
|
||||
if ( _priority >= 128 && _priority < 254)
|
||||
_hyperion->setInput(_priority, _ledColors); // send current color values to hyperion
|
||||
|
||||
return;
|
||||
|
@@ -1,5 +1,4 @@
|
||||
#include <leddevice/LedDevice.h>
|
||||
#include <sstream>
|
||||
|
||||
//QT include
|
||||
#include <QResource>
|
||||
@@ -13,102 +12,115 @@
|
||||
#include "hyperion/Hyperion.h"
|
||||
#include <utils/JsonUtils.h>
|
||||
|
||||
LedDevice::LedDevice(const QJsonObject& config, QObject* parent)
|
||||
//std includes
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
LedDevice::LedDevice(const QJsonObject& deviceConfig, QObject* parent)
|
||||
: QObject(parent)
|
||||
, _devConfig(config)
|
||||
, _log(Logger::getInstance("LEDDEVICE"))
|
||||
, _ledBuffer(0)
|
||||
, _deviceReady(false)
|
||||
, _deviceInError(false)
|
||||
, _refresh_timer(new QTimer(this))
|
||||
, _refresh_timer_interval(0)
|
||||
, _lastWriteTime(QDateTime::currentDateTime())
|
||||
, _latchTime_ms(0)
|
||||
, _componentRegistered(false)
|
||||
, _enabled(false)
|
||||
, _refresh_enabled(false)
|
||||
, _devConfig(deviceConfig)
|
||||
, _log(Logger::getInstance("LEDDEVICE"))
|
||||
, _ledBuffer(0)
|
||||
, _refreshTimer(nullptr)
|
||||
, _refreshTimerInterval_ms(0)
|
||||
, _latchTime_ms(0)
|
||||
, _isRestoreOrigState(false)
|
||||
, _isEnabled(false)
|
||||
, _isDeviceInitialised(false)
|
||||
, _isDeviceReady(false)
|
||||
, _isDeviceInError(false)
|
||||
, _isInSwitchOff (false)
|
||||
, _lastWriteTime(QDateTime::currentDateTime())
|
||||
, _isRefreshEnabled (false)
|
||||
{
|
||||
// setup refreshTimer
|
||||
_refresh_timer->setTimerType(Qt::PreciseTimer);
|
||||
_refresh_timer->setInterval( _refresh_timer_interval );
|
||||
connect(_refresh_timer, SIGNAL(timeout()), this, SLOT(rewriteLeds()));
|
||||
|
||||
}
|
||||
|
||||
LedDevice::~LedDevice()
|
||||
{
|
||||
delete _refresh_timer;
|
||||
delete _refreshTimer;
|
||||
}
|
||||
|
||||
void LedDevice::start()
|
||||
{
|
||||
Info(_log, "Start LedDevice '%s'.", QSTRING_CSTR(_activeDeviceType));
|
||||
|
||||
// setup refreshTimer
|
||||
if ( _refreshTimer == nullptr )
|
||||
{
|
||||
_refreshTimer = new QTimer(this);
|
||||
_refreshTimer->setTimerType(Qt::PreciseTimer);
|
||||
_refreshTimer->setInterval( _refreshTimerInterval_ms );
|
||||
connect(_refreshTimer, &QTimer::timeout, this, &LedDevice::rewriteLEDs );
|
||||
}
|
||||
|
||||
close();
|
||||
|
||||
_isDeviceInitialised = false;
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_isDeviceInitialised = true;
|
||||
setEnable(true);
|
||||
}
|
||||
}
|
||||
|
||||
void LedDevice::stop()
|
||||
{
|
||||
setEnable(false);
|
||||
this->stopRefreshTimer();
|
||||
}
|
||||
|
||||
int LedDevice::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = true;
|
||||
int retval = 0;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDevice::close()
|
||||
{
|
||||
_isDeviceReady = false;
|
||||
int retval = 0;
|
||||
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDevice::setInError(const QString& errorMsg)
|
||||
{
|
||||
_deviceInError = true;
|
||||
_deviceReady = false;
|
||||
_enabled = false;
|
||||
_isDeviceInError = true;
|
||||
_isDeviceReady = false;
|
||||
_isEnabled = false;
|
||||
this->stopRefreshTimer();
|
||||
|
||||
Error(_log, "Device disabled, device '%s' signals error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(errorMsg));
|
||||
emit enableStateChanged(_enabled);
|
||||
}
|
||||
|
||||
void LedDevice::close()
|
||||
{
|
||||
switchOff();
|
||||
this->stopRefreshTimer();
|
||||
emit enableStateChanged(_isEnabled);
|
||||
}
|
||||
|
||||
void LedDevice::setEnable(bool enable)
|
||||
{
|
||||
if ( !_deviceReady && enable )
|
||||
bool isSwitched = false;
|
||||
// switch off device when disabled, default: set black to LEDs when they should go off
|
||||
if ( _isEnabled && !enable)
|
||||
{
|
||||
Debug(_log, "Device '%s' was not ready! Trying to re-open.", QSTRING_CSTR(_activeDeviceType));
|
||||
if ( open() < 0 )
|
||||
{
|
||||
Error(_log, "Device '%s' cannot be enabled, as it is not ready!", QSTRING_CSTR(_activeDeviceType));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Open worked
|
||||
_deviceInError = false;
|
||||
}
|
||||
}
|
||||
|
||||
// emit signal when state changed
|
||||
if ( _enabled != enable )
|
||||
{
|
||||
emit enableStateChanged(enable);
|
||||
}
|
||||
// switch off device when disabled, default: set black to leds when they should go off
|
||||
if ( _enabled && !enable )
|
||||
{
|
||||
switchOff();
|
||||
isSwitched = switchOff();
|
||||
}
|
||||
else
|
||||
{
|
||||
// switch on device when enabled
|
||||
if ( !_enabled && enable )
|
||||
if ( !_isEnabled && enable)
|
||||
{
|
||||
switchOn();
|
||||
isSwitched = switchOn();
|
||||
}
|
||||
}
|
||||
_enabled = enable;
|
||||
|
||||
if ( isSwitched )
|
||||
{
|
||||
_isEnabled = enable;
|
||||
emit enableStateChanged(enable);
|
||||
}
|
||||
}
|
||||
|
||||
void LedDevice::setActiveDeviceType(const QString& deviceType)
|
||||
@@ -118,28 +130,28 @@ void LedDevice::setActiveDeviceType(const QString& deviceType)
|
||||
|
||||
bool LedDevice::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
//Debug(_log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
Debug(_log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
_colorOrder = deviceConfig["colorOrder"].toString("RGB");
|
||||
_activeDeviceType = deviceConfig["type"].toString("file").toLower();
|
||||
setLedCount(static_cast<unsigned int>( deviceConfig["currentLedCount"].toInt(1) )); // property injected to reflect real led count
|
||||
|
||||
_latchTime_ms = deviceConfig["latchTime"].toInt( _latchTime_ms );
|
||||
_refresh_timer_interval = deviceConfig["rewriteTime"].toInt( _refresh_timer_interval);
|
||||
_latchTime_ms =deviceConfig["latchTime"].toInt( _latchTime_ms );
|
||||
_refreshTimerInterval_ms = deviceConfig["rewriteTime"].toInt( _refreshTimerInterval_ms);
|
||||
|
||||
if ( _refresh_timer_interval > 0 )
|
||||
if ( _refreshTimerInterval_ms > 0 )
|
||||
{
|
||||
_refresh_enabled = true;
|
||||
_isRefreshEnabled = true;
|
||||
|
||||
if ( _refresh_timer_interval <= _latchTime_ms )
|
||||
if (_refreshTimerInterval_ms <= _latchTime_ms )
|
||||
{
|
||||
int new_refresh_timer_interval = _latchTime_ms + 10;
|
||||
Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d), set rewriteTime to %dms", _latchTime_ms, _refresh_timer_interval, new_refresh_timer_interval);
|
||||
_refresh_timer_interval = new_refresh_timer_interval;
|
||||
Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d), set rewriteTime to %dms", _latchTime_ms, _refreshTimerInterval_ms, new_refresh_timer_interval);
|
||||
_refreshTimerInterval_ms = new_refresh_timer_interval;
|
||||
_refreshTimer->setInterval( _refreshTimerInterval_ms );
|
||||
}
|
||||
|
||||
//Debug(_log, "Refresh interval = %dms",_refresh_timer_interval );
|
||||
_refresh_timer->setInterval( _refresh_timer_interval );
|
||||
Debug(_log, "Refresh interval = %dms",_refreshTimerInterval_ms );
|
||||
_refreshTimer->setInterval( _refreshTimerInterval_ms );
|
||||
|
||||
_lastWriteTime = QDateTime::currentDateTime();
|
||||
|
||||
@@ -150,21 +162,21 @@ bool LedDevice::init(const QJsonObject &deviceConfig)
|
||||
|
||||
void LedDevice::startRefreshTimer()
|
||||
{
|
||||
if ( _deviceReady )
|
||||
if ( _isDeviceReady && _isEnabled )
|
||||
{
|
||||
_refresh_timer->start();
|
||||
_refreshTimer->start();
|
||||
}
|
||||
}
|
||||
|
||||
void LedDevice::stopRefreshTimer()
|
||||
{
|
||||
_refresh_timer->stop();
|
||||
_refreshTimer->stop();
|
||||
}
|
||||
|
||||
int LedDevice::updateLeds(const std::vector<ColorRgb>& ledValues)
|
||||
{
|
||||
int retval = 0;
|
||||
if ( !_deviceReady || _deviceInError )
|
||||
if ( !isEnabled() || !_isDeviceReady || _isDeviceInError )
|
||||
{
|
||||
//std::cout << "LedDevice::updateLeds(), LedDevice NOT ready!" << std::endl;
|
||||
return -1;
|
||||
@@ -179,16 +191,16 @@ int LedDevice::updateLeds(const std::vector<ColorRgb>& ledValues)
|
||||
_lastWriteTime = QDateTime::currentDateTime();
|
||||
|
||||
// if device requires refreshing, save Led-Values and restart the timer
|
||||
if ( _refresh_enabled )
|
||||
if ( _isRefreshEnabled && _isEnabled )
|
||||
{
|
||||
this->startRefreshTimer();
|
||||
_last_ledValues = ledValues;
|
||||
_lastLedValues = ledValues;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::cout << "LedDevice::updateLeds(), Skip write. elapsedTime (" << elapsedTimeMs << ") ms < _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
|
||||
if ( _refresh_enabled )
|
||||
if ( _isRefreshEnabled )
|
||||
{
|
||||
//Stop timer to allow for next non-refresh update
|
||||
this->stopRefreshTimer();
|
||||
@@ -198,30 +210,187 @@ int LedDevice::updateLeds(const std::vector<ColorRgb>& ledValues)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDevice::writeBlack()
|
||||
int LedDevice::rewriteLEDs()
|
||||
{
|
||||
return _deviceReady ? updateLeds(std::vector<ColorRgb>(static_cast<unsigned long>(_ledCount), ColorRgb::BLACK )) : -1;
|
||||
int retval = -1;
|
||||
|
||||
if ( _isDeviceReady && _isEnabled )
|
||||
{
|
||||
// qint64 elapsedTimeMs = _lastWriteTime.msecsTo(QDateTime::currentDateTime());
|
||||
// std::cout << "LedDevice::rewriteLEDs(): Rewrite LEDs now, elapsedTime [" << elapsedTimeMs << "] ms" << std::endl;
|
||||
// //:TESTING: Inject "white" output records to differentiate from normal writes
|
||||
// _lastLedValues.clear();
|
||||
// _lastLedValues.resize(static_cast<unsigned long>(_ledCount), ColorRgb::WHITE);
|
||||
// printLedValues(_lastLedValues);
|
||||
// //:TESTING:
|
||||
|
||||
retval = write(_lastLedValues);
|
||||
_lastWriteTime = QDateTime::currentDateTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If Device is not ready stop timer
|
||||
this->stopRefreshTimer();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDevice::switchOff()
|
||||
int LedDevice::writeBlack(int numberOfBlack)
|
||||
{
|
||||
// Stop refresh timer to ensure that "write Black" is executed
|
||||
this->stopRefreshTimer();
|
||||
int rc = -1;
|
||||
|
||||
if ( _latchTime_ms > 0 )
|
||||
for (int i = 0; i < numberOfBlack; i++)
|
||||
{
|
||||
// Wait latchtime before writing black
|
||||
QEventLoop loop;
|
||||
QTimer::singleShot( _latchTime_ms, &loop, SLOT( quit() ) );
|
||||
loop.exec();
|
||||
if ( _latchTime_ms > 0 )
|
||||
{
|
||||
// Wait latch time before writing black
|
||||
QEventLoop loop;
|
||||
QTimer::singleShot( _latchTime_ms, &loop, SLOT( quit() ) );
|
||||
loop.exec();
|
||||
}
|
||||
rc = write(std::vector<ColorRgb>(static_cast<unsigned long>(_ledCount), ColorRgb::BLACK ));
|
||||
}
|
||||
int rc = writeBlack();
|
||||
return rc;
|
||||
}
|
||||
|
||||
int LedDevice::switchOn()
|
||||
bool LedDevice::switchOn()
|
||||
{
|
||||
return 0;
|
||||
bool rc = false;
|
||||
if ( _isDeviceInitialised && ! _isDeviceReady && ! _isEnabled )
|
||||
{
|
||||
_isDeviceInError = false;
|
||||
if ( open() < 0 )
|
||||
{
|
||||
rc = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
storeState();
|
||||
|
||||
if ( powerOn() )
|
||||
{
|
||||
_isEnabled = true;
|
||||
rc = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool LedDevice::switchOff()
|
||||
{
|
||||
bool rc = false;
|
||||
|
||||
if ( _isDeviceInitialised )
|
||||
{
|
||||
// Disable device to ensure no standard Led updates are written/processed
|
||||
_isEnabled = false;
|
||||
_isInSwitchOff = true;
|
||||
|
||||
this->stopRefreshTimer();
|
||||
|
||||
rc = true;
|
||||
|
||||
if ( _isDeviceReady )
|
||||
{
|
||||
if ( _isRestoreOrigState )
|
||||
{
|
||||
//Restore devices state
|
||||
restoreState();
|
||||
}
|
||||
else
|
||||
{
|
||||
powerOff();
|
||||
}
|
||||
|
||||
}
|
||||
if ( close() < 0 )
|
||||
{
|
||||
rc = false;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
bool LedDevice::powerOff()
|
||||
{
|
||||
bool rc = false;
|
||||
|
||||
// Simulate power-off by writing a final "Black" to have a defined outcome
|
||||
if ( writeBlack() >= 0 )
|
||||
{
|
||||
rc = true;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool LedDevice::powerOn()
|
||||
{
|
||||
bool rc = true;
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool LedDevice::storeState()
|
||||
{
|
||||
bool rc = true;
|
||||
|
||||
if ( _isRestoreOrigState )
|
||||
{
|
||||
// Save device's original state
|
||||
// _originalStateValues = get device's state;
|
||||
// store original power on/off state, if available
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool LedDevice::restoreState()
|
||||
{
|
||||
bool rc = true;
|
||||
|
||||
if ( _isRestoreOrigState )
|
||||
{
|
||||
// Restore device's original state
|
||||
// update device using _originalStateValues
|
||||
// update original power on/off state, if supported
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
QJsonObject LedDevice::discover()
|
||||
{
|
||||
QJsonObject devicesDiscovered;
|
||||
|
||||
devicesDiscovered.insert("ledDeviceType", _activeDeviceType);
|
||||
|
||||
QJsonArray deviceList;
|
||||
devicesDiscovered.insert("devices", deviceList);
|
||||
|
||||
Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
return devicesDiscovered;
|
||||
}
|
||||
|
||||
QString LedDevice::discoverFirst()
|
||||
{
|
||||
QString deviceDiscovered;
|
||||
|
||||
Debug(_log, "deviceDiscovered: [%s]", QSTRING_CSTR(deviceDiscovered) );
|
||||
return deviceDiscovered;
|
||||
}
|
||||
|
||||
|
||||
QJsonObject LedDevice::getProperties(const QJsonObject& params)
|
||||
{
|
||||
Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
QJsonObject properties;
|
||||
|
||||
QJsonObject deviceProperties;
|
||||
properties.insert("properties", deviceProperties);
|
||||
|
||||
Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
void LedDevice::setLedCount(unsigned int ledCount)
|
||||
@@ -237,31 +406,6 @@ void LedDevice::setLatchTime( int latchTime_ms )
|
||||
Debug(_log, "LatchTime updated to %dms", this->getLatchTime());
|
||||
}
|
||||
|
||||
int LedDevice::rewriteLeds()
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
if ( _deviceReady )
|
||||
{
|
||||
// qint64 elapsedTimeMs = _lastWriteTime.msecsTo(QDateTime::currentDateTime());
|
||||
// std::cout << "LedDevice::rewriteLEDs(): Rewrite LEDs now, elapsedTime [" << elapsedTimeMs << "] ms" << std::endl;
|
||||
// //:TESTING: Inject "white" output records to differentiate from normal writes
|
||||
// _last_ledValues.clear();
|
||||
// _last_ledValues.resize(static_cast<unsigned long>(_ledCount), ColorRgb::WHITE);
|
||||
// printLedValues(_last_ledValues);
|
||||
//:TESTING:
|
||||
|
||||
retval = write(_last_ledValues);
|
||||
_lastWriteTime = QDateTime::currentDateTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If Device is not ready stop timer
|
||||
this->stopRefreshTimer();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDevice::printLedValues(const std::vector<ColorRgb>& ledValues)
|
||||
{
|
||||
std::cout << "LedValues [" << ledValues.size() <<"] [";
|
||||
@@ -271,3 +415,18 @@ void LedDevice::printLedValues(const std::vector<ColorRgb>& ledValues)
|
||||
}
|
||||
std::cout << "]" << std::endl;
|
||||
}
|
||||
|
||||
QString LedDevice::uint8_t_to_hex_string(const uint8_t * data, const qint64 size, qint64 number) const
|
||||
{
|
||||
if ( number <= 0 || number > size)
|
||||
{
|
||||
number = size;
|
||||
}
|
||||
|
||||
QByteArray bytes (reinterpret_cast<const char*>(data), number);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
return bytes.toHex(':');
|
||||
#else
|
||||
return bytes.toHex();
|
||||
#endif
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ LedDevice * LedDeviceFactory::construct(const QJsonObject & deviceConfig)
|
||||
{
|
||||
Logger * log = Logger::getInstance("LEDDEVICE");
|
||||
QJsonDocument config(deviceConfig);
|
||||
QString ss(config.toJson(QJsonDocument::Indented));
|
||||
|
||||
QString type = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
|
||||
@@ -31,7 +30,6 @@ LedDevice * LedDeviceFactory::construct(const QJsonObject & deviceConfig)
|
||||
if (dev.first == type)
|
||||
{
|
||||
device = dev.second(deviceConfig);
|
||||
Info(log,"LedDevice '%s' found.", QSTRING_CSTR(dev.first));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -33,5 +33,7 @@
|
||||
<file alias="schema-ws281x">schemas/schema-ws281x.json</file>
|
||||
<file alias="schema-karate">schemas/schema-karate.json</file>
|
||||
<file alias="schema-nanoleaf">schemas/schema-nanoleaf.json</file>
|
||||
<file alias="schema-wled">schemas/schema-wled.json</file>
|
||||
<file alias="schema-yeelight">schemas/schema-yeelight.json</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -4,7 +4,9 @@ LedDeviceTemplate::LedDeviceTemplate(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceTemplate::construct(const QJsonObject &deviceConfig)
|
||||
@@ -14,18 +16,25 @@ LedDevice* LedDeviceTemplate::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceTemplate::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
// Initiatiale LedDevice configuration and execution environment
|
||||
// ...
|
||||
if ( 0 /*Error during init*/)
|
||||
// Initialise sub-class
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
//Build an errortext, illustrative
|
||||
QString errortext = QString ("Error message: %1").arg("errno/text");
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
// Initialise LedDevice configuration and execution environment
|
||||
// ...
|
||||
if ( 0 /*Error during init*/)
|
||||
{
|
||||
//Build an errortext, illustrative
|
||||
QString errortext = QString ("Error message: %1").arg("errno/text");
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
@@ -33,42 +42,45 @@ int LedDeviceTemplate::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
// Try to open the LedDevice
|
||||
//...
|
||||
|
||||
if ( false /*If opening failed*/ )
|
||||
{
|
||||
// Open/Start LedDevice based on configuration
|
||||
//...
|
||||
//Build an errortext, illustrative
|
||||
errortext = QString ("Failed to xxx. Error message: %1").arg("errno/text");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
if ( false /*If opening failed*/ )
|
||||
{
|
||||
//Build an errortext, illustrative
|
||||
errortext = QString ("Failed to xxx. Error message: %1").arg("errno/text");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDeviceTemplate::close()
|
||||
int LedDeviceTemplate::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
// LedDevice specific closing activites
|
||||
// LedDevice specific closing activities
|
||||
//...
|
||||
int retval = 0;
|
||||
_isDeviceReady = false;
|
||||
|
||||
// Test, if device requires closing
|
||||
if ( true /*If device is still open*/ )
|
||||
{
|
||||
// Close device
|
||||
// Everything is OK -> device is closed
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceTemplate::write(const std::vector<ColorRgb> & ledValues)
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICETEMPLATE_H
|
||||
#define LEDEVICETEMPLATE_H
|
||||
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
@@ -10,46 +11,56 @@
|
||||
class LedDeviceTemplate : public LedDevice
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a specific LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceTemplate(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
/// Writes the led color values to the led-device
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
//////
|
||||
/// @brief Closes the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // LEDEVICETEMPLATE_H
|
||||
|
@@ -22,10 +22,10 @@ LedDeviceWrapper::LedDeviceWrapper(Hyperion* hyperion)
|
||||
, _ledDevice(nullptr)
|
||||
, _enabled(false)
|
||||
{
|
||||
// prepare the device constrcutor map
|
||||
// prepare the device constructor map
|
||||
#define REGISTER(className) LedDeviceWrapper::addToDeviceMap(QString(#className).toLower(), LedDevice##className::construct);
|
||||
|
||||
// the REGISTER() calls are autogenerated by cmake.
|
||||
// the REGISTER() calls are auto-generated by cmake.
|
||||
#include "LedDevice_register.cpp"
|
||||
|
||||
#undef REGISTER
|
||||
@@ -59,7 +59,7 @@ void LedDeviceWrapper::createLedDevice(const QJsonObject& config)
|
||||
connect(this, &LedDeviceWrapper::updateLeds, _ledDevice, &LedDevice::updateLeds, Qt::QueuedConnection);
|
||||
connect(this, &LedDeviceWrapper::setEnable, _ledDevice, &LedDevice::setEnable);
|
||||
|
||||
connect(this, &LedDeviceWrapper::closeLedDevice, _ledDevice, &LedDevice::close, Qt::BlockingQueuedConnection);
|
||||
connect(this, &LedDeviceWrapper::closeLedDevice, _ledDevice, &LedDevice::stop, Qt::BlockingQueuedConnection);
|
||||
|
||||
connect(_ledDevice, &LedDevice::enableStateChanged, this, &LedDeviceWrapper::handleInternalEnableState, Qt::QueuedConnection);
|
||||
|
||||
@@ -72,7 +72,7 @@ const QJsonObject LedDeviceWrapper::getLedDeviceSchemas()
|
||||
// make sure the resources are loaded (they may be left out after static linking)
|
||||
Q_INIT_RESOURCE(LedDeviceSchemas);
|
||||
|
||||
// read the json schema from the resource
|
||||
// read the JSON schema from the resource
|
||||
QDir d(":/leddevices/");
|
||||
QStringList l = d.entryList();
|
||||
QJsonObject result, schemaJson;
|
||||
@@ -91,7 +91,7 @@ const QJsonObject LedDeviceWrapper::getLedDeviceSchemas()
|
||||
QJsonObject schema;
|
||||
if(!JsonUtils::parse(schemaPath, data, schema, Logger::getInstance("LedDevice")))
|
||||
{
|
||||
throw std::runtime_error("ERROR: Json schema wrong of file: " + item.toStdString());
|
||||
throw std::runtime_error("ERROR: JSON schema wrong of file: " + item.toStdString());
|
||||
}
|
||||
|
||||
schemaJson = schema;
|
||||
@@ -134,6 +134,11 @@ unsigned int LedDeviceWrapper::getLedCount() const
|
||||
return _ledDevice->getLedCount();
|
||||
}
|
||||
|
||||
bool LedDeviceWrapper::enabled()
|
||||
{
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
void LedDeviceWrapper::handleComponentState(const hyperion::Components component, const bool state)
|
||||
{
|
||||
if(component == hyperion::COMP_LEDDEVICE)
|
||||
@@ -155,7 +160,7 @@ void LedDeviceWrapper::handleInternalEnableState(bool newState)
|
||||
|
||||
void LedDeviceWrapper::stopDeviceThread()
|
||||
{
|
||||
// turns the leds off & stop refresh timers
|
||||
// turns the LEDs off & stop refresh timers
|
||||
emit closeLedDevice();
|
||||
std::cout << "[hyperiond LedDeviceWrapper] <INFO> LedDevice \'" << QSTRING_CSTR(_ledDevice->getActiveDeviceType()) << "\' closed" << std::endl;
|
||||
|
||||
|
@@ -5,11 +5,12 @@
|
||||
// Local Hyperion includes
|
||||
#include "LedDeviceHyperionUsbasp.h"
|
||||
|
||||
// Static constants which define the Hyperion Usbasp device
|
||||
uint16_t LedDeviceHyperionUsbasp::_usbVendorId = 0x16c0;
|
||||
uint16_t LedDeviceHyperionUsbasp::_usbProductId = 0x05dc;
|
||||
QString LedDeviceHyperionUsbasp::_usbProductDescription = "Hyperion led controller";
|
||||
|
||||
// Constants which define the Hyperion USBasp device
|
||||
namespace {
|
||||
uint16_t _usbVendorId = 0x16c0;
|
||||
uint16_t _usbProductId = 0x05dc;
|
||||
QString _usbProductDescription = "Hyperion led controller";
|
||||
}
|
||||
|
||||
LedDeviceHyperionUsbasp::LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
@@ -17,11 +18,17 @@ LedDeviceHyperionUsbasp::LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig
|
||||
, _deviceHandle(nullptr)
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDeviceHyperionUsbasp::~LedDeviceHyperionUsbasp()
|
||||
{
|
||||
if (_libusbContext != nullptr)
|
||||
{
|
||||
libusb_exit(_libusbContext);
|
||||
}
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceHyperionUsbasp::construct(const QJsonObject &deviceConfig)
|
||||
@@ -31,18 +38,68 @@ LedDevice* LedDeviceHyperionUsbasp::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceHyperionUsbasp::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
QString ledType = deviceConfig["ledType"].toString("ws2801");
|
||||
if (ledType != "ws2801" && ledType != "ws2812")
|
||||
// Initialise sub-class
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
QString errortext = QString ("Invalid ledType; must be 'ws2801' or 'ws2812'.");
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_writeLedsCommand = (ledType == "ws2801") ? CMD_WRITE_WS2801 : CMD_WRITE_WS2812;
|
||||
QString ledType = deviceConfig["ledType"].toString("ws2801");
|
||||
if (ledType != "ws2801" && ledType != "ws2812")
|
||||
{
|
||||
QString errortext = QString ("Invalid ledType; must be 'ws2801' or 'ws2812'.");
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_writeLedsCommand = (ledType == "ws2801") ? CMD_WRITE_WS2801 : CMD_WRITE_WS2812;
|
||||
|
||||
int error;
|
||||
// initialize the USB context
|
||||
if ( (error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS )
|
||||
{
|
||||
_libusbContext = nullptr;
|
||||
|
||||
QString errortext = QString ("Error while initializing USB context(%1):%2").arg(error).arg(libusb_error_name(error));
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug(_log, "USB context initialized");
|
||||
//libusb_set_debug(_libusbContext, 3);
|
||||
|
||||
// retrieve the list of USB devices
|
||||
libusb_device ** deviceList;
|
||||
ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
|
||||
|
||||
// iterate the list of devices
|
||||
for (ssize_t i = 0 ; i < deviceCount; ++i)
|
||||
{
|
||||
// try to open and initialize the device
|
||||
if ( testAndOpen(deviceList[i]) == 0 )
|
||||
{
|
||||
_device = deviceList[i];
|
||||
// a device was successfully opened. break from list
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// free the device list
|
||||
libusb_free_device_list(deviceList, 1);
|
||||
|
||||
if (_deviceHandle == nullptr)
|
||||
{
|
||||
QString errortext;
|
||||
errortext = QString ("No %1 has been found").arg( _usbProductDescription);
|
||||
this->setInError( errortext );
|
||||
}
|
||||
else
|
||||
{
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isInitOK;
|
||||
@@ -51,73 +108,29 @@ bool LedDeviceHyperionUsbasp::init(const QJsonObject &deviceConfig)
|
||||
int LedDeviceHyperionUsbasp::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
if ( libusb_open(_device, &_deviceHandle) != LIBUSB_SUCCESS )
|
||||
{
|
||||
int error;
|
||||
|
||||
// initialize the usb context
|
||||
if ((error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS)
|
||||
{
|
||||
//Error(_log, "Error while initializing USB context(%d):%s", error, libusb_error_name(error));
|
||||
errortext = QString ("Error while initializing USB context(%1):%2").arg( error).arg(libusb_error_name(error));
|
||||
_libusbContext = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
//libusb_set_debug(_libusbContext, 3);
|
||||
Debug(_log, "USB context initialized");
|
||||
|
||||
// retrieve the list of usb devices
|
||||
libusb_device ** deviceList;
|
||||
ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
|
||||
|
||||
// iterate the list of devices
|
||||
for (ssize_t i = 0 ; i < deviceCount; ++i)
|
||||
{
|
||||
// try to open and initialize the device
|
||||
error = testAndOpen(deviceList[i]);
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
// a device was sucessfully opened. break from list
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// free the device list
|
||||
libusb_free_device_list(deviceList, 1);
|
||||
|
||||
if (_deviceHandle == nullptr)
|
||||
{
|
||||
//Error(_log, "No %s has been found", QSTRING_CSTR(_usbProductDescription));
|
||||
errortext = QString ("No %1 has been found").arg( _usbProductDescription);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
QString errortext = QString ("Failed to open [%1]").arg(_usbProductDescription);
|
||||
this->setInError(errortext);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDeviceHyperionUsbasp::close()
|
||||
int LedDeviceHyperionUsbasp::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
int retval = 0;
|
||||
_isDeviceReady = false;
|
||||
|
||||
// LedDevice specific closing activites
|
||||
// LedDevice specific closing activities
|
||||
if (_deviceHandle != nullptr)
|
||||
{
|
||||
libusb_release_interface(_deviceHandle, 0);
|
||||
@@ -126,12 +139,7 @@ void LedDeviceHyperionUsbasp::close()
|
||||
|
||||
_deviceHandle = nullptr;
|
||||
}
|
||||
|
||||
if (_libusbContext != nullptr)
|
||||
{
|
||||
libusb_exit(_libusbContext);
|
||||
_libusbContext = nullptr;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceHyperionUsbasp::testAndOpen(libusb_device * device)
|
||||
@@ -176,7 +184,7 @@ int LedDeviceHyperionUsbasp::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
int nbytes = libusb_control_transfer(
|
||||
_deviceHandle, // device handle
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, // request type
|
||||
static_cast<uint8_t>( LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT ), // request type
|
||||
_writeLedsCommand, // request
|
||||
0, // value
|
||||
0, // index
|
||||
@@ -184,7 +192,7 @@ int LedDeviceHyperionUsbasp::write(const std::vector<ColorRgb> &ledValues)
|
||||
(3*_ledCount) & 0xffff, // length
|
||||
5000); // timeout
|
||||
|
||||
// Disabling interupts for a little while on the device results in a PIPE error. All seems to keep functioning though...
|
||||
// Disabling interrupts for a little while on the device results in a PIPE error. All seems to keep functioning though...
|
||||
if(nbytes < 0 && nbytes != LIBUSB_ERROR_PIPE)
|
||||
{
|
||||
Error(_log, "Error while writing data to %s (%s)", QSTRING_CSTR(_usbProductDescription), libusb_error_name(nbytes));
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEHYPERIONUSBASP_H
|
||||
#define LEDEVICEHYPERIONUSBASP_H
|
||||
|
||||
// stl includes
|
||||
#include <vector>
|
||||
@@ -32,7 +33,7 @@ public:
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @para#endif // LEDEVICETEMPLATE_Hm deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
@@ -49,7 +50,7 @@ public slots:
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
virtual int close() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
@@ -85,11 +86,11 @@ protected:
|
||||
/// libusb context
|
||||
libusb_context * _libusbContext;
|
||||
|
||||
/// libusb device
|
||||
libusb_device * _device;
|
||||
|
||||
/// libusb device handle
|
||||
libusb_device_handle * _deviceHandle;
|
||||
|
||||
/// Usb device identifiers
|
||||
static uint16_t _usbVendorId;
|
||||
static uint16_t _usbProductId;
|
||||
static QString _usbProductDescription;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEHYPERIONUSBASP_H
|
||||
|
@@ -32,20 +32,6 @@ enum DATA_VERSION_INDEXES{
|
||||
INDEX_FW_VER_MINOR
|
||||
};
|
||||
|
||||
LedDeviceLightpack::LedDeviceLightpack(const QString & serialNumber)
|
||||
: LedDevice()
|
||||
, _libusbContext(nullptr)
|
||||
, _deviceHandle(nullptr)
|
||||
, _busNumber(-1)
|
||||
, _addressNumber(-1)
|
||||
, _serialNumber(serialNumber)
|
||||
, _firmwareVersion({-1,-1})
|
||||
, _bitsPerChannel(-1)
|
||||
, _hwLedCount(-1)
|
||||
{
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDeviceLightpack::LedDeviceLightpack(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
, _libusbContext(nullptr)
|
||||
@@ -55,13 +41,20 @@ LedDeviceLightpack::LedDeviceLightpack(const QJsonObject &deviceConfig)
|
||||
, _firmwareVersion({-1,-1})
|
||||
, _bitsPerChannel(-1)
|
||||
, _hwLedCount(-1)
|
||||
,_isOpen(false)
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDeviceLightpack::~LedDeviceLightpack()
|
||||
{
|
||||
if (_libusbContext != nullptr)
|
||||
{
|
||||
libusb_exit(_libusbContext);
|
||||
}
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceLightpack::construct(const QJsonObject &deviceConfig)
|
||||
@@ -71,36 +64,29 @@ LedDevice* LedDeviceLightpack::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceLightpack::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
_serialNumber = deviceConfig["output"].toString("");
|
||||
bool isInitOK = false;
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceLightpack::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
// Initialise sub-class
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
int error;
|
||||
_serialNumber = deviceConfig["serial"].toString("");
|
||||
|
||||
// initialize the usb context
|
||||
if ((error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS)
|
||||
int error;
|
||||
// initialize the USB context
|
||||
if ( (error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS )
|
||||
{
|
||||
//Error(_log, "Error while initializing USB context(%d): %s", error, libusb_error_name(error));
|
||||
errortext = QString ("Error while initializing USB context(%1):%2").arg( error).arg(libusb_error_name(error));
|
||||
_libusbContext = nullptr;
|
||||
|
||||
QString errortext = QString ("Error while initializing USB context(%1):%2").arg(error).arg(libusb_error_name(error));
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//libusb_set_debug(_libusbContext, 3);
|
||||
Debug(_log, "USB context initialized");
|
||||
//libusb_set_debug(_libusbContext, 3);
|
||||
|
||||
// retrieve the list of usb devices
|
||||
// retrieve the list of USB devices
|
||||
libusb_device ** deviceList;
|
||||
ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
|
||||
|
||||
@@ -108,11 +94,10 @@ int LedDeviceLightpack::open()
|
||||
for (ssize_t i = 0 ; i < deviceCount; ++i)
|
||||
{
|
||||
// try to open and initialize the device
|
||||
error = testAndOpen(deviceList[i], _serialNumber);
|
||||
|
||||
if (error == 0)
|
||||
if (testAndOpen(deviceList[i], _serialNumber) == 0)
|
||||
{
|
||||
// a device was sucessfully opened. break from list
|
||||
_device = deviceList[i];
|
||||
// a device was successfully opened. break from list
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -122,53 +107,62 @@ int LedDeviceLightpack::open()
|
||||
|
||||
if (_deviceHandle == nullptr)
|
||||
{
|
||||
QString errortext;
|
||||
if (_serialNumber.isEmpty())
|
||||
{
|
||||
//Warning(_log, "No Lightpack device has been found");
|
||||
errortext = QString ("No Lightpack devices were found");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Error(_log,"No Lightpack device has been found with serial %", QSTRING_CSTR(_serialNumber));
|
||||
errortext = QString ("No Lightpack device has been found with serial %1").arg( _serialNumber);
|
||||
}
|
||||
this->setInError( errortext );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceLightpack::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if ( libusb_open(_device, &_deviceHandle) != LIBUSB_SUCCESS )
|
||||
{
|
||||
QString errortext = QString ("Failed to open [%1]").arg(_serialNumber);
|
||||
this->setInError(errortext);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDeviceLightpack::close()
|
||||
int LedDeviceLightpack::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
int retval = 0;
|
||||
_isDeviceReady = false;
|
||||
|
||||
// LedDevice specific closing activites
|
||||
// LedDevice specific closing activities
|
||||
if (_deviceHandle != nullptr)
|
||||
{
|
||||
_isOpen = false;
|
||||
libusb_release_interface(_deviceHandle, LIGHTPACK_INTERFACE);
|
||||
libusb_attach_kernel_driver(_deviceHandle, LIGHTPACK_INTERFACE);
|
||||
libusb_close(_deviceHandle);
|
||||
|
||||
_deviceHandle = nullptr;
|
||||
}
|
||||
|
||||
if (_libusbContext != nullptr)
|
||||
{
|
||||
libusb_exit(_libusbContext);
|
||||
_libusbContext = nullptr;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requestedSerialNumber)
|
||||
@@ -184,7 +178,7 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
|
||||
if ((deviceDescriptor.idVendor == USB_VENDOR_ID && deviceDescriptor.idProduct == USB_PRODUCT_ID) ||
|
||||
(deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID))
|
||||
{
|
||||
Info(_log, "Found a lightpack device. Retrieving more information...");
|
||||
Info(_log, "Found a Lightpack device. Retrieving more information...");
|
||||
|
||||
// get the hardware address
|
||||
int busNumber = libusb_get_bus_number(device);
|
||||
@@ -226,7 +220,7 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
|
||||
uint8_t buffer[256];
|
||||
error = libusb_control_transfer(
|
||||
_deviceHandle,
|
||||
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
|
||||
static_cast<uint8_t>( LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE),
|
||||
0x01,
|
||||
0x0100,
|
||||
0,
|
||||
@@ -289,19 +283,19 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
|
||||
|
||||
int LedDeviceLightpack::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
return write(ledValues.data(), ledValues.size());
|
||||
return write(ledValues.data(), static_cast<int>(ledValues.size()));
|
||||
}
|
||||
|
||||
int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
|
||||
{
|
||||
int count = qMin(_hwLedCount, static_cast<int>( _ledCount));
|
||||
int count = qMin(_hwLedCount, static_cast<int>( size ));
|
||||
|
||||
for (int i = 0; i < count ; ++i)
|
||||
{
|
||||
const ColorRgb & color = ledValues[i];
|
||||
|
||||
// copy the most significant bits of the rgb values to the first three bytes
|
||||
// offset 1 to accomodate for the command byte
|
||||
// copy the most significant bits of the RGB values to the first three bytes
|
||||
// offset 1 to accommodate for the command byte
|
||||
_ledBuffer[6*i+1] = color.red;
|
||||
_ledBuffer[6*i+2] = color.green;
|
||||
_ledBuffer[6*i+3] = color.blue;
|
||||
@@ -315,14 +309,13 @@ int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
|
||||
return error >= 0 ? 0 : error;
|
||||
}
|
||||
|
||||
int LedDeviceLightpack::switchOff()
|
||||
bool LedDeviceLightpack::powerOff()
|
||||
{
|
||||
int rc = LedDevice::switchOff();
|
||||
if ( _deviceReady )
|
||||
{
|
||||
unsigned char buf[1] = {CMD_OFF_ALL};
|
||||
rc = writeBytes(buf, sizeof(buf)) == sizeof(buf);
|
||||
}
|
||||
bool rc = false;
|
||||
|
||||
unsigned char buf[1] = {CMD_OFF_ALL};
|
||||
rc = writeBytes(buf, sizeof(buf)) == sizeof(buf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -338,7 +331,7 @@ int LedDeviceLightpack::writeBytes(uint8_t *data, int size)
|
||||
// std::cout << std::endl;
|
||||
|
||||
int error = libusb_control_transfer(_deviceHandle,
|
||||
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
|
||||
static_cast<uint8_t>( LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE ),
|
||||
0x09,
|
||||
(2 << 8),
|
||||
0x00,
|
||||
@@ -356,7 +349,13 @@ int LedDeviceLightpack::writeBytes(uint8_t *data, int size)
|
||||
int LedDeviceLightpack::disableSmoothing()
|
||||
{
|
||||
unsigned char buf[2] = {CMD_SET_SMOOTH_SLOWDOWN, 0};
|
||||
return writeBytes(buf, sizeof(buf)) == sizeof(buf);
|
||||
|
||||
int rc = 0;
|
||||
if ( writeBytes(buf, sizeof(buf)) == sizeof(buf) )
|
||||
{
|
||||
rc = 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
libusb_device_handle * LedDeviceLightpack::openDevice(libusb_device *device)
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICELIGHTPACK_H
|
||||
#define LEDEVICELIGHTPACK_H
|
||||
|
||||
// stl includes
|
||||
#include <cstdint>
|
||||
@@ -15,79 +16,93 @@
|
||||
class LedDeviceLightpack : public LedDevice
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs the LedDeviceLightpack
|
||||
/// @brief Constructs a Lightpack LED-device
|
||||
///
|
||||
/// @param serialNumber serial output device
|
||||
///
|
||||
LedDeviceLightpack(const QString & serialNumber = "");
|
||||
explicit LedDeviceLightpack(const QString & serialNumber = "");
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a Lightpack LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceLightpack(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
/// @brief Destructor of the LedDevice
|
||||
///
|
||||
virtual ~LedDeviceLightpack() override;
|
||||
|
||||
///
|
||||
/// Opens and configures the output device
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
int open() override;
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Writes the RGB-Color values to the leds.
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
///
|
||||
/// @brief Closes the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// @brief Power-/turn off the Nanoleaf device.
|
||||
///
|
||||
/// @return True if success
|
||||
///
|
||||
virtual bool powerOff() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues Array of RGB values
|
||||
/// @param[in] size The number of RGB values
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
int write(const ColorRgb * ledValues, int size);
|
||||
|
||||
///
|
||||
/// Switch the leds off
|
||||
/// @brief Get the serial number of the Lightpack
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int switchOff() override;
|
||||
|
||||
/// Get the serial of the Lightpack
|
||||
/// @return Serial Number
|
||||
/// ///
|
||||
const QString & getSerialNumber() const;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
bool isOpen(){ return _isOpen; }
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the RGB-Color values to the leds.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per led
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues) override;
|
||||
|
||||
///
|
||||
/// Test if the device is a (or the) lightpack we are looking for
|
||||
@@ -114,6 +129,9 @@ private:
|
||||
/// libusb context
|
||||
libusb_context * _libusbContext;
|
||||
|
||||
/// libusb device
|
||||
libusb_device * _device;
|
||||
|
||||
/// libusb device handle
|
||||
libusb_device_handle * _deviceHandle;
|
||||
|
||||
@@ -134,4 +152,8 @@ private:
|
||||
|
||||
/// count of real hardware leds
|
||||
int _hwLedCount;
|
||||
|
||||
bool _isOpen;
|
||||
};
|
||||
|
||||
#endif // LEDEVICELIGHTPACK_H
|
||||
|
@@ -22,14 +22,19 @@ LedDeviceMultiLightpack::LedDeviceMultiLightpack(const QJsonObject &deviceConfig
|
||||
, _lightpacks()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDeviceMultiLightpack::~LedDeviceMultiLightpack()
|
||||
{
|
||||
for (LedDeviceLightpack * device : _lightpacks)
|
||||
{
|
||||
delete device;
|
||||
if ( device != nullptr)
|
||||
{
|
||||
delete device;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,14 +43,12 @@ LedDevice* LedDeviceMultiLightpack::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceMultiLightpack(deviceConfig);
|
||||
}
|
||||
|
||||
int LedDeviceMultiLightpack::open()
|
||||
bool LedDeviceMultiLightpack::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
bool isInitOK = false;
|
||||
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
// Initialise sub-class
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
// retrieve a list with Lightpack serials
|
||||
QStringList serialList = getLightpackSerials();
|
||||
@@ -53,47 +56,84 @@ int LedDeviceMultiLightpack::open()
|
||||
// sort the list of Lightpacks based on the serial to get a fixed order
|
||||
std::sort(_lightpacks.begin(), _lightpacks.end(), compareLightpacks);
|
||||
|
||||
// open each lightpack device
|
||||
// open each Lightpack device
|
||||
for (auto serial : serialList)
|
||||
{
|
||||
LedDeviceLightpack * device = new LedDeviceLightpack(serial);
|
||||
int error = device->open();
|
||||
QJsonObject devConfig;
|
||||
devConfig["serial"] = serial;
|
||||
devConfig["latchTime"] = deviceConfig["latchTime"];
|
||||
devConfig["rewriteTime"] = deviceConfig["rewriteTime"];
|
||||
|
||||
if (error == 0)
|
||||
LedDeviceLightpack * device = new LedDeviceLightpack(devConfig);
|
||||
|
||||
device->start();
|
||||
if (device->open() == 0)
|
||||
{
|
||||
_lightpacks.push_back(device);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Error(_log, "Error while creating Lightpack device with serial %s", QSTRING_CSTR(serial));
|
||||
errortext = QString ("Error while creating Lightpack device with serial %1").arg( serial );
|
||||
Error(_log, "Error while creating Lightpack device with serial %s", QSTRING_CSTR(serial));
|
||||
delete device;
|
||||
}
|
||||
}
|
||||
|
||||
if (_lightpacks.size() == 0)
|
||||
if (_lightpacks.empty())
|
||||
{
|
||||
//Warning(_log, "No Lightpack devices were found");
|
||||
errortext = QString ("No Lightpack devices were found");
|
||||
QString errortext = QString ("No Lightpack devices were found");
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info(_log, "%d Lightpack devices were found", _lightpacks.size());
|
||||
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceMultiLightpack::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
int lightsInError = 0;
|
||||
// open each Lightpack device
|
||||
for (LedDeviceLightpack * device : _lightpacks)
|
||||
{
|
||||
if (device->open() < 0)
|
||||
{
|
||||
Error( _log, "Failed to open [%s]", QSTRING_CSTR(device->getSerialNumber()) );
|
||||
++lightsInError;
|
||||
}
|
||||
}
|
||||
|
||||
if ( lightsInError < static_cast<int>(_lightpacks.size()) )
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setInError( "All Lightpacks failed to be opened!" );
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceMultiLightpack::close()
|
||||
{
|
||||
_isDeviceReady = false;
|
||||
|
||||
for (LedDeviceLightpack * device : _lightpacks)
|
||||
{
|
||||
device->close();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
const ColorRgb * data = ledValues.data();
|
||||
@@ -105,7 +145,10 @@ int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
device->write(data, count);
|
||||
if ( device->isOpen() )
|
||||
{
|
||||
device->write(data, count);
|
||||
}
|
||||
|
||||
data += count;
|
||||
size -= count;
|
||||
@@ -119,14 +162,16 @@ int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LedDeviceMultiLightpack::switchOff()
|
||||
bool LedDeviceMultiLightpack::powerOff()
|
||||
{
|
||||
for (LedDeviceLightpack * device : _lightpacks)
|
||||
{
|
||||
device->switchOff();
|
||||
if ( device->isOpen() )
|
||||
{
|
||||
device->powerOff();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList LedDeviceMultiLightpack::getLightpackSerials()
|
||||
@@ -135,7 +180,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
|
||||
Logger * log = Logger::getInstance("LedDevice");
|
||||
Debug(log, "Getting list of Lightpack serials");
|
||||
|
||||
// initialize the usb context
|
||||
// initialize the USB context
|
||||
libusb_context * libusbContext;
|
||||
int error = libusb_init(&libusbContext);
|
||||
if (error != LIBUSB_SUCCESS)
|
||||
@@ -147,7 +192,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
|
||||
//libusb_set_debug(_libusbContext, 3);
|
||||
Info(log, "USB context initialized in multi Lightpack device");
|
||||
|
||||
// retrieve the list of usb devices
|
||||
// retrieve the list of USB devices
|
||||
libusb_device ** deviceList;
|
||||
ssize_t deviceCount = libusb_get_device_list(libusbContext, &deviceList);
|
||||
|
||||
@@ -165,7 +210,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
|
||||
if ((deviceDescriptor.idVendor == USB_VENDOR_ID && deviceDescriptor.idProduct == USB_PRODUCT_ID) ||
|
||||
(deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID))
|
||||
{
|
||||
Info(log, "Found a lightpack device. Retrieving serial...");
|
||||
Info(log, "Found a Lightpack device. Retrieving serial...");
|
||||
|
||||
// get the serial number
|
||||
QString serialNumber;
|
||||
@@ -183,7 +228,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
|
||||
}
|
||||
}
|
||||
|
||||
Error(log, "Lightpack device found with serial %s", QSTRING_CSTR(serialNumber));;
|
||||
Info(log, "Lightpack device found with serial %s", QSTRING_CSTR(serialNumber));
|
||||
serialList.append(serialNumber);
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEMULTILIGHTPACK_H
|
||||
#define LEDEVICEMULTILIGHTPACK_H
|
||||
|
||||
// stl includes
|
||||
#include <vector>
|
||||
@@ -19,43 +20,67 @@
|
||||
class LedDeviceMultiLightpack : public LedDevice
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
///
|
||||
explicit LedDeviceMultiLightpack(const QJsonObject &);
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
/// @brief Constructs a LedDevice of multiple Lightpack LED-devices
|
||||
///
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceMultiLightpack(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// @brief Destructor of the LedDevice
|
||||
///
|
||||
virtual ~LedDeviceMultiLightpack() override;
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
virtual int switchOff() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Opens and configures the output device7
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
int open() override;
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// Switch the leds off
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
///
|
||||
/// @brief Closes the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// @brief Power-/turn off the Nanoleaf device.
|
||||
///
|
||||
/// @return True if success
|
||||
///
|
||||
virtual bool powerOff() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the RGB-Color values to the leds.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per led
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues) override;
|
||||
|
||||
static QStringList getLightpackSerials();
|
||||
static QString getString(libusb_device * device, int stringDescriptorIndex);
|
||||
@@ -63,3 +88,5 @@ private:
|
||||
/// buffer for led data
|
||||
std::vector<LedDeviceLightpack *> _lightpacks;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEMULTILIGHTPACK_H
|
||||
|
@@ -5,9 +5,11 @@ LedDevicePaintpack::LedDevicePaintpack(const QJsonObject &deviceConfig)
|
||||
: ProviderHID()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_useFeature = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDevicePaintpack::construct(const QJsonObject &deviceConfig)
|
||||
@@ -17,12 +19,17 @@ LedDevice* LedDevicePaintpack::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDevicePaintpack::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderHID::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
_ledBuffer.resize(_ledRGBCount + 2, uint8_t(0));
|
||||
_ledBuffer[0] = 3;
|
||||
_ledBuffer[1] = 0;
|
||||
// Initialise sub-class
|
||||
if ( ProviderHID::init(deviceConfig) )
|
||||
{
|
||||
_ledBuffer.resize(_ledRGBCount + 2, uint8_t(0));
|
||||
_ledBuffer[0] = 3;
|
||||
_ledBuffer[1] = 0;
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
|
@@ -1,38 +1,48 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEPAINTTPACK_H
|
||||
#define LEDEVICEPAINTTPACK_H
|
||||
|
||||
// Hyperion includes
|
||||
#include "ProviderHID.h"
|
||||
|
||||
///
|
||||
/// LedDevice implementation for a paintpack device ()
|
||||
/// LedDevice implementation for a paintpack LED-device
|
||||
///
|
||||
class LedDevicePaintpack : public ProviderHID
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a Paintpack LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDevicePaintpack(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the RGB-Color values to the leds.
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per led
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues) override;
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEPAINTTPACK_H
|
||||
|
@@ -5,7 +5,9 @@ LedDeviceRawHID::LedDeviceRawHID(const QJsonObject &deviceConfig)
|
||||
: ProviderHID()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
|
||||
_useFeature = true;
|
||||
}
|
||||
@@ -17,10 +19,14 @@ LedDevice* LedDeviceRawHID::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceRawHID::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderHID::init(deviceConfig);
|
||||
|
||||
_ledBuffer.resize(_ledRGBCount);
|
||||
bool isInitOK = false;
|
||||
|
||||
// Initialise sub-class
|
||||
if ( ProviderHID::init(deviceConfig) )
|
||||
{
|
||||
_ledBuffer.resize(_ledRGBCount);
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICERAWHID_H
|
||||
#define LEDEVICERAWHID_H
|
||||
|
||||
// Qt includes
|
||||
#include <QTimer>
|
||||
@@ -11,31 +12,40 @@
|
||||
///
|
||||
class LedDeviceRawHID : public ProviderHID
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a Raw-HID LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceRawHID(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
};
|
||||
|
||||
#endif // LEDEVICERAWHID_H
|
||||
|
@@ -21,54 +21,59 @@ ProviderHID::ProviderHID()
|
||||
|
||||
ProviderHID::~ProviderHID()
|
||||
{
|
||||
if (_deviceHandle != nullptr)
|
||||
{
|
||||
hid_close(_deviceHandle);
|
||||
}
|
||||
hid_exit();
|
||||
}
|
||||
|
||||
bool ProviderHID::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
_delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(0);
|
||||
auto VendorIdString = deviceConfig["VID"].toString("0x2341").toStdString();
|
||||
auto ProductIdString = deviceConfig["PID"].toString("0x8036").toStdString();
|
||||
// Initialise sub-class
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
_delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(0);
|
||||
auto VendorIdString = deviceConfig["VID"].toString("0x2341").toStdString();
|
||||
auto ProductIdString = deviceConfig["PID"].toString("0x8036").toStdString();
|
||||
|
||||
// Convert HEX values to integer
|
||||
_VendorId = std::stoul(VendorIdString, nullptr, 16);
|
||||
_ProductId = std::stoul(ProductIdString, nullptr, 16);
|
||||
// Convert HEX values to integer
|
||||
_VendorId = std::stoul(VendorIdString, nullptr, 16);
|
||||
_ProductId = std::stoul(ProductIdString, nullptr, 16);
|
||||
|
||||
// Initialize the USB context
|
||||
if ( hid_init() != 0)
|
||||
{
|
||||
this->setInError("Error initializing the HIDAPI context");
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug(_log,"HIDAPI initialized");
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int ProviderHID::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
// Open the device
|
||||
Info(_log, "Opening device: VID %04hx PID %04hx\n", _VendorId, _ProductId);
|
||||
_deviceHandle = hid_open(_VendorId, _ProductId, nullptr);
|
||||
|
||||
if (_deviceHandle == nullptr)
|
||||
{
|
||||
// Initialize the usb context
|
||||
int error = hid_init();
|
||||
if (error != 0)
|
||||
{
|
||||
//Error(_log, "Error while initializing the hidapi context");
|
||||
errortext = "Error while initializing the hidapi context";
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug(_log,"Hidapi initialized");
|
||||
// Failed to open the device
|
||||
this->setInError( "Failed to open HID device. Maybe your PID/VID setting is wrong? Make sure to add a udev rule/use sudo." );
|
||||
|
||||
// Open the device
|
||||
Info(_log, "Opening device: VID %04hx PID %04hx\n", _VendorId, _ProductId);
|
||||
_deviceHandle = hid_open(_VendorId, _ProductId, nullptr);
|
||||
|
||||
if (_deviceHandle == nullptr)
|
||||
{
|
||||
// Failed to open the device
|
||||
Error(_log,"Failed to open HID device. Maybe your PID/VID setting is wrong? Make sure to add a udev rule/use sudo.");
|
||||
errortext = "Failed to open HID device";
|
||||
|
||||
// http://www.signal11.us/oss/hidapi/
|
||||
/*
|
||||
// http://www.signal11.us/oss/hidapi/
|
||||
/*
|
||||
std::cout << "Showing a list of all available HID devices:" << std::endl;
|
||||
auto devs = hid_enumerate(0x00, 0x00);
|
||||
auto cur_dev = devs;
|
||||
@@ -83,45 +88,38 @@ int ProviderHID::open()
|
||||
}
|
||||
hid_free_enumeration(devs);
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
Info(_log,"Opened HID device successful");
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
// Wait after device got opened if enabled
|
||||
if (_delayAfterConnect_ms > 0)
|
||||
{
|
||||
_blockedForDelay = true;
|
||||
QTimer::singleShot(_delayAfterConnect_ms, this, SLOT(unblockAfterDelay()));
|
||||
Debug(_log, "Device blocked for %d ms", _delayAfterConnect_ms);
|
||||
}
|
||||
}
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Info(_log,"Opened HID device successful");
|
||||
// Everything is OK -> enable device
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
// Wait after device got opened if enabled
|
||||
if (_delayAfterConnect_ms > 0)
|
||||
{
|
||||
_blockedForDelay = true;
|
||||
QTimer::singleShot(_delayAfterConnect_ms, this, &ProviderHID::unblockAfterDelay );
|
||||
Debug(_log, "Device blocked for %d ms", _delayAfterConnect_ms);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ProviderHID::close()
|
||||
int ProviderHID::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
int retval = 0;
|
||||
_isDeviceReady = false;
|
||||
|
||||
// LedDevice specific closing activites
|
||||
// LedDevice specific closing activities
|
||||
if (_deviceHandle != nullptr)
|
||||
{
|
||||
hid_close(_deviceHandle);
|
||||
_deviceHandle = nullptr;
|
||||
}
|
||||
|
||||
hid_exit();
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ProviderHID::writeBytes(const unsigned size, const uint8_t * data)
|
||||
@@ -138,7 +136,7 @@ int ProviderHID::writeBytes(const unsigned size, const uint8_t * data)
|
||||
// Try again in 3 seconds
|
||||
int delay_ms = 3000;
|
||||
_blockedForDelay = true;
|
||||
QTimer::singleShot(delay_ms, this, SLOT(unblockAfterDelay()));
|
||||
QTimer::singleShot(delay_ms, this, &ProviderHID::unblockAfterDelay );
|
||||
Debug(_log,"Device blocked for %d ms", delay_ms);
|
||||
}
|
||||
// Return here, to not write led data if the device should be blocked after connect
|
||||
@@ -188,3 +186,38 @@ void ProviderHID::unblockAfterDelay()
|
||||
Debug(_log,"Device unblocked");
|
||||
_blockedForDelay = false;
|
||||
}
|
||||
|
||||
QJsonObject ProviderHID::discover()
|
||||
{
|
||||
QJsonObject devicesDiscovered;
|
||||
devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
|
||||
|
||||
QJsonArray deviceList;
|
||||
|
||||
// Discover HID Devices
|
||||
auto devs = hid_enumerate(0x00, 0x00);
|
||||
|
||||
if ( devs != nullptr )
|
||||
{
|
||||
auto cur_dev = devs;
|
||||
while (cur_dev)
|
||||
{
|
||||
QJsonObject deviceInfo;
|
||||
deviceInfo.insert("manufacturer",QString::fromWCharArray(cur_dev->manufacturer_string));
|
||||
deviceInfo.insert("path",cur_dev->path);
|
||||
deviceInfo.insert("productIdentifier", QString("0x%1").arg(static_cast<ushort>(cur_dev->product_id),0,16));
|
||||
deviceInfo.insert("release_number",QString("0x%1").arg(static_cast<ushort>(cur_dev->release_number),0,16));
|
||||
deviceInfo.insert("serialNumber",QString::fromWCharArray(cur_dev->serial_number));
|
||||
deviceInfo.insert("usage_page", QString("0x%1").arg(static_cast<ushort>(cur_dev->usage_page),0,16));
|
||||
deviceInfo.insert("vendorIdentifier", QString("0x%1").arg(static_cast<ushort>(cur_dev->vendor_id),0,16));
|
||||
deviceInfo.insert("interface_number",cur_dev->interface_number);
|
||||
deviceList.append(deviceInfo);
|
||||
|
||||
cur_dev = cur_dev->next;
|
||||
}
|
||||
hid_free_enumeration(devs);
|
||||
}
|
||||
|
||||
devicesDiscovered.insert("devices", deviceList);
|
||||
return devicesDiscovered;
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#ifndef PROVIDERHID_H
|
||||
#define PROVIDERHID_H
|
||||
|
||||
// libusb include
|
||||
#include <hidapi/hidapi.h>
|
||||
@@ -16,46 +15,57 @@ class ProviderHID : public LedDevice
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a HID (USB) LED-device
|
||||
///
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
ProviderHID();
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
/// @brief Destructor of the LedDevice
|
||||
///
|
||||
virtual ~ProviderHID() override;
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Discover HIB (USB) devices available (for configuration).
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
/// @return A JSON structure holding a list of devices found
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
virtual QJsonObject discover() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Opens and configures the output device
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
int open() override;
|
||||
|
||||
/**
|
||||
* Writes the given bytes to the HID-device and
|
||||
*
|
||||
* @param[in] size The length of the data
|
||||
* @param[in] data The data
|
||||
*
|
||||
* @return Zero on succes else negative
|
||||
*/
|
||||
///
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
///
|
||||
/// @brief Closes the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// @brief Write the given bytes to the HID-device
|
||||
///
|
||||
/// @param[in[ size The length of the data
|
||||
/// @param[in] data The data
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
int writeBytes(const unsigned size, const uint8_t *data);
|
||||
|
||||
// HID VID and PID
|
||||
@@ -74,4 +84,10 @@ protected:
|
||||
private slots:
|
||||
/// Unblock the device after a connection delay
|
||||
void unblockAfterDelay();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif // PROVIDERHID_H
|
||||
|
@@ -1,5 +1,6 @@
|
||||
// Local-Hyperion includes
|
||||
#include "LedDeviceAtmoOrb.h"
|
||||
#include <utils/QStringUtils.h>
|
||||
|
||||
// qt includes
|
||||
#include <QUdpSocket>
|
||||
@@ -19,7 +20,9 @@ LedDeviceAtmoOrb::LedDeviceAtmoOrb(const QJsonObject &deviceConfig)
|
||||
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceAtmoOrb::construct(const QJsonObject &deviceConfig)
|
||||
@@ -31,7 +34,7 @@ LedDeviceAtmoOrb::~LedDeviceAtmoOrb()
|
||||
{
|
||||
if ( _udpSocket != nullptr )
|
||||
{
|
||||
_udpSocket->deleteLater();
|
||||
delete _udpSocket;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,30 +52,31 @@ bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
|
||||
_multiCastGroupPort = static_cast<quint16>(deviceConfig["port"].toInt(MULTICAST_GROUPL_DEFAULT_PORT));
|
||||
_numLeds = deviceConfig["numLeds"].toInt(LEDS_DEFAULT_NUMBER);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||
const QStringList orbIds = deviceConfig["orbIds"].toString().simplified().remove(" ").split(",", Qt::SkipEmptyParts);
|
||||
#else
|
||||
const QStringList orbIds = deviceConfig["orbIds"].toString().simplified().remove(" ").split(",", QString::SkipEmptyParts);
|
||||
#endif
|
||||
|
||||
QStringList orbIds = QStringUtils::split(deviceConfig["orbIds"].toString().simplified().remove(" "),",", QStringUtils::SplitBehavior::SkipEmptyParts);
|
||||
_orbIds.clear();
|
||||
|
||||
for(auto & id_str : orbIds)
|
||||
for (auto & id_str : orbIds)
|
||||
{
|
||||
bool ok;
|
||||
int id = id_str.toInt(&ok);
|
||||
if (ok)
|
||||
{
|
||||
if ( id < 1 || id > 255 )
|
||||
{
|
||||
Warning(_log, "Skip orb id '%d'. IDs must be in range 1-255", id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_orbIds.append(id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(_log, "orb id '%s' is not a number", QSTRING_CSTR(id_str));
|
||||
}
|
||||
}
|
||||
|
||||
if ( _orbIds.size() == 0 )
|
||||
if ( _orbIds.empty() )
|
||||
{
|
||||
this->setInError("No valid OrbIds found!");
|
||||
isInitOK = false;
|
||||
@@ -89,43 +93,40 @@ bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
|
||||
int LedDeviceAtmoOrb::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
// Try to bind the UDP-Socket
|
||||
if ( _udpSocket != nullptr )
|
||||
{
|
||||
// Try to bind the UDP-Socket
|
||||
if ( _udpSocket != nullptr )
|
||||
_groupAddress = QHostAddress(_multicastGroup);
|
||||
if ( !_udpSocket->bind(QHostAddress::AnyIPv4, _multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint) )
|
||||
{
|
||||
_groupAddress = QHostAddress(_multicastGroup);
|
||||
if ( !_udpSocket->bind(QHostAddress::AnyIPv4, _multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint) )
|
||||
QString errortext = QString ("(%1) %2, MulticastGroup: (%3)").arg(_udpSocket->error()).arg(_udpSocket->errorString(), _multicastGroup);
|
||||
this->setInError( errortext );
|
||||
}
|
||||
else
|
||||
{
|
||||
_joinedMulticastgroup = _udpSocket->joinMulticastGroup(_groupAddress);
|
||||
if ( !_joinedMulticastgroup )
|
||||
{
|
||||
QString errortext = QString ("(%1) %2, MulticastGroup: (%3)").arg(_udpSocket->error()).arg(_udpSocket->errorString()).arg(_multicastGroup);
|
||||
QString errortext = QString ("(%1) %2, MulticastGroup: (%3)").arg(_udpSocket->error()).arg(_udpSocket->errorString(), _multicastGroup);
|
||||
this->setInError( errortext );
|
||||
}
|
||||
else
|
||||
{
|
||||
_joinedMulticastgroup = _udpSocket->joinMulticastGroup(_groupAddress);
|
||||
if ( !_joinedMulticastgroup )
|
||||
{
|
||||
QString errortext = QString ("(%1) %2, MulticastGroup: (%3)").arg(_udpSocket->error()).arg(_udpSocket->errorString()).arg(_multicastGroup);
|
||||
this->setInError( errortext );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDeviceAtmoOrb::close()
|
||||
int LedDeviceAtmoOrb::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
int retval = 0;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if ( _udpSocket != nullptr )
|
||||
{
|
||||
@@ -137,6 +138,7 @@ void LedDeviceAtmoOrb::close()
|
||||
// Everything is OK -> device is closed
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues)
|
||||
@@ -211,7 +213,9 @@ int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues)
|
||||
void LedDeviceAtmoOrb::setColor(int orbId, const ColorRgb &color, int commandType)
|
||||
{
|
||||
QByteArray bytes;
|
||||
bytes.resize(5 + _numLeds * 3);
|
||||
|
||||
// 5 bytes command-header + 3 bytes color information
|
||||
bytes.resize(5 + 3);
|
||||
bytes.fill('\0');
|
||||
|
||||
// Command identifier: C0FFEE
|
||||
@@ -230,7 +234,6 @@ void LedDeviceAtmoOrb::setColor(int orbId, const ColorRgb &color, int commandTyp
|
||||
bytes[6] = static_cast<char>(color.green);
|
||||
bytes[7] = static_cast<char>(color.blue);
|
||||
|
||||
// TODO: Why is the datagram _numLeds * 3 in size, if only bypes 5,6,7 are updated with the color?
|
||||
//std::cout << "Orb [" << orbId << "] Cmd [" << bytes.toHex(':').toStdString() <<"]"<< std::endl;
|
||||
|
||||
sendCommand(bytes);
|
||||
|
@@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEATMOORB_H
|
||||
#define LEDEVICEATMOORB_H
|
||||
|
||||
// Qt includes
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QUdpSocket>
|
||||
#include <QHostAddress>
|
||||
#include <QVector>
|
||||
|
||||
@@ -25,38 +24,39 @@ class LedDeviceAtmoOrb : public LedDevice
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs an AtmoOrb LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceAtmoOrb(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Destructor of this device
|
||||
/// @brief Destructor of the LedDevice
|
||||
///
|
||||
virtual ~LedDeviceAtmoOrb() override;
|
||||
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Initialise device's network details
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @return True if success
|
||||
bool initNetwork();
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
@@ -65,18 +65,18 @@ protected:
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual void close() override;
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Sends the given led-color values to the Orbs
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector <ColorRgb> &ledValues) override;
|
||||
|
||||
///
|
||||
/// Set Orbcolor
|
||||
///
|
||||
@@ -93,9 +93,6 @@ private:
|
||||
///
|
||||
void sendCommand(const QByteArray &bytes);
|
||||
|
||||
/// QNetworkAccessManager object for sending requests.
|
||||
QNetworkAccessManager *_networkmanager;
|
||||
|
||||
/// QUdpSocket object used to send data over
|
||||
QUdpSocket * _udpSocket;
|
||||
|
||||
@@ -132,3 +129,5 @@ private:
|
||||
QMap<int, int> lastColorBlueMap;
|
||||
|
||||
};
|
||||
|
||||
#endif // LEDEVICEATMOORB_H
|
||||
|
@@ -6,22 +6,37 @@
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
|
||||
static const signed MAX_NUM_LEDS = 10000; // OPC can handle 21845 leds - in theory, fadecandy device should handle 10000 leds
|
||||
static const unsigned OPC_SET_PIXELS = 0; // OPC command codes
|
||||
static const unsigned OPC_SYS_EX = 255; // OPC command codes
|
||||
static const unsigned OPC_HEADER_SIZE = 4; // OPC header size
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
const signed MAX_NUM_LEDS = 10000; // OPC can handle 21845 LEDs - in theory, fadecandy device should handle 10000 LEDs
|
||||
const unsigned OPC_SET_PIXELS = 0; // OPC command codes
|
||||
const unsigned OPC_SYS_EX = 255; // OPC command codes
|
||||
const unsigned OPC_HEADER_SIZE = 4; // OPC header size
|
||||
|
||||
} //End of constants
|
||||
|
||||
// TCP elements
|
||||
const quint16 STREAM_DEFAULT_PORT = 7890;
|
||||
|
||||
LedDeviceFadeCandy::LedDeviceFadeCandy(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
, _client(nullptr)
|
||||
, _client(nullptr)
|
||||
,_host()
|
||||
,_port(STREAM_DEFAULT_PORT)
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDeviceFadeCandy::~LedDeviceFadeCandy()
|
||||
{
|
||||
_client->deleteLater();
|
||||
if ( _client != nullptr )
|
||||
{
|
||||
delete _client;
|
||||
}
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceFadeCandy::construct(const QJsonObject &deviceConfig)
|
||||
@@ -31,46 +46,59 @@ LedDevice* LedDeviceFadeCandy::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceFadeCandy::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
if ( isInitOK )
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
if (_ledCount > MAX_NUM_LEDS)
|
||||
if (getLedCount() > MAX_NUM_LEDS)
|
||||
{
|
||||
//Error(_log, "fadecandy/opc: Invalid attempt to write led values. Not more than %d leds are allowed.", MAX_NUM_LEDS);
|
||||
QString errortext = QString ("More LED configured than allowed (%1)").arg(MAX_NUM_LEDS);
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_host = deviceConfig["output"].toString("127.0.0.1");
|
||||
_port = deviceConfig["port"].toInt(7890);
|
||||
_channel = deviceConfig["channel"].toInt(0);
|
||||
_gamma = deviceConfig["gamma"].toDouble(1.0);
|
||||
_noDither = ! deviceConfig["dither"].toBool(false);
|
||||
_noInterp = ! deviceConfig["interpolation"].toBool(false);
|
||||
_manualLED = deviceConfig["manualLed"].toBool(false);
|
||||
_ledOnOff = deviceConfig["ledOn"].toBool(false);
|
||||
_setFcConfig = deviceConfig["setFcConfig"].toBool(false);
|
||||
_host = deviceConfig["output"].toString("127.0.0.1");
|
||||
_port = deviceConfig["port"].toInt(STREAM_DEFAULT_PORT);
|
||||
|
||||
_whitePoint_r = 1.0;
|
||||
_whitePoint_g = 1.0;
|
||||
_whitePoint_b = 1.0;
|
||||
|
||||
const QJsonArray whitePointConfig = deviceConfig["whitePoint"].toArray();
|
||||
if ( !whitePointConfig.isEmpty() && whitePointConfig.size() == 3 )
|
||||
//If host not configured the init fails
|
||||
if ( _host.isEmpty() )
|
||||
{
|
||||
_whitePoint_r = whitePointConfig[0].toDouble() / 255.0;
|
||||
_whitePoint_g = whitePointConfig[1].toDouble() / 255.0;
|
||||
_whitePoint_b = whitePointConfig[2].toDouble() / 255.0;
|
||||
this->setInError("No target hostname nor IP defined");
|
||||
}
|
||||
else
|
||||
{
|
||||
_channel = deviceConfig["channel"].toInt(0);
|
||||
_gamma = deviceConfig["gamma"].toDouble(1.0);
|
||||
_noDither = ! deviceConfig["dither"].toBool(false);
|
||||
_noInterp = ! deviceConfig["interpolation"].toBool(false);
|
||||
_manualLED = deviceConfig["manualLed"].toBool(false);
|
||||
_ledOnOff = deviceConfig["ledOn"].toBool(false);
|
||||
_setFcConfig = deviceConfig["setFcConfig"].toBool(false);
|
||||
|
||||
_opc_data.resize( _ledRGBCount + OPC_HEADER_SIZE );
|
||||
_opc_data[0] = _channel;
|
||||
_opc_data[1] = OPC_SET_PIXELS;
|
||||
_opc_data[2] = _ledRGBCount >> 8;
|
||||
_opc_data[3] = _ledRGBCount & 0xff;
|
||||
_whitePoint_r = 1.0;
|
||||
_whitePoint_g = 1.0;
|
||||
_whitePoint_b = 1.0;
|
||||
|
||||
const QJsonArray whitePointConfig = deviceConfig["whitePoint"].toArray();
|
||||
if ( !whitePointConfig.isEmpty() && whitePointConfig.size() == 3 )
|
||||
{
|
||||
_whitePoint_r = whitePointConfig[0].toDouble() / 255.0;
|
||||
_whitePoint_g = whitePointConfig[1].toDouble() / 255.0;
|
||||
_whitePoint_b = whitePointConfig[2].toDouble() / 255.0;
|
||||
}
|
||||
|
||||
_opc_data.resize( _ledRGBCount + OPC_HEADER_SIZE );
|
||||
_opc_data[0] = _channel;
|
||||
_opc_data[1] = OPC_SET_PIXELS;
|
||||
_opc_data[2] = _ledRGBCount >> 8;
|
||||
_opc_data[3] = _ledRGBCount & 0xff;
|
||||
|
||||
if ( initNetwork() )
|
||||
{
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
@@ -78,62 +106,77 @@ bool LedDeviceFadeCandy::init(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceFadeCandy::initNetwork()
|
||||
{
|
||||
bool isInitOK = true;
|
||||
bool isInitOK = false;
|
||||
|
||||
// TODO: Add Network-Error handling
|
||||
_client = new QTcpSocket(this);
|
||||
if ( _client == nullptr )
|
||||
{
|
||||
_client = new QTcpSocket(this);
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceFadeCandy::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_deviceReady = false;
|
||||
QString errortext;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
// Try to open the LedDevice
|
||||
if ( !tryConnect() )
|
||||
{
|
||||
if ( !initNetwork() )
|
||||
{
|
||||
this->setInError( "Network error!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
errortext = QString ("Failed to open device.");
|
||||
this->setInError( errortext );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDeviceFadeCandy::close()
|
||||
int LedDeviceFadeCandy::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
int retval = 0;
|
||||
_isDeviceReady = false;
|
||||
|
||||
// LedDevice specific closing activites
|
||||
_client->close();
|
||||
// LedDevice specific closing activities
|
||||
if ( _client != nullptr )
|
||||
{
|
||||
_client->close();
|
||||
// Everything is OK -> device is closed
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
bool LedDeviceFadeCandy::isConnected()
|
||||
{
|
||||
return _client->state() == QAbstractSocket::ConnectedState;
|
||||
bool connected = false;
|
||||
if ( _client != nullptr )
|
||||
{
|
||||
connected = _client->state() == QAbstractSocket::ConnectedState;
|
||||
}
|
||||
return connected;
|
||||
}
|
||||
|
||||
bool LedDeviceFadeCandy::tryConnect()
|
||||
{
|
||||
if ( _client->state() == QAbstractSocket::UnconnectedState ) {
|
||||
_client->connectToHost( _host, _port);
|
||||
if ( _client->waitForConnected(1000) )
|
||||
{
|
||||
Info(_log,"fadecandy/opc: connected to %s:%i on channel %i", QSTRING_CSTR(_host), _port, _channel);
|
||||
if (_setFcConfig)
|
||||
if ( _client != nullptr )
|
||||
{
|
||||
if ( _client->state() == QAbstractSocket::UnconnectedState ) {
|
||||
_client->connectToHost( _host, _port);
|
||||
if ( _client->waitForConnected(1000) )
|
||||
{
|
||||
sendFadeCandyConfiguration();
|
||||
Info(_log,"fadecandy/opc: connected to %s:%i on channel %i", QSTRING_CSTR(_host), _port, _channel);
|
||||
if (_setFcConfig)
|
||||
{
|
||||
sendFadeCandyConfiguration();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isConnected();
|
||||
}
|
||||
|
||||
@@ -148,15 +191,16 @@ int LedDeviceFadeCandy::write( const std::vector<ColorRgb> & ledValues )
|
||||
idx += 3;
|
||||
}
|
||||
|
||||
return ( transferData()<0 ? -1 : 0 );
|
||||
int retval = transferData()<0 ? -1 : 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceFadeCandy::transferData()
|
||||
{
|
||||
if (LedDevice::enabled())
|
||||
if ( isConnected() || tryConnect() )
|
||||
return _client->write( _opc_data, _opc_data.size() );
|
||||
|
||||
if ( isConnected() || tryConnect() )
|
||||
{
|
||||
return _client->write( _opc_data, _opc_data.size() );
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@@ -1,10 +1,11 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEFADECANDY_H
|
||||
#define LEDEVICEFADECANDY_H
|
||||
|
||||
// STL/Qt includes
|
||||
#include <QTcpSocket>
|
||||
#include <QString>
|
||||
|
||||
// Leddevice includes
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
|
||||
///
|
||||
@@ -17,9 +18,9 @@ class LedDeviceFadeCandy : public LedDevice
|
||||
|
||||
public:
|
||||
///
|
||||
/// Constructs the LedDevice for fadecandy/opc server
|
||||
/// @brief Constructs a LED-device for fadecandy/opc server
|
||||
///
|
||||
/// following code shows all config options
|
||||
/// Following code shows all configuration options
|
||||
/// @code
|
||||
/// "device" :
|
||||
/// {
|
||||
@@ -37,84 +38,95 @@ public:
|
||||
/// },
|
||||
///@endcode
|
||||
///
|
||||
/// @param deviceConfig json config for fadecandy
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceFadeCandy(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the tcp client
|
||||
/// @brief Destructor of the LedDevice
|
||||
///
|
||||
virtual ~LedDeviceFadeCandy();
|
||||
~LedDeviceFadeCandy() override;
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Initialise device's network details
|
||||
/// @brief Initialise the Nanoleaf device's configuration and network address details
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
///
|
||||
/// @brief Closes the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// @brief Initialise device's network details
|
||||
///
|
||||
/// @return True if success
|
||||
bool initNetwork();
|
||||
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
/// @brief try to establish connection to opc server, if not connected yet
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues) override;
|
||||
|
||||
/// try to establish connection to opc server, if not connected yet
|
||||
///
|
||||
/// @return true if connection is established
|
||||
/// @return True, if connection is established
|
||||
///
|
||||
bool tryConnect();
|
||||
|
||||
/// return the conenction state
|
||||
///
|
||||
/// @return True if connection established
|
||||
/// @brief Return the connection state
|
||||
///
|
||||
/// @return True, if connection established
|
||||
///
|
||||
bool isConnected();
|
||||
|
||||
/// transfer current opc_data buffer to opc server
|
||||
///
|
||||
/// @return amount of transfered bytes. -1 error while transfering, -2 error while connecting
|
||||
/// @brief Transfer current opc_data buffer to opc server
|
||||
///
|
||||
/// @return amount of transferred bytes. -1 error while transferring, -2 error while connecting
|
||||
///
|
||||
int transferData();
|
||||
|
||||
/// send system exclusive commands
|
||||
///
|
||||
/// @param systemId fadecandy device identifier (for standard fadecandy always: 1)
|
||||
/// @param commandId id of command
|
||||
/// @param msg the sysEx message
|
||||
/// @return amount bytes written, -1 if fail
|
||||
/// @brief Send system exclusive commands
|
||||
///
|
||||
/// @param[in] systemId fadecandy device identifier (for standard fadecandy always: 1)
|
||||
/// @param[in] commandId id of command
|
||||
/// @param[in] msg the sysEx message
|
||||
/// @return amount bytes written, -1 if failed
|
||||
int sendSysEx(uint8_t systemId, uint8_t commandId, QByteArray msg);
|
||||
|
||||
/// sends the configuration to fcserver
|
||||
///
|
||||
/// @brief Sends the configuration to fadecandy cserver
|
||||
///
|
||||
void sendFadeCandyConfiguration();
|
||||
|
||||
QTcpSocket* _client;
|
||||
@@ -135,3 +147,5 @@ private:
|
||||
bool _ledOnOff;
|
||||
|
||||
};
|
||||
|
||||
#endif // LEDEVICEFADECANDY_H
|
||||
|
@@ -1,8 +1,8 @@
|
||||
// Local-Hyperion includes
|
||||
#include "LedDeviceNanoleaf.h"
|
||||
|
||||
// ssdp discover
|
||||
#include <ssdp/SSDPDiscover.h>
|
||||
#include <utils/QStringUtils.h>
|
||||
|
||||
// Qt includes
|
||||
#include <QEventLoop>
|
||||
@@ -12,61 +12,66 @@
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
//
|
||||
static const bool verbose = false;
|
||||
static const bool verbose3 = false;
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
// Controller configuration settings
|
||||
static const char CONFIG_ADDRESS[] = "host";
|
||||
//static const char CONFIG_PORT[] = "port";
|
||||
static const char CONFIG_AUTH_TOKEN[] ="token";
|
||||
const bool verbose = false;
|
||||
const bool verbose3 = false;
|
||||
|
||||
static const char CONFIG_PANEL_ORDER_TOP_DOWN[] ="panelOrderTopDown";
|
||||
static const char CONFIG_PANEL_ORDER_LEFT_RIGHT[] ="panelOrderLeftRight";
|
||||
static const char CONFIG_PANEL_START_POS[] ="panelStartPos";
|
||||
// Configuration settings
|
||||
const char CONFIG_ADDRESS[] = "host";
|
||||
//const char CONFIG_PORT[] = "port";
|
||||
const char CONFIG_AUTH_TOKEN[] ="token";
|
||||
|
||||
const char CONFIG_PANEL_ORDER_TOP_DOWN[] ="panelOrderTopDown";
|
||||
const char CONFIG_PANEL_ORDER_LEFT_RIGHT[] ="panelOrderLeftRight";
|
||||
const char CONFIG_PANEL_START_POS[] ="panelStartPos";
|
||||
|
||||
// Panel configuration settings
|
||||
static const char PANEL_LAYOUT[] = "layout";
|
||||
static const char PANEL_NUM[] = "numPanels";
|
||||
static const char PANEL_ID[] = "panelId";
|
||||
static const char PANEL_POSITIONDATA[] = "positionData";
|
||||
static const char PANEL_SHAPE_TYPE[] = "shapeType";
|
||||
//static const char PANEL_ORIENTATION[] = "0";
|
||||
static const char PANEL_POS_X[] = "x";
|
||||
static const char PANEL_POS_Y[] = "y";
|
||||
const char PANEL_LAYOUT[] = "layout";
|
||||
const char PANEL_NUM[] = "numPanels";
|
||||
const char PANEL_ID[] = "panelId";
|
||||
const char PANEL_POSITIONDATA[] = "positionData";
|
||||
const char PANEL_SHAPE_TYPE[] = "shapeType";
|
||||
//const char PANEL_ORIENTATION[] = "0";
|
||||
const char PANEL_POS_X[] = "x";
|
||||
const char PANEL_POS_Y[] = "y";
|
||||
|
||||
// List of State Information
|
||||
static const char STATE_ON[] = "on";
|
||||
static const char STATE_ONOFF_VALUE[] = "value";
|
||||
static const char STATE_VALUE_TRUE[] = "true";
|
||||
static const char STATE_VALUE_FALSE[] = "false";
|
||||
const char STATE_ON[] = "on";
|
||||
const char STATE_ONOFF_VALUE[] = "value";
|
||||
const char STATE_VALUE_TRUE[] = "true";
|
||||
const char STATE_VALUE_FALSE[] = "false";
|
||||
|
||||
// Device Data elements
|
||||
static const char DEV_DATA_NAME[] = "name";
|
||||
static const char DEV_DATA_MODEL[] = "model";
|
||||
static const char DEV_DATA_MANUFACTURER[] = "manufacturer";
|
||||
static const char DEV_DATA_FIRMWAREVERSION[] = "firmwareVersion";
|
||||
const char DEV_DATA_NAME[] = "name";
|
||||
const char DEV_DATA_MODEL[] = "model";
|
||||
const char DEV_DATA_MANUFACTURER[] = "manufacturer";
|
||||
const char DEV_DATA_FIRMWAREVERSION[] = "firmwareVersion";
|
||||
|
||||
// Nanoleaf Stream Control elements
|
||||
//static const char STREAM_CONTROL_IP[] = "streamControlIpAddr";
|
||||
static const char STREAM_CONTROL_PORT[] = "streamControlPort";
|
||||
//static const char STREAM_CONTROL_PROTOCOL[] = "streamControlProtocol";
|
||||
//const char STREAM_CONTROL_IP[] = "streamControlIpAddr";
|
||||
const char STREAM_CONTROL_PORT[] = "streamControlPort";
|
||||
//const char STREAM_CONTROL_PROTOCOL[] = "streamControlProtocol";
|
||||
const quint16 STREAM_CONTROL_DEFAULT_PORT = 60222; //Fixed port for Canvas;
|
||||
|
||||
// Nanoleaf OpenAPI URLs
|
||||
static const char API_DEFAULT_PORT[] = "16021";
|
||||
static const char API_URL_FORMAT[] = "http://%1:%2/api/v1/%3/%4";
|
||||
static const char API_ROOT[] = "";
|
||||
//static const char API_EXT_MODE_STRING_V1[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\"}}";
|
||||
static const char API_EXT_MODE_STRING_V2[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\", \"extControlVersion\" : \"v2\"}}";
|
||||
static const char API_STATE[] ="state";
|
||||
static const char API_PANELLAYOUT[] = "panelLayout";
|
||||
static const char API_EFFECT[] = "effects";
|
||||
const int API_DEFAULT_PORT = 16021;
|
||||
const char API_BASE_PATH[] = "/api/v1/%1/";
|
||||
const char API_ROOT[] = "";
|
||||
//const char API_EXT_MODE_STRING_V1[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\"}}";
|
||||
const char API_EXT_MODE_STRING_V2[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\", \"extControlVersion\" : \"v2\"}}";
|
||||
const char API_STATE[] ="state";
|
||||
const char API_PANELLAYOUT[] = "panelLayout";
|
||||
const char API_EFFECT[] = "effects";
|
||||
|
||||
// Nanoleaf ssdp services
|
||||
static const char SSDP_CANVAS[] = "nanoleaf:nl29";
|
||||
static const char SSDP_LIGHTPANELS[] = "nanoleaf_aurora:light";
|
||||
const int SSDP_TIMEOUT = 5000; // timout in ms
|
||||
const char SSDP_ID[] = "ssdp:all";
|
||||
const char SSDP_FILTER_HEADER[] = "ST";
|
||||
const char SSDP_CANVAS[] = "nanoleaf:nl29";
|
||||
const char SSDP_LIGHTPANELS[] = "nanoleaf_aurora:light";
|
||||
|
||||
} //End of constants
|
||||
|
||||
// Nanoleaf Panel Shapetypes
|
||||
enum SHAPETYPES {
|
||||
@@ -84,6 +89,23 @@ enum EXTCONTROLVERSIONS {
|
||||
EXTCTRLVER_V2
|
||||
};
|
||||
|
||||
LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
,_restApi(nullptr)
|
||||
,_apiPort(API_DEFAULT_PORT)
|
||||
,_topDown(true)
|
||||
,_leftRight(true)
|
||||
,_startPos(0)
|
||||
,_endPos(0)
|
||||
,_extControlVersion (EXTCTRLVER_V2),
|
||||
_panelLedCount(0)
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceNanoleaf::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceNanoleaf(deviceConfig);
|
||||
@@ -91,17 +113,11 @@ LedDevice* LedDeviceNanoleaf::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
LedDeviceNanoleaf::~LedDeviceNanoleaf()
|
||||
{
|
||||
_networkmanager->deleteLater();
|
||||
}
|
||||
|
||||
LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_networkmanager = nullptr;
|
||||
_extControlVersion = EXTCTRLVER_V2;
|
||||
_panelLedCount = 0;
|
||||
if ( _restApi != nullptr )
|
||||
{
|
||||
delete _restApi;
|
||||
_restApi = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::init(const QJsonObject &deviceConfig)
|
||||
@@ -116,74 +132,89 @@ bool LedDeviceNanoleaf::init(const QJsonObject &deviceConfig)
|
||||
|
||||
DebugIf(verbose, _log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
if ( isInitOK )
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
uint configuredLedCount = this->getLedCount();
|
||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
||||
Debug(_log, "LedCount : %u", configuredLedCount);
|
||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
||||
Debug(_log, "RefreshTime : %d", _refresh_timer_interval);
|
||||
Debug(_log, "RefreshTime : %d", _refreshTimerInterval_ms);
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
|
||||
// Read panel organisation configuration
|
||||
if ( deviceConfig[ CONFIG_PANEL_ORDER_TOP_DOWN ].isString() )
|
||||
_topDown = deviceConfig[ CONFIG_PANEL_ORDER_TOP_DOWN ].toString().toInt() == 0 ? true : false;
|
||||
{
|
||||
_topDown = deviceConfig[ CONFIG_PANEL_ORDER_TOP_DOWN ].toString().toInt() == 0;
|
||||
}
|
||||
else
|
||||
_topDown = deviceConfig[ CONFIG_PANEL_ORDER_TOP_DOWN ].toInt() == 0 ? true : false;
|
||||
{
|
||||
_topDown = deviceConfig[ CONFIG_PANEL_ORDER_TOP_DOWN ].toInt() == 0;
|
||||
}
|
||||
|
||||
if ( deviceConfig[ CONFIG_PANEL_ORDER_LEFT_RIGHT ].isString() )
|
||||
_leftRight = deviceConfig[ CONFIG_PANEL_ORDER_LEFT_RIGHT ].toString().toInt() == 0 ? true : false;
|
||||
{
|
||||
_leftRight = deviceConfig[ CONFIG_PANEL_ORDER_LEFT_RIGHT ].toString().toInt() == 0;
|
||||
}
|
||||
else
|
||||
_leftRight = deviceConfig[ CONFIG_PANEL_ORDER_LEFT_RIGHT ].toInt() == 0 ? true : false;
|
||||
{
|
||||
_leftRight = deviceConfig[ CONFIG_PANEL_ORDER_LEFT_RIGHT ].toInt() == 0;
|
||||
}
|
||||
|
||||
_startPos = deviceConfig[ CONFIG_PANEL_START_POS ].toInt(0);
|
||||
_startPos = static_cast<uint>( deviceConfig[ CONFIG_PANEL_START_POS ].toInt(0) );
|
||||
|
||||
// TODO: Allow to handle port dynamically
|
||||
|
||||
//Set hostname as per configuration and_defaultHost default port
|
||||
_hostname = deviceConfig[ CONFIG_ADDRESS ].toString();
|
||||
_api_port = API_DEFAULT_PORT;
|
||||
_auth_token = deviceConfig[ CONFIG_AUTH_TOKEN ].toString();
|
||||
_apiPort = API_DEFAULT_PORT;
|
||||
_authToken = deviceConfig[ CONFIG_AUTH_TOKEN ].toString();
|
||||
|
||||
//If host not configured then discover device
|
||||
//If host not configured the init failed
|
||||
if ( _hostname.isEmpty() )
|
||||
{
|
||||
//Discover Nanoleaf device
|
||||
if ( !discoverDevice() )
|
||||
this->setInError("No target hostname nor IP defined");
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( initRestAPI( _hostname, _apiPort, _authToken ) )
|
||||
{
|
||||
this->setInError("No target IP defined nor Nanoleaf device was discovered");
|
||||
return false;
|
||||
// Read LedDevice configuration and validate against device configuration
|
||||
if ( initLedsConfiguration() )
|
||||
{
|
||||
// Set UDP streaming host and port
|
||||
_devConfig["host"] = _hostname;
|
||||
_devConfig["port"] = STREAM_CONTROL_DEFAULT_PORT;
|
||||
|
||||
isInitOK = ProviderUdp::init(_devConfig);
|
||||
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR( _hostname ));
|
||||
Debug(_log, "Port : %d", _port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set UDP streaming port
|
||||
_devConfig["host"] = _hostname;
|
||||
_devConfig["port"] = STREAM_CONTROL_DEFAULT_PORT;
|
||||
isInitOK = ProviderUdp::init(_devConfig);
|
||||
|
||||
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR( _hostname ));
|
||||
Debug(_log, "Port : %d", _port);
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::initLeds()
|
||||
bool LedDeviceNanoleaf::initLedsConfiguration()
|
||||
{
|
||||
bool isInitOK = true;
|
||||
|
||||
//Get Nanoleaf device details and configuration
|
||||
_networkmanager = new QNetworkAccessManager();
|
||||
|
||||
// Read Panel count and panel Ids
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_ROOT );
|
||||
QJsonDocument doc = getJson( url );
|
||||
if ( this->isInError() )
|
||||
_restApi->setPath(API_ROOT);
|
||||
httpResponse response = _restApi->get();
|
||||
if ( response.error() )
|
||||
{
|
||||
this->setInError ( response.getErrorReason() );
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
QJsonObject jsonAllPanelInfo = doc.object();
|
||||
QJsonObject jsonAllPanelInfo = response.getBody().object();
|
||||
|
||||
QString deviceName = jsonAllPanelInfo[DEV_DATA_NAME].toString();
|
||||
_deviceModel = jsonAllPanelInfo[DEV_DATA_MODEL].toString();
|
||||
@@ -205,7 +236,7 @@ bool LedDeviceNanoleaf::initLeds()
|
||||
std::map<uint, std::map<uint, uint>> panelMap;
|
||||
|
||||
// Loop over all children.
|
||||
for (const QJsonValue & value : positionData)
|
||||
for (const QJsonValue value : positionData)
|
||||
{
|
||||
QJsonObject panelObj = value.toObject();
|
||||
|
||||
@@ -239,9 +270,13 @@ bool LedDeviceNanoleaf::initLeds()
|
||||
DebugIf(verbose3, _log, "panelMap[%u][%u]=%u", posY->first, posX->first, posX->second );
|
||||
|
||||
if ( _topDown )
|
||||
{
|
||||
_panelIds.push_back(posX->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
_panelIds.push_front(posX->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -252,9 +287,13 @@ bool LedDeviceNanoleaf::initLeds()
|
||||
DebugIf(verbose3, _log, "panelMap[%u][%u]=%u", posY->first, posX->first, posX->second );
|
||||
|
||||
if ( _topDown )
|
||||
{
|
||||
_panelIds.push_back(posX->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
_panelIds.push_front(posX->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -300,197 +339,199 @@ bool LedDeviceNanoleaf::initLeds()
|
||||
}
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::initRestAPI(const QString &hostname, const int port, const QString &token )
|
||||
{
|
||||
bool isInitOK = false;
|
||||
|
||||
if ( _restApi == nullptr )
|
||||
{
|
||||
_restApi = new ProviderRestApi(hostname, port );
|
||||
|
||||
//Base-path is api-path + authentication token
|
||||
_restApi->setBasePath( QString(API_BASE_PATH).arg(token) );
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceNanoleaf::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
// Set Nanoleaf to External Control (UDP) mode
|
||||
Debug(_log, "Set Nanoleaf to External Control (UDP) streaming mode");
|
||||
QJsonDocument responseDoc = changeToExternalControlMode();
|
||||
// Resolve port for Light Panels
|
||||
QJsonObject jsonStreamControllInfo = responseDoc.object();
|
||||
if ( ! jsonStreamControllInfo.isEmpty() )
|
||||
{
|
||||
if ( !initNetwork() )
|
||||
{
|
||||
this->setInError( "UDP Network error!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( initLeds() )
|
||||
{
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
//Set default streaming port
|
||||
_port = static_cast<uchar>(jsonStreamControllInfo[STREAM_CONTROL_PORT].toInt());
|
||||
}
|
||||
|
||||
if ( ProviderUdp::open() == 0 )
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::discoverDevice()
|
||||
QJsonObject LedDeviceNanoleaf::discover()
|
||||
{
|
||||
QJsonObject devicesDiscovered;
|
||||
devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
|
||||
|
||||
bool isDeviceFound (false);
|
||||
// device searching by ssdp
|
||||
QString address;
|
||||
QJsonArray deviceList;
|
||||
|
||||
// Discover Nanoleaf Devices
|
||||
SSDPDiscover discover;
|
||||
|
||||
// Discover Canvas device
|
||||
address = discover.getFirstService(searchType::STY_WEBSERVER, SSDP_CANVAS, SSDP_TIMEOUT);
|
||||
// Search for Canvas and Light-Panels
|
||||
QString searchTargetFilter = QString("%1|%2").arg(SSDP_CANVAS, SSDP_LIGHTPANELS);
|
||||
|
||||
//No Canvas device not found
|
||||
if ( address.isEmpty() ) {
|
||||
// Discover Light Panels (Aurora) device
|
||||
address = discover.getFirstService(searchType::STY_WEBSERVER, SSDP_LIGHTPANELS, SSDP_TIMEOUT);
|
||||
discover.setSearchFilter(searchTargetFilter, SSDP_FILTER_HEADER);
|
||||
QString searchTarget = SSDP_ID;
|
||||
|
||||
if ( address.isEmpty() ) {
|
||||
Warning(_log, "No Nanoleaf device discovered");
|
||||
}
|
||||
if ( discover.discoverServices(searchTarget) > 0 )
|
||||
{
|
||||
deviceList = discover.getServicesDiscoveredJson();
|
||||
}
|
||||
|
||||
// Canvas or Light Panels found
|
||||
if ( ! address.isEmpty() ) {
|
||||
Info(_log, "Nanoleaf device discovered at [%s]", QSTRING_CSTR( address ));
|
||||
isDeviceFound = true;
|
||||
// Resolve hostname and port (or use default API port)
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||
QStringList addressparts = address.split(":", Qt::SkipEmptyParts);
|
||||
#else
|
||||
QStringList addressparts = address.split(":", QString::SkipEmptyParts);
|
||||
#endif
|
||||
_hostname = addressparts[0];
|
||||
_api_port = addressparts[1];
|
||||
}
|
||||
return isDeviceFound;
|
||||
devicesDiscovered.insert("devices", deviceList);
|
||||
Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
return devicesDiscovered;
|
||||
}
|
||||
|
||||
QJsonObject LedDeviceNanoleaf::getProperties(const QJsonObject& params)
|
||||
{
|
||||
Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
QJsonObject properties;
|
||||
|
||||
// Get Nanoleaf device properties
|
||||
QString host = params["host"].toString("");
|
||||
if ( !host.isEmpty() )
|
||||
{
|
||||
QString authToken = params["token"].toString("");
|
||||
QString filter = params["filter"].toString("");
|
||||
|
||||
// Resolve hostname and port (or use default API port)
|
||||
QStringList addressparts = QStringUtils::split(host,":", QStringUtils::SplitBehavior::SkipEmptyParts);
|
||||
QString apiHost = addressparts[0];
|
||||
int apiPort;
|
||||
|
||||
if ( addressparts.size() > 1)
|
||||
{
|
||||
apiPort = addressparts[1].toInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
apiPort = API_DEFAULT_PORT;
|
||||
}
|
||||
|
||||
initRestAPI(apiHost, apiPort, authToken);
|
||||
_restApi->setPath(filter);
|
||||
|
||||
// Perform request
|
||||
httpResponse response = _restApi->get();
|
||||
if ( response.error() )
|
||||
{
|
||||
Warning (_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||
}
|
||||
|
||||
properties.insert("properties", response.getBody().object());
|
||||
|
||||
Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
void LedDeviceNanoleaf::identify(const QJsonObject& params)
|
||||
{
|
||||
Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
QJsonObject properties;
|
||||
|
||||
// Get Nanoleaf device properties
|
||||
QString host = params["host"].toString("");
|
||||
if ( !host.isEmpty() )
|
||||
{
|
||||
QString authToken = params["token"].toString("");
|
||||
|
||||
// Resolve hostname and port (or use default API port)
|
||||
QStringList addressparts = QStringUtils::split(host,":", QStringUtils::SplitBehavior::SkipEmptyParts);
|
||||
QString apiHost = addressparts[0];
|
||||
int apiPort;
|
||||
|
||||
if ( addressparts.size() > 1)
|
||||
{
|
||||
apiPort = addressparts[1].toInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
apiPort = API_DEFAULT_PORT;
|
||||
}
|
||||
|
||||
initRestAPI(apiHost, apiPort, authToken);
|
||||
_restApi->setPath("identify");
|
||||
|
||||
// Perform request
|
||||
httpResponse response = _restApi->put();
|
||||
if ( response.error() )
|
||||
{
|
||||
Warning (_log, "%s identification failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::powerOn()
|
||||
{
|
||||
if ( _isDeviceReady)
|
||||
{
|
||||
//Power-on Nanoleaf device
|
||||
_restApi->setPath(API_STATE);
|
||||
_restApi->put( getOnOffRequest(true) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::powerOff()
|
||||
{
|
||||
if ( _isDeviceReady)
|
||||
{
|
||||
//Power-off the Nanoleaf device physically
|
||||
_restApi->setPath(API_STATE);
|
||||
_restApi->put( getOnOffRequest(false) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString LedDeviceNanoleaf::getOnOffRequest (bool isOn ) const
|
||||
{
|
||||
QString state = isOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
|
||||
return QString( "{\"%1\":{\"%2\":%3}}" ).arg(STATE_ON, STATE_ONOFF_VALUE, state);
|
||||
}
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode()
|
||||
{
|
||||
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_EFFECT );
|
||||
QJsonDocument jsonDoc;
|
||||
|
||||
_extControlVersion = EXTCTRLVER_V2;
|
||||
//Enable UDP Mode v2
|
||||
jsonDoc= putJson(url, API_EXT_MODE_STRING_V2);
|
||||
|
||||
return jsonDoc;
|
||||
}
|
||||
_restApi->setPath(API_EFFECT);
|
||||
httpResponse response =_restApi->put(API_EXT_MODE_STRING_V2);
|
||||
|
||||
QString LedDeviceNanoleaf::getUrl(QString host, QString port, QString auth_token, QString endpoint) const {
|
||||
return QString(API_URL_FORMAT).arg(host, port, auth_token, endpoint);
|
||||
}
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::getJson(QString url)
|
||||
{
|
||||
|
||||
Debug(_log, "GET: [%s]", QSTRING_CSTR( url ));
|
||||
|
||||
// Perfrom request
|
||||
QNetworkRequest request(url);
|
||||
QNetworkReply* reply = _networkmanager->get(request);
|
||||
// Connect requestFinished signal to quit slot of the loop.
|
||||
QEventLoop loop;
|
||||
loop.connect(reply, SIGNAL(finished()), SLOT(quit()));
|
||||
// Go into the loop until the request is finished.
|
||||
loop.exec();
|
||||
|
||||
QJsonDocument jsonDoc;
|
||||
if(reply->operation() == QNetworkAccessManager::GetOperation)
|
||||
{
|
||||
jsonDoc = handleReply( reply );
|
||||
}
|
||||
// Free space.
|
||||
reply->deleteLater();
|
||||
// Return response
|
||||
return jsonDoc;
|
||||
}
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::putJson(QString url, QString json)
|
||||
{
|
||||
|
||||
Debug(_log, "PUT: [%s] [%s]", QSTRING_CSTR( url ), QSTRING_CSTR( json ) );
|
||||
// Perfrom request
|
||||
QNetworkRequest request(url);
|
||||
QNetworkReply* reply = _networkmanager->put(request, json.toUtf8());
|
||||
// Connect requestFinished signal to quit slot of the loop.
|
||||
QEventLoop loop;
|
||||
loop.connect(reply, SIGNAL(finished()), SLOT(quit()));
|
||||
// Go into the loop until the request is finished.
|
||||
loop.exec();
|
||||
|
||||
QJsonDocument jsonDoc;
|
||||
if(reply->operation() == QNetworkAccessManager::PutOperation)
|
||||
{
|
||||
jsonDoc = handleReply( reply );
|
||||
}
|
||||
// Free space.
|
||||
reply->deleteLater();
|
||||
|
||||
// Return response
|
||||
return jsonDoc;
|
||||
}
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply )
|
||||
{
|
||||
|
||||
QJsonDocument jsonDoc;
|
||||
|
||||
int httpStatusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
|
||||
Debug(_log, "Reply.httpStatusCode [%d]", httpStatusCode );
|
||||
|
||||
if(reply->error() == QNetworkReply::NoError)
|
||||
{
|
||||
if ( httpStatusCode != 204 ){
|
||||
QByteArray response = reply->readAll();
|
||||
QJsonParseError error;
|
||||
jsonDoc = QJsonDocument::fromJson(response, &error);
|
||||
if (error.error != QJsonParseError::NoError)
|
||||
{
|
||||
this->setInError ( "Got invalid response" );
|
||||
}
|
||||
else {
|
||||
//Debug
|
||||
QString strJson(jsonDoc.toJson(QJsonDocument::Compact));
|
||||
DebugIf(verbose, _log, "Reply: [%s]", strJson.toUtf8().constData() );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QString errorReason;
|
||||
if ( httpStatusCode > 0 ) {
|
||||
QString httpReason = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString();
|
||||
QString advise;
|
||||
switch ( httpStatusCode ) {
|
||||
case 400:
|
||||
advise = "Check Request Body";
|
||||
break;
|
||||
case 401:
|
||||
advise = "Check Authentication Token (API Key)";
|
||||
break;
|
||||
case 404:
|
||||
advise = "Check Resource given";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
errorReason = QString ("%1:%2 [%3 %4] - %5").arg(_hostname, _api_port, QString(httpStatusCode) , httpReason, advise);
|
||||
}
|
||||
else {
|
||||
errorReason = QString ("%1:%2 - %3").arg(_hostname, _api_port, reply->errorString());
|
||||
}
|
||||
this->setInError ( errorReason );
|
||||
}
|
||||
// Return response
|
||||
return jsonDoc;
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
|
||||
{
|
||||
|
||||
int retVal = 0;
|
||||
uint udpBufferSize;
|
||||
|
||||
@@ -573,46 +614,6 @@ int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
|
||||
return retVal;
|
||||
}
|
||||
|
||||
QString LedDeviceNanoleaf::getOnOffRequest (bool isOn ) const
|
||||
{
|
||||
QString state = isOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
|
||||
return QString( "{\"%1\":{\"%2\":%3}}" ).arg(STATE_ON, STATE_ONOFF_VALUE, state);
|
||||
}
|
||||
|
||||
int LedDeviceNanoleaf::switchOn()
|
||||
{
|
||||
if ( _deviceReady)
|
||||
{
|
||||
// Set Nanoleaf to External Control (UDP) mode
|
||||
Debug(_log, "Set Nanoleaf to External Control (UDP) streaming mode");
|
||||
QJsonDocument responseDoc = changeToExternalControlMode();
|
||||
// Resolve port for Ligh Panels
|
||||
QJsonObject jsonStreamControllInfo = responseDoc.object();
|
||||
if ( ! jsonStreamControllInfo.isEmpty() ) {
|
||||
_port = static_cast<uchar>(jsonStreamControllInfo[STREAM_CONTROL_PORT].toInt());
|
||||
}
|
||||
|
||||
//Switch on Nanoleaf device
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
|
||||
putJson(url, this->getOnOffRequest(true) );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LedDeviceNanoleaf::switchOff()
|
||||
{
|
||||
//Set all LEDs to Black
|
||||
int rc = LedDevice::switchOff();
|
||||
|
||||
if ( _deviceReady)
|
||||
{
|
||||
//Switch off Nanoleaf device physically
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
|
||||
putJson(url, getOnOffRequest(false) );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
std::string LedDeviceNanoleaf:: uint8_vector_to_hex_string( const std::vector<uint8_t>& buffer ) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
@@ -1,12 +1,11 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICENANOLEAF_H
|
||||
#define LEDEVICENANOLEAF_H
|
||||
|
||||
// Leddevice includes
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
#include "ProviderRestApi.h"
|
||||
#include "ProviderUdp.h"
|
||||
|
||||
// ssdp discover
|
||||
#include <ssdp/SSDPDiscover.h>
|
||||
|
||||
// Qt includes
|
||||
#include <QString>
|
||||
#include <QNetworkAccessManager>
|
||||
@@ -19,85 +18,141 @@ class LedDeviceNanoleaf : public ProviderUdp
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Constructs the LedDevice for Nanoleaf LightPanels (aka Aurora) or Canvas
|
||||
/// @brief Constructs LED-device for Nanoleaf LightPanels (aka Aurora) or Canvas
|
||||
///
|
||||
/// following code shows all config options
|
||||
/// following code shows all configuration options
|
||||
/// @code
|
||||
/// "device" :
|
||||
/// {
|
||||
/// "type" : "nanoleaf"
|
||||
/// "output" : "hostname or IP", // Optional. If empty, device is tried to be discovered
|
||||
/// "token" : "Authentication Token",
|
||||
/// "type" : "nanoleaf"
|
||||
/// "host" : "hostname or IP",
|
||||
/// "token": "Authentication Token",
|
||||
/// },
|
||||
///@endcode
|
||||
///
|
||||
/// @param deviceConfig json config for nanoleaf
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceNanoleaf(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the tcp client
|
||||
/// @brief Destructor of the LED-device
|
||||
///
|
||||
virtual ~LedDeviceNanoleaf() override;
|
||||
|
||||
/// Constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
/// Switch the device on
|
||||
virtual int switchOn() override;
|
||||
///
|
||||
/// @brief Discover Nanoleaf devices available (for configuration).
|
||||
///
|
||||
/// @return A JSON structure holding a list of devices found
|
||||
///
|
||||
virtual QJsonObject discover() override;
|
||||
|
||||
/// Switch the device off
|
||||
virtual int switchOff() override;
|
||||
///
|
||||
/// @brief Get the Nanoleaf device's resource properties
|
||||
///
|
||||
/// Following parameters are required
|
||||
/// @code
|
||||
/// {
|
||||
/// "host" : "hostname or IP [:port]",
|
||||
/// "token" : "authentication token",
|
||||
/// "filter": "resource to query", root "/" is used, if empty
|
||||
/// }
|
||||
///@endcode
|
||||
///
|
||||
/// @param[in] params Parameters to query device
|
||||
/// @return A JSON structure holding the device's properties
|
||||
///
|
||||
virtual QJsonObject getProperties(const QJsonObject& params) override;
|
||||
|
||||
///
|
||||
/// @brief Send an update to the Nanoleaf device to identify it.
|
||||
///
|
||||
/// Following parameters are required
|
||||
/// @code
|
||||
/// {
|
||||
/// "host" : "hostname or IP [:port]",
|
||||
/// "token" : "authentication token",
|
||||
/// }
|
||||
///@endcode
|
||||
///
|
||||
/// @param[in] params Parameters to address device
|
||||
///
|
||||
virtual void identify(const QJsonObject& params) override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Initialise the Nanoleaf device's configuration and network address details
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
///
|
||||
/// Initialise Nanoleaf device's configuration and network address details
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return True if success
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// Get Nanoleaf device details and configuration
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return True, if Nanoleaf device capabilities fit configuration
|
||||
///
|
||||
bool initLeds();
|
||||
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Discover Nanoleaf device via SSDP identifiers
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @return True, if Nanoleaf device was found
|
||||
///
|
||||
bool discoverDevice();
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
//////
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
///
|
||||
/// Change Nanoleaf device to External Control (UDP) mode
|
||||
/// @brief Power-/turn on the Nanoleaf device.
|
||||
///
|
||||
/// @brief Store the device's original state.
|
||||
///
|
||||
virtual bool powerOn() override;
|
||||
|
||||
///
|
||||
/// @brief Power-/turn off the Nanoleaf device.
|
||||
///
|
||||
/// @return True if success
|
||||
///
|
||||
virtual bool powerOff() override;
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// @brief Initialise the access to the REST-API wrapper
|
||||
///
|
||||
/// @param[in] host
|
||||
/// @param[in] port
|
||||
/// @param[in] authentication token
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
bool initRestAPI(const QString &hostname, const int port, const QString &token );
|
||||
|
||||
///
|
||||
/// @brief Get Nanoleaf device details and configuration
|
||||
///
|
||||
/// @return True, if Nanoleaf device capabilities fit configuration
|
||||
///
|
||||
bool initLedsConfiguration();
|
||||
|
||||
///
|
||||
/// @brief Change Nanoleaf device to External Control (UDP) mode
|
||||
///
|
||||
/// @return Response from device
|
||||
///
|
||||
///@brief
|
||||
QJsonDocument changeToExternalControlMode();
|
||||
|
||||
///
|
||||
/// Get command to switch Nanoleaf device on or off
|
||||
/// @brief Get command to power Nanoleaf device on or off
|
||||
///
|
||||
/// @param isOn True, if to switch on device
|
||||
/// @return Command to switch device on/off
|
||||
@@ -105,54 +160,18 @@ private:
|
||||
QString getOnOffRequest (bool isOn ) const;
|
||||
|
||||
///
|
||||
/// Get command as url
|
||||
///
|
||||
/// @param host Hostname or IP
|
||||
/// @param port IP-Port
|
||||
/// @param _auth_token Authorization token
|
||||
/// @param Endpoint command for request
|
||||
/// @return Url to execute endpoint/command
|
||||
///
|
||||
QString getUrl(QString host, QString port, QString auth_token, QString endpoint) const;
|
||||
|
||||
///
|
||||
/// Execute GET request
|
||||
///
|
||||
/// @param url GET request for url
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument getJson(QString url);
|
||||
|
||||
///
|
||||
/// Execute PUT request
|
||||
///
|
||||
/// @param Url for PUT request
|
||||
/// @param json Command for request
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument putJson(QString url, QString json);
|
||||
|
||||
///
|
||||
/// Handle replys for GET and PUT requests
|
||||
///
|
||||
/// @param reply Network reply
|
||||
/// @return Response for request, if no error
|
||||
///
|
||||
QJsonDocument handleReply(QNetworkReply* const &reply );
|
||||
|
||||
///
|
||||
/// convert vector to hex string
|
||||
/// @brief Convert vector to hex string
|
||||
///
|
||||
/// @param uint8_t vector
|
||||
/// @return vector as string of hex values
|
||||
std::string uint8_vector_to_hex_string( const std::vector<uint8_t>& buffer ) const;
|
||||
|
||||
// QNetworkAccessManager object for sending requests.
|
||||
QNetworkAccessManager* _networkmanager;
|
||||
///REST-API wrapper
|
||||
ProviderRestApi* _restApi;
|
||||
|
||||
QString _hostname;
|
||||
QString _api_port;
|
||||
QString _auth_token;
|
||||
int _apiPort;
|
||||
QString _authToken;
|
||||
|
||||
bool _topDown;
|
||||
bool _leftRight;
|
||||
@@ -163,9 +182,13 @@ private:
|
||||
QString _deviceModel;
|
||||
QString _deviceFirmwareVersion;
|
||||
ushort _extControlVersion;
|
||||
/// The number of panels with leds
|
||||
|
||||
/// The number of panels with LEDs
|
||||
uint _panelLedCount;
|
||||
/// Array of the pannel ids.
|
||||
|
||||
/// Array of the panel ids.
|
||||
QVector<uint> _panelIds;
|
||||
|
||||
};
|
||||
|
||||
#endif // LEDEVICENANOLEAF_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -12,8 +12,9 @@
|
||||
#include <QtCore/qmath.h>
|
||||
#include <QStringList>
|
||||
|
||||
// Leddevice includes
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
#include "ProviderRestApi.h"
|
||||
#include "ProviderUdpSSL.h"
|
||||
|
||||
/**
|
||||
@@ -134,7 +135,7 @@ public:
|
||||
///
|
||||
/// @param transitionTime the transition time between colors in multiples of 100 ms
|
||||
///
|
||||
void setTransitionTime(unsigned int transitionTime);
|
||||
void setTransitionTime(int transitionTime);
|
||||
|
||||
///
|
||||
/// @param color the color to set
|
||||
@@ -144,7 +145,7 @@ public:
|
||||
unsigned int getId() const;
|
||||
|
||||
bool getOnOffState() const;
|
||||
unsigned int getTransitionTime() const;
|
||||
int getTransitionTime() const;
|
||||
CiColor getColor() const;
|
||||
|
||||
///
|
||||
@@ -162,7 +163,7 @@ private:
|
||||
unsigned int _id;
|
||||
unsigned int _ledidx;
|
||||
bool _on;
|
||||
unsigned int _transitionTime;
|
||||
int _transitionTime;
|
||||
CiColor _color;
|
||||
/// darkes blue color in hue lamp GAMUT = black
|
||||
CiColor _colorBlack;
|
||||
@@ -185,14 +186,18 @@ class LedDevicePhilipsHueBridge : public ProviderUdpSSL
|
||||
public:
|
||||
|
||||
explicit LedDevicePhilipsHueBridge(const QJsonObject &deviceConfig);
|
||||
~LedDevicePhilipsHueBridge();
|
||||
~LedDevicePhilipsHueBridge() override;
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Initialise the access to the REST-API wrapper
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
/// @param[in] host
|
||||
/// @param[in] port
|
||||
/// @param[in] authentication token
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
bool initRestAPI(const QString &hostname, const int port, const QString &token );
|
||||
|
||||
///
|
||||
/// @param route the route of the POST request.
|
||||
@@ -201,28 +206,56 @@ public:
|
||||
///
|
||||
QJsonDocument post(const QString& route, const QString& content);
|
||||
|
||||
void setLightState(unsigned int lightId = 0, QString state = "");
|
||||
void setLightState(unsigned int lightId = 0, const QString &state = "");
|
||||
|
||||
const QMap<quint16,QJsonObject>& getLightMap();
|
||||
|
||||
const QMap<quint16,QJsonObject>& getGroupMap();
|
||||
|
||||
QString getGroupName(unsigned int groupId = 0);
|
||||
QString getGroupName(quint16 groupId = 0);
|
||||
|
||||
QJsonArray getGroupLights(quint16 groupId = 0);
|
||||
|
||||
QJsonArray getGroupLights(unsigned int groupId = 0);
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Connect to bridge to check availbility and user
|
||||
///
|
||||
virtual int open(void) override;
|
||||
virtual int open( const QString& hostname, const QString& port, const QString& username );
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// @brief Initialise the Hue-Bridge configuration and network address details
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the Hue-Bridge device and its SSL-connection
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
virtual int open(void) override;
|
||||
|
||||
///
|
||||
/// @brief Closes the Hue-Bridge device and its SSL-connection
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// @brief Check, if Hue API response indicate error
|
||||
///
|
||||
/// @param[in] response from Hue-Bridge in JSON-format
|
||||
/// return True, Hue Bridge reports error
|
||||
///
|
||||
bool checkApiError(const QJsonDocument &response );
|
||||
|
||||
///REST-API wrapper
|
||||
ProviderRestApi* _restApi;
|
||||
|
||||
/// Ip address of the bridge
|
||||
QString _hostname;
|
||||
QString _api_port;
|
||||
int _apiPort;
|
||||
/// User name for the API ("newdeveloper")
|
||||
QString _username;
|
||||
|
||||
@@ -231,7 +264,7 @@ protected:
|
||||
QJsonDocument getGroupState( unsigned int groupId );
|
||||
QJsonDocument setGroupState( unsigned int groupId, bool state);
|
||||
|
||||
bool isStreamOwner(const QString streamOwner);
|
||||
bool isStreamOwner(const QString &streamOwner);
|
||||
bool initMaps();
|
||||
|
||||
void log(const char* msg, const char* type, ...);
|
||||
@@ -240,56 +273,10 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Discover device via SSDP identifiers
|
||||
///
|
||||
/// @return True, if device was found
|
||||
///
|
||||
bool discoverDevice();
|
||||
|
||||
///
|
||||
/// Get command as url
|
||||
///
|
||||
/// @param host Hostname or IP
|
||||
/// @param port IP-Port
|
||||
/// @param _auth_token Authorization token
|
||||
/// @param Endpoint command for request
|
||||
/// @return Url to execute endpoint/command
|
||||
///
|
||||
QString getUrl(QString host, QString port, QString auth_token, QString endpoint) const;
|
||||
|
||||
///
|
||||
/// Execute GET request
|
||||
///
|
||||
/// @param url GET request for url
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument getJson(QString url);
|
||||
|
||||
///
|
||||
/// Execute PUT request
|
||||
///
|
||||
/// @param Url for PUT request
|
||||
/// @param json Command for request
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument putJson(QString url, QString json);
|
||||
|
||||
///
|
||||
/// Handle replys for GET and PUT requests
|
||||
///
|
||||
/// @param reply Network reply
|
||||
/// @return Response for request, if no error
|
||||
///
|
||||
QJsonDocument handleReply(QNetworkReply* const &reply );
|
||||
|
||||
QJsonDocument getAllBridgeInfos();
|
||||
void setBridgeConfig( QJsonDocument doc );
|
||||
void setLightsMap( QJsonDocument doc );
|
||||
void setGroupMap( QJsonDocument doc );
|
||||
|
||||
/// QNetworkAccessManager for sending requests.
|
||||
QNetworkAccessManager* _networkmanager;
|
||||
void setBridgeConfig( const QJsonDocument &doc );
|
||||
void setLightsMap( const QJsonDocument &doc );
|
||||
void setGroupMap( const QJsonDocument &doc );
|
||||
|
||||
//Philips Hue Bridge details
|
||||
QString _deviceModel;
|
||||
@@ -320,105 +307,209 @@ class LedDevicePhilipsHue: public LedDevicePhilipsHueBridge
|
||||
|
||||
public:
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs LED-device for Philips Hue Lights system
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDevicePhilipsHue(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Destructor of this device
|
||||
/// @brief Destructor of the LED-device
|
||||
///
|
||||
virtual ~LedDevicePhilipsHue();
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Discover devices of this type available (for configuration).
|
||||
/// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways.
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
/// Switch the device on
|
||||
virtual int switchOn() override;
|
||||
|
||||
/// Switch the device off
|
||||
virtual int switchOff() override;
|
||||
|
||||
/// creates new PhilipsHueLight(s) based on user lightid with bridge feedback
|
||||
/// @return A JSON structure holding a list of devices found
|
||||
///
|
||||
/// @param map Map of lightid/value pairs of bridge
|
||||
///
|
||||
void newLights(QMap<quint16, QJsonObject> map);
|
||||
virtual QJsonObject discover() override;
|
||||
|
||||
///
|
||||
/// @brief Get the Hue Bridge device's resource properties
|
||||
///
|
||||
/// Following parameters are required
|
||||
/// @code
|
||||
/// {
|
||||
/// "host" : "hostname or IP [:port]",
|
||||
/// "user" : "username",
|
||||
/// "filter": "resource to query", root "/" is used, if empty
|
||||
/// }
|
||||
///@endcode
|
||||
///
|
||||
/// @param[in] params Parameters to query device
|
||||
/// @return A JSON structure holding the device's properties
|
||||
///
|
||||
virtual QJsonObject getProperties(const QJsonObject& params) override;
|
||||
|
||||
///
|
||||
/// @brief Send an update to the device to identify it.
|
||||
///
|
||||
/// Used in context of a set of devices of the same type.
|
||||
///
|
||||
/// @param[in] params Parameters to address device
|
||||
///
|
||||
virtual void identify(const QJsonObject& params) override;
|
||||
|
||||
///
|
||||
/// @brief Get the number of LEDs supported by the device.
|
||||
///
|
||||
/// @return Number of device's LEDs
|
||||
///
|
||||
unsigned int getLightsCount() const { return _lightsCount; }
|
||||
void setLightsCount( unsigned int lightsCount);
|
||||
|
||||
bool initStream();
|
||||
bool getStreamGroupState();
|
||||
bool setStreamGroupState(bool state);
|
||||
bool startStream();
|
||||
bool stopStream();
|
||||
|
||||
void setOnOffState(PhilipsHueLight& light, bool on);
|
||||
void setTransitionTime(PhilipsHueLight& light);
|
||||
void setColor(PhilipsHueLight& light, CiColor& color);
|
||||
void setState(PhilipsHueLight& light, bool on, const CiColor& color);
|
||||
|
||||
void restoreOriginalState();
|
||||
|
||||
public slots:
|
||||
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
/// @brief Stops the device.
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
private slots:
|
||||
/// creates new PhilipsHueLight(s) based on user lightid with bridge feedback
|
||||
/// Includes switching-off the device and stopping refreshes.
|
||||
///
|
||||
/// @param map Map of lightid/value pairs of bridge
|
||||
///
|
||||
bool updateLights(QMap<quint16, QJsonObject> map);
|
||||
|
||||
void noSignalTimeout();
|
||||
virtual void stop() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
/// Initialise the device's configuration
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
/// @param deviceConfig Device's configuration in JSON
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
///
|
||||
/// Get Philips Hue device details and configuration
|
||||
/// @brief Closes the output device.
|
||||
///
|
||||
/// @return True, if Nanoleaf device capabilities fit configuration
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
bool initLeds();
|
||||
bool reinitLeds();
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// Writes the RGB-Color values to the leds.
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per led
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues) override;
|
||||
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
/// @brief Switch the LEDs on.
|
||||
///
|
||||
/// Takes care that the device is opened and powered-on.
|
||||
/// Depending on the configuration, the device may store its current state for later restore.
|
||||
/// @see powerOn, storeState
|
||||
///
|
||||
/// @return True if success
|
||||
///
|
||||
//virtual bool switchOn() override;
|
||||
|
||||
///
|
||||
/// @brief Switch the LEDs off.
|
||||
///
|
||||
/// Takes care that the LEDs and device are switched-off and device is closed.
|
||||
/// Depending on the configuration, the device may be powered-off or restored to its previous state.
|
||||
/// @see powerOff, restoreState
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool switchOff() override;
|
||||
|
||||
///
|
||||
/// @brief Power-/turn on the LED-device.
|
||||
///
|
||||
/// Powers-/Turns on the LED hardware, if supported.
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool powerOn() override;
|
||||
|
||||
///
|
||||
/// @brief Power-/turn off the LED-device.
|
||||
///
|
||||
/// Depending on the device's capability, the device is powered-/turned off or
|
||||
/// an off state is simulated by writing "Black to LED" (default).
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool powerOff() override;
|
||||
|
||||
///
|
||||
/// @brief Store the device's original state.
|
||||
///
|
||||
/// Save the device's state before hyperion color streaming starts allowing to restore state during switchOff().
|
||||
///
|
||||
/// @return True if success
|
||||
///
|
||||
virtual bool storeState() override;
|
||||
|
||||
///
|
||||
/// @brief Restore the device's original state.
|
||||
///
|
||||
/// Restore the device's state as before hyperion color streaming started.
|
||||
/// This includes the on/off state of the device.
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool restoreState() override;
|
||||
|
||||
private slots:
|
||||
|
||||
void noSignalTimeout();
|
||||
|
||||
private:
|
||||
|
||||
bool initLeds();
|
||||
|
||||
///
|
||||
/// @brief Creates new PhilipsHueLight(s) based on user lightid with bridge feedback
|
||||
///
|
||||
/// @param map Map of lightid/value pairs of bridge
|
||||
///
|
||||
void newLights(QMap<quint16, QJsonObject> map);
|
||||
|
||||
bool setLights();
|
||||
|
||||
int writeSingleLights(const std::vector<ColorRgb>& ledValues);
|
||||
/// creates new PhilipsHueLight(s) based on user lightid with bridge feedback
|
||||
///
|
||||
/// @param map Map of lightid/value pairs of bridge
|
||||
///
|
||||
bool updateLights(const QMap<quint16, QJsonObject> &map);
|
||||
|
||||
///
|
||||
/// @brief Set the number of LEDs supported by the device.
|
||||
///
|
||||
/// @rparam[in] Number of device's LEDs
|
||||
//
|
||||
void setLightsCount( unsigned int lightsCount);
|
||||
|
||||
bool openStream();
|
||||
bool getStreamGroupState();
|
||||
bool setStreamGroupState(bool state);
|
||||
bool startStream();
|
||||
bool stopStream();
|
||||
|
||||
void writeStream();
|
||||
int writeSingleLights(const std::vector<ColorRgb>& ledValues);
|
||||
|
||||
bool noSignalDetection();
|
||||
|
||||
@@ -430,21 +521,20 @@ private:
|
||||
bool _switchOffOnBlack;
|
||||
/// The brightness factor to multiply on color change.
|
||||
double _brightnessFactor;
|
||||
/// Transition time in multiples of 100 ms.
|
||||
/// The default of the Hue lights is 400 ms, but we may want it snapier.
|
||||
unsigned int _transitionTime;
|
||||
/// Transition time in multiples of 100 ms.
|
||||
/// The default of the Hue lights is 400 ms, but we may want it snappier.
|
||||
int _transitionTime;
|
||||
|
||||
bool _isRestoreOrigState;
|
||||
bool _lightStatesRestored;
|
||||
bool _isInitLeds;
|
||||
|
||||
/// Array of the light ids.
|
||||
std::vector<unsigned int> _lightIds;
|
||||
std::vector<quint16> _lightIds;
|
||||
/// Array to save the lamps.
|
||||
std::vector<PhilipsHueLight> _lights;
|
||||
|
||||
unsigned int _lightsCount;
|
||||
unsigned int _groupId;
|
||||
quint16 _groupId;
|
||||
|
||||
double _brightnessMin;
|
||||
double _brightnessMax;
|
||||
@@ -452,7 +542,7 @@ private:
|
||||
bool _allLightsBlack;
|
||||
|
||||
QTimer* _blackLightsTimer;
|
||||
unsigned int _blackLightsTimeout;
|
||||
int _blackLightsTimeout;
|
||||
double _brightnessThreshold;
|
||||
|
||||
int _handshake_timeout_min;
|
||||
@@ -466,4 +556,5 @@ private:
|
||||
|
||||
int start_retry_left;
|
||||
int stop_retry_left;
|
||||
|
||||
};
|
||||
|
@@ -1,10 +1,14 @@
|
||||
#include "LedDeviceTpm2net.h"
|
||||
|
||||
const ushort TPM2_DEFAULT_PORT = 65506;
|
||||
|
||||
LedDeviceTpm2net::LedDeviceTpm2net(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceTpm2net::construct(const QJsonObject &deviceConfig)
|
||||
@@ -14,13 +18,19 @@ LedDevice* LedDeviceTpm2net::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceTpm2net::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = false;
|
||||
|
||||
_port = TPM2_DEFAULT_PORT;
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
|
||||
_tpm2_max = deviceConfig["max-packet"].toInt(170);
|
||||
_tpm2ByteCount = 3 * _ledCount;
|
||||
_tpm2TotalPackets = 1 + _tpm2ByteCount / _tpm2_max;
|
||||
// Initialise sub-class
|
||||
if ( ProviderUdp::init(deviceConfig) )
|
||||
{
|
||||
_tpm2_max = deviceConfig["max-packet"].toInt(170);
|
||||
_tpm2ByteCount = 3 * _ledCount;
|
||||
_tpm2TotalPackets = 1 + _tpm2ByteCount / _tpm2_max;
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
|
@@ -1,44 +1,53 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICETPM2NET_H
|
||||
#define LEDEVICETPM2NET_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderUdp.h"
|
||||
|
||||
const ushort TPM2_DEFAULT_PORT = 65506;
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending led colors via udp tpm2.net packets
|
||||
/// Implementation of the LedDevice interface for sending LED colors via udp tpm2.net packets
|
||||
///
|
||||
class LedDeviceTpm2net : public ProviderUdp
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a TPM2 LED-device fed via UDP
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceTpm2net(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
int _tpm2_max;
|
||||
int _tpm2ByteCount;
|
||||
int _tpm2TotalPackets;
|
||||
int _tpm2ThisPacket;
|
||||
};
|
||||
|
||||
#endif // LEDEVICETPM2NET_H
|
||||
|
@@ -1,3 +1,6 @@
|
||||
// hyperion local includes
|
||||
#include "LedDeviceUdpArtNet.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
#else
|
||||
@@ -6,16 +9,18 @@
|
||||
|
||||
#include <QHostInfo>
|
||||
|
||||
// hyperion local includes
|
||||
#include "LedDeviceUdpArtNet.h"
|
||||
const ushort ARTNET_DEFAULT_PORT = 6454;
|
||||
|
||||
LedDeviceUdpArtNet::LedDeviceUdpArtNet(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
|
||||
LedDevice* LedDeviceUdpArtNet::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceUdpArtNet(deviceConfig);
|
||||
@@ -23,12 +28,18 @@ LedDevice* LedDeviceUdpArtNet::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceUdpArtNet::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = false;
|
||||
|
||||
_port = ARTNET_DEFAULT_PORT;
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
|
||||
_artnet_universe = deviceConfig["universe"].toInt(1);
|
||||
_artnet_channelsPerFixture = deviceConfig["channelsPerFixture"].toInt(3);
|
||||
// Initialise sub-class
|
||||
if ( ProviderUdp::init(deviceConfig) )
|
||||
{
|
||||
_artnet_universe = deviceConfig["universe"].toInt(1);
|
||||
_artnet_channelsPerFixture = deviceConfig["channelsPerFixture"].toInt(3);
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
@@ -51,7 +62,6 @@ void LedDeviceUdpArtNet::prepare(const unsigned this_universe, const unsigned th
|
||||
artnet_packet.SubUni = this_universe & 0xff ;
|
||||
artnet_packet.Net = (this_universe >> 8) & 0x7f;
|
||||
artnet_packet.Length = htons(this_dmxChannelCount);
|
||||
|
||||
}
|
||||
|
||||
int LedDeviceUdpArtNet::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEUDPARTNET_H
|
||||
#define LEDEVICEUDPARTNET_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderUdp.h"
|
||||
@@ -13,9 +14,7 @@
|
||||
*
|
||||
**/
|
||||
|
||||
const ushort ARTNET_DEFAULT_PORT = 6454;
|
||||
|
||||
#define DMX_MAX 512 // 512 usable slots
|
||||
const int DMX_MAX = 512; // 512 usable slots
|
||||
|
||||
// http://stackoverflow.com/questions/16396013/artnet-packet-structure
|
||||
typedef union
|
||||
@@ -23,7 +22,7 @@ typedef union
|
||||
#pragma pack(push, 1)
|
||||
struct {
|
||||
char ID[8]; // "Art-Net"
|
||||
uint16_t OpCode; // See Doc. Table 1 - OpCodes eg. 0x5000 OpOutput / OpDmx
|
||||
uint16_t OpCode; // See Doc. Table 1 - OpCodes e.g. 0x5000 OpOutput / OpDmx
|
||||
uint16_t ProtVer; // 0x0e00 (aka 14)
|
||||
uint8_t Sequence; // monotonic counter
|
||||
uint8_t Physical; // 0x00
|
||||
@@ -39,42 +38,54 @@ typedef union
|
||||
} artnet_packet_t;
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending led colors via udp/E1.31 packets
|
||||
/// Implementation of the LedDevice interface for sending LED colors to an Art-Net LED-device via UDP
|
||||
///
|
||||
class LedDeviceUdpArtNet : public ProviderUdp
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs an Art-Net LED-device fed via UDP
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceUdpArtNet(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
///
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
///
|
||||
/// @brief Generate Art-Net communication header
|
||||
///
|
||||
void prepare(const unsigned this_universe, const unsigned this_sequence, const unsigned this_dmxChannelCount);
|
||||
|
||||
|
||||
artnet_packet_t artnet_packet;
|
||||
uint8_t _artnet_seq = 1;
|
||||
int _artnet_channelsPerFixture = 3;
|
||||
int _artnet_universe = 1;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEUDPARTNET_H
|
||||
|
@@ -9,18 +9,43 @@
|
||||
// hyperion local includes
|
||||
#include "LedDeviceUdpE131.h"
|
||||
|
||||
const ushort E131_DEFAULT_PORT = 5568;
|
||||
|
||||
/* defined parameters from http://tsp.esta.org/tsp/documents/docs/BSR_E1-31-20xx_CP-2014-1009r2.pdf */
|
||||
const uint32_t VECTOR_ROOT_E131_DATA = 0x00000004;
|
||||
//#define VECTOR_ROOT_E131_EXTENDED 0x00000008
|
||||
const uint8_t VECTOR_DMP_SET_PROPERTY = 0x02;
|
||||
const uint32_t VECTOR_E131_DATA_PACKET = 0x00000002;
|
||||
//#define VECTOR_E131_EXTENDED_SYNCHRONIZATION 0x00000001
|
||||
//#define VECTOR_E131_EXTENDED_DISCOVERY 0x00000002
|
||||
//#define VECTOR_UNIVERSE_DISCOVERY_UNIVERSE_LIST 0x00000001
|
||||
//#define E131_E131_UNIVERSE_DISCOVERY_INTERVAL 10 // seconds
|
||||
//#define E131_NETWORK_DATA_LOSS_TIMEOUT 2500 // milli econds
|
||||
//#define E131_DISCOVERY_UNIVERSE 64214
|
||||
const int DMX_MAX = 512; // 512 usable slots
|
||||
|
||||
LedDeviceUdpE131::LedDeviceUdpE131(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpE131::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceUdpE131(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = false;
|
||||
|
||||
_port = E131_DEFAULT_PORT;
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
|
||||
// Initialise sub-class
|
||||
if ( ProviderUdp::init(deviceConfig) )
|
||||
{
|
||||
_e131_universe = deviceConfig["universe"].toInt(1);
|
||||
_e131_source_name = deviceConfig["source-name"].toString("hyperion on "+QHostInfo::localHostName());
|
||||
@@ -29,22 +54,26 @@ bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig)
|
||||
if (_json_cid.isEmpty())
|
||||
{
|
||||
_e131_cid = QUuid::createUuid();
|
||||
Debug( _log, "e131 no cid found, generated %s", QSTRING_CSTR(_e131_cid.toString()));
|
||||
Debug( _log, "e131 no CID found, generated %s", QSTRING_CSTR(_e131_cid.toString()));
|
||||
isInitOK = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_e131_cid = QUuid(_json_cid);
|
||||
Debug( _log, "e131 cid found, using %s", QSTRING_CSTR(_e131_cid.toString()));
|
||||
if ( !_e131_cid.isNull() )
|
||||
{
|
||||
Debug( _log, "e131 CID found, using %s", QSTRING_CSTR(_e131_cid.toString()));
|
||||
isInitOK = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setInError("CID configured is not a valid UUID. Format expected is \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpE131::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceUdpE131(deviceConfig);
|
||||
}
|
||||
|
||||
// populates the headers
|
||||
void LedDeviceUdpE131::prepare(const unsigned this_universe, const unsigned this_dmxChannelCount)
|
||||
{
|
||||
@@ -120,4 +149,3 @@ int LedDeviceUdpE131::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEUDPE131_H
|
||||
#define LEDEVICEUDPE131_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderUdp.h"
|
||||
@@ -18,32 +19,30 @@
|
||||
*
|
||||
**/
|
||||
|
||||
const ushort E131_DEFAULT_PORT = 5568;
|
||||
|
||||
/* E1.31 Packet Offsets */
|
||||
#define E131_ROOT_PREAMBLE_SIZE 0
|
||||
#define E131_ROOT_POSTAMBLE_SIZE 2
|
||||
#define E131_ROOT_ID 4
|
||||
#define E131_ROOT_FLENGTH 16
|
||||
#define E131_ROOT_VECTOR 18
|
||||
#define E131_ROOT_CID 22
|
||||
//#define E131_ROOT_PREAMBLE_SIZE 0
|
||||
//#define E131_ROOT_POSTAMBLE_SIZE 2
|
||||
//#define E131_ROOT_ID 4
|
||||
//#define E131_ROOT_FLENGTH 16
|
||||
//#define E131_ROOT_VECTOR 18
|
||||
//#define E131_ROOT_CID 22
|
||||
|
||||
#define E131_FRAME_FLENGTH 38
|
||||
#define E131_FRAME_VECTOR 40
|
||||
#define E131_FRAME_SOURCE 44
|
||||
#define E131_FRAME_PRIORITY 108
|
||||
#define E131_FRAME_RESERVED 109
|
||||
#define E131_FRAME_SEQ 111
|
||||
#define E131_FRAME_OPT 112
|
||||
#define E131_FRAME_UNIVERSE 113
|
||||
//#define E131_FRAME_FLENGTH 38
|
||||
//#define E131_FRAME_VECTOR 40
|
||||
//#define E131_FRAME_SOURCE 44
|
||||
//#define E131_FRAME_PRIORITY 108
|
||||
//#define E131_FRAME_RESERVED 109
|
||||
//#define E131_FRAME_SEQ 111
|
||||
//#define E131_FRAME_OPT 112
|
||||
//#define E131_FRAME_UNIVERSE 113
|
||||
|
||||
#define E131_DMP_FLENGTH 115
|
||||
#define E131_DMP_VECTOR 117
|
||||
#define E131_DMP_TYPE 118
|
||||
#define E131_DMP_ADDR_FIRST 119
|
||||
#define E131_DMP_ADDR_INC 121
|
||||
#define E131_DMP_COUNT 123
|
||||
#define E131_DMP_DATA 125
|
||||
//#define E131_DMP_FLENGTH 115
|
||||
//#define E131_DMP_VECTOR 117
|
||||
//#define E131_DMP_TYPE 118
|
||||
//#define E131_DMP_ADDR_FIRST 119
|
||||
//#define E131_DMP_ADDR_INC 121
|
||||
//#define E131_DMP_COUNT 123
|
||||
const unsigned int E131_DMP_DATA=125;
|
||||
|
||||
/* E1.31 Packet Structure */
|
||||
typedef union
|
||||
@@ -83,51 +82,49 @@ typedef union
|
||||
uint8_t raw[638];
|
||||
} e131_packet_t;
|
||||
|
||||
/* defined parameters from http://tsp.esta.org/tsp/documents/docs/BSR_E1-31-20xx_CP-2014-1009r2.pdf */
|
||||
#define VECTOR_ROOT_E131_DATA 0x00000004
|
||||
#define VECTOR_ROOT_E131_EXTENDED 0x00000008
|
||||
#define VECTOR_DMP_SET_PROPERTY 0x02
|
||||
#define VECTOR_E131_DATA_PACKET 0x00000002
|
||||
#define VECTOR_E131_EXTENDED_SYNCHRONIZATION 0x00000001
|
||||
#define VECTOR_E131_EXTENDED_DISCOVERY 0x00000002
|
||||
#define VECTOR_UNIVERSE_DISCOVERY_UNIVERSE_LIST 0x00000001
|
||||
#define E131_E131_UNIVERSE_DISCOVERY_INTERVAL 10 // seconds
|
||||
#define E131_NETWORK_DATA_LOSS_TIMEOUT 2500 // milli econds
|
||||
#define E131_DISCOVERY_UNIVERSE 64214
|
||||
#define DMX_MAX 512 // 512 usable slots
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending led colors via udp/E1.31 packets
|
||||
///
|
||||
class LedDeviceUdpE131 : public ProviderUdp
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs an E1.31 LED-device fed via UDP
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceUdpE131(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
///
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
///
|
||||
/// @brief Generate E1.31 communication header
|
||||
///
|
||||
void prepare(const unsigned this_universe, const unsigned this_dmxChannelCount);
|
||||
|
||||
e131_packet_t e131_packet;
|
||||
@@ -137,3 +134,5 @@ private:
|
||||
QString _e131_source_name;
|
||||
QUuid _e131_cid;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEUDPE131_H
|
||||
|
@@ -1,13 +1,20 @@
|
||||
#include "LedDeviceUdpH801.h"
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
const ushort H801_DEFAULT_PORT = 30977;
|
||||
static const char H801_DEFAULT_HOST[] = "255.255.255.255";
|
||||
const char H801_DEFAULT_HOST[] = "255.255.255.255";
|
||||
|
||||
} //End of constants
|
||||
|
||||
LedDeviceUdpH801::LedDeviceUdpH801(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpH801::construct(const QJsonObject &deviceConfig)
|
||||
@@ -17,13 +24,15 @@ LedDevice* LedDeviceUdpH801::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceUdpH801::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = false;
|
||||
|
||||
/* The H801 port is fixed */
|
||||
_latchTime_ms = 10;
|
||||
_port = H801_DEFAULT_PORT;
|
||||
_defaultHost = H801_DEFAULT_HOST;
|
||||
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
// Initialise sub-class
|
||||
if ( ProviderUdp::init(deviceConfig) )
|
||||
{
|
||||
_ids.clear();
|
||||
QJsonArray lArray = deviceConfig["lightIds"].toArray();
|
||||
@@ -44,6 +53,8 @@ bool LedDeviceUdpH801::init(const QJsonObject &deviceConfig)
|
||||
}
|
||||
|
||||
Debug(_log, "H801 using %s:%d", _address.toString().toStdString().c_str(), _port);
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
@@ -1,16 +1,50 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEUDPH801_H
|
||||
#define LEDEVICEUDPH801_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderUdp.h"
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending led colors via udp.
|
||||
/// Implementation of the LedDevice interface for sending LED colors to a H801 LED-device via UDP
|
||||
///
|
||||
///
|
||||
|
||||
class LedDeviceUdpH801: public ProviderUdp
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
|
||||
///
|
||||
/// @brief Constructs a H801 LED-device fed via UDP
|
||||
///
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceUdpH801(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
QList<int> _ids;
|
||||
QByteArray _message;
|
||||
const int _prefix_size = 2;
|
||||
@@ -18,29 +52,6 @@ protected:
|
||||
const int _id_size = 3;
|
||||
const int _suffix_size = 1;
|
||||
|
||||
public:
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
explicit LedDeviceUdpH801(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEUDPH801_H
|
||||
|
@@ -1,10 +1,14 @@
|
||||
#include "LedDeviceUdpRaw.h"
|
||||
|
||||
const ushort RAW_DEFAULT_PORT=5568;
|
||||
|
||||
LedDeviceUdpRaw::LedDeviceUdpRaw(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpRaw::construct(const QJsonObject &deviceConfig)
|
||||
@@ -15,6 +19,8 @@ LedDevice* LedDeviceUdpRaw::construct(const QJsonObject &deviceConfig)
|
||||
bool LedDeviceUdpRaw::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = RAW_DEFAULT_PORT;
|
||||
|
||||
// Initialise sub-class
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
return isInitOK;
|
||||
}
|
||||
@@ -23,5 +29,5 @@ int LedDeviceUdpRaw::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());
|
||||
|
||||
return writeBytes((unsigned)_ledRGBCount, dataPtr);
|
||||
return writeBytes(_ledRGBCount, dataPtr);
|
||||
}
|
||||
|
@@ -1,39 +1,48 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEUDPRAW_H
|
||||
#define LEDEVICEUDPRAW_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderUdp.h"
|
||||
|
||||
#define RAW_DEFAULT_PORT 5568
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending led colors via udp.
|
||||
/// Implementation of the LedDevice interface for sending LED colors via UDP
|
||||
///
|
||||
class LedDeviceUdpRaw : public ProviderUdp
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a LED-device fed via UDP
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceUdpRaw(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
protected:
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEUDPRAW_H
|
||||
|
291
libsrc/leddevice/dev_net/LedDeviceWled.cpp
Normal file
291
libsrc/leddevice/dev_net/LedDeviceWled.cpp
Normal file
@@ -0,0 +1,291 @@
|
||||
// Local-Hyperion includes
|
||||
#include "LedDeviceWled.h"
|
||||
|
||||
#include <ssdp/SSDPDiscover.h>
|
||||
#include <utils/QStringUtils.h>
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
// Configuration settings
|
||||
const char CONFIG_ADDRESS[] = "host";
|
||||
|
||||
// UDP elements
|
||||
const quint16 STREAM_DEFAULT_PORT = 19446;
|
||||
|
||||
// WLED JSON-API elements
|
||||
const int API_DEFAULT_PORT = -1; //Use default port per communication scheme
|
||||
|
||||
const char API_BASE_PATH[] = "/json/";
|
||||
const char API_PATH_INFO[] = "info";
|
||||
const char API_PATH_STATE[] = "state";
|
||||
|
||||
// List of State Information
|
||||
const char STATE_ON[] = "on";
|
||||
const char STATE_VALUE_TRUE[] = "true";
|
||||
const char STATE_VALUE_FALSE[] = "false";
|
||||
|
||||
// WLED ssdp services
|
||||
// TODO: WLED - Update ssdp discovery parameters when available
|
||||
const char SSDP_ID[] = "ssdp:all";
|
||||
const char SSDP_FILTER[] = "(.*)";
|
||||
const char SSDP_FILTER_HEADER[] = "ST";
|
||||
|
||||
} //End of constants
|
||||
|
||||
LedDeviceWled::LedDeviceWled(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
,_restApi(nullptr)
|
||||
,_apiPort(API_DEFAULT_PORT)
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDeviceWled::~LedDeviceWled()
|
||||
{
|
||||
if ( _restApi != nullptr )
|
||||
{
|
||||
delete _restApi;
|
||||
_restApi = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceWled::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceWled(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceWled::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
Debug(_log, "");
|
||||
bool isInitOK = false;
|
||||
|
||||
// Initialise LedDevice sub-class, ProviderUdp::init will be executed later, if connectivity is defined
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
// Initialise LedDevice configuration and execution environment
|
||||
uint configuredLedCount = this->getLedCount();
|
||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
||||
Debug(_log, "LedCount : %u", configuredLedCount);
|
||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
|
||||
//Set hostname as per configuration
|
||||
QString address = deviceConfig[ CONFIG_ADDRESS ].toString();
|
||||
|
||||
//If host not configured the init fails
|
||||
if ( address.isEmpty() )
|
||||
{
|
||||
this->setInError("No target hostname nor IP defined");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
QStringList addressparts = QStringUtils::split(address,":", QStringUtils::SplitBehavior::SkipEmptyParts);
|
||||
_hostname = addressparts[0];
|
||||
if ( addressparts.size() > 1 )
|
||||
{
|
||||
_apiPort = addressparts[1].toInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
_apiPort = API_DEFAULT_PORT;
|
||||
}
|
||||
|
||||
if ( initRestAPI( _hostname, _apiPort ) )
|
||||
{
|
||||
// Update configuration with hostname without port
|
||||
_devConfig["host"] = _hostname;
|
||||
_devConfig["port"] = STREAM_DEFAULT_PORT;
|
||||
|
||||
isInitOK = ProviderUdp::init(_devConfig);
|
||||
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR( _hostname ));
|
||||
Debug(_log, "Port : %d", _port);
|
||||
}
|
||||
}
|
||||
}
|
||||
Debug(_log, "[%d]", isInitOK);
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceWled::initRestAPI(const QString &hostname, const int port )
|
||||
{
|
||||
Debug(_log, "");
|
||||
bool isInitOK = false;
|
||||
|
||||
if ( _restApi == nullptr )
|
||||
{
|
||||
_restApi = new ProviderRestApi(hostname, port);
|
||||
_restApi->setBasePath( API_BASE_PATH );
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
|
||||
Debug(_log, "[%d]", isInitOK);
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
QString LedDeviceWled::getOnOffRequest (bool isOn ) const
|
||||
{
|
||||
QString state = isOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
|
||||
return QString( "{\"%1\":%2}" ).arg( STATE_ON, state);
|
||||
}
|
||||
|
||||
bool LedDeviceWled::powerOn()
|
||||
{
|
||||
Debug(_log, "");
|
||||
bool on = true;
|
||||
if ( _isDeviceReady)
|
||||
{
|
||||
//Power-on WLED device
|
||||
_restApi->setPath(API_PATH_STATE);
|
||||
httpResponse response = _restApi->put(getOnOffRequest(true));
|
||||
if ( response.error() )
|
||||
{
|
||||
this->setInError ( response.getErrorReason() );
|
||||
on = false;
|
||||
}
|
||||
}
|
||||
return on;
|
||||
}
|
||||
|
||||
bool LedDeviceWled::powerOff()
|
||||
{
|
||||
Debug(_log, "");
|
||||
bool off = true;
|
||||
if ( _isDeviceReady)
|
||||
{
|
||||
// Write a final "Black" to have a defined outcome
|
||||
writeBlack();
|
||||
|
||||
//Power-off the WLED device physically
|
||||
_restApi->setPath(API_PATH_STATE);
|
||||
httpResponse response = _restApi->put(getOnOffRequest(false));
|
||||
if ( response.error() )
|
||||
{
|
||||
this->setInError ( response.getErrorReason() );
|
||||
off = false;
|
||||
}
|
||||
}
|
||||
return off;
|
||||
}
|
||||
|
||||
QJsonObject LedDeviceWled::discover()
|
||||
{
|
||||
QJsonObject devicesDiscovered;
|
||||
devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
|
||||
|
||||
QJsonArray deviceList;
|
||||
|
||||
// Discover WLED Devices
|
||||
SSDPDiscover discover;
|
||||
discover.skipDuplicateKeys(true);
|
||||
discover.setSearchFilter(SSDP_FILTER, SSDP_FILTER_HEADER);
|
||||
QString searchTarget = SSDP_ID;
|
||||
|
||||
if ( discover.discoverServices(searchTarget) > 0 )
|
||||
{
|
||||
deviceList = discover.getServicesDiscoveredJson();
|
||||
}
|
||||
|
||||
devicesDiscovered.insert("devices", deviceList);
|
||||
Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
return devicesDiscovered;
|
||||
}
|
||||
|
||||
QJsonObject LedDeviceWled::getProperties(const QJsonObject& params)
|
||||
{
|
||||
Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
QJsonObject properties;
|
||||
|
||||
// Get Nanoleaf device properties
|
||||
QString host = params["host"].toString("");
|
||||
if ( !host.isEmpty() )
|
||||
{
|
||||
QString filter = params["filter"].toString("");
|
||||
|
||||
// Resolve hostname and port (or use default API port)
|
||||
QStringList addressparts = QStringUtils::split(host,":", QStringUtils::SplitBehavior::SkipEmptyParts);
|
||||
QString apiHost = addressparts[0];
|
||||
int apiPort;
|
||||
|
||||
if ( addressparts.size() > 1)
|
||||
{
|
||||
apiPort = addressparts[1].toInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
apiPort = API_DEFAULT_PORT;
|
||||
}
|
||||
|
||||
if ( filter.startsWith("/") )
|
||||
filter.remove(0,1);
|
||||
|
||||
initRestAPI(apiHost, apiPort);
|
||||
_restApi->setPath(API_PATH_INFO);
|
||||
|
||||
// Perform request
|
||||
// TODO: WLED::getProperties - Check, if filter is supported
|
||||
httpResponse response = _restApi->put(filter);
|
||||
if ( response.error() )
|
||||
{
|
||||
Warning (_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||
}
|
||||
|
||||
properties.insert("properties", response.getBody().object());
|
||||
|
||||
Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
void LedDeviceWled::identify(const QJsonObject& params)
|
||||
{
|
||||
Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
QJsonObject properties;
|
||||
|
||||
// Get Nanoleaf device properties
|
||||
QString host = params["host"].toString("");
|
||||
if ( !host.isEmpty() )
|
||||
{
|
||||
// Resolve hostname and port (or use default API port)
|
||||
QStringList addressparts = QStringUtils::split(host,":", QStringUtils::SplitBehavior::SkipEmptyParts);
|
||||
QString apiHost = addressparts[0];
|
||||
int apiPort;
|
||||
|
||||
if ( addressparts.size() > 1)
|
||||
apiPort = addressparts[1].toInt();
|
||||
else
|
||||
apiPort = API_DEFAULT_PORT;
|
||||
|
||||
// TODO: WLED::identify - Replace with valid identification code
|
||||
|
||||
// initRestAPI(apiHost, apiPort);
|
||||
|
||||
// QString resource = QString("%1/%2/%3").arg( API_LIGHTS ).arg( lightId ).arg( API_STATE);
|
||||
// _restApi->setPath(resource);
|
||||
|
||||
// QString stateCmd;
|
||||
// stateCmd += QString("\"%1\":%2,").arg( API_STATE_ON ).arg( API_STATE_VALUE_TRUE );
|
||||
// stateCmd += QString("\"%1\":\"%2\"").arg( "alert" ).arg( "select" );
|
||||
// stateCmd = "{" + stateCmd + "}";
|
||||
|
||||
// // Perform request
|
||||
// httpResponse response = _restApi->put(stateCmd);
|
||||
// if ( response.error() )
|
||||
// {
|
||||
// Warning (_log, "%s identification failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
int LedDeviceWled::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());
|
||||
|
||||
return writeBytes( _ledRGBCount, dataPtr);
|
||||
}
|
132
libsrc/leddevice/dev_net/LedDeviceWled.h
Normal file
132
libsrc/leddevice/dev_net/LedDeviceWled.h
Normal file
@@ -0,0 +1,132 @@
|
||||
#ifndef LEDDEVICEWLED_H
|
||||
#define LEDDEVICEWLED_H
|
||||
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
#include "ProviderRestApi.h"
|
||||
#include "ProviderUdp.h"
|
||||
|
||||
///
|
||||
/// Implementation of a WLED-device
|
||||
/// ...
|
||||
///
|
||||
///
|
||||
class LedDeviceWled : public ProviderUdp
|
||||
{
|
||||
|
||||
public:
|
||||
///
|
||||
/// @brief Constructs a WLED-device
|
||||
///
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceWled(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// @brief Destructor of the WLED-device
|
||||
///
|
||||
virtual ~LedDeviceWled() override;
|
||||
|
||||
///
|
||||
/// @brief Constructs the WLED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// @brief Discover WLED devices available (for configuration).
|
||||
///
|
||||
/// @return A JSON structure holding a list of devices found
|
||||
///
|
||||
virtual QJsonObject discover() override;
|
||||
|
||||
///
|
||||
/// @brief Get the WLED device's resource properties
|
||||
///
|
||||
/// Following parameters are required
|
||||
/// @code
|
||||
/// {
|
||||
/// "host" : "hostname or IP [:port]",
|
||||
/// "filter": "resource to query", root "/" is used, if empty
|
||||
/// }
|
||||
///@endcode
|
||||
///
|
||||
/// @param[in] params Parameters to query device
|
||||
/// @return A JSON structure holding the device's properties
|
||||
///
|
||||
virtual QJsonObject getProperties(const QJsonObject& params) override;
|
||||
|
||||
///
|
||||
/// @brief Send an update to the WLED device to identify it.
|
||||
///
|
||||
/// Following parameters are required
|
||||
/// @code
|
||||
/// {
|
||||
/// "host" : "hostname or IP [:port]",
|
||||
/// }
|
||||
///@endcode
|
||||
///
|
||||
/// @param[in] params Parameters to address device
|
||||
///
|
||||
virtual void identify(const QJsonObject& params) override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// @brief Initialise the WLED device's configuration and network address details
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
///
|
||||
/// @brief Power-/turn on the WLED device.
|
||||
///
|
||||
/// @brief Store the device's original state.
|
||||
///
|
||||
virtual bool powerOn() override;
|
||||
|
||||
///
|
||||
/// @brief Power-/turn off the WLED device.
|
||||
///
|
||||
/// @return True if success
|
||||
///
|
||||
virtual bool powerOff() override;
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// @brief Initialise the access to the REST-API wrapper
|
||||
///
|
||||
/// @param[in] host
|
||||
/// @param[in] port
|
||||
/// @return True, if success
|
||||
///
|
||||
bool initRestAPI(const QString &hostname, const int port );
|
||||
|
||||
///
|
||||
/// @brief Get command to power WLED-device on or off
|
||||
///
|
||||
/// @param isOn True, if to switch on device
|
||||
/// @return Command to switch device on/off
|
||||
///
|
||||
QString getOnOffRequest (bool isOn ) const;
|
||||
|
||||
///REST-API wrapper
|
||||
ProviderRestApi* _restApi;
|
||||
|
||||
QString _hostname;
|
||||
int _apiPort;
|
||||
};
|
||||
|
||||
#endif // LEDDEVICEWLED_H
|
1502
libsrc/leddevice/dev_net/LedDeviceYeelight.cpp
Normal file
1502
libsrc/leddevice/dev_net/LedDeviceYeelight.cpp
Normal file
File diff suppressed because it is too large
Load Diff
627
libsrc/leddevice/dev_net/LedDeviceYeelight.h
Normal file
627
libsrc/leddevice/dev_net/LedDeviceYeelight.h
Normal file
@@ -0,0 +1,627 @@
|
||||
#ifndef LEDEVICEYEELIGHT_H
|
||||
#define LEDEVICEYEELIGHT_H
|
||||
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
|
||||
// Qt includes
|
||||
#include <QTcpSocket>
|
||||
#include <QHostAddress>
|
||||
#include <QTcpServer>
|
||||
#include <QColor>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
// List of State Information
|
||||
const char API_METHOD_POWER[] = "set_power";
|
||||
const char API_METHOD_POWER_ON[] = "on";
|
||||
const char API_METHOD_POWER_OFF[] = "off";
|
||||
|
||||
const char API_METHOD_MUSIC_MODE[] = "set_music";
|
||||
const int API_METHOD_MUSIC_MODE_ON = 1;
|
||||
const int API_METHOD_MUSIC_MODE_OFF = 0;
|
||||
|
||||
const char API_METHOD_SETRGB[] = "set_rgb";
|
||||
const char API_METHOD_SETSCENE[] = "set_scene";
|
||||
const char API_METHOD_GETPROP[] = "get_prop";
|
||||
|
||||
const char API_PARAM_EFFECT_SUDDEN[] = "sudden";
|
||||
const char API_PARAM_EFFECT_SMOOTH[] = "smooth";
|
||||
|
||||
constexpr std::chrono::milliseconds API_PARAM_DURATION{50};
|
||||
constexpr std::chrono::milliseconds API_PARAM_DURATION_POWERONOFF{1000};
|
||||
constexpr std::chrono::milliseconds API_PARAM_EXTRA_TIME_DARKNESS{200};
|
||||
|
||||
} //End of constants
|
||||
///
|
||||
/// Response object for Yeelight-API calls and JSON-responses
|
||||
///
|
||||
class YeelightResponse
|
||||
{
|
||||
public:
|
||||
|
||||
enum API_REPLY{
|
||||
API_OK,
|
||||
API_ERROR,
|
||||
API_NOTIFICATION,
|
||||
};
|
||||
|
||||
explicit YeelightResponse() {}
|
||||
|
||||
API_REPLY error() { return _error;}
|
||||
void setError(const YeelightResponse::API_REPLY replyType) { _error = replyType; }
|
||||
|
||||
QJsonArray getResult() const { return _resultArray; }
|
||||
void setResult(const QJsonArray &result) { _resultArray = result; }
|
||||
|
||||
int getErrorCode() const { return _errorCode; }
|
||||
void setErrorCode(const int &errorCode) { _errorCode = errorCode; _error = API_ERROR;}
|
||||
|
||||
QString getErrorReason() const { return _errorReason; }
|
||||
void setErrorReason(const QString &errorReason) { _errorReason = errorReason; }
|
||||
|
||||
private:
|
||||
|
||||
QJsonArray _resultArray;
|
||||
API_REPLY _error = API_OK;
|
||||
|
||||
int _errorCode = 0;
|
||||
QString _errorReason;
|
||||
};
|
||||
|
||||
///
|
||||
/// Implementation of one Yeelight light.
|
||||
///
|
||||
class YeelightLight
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
enum API_EFFECT{
|
||||
API_EFFECT_SMOOTH,
|
||||
API_EFFECT_SUDDEN
|
||||
};
|
||||
|
||||
enum API_MODE{
|
||||
API_TURN_ON_MODE,
|
||||
API_CT_MODE,
|
||||
API_RGB_MODE,
|
||||
API_HSV_MODE,
|
||||
API_COLOR_FLOW_MODE,
|
||||
API_NIGHT_LIGHT_MODE
|
||||
};
|
||||
|
||||
/// @brief Constructs one Yeelight light
|
||||
///
|
||||
/// @param[in] log Logger instance
|
||||
/// @param[in] hostname or IP-address
|
||||
/// @param[in] port, default port 55443 is used when not provided
|
||||
///
|
||||
YeelightLight( Logger *log, const QString &hostname, quint16 port);
|
||||
|
||||
///
|
||||
/// @brief Destructor of the Yeelight light
|
||||
///
|
||||
virtual ~YeelightLight();
|
||||
|
||||
///
|
||||
/// @brief Set the Yeelight light connectivity parameters
|
||||
///
|
||||
/// @param[in] hostname or IP-address
|
||||
/// @param[in] port, default port 55443 is used when not provided
|
||||
///
|
||||
void setHostname( const QString &hostname, quint16 port);
|
||||
|
||||
///
|
||||
/// @brief Set the Yeelight light name
|
||||
///
|
||||
/// @param[in] name
|
||||
///
|
||||
void setName( const QString& name ) { _name = name; }
|
||||
|
||||
///
|
||||
/// @brief Get the Yeelight light name
|
||||
///
|
||||
/// @return The Yeelight light name
|
||||
///
|
||||
QString getName() const { return _name; }
|
||||
|
||||
///
|
||||
/// @brief Opens the Yeelight light connectivity
|
||||
///
|
||||
/// @return True, on success (i.e. device is open)
|
||||
///
|
||||
bool open();
|
||||
|
||||
///
|
||||
/// @brief Closes the Yeelight light connectivity
|
||||
///
|
||||
/// @return True, on success (i.e. device is closed)
|
||||
///
|
||||
bool close();
|
||||
|
||||
///
|
||||
/// @brief Send a command to light up Yeelight light to allow identification
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
bool identify();
|
||||
|
||||
///
|
||||
/// @brief Execute a Yeelight-API command
|
||||
///
|
||||
/// @param[in] command The API command request in JSON
|
||||
/// @return 0: success, -1: error, -2: command quota exceeded
|
||||
///
|
||||
int writeCommand( const QJsonDocument &command );
|
||||
|
||||
///
|
||||
/// @brief Execute a Yeelight-API command
|
||||
///
|
||||
/// @param[in] command The API command request in JSON
|
||||
/// @param[out] result The response to the command in JSON
|
||||
/// @return 0: success, -1: error, -2: command quota exceeded
|
||||
///
|
||||
int writeCommand( const QJsonDocument &command, QJsonArray &result );
|
||||
|
||||
///
|
||||
/// @brief Stream a Yeelight-API command
|
||||
///
|
||||
/// Yeelight must be in music mode, i.e. Streaming socket is established
|
||||
///
|
||||
/// @param[in] command The API command request in JSON
|
||||
/// @return True, on success
|
||||
///
|
||||
bool streamCommand( const QJsonDocument &command );
|
||||
|
||||
///
|
||||
/// @brief Set the Yeelight light streaming socket
|
||||
///
|
||||
/// @param[in] socket
|
||||
///
|
||||
void setStreamSocket( QTcpSocket* socket );
|
||||
|
||||
///
|
||||
/// @brief Power on/off on the Yeelight light
|
||||
///
|
||||
/// @param[in] on True: power on, False: power off
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
bool setPower( bool on );
|
||||
|
||||
///
|
||||
/// @brief Power on/off on the Yeelight light
|
||||
///
|
||||
/// @param[in] on True: power on, False: power off
|
||||
/// @param[in] effect Transition effect, sudden or smooth
|
||||
/// @param[in] duration Duration of the transition, if smooth
|
||||
/// @param[in] mode Color mode after powering on
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
bool setPower( bool on, API_EFFECT effect, int duration, API_MODE mode = API_RGB_MODE );
|
||||
|
||||
///
|
||||
/// @brief Set the Yeelight light to the given color (using RGB mode)
|
||||
///
|
||||
/// @param[in] color as RGB value
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
bool setColorRGB( const ColorRgb &color );
|
||||
|
||||
///
|
||||
/// @brief Set the Yeelight light to the given color (using HSV mode)
|
||||
///
|
||||
/// @param[in] color as RGB value
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
bool setColorHSV( const ColorRgb &color );
|
||||
|
||||
///
|
||||
/// @brief Set the Yeelight light effect and duration while transiting between color updates
|
||||
///
|
||||
/// @param[in] effect Transition effect, sudden or smooth
|
||||
/// @param[in] duration Duration of the transition, if smooth
|
||||
///
|
||||
void setTransitionEffect ( API_EFFECT effect ,int duration = API_PARAM_DURATION.count() );
|
||||
|
||||
///
|
||||
/// @brief Set the Yeelight light brightness configuration behaviour
|
||||
///
|
||||
/// @param[in] min Minimum Brightness (in %). Every value lower than minimum will be set to minimum.
|
||||
/// @param[in] max Maximum Brightness (in %). Every value greater than maximum will be set to maximum.
|
||||
/// @param[in] switchoff True, power-off light, if brightness is lower then minimum
|
||||
/// @param[in] extraTime Additional time (in ms), which added to transition duration while powering-off
|
||||
/// @param[in] factor Brightness factor to multiply on color change.
|
||||
///
|
||||
void setBrightnessConfig (int min = 1, int max = 100, bool switchoff = false, int extraTime = 0, double factor = 1);
|
||||
|
||||
///
|
||||
/// @brief Set the Yeelight light into music-mode
|
||||
///
|
||||
/// @param[in] on True: music-mode on, False: music-mode off
|
||||
/// @param[in] hostAddress of the music-mode server
|
||||
/// @param[in] port of the music-mode server
|
||||
///
|
||||
bool setMusicMode( bool on, const QHostAddress &hostAddress = {} , int port = -1 );
|
||||
|
||||
///
|
||||
/// @brief Set the wait-time between two Yeelight light commands
|
||||
///
|
||||
/// The write of a command is delayed by the given wait-time, if the last write happen in the wait-time time frame.
|
||||
/// Used to avoid that the Yeelight light runs into the quota exceed error scenario.
|
||||
/// A Yeelight light can do 60 commands/min ( -> wait-time = 1000ms).
|
||||
///
|
||||
/// @param[in] waitTime in milliseconds
|
||||
///
|
||||
void setQuotaWaitTime( int waitTime ) { _waitTimeQuota = waitTime; }
|
||||
|
||||
///
|
||||
/// @brief Get the Yeelight light properties
|
||||
///
|
||||
/// @return properties as JSON-object
|
||||
///
|
||||
QJsonObject getProperties();
|
||||
|
||||
///
|
||||
/// @brief Get the Yeelight light properties and store them along the Yeelight light for later access
|
||||
///
|
||||
void storeState();
|
||||
|
||||
///
|
||||
/// @brief Restore the Yeelight light's original state.
|
||||
///
|
||||
/// Restore the device's state as before hyperion color streaming started.
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool restoreState();
|
||||
|
||||
///
|
||||
/// @brief Check, if light was originally powered on before hyperion color streaming started..
|
||||
///
|
||||
/// @return True, if light was on at start
|
||||
///
|
||||
bool wasOriginallyOn() const { return _power == API_METHOD_POWER_ON ? true : false; }
|
||||
|
||||
///
|
||||
/// @brief Check, if the Yeelight light is ready for updates
|
||||
///
|
||||
/// @return True, if ready
|
||||
///
|
||||
bool isReady() const { return !_isInError; }
|
||||
|
||||
///
|
||||
/// @brief Check, if the Yeelight light is powered on
|
||||
///
|
||||
/// @return True, if powered on
|
||||
///
|
||||
bool isOn() const { return _isOn; }
|
||||
|
||||
///
|
||||
/// @brief Check, if the Yeelight light is in music-mode
|
||||
///
|
||||
/// @return True, if in music mode
|
||||
///
|
||||
bool isInMusicMode( bool deviceCheck = false );
|
||||
|
||||
///
|
||||
/// @brief Set the Yeelight light in error state
|
||||
///
|
||||
/// @param[in] errorMsg The error message to be logged
|
||||
///
|
||||
void setInError( const QString& errorMsg );
|
||||
|
||||
///
|
||||
/// @brief Set the Yeelight light debug-level
|
||||
///
|
||||
/// @param[in] level Debug level (0: no debug output, 1-3: verbosity level)
|
||||
///
|
||||
void setDebuglevel ( int level ) { _debugLevel = level; }
|
||||
|
||||
private:
|
||||
|
||||
YeelightResponse handleResponse(int correlationID, QByteArray const &response );
|
||||
|
||||
///
|
||||
/// @brief Build Yeelight-API command
|
||||
///
|
||||
/// @param[in] method Control method to be invoked
|
||||
/// @param[in] params Parameters for control method
|
||||
/// @return Yeelight-API command in JSON format
|
||||
///
|
||||
QJsonDocument getCommand(const QString &method, const QJsonArray ¶ms);
|
||||
|
||||
///
|
||||
/// @brief Map Yeelight light properties into the Yeelight light members for direct access
|
||||
///
|
||||
/// @param[in] properties Yeelight light's properties as JSON-Object
|
||||
///
|
||||
void mapProperties(const QJsonObject &properties);
|
||||
|
||||
///
|
||||
/// @brief Write a Yeelight light specific log-line for debugging purposed
|
||||
///
|
||||
/// @param[in] logLevel Debug level (0: no debug output, 1-3: verbosity level)
|
||||
/// @param[in] msg Log message prefix (max 20 characters)
|
||||
/// @param[in] type log message text
|
||||
/// @param[in] ... variable input to log message text
|
||||
/// ///
|
||||
void log(const int logLevel,const char* msg, const char* type, ...);
|
||||
|
||||
Logger* _log;
|
||||
int _debugLevel;
|
||||
|
||||
/// Error status of Yeelight light
|
||||
bool _isInError;
|
||||
|
||||
/// IP address/port of the Yeelight light
|
||||
QString _host;
|
||||
quint16 _port;
|
||||
|
||||
/// Yeelight light communication socket
|
||||
QTcpSocket* _tcpSocket;
|
||||
/// Music mode server communication socket
|
||||
QTcpSocket* _tcpStreamSocket;
|
||||
|
||||
/// ID of last command written or streamed
|
||||
int _correlationID;
|
||||
/// Timestamp of last write
|
||||
qint64 _lastWriteTime;
|
||||
|
||||
/// Last color written to Yeelight light (RGB represented as QColor)
|
||||
QColor _color;
|
||||
/// Last color written to Yeelight light (RGB represented as int)
|
||||
int _lastColorRgbValue;
|
||||
|
||||
/// Yeelight light behavioural parameters
|
||||
API_EFFECT _transitionEffect;
|
||||
int _transitionDuration;
|
||||
int _extraTimeDarkness;
|
||||
|
||||
int _brightnessMin;
|
||||
bool _isBrightnessSwitchOffMinimum;
|
||||
int _brightnessMax;
|
||||
double _brightnessFactor;
|
||||
|
||||
QString _transitionEffectParam;
|
||||
|
||||
/// Wait time to avoid quota exceed scenario
|
||||
int _waitTimeQuota;
|
||||
|
||||
/// Yeelight light properties
|
||||
QJsonObject _originalStateProperties;
|
||||
QString _name;
|
||||
QString _model;
|
||||
QString _power;
|
||||
QString _fw_ver;
|
||||
int _colorRgbValue;
|
||||
int _bright;
|
||||
int _ct;
|
||||
|
||||
/// Yeelight light status
|
||||
bool _isOn;
|
||||
bool _isInMusicMode;
|
||||
};
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending to
|
||||
/// Yeelight devices via network
|
||||
///
|
||||
class LedDeviceYeelight : public LedDevice
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// @brief Constructs a Yeelight LED-device serving multiple lights
|
||||
///
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceYeelight(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// @brief Destructor of the LedDevice
|
||||
///
|
||||
virtual ~LedDeviceYeelight() override;
|
||||
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// @brief Discover Yeelight devices available (for configuration).
|
||||
///
|
||||
/// @return A JSON structure holding a list of devices found
|
||||
///
|
||||
virtual QJsonObject discover() override;
|
||||
|
||||
///
|
||||
/// @brief Get a Yeelight device's resource properties
|
||||
///
|
||||
/// Following parameters are required
|
||||
/// @code
|
||||
/// {
|
||||
/// "hostname" : "hostname or IP",
|
||||
/// "port" : port, default port 55443 is used when not provided
|
||||
/// }
|
||||
///@endcode
|
||||
///
|
||||
/// @param[in] params Parameters to query device
|
||||
/// @return A JSON structure holding the device's properties
|
||||
///
|
||||
virtual QJsonObject getProperties(const QJsonObject& params) override;
|
||||
|
||||
///
|
||||
/// @brief Send an update to the Yeelight device to identify it.
|
||||
///
|
||||
/// Following parameters are required
|
||||
/// @code
|
||||
/// {
|
||||
/// "hostname" : "hostname or IP",
|
||||
/// "port" : port, default port 55443 is used when not provided
|
||||
/// }
|
||||
///@endcode
|
||||
///
|
||||
/// @param[in] params Parameters to address device
|
||||
///
|
||||
virtual void identify(const QJsonObject& params) override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
///
|
||||
/// @brief Closes the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
///
|
||||
/// @brief Power-/turn on the Nanoleaf device.
|
||||
///
|
||||
/// @brief Store the device's original state.
|
||||
///
|
||||
virtual bool powerOn() override;
|
||||
|
||||
///
|
||||
/// @brief Power-/turn off the Nanoleaf device.
|
||||
///
|
||||
/// @return True if success
|
||||
///
|
||||
virtual bool powerOff() override;
|
||||
|
||||
///
|
||||
/// @brief Store the device's original state.
|
||||
///
|
||||
/// Save the device's state before hyperion color streaming starts allowing to restore state during switchOff().
|
||||
///
|
||||
/// @return True if success
|
||||
///
|
||||
virtual bool storeState() override;
|
||||
|
||||
///
|
||||
/// @brief Restore the device's original state.
|
||||
///
|
||||
/// Restore the device's state as before hyperion color streaming started.
|
||||
/// This includes the on/off state of the device.
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool restoreState() override;
|
||||
|
||||
private:
|
||||
|
||||
struct yeelightAddress {
|
||||
QString host;
|
||||
int port;
|
||||
|
||||
bool operator == (yeelightAddress const& a) const
|
||||
{
|
||||
return ((host == a.host) && (port == a.port));
|
||||
}
|
||||
};
|
||||
|
||||
enum COLOR_MODEL{
|
||||
MODEL_HSV,
|
||||
MODEL_RGB
|
||||
};
|
||||
|
||||
///
|
||||
/// @brief Start music-mode server
|
||||
///
|
||||
/// @return True, if music mode server is running
|
||||
///
|
||||
bool startMusicModeServer();
|
||||
|
||||
///
|
||||
/// @brief Stop music-mode server
|
||||
///
|
||||
/// @return True, if music mode server has been stopped
|
||||
///
|
||||
bool stopMusicModeServer();
|
||||
|
||||
///
|
||||
/// @brief Update list of Yeelight lights handled by the LED-device
|
||||
///
|
||||
/// @param[in] list List of Yeelight lights
|
||||
///
|
||||
/// @return False, if no lights were provided
|
||||
///
|
||||
bool updateLights(const QVector<yeelightAddress> &list);
|
||||
|
||||
///
|
||||
/// @brief Set the number of Yeelight lights handled by the LED-device
|
||||
///
|
||||
/// @param[in] lightsCount Number of Yeelight lights
|
||||
///
|
||||
void setLightsCount( unsigned int lightsCount ) { _lightsCount = lightsCount; }
|
||||
|
||||
///
|
||||
/// @brief Get the number of Yeelight lights handled by the LED-device
|
||||
///
|
||||
/// @return Number of Yeelight lights
|
||||
///
|
||||
uint getLightsCount() const { return _lightsCount; }
|
||||
|
||||
/// Array of the Yeelight addresses handled by the LED-device
|
||||
QVector<yeelightAddress> _lightsAddressList;
|
||||
|
||||
/// Array to save the lights
|
||||
std::vector<YeelightLight> _lights;
|
||||
unsigned int _lightsCount;
|
||||
|
||||
/// Yeelight configuration/behavioural parameters
|
||||
int _outputColorModel;
|
||||
YeelightLight::API_EFFECT _transitionEffect;
|
||||
int _transitionDuration;
|
||||
int _extraTimeDarkness;
|
||||
|
||||
int _brightnessMin;
|
||||
bool _isBrightnessSwitchOffMinimum;
|
||||
int _brightnessMax;
|
||||
double _brightnessFactor;
|
||||
|
||||
int _waitTimeQuota;
|
||||
|
||||
int _debuglevel;
|
||||
|
||||
///Music mode Server details
|
||||
QHostAddress _musicModeServerAddress;
|
||||
int _musicModeServerPort;
|
||||
QTcpServer* _tcpMusicModeServer = nullptr;
|
||||
|
||||
};
|
||||
|
||||
#endif // LEDEVICEYEELIGHT_H
|
247
libsrc/leddevice/dev_net/ProviderRestApi.cpp
Normal file
247
libsrc/leddevice/dev_net/ProviderRestApi.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
// Local-Hyperion includes
|
||||
#include "ProviderRestApi.h"
|
||||
|
||||
// Qt includes
|
||||
#include <QEventLoop>
|
||||
#include <QNetworkReply>
|
||||
#include <QByteArray>
|
||||
|
||||
//std includes
|
||||
#include <iostream>
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
const QChar ONE_SLASH = '/';
|
||||
|
||||
} //End of constants
|
||||
|
||||
ProviderRestApi::ProviderRestApi(const QString &host, const int &port, const QString &basePath)
|
||||
:_log(Logger::getInstance("LEDDEVICE"))
|
||||
,_networkManager(nullptr)
|
||||
,_scheme("http")
|
||||
,_hostname(host)
|
||||
,_port(port)
|
||||
{
|
||||
_networkManager = new QNetworkAccessManager();
|
||||
|
||||
_apiUrl.setScheme(_scheme);
|
||||
_apiUrl.setHost(host);
|
||||
_apiUrl.setPort(port);
|
||||
_basePath = basePath;
|
||||
}
|
||||
|
||||
ProviderRestApi::ProviderRestApi(const QString &host, const int &port)
|
||||
: ProviderRestApi(host, port, "") {}
|
||||
|
||||
ProviderRestApi::ProviderRestApi()
|
||||
: ProviderRestApi("", -1) {}
|
||||
|
||||
ProviderRestApi::~ProviderRestApi()
|
||||
{
|
||||
if ( _networkManager != nullptr )
|
||||
{
|
||||
delete _networkManager;
|
||||
}
|
||||
}
|
||||
|
||||
void ProviderRestApi::setBasePath(const QString &basePath)
|
||||
{
|
||||
_basePath.clear();
|
||||
appendPath (_basePath, basePath );
|
||||
}
|
||||
|
||||
void ProviderRestApi::setPath ( const QString &path )
|
||||
{
|
||||
_path.clear();
|
||||
appendPath (_path, path );
|
||||
}
|
||||
|
||||
void ProviderRestApi::appendPath ( const QString &path )
|
||||
{
|
||||
appendPath (_path, path );
|
||||
}
|
||||
|
||||
void ProviderRestApi::appendPath ( QString& path, const QString &appendPath) const
|
||||
{
|
||||
if ( !appendPath.isEmpty() && appendPath != ONE_SLASH )
|
||||
{
|
||||
if (path.isEmpty() || path == ONE_SLASH )
|
||||
{
|
||||
path.clear();
|
||||
if (appendPath[0] != ONE_SLASH )
|
||||
{
|
||||
path.push_back(ONE_SLASH);
|
||||
}
|
||||
}
|
||||
else if (path[path.size()-1] == ONE_SLASH && appendPath[0] == ONE_SLASH)
|
||||
{
|
||||
path.chop(1);
|
||||
}
|
||||
else if (path[path.size()-1] != ONE_SLASH && appendPath[0] != ONE_SLASH)
|
||||
{
|
||||
path.push_back(ONE_SLASH);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only one slash.
|
||||
}
|
||||
|
||||
path.append(appendPath);
|
||||
}
|
||||
}
|
||||
|
||||
void ProviderRestApi::setFragment(const QString &fragment)
|
||||
{
|
||||
_fragment = fragment;
|
||||
}
|
||||
|
||||
void ProviderRestApi::setQuery(const QUrlQuery &query)
|
||||
{
|
||||
_query = query;
|
||||
}
|
||||
|
||||
QUrl ProviderRestApi::getUrl() const
|
||||
{
|
||||
QUrl url = _apiUrl;
|
||||
|
||||
QString fullPath = _basePath;
|
||||
appendPath (fullPath, _path );
|
||||
|
||||
url.setPath(fullPath);
|
||||
url.setFragment( _fragment );
|
||||
url.setQuery( _query );
|
||||
return url;
|
||||
}
|
||||
|
||||
httpResponse ProviderRestApi::get()
|
||||
{
|
||||
return get( getUrl() );
|
||||
}
|
||||
|
||||
httpResponse ProviderRestApi::get(const QUrl &url)
|
||||
{
|
||||
Debug(_log, "GET: [%s]", QSTRING_CSTR( url.toString() ));
|
||||
|
||||
// Perform request
|
||||
QNetworkRequest request(url);
|
||||
QNetworkReply* reply = _networkManager->get(request);
|
||||
// Connect requestFinished signal to quit slot of the loop.
|
||||
QEventLoop loop;
|
||||
loop.connect(reply, SIGNAL(finished()), SLOT(quit()));
|
||||
// Go into the loop until the request is finished.
|
||||
loop.exec();
|
||||
|
||||
httpResponse response;
|
||||
if(reply->operation() == QNetworkAccessManager::GetOperation)
|
||||
{
|
||||
response = getResponse(reply );
|
||||
}
|
||||
// Free space.
|
||||
reply->deleteLater();
|
||||
// Return response
|
||||
return response;
|
||||
}
|
||||
|
||||
httpResponse ProviderRestApi::put(const QString &body)
|
||||
{
|
||||
return put( getUrl(), body );
|
||||
}
|
||||
|
||||
httpResponse ProviderRestApi::put(const QUrl &url, const QString &body)
|
||||
{
|
||||
Debug(_log, "PUT: [%s] [%s]", QSTRING_CSTR( url.toString() ), QSTRING_CSTR( body ) );
|
||||
// Perform request
|
||||
QNetworkRequest request(url);
|
||||
QNetworkReply* reply = _networkManager->put(request, body.toUtf8());
|
||||
// Connect requestFinished signal to quit slot of the loop.
|
||||
QEventLoop loop;
|
||||
loop.connect(reply, SIGNAL(finished()), SLOT(quit()));
|
||||
// Go into the loop until the request is finished.
|
||||
loop.exec();
|
||||
|
||||
httpResponse response;
|
||||
if(reply->operation() == QNetworkAccessManager::PutOperation)
|
||||
{
|
||||
response = getResponse(reply);
|
||||
}
|
||||
// Free space.
|
||||
reply->deleteLater();
|
||||
|
||||
// Return response
|
||||
return response;
|
||||
}
|
||||
|
||||
httpResponse ProviderRestApi::getResponse(QNetworkReply* const &reply)
|
||||
{
|
||||
httpResponse response;
|
||||
|
||||
int httpStatusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
|
||||
response.setHttpStatusCode(httpStatusCode);
|
||||
|
||||
Debug(_log, "Reply.httpStatusCode [%d]", httpStatusCode );
|
||||
|
||||
response.setNetworkReplyError(reply->error());
|
||||
|
||||
if(reply->error() == QNetworkReply::NoError)
|
||||
{
|
||||
if ( httpStatusCode != 204 ){
|
||||
QByteArray replyData = reply->readAll();
|
||||
|
||||
if ( !replyData.isEmpty())
|
||||
{
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(replyData, &error);
|
||||
|
||||
if (error.error != QJsonParseError::NoError)
|
||||
{
|
||||
//Received not valid JSON response
|
||||
//std::cout << "Response: [" << replyData.toStdString() << "]" << std::endl;
|
||||
response.setError(true);
|
||||
response.setErrorReason(error.errorString());
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::cout << "Response: [" << QString (jsonDoc.toJson(QJsonDocument::Compact)).toStdString() << "]" << std::endl;
|
||||
response.setBody( jsonDoc );
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Create valid body which is empty
|
||||
response.setBody( QJsonDocument() );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QString errorReason;
|
||||
if ( httpStatusCode > 0 ) {
|
||||
QString httpReason = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString();
|
||||
QString advise;
|
||||
switch ( httpStatusCode ) {
|
||||
case 400:
|
||||
advise = "Check Request Body";
|
||||
break;
|
||||
case 401:
|
||||
advise = "Check Authentication Token (API Key)";
|
||||
break;
|
||||
case 404:
|
||||
advise = "Check Resource given";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
errorReason = QString ("[%3 %4] - %5").arg(QString(httpStatusCode) , httpReason, advise);
|
||||
}
|
||||
else {
|
||||
errorReason = reply->errorString();
|
||||
}
|
||||
response.setError(true);
|
||||
response.setErrorReason(errorReason);
|
||||
|
||||
// Create valid body which is empty
|
||||
response.setBody( QJsonDocument() );
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
216
libsrc/leddevice/dev_net/ProviderRestApi.h
Normal file
216
libsrc/leddevice/dev_net/ProviderRestApi.h
Normal file
@@ -0,0 +1,216 @@
|
||||
#ifndef PROVIDERRESTKAPI_H
|
||||
#define PROVIDERRESTKAPI_H
|
||||
|
||||
// Local-Hyperion includes
|
||||
#include <utils/Logger.h>
|
||||
|
||||
// Qt includes
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QUrlQuery>
|
||||
#include <QJsonDocument>
|
||||
|
||||
///
|
||||
/// Response object for REST-API calls and JSON-responses
|
||||
///
|
||||
class httpResponse
|
||||
{
|
||||
public:
|
||||
|
||||
explicit httpResponse() {}
|
||||
|
||||
bool error() { return _hasError;}
|
||||
void setError(const bool hasError) { _hasError = hasError; }
|
||||
|
||||
QJsonDocument getBody() const { return _responseBody; }
|
||||
void setBody(const QJsonDocument &body) { _responseBody = body; }
|
||||
|
||||
QString getErrorReason() const { return _errorReason; }
|
||||
void setErrorReason(const QString &errorReason) { _errorReason = errorReason; }
|
||||
|
||||
int getHttpStatusCode() const { return _httpStatusCode; }
|
||||
void setHttpStatusCode(const int httpStatusCode) { _httpStatusCode = httpStatusCode; }
|
||||
|
||||
QNetworkReply::NetworkError getNetworkReplyError() const { return _networkReplyError; }
|
||||
void setNetworkReplyError (const QNetworkReply::NetworkError networkReplyError) { _networkReplyError = networkReplyError; }
|
||||
|
||||
private:
|
||||
|
||||
QJsonDocument _responseBody;
|
||||
bool _hasError = false;
|
||||
QString _errorReason;
|
||||
|
||||
int _httpStatusCode = 0;
|
||||
QNetworkReply::NetworkError _networkReplyError = QNetworkReply::NoError;
|
||||
};
|
||||
|
||||
///
|
||||
/// Wrapper class supporting REST-API calls with JSON requests and responses
|
||||
///
|
||||
/// Usage sample:
|
||||
/// @code
|
||||
///
|
||||
/// ProviderRestApi* _restApi = new ProviderRestApi(hostname, port );
|
||||
///
|
||||
/// _restApi->setBasePath( QString("/api/%1/").arg(token) );
|
||||
/// _restApi->setPath( QString("%1/%2").arg( "groups" ).arg( groupId ) );
|
||||
///
|
||||
/// httpResponse response = _restApi->get();
|
||||
/// if ( !response.error() )
|
||||
/// response.getBody();
|
||||
///
|
||||
/// delete _restApi;
|
||||
///
|
||||
///@endcode
|
||||
///
|
||||
class ProviderRestApi
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// @brief Constructor of the REST-API wrapper
|
||||
///
|
||||
explicit ProviderRestApi();
|
||||
|
||||
///
|
||||
/// @brief Constructor of the REST-API wrapper
|
||||
///
|
||||
/// @param[in] host
|
||||
/// @param[in] port
|
||||
///
|
||||
explicit ProviderRestApi(const QString &host, const int &port);
|
||||
|
||||
///
|
||||
/// @brief Constructor of the REST-API wrapper
|
||||
///
|
||||
/// @param[in] host
|
||||
/// @param[in] port
|
||||
/// @param[in] API base-path
|
||||
///
|
||||
explicit ProviderRestApi(const QString &host, const int &port, const QString &basePath);
|
||||
|
||||
///
|
||||
/// @brief Destructor of the REST-API wrapper
|
||||
///
|
||||
virtual ~ProviderRestApi();
|
||||
|
||||
///
|
||||
/// @brief Get the URL as defined using scheme, host, port, API-basepath, path, query, fragment
|
||||
///
|
||||
/// @return url
|
||||
///
|
||||
QUrl getUrl() const;
|
||||
|
||||
///
|
||||
/// @brief Set an API's base path (the stable path element before addressing resources)
|
||||
///
|
||||
/// @param[in] basePath, e.g. "/api/v1/" or "/json"
|
||||
///
|
||||
void setBasePath(const QString &basePath);
|
||||
|
||||
///
|
||||
/// @brief Set an API's path to address resources
|
||||
///
|
||||
/// @param[in] path, e.g. "/lights/1/state/"
|
||||
///
|
||||
void setPath ( const QString &path );
|
||||
|
||||
///
|
||||
/// @brief Append an API's path element to path set before
|
||||
///
|
||||
/// @param[in] path
|
||||
///
|
||||
void appendPath (const QString &appendPath);
|
||||
|
||||
///
|
||||
/// @brief Set an API's fragment
|
||||
///
|
||||
/// @param[in] fragment, e.g. "question3"
|
||||
///
|
||||
void setFragment(const QString&fragment);
|
||||
|
||||
///
|
||||
/// @brief Set an API's query string
|
||||
///
|
||||
/// @param[in] query, e.g. "&A=128&FX=0"
|
||||
///
|
||||
void setQuery(const QUrlQuery &query);
|
||||
|
||||
///
|
||||
/// @brief Execute GET request
|
||||
///
|
||||
/// @return Response The body of the response in JSON
|
||||
///
|
||||
httpResponse get();
|
||||
|
||||
///
|
||||
/// @brief Execute GET request
|
||||
///
|
||||
/// @param[in] url GET request for URL
|
||||
/// @return Response The body of the response in JSON
|
||||
///
|
||||
httpResponse get(const QUrl &url);
|
||||
|
||||
///
|
||||
/// @brief Execute PUT request
|
||||
///
|
||||
/// @param[in] body The body of the request in JSON
|
||||
/// @return Response The body of the response in JSON
|
||||
///
|
||||
httpResponse put(const QString &body = "");
|
||||
|
||||
///
|
||||
/// @brief Execute PUT request
|
||||
///
|
||||
/// @param[in] URL for PUT request
|
||||
/// @param[in] body The body of the request in JSON
|
||||
/// @return Response The body of the response in JSON
|
||||
///
|
||||
httpResponse put(const QUrl &url, const QString &body = "");
|
||||
|
||||
///
|
||||
/// @brief Execute POST request
|
||||
///
|
||||
/// @param[in] body The body of the request in JSON
|
||||
/// @return Response The body of the response in JSON
|
||||
///
|
||||
httpResponse post(QString body = "");
|
||||
|
||||
///
|
||||
/// @brief Handle responses for REST requests
|
||||
///
|
||||
/// @param[in] reply Network reply
|
||||
/// @return Response The body of the response in JSON
|
||||
///
|
||||
httpResponse getResponse(QNetworkReply* const &reply);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// @brief Append an API's path element to path given as param
|
||||
///
|
||||
/// @param[in/out] path to be updated
|
||||
/// @param[in] path, element to be appended
|
||||
///
|
||||
void appendPath (QString &path, const QString &appendPath) const;
|
||||
|
||||
Logger* _log;
|
||||
|
||||
// QNetworkAccessManager object for sending REST-requests.
|
||||
QNetworkAccessManager* _networkManager;
|
||||
|
||||
QUrl _apiUrl;
|
||||
|
||||
QString _scheme;
|
||||
QString _hostname;
|
||||
int _port;
|
||||
|
||||
QString _basePath;
|
||||
QString _path;
|
||||
|
||||
QString _fragment;
|
||||
QUrlQuery _query;
|
||||
|
||||
};
|
||||
|
||||
#endif // PROVIDERRESTKAPI_H
|
@@ -22,7 +22,7 @@ ProviderUdp::ProviderUdp()
|
||||
, _port(1)
|
||||
, _defaultHost("127.0.0.1")
|
||||
{
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
_latchTime_ms = 1;
|
||||
}
|
||||
|
||||
@@ -30,59 +30,65 @@ ProviderUdp::~ProviderUdp()
|
||||
{
|
||||
if ( _udpSocket != nullptr )
|
||||
{
|
||||
_udpSocket->deleteLater();
|
||||
delete _udpSocket;
|
||||
}
|
||||
}
|
||||
|
||||
bool ProviderUdp::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
QString host = deviceConfig["host"].toString(_defaultHost);
|
||||
// Initialise sub-class
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
QString host = deviceConfig["host"].toString(_defaultHost);
|
||||
|
||||
if (_address.setAddress(host) )
|
||||
{
|
||||
Debug( _log, "Successfully parsed %s as an ip address.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "Failed to parse [%s] as an ip address.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
QHostInfo info = QHostInfo::fromName(host);
|
||||
if (info.addresses().isEmpty())
|
||||
if (_address.setAddress(host) )
|
||||
{
|
||||
Debug( _log, "Failed to parse [%s] as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
QString errortext = QString ("Invalid target address [%1]!").arg(host);
|
||||
this->setInError ( errortext );
|
||||
return false;
|
||||
Debug( _log, "Successfully parsed %s as an ip address.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "Successfully parsed %s as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
_address = info.addresses().first();
|
||||
Debug( _log, "Failed to parse [%s] as an ip address.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
QHostInfo info = QHostInfo::fromName(host);
|
||||
if (info.addresses().isEmpty())
|
||||
{
|
||||
Debug( _log, "Failed to parse [%s] as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
QString errortext = QString ("Invalid target address [%1]!").arg(host);
|
||||
this->setInError ( errortext );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "Successfully parsed %s as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
_address = info.addresses().first();
|
||||
}
|
||||
}
|
||||
|
||||
int config_port = deviceConfig["port"].toInt(_port);
|
||||
if ( config_port <= 0 || config_port > MAX_PORT )
|
||||
{
|
||||
QString errortext = QString ("Invalid target port [%1]!").arg(config_port);
|
||||
this->setInError ( errortext );
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_port = static_cast<int>(config_port);
|
||||
Debug( _log, "UDP using %s:%d", _address.toString().toStdString().c_str() , _port );
|
||||
|
||||
_udpSocket = new QUdpSocket(this);
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
|
||||
int config_port = deviceConfig["port"].toInt(_port);
|
||||
if ( config_port <= 0 || config_port > MAX_PORT )
|
||||
{
|
||||
QString errortext = QString ("Invalid target port [%1]!").arg(config_port);
|
||||
this->setInError ( errortext );
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_port = static_cast<int>(config_port);
|
||||
Debug( _log, "UDP using %s:%d", _address.toString().toStdString().c_str() , _port );
|
||||
}
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool ProviderUdp::initNetwork()
|
||||
int ProviderUdp::open()
|
||||
{
|
||||
bool isInitOK = false;
|
||||
|
||||
_udpSocket = new QUdpSocket(this);
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
// Try to bind the UDP-Socket
|
||||
if ( _udpSocket != nullptr )
|
||||
@@ -94,37 +100,21 @@ bool ProviderUdp::initNetwork()
|
||||
QString warntext = QString ("Could not bind local address: %1, (%2) %3").arg(localAddress.toString()).arg(_udpSocket->error()).arg(_udpSocket->errorString());
|
||||
Warning ( _log, "%s", QSTRING_CSTR(warntext));
|
||||
}
|
||||
isInitOK = true;
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int ProviderUdp::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
else
|
||||
{
|
||||
if ( ! initNetwork())
|
||||
{
|
||||
this->setInError( "UDP Network error!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
this->setInError( " Open error. UDP Socket not initialised!" );
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ProviderUdp::close()
|
||||
int ProviderUdp::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
int retval = 0;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if ( _udpSocket != nullptr )
|
||||
{
|
||||
@@ -136,6 +126,7 @@ void ProviderUdp::close()
|
||||
// Everything is OK -> device is closed
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ProviderUdp::writeBytes(const unsigned size, const uint8_t * data)
|
||||
|
@@ -1,13 +1,15 @@
|
||||
#pragma once
|
||||
#ifndef PROVIDERUDP_H
|
||||
#define PROVIDERUDP_H
|
||||
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
|
||||
// Hyperion includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
#include <utils/Logger.h>
|
||||
|
||||
// qt
|
||||
// Qt includes
|
||||
#include <QHostAddress>
|
||||
|
||||
class QUdpSocket;
|
||||
#include <QUdpSocket>
|
||||
|
||||
///
|
||||
/// The ProviderUdp implements an abstract base-class for LedDevices using UDP packets.
|
||||
@@ -15,53 +17,49 @@ class QUdpSocket;
|
||||
class ProviderUdp : public LedDevice
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs an UDP LED-device
|
||||
///
|
||||
ProviderUdp();
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
/// @brief Destructor of the UDP LED-device
|
||||
///
|
||||
virtual ~ProviderUdp() override;
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Initialise device's network details
|
||||
/// @brief Initialise the UDP device's configuration and network address details
|
||||
///
|
||||
/// @return True if success
|
||||
bool initNetwork();
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// Opens and configures the output device
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
int open() override;
|
||||
virtual int open() override;
|
||||
|
||||
///
|
||||
/// Writes the given bytes/bits to the UDP-device and sleeps the latch time to ensure that the
|
||||
/// @brief Closes the UDP device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the given bytes/bits to the UDP-device and sleeps the latch time to ensure that the
|
||||
/// values are latched.
|
||||
///
|
||||
/// @param[in] size The length of the data
|
||||
/// @param[in] data The data
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
int writeBytes(const unsigned size, const uint8_t *data);
|
||||
|
||||
@@ -71,3 +69,5 @@ protected:
|
||||
ushort _port;
|
||||
QString _defaultHost;
|
||||
};
|
||||
|
||||
#endif // PROVIDERUDP_H
|
||||
|
@@ -12,6 +12,9 @@
|
||||
// Local Hyperion includes
|
||||
#include "ProviderUdpSSL.h"
|
||||
|
||||
const int MAX_RETRY = 5;
|
||||
const ushort MAX_PORT_SSL = 65535;
|
||||
|
||||
ProviderUdpSSL::ProviderUdpSSL()
|
||||
: LedDevice()
|
||||
, client_fd()
|
||||
@@ -29,16 +32,16 @@ ProviderUdpSSL::ProviderUdpSSL()
|
||||
, _server_name()
|
||||
, _psk()
|
||||
, _psk_identity()
|
||||
, _read_timeout(0)
|
||||
, _handshake_timeout_min(400)
|
||||
, _handshake_timeout_max(1000)
|
||||
, _read_timeout(STREAM_SSL_READ_TIMEOUT.count())
|
||||
, _handshake_timeout_min(STREAM_SSL_HANDSHAKE_TIMEOUT_MIN.count())
|
||||
, _handshake_timeout_max(STREAM_SSL_HANDSHAKE_TIMEOUT_MAX.count())
|
||||
, _handshake_attempts(5)
|
||||
, _retry_left(MAX_RETRY)
|
||||
, _stopConnection(true)
|
||||
, _debugStreamer(false)
|
||||
, _debugLevel(0)
|
||||
{
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
_latchTime_ms = 1;
|
||||
}
|
||||
|
||||
@@ -48,114 +51,131 @@ ProviderUdpSSL::~ProviderUdpSSL()
|
||||
|
||||
bool ProviderUdpSSL::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
_debugStreamer = deviceConfig["debugStreamer"].toBool(false);
|
||||
_debugLevel = deviceConfig["debugLevel"].toString().toInt(0);
|
||||
|
||||
//PSK Pre Shared Key
|
||||
_psk = deviceConfig["psk"].toString();
|
||||
_psk_identity = deviceConfig["psk_identity"].toString();
|
||||
_port = deviceConfig["sslport"].toInt(2100);
|
||||
_server_name = deviceConfig["servername"].toString();
|
||||
|
||||
if( deviceConfig.contains("transport_type") ) _transport_type = deviceConfig["transport_type"].toString("DTLS");
|
||||
if( deviceConfig.contains("seed_custom") ) _custom = deviceConfig["seed_custom"].toString("dtls_client");
|
||||
if( deviceConfig.contains("retry_left") ) _retry_left = deviceConfig["retry_left"].toInt(MAX_RETRY);
|
||||
if( deviceConfig.contains("read_timeout") ) _read_timeout = deviceConfig["read_timeout"].toInt(0);
|
||||
if( deviceConfig.contains("hs_timeout_min") ) _handshake_timeout_min = deviceConfig["hs_timeout_min"].toInt(400);
|
||||
if( deviceConfig.contains("hs_timeout_max") ) _handshake_timeout_max = deviceConfig["hs_timeout_max"].toInt(1000);
|
||||
if( deviceConfig.contains("hs_attempts") ) _handshake_attempts = deviceConfig["hs_attempts"].toInt(5);
|
||||
|
||||
QString host = deviceConfig["host"].toString(_defaultHost);
|
||||
QStringList debugLevels = QStringList() << "No Debug" << "Error" << "State Change" << "Informational" << "Verbose";
|
||||
|
||||
configLog( "SSL Streamer Debug", "%s", ( _debugStreamer ) ? "yes" : "no" );
|
||||
configLog( "SSL DebugLevel", "[%d] %s", _debugLevel, QSTRING_CSTR( debugLevels[ _debugLevel ]) );
|
||||
|
||||
configLog( "SSL Servername", "%s", QSTRING_CSTR( _server_name ) );
|
||||
configLog( "SSL Host", "%s", QSTRING_CSTR( host ) );
|
||||
configLog( "SSL Port", "%d", _port );
|
||||
configLog( "PSK", "%s", QSTRING_CSTR( _psk ) );
|
||||
configLog( "PSK-Identity", "%s", QSTRING_CSTR( _psk_identity ) );
|
||||
configLog( "SSL Transport Type", "%s", QSTRING_CSTR( _transport_type ) );
|
||||
configLog( "SSL Seed Custom", "%s", QSTRING_CSTR( _custom ) );
|
||||
configLog( "SSL Retry Left", "%d", _retry_left );
|
||||
configLog( "SSL Read Timeout", "%d", _read_timeout );
|
||||
configLog( "SSL Handshake Timeout min", "%d", _handshake_timeout_min );
|
||||
configLog( "SSL Handshake Timeout max", "%d", _handshake_timeout_max );
|
||||
configLog( "SSL Handshake attempts", "%d", _handshake_attempts );
|
||||
|
||||
if ( _address.setAddress(host) )
|
||||
// Initialise sub-class
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
Debug( _log, "Successfully parsed %s as an ip address.", QSTRING_CSTR( host ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "Failed to parse [%s] as an ip address.", QSTRING_CSTR( host ) );
|
||||
QHostInfo info = QHostInfo::fromName(host);
|
||||
if ( info.addresses().isEmpty() )
|
||||
_debugStreamer = deviceConfig["debugStreamer"].toBool(false);
|
||||
_debugLevel = deviceConfig["debugLevel"].toString().toInt(0);
|
||||
|
||||
//PSK Pre Shared Key
|
||||
_psk = deviceConfig["psk"].toString();
|
||||
_psk_identity = deviceConfig["psk_identity"].toString();
|
||||
_port = deviceConfig["sslport"].toInt(2100);
|
||||
_server_name = deviceConfig["servername"].toString();
|
||||
|
||||
if( deviceConfig.contains("transport_type") ) _transport_type = deviceConfig["transport_type"].toString("DTLS");
|
||||
if( deviceConfig.contains("seed_custom") ) _custom = deviceConfig["seed_custom"].toString("dtls_client");
|
||||
if( deviceConfig.contains("retry_left") ) _retry_left = deviceConfig["retry_left"].toInt(MAX_RETRY);
|
||||
if( deviceConfig.contains("read_timeout") ) _read_timeout = deviceConfig["read_timeout"].toInt(0);
|
||||
if( deviceConfig.contains("hs_timeout_min") ) _handshake_timeout_min = deviceConfig["hs_timeout_min"].toInt(400);
|
||||
if( deviceConfig.contains("hs_timeout_max") ) _handshake_timeout_max = deviceConfig["hs_timeout_max"].toInt(1000);
|
||||
if( deviceConfig.contains("hs_attempts") ) _handshake_attempts = deviceConfig["hs_attempts"].toInt(5);
|
||||
|
||||
QString host = deviceConfig["host"].toString(_defaultHost);
|
||||
QStringList debugLevels = QStringList() << "No Debug" << "Error" << "State Change" << "Informational" << "Verbose";
|
||||
|
||||
configLog( "SSL Streamer Debug", "%s", ( _debugStreamer ) ? "yes" : "no" );
|
||||
configLog( "SSL DebugLevel", "[%d] %s", _debugLevel, QSTRING_CSTR( debugLevels[ _debugLevel ]) );
|
||||
|
||||
configLog( "SSL Servername", "%s", QSTRING_CSTR( _server_name ) );
|
||||
configLog( "SSL Host", "%s", QSTRING_CSTR( host ) );
|
||||
configLog( "SSL Port", "%d", _port );
|
||||
configLog( "PSK", "%s", QSTRING_CSTR( _psk ) );
|
||||
configLog( "PSK-Identity", "%s", QSTRING_CSTR( _psk_identity ) );
|
||||
configLog( "SSL Transport Type", "%s", QSTRING_CSTR( _transport_type ) );
|
||||
configLog( "SSL Seed Custom", "%s", QSTRING_CSTR( _custom ) );
|
||||
configLog( "SSL Retry Left", "%d", _retry_left );
|
||||
configLog( "SSL Read Timeout", "%d", _read_timeout );
|
||||
configLog( "SSL Handshake Timeout min", "%d", _handshake_timeout_min );
|
||||
configLog( "SSL Handshake Timeout max", "%d", _handshake_timeout_max );
|
||||
configLog( "SSL Handshake attempts", "%d", _handshake_attempts );
|
||||
|
||||
if ( _address.setAddress(host) )
|
||||
{
|
||||
Debug( _log, "Failed to parse [%s] as a hostname.", QSTRING_CSTR( host ) );
|
||||
QString errortext = QString("Invalid target address [%1]!").arg(host);
|
||||
Debug( _log, "Successfully parsed %s as an ip address.", QSTRING_CSTR( host ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "Failed to parse [%s] as an ip address.", QSTRING_CSTR( host ) );
|
||||
QHostInfo info = QHostInfo::fromName(host);
|
||||
if ( info.addresses().isEmpty() )
|
||||
{
|
||||
Debug( _log, "Failed to parse [%s] as a hostname.", QSTRING_CSTR( host ) );
|
||||
QString errortext = QString("Invalid target address [%1]!").arg(host);
|
||||
this->setInError( errortext );
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "Successfully parsed %s as a hostname.", QSTRING_CSTR( host ) );
|
||||
_address = info.addresses().first();
|
||||
}
|
||||
}
|
||||
|
||||
int config_port = deviceConfig["sslport"].toInt(_port);
|
||||
|
||||
if ( config_port <= 0 || config_port > MAX_PORT_SSL )
|
||||
{
|
||||
QString errortext = QString ("Invalid target port [%1]!").arg(config_port);
|
||||
this->setInError( errortext );
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "Successfully parsed %s as a hostname.", QSTRING_CSTR( host ) );
|
||||
_address = info.addresses().first();
|
||||
_ssl_port = config_port;
|
||||
Debug( _log, "UDP SSL using %s:%u", QSTRING_CSTR( _address.toString() ), _ssl_port );
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
|
||||
int config_port = deviceConfig["sslport"].toInt(_port);
|
||||
|
||||
if ( config_port <= 0 || config_port > MAX_PORT_SSL )
|
||||
{
|
||||
QString errortext = QString ("Invalid target port [%1]!").arg(config_port);
|
||||
this->setInError( errortext );
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ssl_port = config_port;
|
||||
Debug( _log, "UDP SSL using %s:%u", QSTRING_CSTR( _address.toString() ), _ssl_port );
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int ProviderUdpSSL::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
// TODO: Question: Just checking .... Is this one time initialisation or required with every open request (during switch-off/switch-on)?
|
||||
// In case one time initialisation, it should go to the init method.
|
||||
// Everything that is required to pen a UDP-SSL connection again (after it maybe was closed remotely should go here)
|
||||
|
||||
if ( !initNetwork() )
|
||||
{
|
||||
if ( !initNetwork() )
|
||||
{
|
||||
this->setInError( "UDP SSL Network error!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
this->setInError( "UDP SSL Network error!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ProviderUdpSSL::close()
|
||||
int ProviderUdpSSL::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
closeSSLConnection();
|
||||
// LedDevice specific closing activities
|
||||
int retval = 0;
|
||||
_isDeviceReady = false;
|
||||
|
||||
// TODO: You may want to check, if the device is already closed or close it and return, if ok or not
|
||||
// Test, if device requires closing
|
||||
if ( true /*If device is still open*/ )
|
||||
{
|
||||
// Close device
|
||||
|
||||
LedDevice::close();
|
||||
closeSSLConnection();
|
||||
// Everything is OK -> device is closed
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ProviderUdpSSL::closeSSLConnection()
|
||||
{
|
||||
if( _deviceReady && !_stopConnection )
|
||||
if( _isDeviceReady && !_stopConnection )
|
||||
{
|
||||
closeSSLNotify();
|
||||
freeSSLConnection();
|
||||
@@ -412,7 +432,7 @@ bool ProviderUdpSSL::startSSLHandshake()
|
||||
|
||||
void ProviderUdpSSL::freeSSLConnection()
|
||||
{
|
||||
sslLog( "SSL Connection cleanup..." );
|
||||
sslLog( "SSL Connection clean-up..." );
|
||||
|
||||
_stopConnection = true;
|
||||
|
||||
@@ -425,15 +445,15 @@ void ProviderUdpSSL::freeSSLConnection()
|
||||
mbedtls_x509_crt_free(&cacert);
|
||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||
mbedtls_entropy_free(&entropy);
|
||||
sslLog( "SSL Connection cleanup...ok" );
|
||||
sslLog( "SSL Connection clean-up...ok" );
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
sslLog( QString("SSL Connection cleanup Error: %s").arg( e.what() ) );
|
||||
sslLog( QString("SSL Connection clean-up Error: %s").arg( e.what() ) );
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
sslLog( "SSL Connection cleanup Error: <unknown>" );
|
||||
sslLog( "SSL Connection clean-up Error: <unknown>" );
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef PROVIDERUDPSSL_H
|
||||
#define PROVIDERUDPSSL_H
|
||||
|
||||
#include <leddevice/LedDevice.h>
|
||||
#include <utils/Logger.h>
|
||||
@@ -36,6 +37,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <cstring>
|
||||
#include <chrono>
|
||||
|
||||
#include <mbedtls/net_sockets.h>
|
||||
#include <mbedtls/ssl_ciphersuites.h>
|
||||
@@ -45,12 +47,11 @@
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/debug.h>
|
||||
|
||||
#define READ_TIMEOUT_MS 1000
|
||||
#define MAX_RETRY 5
|
||||
|
||||
//----------- END mbedtls
|
||||
|
||||
const ushort MAX_PORT_SSL = 65535;
|
||||
constexpr std::chrono::milliseconds STREAM_SSL_HANDSHAKE_TIMEOUT_MIN{400};
|
||||
constexpr std::chrono::milliseconds STREAM_SSL_HANDSHAKE_TIMEOUT_MAX{1000};
|
||||
constexpr std::chrono::milliseconds STREAM_SSL_READ_TIMEOUT{0};
|
||||
|
||||
class ProviderUdpSSL : public LedDevice
|
||||
{
|
||||
@@ -58,44 +59,45 @@ class ProviderUdpSSL : public LedDevice
|
||||
|
||||
public:
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs an UDP SSL LED-device
|
||||
///
|
||||
ProviderUdpSSL();
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
/// @brief Destructor of the LED-device
|
||||
///
|
||||
virtual ~ProviderUdpSSL() override;
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Initialise device's network details
|
||||
/// @brief Initialise the UDP-SSL device's configuration and network address details
|
||||
///
|
||||
/// @return True if success
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success#endif // PROVIDERUDP_H
|
||||
///
|
||||
bool initNetwork();
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// Opens and configures the output device
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
int open() override;
|
||||
virtual int open() override;
|
||||
|
||||
///
|
||||
/// @brief Closes the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// @brief Initialise device's network details
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
bool initNetwork();
|
||||
|
||||
///
|
||||
/// Writes the given bytes/bits to the UDP-device and sleeps the latch time to ensure that the
|
||||
@@ -208,3 +210,5 @@ private:
|
||||
bool _debugStreamer;
|
||||
int _debugLevel;
|
||||
};
|
||||
|
||||
#endif // PROVIDERUDPSSL_H
|
||||
|
@@ -9,16 +9,15 @@ LedDeviceFile::LedDeviceFile(const QJsonObject &deviceConfig)
|
||||
, _file (nullptr)
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
_printTimeStamp = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDeviceFile::~LedDeviceFile()
|
||||
{
|
||||
if ( _file != nullptr )
|
||||
{
|
||||
_file->deleteLater();
|
||||
}
|
||||
delete _file;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceFile::construct(const QJsonObject &deviceConfig)
|
||||
@@ -49,38 +48,30 @@ void LedDeviceFile::initFile(const QString &fileName)
|
||||
int LedDeviceFile::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
if ( ! _file->isOpen() )
|
||||
{
|
||||
if ( ! _file->isOpen() )
|
||||
Debug(_log, "QIODevice::WriteOnly, %s", QSTRING_CSTR(_fileName));
|
||||
if ( !_file->open(QIODevice::WriteOnly | QIODevice::Text) )
|
||||
{
|
||||
Debug(_log, "QIODevice::WriteOnly, %s", QSTRING_CSTR(_fileName));
|
||||
if ( !_file->open(QIODevice::WriteOnly | QIODevice::Text) )
|
||||
{
|
||||
errortext = QString ("(%1) %2, file: (%3)").arg(_file->error()).arg(_file->errorString()).arg(_fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
QString errortext = QString ("(%1) %2, file: (%3)").arg(_file->error()).arg(_file->errorString(),_fileName);
|
||||
this->setInError( errortext );
|
||||
}
|
||||
else
|
||||
{
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDeviceFile::close()
|
||||
int LedDeviceFile::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
int retval = 0;
|
||||
|
||||
_isDeviceReady = false;
|
||||
if ( _file != nullptr)
|
||||
{
|
||||
// Test, if device requires closing
|
||||
@@ -91,6 +82,7 @@ void LedDeviceFile::close()
|
||||
_file->close();
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceFile::write(const std::vector<ColorRgb> & ledValues)
|
||||
|
@@ -35,14 +35,6 @@ public:
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// @brief Closes the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
@@ -60,6 +52,13 @@ protected:
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
///
|
||||
/// @brief Closes the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
|
@@ -13,7 +13,9 @@ LedDevicePiBlaster::LedDevicePiBlaster(const QJsonObject &deviceConfig)
|
||||
: _fid(nullptr)
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
@@ -55,7 +57,7 @@ bool LedDevicePiBlaster::init(const QJsonObject &deviceConfig)
|
||||
return false;
|
||||
}
|
||||
|
||||
// walk through the json config and populate the mapping tables
|
||||
// walk through the JSON configuration and populate the mapping tables
|
||||
for(QJsonArray::const_iterator gpioArray = gpioMapping.begin(); gpioArray != gpioMapping.end(); ++gpioArray)
|
||||
{
|
||||
const QJsonObject value = (*gpioArray).toObject();
|
||||
@@ -84,56 +86,57 @@ int LedDevicePiBlaster::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
if (_fid != nullptr)
|
||||
{
|
||||
if (_fid != nullptr)
|
||||
// The file pointer is already open
|
||||
errortext = QString ("Device (%1) is already open.").arg(_deviceName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!QFile::exists(_deviceName))
|
||||
{
|
||||
// The file pointer is already open
|
||||
errortext = QString ("Device (%1) is already open.").arg(_deviceName);
|
||||
errortext = QString ("The device (%1) does not yet exist.").arg(_deviceName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!QFile::exists(_deviceName))
|
||||
_fid = fopen(QSTRING_CSTR(_deviceName), "w");
|
||||
if (_fid == nullptr)
|
||||
{
|
||||
errortext = QString ("The device (%1) does not yet exist.").arg(_deviceName);
|
||||
errortext = QString ("Failed to open device (%1). Error message: %2").arg(_deviceName, strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
_fid = fopen(QSTRING_CSTR(_deviceName), "w");
|
||||
if (_fid == nullptr)
|
||||
{
|
||||
errortext = QString ("Failed to open device (%1). Error message: %2").arg(_deviceName, strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
Info( _log, "Connected to device(%s)", QSTRING_CSTR(_deviceName));
|
||||
retval = 0;
|
||||
setEnable(true);
|
||||
}
|
||||
Info( _log, "Connected to device(%s)", QSTRING_CSTR(_deviceName));
|
||||
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDevicePiBlaster::close()
|
||||
int LedDevicePiBlaster::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
int retval = 0;
|
||||
_isDeviceReady = false;
|
||||
|
||||
// LedDevice specific closing activites
|
||||
// Close the device (if it is opened)
|
||||
// Test, if device requires closing
|
||||
if (_fid != nullptr)
|
||||
{
|
||||
fclose(_fid);
|
||||
_fid = nullptr;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDevicePiBlaster::write(const std::vector<ColorRgb> & ledValues)
|
||||
|
@@ -1,57 +1,64 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEPIBLASTER_H
|
||||
#define LEDEVICEPIBLASTER_H
|
||||
|
||||
// Hyperion-Leddevice includes
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for writing to pi-blaster based PWM LEDs
|
||||
///
|
||||
|
||||
class LedDevicePiBlaster : public LedDevice
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a pi-Blaster LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDevicePiBlaster(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// @brief Destructor of the LedDevice
|
||||
///
|
||||
virtual ~LedDevicePiBlaster() override;
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
/// constructs leddevice
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// Attempts to open the piblaster-device. This will only succeed if the device is not yet open
|
||||
/// and the device is available.
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
int open() override;
|
||||
virtual int open() override;
|
||||
|
||||
///
|
||||
/// @brief Closes the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual int close() override;
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Writes the colors to the PiBlaster device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color value for each led
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
@@ -65,3 +72,5 @@ private:
|
||||
FILE * _fid;
|
||||
|
||||
};
|
||||
|
||||
#endif // LEDEVICETEMPLATE_H
|
||||
|
@@ -4,7 +4,9 @@ LedDeviceWS281x::LedDeviceWS281x(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDeviceWS281x::~LedDeviceWS281x()
|
||||
@@ -20,10 +22,11 @@ bool LedDeviceWS281x::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
QString errortext;
|
||||
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
{
|
||||
bool isInitOK = false;
|
||||
|
||||
// Initialise sub-class
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
QString whiteAlgorithm = deviceConfig["whiteAlgorithm"].toString("white_off");
|
||||
|
||||
_whiteAlgorithm = RGBW::stringToWhiteAlgorithm(whiteAlgorithm);
|
||||
@@ -43,7 +46,7 @@ bool LedDeviceWS281x::init(const QJsonObject &deviceConfig)
|
||||
else
|
||||
{
|
||||
memset(&_led_string, 0, sizeof(_led_string));
|
||||
_led_string.freq = deviceConfig["freq"].toInt(800000ul);
|
||||
_led_string.freq = deviceConfig["freq"].toInt(800000UL);
|
||||
_led_string.dmanum = deviceConfig["dma"].toInt(5);
|
||||
_led_string.channel[_channel].gpionum = deviceConfig["gpio"].toInt(18);
|
||||
_led_string.channel[_channel].count = deviceConfig["leds"].toInt(256);
|
||||
@@ -59,15 +62,7 @@ bool LedDeviceWS281x::init(const QJsonObject &deviceConfig)
|
||||
|
||||
Debug( _log, "ws281x strip type : %d", _led_string.channel[_channel].strip_type );
|
||||
|
||||
if (ws2811_init(&_led_string) < 0)
|
||||
{
|
||||
errortext = "Unable to initialize ws281x library.";
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
isInitOK = true;
|
||||
}
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,14 +74,40 @@ bool LedDeviceWS281x::init(const QJsonObject &deviceConfig)
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
void LedDeviceWS281x::close()
|
||||
int LedDeviceWS281x::open()
|
||||
{
|
||||
LedDevice::close();
|
||||
int retval = -1;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if (_deviceReady)
|
||||
// Try to open the LedDevice
|
||||
|
||||
ws2811_return_t rc = ws2811_init(&_led_string);
|
||||
if ( rc != WS2811_SUCCESS )
|
||||
{
|
||||
QString errortext = QString ("Failed to open. Error message: %1").arg( ws2811_get_return_t_str(rc) );
|
||||
this->setInError( errortext );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceWS281x::close()
|
||||
{
|
||||
int retval = 0;
|
||||
_isDeviceReady = false;
|
||||
|
||||
// LedDevice specific closing activities
|
||||
if ( isInitialised() )
|
||||
{
|
||||
ws2811_fini(&_led_string);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Send new values down the LED chain
|
||||
|
@@ -1,52 +1,65 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEWS281X_H
|
||||
#define LEDEVICEWS281X_H
|
||||
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
#include <ws2811.h>
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for writing to Ws2812 led device via pwm.
|
||||
/// Implementation of the LedDevice interface for writing to WS281x LED-device via pwm.
|
||||
///
|
||||
class LedDeviceWS281x : public LedDevice
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs an WS281x LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceWS281x(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice, waits for DMA to complete and then cleans up
|
||||
/// @brief Destructor of the LedDevice
|
||||
///
|
||||
virtual ~LedDeviceWS281x() override;
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Destructor of the LedDevice
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
virtual void close() override;
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Closes the output device.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -55,3 +68,5 @@ private:
|
||||
RGBW::WhiteAlgorithm _whiteAlgorithm;
|
||||
ColorRgbw _temp_rgbw;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEWS281X_H
|
||||
|
@@ -2,13 +2,13 @@
|
||||
|
||||
LedDeviceAdalight::LedDeviceAdalight(const QJsonObject &deviceConfig)
|
||||
: ProviderRs232()
|
||||
, _headerSize(6)
|
||||
, _ligthBerryAPA102Mode(false)
|
||||
, _headerSize(6)
|
||||
, _ligthBerryAPA102Mode(false)
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
connect(this,SIGNAL(receivedData(QByteArray)),this,SLOT(receivedData(QByteArray)));
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceAdalight::construct(const QJsonObject &deviceConfig)
|
||||
@@ -18,43 +18,49 @@ LedDevice* LedDeviceAdalight::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceAdalight::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderRs232::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
_ligthBerryAPA102Mode = deviceConfig["lightberry_apa102_mode"].toBool(false);
|
||||
|
||||
// create ledBuffer
|
||||
unsigned int totalLedCount = _ledCount;
|
||||
|
||||
if (_ligthBerryAPA102Mode)
|
||||
// Initialise sub-class
|
||||
if ( ProviderRs232::init(deviceConfig) )
|
||||
{
|
||||
const unsigned int startFrameSize = 4;
|
||||
const unsigned int bytesPerRGBLed = 4;
|
||||
const unsigned int endFrameSize = qMax<unsigned int>(((_ledCount + 15) / 16), bytesPerRGBLed);
|
||||
_ledBuffer.resize(_headerSize + (_ledCount * bytesPerRGBLed) + startFrameSize + endFrameSize, 0x00);
|
||||
|
||||
// init constant data values
|
||||
for (signed iLed=1; iLed<= static_cast<int>( _ledCount); iLed++)
|
||||
|
||||
_ligthBerryAPA102Mode = deviceConfig["lightberry_apa102_mode"].toBool(false);
|
||||
|
||||
// create ledBuffer
|
||||
unsigned int totalLedCount = _ledCount;
|
||||
|
||||
if (_ligthBerryAPA102Mode)
|
||||
{
|
||||
_ledBuffer[iLed*4+_headerSize] = 0xFF;
|
||||
const unsigned int startFrameSize = 4;
|
||||
const unsigned int bytesPerRGBLed = 4;
|
||||
const unsigned int endFrameSize = qMax<unsigned int>(((_ledCount + 15) / 16), bytesPerRGBLed);
|
||||
_ledBuffer.resize(_headerSize + (_ledCount * bytesPerRGBLed) + startFrameSize + endFrameSize, 0x00);
|
||||
|
||||
// init constant data values
|
||||
for (signed iLed=1; iLed<= static_cast<int>( _ledCount); iLed++)
|
||||
{
|
||||
_ledBuffer[iLed*4+_headerSize] = 0xFF;
|
||||
}
|
||||
Debug( _log, "Adalight driver with activated LightBerry APA102 mode");
|
||||
}
|
||||
Debug( _log, "Adalight driver with activated LightBerry APA102 mode");
|
||||
else
|
||||
{
|
||||
totalLedCount -= 1;
|
||||
_ledBuffer.resize(_headerSize + _ledRGBCount, 0x00);
|
||||
}
|
||||
|
||||
_ledBuffer[0] = 'A';
|
||||
_ledBuffer[1] = 'd';
|
||||
_ledBuffer[2] = 'a';
|
||||
_ledBuffer[3] = (totalLedCount >> 8) & 0xFF; // LED count high byte
|
||||
_ledBuffer[4] = totalLedCount & 0xFF; // LED count low byte
|
||||
_ledBuffer[5] = _ledBuffer[3] ^ _ledBuffer[4] ^ 0x55; // Checksum
|
||||
|
||||
Debug( _log, "Adalight header for %d leds: %c%c%c 0x%02x 0x%02x 0x%02x", _ledCount,
|
||||
_ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3], _ledBuffer[4], _ledBuffer[5] );
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
totalLedCount -= 1;
|
||||
_ledBuffer.resize(_headerSize + _ledRGBCount, 0x00);
|
||||
}
|
||||
|
||||
_ledBuffer[0] = 'A';
|
||||
_ledBuffer[1] = 'd';
|
||||
_ledBuffer[2] = 'a';
|
||||
_ledBuffer[3] = (totalLedCount >> 8) & 0xFF; // LED count high byte
|
||||
_ledBuffer[4] = totalLedCount & 0xFF; // LED count low byte
|
||||
_ledBuffer[5] = _ledBuffer[3] ^ _ledBuffer[4] ^ 0x55; // Checksum
|
||||
|
||||
Debug( _log, "Adalight header for %d leds: %c%c%c 0x%02x 0x%02x 0x%02x", _ledCount,
|
||||
_ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3], _ledBuffer[4], _ledBuffer[5] );
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
@@ -74,11 +80,8 @@ int LedDeviceAdalight::write(const std::vector<ColorRgb> & ledValues)
|
||||
{
|
||||
memcpy(_headerSize + _ledBuffer.data(), ledValues.data(), ledValues.size() * 3);
|
||||
}
|
||||
|
||||
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
|
||||
}
|
||||
|
||||
void LedDeviceAdalight::receivedData(QByteArray data)
|
||||
{
|
||||
Debug(_log, ">>received %d bytes data", data.size());
|
||||
int rc = writeBytes(_ledBuffer.size(), _ledBuffer.data());
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@@ -1,37 +1,47 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICETADALIGHT_H
|
||||
#define LEDEVICETADALIGHT_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderRs232.h"
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for writing to an Adalight led device.
|
||||
/// Implementation of the LedDevice interface for writing to an Adalight LED-device.
|
||||
///
|
||||
class LedDeviceAdalight : public ProviderRs232
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs an Adalight LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceAdalight(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
void receivedData(QByteArray data);
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
@@ -39,3 +49,4 @@ private:
|
||||
bool _ligthBerryAPA102Mode;
|
||||
};
|
||||
|
||||
#endif // LEDEVICETADALIGHT_H
|
||||
|
@@ -5,9 +5,12 @@ LedDeviceAtmo::LedDeviceAtmo(const QJsonObject &deviceConfig)
|
||||
: ProviderRs232()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
|
||||
LedDevice* LedDeviceAtmo::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceAtmo(deviceConfig);
|
||||
@@ -15,13 +18,13 @@ LedDevice* LedDeviceAtmo::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceAtmo::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderRs232::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
if ( isInitOK )
|
||||
// Initialise sub-class
|
||||
if ( ProviderRs232::init(deviceConfig) )
|
||||
{
|
||||
if (_ledCount != 5)
|
||||
{
|
||||
//Error( _log, "%d channels configured. This should always be 5!", _ledCount);
|
||||
QString errortext = QString ("%1 channels configured. This should always be 5!").arg(_ledCount);
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
@@ -33,6 +36,8 @@ bool LedDeviceAtmo::init(const QJsonObject &deviceConfig)
|
||||
_ledBuffer[1] = 0x00; // StartChannel(Low)
|
||||
_ledBuffer[2] = 0x00; // StartChannel(High)
|
||||
_ledBuffer[3] = 0x0F; // Number of Databytes send (always! 15)
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEATMO_H
|
||||
#define LEDEVICEATMO_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderRs232.h"
|
||||
@@ -9,24 +10,35 @@
|
||||
class LedDeviceAtmo : public ProviderRs232
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs an Atmo LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceAtmo(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Destructor of the LedDevice
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEATMO_H
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#include "LedDeviceDMX.h"
|
||||
|
||||
#include <QSerialPort>
|
||||
#ifndef _WIN32
|
||||
#include <time.h>
|
||||
@@ -13,9 +14,12 @@ LedDeviceDMX::LedDeviceDMX(const QJsonObject &deviceConfig)
|
||||
, _dmxChannelCount(0)
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
|
||||
LedDevice* LedDeviceDMX::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceDMX(deviceConfig);
|
||||
@@ -23,18 +27,19 @@ LedDevice* LedDeviceDMX::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceDMX::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderRs232::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
if ( isInitOK )
|
||||
// Initialise sub-class
|
||||
if ( ProviderRs232::init(deviceConfig) )
|
||||
{
|
||||
QString dmxString = deviceConfig["dmxdevice"].toString("invalid");
|
||||
if (dmxString == "raw")
|
||||
QString dmxTypeString = deviceConfig["dmxtype"].toString("invalid");
|
||||
if (dmxTypeString == "raw")
|
||||
{
|
||||
_dmxDeviceType = 0;
|
||||
_dmxStart = 1;
|
||||
_dmxSlotsPerLed = 3;
|
||||
}
|
||||
else if (dmxString == "McCrypt")
|
||||
else if (dmxTypeString == "McCrypt")
|
||||
{
|
||||
_dmxDeviceType = 1;
|
||||
_dmxStart = 1;
|
||||
@@ -43,12 +48,12 @@ bool LedDeviceDMX::init(const QJsonObject &deviceConfig)
|
||||
else
|
||||
{
|
||||
//Error(_log, "unknown dmx device type %s", QSTRING_CSTR(dmxString));
|
||||
QString errortext = QString ("unknown dmx device type: %1").arg(dmxString);
|
||||
QString errortext = QString ("unknown dmx device type: %1").arg(dmxTypeString);
|
||||
this->setInError(errortext);
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug(_log, "_dmxString \"%s\", _dmxDeviceType %d", QSTRING_CSTR(dmxString), _dmxDeviceType );
|
||||
Debug(_log, "_dmxTypeString \"%s\", _dmxDeviceType %d", QSTRING_CSTR(dmxTypeString), _dmxDeviceType );
|
||||
_rs232Port.setStopBits(QSerialPort::TwoStop);
|
||||
|
||||
_dmxLedCount = qMin(static_cast<int>(_ledCount), 512/_dmxSlotsPerLed);
|
||||
@@ -59,6 +64,8 @@ bool LedDeviceDMX::init(const QJsonObject &deviceConfig)
|
||||
|
||||
_ledBuffer.resize(_dmxChannelCount, 0);
|
||||
_ledBuffer[0] = 0x00; // NULL START code
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
@@ -1,37 +1,53 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEDMX_H
|
||||
#define LEDEVICEDMX_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderRs232.h"
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for writing to DMX512 rs232 led device.
|
||||
/// Implementation of the LedDevice interface for writing to DMX512 rs232 LED-device.
|
||||
///
|
||||
class LedDeviceDMX : public ProviderRs232
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a DMX LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceDMX(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
int _dmxDeviceType = 0;
|
||||
int _dmxStart = 1;
|
||||
int _dmxSlotsPerLed = 3;
|
||||
int _dmxLedCount = 0;
|
||||
unsigned int _dmxChannelCount = 0;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEDMX_H
|
||||
|
@@ -5,9 +5,9 @@ LedDeviceKarate::LedDeviceKarate(const QJsonObject &deviceConfig)
|
||||
: ProviderRs232()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
connect(this,SIGNAL(receivedData(QByteArray)),this,SLOT(receivedData(QByteArray)));
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceKarate::construct(const QJsonObject &deviceConfig)
|
||||
@@ -17,9 +17,10 @@ LedDevice* LedDeviceKarate::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceKarate::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderRs232::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
if ( isInitOK )
|
||||
// Initialise sub-class
|
||||
if ( ProviderRs232::init(deviceConfig) )
|
||||
{
|
||||
if (_ledCount != 16)
|
||||
{
|
||||
@@ -30,15 +31,16 @@ bool LedDeviceKarate::init(const QJsonObject &deviceConfig)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
_ledBuffer.resize(4 + _ledCount * 3); // 4-byte header, 3 RGB values
|
||||
_ledBuffer[0] = 0xAA; // Startbyte
|
||||
_ledBuffer[1] = 0x12; // Send all Channels in Batch
|
||||
_ledBuffer[2] = 0x00; // Checksum
|
||||
_ledBuffer[3] = _ledCount * 3; // Number of Databytes send
|
||||
_ledBuffer[0] = 0xAA; // Startbyte
|
||||
_ledBuffer[1] = 0x12; // Send all Channels in Batch
|
||||
_ledBuffer[2] = 0x00; // Checksum
|
||||
_ledBuffer[3] = _ledCount * 3; // Number of Databytes send
|
||||
|
||||
Debug( _log, "Karatelight header for %d leds: 0x%02x 0x%02x 0x%02x 0x%02x", _ledCount,
|
||||
_ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3] );
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
@@ -62,8 +64,3 @@ int LedDeviceKarate::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
||||
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
|
||||
}
|
||||
|
||||
void LedDeviceKarate::receivedData(QByteArray data)
|
||||
{
|
||||
Debug(_log, ">>received %d bytes data %s", data.size(),data.data());
|
||||
}
|
||||
|
@@ -1,36 +1,47 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEKARATE_H
|
||||
#define LEDEVICEKARATE_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderRs232.h"
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for writing to serial device using tpm2 protocol.
|
||||
/// Implementation of the LedDevice interface for writing to serial device
|
||||
///
|
||||
class LedDeviceKarate : public ProviderRs232
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a Karate LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceKarate(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
void receivedData(QByteArray data);
|
||||
|
||||
private:
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEKARATE_H
|
||||
|
@@ -10,7 +10,9 @@ LedDeviceSedu::LedDeviceSedu(const QJsonObject &deviceConfig)
|
||||
: ProviderRs232()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceSedu::construct(const QJsonObject &deviceConfig)
|
||||
@@ -20,31 +22,37 @@ LedDevice* LedDeviceSedu::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceSedu::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderRs232::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
std::vector<FrameSpec> frameSpecs{{0xA1, 256}, {0xA2, 512}, {0xB0, 768}, {0xB1, 1536}, {0xB2, 3072} };
|
||||
|
||||
for (const FrameSpec& frameSpec : frameSpecs)
|
||||
// Initialise sub-class
|
||||
if ( ProviderRs232::init(deviceConfig) )
|
||||
{
|
||||
if ((unsigned)_ledRGBCount <= frameSpec.size)
|
||||
std::vector<FrameSpec> frameSpecs{{0xA1, 256}, {0xA2, 512}, {0xB0, 768}, {0xB1, 1536}, {0xB2, 3072} };
|
||||
|
||||
for (const FrameSpec& frameSpec : frameSpecs)
|
||||
{
|
||||
_ledBuffer.clear();
|
||||
_ledBuffer.resize(frameSpec.size + 3, 0);
|
||||
_ledBuffer[0] = 0x5A;
|
||||
_ledBuffer[1] = frameSpec.id;
|
||||
_ledBuffer.back() = 0xA5;
|
||||
break;
|
||||
if ((unsigned)_ledRGBCount <= frameSpec.size)
|
||||
{
|
||||
_ledBuffer.clear();
|
||||
_ledBuffer.resize(frameSpec.size + 3, 0);
|
||||
_ledBuffer[0] = 0x5A;
|
||||
_ledBuffer[1] = frameSpec.id;
|
||||
_ledBuffer.back() = 0xA5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_ledBuffer.empty())
|
||||
{
|
||||
//Warning(_log, "More rgb-channels required then available");
|
||||
QString errortext = "More rgb-channels required then available";
|
||||
this->setInError(errortext);
|
||||
}
|
||||
else
|
||||
{
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_ledBuffer.size() == 0)
|
||||
{
|
||||
//Warning(_log, "More rgb-channels required then available");
|
||||
QString errortext = "More rgb-channels required then available";
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
|
@@ -1,32 +1,47 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICESEDU_H
|
||||
#define LEDEVICESEDU_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderRs232.h"
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for writing to SEDU led device.
|
||||
/// Implementation of the LedDevice interface for writing to SEDU LED-device.
|
||||
///
|
||||
class LedDeviceSedu : public ProviderRs232
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a SEDU LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceSedu(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
||||
#endif // LEDEVICESEDU_H
|
||||
|
@@ -5,9 +5,12 @@ LedDeviceTpm2::LedDeviceTpm2(const QJsonObject &deviceConfig)
|
||||
: ProviderRs232()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
|
||||
LedDevice* LedDeviceTpm2::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceTpm2(deviceConfig);
|
||||
@@ -15,15 +18,21 @@ LedDevice* LedDeviceTpm2::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceTpm2::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderRs232::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
_ledBuffer.resize(5 + _ledRGBCount);
|
||||
_ledBuffer[0] = 0xC9; // block-start byte
|
||||
_ledBuffer[1] = 0xDA; // DATA frame
|
||||
_ledBuffer[2] = (_ledRGBCount >> 8) & 0xFF; // frame size high byte
|
||||
_ledBuffer[3] = _ledRGBCount & 0xFF; // frame size low byte
|
||||
_ledBuffer.back() = 0x36; // block-end byte
|
||||
// Initialise sub-class
|
||||
if ( ProviderRs232::init(deviceConfig) )
|
||||
{
|
||||
|
||||
_ledBuffer.resize(5 + _ledRGBCount);
|
||||
_ledBuffer[0] = 0xC9; // block-start byte
|
||||
_ledBuffer[1] = 0xDA; // DATA frame
|
||||
_ledBuffer[2] = (_ledRGBCount >> 8) & 0xFF; // frame size high byte
|
||||
_ledBuffer[3] = _ledRGBCount & 0xFF; // frame size low byte
|
||||
_ledBuffer.back() = 0x36; // block-end byte
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICETPM2_H
|
||||
#define LEDEVICETPM2_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderRs232.h"
|
||||
@@ -9,24 +10,38 @@
|
||||
class LedDeviceTpm2 : public ProviderRs232
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a TPM 2 LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceTpm2(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
||||
#endif // LEDEVICETPM2_H
|
||||
|
@@ -1,290 +1,297 @@
|
||||
|
||||
// STL includes
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
// Qt includes
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
#include <QSerialPortInfo>
|
||||
|
||||
// Local Hyperion includes
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
#include "ProviderRs232.h"
|
||||
|
||||
// qt includes
|
||||
#include <QSerialPortInfo>
|
||||
#include <QEventLoop>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
// Constants
|
||||
constexpr std::chrono::milliseconds WRITE_TIMEOUT{1000}; // device write timeout in ms
|
||||
constexpr std::chrono::milliseconds OPEN_TIMEOUT{5000}; // device open timeout in ms
|
||||
const int MAX_WRITE_TIMEOUTS = 5; // maximum number of allowed timeouts
|
||||
|
||||
const int NUM_POWEROFF_WRITE_BLACK = 2; // Number of write "BLACK" during powering off
|
||||
|
||||
ProviderRs232::ProviderRs232()
|
||||
: _rs232Port(this)
|
||||
, _writeTimeout(this)
|
||||
, _blockedForDelay(false)
|
||||
, _stateChanged(true)
|
||||
, _bytesToWrite(0)
|
||||
, _frameDropCounter(0)
|
||||
, _lastError(QSerialPort::NoError)
|
||||
, _preOpenDelayTimeOut(0)
|
||||
, _preOpenDelay(2000)
|
||||
, _enableAutoDeviceName(false)
|
||||
,_baudRate_Hz(1000000)
|
||||
,_isAutoDeviceName(false)
|
||||
,_delayAfterConnect_ms(0)
|
||||
,_frameDropCounter(0)
|
||||
{
|
||||
connect(&_rs232Port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(error(QSerialPort::SerialPortError)));
|
||||
connect(&_rs232Port, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64)));
|
||||
connect(&_rs232Port, SIGNAL(readyRead()), this, SLOT(readyRead()));
|
||||
|
||||
_writeTimeout.setInterval(5000);
|
||||
_writeTimeout.setSingleShot(true);
|
||||
connect(&_writeTimeout, SIGNAL(timeout()), this, SLOT(writeTimeout()));
|
||||
}
|
||||
|
||||
bool ProviderRs232::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
closeDevice();
|
||||
bool isInitOK = false;
|
||||
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
// Initialise sub-class
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
|
||||
_deviceName = deviceConfig["output"].toString("auto");
|
||||
_enableAutoDeviceName = _deviceName == "auto";
|
||||
_baudRate_Hz = deviceConfig["rate"].toInt();
|
||||
_delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(1500);
|
||||
_preOpenDelay = deviceConfig["delayBeforeConnect"].toInt(1500);
|
||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
||||
Debug(_log, "LedCount : %u", this->getLedCount());
|
||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
||||
Debug(_log, "RefreshTime : %d", _refreshTimerInterval_ms);
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
|
||||
_deviceName = deviceConfig["output"].toString("auto");
|
||||
|
||||
// If device name was given as unix /dev/ system-location, get port name
|
||||
if ( _deviceName.startsWith(QLatin1String("/dev/")) )
|
||||
_deviceName = _deviceName.mid(5);
|
||||
|
||||
_isAutoDeviceName = _deviceName.toLower() == "auto";
|
||||
_baudRate_Hz = deviceConfig["rate"].toInt();
|
||||
_delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(1500);
|
||||
|
||||
Debug(_log, "deviceName : %s", QSTRING_CSTR(_deviceName));
|
||||
Debug(_log, "AutoDevice : %d", _isAutoDeviceName);
|
||||
Debug(_log, "baudRate_Hz : %d", _baudRate_Hz);
|
||||
Debug(_log, "delayAfCon ms: %d", _delayAfterConnect_ms);
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
|
||||
void ProviderRs232::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
// LedDevice specific closing activites
|
||||
closeDevice();
|
||||
}
|
||||
|
||||
QString ProviderRs232::findSerialDevice()
|
||||
{
|
||||
// take first available usb serial port - currently no probing!
|
||||
for( auto port : QSerialPortInfo::availablePorts())
|
||||
{
|
||||
if (port.hasProductIdentifier() && port.hasVendorIdentifier() && !port.isBusy())
|
||||
{
|
||||
Info(_log, "found serial device: %s", port.systemLocation().toLocal8Bit().constData());
|
||||
return port.systemLocation();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void ProviderRs232::bytesWritten(qint64 bytes)
|
||||
{
|
||||
_bytesToWrite -= bytes;
|
||||
if (_bytesToWrite <= 0)
|
||||
{
|
||||
_blockedForDelay = false;
|
||||
_writeTimeout.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ProviderRs232::readyRead()
|
||||
{
|
||||
emit receivedData(_rs232Port.readAll());
|
||||
//Debug(_log, "received data");
|
||||
}
|
||||
|
||||
|
||||
void ProviderRs232::error(QSerialPort::SerialPortError error)
|
||||
{
|
||||
if ( error != QSerialPort::NoError )
|
||||
{
|
||||
if (_lastError != error)
|
||||
{
|
||||
_lastError = error;
|
||||
switch (error)
|
||||
{
|
||||
case QSerialPort::DeviceNotFoundError:
|
||||
Error(_log, "An error occurred while attempting to open an non-existing device."); break;
|
||||
case QSerialPort::PermissionError:
|
||||
Error(_log, "An error occurred while attempting to open an already opened device by another process or a user not having enough permission and credentials to open. Device disabled.");
|
||||
_deviceReady = false;
|
||||
break;
|
||||
case QSerialPort::OpenError:
|
||||
Error(_log, "An error occurred while attempting to open an already opened device in this object."); break;
|
||||
case QSerialPort::NotOpenError:
|
||||
Error(_log, "This error occurs when an operation is executed that can only be successfully performed if the device is open."); break;
|
||||
case QSerialPort::ParityError:
|
||||
Error(_log, "Parity error detected by the hardware while reading data."); break;
|
||||
case QSerialPort::FramingError:
|
||||
Error(_log, "Framing error detected by the hardware while reading data."); break;
|
||||
case QSerialPort::BreakConditionError:
|
||||
Error(_log, "Break condition detected by the hardware on the input line."); break;
|
||||
case QSerialPort::WriteError:
|
||||
Error(_log, "An I/O error occurred while writing the data."); break;
|
||||
case QSerialPort::ReadError:
|
||||
Error(_log, "An I/O error occurred while reading the data."); break;
|
||||
case QSerialPort::ResourceError:
|
||||
Error(_log, "An I/O error occurred when a resource becomes unavailable, e.g. when the device is unexpectedly removed from the system."); break;
|
||||
case QSerialPort::UnsupportedOperationError:
|
||||
Error(_log, "The requested device operation is not supported or prohibited by the running operating system. Device disabled.");
|
||||
_deviceReady = false;
|
||||
break;
|
||||
case QSerialPort::TimeoutError:
|
||||
Error(_log, "A timeout error occurred."); break;
|
||||
default:
|
||||
Error(_log,"An unidentified error occurred. Device disabled. (%d)", error);
|
||||
_deviceReady = false;
|
||||
}
|
||||
_rs232Port.clearError();
|
||||
this->setInError( "Rs232 SerialPortError, see details in previous log lines!" );
|
||||
closeDevice();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProviderRs232::~ProviderRs232()
|
||||
{
|
||||
disconnect(&_rs232Port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(error(QSerialPort::SerialPortError)));
|
||||
}
|
||||
|
||||
void ProviderRs232::closeDevice()
|
||||
{
|
||||
_writeTimeout.stop();
|
||||
|
||||
if (_rs232Port.isOpen())
|
||||
{
|
||||
_rs232Port.close();
|
||||
Debug(_log,"Close UART: %s", _deviceName.toLocal8Bit().constData());
|
||||
}
|
||||
|
||||
_stateChanged = true;
|
||||
_bytesToWrite = 0;
|
||||
_blockedForDelay = false;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
int ProviderRs232::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
_isInSwitchOff = false;
|
||||
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
// open device physically
|
||||
if ( tryOpen(_delayAfterConnect_ms) )
|
||||
{
|
||||
if ( tryOpen(_delayAfterConnect_ms) )
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setInError( "Error opening device!" );
|
||||
}
|
||||
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ProviderRs232::close()
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
_isDeviceReady = false;
|
||||
|
||||
// Test, if device requires closing
|
||||
if (_rs232Port.isOpen())
|
||||
{
|
||||
if ( _rs232Port.flush() )
|
||||
{
|
||||
Debug(_log,"Flush was successful");
|
||||
}
|
||||
Debug(_log,"Close UART: %s", QSTRING_CSTR(_deviceName) );
|
||||
_rs232Port.close();
|
||||
// Everything is OK -> device is closed
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool ProviderRs232::powerOff()
|
||||
{
|
||||
// Simulate power-off by writing a final "Black" to have a defined outcome
|
||||
bool rc = false;
|
||||
if ( writeBlack( NUM_POWEROFF_WRITE_BLACK ) >= 0 )
|
||||
{
|
||||
rc = true;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool ProviderRs232::tryOpen(const int delayAfterConnect_ms)
|
||||
{
|
||||
if (_deviceName.isEmpty() || _rs232Port.portName().isEmpty())
|
||||
{
|
||||
if ( _enableAutoDeviceName )
|
||||
if (!_rs232Port.isOpen())
|
||||
{
|
||||
_deviceName = findSerialDevice();
|
||||
if ( _deviceName.isEmpty() )
|
||||
if ( _isAutoDeviceName )
|
||||
{
|
||||
return false;
|
||||
_deviceName = discoverFirst();
|
||||
if (_deviceName.isEmpty())
|
||||
{
|
||||
this->setInError( QString("No serial device found automatically!") );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Info(_log, "Opening UART: %s", _deviceName.toLocal8Bit().constData());
|
||||
|
||||
_rs232Port.setPortName(_deviceName);
|
||||
}
|
||||
|
||||
if ( ! _rs232Port.isOpen() )
|
||||
if (!_rs232Port.isOpen())
|
||||
{
|
||||
Info(_log, "Opening UART: %s", QSTRING_CSTR(_deviceName));
|
||||
|
||||
_frameDropCounter = 0;
|
||||
|
||||
_rs232Port.setBaudRate( _baudRate_Hz );
|
||||
|
||||
Debug(_log, "_rs232Port.open(QIODevice::WriteOnly): %s, Baud rate [%d]bps", QSTRING_CSTR(_deviceName), _baudRate_Hz);
|
||||
|
||||
QSerialPortInfo serialPortInfo(_deviceName);
|
||||
if (! serialPortInfo.isNull())
|
||||
|
||||
QJsonObject portInfo;
|
||||
Debug(_log, "portName: %s", QSTRING_CSTR(serialPortInfo.portName()));
|
||||
Debug(_log, "systemLocation: %s", QSTRING_CSTR(serialPortInfo.systemLocation()));
|
||||
Debug(_log, "description: %s", QSTRING_CSTR(serialPortInfo.description()));
|
||||
Debug(_log, "manufacturer: %s", QSTRING_CSTR(serialPortInfo.manufacturer()));
|
||||
Debug(_log, "productIdentifier: %s", QSTRING_CSTR(QString("0x%1").arg(serialPortInfo.productIdentifier(), 0, 16)));
|
||||
Debug(_log, "vendorIdentifier: %s", QSTRING_CSTR(QString("0x%1").arg(serialPortInfo.vendorIdentifier(), 0, 16)));
|
||||
Debug(_log, "serialNumber: %s", QSTRING_CSTR(serialPortInfo.serialNumber()));
|
||||
|
||||
if (!serialPortInfo.isNull() )
|
||||
{
|
||||
if ( _preOpenDelayTimeOut > QDateTime::currentMSecsSinceEpoch() )
|
||||
if ( !_rs232Port.open(QIODevice::WriteOnly) )
|
||||
{
|
||||
this->setInError(_rs232Port.errorString());
|
||||
return false;
|
||||
}
|
||||
if ( ! _rs232Port.open(QIODevice::ReadWrite) )
|
||||
{
|
||||
if ( _stateChanged )
|
||||
{
|
||||
Error(_log, "Unable to open RS232 device (%s)", _deviceName.toLocal8Bit().constData());
|
||||
_stateChanged = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Debug(_log, "Setting baud rate to %d", _baudRate_Hz);
|
||||
_rs232Port.setBaudRate(_baudRate_Hz);
|
||||
_stateChanged = true;
|
||||
_preOpenDelayTimeOut = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
QString errortext = QString("Invalid serial device name: [%1]!").arg(_deviceName);
|
||||
this->setInError(errortext);
|
||||
_preOpenDelayTimeOut = QDateTime::currentMSecsSinceEpoch() + _preOpenDelay;
|
||||
this->setInError( errortext );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (delayAfterConnect_ms > 0)
|
||||
{
|
||||
_blockedForDelay = true;
|
||||
QTimer::singleShot(delayAfterConnect_ms, this, SLOT(unblockAfterDelay()));
|
||||
Debug(_log, "Device blocked for %d ms", delayAfterConnect_ms);
|
||||
|
||||
Debug(_log, "delayAfterConnect for %d ms - start", delayAfterConnect_ms);
|
||||
|
||||
// Wait delayAfterConnect_ms before allowing write
|
||||
QEventLoop loop;
|
||||
QTimer::singleShot( delayAfterConnect_ms, &loop, SLOT( quit() ) );
|
||||
loop.exec();
|
||||
|
||||
Debug(_log, "delayAfterConnect for %d ms - finished", delayAfterConnect_ms);
|
||||
}
|
||||
|
||||
return _rs232Port.isOpen();
|
||||
}
|
||||
|
||||
|
||||
int ProviderRs232::writeBytes(const qint64 size, const uint8_t * data)
|
||||
void ProviderRs232::setInError(const QString& errorMsg)
|
||||
{
|
||||
if (! _blockedForDelay)
|
||||
{
|
||||
if (!_rs232Port.isOpen())
|
||||
{
|
||||
return tryOpen(5000) ? 0 : -1;
|
||||
}
|
||||
_rs232Port.clearError();
|
||||
this->close();
|
||||
|
||||
if (_frameDropCounter > 5)
|
||||
LedDevice::setInError( errorMsg );
|
||||
}
|
||||
|
||||
int ProviderRs232::writeBytes(const qint64 size, const uint8_t *data)
|
||||
{
|
||||
DebugIf(_isInSwitchOff, _log, "_inClosing [%d], enabled [%d], _deviceReady [%d], _frameDropCounter [%d]", _isInSwitchOff, this->isEnabled(), _isDeviceReady, _frameDropCounter);
|
||||
|
||||
int rc = 0;
|
||||
if (!_rs232Port.isOpen())
|
||||
{
|
||||
Debug(_log, "!_rs232Port.isOpen()");
|
||||
|
||||
if ( !tryOpen(OPEN_TIMEOUT.count()) )
|
||||
{
|
||||
Debug(_log, "%d frames dropped", _frameDropCounter);
|
||||
}
|
||||
_frameDropCounter = 0;
|
||||
_blockedForDelay = true;
|
||||
_bytesToWrite = size;
|
||||
qint64 bytesWritten = _rs232Port.write(reinterpret_cast<const char*>(data), size);
|
||||
if (bytesWritten == -1 || bytesWritten != size)
|
||||
{
|
||||
Warning(_log,"failed writing data");
|
||||
QTimer::singleShot(500, this, SLOT(unblockAfterDelay()));
|
||||
return -1;
|
||||
}
|
||||
_writeTimeout.start();
|
||||
}
|
||||
|
||||
DebugIf( _isInSwitchOff, _log, "[%s]", QSTRING_CSTR(uint8_t_to_hex_string(data, size, 32)) );
|
||||
|
||||
qint64 bytesWritten = _rs232Port.write(reinterpret_cast<const char*>(data), size);
|
||||
if (bytesWritten == -1 || bytesWritten != size)
|
||||
{
|
||||
this->setInError( QString ("Rs232 SerialPortError: %1").arg(_rs232Port.errorString()) );
|
||||
rc = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_frameDropCounter++;
|
||||
if (!_rs232Port.waitForBytesWritten(WRITE_TIMEOUT.count()))
|
||||
{
|
||||
if ( _rs232Port.error() == QSerialPort::TimeoutError )
|
||||
{
|
||||
Debug(_log, "Timeout after %dms: %d frames already dropped", WRITE_TIMEOUT, _frameDropCounter);
|
||||
|
||||
++_frameDropCounter;
|
||||
|
||||
// Check,if number of timeouts in a given time frame is greater than defined
|
||||
// TODO: ProviderRs232::writeBytes - Add time frame to check for timeouts that devices does not close after absolute number of timeouts
|
||||
if ( _frameDropCounter > MAX_WRITE_TIMEOUTS )
|
||||
{
|
||||
this->setInError( QString ("Timeout writing data to %1").arg(_deviceName) );
|
||||
rc = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//give it another try
|
||||
_rs232Port.clearError();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setInError( QString ("Rs232 SerialPortError: %1").arg(_rs232Port.errorString()) );
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugIf(_isInSwitchOff,_log, "In Closing: bytesWritten [%d], _rs232Port.error() [%d], %s", bytesWritten, _rs232Port.error(), _rs232Port.error() == QSerialPort::NoError ? "No Error" : QSTRING_CSTR(_rs232Port.errorString()) );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
DebugIf(_isInSwitchOff, _log, "[%d], _inClosing[%d], enabled [%d], _deviceReady [%d]", rc, _isInSwitchOff, this->isEnabled(), _isDeviceReady);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ProviderRs232::writeTimeout()
|
||||
QString ProviderRs232::discoverFirst()
|
||||
{
|
||||
//Error(_log, "Timeout on write data to %s", _deviceName.toLocal8Bit().constData());
|
||||
QString errortext = QString ("Timeout on write data to %1").arg(_deviceName);
|
||||
setInError( errortext );
|
||||
close();
|
||||
// take first available USB serial port - currently no probing!
|
||||
for (auto const & port : QSerialPortInfo::availablePorts())
|
||||
{
|
||||
if (!port.isNull() && !port.isBusy())
|
||||
{
|
||||
Info(_log, "found serial device: %s", QSTRING_CSTR(port.portName()));
|
||||
return port.portName();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void ProviderRs232::unblockAfterDelay()
|
||||
QJsonObject ProviderRs232::discover()
|
||||
{
|
||||
_blockedForDelay = false;
|
||||
QJsonObject devicesDiscovered;
|
||||
devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
|
||||
|
||||
QJsonArray deviceList;
|
||||
|
||||
// Discover serial Devices
|
||||
for (auto &port : QSerialPortInfo::availablePorts() )
|
||||
{
|
||||
if ( !port.isNull() )
|
||||
{
|
||||
QJsonObject portInfo;
|
||||
portInfo.insert("description", port.description());
|
||||
portInfo.insert("manufacturer", port.manufacturer());
|
||||
portInfo.insert("portName", port.portName());
|
||||
portInfo.insert("productIdentifier", QString("0x%1").arg(port.productIdentifier(), 0, 16));
|
||||
portInfo.insert("serialNumber", port.serialNumber());
|
||||
portInfo.insert("systemLocation", port.systemLocation());
|
||||
portInfo.insert("vendorIdentifier", QString("0x%1").arg(port.vendorIdentifier(), 0, 16));
|
||||
|
||||
deviceList.append(portInfo);
|
||||
}
|
||||
}
|
||||
|
||||
devicesDiscovered.insert("devices", deviceList);
|
||||
return devicesDiscovered;
|
||||
}
|
||||
|
@@ -1,13 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QSerialPort>
|
||||
#include <QTimer>
|
||||
#include <QString>
|
||||
#ifndef PROVIDERRS232_H
|
||||
#define PROVIDERRS232_H
|
||||
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
|
||||
// qt includes
|
||||
#include <QSerialPort>
|
||||
|
||||
///
|
||||
/// The ProviderRs232 implements an abstract base-class for LedDevices using a RS232-device.
|
||||
///
|
||||
@@ -16,91 +15,106 @@ class ProviderRs232 : public LedDevice
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a RS232 LED-device
|
||||
///
|
||||
ProviderRs232();
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
/// @brief Destructor of the UDP LED-device
|
||||
///
|
||||
virtual ~ProviderRs232() override;
|
||||
|
||||
///
|
||||
/// Opens and configures the output device
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
int open() override;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
private slots:
|
||||
|
||||
/// Unblock the device after a connection delay
|
||||
void writeTimeout();
|
||||
void unblockAfterDelay();
|
||||
void error(QSerialPort::SerialPortError setInError);
|
||||
void bytesWritten(qint64 bytes);
|
||||
void readyRead();
|
||||
|
||||
signals:
|
||||
void receivedData(QByteArray data);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Writes the given bytes to the RS232-device and
|
||||
*
|
||||
* @param[in[ size The length of the data
|
||||
* @param[in] data The data
|
||||
*
|
||||
* @return Zero on success else negative
|
||||
*/
|
||||
|
||||
///
|
||||
/// @brief Initialise the RS232 device's configuration and network address details
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens the output device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
///
|
||||
/// @brief Closes the UDP device.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is closed), else negative
|
||||
///
|
||||
virtual int close() override;
|
||||
|
||||
///
|
||||
/// @brief Power-/turn off a RS232-device
|
||||
///
|
||||
/// The off-state is simulated by writing "Black to LED"
|
||||
///
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool powerOff() override;
|
||||
|
||||
///
|
||||
/// @brief Discover first devices of a serial device available (for configuration)
|
||||
///
|
||||
/// @return A string of the device found
|
||||
///
|
||||
virtual QString discoverFirst() override;
|
||||
|
||||
///
|
||||
/// @brief Discover RS232 serial devices available (for configuration).
|
||||
///
|
||||
/// @return A JSON structure holding a list of devices found
|
||||
///
|
||||
virtual QJsonObject discover() override;
|
||||
|
||||
///
|
||||
/// @brief Write the given bytes to the RS232-device
|
||||
///
|
||||
/// @param[in[ size The length of the data
|
||||
/// @param[in] data The data
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
int writeBytes(const qint64 size, const uint8_t *data);
|
||||
|
||||
void closeDevice();
|
||||
|
||||
QString findSerialDevice();
|
||||
|
||||
// tries to open device if not opened
|
||||
bool tryOpen(const int delayAfterConnect_ms);
|
||||
|
||||
|
||||
/// The name of the output device
|
||||
QString _deviceName;
|
||||
|
||||
/// The used baudrate of the output device
|
||||
/// The RS232 serial-device
|
||||
QSerialPort _rs232Port;
|
||||
/// The used baud-rate of the output device
|
||||
qint32 _baudRate_Hz;
|
||||
|
||||
protected slots:
|
||||
|
||||
///
|
||||
/// @brief Set device in error state
|
||||
///
|
||||
/// @param errorMsg The error message to be logged
|
||||
///
|
||||
virtual void setInError( const QString& errorMsg) override;
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// @brief Try to open device if not opened
|
||||
///
|
||||
/// @return True,if on success
|
||||
///
|
||||
bool tryOpen(const int delayAfterConnect_ms);
|
||||
|
||||
/// Try to auto-discover device name?
|
||||
bool _isAutoDeviceName;
|
||||
|
||||
/// Sleep after the connect before continuing
|
||||
int _delayAfterConnect_ms;
|
||||
|
||||
/// The RS232 serial-device
|
||||
QSerialPort _rs232Port;
|
||||
|
||||
/// A timeout timer for the asynchronous connection
|
||||
QTimer _writeTimeout;
|
||||
|
||||
bool _blockedForDelay;
|
||||
|
||||
bool _stateChanged;
|
||||
|
||||
qint64 _bytesToWrite;
|
||||
qint64 _frameDropCounter;
|
||||
QSerialPort::SerialPortError _lastError;
|
||||
qint64 _preOpenDelayTimeOut;
|
||||
int _preOpenDelay;
|
||||
bool _enableAutoDeviceName;
|
||||
/// Frames dropped, as write failed
|
||||
int _frameDropCounter;
|
||||
};
|
||||
|
||||
#endif // PROVIDERRS232_H
|
||||
|
@@ -4,7 +4,9 @@ LedDeviceAPA102::LedDeviceAPA102(const QJsonObject &deviceConfig)
|
||||
: ProviderSpi()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceAPA102::construct(const QJsonObject &deviceConfig)
|
||||
@@ -14,10 +16,12 @@ LedDevice* LedDeviceAPA102::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceAPA102::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
if ( isInitOK )
|
||||
// Initialise sub-class
|
||||
if ( ProviderSpi::init(deviceConfig) )
|
||||
{
|
||||
|
||||
const unsigned int startFrameSize = 4;
|
||||
const unsigned int endFrameSize = qMax<unsigned int>(((_ledCount + 15) / 16), 4);
|
||||
const unsigned int APAbufferSize = (_ledCount * 4) + startFrameSize + endFrameSize;
|
||||
@@ -27,6 +31,9 @@ bool LedDeviceAPA102::init(const QJsonObject &deviceConfig)
|
||||
_ledBuffer[1] = 0x00;
|
||||
_ledBuffer[2] = 0x00;
|
||||
_ledBuffer[3] = 0x00;
|
||||
|
||||
isInitOK = true;
|
||||
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEAPA102_H
|
||||
#define LEDEVICEAPA102_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
@@ -9,26 +10,39 @@
|
||||
class LedDeviceAPA102 : public ProviderSpi
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs an APA102 LED-device
|
||||
///
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceAPA102(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
private:
|
||||
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEAPA102_H
|
||||
|
@@ -46,9 +46,12 @@ LedDeviceAPA104::LedDeviceAPA104(const QJsonObject &deviceConfig)
|
||||
}
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
|
||||
LedDevice* LedDeviceAPA104::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceAPA104(deviceConfig);
|
||||
@@ -58,12 +61,16 @@ bool LedDeviceAPA104::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_baudRate_Hz = 2235000;
|
||||
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
bool isInitOK = false;
|
||||
|
||||
// Initialise sub-class
|
||||
if ( ProviderSpi::init(deviceConfig) )
|
||||
{
|
||||
WarningIf(( _baudRate_Hz < 2000000 || _baudRate_Hz > 2470000 ), _log, "SPI rate %d outside recommended range (2000000 -> 2470000)", _baudRate_Hz);
|
||||
|
||||
_ledBuffer.resize(_ledRGBCount * SPI_BYTES_PER_COLOUR + SPI_FRAME_END_LATCH_BYTES, 0x00);
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEAPA104_H
|
||||
#define LEDEVICEAPA104_H
|
||||
|
||||
// hyperion inclusdes
|
||||
// hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
@@ -9,34 +10,43 @@
|
||||
class LedDeviceAPA104 : public ProviderSpi
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs an APA104 LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceAPA104(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
const int SPI_BYTES_PER_COLOUR;
|
||||
const int SPI_FRAME_END_LATCH_BYTES;
|
||||
|
||||
uint8_t bitpair_to_byte[4];
|
||||
};
|
||||
|
||||
#endif // LEDEVICEAPA104_H
|
||||
|
@@ -4,7 +4,9 @@ LedDeviceLpd6803::LedDeviceLpd6803(const QJsonObject &deviceConfig)
|
||||
: ProviderSpi()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceLpd6803::construct(const QJsonObject &deviceConfig)
|
||||
@@ -14,12 +16,16 @@ LedDevice* LedDeviceLpd6803::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceLpd6803::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
bool isInitOK = false;
|
||||
|
||||
// Initialise sub-class
|
||||
if ( ProviderSpi::init(deviceConfig) )
|
||||
{
|
||||
unsigned messageLength = 4 + 2*_ledCount + _ledCount/8 + 1;
|
||||
// Initialise the buffer
|
||||
_ledBuffer.resize(messageLength, 0x00);
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
@@ -1,45 +1,55 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICELPD6803_H
|
||||
#define LEDEVICELPD6803_H
|
||||
|
||||
// Local hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for writing to LDP6803 led device.
|
||||
/// Implementation of the LedDevice interface for writing to LDP6803 LED-device.
|
||||
///
|
||||
/// 00000000 00000000 00000000 00000000 1RRRRRGG GGGBBBBB 1RRRRRGG GGGBBBBB ...
|
||||
/// |---------------------------------| |---------------| |---------------|
|
||||
/// 32 zeros to start the frame Led1 Led2 ...
|
||||
/// 32 zeros to start the frame LED1 LED2 ...
|
||||
///
|
||||
/// For each led, the first bit is always 1, and then you have 5 bits each for red, green and blue
|
||||
/// (R, G and B in the above illustration) making 16 bits per led. Total bytes = 4 + (2 x number of
|
||||
/// leds)
|
||||
/// (R, G and B in the above illustration) making 16 bits per led. Total bytes = 4 + (2 x number of LEDs)
|
||||
///
|
||||
class LedDeviceLpd6803 : public ProviderSpi
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a LDP6803 LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceLpd6803(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
};
|
||||
|
||||
#endif // LEDEVICELPD6803_H
|
||||
|
@@ -4,7 +4,9 @@ LedDeviceLpd8806::LedDeviceLpd8806(const QJsonObject &deviceConfig)
|
||||
: ProviderSpi()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceLpd8806::construct(const QJsonObject &deviceConfig)
|
||||
@@ -14,13 +16,18 @@ LedDevice* LedDeviceLpd8806::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceLpd8806::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
const unsigned clearSize = _ledCount/32+1;
|
||||
unsigned messageLength = _ledRGBCount + clearSize;
|
||||
// Initialise the buffer
|
||||
_ledBuffer.resize(messageLength, 0x00);
|
||||
// Initialise sub-class
|
||||
if ( ProviderSpi::init(deviceConfig) )
|
||||
{
|
||||
const unsigned clearSize = _ledCount/32+1;
|
||||
unsigned messageLength = _ledRGBCount + clearSize;
|
||||
// Initialise the buffer
|
||||
_ledBuffer.resize(messageLength, 0x00);
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICELPD8806_H
|
||||
#define LEDEVICELPD8806_H
|
||||
|
||||
// Local hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
@@ -32,7 +33,7 @@
|
||||
/// applications. The 'subsequent' rule also means that at least one extra
|
||||
/// byte must follow the last pixel, in order for the final blue LED to latch.
|
||||
///
|
||||
/// To reset the pass-through behavior and begin sending new data to the start
|
||||
/// To reset the pass-through behaviour and begin sending new data to the start
|
||||
/// of the strip, a number of zero bytes must be issued (remember, all color
|
||||
/// data bytes have the high bit set, thus are in the range 128 to 255, so the
|
||||
/// zero is 'special'). This should be done before each full payload of color
|
||||
@@ -69,7 +70,7 @@
|
||||
/// Tested. Confirmed. Fact.
|
||||
///
|
||||
///
|
||||
/// The summary of the story is that the following needs to be writen on the spi-device:
|
||||
/// The summary of the story is that the following needs to be written on the spi-device:
|
||||
/// 1RRRRRRR 1GGGGGGG 1BBBBBBB 1RRRRRRR 1GGGGGGG ... ... 1GGGGGGG 1BBBBBBB 00000000 00000000 ...
|
||||
/// |---------led_1----------| |---------led_2-- -led_n----------| |----clear data--
|
||||
///
|
||||
@@ -78,29 +79,39 @@
|
||||
class LedDeviceLpd8806 : public ProviderSpi
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a LDP8806 LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceLpd8806(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
///
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
};
|
||||
|
||||
#endif // LEDEVICELPD8806_H
|
||||
|
@@ -4,7 +4,9 @@ LedDeviceP9813::LedDeviceP9813(const QJsonObject &deviceConfig)
|
||||
: ProviderSpi()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceP9813::construct(const QJsonObject &deviceConfig)
|
||||
@@ -14,10 +16,13 @@ LedDevice* LedDeviceP9813::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceP9813::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
bool isInitOK = false;
|
||||
|
||||
// Initialise sub-class
|
||||
if ( ProviderSpi::init(deviceConfig) )
|
||||
{
|
||||
_ledBuffer.resize(_ledCount * 4 + 8, 0x00);
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
@@ -1,45 +1,54 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEP9813_H
|
||||
#define LEDEVICEP9813_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for writing to P9813 led device.
|
||||
/// Implementation of the LedDevice interface for writing to P9813 LED-device.
|
||||
///
|
||||
class LedDeviceP9813 : public ProviderSpi
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a P9813 LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceP9813(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
///
|
||||
/// Calculates the required checksum for one led
|
||||
/// Calculates the required checksum for one LED
|
||||
///
|
||||
/// @param color The color of the led
|
||||
/// @return The checksum for the led
|
||||
///
|
||||
uint8_t calculateChecksum(const ColorRgb & color) const;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEP9813_H
|
||||
|
@@ -12,7 +12,9 @@
|
||||
}
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceSk6812SPI::construct(const QJsonObject &deviceConfig)
|
||||
@@ -24,8 +26,10 @@ bool LedDeviceSk6812SPI::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_baudRate_Hz = 3000000;
|
||||
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
bool isInitOK = false;
|
||||
|
||||
// Initialise sub-class
|
||||
if ( ProviderSpi::init(deviceConfig) )
|
||||
{
|
||||
QString whiteAlgorithm = deviceConfig["whiteAlgorithm"].toString("white_off");
|
||||
|
||||
@@ -44,6 +48,8 @@ bool LedDeviceSk6812SPI::init(const QJsonObject &deviceConfig)
|
||||
|
||||
const int SPI_FRAME_END_LATCH_BYTES = 3;
|
||||
_ledBuffer.resize(_ledRGBWCount * SPI_BYTES_PER_COLOUR + SPI_FRAME_END_LATCH_BYTES, 0x00);
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
|
@@ -1,39 +1,47 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICESK6812SPI_H
|
||||
#define LEDEVICESK6812SPI_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for writing to Sk6801 led device via SPI.
|
||||
/// Implementation of the LedDevice interface for writing to Sk6801 LED-device via SPI.
|
||||
///
|
||||
class LedDeviceSk6812SPI : public ProviderSpi
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a Sk6801 LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceSk6812SPI(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
RGBW::WhiteAlgorithm _whiteAlgorithm;
|
||||
|
||||
@@ -42,3 +50,5 @@ private:
|
||||
|
||||
ColorRgbw _temp_rgbw;
|
||||
};
|
||||
|
||||
#endif // LEDEVICESK6812SPI_H
|
||||
|
@@ -49,9 +49,12 @@ LedDeviceSk6822SPI::LedDeviceSk6822SPI(const QJsonObject &deviceConfig)
|
||||
}
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
|
||||
LedDevice* LedDeviceSk6822SPI::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceSk6822SPI(deviceConfig);
|
||||
@@ -61,13 +64,17 @@ bool LedDeviceSk6822SPI::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_baudRate_Hz = 2230000;
|
||||
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
bool isInitOK = false;
|
||||
|
||||
// Initialise sub-class
|
||||
if ( ProviderSpi::init(deviceConfig) )
|
||||
{
|
||||
WarningIf(( _baudRate_Hz < 2000000 || _baudRate_Hz > 2460000 ), _log, "SPI rate %d outside recommended range (2000000 -> 2460000)", _baudRate_Hz);
|
||||
|
||||
_ledBuffer.resize( (_ledRGBCount * SPI_BYTES_PER_COLOUR) + (_ledCount * SPI_BYTES_WAIT_TIME ) + SPI_FRAME_END_LATCH_BYTES, 0x00);
|
||||
// Debug(_log, "_ledBuffer.resize(_ledRGBCount:%d * SPI_BYTES_PER_COLOUR:%d) + ( _ledCount:%d * SPI_BYTES_WAIT_TIME:%d ) + SPI_FRAME_END_LATCH_BYTES:%d, 0x00)", _ledRGBCount, SPI_BYTES_PER_COLOUR, _ledCount, SPI_BYTES_WAIT_TIME, SPI_FRAME_END_LATCH_BYTES);
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
|
||||
return isInitOK;
|
||||
@@ -93,9 +100,8 @@ int LedDeviceSk6822SPI::write(const std::vector<ColorRgb> &ledValues)
|
||||
spi_ptr += SPI_BYTES_WAIT_TIME; // the wait between led time is all zeros
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// debug the whole SPI packet
|
||||
/*
|
||||
// debug the whole SPI packet
|
||||
char debug_line[2048];
|
||||
int ptr=0;
|
||||
for (unsigned int i=0; i < _ledBuffer.size(); i++)
|
||||
@@ -105,14 +111,14 @@ int LedDeviceSk6822SPI::write(const std::vector<ColorRgb> &ledValues)
|
||||
ptr += snprintf (ptr+debug_line, sizeof(debug_line)-ptr, "%03x: ", i);
|
||||
}
|
||||
|
||||
ptr += snprintf (ptr+debug_line, sizeof(debug_line)-ptr, "%02x ", _ledBuffer.data()[i]);
|
||||
ptr += snprintf (ptr+debug_line, sizeof(debug_line)-ptr, "%02x ", _ledBuffer.data()[i]);
|
||||
|
||||
if ( (i%16 == 15) || ( i == _ledBuffer.size()-1 ) )
|
||||
{
|
||||
Debug(_log, debug_line);
|
||||
ptr = 0;
|
||||
if ( (i%16 == 15) || ( i == _ledBuffer.size()-1 ) )
|
||||
{
|
||||
Debug(_log, debug_line);
|
||||
ptr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
|
||||
|
@@ -1,39 +1,47 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICESK6822SPI_H
|
||||
#define LEDEVICESK6822SPI_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for writing to Ws2812 led device via spi.
|
||||
/// Implementation of the LedDevice interface for writing to Sk6822 LED-device via SPI.
|
||||
///
|
||||
class LedDeviceSk6822SPI : public ProviderSpi
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a Sk6822 LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceSk6822SPI(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
const int SPI_BYTES_PER_COLOUR;
|
||||
const int SPI_BYTES_WAIT_TIME;
|
||||
@@ -41,3 +49,5 @@ private:
|
||||
|
||||
uint8_t bitpair_to_byte[4];
|
||||
};
|
||||
|
||||
#endif // LEDEVICESK6822SPI_H
|
||||
|
@@ -4,7 +4,9 @@ LedDeviceWs2801::LedDeviceWs2801(const QJsonObject &deviceConfig)
|
||||
: ProviderSpi()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceWs2801::construct(const QJsonObject &deviceConfig)
|
||||
|
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEWS2801_H
|
||||
#define LEDEVICEWS2801_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
@@ -9,29 +10,38 @@
|
||||
class LedDeviceWs2801 : public ProviderSpi
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a Ws2801 LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceWs2801(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
};
|
||||
|
||||
#endif // LEDEVICEWS2801_H
|
||||
|
@@ -46,7 +46,9 @@ Reset time is 300uS = 923 bits = 116 bytes
|
||||
}
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceWs2812SPI::construct(const QJsonObject &deviceConfig)
|
||||
@@ -58,13 +60,18 @@ bool LedDeviceWs2812SPI::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_baudRate_Hz = 2600000;
|
||||
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
bool isInitOK = false;
|
||||
|
||||
// Initialise sub-class
|
||||
if ( ProviderSpi::init(deviceConfig) )
|
||||
{
|
||||
WarningIf(( _baudRate_Hz < 2106000 || _baudRate_Hz > 3075000 ), _log, "SPI rate %d outside recommended range (2106000 -> 3075000)", _baudRate_Hz);
|
||||
|
||||
_ledBuffer.resize(_ledRGBCount * SPI_BYTES_PER_COLOUR + SPI_FRAME_END_LATCH_BYTES, 0x00);
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
|
@@ -1,42 +1,52 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICEWS2812_H
|
||||
#define LEDEVICEWS2812_H
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for writing to Ws2812 led device via spi.
|
||||
/// Implementation of the LedDevice interface for writing to Ws2812 led device.
|
||||
///
|
||||
class LedDeviceWs2812SPI : public ProviderSpi
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a Ws2812 LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceWs2812SPI(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
const int SPI_BYTES_PER_COLOUR;
|
||||
const int SPI_FRAME_END_LATCH_BYTES;
|
||||
|
||||
uint8_t bitpair_to_byte[4];
|
||||
};
|
||||
|
||||
#endif // LEDEVICEWS2812_H
|
||||
|
@@ -33,13 +33,21 @@ ProviderSpi::~ProviderSpi()
|
||||
|
||||
bool ProviderSpi::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
bool isInitOK = false;
|
||||
|
||||
_deviceName = deviceConfig["output"].toString(_deviceName);
|
||||
_baudRate_Hz = deviceConfig["rate"].toInt(_baudRate_Hz);
|
||||
_spiMode = deviceConfig["spimode"].toInt(_spiMode);
|
||||
_spiDataInvert = deviceConfig["invert"].toBool(_spiDataInvert);
|
||||
// Initialise sub-class
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
_deviceName = deviceConfig["output"].toString(_deviceName);
|
||||
_baudRate_Hz = deviceConfig["rate"].toInt(_baudRate_Hz);
|
||||
_spiMode = deviceConfig["spimode"].toInt(_spiMode);
|
||||
_spiDataInvert = deviceConfig["invert"].toBool(_spiDataInvert);
|
||||
|
||||
Debug(_log, "_baudRate_Hz [%d], _latchTime_ms [%d]", _baudRate_Hz, _latchTime_ms);
|
||||
Debug(_log, "_spiDataInvert [%d], _spiMode [%d]", _spiDataInvert, _spiMode);
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
@@ -47,77 +55,74 @@ int ProviderSpi::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
const int bitsPerWord = 8;
|
||||
|
||||
_fid = ::open(QSTRING_CSTR(_deviceName), O_RDWR);
|
||||
|
||||
if (_fid < 0)
|
||||
{
|
||||
|
||||
Debug(_log, "_baudRate_Hz [%d], _latchTime_ms [%d]", _baudRate_Hz, _latchTime_ms);
|
||||
Debug(_log, "_spiDataInvert [%d], _spiMode [%d]", _spiDataInvert, _spiMode);
|
||||
|
||||
const int bitsPerWord = 8;
|
||||
|
||||
_fid = ::open(QSTRING_CSTR(_deviceName), O_RDWR);
|
||||
|
||||
if (_fid < 0)
|
||||
errortext = QString ("Failed to open device (%1). Error message: %2").arg(_deviceName, strerror(errno));
|
||||
retval = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ioctl(_fid, SPI_IOC_WR_MODE, &_spiMode) == -1 || ioctl(_fid, SPI_IOC_RD_MODE, &_spiMode) == -1)
|
||||
{
|
||||
errortext = QString ("Failed to open device (%1). Error message: %2").arg(_deviceName, strerror(errno));
|
||||
retval = -1;
|
||||
retval = -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ioctl(_fid, SPI_IOC_WR_MODE, &_spiMode) == -1 || ioctl(_fid, SPI_IOC_RD_MODE, &_spiMode) == -1)
|
||||
if (ioctl(_fid, SPI_IOC_WR_BITS_PER_WORD, &bitsPerWord) == -1 || ioctl(_fid, SPI_IOC_RD_BITS_PER_WORD, &bitsPerWord) == -1)
|
||||
{
|
||||
retval = -2;
|
||||
retval = -4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ioctl(_fid, SPI_IOC_WR_BITS_PER_WORD, &bitsPerWord) == -1 || ioctl(_fid, SPI_IOC_RD_BITS_PER_WORD, &bitsPerWord) == -1)
|
||||
if (ioctl(_fid, SPI_IOC_WR_MAX_SPEED_HZ, &_baudRate_Hz) == -1 || ioctl(_fid, SPI_IOC_RD_MAX_SPEED_HZ, &_baudRate_Hz) == -1)
|
||||
{
|
||||
retval = -4;
|
||||
retval = -6;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ioctl(_fid, SPI_IOC_WR_MAX_SPEED_HZ, &_baudRate_Hz) == -1 || ioctl(_fid, SPI_IOC_RD_MAX_SPEED_HZ, &_baudRate_Hz) == -1)
|
||||
{
|
||||
retval = -6;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
// Everything OK -> enable device
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
if ( retval < 0 )
|
||||
{
|
||||
errortext = QString ("Failed to open device (%1). Error Code: %2").arg(_deviceName).arg(retval);
|
||||
}
|
||||
}
|
||||
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
errortext = QString ("Failed to open device (%1). Error Code: %2").arg(_deviceName).arg(retval);
|
||||
}
|
||||
}
|
||||
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ProviderSpi::close()
|
||||
int ProviderSpi::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
// LedDevice specific closing activities
|
||||
int retval = 0;
|
||||
_isDeviceReady = false;
|
||||
|
||||
// Device specific closing activites
|
||||
// Test, if device requires closing
|
||||
if ( _fid > -1 )
|
||||
{
|
||||
// Close device
|
||||
if ( ::close(_fid) != 0 )
|
||||
{
|
||||
Error( _log, "Failed to close device (%s). Error message: %s", QSTRING_CSTR(_deviceName), strerror(errno) );
|
||||
retval = -1;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ProviderSpi::writeBytes(const unsigned size, const uint8_t * data)
|
||||
|
@@ -41,7 +41,7 @@ public slots:
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
virtual int close() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
@@ -51,7 +51,7 @@ protected:
|
||||
/// @param[in[ size The length of the data
|
||||
/// @param[in] data The data
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
int writeBytes(const unsigned size, const uint8_t *data);
|
||||
|
||||
|
@@ -6,17 +6,26 @@
|
||||
// Local LedDevice includes
|
||||
#include "LedDeviceTinkerforge.h"
|
||||
|
||||
static const unsigned MAX_NUM_LEDS = 320;
|
||||
static const unsigned MAX_NUM_LEDS_SETTABLE = 16;
|
||||
// Constants
|
||||
namespace {
|
||||
|
||||
const unsigned MAX_NUM_LEDS = 320;
|
||||
const unsigned MAX_NUM_LEDS_SETTABLE = 16;
|
||||
const uint16_t DEFAULT_PORT = 4223;
|
||||
|
||||
} //End of constants
|
||||
|
||||
LedDeviceTinkerforge::LedDeviceTinkerforge(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
, _ipConnection(nullptr)
|
||||
, _ledStrip(nullptr)
|
||||
, _colorChannelSize(0)
|
||||
,_port(DEFAULT_PORT)
|
||||
,_ipConnection(nullptr)
|
||||
,_ledStrip(nullptr)
|
||||
,_colorChannelSize(0)
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
|
||||
}
|
||||
|
||||
LedDeviceTinkerforge::~LedDeviceTinkerforge()
|
||||
@@ -31,20 +40,21 @@ LedDevice* LedDeviceTinkerforge::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceTinkerforge(deviceConfig);
|
||||
}
|
||||
|
||||
|
||||
bool LedDeviceTinkerforge::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
if (isInitOK)
|
||||
bool isInitOK = false;
|
||||
|
||||
// Initialise sub-class
|
||||
if ( LedDevice::init(deviceConfig) )
|
||||
{
|
||||
_host = deviceConfig["output"].toString("127.0.0.1");
|
||||
_port = deviceConfig["port"].toInt(4223);
|
||||
_port = deviceConfig["port"].toInt(DEFAULT_PORT);
|
||||
_uid = deviceConfig["uid"].toString();
|
||||
_interval = deviceConfig["rate"].toInt();
|
||||
|
||||
if ((unsigned)_ledCount > MAX_NUM_LEDS)
|
||||
{
|
||||
QString errortext = QString ("Initialization error. Not more than %1 leds are allowed.").arg(MAX_NUM_LEDS);
|
||||
QString errortext = QString ("Initialization error. Not more than %1 LEDs are allowed.").arg(MAX_NUM_LEDS);
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
@@ -66,53 +76,47 @@ bool LedDeviceTinkerforge::init(const QJsonObject &deviceConfig)
|
||||
int LedDeviceTinkerforge::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
_isDeviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
// Check if connection is already created
|
||||
if (_ipConnection != nullptr)
|
||||
{
|
||||
Error(_log, "Attempt to open existing connection; close before opening");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialise a new connection
|
||||
_ipConnection = new IPConnection;
|
||||
ipcon_create(_ipConnection);
|
||||
|
||||
// Check if connection is already createds
|
||||
if (_ipConnection != nullptr)
|
||||
int connectionStatus = ipcon_connect(_ipConnection, QSTRING_CSTR(_host), _port);
|
||||
if (connectionStatus < 0)
|
||||
{
|
||||
Error(_log, "Attempt to open existing connection; close before opening");
|
||||
Error(_log, "Attempt to connect to master brick (%s:%d) failed with status %d", QSTRING_CSTR(_host), _port, connectionStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialise a new connection
|
||||
_ipConnection = new IPConnection;
|
||||
ipcon_create(_ipConnection);
|
||||
// Create the 'LedStrip'
|
||||
_ledStrip = new LEDStrip;
|
||||
led_strip_create(_ledStrip, QSTRING_CSTR(_uid), _ipConnection);
|
||||
|
||||
int connectionStatus = ipcon_connect(_ipConnection, QSTRING_CSTR(_host), _port);
|
||||
if (connectionStatus < 0)
|
||||
int frameStatus = led_strip_set_frame_duration(_ledStrip, _interval);
|
||||
if (frameStatus < 0)
|
||||
{
|
||||
Error(_log, "Attempt to connect to master brick (%s:%d) failed with status %d", QSTRING_CSTR(_host), _port, connectionStatus);
|
||||
Error(_log,"Attempt to connect to led strip bricklet (led_strip_set_frame_duration()) failed with status %d", frameStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create the 'LedStrip'
|
||||
_ledStrip = new LEDStrip;
|
||||
led_strip_create(_ledStrip, QSTRING_CSTR(_uid), _ipConnection);
|
||||
|
||||
int frameStatus = led_strip_set_frame_duration(_ledStrip, _interval);
|
||||
if (frameStatus < 0)
|
||||
{
|
||||
Error(_log,"Attempt to connect to led strip bricklet (led_strip_set_frame_duration()) failed with status %d", frameStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
// Everything is OK, device is ready
|
||||
_isDeviceReady = true;
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( "Error opening device!" );
|
||||
}
|
||||
}
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( "Error opening device!" );
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
@@ -1,10 +1,9 @@
|
||||
#pragma once
|
||||
#ifndef LEDEVICETINKERFORGE_H
|
||||
#define LEDEVICETINKERFORGE_H
|
||||
|
||||
// STL includes
|
||||
#include <cstdio>
|
||||
|
||||
#include <QString>
|
||||
|
||||
// Hyperion-Leddevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
|
||||
@@ -16,45 +15,52 @@ extern "C" {
|
||||
class LedDeviceTinkerforge : public LedDevice
|
||||
{
|
||||
public:
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
/// @brief Constructs a Tinkerforge LED-device
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
/// @param deviceConfig Device's configuration as JSON-Object
|
||||
///
|
||||
explicit LedDeviceTinkerforge(const QJsonObject &deviceConfig);
|
||||
|
||||
virtual ~LedDeviceTinkerforge() override;
|
||||
|
||||
/// constructs leddevice
|
||||
///
|
||||
/// @brief Constructs the LED-device
|
||||
///
|
||||
/// @param[in] deviceConfig Device's configuration as JSON-Object
|
||||
/// @return LedDevice constructed
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Attempts to open a connection to the master bricklet and the led strip bricklet.
|
||||
/// @brief Initialise the device's configuration
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
/// @param[in] deviceConfig the JSON device configuration
|
||||
/// @return True, if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// @brief Opens a connection to the master bricklet and the led strip bricklet.
|
||||
///
|
||||
/// @return Zero on success (i.e. device is ready), else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
///
|
||||
/// @brief Writes the RGB-Color values to the LEDs.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per LED
|
||||
/// @return Zero on success, else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the colors to the led strip bricklet
|
||||
///
|
||||
/// @param ledValues The color value for each led
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
///
|
||||
/// Writes the data to the led strip blicklet
|
||||
/// Writes the data to the LED strip bricklet
|
||||
int transferLedData(LEDStrip *ledstrip, unsigned int index, unsigned int length, uint8_t *redChannel, uint8_t *greenChannel, uint8_t *blueChannel);
|
||||
|
||||
/// The host of the master brick
|
||||
@@ -88,3 +94,5 @@ private:
|
||||
unsigned int _colorChannelSize;
|
||||
|
||||
};
|
||||
|
||||
#endif // LEDEVICETINKERFORGE_H
|
||||
|
@@ -5,7 +5,7 @@
|
||||
"output": {
|
||||
"type": "string",
|
||||
"title":"edt_dev_spec_outputPath_title",
|
||||
"default":"/dev/ttyACM0",
|
||||
"default":"ttyACM0",
|
||||
"propertyOrder" : 1
|
||||
},
|
||||
"rate": {
|
||||
|
@@ -5,7 +5,7 @@
|
||||
"output": {
|
||||
"type": "string",
|
||||
"title":"edt_dev_spec_outputPath_title",
|
||||
"default":"/dev/ttyUSB0",
|
||||
"default":"ttyUSB0",
|
||||
"propertyOrder" : 1
|
||||
},
|
||||
"rate": {
|
||||
|
@@ -2,23 +2,35 @@
|
||||
"type":"object",
|
||||
"required":true,
|
||||
"properties":{
|
||||
"dmxtype": {
|
||||
"type": "string",
|
||||
"title":"edt_dev_spec_ledType_title",
|
||||
"enum" : ["raw", "McCrypt"],
|
||||
"default" : "raw",
|
||||
"options" : {
|
||||
"enum_titles" : ["Raw", "McCrypt"]
|
||||
},
|
||||
"minimum" : 0,
|
||||
"maximum" : 1,
|
||||
"propertyOrder" : 1
|
||||
},
|
||||
"output": {
|
||||
"type": "string",
|
||||
"title":"edt_dev_spec_outputPath_title",
|
||||
"default":"/dev/ttyUSB0",
|
||||
"propertyOrder" : 1
|
||||
"default":"ttyUSB0",
|
||||
"propertyOrder" : 2
|
||||
},
|
||||
"rate": {
|
||||
"type": "integer",
|
||||
"title":"edt_dev_spec_baudrate_title",
|
||||
"default": 250000,
|
||||
"propertyOrder" : 2
|
||||
"propertyOrder" : 3
|
||||
},
|
||||
"delayAfterConnect": {
|
||||
"type": "integer",
|
||||
"title":"edt_dev_spec_delayAfterConnect_title",
|
||||
"default": 250,
|
||||
"propertyOrder" : 3
|
||||
"propertyOrder" : 4
|
||||
},
|
||||
"latchTime": {
|
||||
"type": "integer",
|
||||
@@ -28,7 +40,7 @@
|
||||
"minimum": 0,
|
||||
"maximum": 1000,
|
||||
"access" : "expert",
|
||||
"propertyOrder" : 4
|
||||
"propertyOrder" : 5
|
||||
},
|
||||
"rewriteTime": {
|
||||
"type": "integer",
|
||||
@@ -37,7 +49,7 @@
|
||||
"append" : "edt_append_ms",
|
||||
"minimum": 0,
|
||||
"access" : "expert",
|
||||
"propertyOrder" : 5
|
||||
"propertyOrder" : 6
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
|
@@ -5,7 +5,7 @@
|
||||
"output": {
|
||||
"type": "string",
|
||||
"title":"edt_dev_spec_outputPath_title",
|
||||
"default":"/dev/ttyACM0",
|
||||
"default":"ttyACM0",
|
||||
"propertyOrder" : 1
|
||||
},
|
||||
"rate": {
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"type":"object",
|
||||
"required":true,
|
||||
"properties":{
|
||||
"output": {
|
||||
"serial": {
|
||||
"type": "string",
|
||||
"title":"edt_dev_spec_serial_title",
|
||||
"propertyOrder" : 1
|
||||
|
@@ -5,7 +5,7 @@
|
||||
"output": {
|
||||
"type": "string",
|
||||
"title":"edt_dev_spec_outputPath_title",
|
||||
"default":"/dev/ttyACM0",
|
||||
"default":"ttyACM0",
|
||||
"propertyOrder" : 1
|
||||
},
|
||||
"rate": {
|
||||
|
@@ -5,7 +5,7 @@
|
||||
"output": {
|
||||
"type": "string",
|
||||
"title":"edt_dev_spec_outputPath_title",
|
||||
"default":"/dev/ttyACM0",
|
||||
"default":"ttyACM0",
|
||||
"propertyOrder" : 1
|
||||
},
|
||||
"rate": {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user