Disentangle LedDevice/LinearColorSmoothing, Bug Fixes & Test support (#654)

* Handle Exceptions in main & Pythoninit

* Have SSDPDiscover generic again

* Have SSDPDiscover generic again

* Change Info- to Debug logs as technical service messages

* Nanoleaf - When switched on, ensure UDP mode

* Include SQL Database in Cross-Compile instructions

* Fix Clazy (QT code checker) and clang Warnings

* Stop LedDevice:write for disabled device

* Nanoleaf: Fix uint printfs

* NanoLeaf: Fix indents to tabs

* NanoLeaf - Add debug verbosity switches

* Device switchability support, FileDevice with timestamp support

* Nanoleaf Light Panels now support External Control V2

* Enhance LedDeviceFile by Timestamp + fix readyness

* Stop color stream, if LedDevice disabled

* Nanoleaf - remove switchability

* Fix MultiColorAdjustment, if led-range is greater lednum

* Fix logging

* LedFileDevice/LedDevice - add testing support

* New "Led Test" effect

* LedDeviceFile - Add chrono include + Allow Led rewrites for testing

* Stabilize Effects for LedDevices where latchtime = 0

* Update LedDeviceFile, allow latchtime = 0

* Distangle LinearColorSmoothing and LEDDevice, Fix Effect configuration updates

* Updates LedDeviceFile - Initialize via Open

* Updates LedDeviceNanoleaf - Initialize via Open, Remove throwing exceptions

* Updates ProviderUDP - Remove throwing exceptions

* Framebuffer - Use precise timer

* TestSpi - Align to LedDevice updates

* Pretty Print CrossCompileHowTo as markdown-file

* Ensure that output is only written when LedDevice is ready

* Align APA102 Device to new device staging

* Logger - Remove clang warnings on extra semicolon

* Devices SPI - Align to Device stages and methods

* Fix cppcheck and clang findings

* Add Code-Template for new Devices

* Align devices to stages and methods, clean-up some code

* Allow to reopen LedDevice without restart

* Revert change "Remove Connect (PriorityMuxer::visiblePriorityChanged -> Hyperion::update) due to double writes"

* Remove visiblePriorityChanged from LedDevice to decouple LedDevice from hyperion logic

* Expose LedDevice getLedCount and align signedness
This commit is contained in:
LordGrey
2020-02-10 15:21:58 +01:00
committed by GitHub
parent 1aba51e85c
commit ed5455458b
107 changed files with 2980 additions and 1551 deletions

View File

@@ -6,6 +6,8 @@
#include <QStringList>
#include <QDir>
#include <QDateTime>
#include <QEventLoop>
#include <QTimer>
#include "hyperion/Hyperion.h"
#include <utils/JsonUtils.h>
@@ -15,32 +17,62 @@ LedDevice::LedDevice(const QJsonObject& config, QObject* parent)
, _devConfig(config)
, _log(Logger::getInstance("LEDDEVICE"))
, _ledBuffer(0)
, _deviceReady(true)
, _refresh_timer()
, _deviceReady(false)
, _deviceInError(false)
, _refresh_timer(new QTimer(this))
, _refresh_timer_interval(0)
, _last_write_time(QDateTime::currentMSecsSinceEpoch())
, _latchTime_ms(0)
, _componentRegistered(false)
, _enabled(true)
, _enabled(false)
, _refresh_enabled (false)
{
// setup timer
_refresh_timer.setInterval(0);
connect(&_refresh_timer, SIGNAL(timeout()), this, SLOT(rewriteLeds()));
// setup refreshTimer
_refresh_timer->setTimerType(Qt::PreciseTimer);
_refresh_timer->setInterval( _refresh_timer_interval );
connect(_refresh_timer, SIGNAL(timeout()), this, SLOT(rewriteLeds()));
}
LedDevice::~LedDevice()
{
_refresh_timer->deleteLater();
}
// dummy implemention
int LedDevice::open()
{
setEnable (true);
return 0;
}
void LedDevice::setInError(const QString& errorMsg)
{
_deviceInError = true;
_deviceReady = false;
_enabled = 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();
}
void LedDevice::setEnable(bool enable)
{
if (!_deviceReady && 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;
}
}
// emit signal when state changed
if (_enabled != enable)
{
@@ -62,7 +94,7 @@ void LedDevice::setEnable(bool enable)
_enabled = enable;
}
void LedDevice::setActiveDeviceType(QString deviceType)
void LedDevice::setActiveDeviceType(const QString& deviceType)
{
_activeDeviceType = deviceType;
}
@@ -71,50 +103,100 @@ bool LedDevice::init(const QJsonObject &deviceConfig)
{
_colorOrder = deviceConfig["colorOrder"].toString("RGB");
_activeDeviceType = deviceConfig["type"].toString("file").toLower();
setLedCount(deviceConfig["currentLedCount"].toInt(1)); // property injected to reflect real led count
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.setInterval( deviceConfig["rewriteTime"].toInt( _refresh_timer_interval) );
if (_refresh_timer.interval() <= (signed)_latchTime_ms )
_latchTime_ms =deviceConfig["latchTime"].toInt( _latchTime_ms );
_refresh_timer_interval = deviceConfig["rewriteTime"].toInt( _refresh_timer_interval);
if ( _refresh_timer_interval > 0 )
{
Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d)", _refresh_timer.interval(), _latchTime_ms);
_refresh_timer.setInterval(_latchTime_ms+10);
}
_refresh_enabled = true;
if (_refresh_timer_interval <= _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;
_refresh_timer->setInterval( _refresh_timer_interval );
}
//Debug(_log, "Refresh interval = %dms",_refresh_timer_interval );
_refresh_timer->setInterval( _refresh_timer_interval );
_last_write_time = QDateTime::currentMSecsSinceEpoch();
this->startRefreshTimer();
}
return true;
}
int LedDevice::setLedValues(const std::vector<ColorRgb>& ledValues)
void LedDevice::startRefreshTimer()
{
if ( _deviceReady)
{
_refresh_timer->start();
}
}
void LedDevice::stopRefreshTimer()
{
_refresh_timer->stop();
}
int LedDevice::updateLeds(const std::vector<ColorRgb>& ledValues)
{
int retval = 0;
if (!_deviceReady || !_enabled)
if ( !_deviceReady )
{
std::cout << "LedDevice::updateLeds(), LedDevice NOT ready!" << std::endl;
return -1;
// restart the timer
if (_refresh_timer.interval() > 0)
{
_refresh_timer.start();
}
if (_latchTime_ms == 0 || QDateTime::currentMSecsSinceEpoch()-_last_write_time >= _latchTime_ms)
else
{
_ledValues = ledValues;
retval = write(ledValues);
_last_write_time = QDateTime::currentMSecsSinceEpoch();
}
//else Debug(_log, "latch %d", QDateTime::currentMSecsSinceEpoch()-_last_write_time);
qint64 elapsedTime = QDateTime::currentMSecsSinceEpoch() - _last_write_time;
if (_latchTime_ms == 0 || elapsedTime >= _latchTime_ms)
{
//std::cout << "LedDevice::updateLeds(), Elapsed time since last write (" << elapsedTime << ") ms > _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
retval = write(ledValues);
_last_write_time = QDateTime::currentMSecsSinceEpoch();
// if device requires refreshing, save Led-Values and restart the timer
if ( _refresh_enabled )
{
this->startRefreshTimer();
_last_ledValues = ledValues;
}
}
else
{
//std::cout << "LedDevice::updateLeds(), Skip write. _latchTime_ms (" << _latchTime_ms << ") ms > elapsedTime (" << elapsedTime << ") ms" << std::endl;
if ( _refresh_enabled )
{
//Stop timer to allow for next non-refresh update
this->stopRefreshTimer();
}
}
}
return retval;
}
int LedDevice::writeBlack()
{
return _deviceReady ? write(std::vector<ColorRgb>(_ledCount, ColorRgb::BLACK )) : -1;
return _deviceReady ? updateLeds(std::vector<ColorRgb>(static_cast<unsigned long>(_ledCount), ColorRgb::BLACK )) : -1;
}
int LedDevice::switchOff()
{
// Stop refresh timer to ensure that "write Black" is executed
this->stopRefreshTimer();
if ( _latchTime_ms > 0 )
{
// Wait latchtime before writing black
QEventLoop loop;
QTimer::singleShot( _latchTime_ms, &loop, SLOT( quit() ) );
loop.exec();
}
int rc = writeBlack();
return rc;
}
@@ -124,7 +206,7 @@ int LedDevice::switchOn()
return 0;
}
void LedDevice::setLedCount(int ledCount)
void LedDevice::setLedCount(unsigned int ledCount)
{
_ledCount = ledCount;
_ledRGBCount = _ledCount * sizeof(ColorRgb);
@@ -133,6 +215,35 @@ void LedDevice::setLedCount(int ledCount)
int LedDevice::rewriteLeds()
{
return _enabled ? write(_ledValues) : -1;
int retval = -1;
if ( _deviceReady )
{
//qint64 elapsedTime = QDateTime::currentMSecsSinceEpoch() - _last_write_time;
//std::cout << "LedDevice::rewriteLeds(): Rewrite Leds now, elapsedTime [" << elapsedTime << "] 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);
_last_write_time = QDateTime::currentMSecsSinceEpoch();
}
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() <<"] [";
for (const ColorRgb& color : ledValues)
{
std::cout << color;
}
std::cout << "]" << std::endl;
}

View File

@@ -31,7 +31,7 @@ LedDevice * LedDeviceFactory::construct(const QJsonObject & deviceConfig)
if (dev.first == type)
{
device = dev.second(deviceConfig);
Info(log,"LedDevice '%s' configured.", QSTRING_CSTR(dev.first));
Info(log,"LedDevice '%s' found.", QSTRING_CSTR(dev.first));
break;
}
}

View File

@@ -0,0 +1,87 @@
#include "LedDeviceTemplate.h"
LedDeviceTemplate::LedDeviceTemplate(const QJsonObject &deviceConfig)
: LedDevice()
{
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDeviceTemplate::~LedDeviceTemplate()
{
}
LedDevice* LedDeviceTemplate::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceTemplate(deviceConfig);
}
bool LedDeviceTemplate::init(const QJsonObject &deviceConfig)
{
bool isInitOK = LedDevice::init(deviceConfig);
// Initiatiale 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;
}
return isInitOK;
}
int LedDeviceTemplate::open()
{
int retval = -1;
QString errortext;
_deviceReady = false;
// General initialisation and configuration of LedDevice
if ( init(_devConfig) )
{
// Open/Start LedDevice based on configuration
//...
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 );
}
}
return retval;
}
void LedDeviceTemplate::close()
{
LedDevice::close();
// LedDevice specific closing activites
//...
}
int LedDeviceTemplate::write(const std::vector<ColorRgb> & ledValues)
{
int retval = -1;
//...
return retval;
}

View File

@@ -0,0 +1,60 @@
#pragma once
// LedDevice includes
#include <leddevice/LedDevice.h>
///
/// Implementation of a LedDevice ...
/// ...
///
class LedDeviceTemplate : public LedDevice
{
public:
///
/// Constructs specific LedDevice
///
/// @param deviceConfig json device config
///
explicit LedDeviceTemplate(const QJsonObject &deviceConfig);
///
/// Destructor of this LedDevice
///
virtual ~LedDeviceTemplate() override;
/// constructs leddevice
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;
public slots:
///
/// Closes the output device.
/// Includes switching-off the device and stopping refreshes
///
virtual void close() override;
protected:
///
/// Opens and initiatialises the output device
///
/// @return Zero on succes (i.e. device is ready and enabled) 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
//////
virtual int write(const std::vector<ColorRgb> & ledValues) override;
private:
};

View File

@@ -20,7 +20,7 @@ LedDeviceWrapper::LedDeviceWrapper(Hyperion* hyperion)
: QObject(hyperion)
, _hyperion(hyperion)
, _ledDevice(nullptr)
, _enabled(true)
, _enabled(false)
{
// prepare the device constrcutor map
#define REGISTER(className) LedDeviceWrapper::addToDeviceMap(QString(#className).toLower(), LedDevice##className::construct);
@@ -30,7 +30,7 @@ LedDeviceWrapper::LedDeviceWrapper(Hyperion* hyperion)
#undef REGISTER
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, true);
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, false);
}
LedDeviceWrapper::~LedDeviceWrapper()
@@ -55,8 +55,11 @@ void LedDeviceWrapper::createLedDevice(const QJsonObject& config)
connect(thread, &QThread::finished, _ledDevice, &LedDevice::deleteLater);
// further signals
connect(this, &LedDeviceWrapper::write, _ledDevice, &LedDevice::write, Qt::QueuedConnection);
connect(_hyperion->getMuxerInstance(), &PriorityMuxer::visiblePriorityChanged, _ledDevice, &LedDevice::visiblePriorityChanged, Qt::QueuedConnection);
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(_ledDevice, &LedDevice::enableStateChanged, this, &LedDeviceWrapper::handleInternalEnableState, Qt::QueuedConnection);
// start the thread
@@ -125,13 +128,21 @@ const QString & LedDeviceWrapper::getColorOrder()
return _ledDevice->getColorOrder();
}
unsigned int LedDeviceWrapper::getLedCount() const
{
return _ledDevice->getLedCount();
}
void LedDeviceWrapper::handleComponentState(const hyperion::Components component, const bool state)
{
if(component == hyperion::COMP_LEDDEVICE)
{
_ledDevice->setEnable(state);
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, _ledDevice->componentState());
_enabled = state;
emit setEnable(state);
//Get device's state, considering situations where it is not ready
bool deviceState = _ledDevice->componentState();
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, deviceState);
_enabled = deviceState;
}
}
@@ -143,17 +154,18 @@ void LedDeviceWrapper::handleInternalEnableState(bool newState)
void LedDeviceWrapper::stopDeviceThread()
{
// turns the leds off
_ledDevice->switchOff();
// turns the leds off & stop refresh timers
emit closeLedDevice();
std::cout << "[hyperiond LedDeviceWrapper] <INFO> LedDevice \'" << QSTRING_CSTR(_ledDevice->getActiveDeviceType()) << "\' closed" << std::endl;
// get current thread
QThread* oldThread = _ledDevice->thread();
disconnect(oldThread, 0, 0, 0);
disconnect(oldThread, nullptr, nullptr, nullptr);
oldThread->quit();
oldThread->wait();
delete oldThread;
disconnect(_ledDevice, 0, 0, 0);
disconnect(_ledDevice, nullptr, nullptr, nullptr);
delete _ledDevice;
_ledDevice = nullptr;
}

View File

@@ -16,11 +16,108 @@ LedDeviceHyperionUsbasp::LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig
, _libusbContext(nullptr)
, _deviceHandle(nullptr)
{
init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDeviceHyperionUsbasp::~LedDeviceHyperionUsbasp()
{
}
LedDevice* LedDeviceHyperionUsbasp::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceHyperionUsbasp(deviceConfig);
}
bool LedDeviceHyperionUsbasp::init(const QJsonObject &deviceConfig)
{
bool isInitOK = LedDevice::init(deviceConfig);
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;
}
return isInitOK;
}
int LedDeviceHyperionUsbasp::open()
{
int retval = -1;
QString errortext;
_deviceReady = false;
// General initialisation and configuration of LedDevice
if ( init(_devConfig) )
{
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 );
}
}
return retval;
}
void LedDeviceHyperionUsbasp::close()
{
LedDevice::close();
// LedDevice specific closing activites
if (_deviceHandle != nullptr)
{
libusb_release_interface(_deviceHandle, 0);
@@ -37,69 +134,6 @@ LedDeviceHyperionUsbasp::~LedDeviceHyperionUsbasp()
}
}
bool LedDeviceHyperionUsbasp::init(const QJsonObject &deviceConfig)
{
LedDevice::init(deviceConfig);
QString ledType = deviceConfig["ledType"].toString("ws2801");
if (ledType != "ws2801" && ledType != "ws2812")
{
throw std::runtime_error("HyperionUsbasp: invalid ledType; must be 'ws2801' or 'ws2812'.");
}
_writeLedsCommand = (ledType == "ws2801") ? CMD_WRITE_WS2801 : CMD_WRITE_WS2812;
return true;
}
LedDevice* LedDeviceHyperionUsbasp::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceHyperionUsbasp(deviceConfig);
}
int LedDeviceHyperionUsbasp::open()
{
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));
_libusbContext = nullptr;
return -1;
}
//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));
}
return _deviceHandle == nullptr ? -1 : 0;
}
int LedDeviceHyperionUsbasp::testAndOpen(libusb_device * device)
{
libusb_device_descriptor deviceDescriptor;
@@ -121,6 +155,7 @@ int LedDeviceHyperionUsbasp::testAndOpen(libusb_device * device)
Info(_log, "%s found: bus=%d address=%d", QSTRING_CSTR(_usbProductDescription), busNumber, addressNumber);
// TODO: Check, if exceptions via try/catch need to be replaced in Qt environment
try
{
_deviceHandle = openDevice(device);

View File

@@ -27,14 +27,14 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig);
explicit LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig);
///
/// Sets configuration
///
/// @param deviceConfig the json device config
/// @return true if success
bool init(const QJsonObject &deviceConfig);
bool init(const QJsonObject &deviceConfig) override;
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
@@ -42,16 +42,23 @@ public:
///
/// Destructor of the LedDevice; closes the output device if it is open
///
virtual ~LedDeviceHyperionUsbasp();
virtual ~LedDeviceHyperionUsbasp() override;
public slots:
///
/// Closes the output device.
/// Includes switching-off the device and stopping refreshes
///
virtual void close() override;
protected:
///
/// Opens and configures the output device
///
/// @return Zero on succes else negative
///
int open();
int open() override;
protected:
///
/// Writes the RGB-Color values to the leds.
///
@@ -59,7 +66,7 @@ protected:
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb>& ledValues);
virtual int write(const std::vector<ColorRgb>& ledValues) override;
///
/// Test if the device is a Hyperion Usbasp device

View File

@@ -43,16 +43,118 @@ LedDeviceLightpack::LedDeviceLightpack(const QString & serialNumber)
, _bitsPerChannel(-1)
, _hwLedCount(-1)
{
_deviceReady = false;
}
LedDeviceLightpack::LedDeviceLightpack(const QJsonObject &deviceConfig)
: LedDevice()
, _libusbContext(nullptr)
, _deviceHandle(nullptr)
, _busNumber(-1)
, _addressNumber(-1)
, _firmwareVersion({-1,-1})
, _bitsPerChannel(-1)
, _hwLedCount(-1)
{
init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDeviceLightpack::~LedDeviceLightpack()
{
}
LedDevice* LedDeviceLightpack::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceLightpack(deviceConfig);
}
bool LedDeviceLightpack::init(const QJsonObject &deviceConfig)
{
bool isInitOK = LedDevice::init(deviceConfig);
_serialNumber = deviceConfig["output"].toString("");
return isInitOK;
}
int LedDeviceLightpack::open()
{
int retval = -1;
QString errortext;
_deviceReady = false;
// General initialisation and configuration of LedDevice
if ( init(_devConfig) )
{
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], _serialNumber);
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)
{
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);
}
}
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 );
}
}
return retval;
}
void LedDeviceLightpack::close()
{
LedDevice::close();
// LedDevice specific closing activites
if (_deviceHandle != nullptr)
{
libusb_release_interface(_deviceHandle, LIGHTPACK_INTERFACE);
@@ -69,68 +171,6 @@ LedDeviceLightpack::~LedDeviceLightpack()
}
}
bool LedDeviceLightpack::init(const QJsonObject &deviceConfig)
{
LedDevice::init(deviceConfig);
_serialNumber = deviceConfig["output"].toString("");
return true;
}
LedDevice* LedDeviceLightpack::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceLightpack(deviceConfig);
}
int LedDeviceLightpack::open()
{
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));
_libusbContext = nullptr;
return -1;
}
//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], _serialNumber);
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)
{
if (_serialNumber.isEmpty())
{
Warning(_log, "No Lightpack device has been found");
}
else
{
Error(_log,"No Lightpack device has been found with serial %s", QSTRING_CSTR(_serialNumber));
}
}
return _deviceHandle == nullptr ? -1 : 0;
}
int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requestedSerialNumber)
{
libusb_device_descriptor deviceDescriptor;
@@ -154,6 +194,7 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
QString serialNumber;
if (deviceDescriptor.iSerialNumber != 0)
{
// TODO: Check, if exceptions via try/catch need to be replaced in Qt environment
try
{
serialNumber = LedDeviceLightpack::getString(device, deviceDescriptor.iSerialNumber);
@@ -171,6 +212,7 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
if (requestedSerialNumber.isEmpty() || requestedSerialNumber == serialNumber)
{
// This is it!
// TODO: Check, if exceptions via try/catch need to be replaced in Qt environment
try
{
_deviceHandle = openDevice(device);
@@ -252,7 +294,7 @@ int LedDeviceLightpack::write(const std::vector<ColorRgb> &ledValues)
int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
{
int count = qMin(_hwLedCount, _ledCount);
int count = qMin(_hwLedCount, static_cast<int>( _ledCount));
for (int i = 0; i < count ; ++i)
{
@@ -275,8 +317,13 @@ int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
int LedDeviceLightpack::switchOff()
{
unsigned char buf[1] = {CMD_OFF_ALL};
return writeBytes(buf, sizeof(buf)) == sizeof(buf);
int rc = LedDevice::switchOff();
if ( _deviceReady )
{
unsigned char buf[1] = {CMD_OFF_ALL};
rc = writeBytes(buf, sizeof(buf)) == sizeof(buf);
}
return rc;
}
const QString &LedDeviceLightpack::getSerialNumber() const
@@ -284,11 +331,6 @@ const QString &LedDeviceLightpack::getSerialNumber() const
return _serialNumber;
}
int LedDeviceLightpack::getLedCount() const
{
return _ledCount;
}
int LedDeviceLightpack::writeBytes(uint8_t *data, int size)
{
// std::cout << "Writing " << size << " bytes: ";

View File

@@ -26,14 +26,14 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceLightpack(const QJsonObject &deviceConfig);
explicit LedDeviceLightpack(const QJsonObject &deviceConfig);
///
/// Sets configuration
///
/// @param deviceConfig the json device config
/// @return true if success
bool init(const QJsonObject &deviceConfig);
bool init(const QJsonObject &deviceConfig) override;
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
@@ -41,14 +41,14 @@ public:
///
/// Destructor of the LedDevice; closes the output device if it is open
///
virtual ~LedDeviceLightpack();
virtual ~LedDeviceLightpack() override;
///
/// Opens and configures the output device
///
/// @return Zero on succes else negative
///
int open();
int open() override;
///
/// Writes the RGB-Color values to the leds.
@@ -65,13 +65,19 @@ public:
///
/// @return Zero on success else negative
///
virtual int switchOff();
virtual int switchOff() override;
/// Get the serial of the Lightpack
const QString & getSerialNumber() const;
/// Get the number of leds
int getLedCount() const;
public slots:
///
/// Closes the output device.
/// Includes switching-off the device and stopping refreshes
///
virtual void close() override;
protected:
private:
///

View File

@@ -21,7 +21,8 @@ LedDeviceMultiLightpack::LedDeviceMultiLightpack(const QJsonObject &deviceConfig
: LedDevice()
, _lightpacks()
{
LedDevice::init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDeviceMultiLightpack::~LedDeviceMultiLightpack()
@@ -39,39 +40,58 @@ LedDevice* LedDeviceMultiLightpack::construct(const QJsonObject &deviceConfig)
int LedDeviceMultiLightpack::open()
{
// retrieve a list with Lightpack serials
QStringList serialList = getLightpackSerials();
int retval = -1;
QString errortext;
_deviceReady = false;
// 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
foreach (auto serial , serialList)
// General initialisation and configuration of LedDevice
if ( init(_devConfig) )
{
LedDeviceLightpack * device = new LedDeviceLightpack(serial);
int error = device->open();
// retrieve a list with Lightpack serials
QStringList serialList = getLightpackSerials();
if (error == 0)
// 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
foreach (auto serial , serialList)
{
_lightpacks.push_back(device);
LedDeviceLightpack * device = new LedDeviceLightpack(serial);
int error = device->open();
if (error == 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 );
delete device;
}
}
if (_lightpacks.size() == 0)
{
//Warning(_log, "No Lightpack devices were found");
errortext = QString ("No Lightpack devices were found");
}
else
{
Error(_log, "Error while creating Lightpack device with serial %s", QSTRING_CSTR(serial));
delete device;
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 );
}
}
if (_lightpacks.size() == 0)
{
Warning(_log, "No Lightpack devices were found");
}
else
{
Info(_log, "%d Lightpack devices were found", _lightpacks.size());
}
return _lightpacks.size() > 0 ? 0 : -1;
return retval;
}
int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
@@ -81,7 +101,7 @@ int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
for (LedDeviceLightpack * device : _lightpacks)
{
int count = qMin(device->getLedCount(), size);
int count = qMin(static_cast<int>( device->getLedCount()), size);
if (count > 0)
{
@@ -151,6 +171,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
QString serialNumber;
if (deviceDescriptor.iSerialNumber != 0)
{
// TODO: Check, if exceptions via try/catch need to be replaced in Qt environment
try
{
serialNumber = LedDeviceMultiLightpack::getString(deviceList[i], deviceDescriptor.iSerialNumber);

View File

@@ -22,29 +22,30 @@ public:
///
/// Constructs specific LedDevice
///
LedDeviceMultiLightpack(const QJsonObject &);
explicit LedDeviceMultiLightpack(const QJsonObject &);
///
/// Destructor of the LedDevice; closes the output device if it is open
///
virtual ~LedDeviceMultiLightpack();
virtual ~LedDeviceMultiLightpack() override;
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
///
virtual int switchOff() override;
protected:
///
/// Opens and configures the output device7
///
/// @return Zero on succes else negative
///
int open();
int open() override;
///
/// Switch the leds off
///
/// @return Zero on success else negative
///
virtual int switchOff();
private:
///
@@ -54,7 +55,7 @@ private:
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb>& ledValues);
virtual int write(const std::vector<ColorRgb>& ledValues) override;
static QStringList getLightpackSerials();
static QString getString(libusb_device * device, int stringDescriptorIndex);

View File

@@ -4,12 +4,10 @@
LedDevicePaintpack::LedDevicePaintpack(const QJsonObject &deviceConfig)
: ProviderHID()
{
ProviderHID::init(deviceConfig);
_useFeature = false;
_devConfig = deviceConfig;
_deviceReady = false;
_ledBuffer.resize(_ledRGBCount + 2, uint8_t(0));
_ledBuffer[0] = 3;
_ledBuffer[1] = 0;
_useFeature = false;
}
LedDevice* LedDevicePaintpack::construct(const QJsonObject &deviceConfig)
@@ -17,6 +15,17 @@ LedDevice* LedDevicePaintpack::construct(const QJsonObject &deviceConfig)
return new LedDevicePaintpack(deviceConfig);
}
bool LedDevicePaintpack::init(const QJsonObject &deviceConfig)
{
bool isInitOK = ProviderHID::init(deviceConfig);
_ledBuffer.resize(_ledRGBCount + 2, uint8_t(0));
_ledBuffer[0] = 3;
_ledBuffer[1] = 0;
return isInitOK;
}
int LedDevicePaintpack::write(const std::vector<ColorRgb> & ledValues)
{
auto bufIt = _ledBuffer.begin()+2;

View File

@@ -14,11 +14,18 @@ public:
///
/// @param deviceConfig json device config
///
LedDevicePaintpack(const QJsonObject &deviceConfig);
explicit LedDevicePaintpack(const QJsonObject &deviceConfig);
/// constructs leddevice
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 RGB-Color values to the leds.
@@ -27,5 +34,5 @@ private:
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb>& ledValues);
virtual int write(const std::vector<ColorRgb>& ledValues) override;
};

View File

@@ -4,9 +4,10 @@
LedDeviceRawHID::LedDeviceRawHID(const QJsonObject &deviceConfig)
: ProviderHID()
{
ProviderHID::init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
_useFeature = true;
_ledBuffer.resize(_ledRGBCount);
}
LedDevice* LedDeviceRawHID::construct(const QJsonObject &deviceConfig)
@@ -14,14 +15,18 @@ LedDevice* LedDeviceRawHID::construct(const QJsonObject &deviceConfig)
return new LedDeviceRawHID(deviceConfig);
}
bool LedDeviceRawHID::init(const QJsonObject &deviceConfig)
{
bool isInitOK = ProviderHID::init(deviceConfig);
_ledBuffer.resize(_ledRGBCount);
return isInitOK;
}
int LedDeviceRawHID::write(const std::vector<ColorRgb> & ledValues)
{
// write data
memcpy(_ledBuffer.data(), ledValues.data(), _ledRGBCount);
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
}
void LedDeviceRawHID::rewriteLeds()
{
writeBytes(_ledBuffer.size(), _ledBuffer.data());
}

View File

@@ -18,14 +18,17 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceRawHID(const QJsonObject &deviceConfig);
explicit LedDeviceRawHID(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
private slots:
/// Write the last data to the leds again
void rewriteLeds();
///
/// Sets configuration
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -34,5 +37,5 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> & ledValues);
virtual int write(const std::vector<ColorRgb> & ledValues) override;
};

View File

@@ -10,26 +10,22 @@
#include "ProviderHID.h"
ProviderHID::ProviderHID()
: _useFeature(false)
, _deviceHandle(nullptr)
, _blockedForDelay(false)
: _VendorId(0)
, _ProductId(0)
, _useFeature(false)
, _deviceHandle(nullptr)
, _delayAfterConnect_ms (0)
, _blockedForDelay(false)
{
}
ProviderHID::~ProviderHID()
{
if (_deviceHandle != nullptr)
{
hid_close(_deviceHandle);
_deviceHandle = nullptr;
}
hid_exit();
}
bool ProviderHID::init(const QJsonObject &deviceConfig)
{
LedDevice::init(deviceConfig);
bool isInitOK = LedDevice::init(deviceConfig);
_delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(0);
auto VendorIdString = deviceConfig["VID"].toString("0x2341").toStdString();
@@ -39,64 +35,94 @@ bool ProviderHID::init(const QJsonObject &deviceConfig)
_VendorId = std::stoul(VendorIdString, nullptr, 16);
_ProductId = std::stoul(ProductIdString, nullptr, 16);
return true;
return isInitOK;
}
int ProviderHID::open()
{
// Initialize the usb context
int error = hid_init();
if (error != 0)
{
Error(_log, "Error while initializing the hidapi context");
return -1;
}
Debug(_log,"Hidapi initialized");
int retval = -1;
QString errortext;
_deviceReady = false;
// Open the device
Info(_log, "Opening device: VID %04hx PID %04hx\n", _VendorId, _ProductId);
_deviceHandle = hid_open(_VendorId, _ProductId, nullptr);
if (_deviceHandle == nullptr)
if ( init(_devConfig) )
{
// 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.");
// 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;
while (cur_dev) {
printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls",
cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
printf("\n");
printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string);
printf(" Product: %ls\n", cur_dev->product_string);
printf("\n");
cur_dev = cur_dev->next;
// 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";
}
hid_free_enumeration(devs);
*/
return -1;
}
else
{
Info(_log,"Opened HID device successful");
}
// 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);
}
else
{
Debug(_log,"Hidapi initialized");
return 0;
// 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/
/*
std::cout << "Showing a list of all available HID devices:" << std::endl;
auto devs = hid_enumerate(0x00, 0x00);
auto cur_dev = devs;
while (cur_dev) {
printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls",
cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
printf("\n");
printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string);
printf(" Product: %ls\n", cur_dev->product_string);
printf("\n");
cur_dev = cur_dev->next;
}
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 );
}
}
return retval;
}
void ProviderHID::close()
{
LedDevice::close();
// LedDevice specific closing activites
if (_deviceHandle != nullptr)
{
hid_close(_deviceHandle);
_deviceHandle = nullptr;
}
hid_exit();
}
int ProviderHID::writeBytes(const unsigned size, const uint8_t * data)
{

View File

@@ -24,22 +24,30 @@ public:
///
/// Destructor of the LedDevice; closes the output device if it is open
///
virtual ~ProviderHID();
virtual ~ProviderHID() override;
///
/// Sets configuration
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig);
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:
///
/// Opens and configures the output device
///
/// @return Zero on succes else negative
///
int open();
protected:
int open() override;
/**
* Writes the given bytes to the HID-device and
*

View File

@@ -242,11 +242,6 @@ const std::string &LedDeviceLightpackHidapi::getSerialNumber() const
return _serialNumber;
}
int LedDeviceLightpackHidapi::getLedCount() const
{
return _ledCount;
}
int LedDeviceLightpackHidapi::writeBytes(uint8_t *data, int size)
{
// std::cout << "Writing " << size << " bytes: ";

View File

@@ -57,9 +57,6 @@ public:
/// Get the serial of the Lightpack
const std::string & getSerialNumber() const;
/// Get the number of leds
int getLedCount() const;
private:
///
/// Writes the RGB-Color values to the leds.

View File

@@ -2,58 +2,105 @@
#include "LedDeviceAtmoOrb.h"
// qt includes
#include <QtCore/qmath.h>
#include <QEventLoop>
#include <QtNetwork>
#include <QNetworkReply>
#include <QStringList>
AtmoOrbLight::AtmoOrbLight(unsigned int id)
{
// Not implemented
}
LedDeviceAtmoOrb::LedDeviceAtmoOrb(const QJsonObject &deviceConfig)
: LedDevice()
, _networkmanager (nullptr)
, _udpSocket (nullptr)
, _multiCastGroupPort (49692)
, joinedMulticastgroup (false)
, _useOrbSmoothing (false)
, _transitiontime (0)
, _skipSmoothingDiff (0)
, _numLeds (24)
{
init(deviceConfig);
_manager = new QNetworkAccessManager();
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceAtmoOrb::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceAtmoOrb(deviceConfig);
}
LedDeviceAtmoOrb::~LedDeviceAtmoOrb()
{
_networkmanager->deleteLater();
_udpSocket->deleteLater();
}
bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
{
bool isInitOK = LedDevice::init(deviceConfig);
if ( isInitOK )
{
_multicastGroup = deviceConfig["output"].toString().toStdString().c_str();
_useOrbSmoothing = deviceConfig["useOrbSmoothing"].toBool(false);
_transitiontime = deviceConfig["transitiontime"].toInt(0);
_skipSmoothingDiff = deviceConfig["skipSmoothingDiff"].toInt(0);
_multiCastGroupPort = static_cast<quint16>(deviceConfig["port"].toInt(49692));
_numLeds = deviceConfig["numLeds"].toInt(24);
const QStringList orbIds = deviceConfig["orbIds"].toString().simplified().remove(" ").split(",", QString::SkipEmptyParts);
_orbIds.clear();
foreach(auto & id_str, orbIds)
{
bool ok;
int id = id_str.toInt(&ok);
if (ok)
_orbIds.append(id);
else
Error(_log, "orb id '%s' is not a number", QSTRING_CSTR(id_str));
}
if ( _orbIds.size() == 0 )
{
this->setInError("No valid OrbIds found!");
isInitOK = false;
}
}
return isInitOK;
}
bool LedDeviceAtmoOrb::initNetwork()
{
bool isInitOK = true;
// TODO: Add Network-Error handling
_networkmanager = new QNetworkAccessManager();
_groupAddress = QHostAddress(_multicastGroup);
_udpSocket = new QUdpSocket(this);
_udpSocket->bind(QHostAddress::AnyIPv4, _multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
joinedMulticastgroup = _udpSocket->joinMulticastGroup(_groupAddress);
return isInitOK;
}
bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
int LedDeviceAtmoOrb::open()
{
_multicastGroup = deviceConfig["output"].toString().toStdString().c_str();
_useOrbSmoothing = deviceConfig["useOrbSmoothing"].toBool(false);
_transitiontime = deviceConfig["transitiontime"].toInt(0);
_skipSmoothingDiff = deviceConfig["skipSmoothingDiff"].toInt(0);
_multiCastGroupPort = deviceConfig["port"].toInt(49692);
_numLeds = deviceConfig["numLeds"].toInt(24);
const QStringList orbIds = deviceConfig["orbIds"].toString().simplified().remove(" ").split(",", QString::SkipEmptyParts);
_orbIds.clear();
int retval = -1;
_deviceReady = false;
foreach(auto & id_str, orbIds)
if ( init(_devConfig) )
{
bool ok;
int id = id_str.toInt(&ok);
if (ok)
_orbIds.append(id);
if ( !initNetwork() )
{
this->setInError( "Network error!" );
}
else
Error(_log, "orb id '%s' is not a number", QSTRING_CSTR(id_str));
{
_deviceReady = true;
setEnable(true);
retval = 0;
}
}
return _orbIds.size() > 0;
}
LedDevice* LedDeviceAtmoOrb::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceAtmoOrb(deviceConfig);
return retval;
}
int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues)
@@ -79,7 +126,7 @@ int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues)
// Iterate through colors and set Orb color
// Start off with idx 1 as 0 is reserved for controlling all orbs at once
unsigned int idx = 1;
int idx = 1;
for (const ColorRgb &color : ledValues)
{
@@ -125,7 +172,7 @@ int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues)
return 0;
}
void LedDeviceAtmoOrb::setColor(unsigned int orbId, const ColorRgb &color, int commandType)
void LedDeviceAtmoOrb::setColor(int orbId, const ColorRgb &color, int commandType)
{
QByteArray bytes;
bytes.resize(5 + _numLeds * 3);
@@ -155,17 +202,3 @@ void LedDeviceAtmoOrb::sendCommand(const QByteArray &bytes)
QByteArray datagram = bytes;
_udpSocket->writeDatagram(datagram.data(), datagram.size(), _groupAddress, _multiCastGroupPort);
}
int LedDeviceAtmoOrb::switchOff()
{
for (auto orbId : _orbIds)
{
setColor(orbId, ColorRgb::BLACK, 1);
}
return 0;
}
LedDeviceAtmoOrb::~LedDeviceAtmoOrb()
{
delete _manager;
}

View File

@@ -5,25 +5,13 @@
#include <QString>
#include <QNetworkAccessManager>
#include <QHostAddress>
#include <QMap>
#include <QVector>
// Leddevice includes
// LedDevice includes
#include <leddevice/LedDevice.h>
class QUdpSocket;
class AtmoOrbLight {
public:
unsigned int id;
///
/// Constructs the light.
///
/// @param id the orb id
AtmoOrbLight(unsigned int id);
};
/**
* Implementation for the AtmoOrb
*
@@ -35,52 +23,87 @@ class LedDeviceAtmoOrb : public LedDevice
{
Q_OBJECT
public:
// Last send color map
QMap<int, int> lastColorRedMap;
QMap<int, int> lastColorGreenMap;
QMap<int, int> lastColorBlueMap;
// Multicast status
bool joinedMulticastgroup;
///
/// Constructs specific LedDevice
///
/// @param deviceConfig json device config
///
LedDeviceAtmoOrb(const QJsonObject &deviceConfig);
explicit LedDeviceAtmoOrb(const QJsonObject &deviceConfig);
///
/// Sets configuration
///
/// @param deviceConfig the json device config
/// @return true if success
bool init(const QJsonObject &deviceConfig);
bool init(const QJsonObject &deviceConfig) override;
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
///
/// Destructor of this device
///
virtual ~LedDeviceAtmoOrb();
virtual ~LedDeviceAtmoOrb() override;
virtual int switchOff();
protected:
///
/// Initialise device's network details
///
/// @return True if success
bool initNetwork();
///
/// Opens and initiatialises the output device
///
/// @return Zero on succes (i.e. device is ready and enabled) else negative
///
virtual int open() 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);
virtual int write(const std::vector <ColorRgb> &ledValues) override;
///
/// Set Orbcolor
///
/// @param orbId the orb id
/// @param color which color to set
/// @param commandType which type of command to send (off / smoothing / etc..)
///
void setColor(int orbId, const ColorRgb &color, int commandType);
///
/// Send Orb command
///
/// @param bytes the byte array containing command to send over multicast
///
void sendCommand(const QByteArray &bytes);
/// QNetworkAccessManager object for sending requests.
QNetworkAccessManager *_manager;
QNetworkAccessManager *_networkmanager;
/// QUdpSocket object used to send data over
QUdpSocket * _udpSocket;
/// QHostAddress object of multicast group IP address
QHostAddress _groupAddress;
/// String containing multicast group IP address
QString _multicastGroup;
/// Multicast port to send data to
quint16 _multiCastGroupPort;
// Multicast status
bool joinedMulticastgroup;
/// use Orbs own (external) smoothing algorithm
bool _useOrbSmoothing;
@@ -90,34 +113,21 @@ private:
// Maximum allowed color difference, will skip Orb (external) smoothing once reached
int _skipSmoothingDiff;
/// Multicast port to send data to
int _multiCastGroupPort;
/// Number of leds in Orb, used to determine buffer size
int _numLeds;
/// QHostAddress object of multicast group IP address
QHostAddress _groupAddress;
/// QUdpSocket object used to send data over
QUdpSocket * _udpSocket;
/// Array of the orb ids.
QVector<unsigned int> _orbIds;
QVector<int> _orbIds;
// Last send color map
QMap<int, int> lastColorRedMap;
QMap<int, int> lastColorGreenMap;
QMap<int, int> lastColorBlueMap;
///
/// Set Orbcolor
///
/// @param orbId the orb id
/// @param color which color to set
/// @param commandType which type of command to send (off / smoothing / etc..)
///
void setColor(unsigned int orbId, const ColorRgb &color, int commandType);
///
/// Send Orb command
///
/// @param bytes the byte array containing command to send over multicast
///
void sendCommand(const QByteArray &bytes);
};

View File

@@ -9,13 +9,13 @@ LedDeviceFadeCandy::LedDeviceFadeCandy(const QJsonObject &deviceConfig)
: LedDevice()
, _client(nullptr)
{
_deviceReady = init(deviceConfig);
_client = new QTcpSocket(this);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDeviceFadeCandy::~LedDeviceFadeCandy()
{
_client->close();
_client->deleteLater();
}
LedDevice* LedDeviceFadeCandy::construct(const QJsonObject &deviceConfig)
@@ -25,45 +25,90 @@ LedDevice* LedDeviceFadeCandy::construct(const QJsonObject &deviceConfig)
bool LedDeviceFadeCandy::init(const QJsonObject &deviceConfig)
{
LedDevice::init(deviceConfig);
bool isInitOK = LedDevice::init(deviceConfig);
if (_ledCount > MAX_NUM_LEDS)
if ( isInitOK )
{
Error(_log, "fadecandy/opc: Invalid attempt to write led values. Not more than %d leds are allowed.", MAX_NUM_LEDS);
return false;
if (_ledCount > 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);
_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;
}
}
_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);
_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;
return true;
return isInitOK;
}
bool LedDeviceFadeCandy::initNetwork()
{
bool isInitOK = true;
// TODO: Add Network-Error handling
_client = new QTcpSocket(this);
return isInitOK;
}
int LedDeviceFadeCandy::open()
{
int retval = -1;
_deviceReady = false;
if ( init(_devConfig) )
{
if ( !initNetwork() )
{
this->setInError( "Network error!" );
}
else
{
_deviceReady = true;
setEnable(true);
retval = 0;
}
}
return retval;
}
void LedDeviceFadeCandy::close()
{
LedDevice::close();
// LedDevice specific closing activites
_client->close();
}
bool LedDeviceFadeCandy::isConnected()
{
return _client->state() == QAbstractSocket::ConnectedState;

View File

@@ -39,7 +39,7 @@ public:
///
/// @param deviceConfig json config for fadecandy
///
LedDeviceFadeCandy(const QJsonObject &deviceConfig);
explicit LedDeviceFadeCandy(const QJsonObject &deviceConfig);
///
/// Destructor of the LedDevice; closes the tcp client
@@ -54,7 +54,30 @@ public:
///
/// @param deviceConfig the json device config
/// @return true if success
bool init(const QJsonObject &deviceConfig);
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
///
/// @return True if success
bool initNetwork();
///
/// Opens and initiatialises the output device
///
/// @return Zero on succes (i.e. device is ready and enabled) else negative
///
virtual int open() override;
private:
///
@@ -63,25 +86,7 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb>& ledValues);
protected:
QTcpSocket* _client;
QString _host;
uint16_t _port;
unsigned _channel;
QByteArray _opc_data;
// fadecandy sysEx
bool _setFcConfig;
double _gamma;
double _whitePoint_r;
double _whitePoint_g;
double _whitePoint_b;
bool _noDither;
bool _noInterp;
bool _manualLED;
bool _ledOnOff;
virtual int write(const std::vector<ColorRgb>& ledValues) override;
/// try to establish connection to opc server, if not connected yet
///
@@ -112,4 +117,21 @@ protected:
/// sends the configuration to fcserver
void sendFadeCandyConfiguration();
QTcpSocket* _client;
QString _host;
uint16_t _port;
unsigned _channel;
QByteArray _opc_data;
// fadecandy sysEx
bool _setFcConfig;
double _gamma;
double _whitePoint_r;
double _whitePoint_g;
double _whitePoint_b;
bool _noDither;
bool _noInterp;
bool _manualLED;
bool _ledOnOff;
};

View File

@@ -17,7 +17,7 @@ static const bool verbose = false;
static const bool verbose3 = false;
// Controller configuration settings
static const char CONFIG_ADDRESS[] = "output";
static const char CONFIG_ADDRESS[] = "host";
//static const char CONFIG_PORT[] = "port";
static const char CONFIG_AUTH_TOKEN[] ="token";
@@ -85,120 +85,189 @@ LedDevice* LedDeviceNanoleaf::construct(const QJsonObject &deviceConfig)
return new LedDeviceNanoleaf(deviceConfig);
}
LedDeviceNanoleaf::~LedDeviceNanoleaf()
{
_networkmanager->deleteLater();
}
LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject &deviceConfig)
: ProviderUdp()
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
_networkmanager = nullptr;
_extControlVersion = EXTCTRLVER_V2;
_panelLedCount = 0;
}
bool LedDeviceNanoleaf::init(const QJsonObject &deviceConfig) {
bool LedDeviceNanoleaf::init(const QJsonObject &deviceConfig)
{
// Overwrite non supported/required features
_devConfig["latchTime"] = 0;
if (deviceConfig["rewriteTime"].toInt(0) > 0)
{
Info (_log, "Device Nanoleaf does not require rewrites. Refresh time is ignored.");
_devConfig["rewriteTime"] = 0;
}
LedDevice::init(deviceConfig);
DebugIf(verbose, _log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
uint configuredLedCount = static_cast<uint>(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());
bool isInitOK = LedDevice::init(deviceConfig);
//Set hostname as per configuration and default port
_hostname = deviceConfig[ CONFIG_ADDRESS ].toString();
_api_port = API_DEFAULT_PORT;
_auth_token = deviceConfig[ CONFIG_AUTH_TOKEN ].toString();
if ( isInitOK )
{
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, "LatchTime : %d", this->getLatchTime());
//If host not configured then discover device
if ( _hostname.isEmpty() )
//Discover Nanoleaf device
if ( !discoverNanoleafDevice() ) {
throw std::runtime_error("No target IP defined nor Nanoleaf device discovered");
//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();
//If host not configured then discover device
if ( _hostname.isEmpty() )
{
//Discover Nanoleaf device
if ( !discoverNanoleafDevice() )
{
this->setInError("No target IP defined nor Nanoleaf device was discovered");
return false;
}
}
// 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 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() )
{
isInitOK = false;
}
else
{
QJsonObject jsonAllPanelInfo = doc.object();
QJsonObject jsonAllPanelInfo = doc.object();
QString deviceName = jsonAllPanelInfo[DEV_DATA_NAME].toString();
_deviceModel = jsonAllPanelInfo[DEV_DATA_MODEL].toString();
QString deviceManufacturer = jsonAllPanelInfo[DEV_DATA_MANUFACTURER].toString();
_deviceFirmwareVersion = jsonAllPanelInfo[DEV_DATA_FIRMWAREVERSION].toString();
QString deviceName = jsonAllPanelInfo[DEV_DATA_NAME].toString();
_deviceModel = jsonAllPanelInfo[DEV_DATA_MODEL].toString();
QString deviceManufacturer = jsonAllPanelInfo[DEV_DATA_MANUFACTURER].toString();
_deviceFirmwareVersion = jsonAllPanelInfo[DEV_DATA_FIRMWAREVERSION].toString();
Debug(_log, "Name : %s", QSTRING_CSTR( deviceName ));
Debug(_log, "Model : %s", QSTRING_CSTR( _deviceModel ));
Debug(_log, "Manufacturer : %s", QSTRING_CSTR( deviceManufacturer ));
Debug(_log, "FirmwareVersion: %s", QSTRING_CSTR( _deviceFirmwareVersion));
Debug(_log, "Name : %s", QSTRING_CSTR( deviceName ));
Debug(_log, "Model : %s", QSTRING_CSTR( _deviceModel ));
Debug(_log, "Manufacturer : %s", QSTRING_CSTR( deviceManufacturer ));
Debug(_log, "FirmwareVersion: %s", QSTRING_CSTR( _deviceFirmwareVersion));
// Get panel details from /panelLayout/layout
QJsonObject jsonPanelLayout = jsonAllPanelInfo[API_PANELLAYOUT].toObject();
QJsonObject jsonLayout = jsonPanelLayout[PANEL_LAYOUT].toObject();
// Get panel details from /panelLayout/layout
QJsonObject jsonPanelLayout = jsonAllPanelInfo[API_PANELLAYOUT].toObject();
QJsonObject jsonLayout = jsonPanelLayout[PANEL_LAYOUT].toObject();
uint panelNum = static_cast<uint>(jsonLayout[PANEL_NUM].toInt());
QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray();
uint panelNum = static_cast<uint>(jsonLayout[PANEL_NUM].toInt());
QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray();
std::map<uint, std::map<uint, uint>> panelMap;
std::map<uint, std::map<uint, uint>> panelMap;
// Loop over all children.
foreach (const QJsonValue & value, positionData)
{
QJsonObject panelObj = value.toObject();
// Loop over all children.
foreach (const QJsonValue & value, positionData) {
QJsonObject panelObj = value.toObject();
uint panelId = static_cast<uint>(panelObj[PANEL_ID].toInt());
uint panelX = static_cast<uint>(panelObj[PANEL_POS_X].toInt());
uint panelY = static_cast<uint>(panelObj[PANEL_POS_Y].toInt());
uint panelshapeType = static_cast<uint>(panelObj[PANEL_SHAPE_TYPE].toInt());
//uint panelOrientation = static_cast<uint>(panelObj[PANEL_ORIENTATION].toInt());
uint panelId = static_cast<uint>(panelObj[PANEL_ID].toInt());
uint panelX = static_cast<uint>(panelObj[PANEL_POS_X].toInt());
uint panelY = static_cast<uint>(panelObj[PANEL_POS_Y].toInt());
uint panelshapeType = static_cast<uint>(panelObj[PANEL_SHAPE_TYPE].toInt());
//uint panelOrientation = static_cast<uint>(panelObj[PANEL_ORIENTATION].toInt());
DebugIf(verbose, _log, "Panel [%u] (%u,%u) - Type: [%u]", panelId, panelX, panelY, panelshapeType );
DebugIf(verbose, _log, "Panel [%u] (%u,%u) - Type: [%u]", panelId, panelX, panelY, panelshapeType );
// Skip Rhythm panels
if ( panelshapeType != RHYTM )
{
panelMap[panelY][panelX] = panelId;
}
else
{ // Reset non support/required features
Info(_log, "Rhythm panel skipped.");
}
}
// Skip Rhythm panels
if ( panelshapeType != RHYTM ) {
panelMap[panelY][panelX] = panelId;
} else {
Info(_log, "Rhythm panel skipped.");
// Sort panels top down, left right
for(auto posY = panelMap.crbegin(); posY != panelMap.crend(); ++posY)
{
// posY.first is the first key
for(auto const &posX : posY->second)
{
// posX.first is the second key, posX.second is the data
DebugIf(verbose3, _log, "panelMap[%u][%u]=%u", posY->first, posX.first, posX.second );
_panelIds.push_back(posX.second);
}
}
this->_panelLedCount = static_cast<uint>(_panelIds.size());
_devConfig["hardwareLedCount"] = static_cast<int>(_panelLedCount);
Debug(_log, "PanelsNum : %u", panelNum);
Debug(_log, "PanelLedCount : %u", _panelLedCount);
// Check. if enough panelds were found.
uint configuredLedCount = this->getLedCount();
if (_panelLedCount < configuredLedCount )
{
QString errorReason = QString("Not enough panels [%1] for configured LEDs [%2] found!")
.arg(_panelLedCount)
.arg(configuredLedCount);
this->setInError(errorReason);
isInitOK = false;
}
else
{
if ( _panelLedCount > this->getLedCount() )
{
Warning(_log, "Nanoleaf: More panels [%u] than configured LEDs [%u].", _panelLedCount, configuredLedCount );
}
}
}
// Sort panels top down, left right
for(auto posY = panelMap.crbegin(); posY != panelMap.crend(); ++posY) {
// posY.first is the first key
for(auto const &posX : posY->second) {
// posX.first is the second key, posX.second is the data
DebugIf(verbose3, _log, "panelMap[%u][%u]=%u", posY->first, posX.first, posX.second );
_panelIds.push_back(posX.second);
}
}
this->_panelLedCount = static_cast<uint>(_panelIds.size());
Debug(_log, "PanelsNum : %u", panelNum);
Debug(_log, "PanelLedCount : %u", _panelLedCount);
// Check. if enough panelds were found.
if (_panelLedCount < configuredLedCount) {
throw std::runtime_error ( (QString ("Not enough panels [%1] for configured LEDs [%2] found!").arg(_panelLedCount).arg(configuredLedCount)).toStdString() );
} else {
if ( _panelLedCount > static_cast<uint>(this->getLedCount()) ) {
Warning(_log, "Nanoleaf: More panels [%u] than configured LEDs [%u].", _panelLedCount, configuredLedCount );
}
}
// Set UDP streaming port
_port = STREAM_CONTROL_DEFAULT_PORT;
_defaultHost = _hostname;
switchOn();
ProviderUdp::init(deviceConfig);
Debug(_log, "Started successfully" );
return true;
return isInitOK;
}
bool LedDeviceNanoleaf::discoverNanoleafDevice() {
int LedDeviceNanoleaf::open()
{
int retval = -1;
_deviceReady = false;
if ( init(_devConfig) )
{
if ( initLeds() )
{
_deviceReady = true;
setEnable(true);
retval = 0;
}
}
return retval;
}
bool LedDeviceNanoleaf::discoverNanoleafDevice()
{
bool isDeviceFound (false);
// device searching by ssdp
@@ -229,7 +298,9 @@ bool LedDeviceNanoleaf::discoverNanoleafDevice() {
return isDeviceFound;
}
QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode() {
QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode()
{
QString url = getUrl(_hostname, _api_port, _auth_token, API_EFFECT );
QJsonDocument jsonDoc;
@@ -245,7 +316,8 @@ QString LedDeviceNanoleaf::getUrl(QString host, QString port, QString auth_token
return QString(API_URL_FORMAT).arg(host, port, auth_token, endpoint);
}
QJsonDocument LedDeviceNanoleaf::getJson(QString url) const {
QJsonDocument LedDeviceNanoleaf::getJson(QString url)
{
Debug(_log, "GET: [%s]", QSTRING_CSTR( url ));
@@ -269,7 +341,8 @@ QJsonDocument LedDeviceNanoleaf::getJson(QString url) const {
return jsonDoc;
}
QJsonDocument LedDeviceNanoleaf::putJson(QString url, QString json) const {
QJsonDocument LedDeviceNanoleaf::putJson(QString url, QString json)
{
Debug(_log, "PUT: [%s] [%s]", QSTRING_CSTR( url ), QSTRING_CSTR( json ) );
// Perfrom request
@@ -293,15 +366,15 @@ QJsonDocument LedDeviceNanoleaf::putJson(QString url, QString json) const {
return jsonDoc;
}
QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply ) const {
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(reply->error() == QNetworkReply::NoError)
{
if ( httpStatusCode != 204 ){
QByteArray response = reply->readAll();
@@ -309,8 +382,7 @@ QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply ) const
jsonDoc = QJsonDocument::fromJson(response, &error);
if (error.error != QJsonParseError::NoError)
{
Error (_log, "Got invalid response");
throw std::runtime_error("");
this->setInError ( "Got invalid response" );
}
else {
//Debug
@@ -326,35 +398,30 @@ QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply ) const
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;
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);
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());
}
Error (_log, "%s", QSTRING_CSTR( errorReason ));
throw std::runtime_error("Network Error");
this->setInError ( errorReason );
}
// Return response
return jsonDoc;
}
LedDeviceNanoleaf::~LedDeviceNanoleaf()
{
delete _networkmanager;
}
int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
{
@@ -396,7 +463,7 @@ int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
lowByte = static_cast<uchar>(panelID & 0xFF);
// Set panels configured
if( panelCounter < static_cast<uint>(this->getLedCount()) ) {
if( panelCounter < this->getLedCount() ) {
color = static_cast<ColorRgb>(ledValues.at(panelCounter));
}
else
@@ -437,40 +504,43 @@ int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
return retVal;
}
QString LedDeviceNanoleaf::getOnOffRequest (bool isOn ) const {
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() {
Debug(_log, "switchOn()");
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());
}
// 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) );
}
//Switch on Nanoleaf device
QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
putJson(url, this->getOnOffRequest(true) );
return 0;
}
int LedDeviceNanoleaf::switchOff() {
Debug(_log, "switchOff()");
int LedDeviceNanoleaf::switchOff()
{
//Set all LEDs to Black
int rc = writeBlack();
//Switch off Nanoleaf device physically
QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
putJson(url, getOnOffRequest(false) );
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;
}
@@ -480,7 +550,7 @@ std::string LedDeviceNanoleaf:: uint8_vector_to_hex_string( const std::vector<ui
ss << std::hex << std::setfill('0');
std::vector<uint8_t>::const_iterator it;
for (it = buffer.begin(); it != buffer.end(); it++)
for (it = buffer.begin(); it != buffer.end(); ++it)
{
ss << " " << std::setw(2) << static_cast<unsigned>(*it);
}

View File

@@ -18,134 +18,143 @@
class LedDeviceNanoleaf : public ProviderUdp
{
public:
///
/// Constructs the LedDevice for Nanoleaf LightPanels (aka Aurora) or Canvas
///
/// following code shows all config options
/// @code
/// "device" :
/// {
/// "type" : "nanoleaf"
/// "output" : "hostname or IP", // Optional. If empty, device is tried to be discovered
/// "token" : "Authentication Token",
/// },
///@endcode
///
/// @param deviceConfig json config for nanoleaf
///
LedDeviceNanoleaf(const QJsonObject &deviceConfig);
///
/// Constructs the LedDevice for Nanoleaf LightPanels (aka Aurora) or Canvas
///
/// following code shows all config options
/// @code
/// "device" :
/// {
/// "type" : "nanoleaf"
/// "output" : "hostname or IP", // Optional. If empty, device is tried to be discovered
/// "token" : "Authentication Token",
/// },
///@endcode
///
/// @param deviceConfig json config for nanoleaf
///
explicit LedDeviceNanoleaf(const QJsonObject &deviceConfig);
///
/// Destructor of the LedDevice; closes the tcp client
///
virtual ~LedDeviceNanoleaf();
///
/// Destructor of the LedDevice; closes the tcp client
///
virtual ~LedDeviceNanoleaf() override;
/// Constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
/// Constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
/// Switch the leds on
virtual int switchOn();
/// Switch the device on
virtual int switchOn() override;
/// Switch the leds off
virtual int switchOff();
/// Switch the device off
virtual int switchOff() override;
protected:
///
/// 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);
///
/// 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;
///
/// Identifies a Nanoleaf device's panel configuration,
/// sets device into External Control (UDP) mode
///
/// @param deviceConfig the json device config
/// @return true if success
/// @exception runtime_error in case device cannot be initialised
/// e.g. more LEDs configured than device has panels or network problems
///
bool init(const QJsonObject &deviceConfig);
///
/// Initialise Nanoleaf device's configuration and network address details
///
/// @param deviceConfig the json device config
/// @return True if success
///
bool init(const QJsonObject &deviceConfig) override;
///
/// Get Nanoleaf device details and configuration
///
/// @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
///
virtual int open() override;
private:
// QNetworkAccessManager object for sending requests.
QNetworkAccessManager* _networkmanager;
// QNetworkAccessManager object for sending requests.
QNetworkAccessManager* _networkmanager;
QString _hostname;
QString _api_port;
QString _auth_token;
QString _hostname;
QString _api_port;
QString _auth_token;
//Nanoleaf device details
QString _deviceModel;
QString _deviceFirmwareVersion;
ushort _extControlVersion;
/// The number of panels with leds
//Nanoleaf device details
QString _deviceModel;
QString _deviceFirmwareVersion;
ushort _extControlVersion;
/// The number of panels with leds
uint _panelLedCount;
/// Array of the pannel ids.
std::vector<uint> _panelIds;
/// Array of the pannel ids.
std::vector<uint> _panelIds;
///
/// Discover Nanoleaf device via SSDP identifiers
///
/// @return True, if Nanoleaf device was found
///
bool discoverNanoleafDevice();
///
/// Discover Nanoleaf device via SSDP identifiers
///
/// @return True, if Nanoleaf device was found
///
bool discoverNanoleafDevice();
///
/// Change Nanoleaf device to External Control (UDP) mode
///
/// @return Response from device
///
QJsonDocument changeToExternalControlMode();
///
/// Change Nanoleaf device to External Control (UDP) mode
///
/// @return Response from device
///
QJsonDocument changeToExternalControlMode();
///
/// Get command to switch Nanoleaf device on or off
///
/// @param isOn True, if to switch on device
/// @return Command to switch device on/off
///
QString getOnOffRequest (bool isOn ) const;
///
/// Get command to switch Nanoleaf device on or off
///
/// @param isOn True, if to switch on device
/// @return Command to switch device on/off
///
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;
///
/// 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) 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) const;
///
/// Handle replys for GET and PUT requests
///
/// @param reply Network reply
/// @return Response for request, if no error
/// @exception runtime_error for network or request errors
///
QJsonDocument handleReply(QNetworkReply* const &reply ) const;
///
/// 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

View File

@@ -217,7 +217,7 @@ public:
///
/// @param deviceConfig json device config
///
LedDevicePhilipsHue(const QJsonObject &deviceConfig);
explicit LedDevicePhilipsHue(const QJsonObject &deviceConfig);
///
/// Destructor of this device
@@ -229,7 +229,7 @@ public:
public slots:
/// thread start
virtual void start();
virtual void start() override;
private slots:
/// creates new PhilipsHueLight(s) based on user lightid with bridge feedback
@@ -248,8 +248,8 @@ protected:
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb> & ledValues);
bool init(const QJsonObject &deviceConfig);
virtual int write(const std::vector<ColorRgb> & ledValues) override;
bool init(const QJsonObject &deviceConfig) override;
private:
/// bridge class

View File

@@ -3,18 +3,8 @@
LedDeviceTpm2net::LedDeviceTpm2net(const QJsonObject &deviceConfig)
: ProviderUdp()
{
_deviceReady = init(deviceConfig);
}
bool LedDeviceTpm2net::init(const QJsonObject &deviceConfig)
{
_port = TPM2_DEFAULT_PORT;
ProviderUdp::init(deviceConfig);
_tpm2_max = deviceConfig["max-packet"].toInt(170);
_tpm2ByteCount = 3 * _ledCount;
_tpm2TotalPackets = 1 + _tpm2ByteCount / _tpm2_max;
return true;
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceTpm2net::construct(const QJsonObject &deviceConfig)
@@ -22,8 +12,17 @@ LedDevice* LedDeviceTpm2net::construct(const QJsonObject &deviceConfig)
return new LedDeviceTpm2net(deviceConfig);
}
bool LedDeviceTpm2net::init(const QJsonObject &deviceConfig)
{
_port = TPM2_DEFAULT_PORT;
bool isInitOK = ProviderUdp::init(deviceConfig);
// populates the headers
_tpm2_max = deviceConfig["max-packet"].toInt(170);
_tpm2ByteCount = 3 * _ledCount;
_tpm2TotalPackets = 1 + _tpm2ByteCount / _tpm2_max;
return isInitOK;
}
int LedDeviceTpm2net::write(const std::vector<ColorRgb> &ledValues)
{

View File

@@ -3,7 +3,7 @@
// hyperion includes
#include "ProviderUdp.h"
#define TPM2_DEFAULT_PORT 65506
const ushort TPM2_DEFAULT_PORT = 65506;
///
/// Implementation of the LedDevice interface for sending led colors via udp tpm2.net packets
@@ -16,17 +16,17 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceTpm2net(const QJsonObject &deviceConfig);
explicit LedDeviceTpm2net(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
///
/// Sets configuration
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -35,7 +35,7 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
int _tpm2_max;
int _tpm2ByteCount;

View File

@@ -7,17 +7,8 @@
LedDeviceUdpArtNet::LedDeviceUdpArtNet(const QJsonObject &deviceConfig)
: ProviderUdp()
{
_deviceReady = init(deviceConfig);
}
bool LedDeviceUdpArtNet::init(const QJsonObject &deviceConfig)
{
_port = 6454;
ProviderUdp::init(deviceConfig);
_artnet_universe = deviceConfig["universe"].toInt(1);
_artnet_channelsPerFixture = deviceConfig["channelsPerFixture"].toInt(3);
return true;
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceUdpArtNet::construct(const QJsonObject &deviceConfig)
@@ -25,6 +16,16 @@ LedDevice* LedDeviceUdpArtNet::construct(const QJsonObject &deviceConfig)
return new LedDeviceUdpArtNet(deviceConfig);
}
bool LedDeviceUdpArtNet::init(const QJsonObject &deviceConfig)
{
_port = ARTNET_DEFAULT_PORT;
bool isInitOK = ProviderUdp::init(deviceConfig);
_artnet_universe = deviceConfig["universe"].toInt(1);
_artnet_channelsPerFixture = deviceConfig["channelsPerFixture"].toInt(3);
return isInitOK;
}
// populates the headers
void LedDeviceUdpArtNet::prepare(const unsigned this_universe, const unsigned this_sequence, unsigned this_dmxChannelCount)
@@ -66,7 +67,7 @@ The Sequence field is set to 0x00 to disable this feature.
int dmxIdx = 0; // offset into the current dmx packet
memset(artnet_packet.raw, 0, sizeof(artnet_packet.raw));
for (int ledIdx = 0; ledIdx < _ledRGBCount; ledIdx++)
for (unsigned int ledIdx = 0; ledIdx < _ledRGBCount; ledIdx++)
{
artnet_packet.Data[dmxIdx++] = rawdata[ledIdx];
@@ -90,4 +91,3 @@ The Sequence field is set to 0x00 to disable this feature.
return retVal;
}

View File

@@ -13,7 +13,7 @@
*
**/
#define ArtNet_DEFAULT_PORT 5568
const ushort ARTNET_DEFAULT_PORT = 6454;
#define DMX_MAX 512 // 512 usable slots
@@ -47,18 +47,17 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceUdpArtNet(const QJsonObject &deviceConfig);
explicit LedDeviceUdpArtNet(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);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -67,13 +66,13 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
void prepare(const unsigned this_universe, const unsigned this_sequence, const unsigned this_dmxChannelCount);
artnet_packet_t artnet_packet;
uint8_t _artnet_seq = 1;
uint8_t _artnet_channelsPerFixture = 3;
unsigned _artnet_universe = 1;
int _artnet_channelsPerFixture = 3;
int _artnet_universe = 1;
};

View File

@@ -7,27 +7,32 @@
LedDeviceUdpE131::LedDeviceUdpE131(const QJsonObject &deviceConfig)
: ProviderUdp()
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig)
{
_port = 5568;
ProviderUdp::init(deviceConfig);
_e131_universe = deviceConfig["universe"].toInt(1);
_e131_source_name = deviceConfig["source-name"].toString("hyperion on "+QHostInfo::localHostName());
QString _json_cid = deviceConfig["cid"].toString("");
if (_json_cid.isEmpty())
_port = E131_DEFAULT_PORT;
bool isInitOK = ProviderUdp::init(deviceConfig);
if ( isInitOK )
{
_e131_cid = QUuid::createUuid();
Debug( _log, "e131 no cid found, generated %s", QSTRING_CSTR(_e131_cid.toString()));
} else {
_e131_cid = QUuid(_json_cid);
Debug( _log, "e131 cid found, using %s", QSTRING_CSTR(_e131_cid.toString()));
}
_e131_universe = deviceConfig["universe"].toInt(1);
_e131_source_name = deviceConfig["source-name"].toString("hyperion on "+QHostInfo::localHostName());
QString _json_cid = deviceConfig["cid"].toString("");
return true;
if (_json_cid.isEmpty())
{
_e131_cid = QUuid::createUuid();
Debug( _log, "e131 no cid found, generated %s", QSTRING_CSTR(_e131_cid.toString()));
}
else
{
_e131_cid = QUuid(_json_cid);
Debug( _log, "e131 cid found, using %s", QSTRING_CSTR(_e131_cid.toString()));
}
}
return isInitOK;
}
LedDevice* LedDeviceUdpE131::construct(const QJsonObject &deviceConfig)
@@ -35,7 +40,6 @@ LedDevice* LedDeviceUdpE131::construct(const QJsonObject &deviceConfig)
return new LedDeviceUdpE131(deviceConfig);
}
// populates the headers
void LedDeviceUdpE131::prepare(const unsigned this_universe, const unsigned this_dmxChannelCount)
{

View File

@@ -18,7 +18,7 @@
*
**/
#define E131_DEFAULT_PORT 5568
const ushort E131_DEFAULT_PORT = 5568;
/* E1.31 Packet Offsets */
#define E131_ROOT_PREAMBLE_SIZE 0
@@ -105,18 +105,17 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceUdpE131(const QJsonObject &deviceConfig);
explicit LedDeviceUdpE131(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);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -125,7 +124,7 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
void prepare(const unsigned this_universe, const unsigned this_dmxChannelCount);

View File

@@ -3,43 +3,46 @@
LedDeviceUdpH801::LedDeviceUdpH801(const QJsonObject &deviceConfig)
: ProviderUdp()
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceUdpH801::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceUdpH801(deviceConfig);
}
bool LedDeviceUdpH801::init(const QJsonObject &deviceConfig)
{
/* The H801 port is fixed */
_latchTime_ms = 10;
_port = 30977;
_defaultHost = "255.255.255.255";
ProviderUdp::init(deviceConfig);
_port = H801_DEFAULT_PORT;
_defaultHost = H801_DEFAULT_HOST;
_ids.clear();
QJsonArray lArray = deviceConfig["lightIds"].toArray();
for (int i = 0; i < lArray.size(); i++)
bool isInitOK = ProviderUdp::init(deviceConfig);
if ( isInitOK )
{
QString id = lArray[i].toString();
_ids.push_back(id.toInt(nullptr, 16));
_ids.clear();
QJsonArray lArray = deviceConfig["lightIds"].toArray();
for (int i = 0; i < lArray.size(); i++)
{
QString id = lArray[i].toString();
_ids.push_back(id.toInt(nullptr, 16));
}
_message = QByteArray(_prefix_size + _colors + _id_size * _ids.size() + _suffix_size, 0x00);
_message[0] = 0xFB;
_message[1] = 0xEB;
for (int i = 0; i < _ids.length(); i++) {
_message[_prefix_size + _colors + i * _id_size + 0] = (_ids[i] >> 0x00) & 0xFF;
_message[_prefix_size + _colors + i * _id_size + 1] = (_ids[i] >> 0x08) & 0xFF;
_message[_prefix_size + _colors + i * _id_size + 2] = (_ids[i] >> 0x10) & 0xFF;
}
Debug(_log, "H801 using %s:%d", _address.toString().toStdString().c_str(), _port);
}
_message = QByteArray(_prefix_size + _colors + _id_size * _ids.size() + _suffix_size, 0x00);
_message[0] = 0xFB;
_message[1] = 0xEB;
for (int i = 0; i < _ids.length(); i++) {
_message[_prefix_size + _colors + i * _id_size + 0] = (_ids[i] >> 0x00) & 0xFF;
_message[_prefix_size + _colors + i * _id_size + 1] = (_ids[i] >> 0x08) & 0xFF;
_message[_prefix_size + _colors + i * _id_size + 2] = (_ids[i] >> 0x10) & 0xFF;
}
Debug(_log, "H801 using %s:%d", _address.toString().toStdString().c_str(), _port);
return true;
}
LedDevice* LedDeviceUdpH801::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceUdpH801(deviceConfig);
return isInitOK;
}
int LedDeviceUdpH801::write(const std::vector<ColorRgb> &ledValues)

View File

@@ -6,6 +6,11 @@
///
/// Implementation of the LedDevice interface for sending led colors via udp.
///
///
const ushort H801_DEFAULT_PORT = 30977;
static const char H801_DEFAULT_HOST[] = "255.255.255.255";
class LedDeviceUdpH801: public ProviderUdp
{
protected:
@@ -22,17 +27,16 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceUdpH801(const QJsonObject &deviceConfig);
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);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -41,5 +45,5 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
};

View File

@@ -3,8 +3,8 @@
LedDeviceUdpRaw::LedDeviceUdpRaw(const QJsonObject &deviceConfig)
: ProviderUdp()
{
_port = 5568;
init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceUdpRaw::construct(const QJsonObject &deviceConfig)
@@ -12,6 +12,13 @@ LedDevice* LedDeviceUdpRaw::construct(const QJsonObject &deviceConfig)
return new LedDeviceUdpRaw(deviceConfig);
}
bool LedDeviceUdpRaw::init(const QJsonObject &deviceConfig)
{
_port = RAW_DEFAULT_PORT;
bool isInitOK = ProviderUdp::init(deviceConfig);
return isInitOK;
}
int LedDeviceUdpRaw::write(const std::vector<ColorRgb> &ledValues)
{
const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());

View File

@@ -1,8 +1,10 @@
#pragma once
// hyperion incluse
// hyperion includes
#include "ProviderUdp.h"
#define RAW_DEFAULT_PORT 5568
///
/// Implementation of the LedDevice interface for sending led colors via udp.
///
@@ -14,16 +16,24 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceUdpRaw(const QJsonObject &deviceConfig);
explicit LedDeviceUdpRaw(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);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
};

View File

@@ -17,21 +17,22 @@
ProviderUdp::ProviderUdp()
: LedDevice()
, _port(1)
, _defaultHost("127.0.0.1")
, _udpSocket (nullptr)
, _port(1)
, _defaultHost("127.0.0.1")
{
_deviceReady = false;
_latchTime_ms = 1;
_udpSocket = new QUdpSocket(this);
}
ProviderUdp::~ProviderUdp()
{
_udpSocket->close();
_udpSocket->deleteLater();
}
bool ProviderUdp::init(const QJsonObject &deviceConfig)
{
LedDevice::init(deviceConfig);
bool isInitOK = LedDevice::init(deviceConfig);
QString host = deviceConfig["host"].toString(_defaultHost);
@@ -41,36 +42,86 @@ bool ProviderUdp::init(const QJsonObject &deviceConfig)
}
else
{
Debug( _log, "Failed to parse %s as an ip address.", deviceConfig["host"].toString().toStdString().c_str());
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());
throw std::runtime_error("invalid target address");
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();
}
Debug( _log, "Successfully parsed %s as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
_address = info.addresses().first();
}
_port = deviceConfig["port"].toInt(_port);
if ( (_port <= 0) || (_port > MAX_PORT) )
int config_port = deviceConfig["port"].toInt(_port);
if ( config_port <= 0 || config_port > MAX_PORT )
{
throw std::runtime_error("invalid target 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 );
}
Debug( _log, "UDP using %s:%d", _address.toString().toStdString().c_str() , _port );
return isInitOK;
}
return true;
bool ProviderUdp::initNetwork()
{
bool isInitOK = true;
// TODO: Add Network-Error handling
_udpSocket = new QUdpSocket(this);
return isInitOK;
}
int ProviderUdp::open()
{
QHostAddress localAddress = QHostAddress::Any;
quint16 localPort = 0;
int retval = -1;
QString errortext;
_deviceReady = false;
WarningIf( !_udpSocket->bind(localAddress, localPort), _log, "Could not bind local address: %s", strerror(errno));
if ( init(_devConfig) )
{
if ( ! initNetwork())
{
this->setInError( "Network error!" );
}
else
{
QHostAddress localAddress = QHostAddress::Any;
quint16 localPort = 0;
return 0;
if ( !_udpSocket->bind(localAddress, localPort) )
{
Warning ( _log, "Could not bind local address: %s", strerror(errno));
}
// Everything is OK -> enable device
_deviceReady = true;
setEnable(true);
retval = 0;
}
}
return retval;
}
void ProviderUdp::close()
{
LedDevice::close();
// LedDevice specific closing activites
if ( _udpSocket != nullptr)
{
_udpSocket->close();
}
}
int ProviderUdp::writeBytes(const unsigned size, const uint8_t * data)

View File

@@ -9,7 +9,7 @@
class QUdpSocket;
#define MAX_PORT 65535
const ushort MAX_PORT = 65535;
///
/// The ProviderUdp implements an abstract base-class for LedDevices using UDP packets.
@@ -25,23 +25,37 @@ public:
///
/// Destructor of the LedDevice; closes the output device if it is open
///
virtual ~ProviderUdp();
virtual ~ProviderUdp() override;
///
/// Sets configuration
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig);
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
///
/// @return True if success
bool initNetwork();
///
/// Opens and configures the output device
///
/// @return Zero on succes else negative
///
int open();
int open() override;
protected:
///
/// Writes the given bytes/bits to the UDP-device and sleeps the latch time to ensure that the
/// values are latched.

View File

@@ -7,7 +7,9 @@
LedDeviceFile::LedDeviceFile(const QJsonObject &deviceConfig)
: LedDevice()
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
_printTimeStamp = false;
}
LedDeviceFile::~LedDeviceFile()
@@ -21,39 +23,83 @@ LedDevice* LedDeviceFile::construct(const QJsonObject &deviceConfig)
bool LedDeviceFile::init(const QJsonObject &deviceConfig)
{
LedDevice::init(deviceConfig);
_refresh_timer_interval = 0;
bool initOK = LedDevice::init(deviceConfig);
_fileName = deviceConfig["output"].toString("/dev/null");
_printTimeStamp = deviceConfig["printTimeStamp"].toBool(false);
return true;
return initOK;
}
int LedDeviceFile::open()
{
if ( _ofs.is_open() )
int retval = -1;
QString errortext;
_deviceReady = false;
if ( init(_devConfig) )
{
if ( _ofs.is_open() )
{
_ofs.close();
}
_ofs.open( QSTRING_CSTR(_fileName));
if ( _ofs.fail() )
{
errortext = QString ("Failed to open file (%1). Error message: %2").arg(_fileName, strerror(errno));
}
else
{
_deviceReady = true;
setEnable(true);
retval = 0;
}
if ( retval < 0 )
{
this->setInError( errortext );
}
}
return retval;
}
void LedDeviceFile::close()
{
LedDevice::close();
// LedDevice specific closing activites
if ( _ofs )
{
_ofs.close();
if ( _ofs.fail() )
{
Error( _log, "Failed to close device (%s). Error message: %s", QSTRING_CSTR(_fileName), strerror(errno) );
}
}
_ofs.open( QSTRING_CSTR(_fileName) );
return 0;
}
int LedDeviceFile::write(const std::vector<ColorRgb> & ledValues)
{
//printLedValues (ledValues);
if ( _printTimeStamp )
{
// get a precise timestamp as a string
const auto now = std::chrono::system_clock::now();
const auto nowAsTimeT = std::chrono::system_clock::to_time_t(now);
const auto nowMs = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()) % 1000;
now.time_since_epoch()) % 1000;
const auto elapsedTimeMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastWriteTime);
_ofs
<< std::put_time(std::localtime(&nowAsTimeT), "%Y-%m-%d %T")
<< '.' << std::setfill('0') << std::setw(3) << nowMs.count();
<< '.' << std::setfill('0') << std::setw(3) << nowMs.count()
<< " | +" << std::setfill('0') << std::setw(4) << elapsedTimeMs.count();
lastWriteTime = now;
}
_ofs << " [";
for (const ColorRgb& color : ledValues)
{

View File

@@ -2,6 +2,7 @@
// STL includes
#include <fstream>
#include <chrono>
// Leddevice includes
#include <leddevice/LedDevice.h>
@@ -18,12 +19,12 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceFile(const QJsonObject &deviceConfig);
explicit LedDeviceFile(const QJsonObject &deviceConfig);
///
/// Destructor of this test-device
///
virtual ~LedDeviceFile();
virtual ~LedDeviceFile() override;
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
@@ -33,16 +34,23 @@ public:
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig);
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:
///
/// Opens and configures the output file
/// Opens and initiatialises the output device
///
/// @return Zero on succes else negative
/// @return Zero on succes (i.e. device is ready and enabled) else negative
///
///
virtual int open();
virtual int open() override;
///
/// Writes the given led-color values to the output stream
///
@@ -50,7 +58,7 @@ protected:
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb> & ledValues);
virtual int write(const std::vector<ColorRgb> & ledValues) override;
/// The outputstream
std::ofstream _ofs;
@@ -60,4 +68,7 @@ private:
QString _fileName;
/// Timestamp for the output record
bool _printTimeStamp;
/// Last write/output timestamp
std::chrono::system_clock::time_point lastWriteTime = std::chrono::system_clock::now();
};

View File

@@ -12,12 +12,15 @@
LedDevicePiBlaster::LedDevicePiBlaster(const QJsonObject &deviceConfig)
: _fid(nullptr)
{
_devConfig = deviceConfig;
_deviceReady = false;
signal(SIGPIPE, SIG_IGN);
// initialise the mapping tables
// -1 is invalid
// z is also meaningless
// { "gpio" : 4, "ledindex" : 0, "ledcolor" : "r" },
// initialise the mapping tables
// -1 is invalid
// z is also meaningless
// { "gpio" : 4, "ledindex" : 0, "ledcolor" : "r" },
#define TABLE_SZ sizeof(_gpio_to_led)/sizeof(_gpio_to_led[0])
for (unsigned i=0; i < TABLE_SZ; i++ )
@@ -25,51 +28,48 @@ LedDevicePiBlaster::LedDevicePiBlaster(const QJsonObject &deviceConfig)
_gpio_to_led[i] = -1;
_gpio_to_color[i] = 'z';
}
_deviceReady = init(deviceConfig);
}
LedDevicePiBlaster::~LedDevicePiBlaster()
{
// Close the device (if it is opened)
if (_fid != nullptr)
{
fclose(_fid);
_fid = nullptr;
}
}
bool LedDevicePiBlaster::init(const QJsonObject &deviceConfig)
{
LedDevice::init(deviceConfig);
bool isInitOK = LedDevice::init(deviceConfig);
_deviceName = deviceConfig["output"].toString("/dev/pi-blaster");
QJsonArray gpioMapping = deviceConfig["gpiomap"].toArray();
if (gpioMapping.isEmpty())
if ( isInitOK )
{
throw std::runtime_error("Piblaster: no gpiomap defined.");
}
QJsonArray gpioMapping = deviceConfig["gpiomap"].toArray();
// walk through the json config and populate the mapping tables
for(QJsonArray::const_iterator gpioArray = gpioMapping.begin(); gpioArray != gpioMapping.end(); ++gpioArray)
{
const QJsonObject value = (*gpioArray).toObject();
const int gpio = value["gpio"].toInt(-1);
const int ledindex = value["ledindex"].toInt(-1);
const std::string ledcolor = value["ledcolor"].toString("z").toStdString();
if (gpioMapping.isEmpty())
{
this->setInError("PiBlaster: no gpiomap defined.");
return false;
}
// ignore missing/invalid settings
if ( (gpio >= 0) && (gpio < signed(TABLE_SZ)) && (ledindex >= 0) ){
_gpio_to_led[gpio] = ledindex;
_gpio_to_color[gpio] = ledcolor[0]; // 1st char of string
} else {
Warning( _log, "IGNORING gpio %d ledindex %d color %c", gpio,ledindex, ledcolor[0]);
// walk through the json config and populate the mapping tables
for(QJsonArray::const_iterator gpioArray = gpioMapping.begin(); gpioArray != gpioMapping.end(); ++gpioArray)
{
const QJsonObject value = (*gpioArray).toObject();
const int gpio = value["gpio"].toInt(-1);
const int ledindex = value["ledindex"].toInt(-1);
const std::string ledcolor = value["ledcolor"].toString("z").toStdString();
// ignore missing/invalid settings
if ( (gpio >= 0) && (gpio < signed(TABLE_SZ)) && (ledindex >= 0) ){
_gpio_to_led[gpio] = ledindex;
_gpio_to_color[gpio] = ledcolor[0]; // 1st char of string
} else {
Warning( _log, "IGNORING gpio %d ledindex %d color %c", gpio,ledindex, ledcolor[0]);
}
}
}
return true;
return isInitOK;
}
LedDevice* LedDevicePiBlaster::construct(const QJsonObject &deviceConfig)
@@ -79,30 +79,61 @@ LedDevice* LedDevicePiBlaster::construct(const QJsonObject &deviceConfig)
int LedDevicePiBlaster::open()
{
int retval = -1;
QString errortext;
_deviceReady = false;
if ( init(_devConfig) )
{
if (_fid != nullptr)
{
// The file pointer is already open
errortext = QString ("Device (%1) is already open.").arg(_deviceName);
}
else
{
if (!QFile::exists(_deviceName))
{
errortext = QString ("The device (%1) does not yet exist.").arg(_deviceName);
}
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);
}
}
}
if ( retval < 0 )
{
this->setInError( errortext );
}
}
return retval;
}
void LedDevicePiBlaster::close()
{
LedDevice::close();
// LedDevice specific closing activites
// Close the device (if it is opened)
if (_fid != nullptr)
{
// The file pointer is already open
Error( _log, "Device (%s) is already open.", QSTRING_CSTR(_deviceName) );
return -1;
}
fclose(_fid);
_fid = nullptr;
}}
if (!QFile::exists(_deviceName))
{
Error( _log, "The device (%s) does not yet exist.",QSTRING_CSTR(_deviceName) );
return -1;
}
_fid = fopen(QSTRING_CSTR(_deviceName), "w");
if (_fid == nullptr)
{
Error( _log, "Failed to open device (%s). Error message: %s", QSTRING_CSTR(_deviceName), strerror(errno) );
return -1;
}
Info( _log, "Connected to device(%s)", QSTRING_CSTR(_deviceName));
return 0;
}
int LedDevicePiBlaster::write(const std::vector<ColorRgb> & ledValues)
{
@@ -112,11 +143,10 @@ int LedDevicePiBlaster::write(const std::vector<ColorRgb> & ledValues)
return -1;
}
int valueIdx = -1;
for (unsigned int i=0; i < TABLE_SZ; i++ )
{
valueIdx = _gpio_to_led[ i ];
if ( (valueIdx >= 0) && (valueIdx < _ledCount) )
int valueIdx = _gpio_to_led[ i ];
if ( (valueIdx >= 0) && (valueIdx < static_cast<int>( _ledCount)) )
{
double pwmDutyCycle = 0.0;
switch (_gpio_to_color[ i ])

View File

@@ -15,27 +15,35 @@ public:
///
/// @param deviceConfig json device config
///
LedDevicePiBlaster(const QJsonObject &deviceConfig);
explicit LedDevicePiBlaster(const QJsonObject &deviceConfig);
virtual ~LedDevicePiBlaster();
virtual ~LedDevicePiBlaster() override;
///
/// Sets configuration
///
/// @param deviceConfig the json device config
/// @return true if success
bool init(const QJsonObject &deviceConfig);
bool init(const QJsonObject &deviceConfig) override;
/// constructs leddevice
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:
///
/// 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
///
int open();
int open() override;
private:
///
@@ -45,7 +53,7 @@ private:
///
/// @return Zero on success else negative
///
int write(const std::vector<ColorRgb> &ledValues);
int write(const std::vector<ColorRgb> &ledValues) override;
/// The name of the output device (very likely '/dev/pi-blaster')
QString _deviceName;

View File

@@ -1,64 +1,87 @@
#include <exception>
#include "LedDeviceWS281x.h"
LedDeviceWS281x::LedDeviceWS281x(const QJsonObject &deviceConfig)
: LedDevice()
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDeviceWS281x::~LedDeviceWS281x()
{
if (_deviceReady)
{
ws2811_fini(&_led_string);
}
}
bool LedDeviceWS281x::init(const QJsonObject &deviceConfig)
{
LedDevice::init(deviceConfig);
QString errortext;
QString whiteAlgorithm = deviceConfig["whiteAlgorithm"].toString("white_off");
_whiteAlgorithm = RGBW::stringToWhiteAlgorithm(whiteAlgorithm);
Debug( _log, "whiteAlgorithm : %s", QSTRING_CSTR(whiteAlgorithm));
Debug( _log, "rgbw : %d", deviceConfig["rgbw"].toBool(false) );
if (_whiteAlgorithm == RGBW::INVALID)
bool isInitOK = LedDevice::init(deviceConfig);
if ( isInitOK )
{
Error(_log, "unknown whiteAlgorithm %s", QSTRING_CSTR(whiteAlgorithm));
return false;
QString whiteAlgorithm = deviceConfig["whiteAlgorithm"].toString("white_off");
_whiteAlgorithm = RGBW::stringToWhiteAlgorithm(whiteAlgorithm);
if (_whiteAlgorithm == RGBW::INVALID)
{
errortext = QString ("unknown whiteAlgorithm: %1").arg(whiteAlgorithm);
isInitOK = false;
}
else
{
_channel = deviceConfig["pwmchannel"].toInt(0);
if (_channel != 0 && _channel != 1)
{
errortext = "WS281x: invalid PWM channel; must be 0 or 1.";
isInitOK = false;
}
else
{
memset(&_led_string, 0, sizeof(_led_string));
_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);
_led_string.channel[_channel].invert = deviceConfig["invert"].toInt(0);
_led_string.channel[_channel].strip_type = (deviceConfig["rgbw"].toBool(false) ? SK6812_STRIP_GRBW : WS2811_STRIP_RGB);
_led_string.channel[_channel].brightness = 255;
_led_string.channel[!_channel].gpionum = 0;
_led_string.channel[!_channel].invert = _led_string.channel[_channel].invert;
_led_string.channel[!_channel].count = 0;
_led_string.channel[!_channel].brightness = 0;
_led_string.channel[!_channel].strip_type = WS2811_STRIP_RGB;
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;
}
}
}
}
_channel = deviceConfig["pwmchannel"].toInt(0);
if (_channel != 0 && _channel != 1)
if ( !isInitOK)
{
throw std::runtime_error("WS281x: invalid PWM channel; must be 0 or 1.");
this->setInError(errortext);
}
return isInitOK;
}
memset(&_led_string, 0, sizeof(_led_string));
_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);
_led_string.channel[_channel].invert = deviceConfig["invert"].toInt(0);
_led_string.channel[_channel].strip_type = (deviceConfig["rgbw"].toBool(false) ? SK6812_STRIP_GRBW : WS2811_STRIP_RGB);
_led_string.channel[_channel].brightness = 255;
void LedDeviceWS281x::close()
{
LedDevice::close();
_led_string.channel[!_channel].gpionum = 0;
_led_string.channel[!_channel].invert = _led_string.channel[_channel].invert;
_led_string.channel[!_channel].count = 0;
_led_string.channel[!_channel].brightness = 0;
_led_string.channel[!_channel].strip_type = WS2811_STRIP_RGB;
Debug( _log, "ws281x strip type : %d", _led_string.channel[_channel].strip_type );
if (ws2811_init(&_led_string) < 0)
if (_deviceReady)
{
throw std::runtime_error("Unable to initialize ws281x library.");
ws2811_fini(&_led_string);
}
return true;
}
LedDevice* LedDeviceWS281x::construct(const QJsonObject &deviceConfig)

View File

@@ -1,5 +1,6 @@
#pragma once
// LedDevice includes
#include <leddevice/LedDevice.h>
#include <ws2811.h>
@@ -19,17 +20,24 @@ public:
///
/// Destructor of the LedDevice, waits for DMA to complete and then cleans up
///
~LedDeviceWS281x();
~LedDeviceWS281x() override;
/// 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);
bool init(const QJsonObject &deviceConfig) override;
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
public slots:
///
/// Closes the output device.
/// Includes switching-off the device and stopping refreshes
///
virtual void close() override;
private:
///
@@ -38,7 +46,7 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
ws2811_t _led_string;
int _channel;

View File

@@ -5,7 +5,9 @@ LedDeviceAdalight::LedDeviceAdalight(const QJsonObject &deviceConfig)
, _headerSize(6)
, _ligthBerryAPA102Mode(false)
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
connect(this,SIGNAL(receivedData(QByteArray)),this,SLOT(receivedData(QByteArray)));
}
@@ -16,7 +18,8 @@ LedDevice* LedDeviceAdalight::construct(const QJsonObject &deviceConfig)
bool LedDeviceAdalight::init(const QJsonObject &deviceConfig)
{
ProviderRs232::init(deviceConfig);
bool isInitOK = ProviderRs232::init(deviceConfig);
_ligthBerryAPA102Mode = deviceConfig["lightberry_apa102_mode"].toBool(false);
// create ledBuffer
@@ -30,7 +33,7 @@ bool LedDeviceAdalight::init(const QJsonObject &deviceConfig)
_ledBuffer.resize(_headerSize + (_ledCount * bytesPerRGBLed) + startFrameSize + endFrameSize, 0x00);
// init constant data values
for (signed iLed=1; iLed<=_ledCount; iLed++)
for (signed iLed=1; iLed<= static_cast<int>( _ledCount); iLed++)
{
_ledBuffer[iLed*4+_headerSize] = 0xFF;
}
@@ -52,14 +55,14 @@ bool LedDeviceAdalight::init(const QJsonObject &deviceConfig)
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 true;
return isInitOK;
}
int LedDeviceAdalight::write(const std::vector<ColorRgb> & ledValues)
{
if(_ligthBerryAPA102Mode)
{
for (signed iLed=1; iLed<=_ledCount; iLed++)
for (signed iLed=1; iLed<=static_cast<int>( _ledCount); iLed++)
{
const ColorRgb& rgb = ledValues[iLed-1];
_ledBuffer[iLed*4+7] = rgb.red;

View File

@@ -1,5 +1,6 @@
#pragma once
// hyperion includes
#include "ProviderRs232.h"
///
@@ -15,12 +16,12 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceAdalight(const QJsonObject &deviceConfig);
explicit LedDeviceAdalight(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig) override;
public slots:
void receivedData(QByteArray data);
@@ -32,7 +33,7 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> & ledValues);
virtual int write(const std::vector<ColorRgb> & ledValues) override;
const short _headerSize;
bool _ligthBerryAPA102Mode;

View File

@@ -4,7 +4,8 @@
LedDeviceAtmo::LedDeviceAtmo(const QJsonObject &deviceConfig)
: ProviderRs232()
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceAtmo::construct(const QJsonObject &deviceConfig)
@@ -14,21 +15,27 @@ LedDevice* LedDeviceAtmo::construct(const QJsonObject &deviceConfig)
bool LedDeviceAtmo::init(const QJsonObject &deviceConfig)
{
ProviderRs232::init(deviceConfig);
bool isInitOK = ProviderRs232::init(deviceConfig);
if (_ledCount != 5)
if ( isInitOK )
{
Error( _log, "%d channels configured. This should always be 5!", _ledCount);
return 0;
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;
}
else
{
_ledBuffer.resize(4 + 5*3); // 4-byte header, 5 RGB values
_ledBuffer[0] = 0xFF; // Startbyte
_ledBuffer[1] = 0x00; // StartChannel(Low)
_ledBuffer[2] = 0x00; // StartChannel(High)
_ledBuffer[3] = 0x0F; // Number of Databytes send (always! 15)
}
}
_ledBuffer.resize(4 + 5*3); // 4-byte header, 5 RGB values
_ledBuffer[0] = 0xFF; // Startbyte
_ledBuffer[1] = 0x00; // StartChannel(Low)
_ledBuffer[2] = 0x00; // StartChannel(High)
_ledBuffer[3] = 0x0F; // Number of Databytes send (always! 15)
return true;
return isInitOK;
}
int LedDeviceAtmo::write(const std::vector<ColorRgb> &ledValues)

View File

@@ -1,6 +1,6 @@
#pragma once
// hyperion incluse
// hyperion includes
#include "ProviderRs232.h"
///
@@ -14,12 +14,12 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceAtmo(const QJsonObject &deviceConfig);
explicit LedDeviceAtmo(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -28,5 +28,5 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
};

View File

@@ -10,44 +10,8 @@ LedDeviceDMX::LedDeviceDMX(const QJsonObject &deviceConfig)
, _dmxLedCount(0)
, _dmxChannelCount(0)
{
_deviceReady = init(deviceConfig);
}
bool LedDeviceDMX::init(const QJsonObject &deviceConfig)
{
ProviderRs232::init(deviceConfig);
QString dmxString = deviceConfig["dmxdevice"].toString("invalid");
if (dmxString == "raw")
{
_dmxDeviceType = 0;
_dmxStart = 1;
_dmxSlotsPerLed = 3;
}
else if (dmxString == "McCrypt")
{
_dmxDeviceType = 1;
_dmxStart = 1;
_dmxSlotsPerLed = 4;
}
else
{
Error(_log, "unknown dmx device type %s", QSTRING_CSTR(dmxString));
}
Debug(_log, "_dmxString \"%s\", _dmxDeviceType %d", QSTRING_CSTR(dmxString), _dmxDeviceType );
_rs232Port.setStopBits(QSerialPort::TwoStop);
_dmxLedCount = qMin(_ledCount, 512/_dmxSlotsPerLed);
_dmxChannelCount = 1 + _dmxSlotsPerLed * _dmxLedCount;
Debug(_log, "_dmxStart %d, _dmxSlotsPerLed %d", _dmxStart, _dmxSlotsPerLed);
Debug(_log, "_ledCount %d, _dmxLedCount %d, _dmxChannelCount %d", _ledCount, _dmxLedCount, _dmxChannelCount);
_ledBuffer.resize(_dmxChannelCount, 0);
_ledBuffer[0] = 0x00; // NULL START code
return true;
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceDMX::construct(const QJsonObject &deviceConfig)
@@ -55,6 +19,48 @@ LedDevice* LedDeviceDMX::construct(const QJsonObject &deviceConfig)
return new LedDeviceDMX(deviceConfig);
}
bool LedDeviceDMX::init(const QJsonObject &deviceConfig)
{
bool isInitOK = ProviderRs232::init(deviceConfig);
if ( isInitOK )
{
QString dmxString = deviceConfig["dmxdevice"].toString("invalid");
if (dmxString == "raw")
{
_dmxDeviceType = 0;
_dmxStart = 1;
_dmxSlotsPerLed = 3;
}
else if (dmxString == "McCrypt")
{
_dmxDeviceType = 1;
_dmxStart = 1;
_dmxSlotsPerLed = 4;
}
else
{
//Error(_log, "unknown dmx device type %s", QSTRING_CSTR(dmxString));
QString errortext = QString ("unknown dmx device type: %1").arg(dmxString);
this->setInError(errortext);
return false;
}
Debug(_log, "_dmxString \"%s\", _dmxDeviceType %d", QSTRING_CSTR(dmxString), _dmxDeviceType );
_rs232Port.setStopBits(QSerialPort::TwoStop);
_dmxLedCount = qMin(static_cast<int>(_ledCount), 512/_dmxSlotsPerLed);
_dmxChannelCount = 1 + _dmxSlotsPerLed * _dmxLedCount;
Debug(_log, "_dmxStart %d, _dmxSlotsPerLed %d", _dmxStart, _dmxSlotsPerLed);
Debug(_log, "_ledCount %d, _dmxLedCount %d, _dmxChannelCount %d", _ledCount, _dmxLedCount, _dmxChannelCount);
_ledBuffer.resize(_dmxChannelCount, 0);
_ledBuffer[0] = 0x00; // NULL START code
}
return isInitOK;
}
int LedDeviceDMX::write(const std::vector<ColorRgb> &ledValues)
{
switch (_dmxDeviceType) {

View File

@@ -1,6 +1,6 @@
#pragma once
// hyperion incluse
// hyperion includes
#include "ProviderRs232.h"
///
@@ -14,12 +14,12 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceDMX(const QJsonObject &deviceConfig);
explicit LedDeviceDMX(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -28,7 +28,7 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
int _dmxDeviceType = 0;
int _dmxStart = 1;
int _dmxSlotsPerLed = 3;

View File

@@ -4,7 +4,9 @@
LedDeviceKarate::LedDeviceKarate(const QJsonObject &deviceConfig)
: ProviderRs232()
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
connect(this,SIGNAL(receivedData(QByteArray)),this,SLOT(receivedData(QByteArray)));
}
@@ -15,23 +17,31 @@ LedDevice* LedDeviceKarate::construct(const QJsonObject &deviceConfig)
bool LedDeviceKarate::init(const QJsonObject &deviceConfig)
{
ProviderRs232::init(deviceConfig);
bool isInitOK = ProviderRs232::init(deviceConfig);
if (_ledCount != 16)
if ( isInitOK )
{
Error( _log, "%d channels configured. This should always be 16!", _ledCount);
return 0;
if (_ledCount != 16)
{
//Error( _log, "%d channels configured. This should always be 16!", _ledCount);
QString errortext = QString ("%1 channels configured. This should always be 16!").arg(_ledCount);
this->setInError(errortext);
isInitOK = false;
}
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
Debug( _log, "Karatelight header for %d leds: 0x%02x 0x%02x 0x%02x 0x%02x", _ledCount,
_ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3] );
}
}
_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
Debug( _log, "Karatelight header for %d leds: 0x%02x 0x%02x 0x%02x 0x%02x", _ledCount,
_ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3] );
return true;
return isInitOK;
}
int LedDeviceKarate::write(const std::vector<ColorRgb> &ledValues)

View File

@@ -1,6 +1,6 @@
#pragma once
// hyperion incluse
// hyperion includes
#include "ProviderRs232.h"
///
@@ -15,12 +15,12 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceKarate(const QJsonObject &deviceConfig);
explicit LedDeviceKarate(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig) override;
public slots:
void receivedData(QByteArray data);
@@ -32,5 +32,5 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
};

View File

@@ -9,7 +9,8 @@ struct FrameSpec
LedDeviceSedu::LedDeviceSedu(const QJsonObject &deviceConfig)
: ProviderRs232()
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceSedu::construct(const QJsonObject &deviceConfig)
@@ -19,7 +20,7 @@ LedDevice* LedDeviceSedu::construct(const QJsonObject &deviceConfig)
bool LedDeviceSedu::init(const QJsonObject &deviceConfig)
{
ProviderRs232::init(deviceConfig);
bool isInitOK = ProviderRs232::init(deviceConfig);
std::vector<FrameSpec> frameSpecs{{0xA1, 256}, {0xA2, 512}, {0xB0, 768}, {0xB1, 1536}, {0xB2, 3072} };
@@ -38,11 +39,13 @@ bool LedDeviceSedu::init(const QJsonObject &deviceConfig)
if (_ledBuffer.size() == 0)
{
Warning(_log, "More rgb-channels required then available");
return false;
//Warning(_log, "More rgb-channels required then available");
QString errortext = "More rgb-channels required then available";
this->setInError(errortext);
isInitOK = false;
}
return true;
return isInitOK;
}
int LedDeviceSedu::write(const std::vector<ColorRgb> &ledValues)

View File

@@ -1,6 +1,6 @@
#pragma once
// hyperion incluse
// hyperion includes
#include "ProviderRs232.h"
///
@@ -14,12 +14,12 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceSedu(const QJsonObject &deviceConfig);
explicit LedDeviceSedu(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -28,5 +28,5 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
};

View File

@@ -4,7 +4,8 @@
LedDeviceTpm2::LedDeviceTpm2(const QJsonObject &deviceConfig)
: ProviderRs232()
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceTpm2::construct(const QJsonObject &deviceConfig)
@@ -14,7 +15,7 @@ LedDevice* LedDeviceTpm2::construct(const QJsonObject &deviceConfig)
bool LedDeviceTpm2::init(const QJsonObject &deviceConfig)
{
ProviderRs232::init(deviceConfig);
bool isInitOK = ProviderRs232::init(deviceConfig);
_ledBuffer.resize(5 + _ledRGBCount);
_ledBuffer[0] = 0xC9; // block-start byte
@@ -23,7 +24,7 @@ bool LedDeviceTpm2::init(const QJsonObject &deviceConfig)
_ledBuffer[3] = _ledRGBCount & 0xFF; // frame size low byte
_ledBuffer.back() = 0x36; // block-end byte
return true;
return isInitOK;
}
int LedDeviceTpm2::write(const std::vector<ColorRgb> &ledValues)

View File

@@ -1,6 +1,6 @@
#pragma once
// hyperion incluse
// hyperion includes
#include "ProviderRs232.h"
///
@@ -14,12 +14,12 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceTpm2(const QJsonObject &deviceConfig);
explicit LedDeviceTpm2(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -28,5 +28,5 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
};

View File

@@ -27,6 +27,7 @@ ProviderRs232::ProviderRs232()
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()));
@@ -36,7 +37,7 @@ bool ProviderRs232::init(const QJsonObject &deviceConfig)
{
closeDevice();
LedDevice::init(deviceConfig);
bool isInitOK = LedDevice::init(deviceConfig);
_deviceName = deviceConfig["output"].toString("auto");
_enableAutoDeviceName = _deviceName == "auto";
@@ -44,7 +45,16 @@ bool ProviderRs232::init(const QJsonObject &deviceConfig)
_delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(1500);
_preOpenDelay = deviceConfig["delayBeforeConnect"].toInt(1500);
return true;
return isInitOK;
}
void ProviderRs232::close()
{
LedDevice::close();
// LedDevice specific closing activites
closeDevice();
}
QString ProviderRs232::findSerialDevice()
@@ -56,7 +66,6 @@ QString ProviderRs232::findSerialDevice()
{
Info(_log, "found serial device: %s", port.systemLocation().toLocal8Bit().constData());
return port.systemLocation();
break;
}
}
return "";
@@ -122,6 +131,7 @@ void ProviderRs232::error(QSerialPort::SerialPortError error)
_deviceReady = false;
}
_rs232Port.clearError();
this->setInError( "Rs232 SerialPortError, see details in previous log lines!" );
closeDevice();
}
}
@@ -130,7 +140,6 @@ void ProviderRs232::error(QSerialPort::SerialPortError error)
ProviderRs232::~ProviderRs232()
{
disconnect(&_rs232Port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(error(QSerialPort::SerialPortError)));
closeDevice();
}
void ProviderRs232::closeDevice()
@@ -151,9 +160,27 @@ void ProviderRs232::closeDevice()
int ProviderRs232::open()
{
return tryOpen(_delayAfterConnect_ms) ? 0 : -1;
}
int retval = -1;
_deviceReady = false;
// General initialisation and configuration of LedDevice
if ( init(_devConfig) )
{
if ( tryOpen(_delayAfterConnect_ms) )
{
// Everything is OK -> enable device
_deviceReady = true;
setEnable(true);
retval = 0;
}
else
{
this->setInError( "Error opening device!" );
}
}
return retval;
}
bool ProviderRs232::tryOpen(const int delayAfterConnect_ms)
{
@@ -247,16 +274,13 @@ int ProviderRs232::writeBytes(const qint64 size, const uint8_t * data)
void ProviderRs232::writeTimeout()
{
Error(_log, "Timeout on write data to %s", _deviceName.toLocal8Bit().constData());
closeDevice();
//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();
}
void ProviderRs232::unblockAfterDelay()
{
_blockedForDelay = false;
}
int ProviderRs232::rewriteLeds()
{
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
}

View File

@@ -5,7 +5,7 @@
#include <QTimer>
#include <QString>
// Leddevice includes
// LedDevice includes
#include <leddevice/LedDevice.h>
///
@@ -26,28 +26,33 @@ public:
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig) override;
///
/// Destructor of the LedDevice; closes the output device if it is open
///
virtual ~ProviderRs232();
virtual ~ProviderRs232() override;
///
/// Opens and configures the output device
///
/// @return Zero on succes else negative
///
int open();
int open() override;
public slots:
///
/// Closes the output device.
/// Includes switching-off the device and stopping refreshes
///
virtual void close() override;
private slots:
/// Write the last data to the leds again
int rewriteLeds();
/// Unblock the device after a connection delay
void writeTimeout();
void unblockAfterDelay();
void error(QSerialPort::SerialPortError error);
void error(QSerialPort::SerialPortError setInError);
void bytesWritten(qint64 bytes);
void readyRead();

View File

@@ -3,7 +3,8 @@
LedDeviceAPA102::LedDeviceAPA102(const QJsonObject &deviceConfig)
: ProviderSpi()
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceAPA102::construct(const QJsonObject &deviceConfig)
@@ -13,24 +14,26 @@ LedDevice* LedDeviceAPA102::construct(const QJsonObject &deviceConfig)
bool LedDeviceAPA102::init(const QJsonObject &deviceConfig)
{
ProviderSpi::init(deviceConfig);
bool isInitOK = 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;
if ( isInitOK )
{
const unsigned int startFrameSize = 4;
const unsigned int endFrameSize = qMax<unsigned int>(((_ledCount + 15) / 16), 4);
const unsigned int APAbufferSize = (_ledCount * 4) + startFrameSize + endFrameSize;
_ledBuffer.resize(APAbufferSize, 0xFF);
_ledBuffer[0] = 0x00;
_ledBuffer[1] = 0x00;
_ledBuffer[2] = 0x00;
_ledBuffer[3] = 0x00;
return true;
_ledBuffer.resize(APAbufferSize, 0xFF);
_ledBuffer[0] = 0x00;
_ledBuffer[1] = 0x00;
_ledBuffer[2] = 0x00;
_ledBuffer[3] = 0x00;
}
return isInitOK;
}
int LedDeviceAPA102::write(const std::vector<ColorRgb> &ledValues)
{
for (signed iLed=0; iLed < _ledCount; ++iLed) {
for (signed iLed=0; iLed < static_cast<int>( _ledCount); ++iLed) {
const ColorRgb& rgb = ledValues[iLed];
_ledBuffer[4+iLed*4] = 0xFF;
_ledBuffer[4+iLed*4+1] = rgb.red;

View File

@@ -1,9 +1,8 @@
#pragma once
// hyperion incluse
// hyperion includes
#include "ProviderSpi.h"
///
/// Implementation of the LedDevice interface for writing to APA102 led device.
///
@@ -13,12 +12,17 @@ public:
///
/// Constructs specific LedDevice
///
LedDeviceAPA102(const QJsonObject &deviceConfig);
explicit LedDeviceAPA102(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
virtual bool init(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
@@ -26,5 +30,5 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
};

View File

@@ -45,7 +45,8 @@ LedDeviceAPA104::LedDeviceAPA104(const QJsonObject &deviceConfig)
0b11101110,
}
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceAPA104::construct(const QJsonObject &deviceConfig)
@@ -56,15 +57,15 @@ LedDevice* LedDeviceAPA104::construct(const QJsonObject &deviceConfig)
bool LedDeviceAPA104::init(const QJsonObject &deviceConfig)
{
_baudRate_Hz = 2235000;
if ( !ProviderSpi::init(deviceConfig) )
bool isInitOK = ProviderSpi::init(deviceConfig);
if ( isInitOK )
{
return false;
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);
}
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);
return true;
return isInitOK;
}
int LedDeviceAPA104::write(const std::vector<ColorRgb> &ledValues)

View File

@@ -1,6 +1,6 @@
#pragma once
// hyperion incluse
// hyperion inclusdes
#include "ProviderSpi.h"
///
@@ -14,7 +14,7 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceAPA104(const QJsonObject &deviceConfig);
explicit LedDeviceAPA104(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
@@ -24,7 +24,7 @@ public:
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -33,10 +33,9 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
const int SPI_BYTES_PER_COLOUR;
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];

View File

@@ -3,7 +3,8 @@
LedDeviceLpd6803::LedDeviceLpd6803(const QJsonObject &deviceConfig)
: ProviderSpi()
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceLpd6803::construct(const QJsonObject &deviceConfig)
@@ -13,13 +14,14 @@ LedDevice* LedDeviceLpd6803::construct(const QJsonObject &deviceConfig)
bool LedDeviceLpd6803::init(const QJsonObject &deviceConfig)
{
ProviderSpi::init(deviceConfig);
unsigned messageLength = 4 + 2*_ledCount + _ledCount/8 + 1;
// Initialise the buffer
_ledBuffer.resize(messageLength, 0x00);
return true;
bool isInitOK = ProviderSpi::init(deviceConfig);
if ( isInitOK )
{
unsigned messageLength = 4 + 2*_ledCount + _ledCount/8 + 1;
// Initialise the buffer
_ledBuffer.resize(messageLength, 0x00);
}
return isInitOK;
}
int LedDeviceLpd6803::write(const std::vector<ColorRgb> &ledValues)

View File

@@ -1,6 +1,6 @@
#pragma once
// Local hyperion incluse
// Local hyperion includes
#include "ProviderSpi.h"
///
@@ -22,12 +22,17 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceLpd6803(const QJsonObject &deviceConfig);
explicit LedDeviceLpd6803(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig);
///
/// Sets configuration
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -36,5 +41,5 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
};

View File

@@ -3,7 +3,8 @@
LedDeviceLpd8806::LedDeviceLpd8806(const QJsonObject &deviceConfig)
: ProviderSpi()
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceLpd8806::construct(const QJsonObject &deviceConfig)
@@ -13,15 +14,46 @@ LedDevice* LedDeviceLpd8806::construct(const QJsonObject &deviceConfig)
bool LedDeviceLpd8806::init(const QJsonObject &deviceConfig)
{
ProviderSpi::init(deviceConfig);
bool isInitOK = ProviderSpi::init(deviceConfig);
const unsigned clearSize = _ledCount/32+1;
unsigned messageLength = _ledRGBCount + clearSize;
// Initialise the buffer
_ledBuffer.resize(messageLength, 0x00);
// Perform an initial reset to start accepting data on the first led
return writeBytes(clearSize, _ledBuffer.data());
return isInitOK;
}
int LedDeviceLpd8806::open()
{
int retval = -1;
QString errortext;
_deviceReady = false;
// General initialisation and configuration of LedDevice
if ( init(_devConfig) )
{
// Perform an initial reset to start accepting data on the first led
const unsigned clearSize = _ledCount/32+1;
if ( writeBytes(clearSize, _ledBuffer.data()) < 0 )
{
errortext = QString ("Failed to do initial write");
}
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 );
}
}
return retval;
}
int LedDeviceLpd8806::write(const std::vector<ColorRgb> &ledValues)

View File

@@ -1,6 +1,6 @@
#pragma once
// Local hyperion incluse
// Local hyperion includes
#include "ProviderSpi.h"
///
@@ -83,12 +83,25 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceLpd8806(const QJsonObject &deviceConfig);
explicit LedDeviceLpd8806(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig);
///
/// Sets configuration
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig) override;
protected:
///
/// Opens and initiatialises the output device
///
/// @return Zero on succes (i.e. device is ready and enabled) else negative
///
virtual int open() override;
private:
///
@@ -97,5 +110,5 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
};

View File

@@ -3,7 +3,8 @@
LedDeviceP9813::LedDeviceP9813(const QJsonObject &deviceConfig)
: ProviderSpi()
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceP9813::construct(const QJsonObject &deviceConfig)
@@ -13,11 +14,12 @@ LedDevice* LedDeviceP9813::construct(const QJsonObject &deviceConfig)
bool LedDeviceP9813::init(const QJsonObject &deviceConfig)
{
ProviderSpi::init(deviceConfig);
_ledBuffer.resize(_ledCount * 4 + 8, 0x00);
return true;
bool isInitOK = ProviderSpi::init(deviceConfig);
if ( isInitOK )
{
_ledBuffer.resize(_ledCount * 4 + 8, 0x00);
}
return isInitOK;
}
int LedDeviceP9813::write(const std::vector<ColorRgb> &ledValues)

View File

@@ -1,6 +1,6 @@
#pragma once
// hyperion include
// hyperion includes
#include "ProviderSpi.h"
///
@@ -14,12 +14,17 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceP9813(const QJsonObject &deviceConfig);
explicit LedDeviceP9813(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig);
///
/// Sets configuration
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -28,7 +33,7 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
///
/// Calculates the required checksum for one led

View File

@@ -1,17 +1,18 @@
#include "LedDeviceSk6812SPI.h"
LedDeviceSk6812SPI::LedDeviceSk6812SPI(const QJsonObject &deviceConfig)
LedDeviceSk6812SPI::LedDeviceSk6812SPI(const QJsonObject &deviceConfig)
: ProviderSpi()
, _whiteAlgorithm(RGBW::INVALID)
, SPI_BYTES_PER_COLOUR(4)
, bitpair_to_byte {
0b10001000,
0b10001100,
0b11001000,
0b11001100,
}
, _whiteAlgorithm(RGBW::INVALID)
, SPI_BYTES_PER_COLOUR(4)
, bitpair_to_byte {
0b10001000,
0b10001100,
0b11001000,
0b11001100,
}
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceSk6812SPI::construct(const QJsonObject &deviceConfig)
@@ -21,27 +22,31 @@ LedDevice* LedDeviceSk6812SPI::construct(const QJsonObject &deviceConfig)
bool LedDeviceSk6812SPI::init(const QJsonObject &deviceConfig)
{
QString whiteAlgorithm = deviceConfig["whiteAlgorithm"].toString("white_off");
_whiteAlgorithm = RGBW::stringToWhiteAlgorithm(whiteAlgorithm);
if (_whiteAlgorithm == RGBW::INVALID)
{
Error(_log, "unknown whiteAlgorithm %s", QSTRING_CSTR(whiteAlgorithm));
return false;
}
Debug( _log, "whiteAlgorithm : %s", QSTRING_CSTR(whiteAlgorithm));
_baudRate_Hz = 3000000;
if ( !ProviderSpi::init(deviceConfig) )
{
return false;
}
WarningIf(( _baudRate_Hz < 2050000 || _baudRate_Hz > 4000000 ), _log, "SPI rate %d outside recommended range (2050000 -> 4000000)", _baudRate_Hz);
const int SPI_FRAME_END_LATCH_BYTES = 3;
_ledBuffer.resize(_ledRGBWCount * SPI_BYTES_PER_COLOUR + SPI_FRAME_END_LATCH_BYTES, 0x00);
return true;
bool isInitOK = ProviderSpi::init(deviceConfig);
if ( isInitOK )
{
QString whiteAlgorithm = deviceConfig["whiteAlgorithm"].toString("white_off");
_whiteAlgorithm = RGBW::stringToWhiteAlgorithm(whiteAlgorithm);
if (_whiteAlgorithm == RGBW::INVALID)
{
QString errortext = QString ("unknown whiteAlgorithm: %1").arg(whiteAlgorithm);
this->setInError(errortext);
isInitOK = false;
}
else
{
Debug( _log, "whiteAlgorithm : %s", QSTRING_CSTR(whiteAlgorithm));
WarningIf(( _baudRate_Hz < 2050000 || _baudRate_Hz > 4000000 ), _log, "SPI rate %d outside recommended range (2050000 -> 4000000)", _baudRate_Hz);
const int SPI_FRAME_END_LATCH_BYTES = 3;
_ledBuffer.resize(_ledRGBWCount * SPI_BYTES_PER_COLOUR + SPI_FRAME_END_LATCH_BYTES, 0x00);
}
}
return isInitOK;
}
int LedDeviceSk6812SPI::write(const std::vector<ColorRgb> &ledValues)

View File

@@ -1,6 +1,6 @@
#pragma once
// hyperion incluse
// hyperion includes
#include "ProviderSpi.h"
///
@@ -14,7 +14,7 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceSk6812SPI(const QJsonObject &deviceConfig);
explicit LedDeviceSk6812SPI(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
@@ -24,7 +24,7 @@ public:
///
/// @param deviceConfig the json device config
/// @return true if success
bool init(const QJsonObject &deviceConfig);
bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -33,13 +33,12 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
RGBW::WhiteAlgorithm _whiteAlgorithm;
const int SPI_BYTES_PER_COLOUR;
const int SPI_BYTES_PER_COLOUR;
uint8_t bitpair_to_byte[4];
ColorRgbw _temp_rgbw;
};

View File

@@ -36,20 +36,20 @@ Reset time is 50uS = 100 bits = 13 bytes
*/
LedDeviceSk6822SPI::LedDeviceSk6822SPI(const QJsonObject &deviceConfig)
: ProviderSpi()
, SPI_BYTES_PER_COLOUR(4)
, SPI_BYTES_WAIT_TIME(3)
, SPI_FRAME_END_LATCH_BYTES(13)
, bitpair_to_byte {
0b10001000,
0b10001110,
0b11101000,
0b11101110,
}
, SPI_BYTES_PER_COLOUR(4)
, SPI_BYTES_WAIT_TIME(3)
, SPI_FRAME_END_LATCH_BYTES(13)
, bitpair_to_byte {
0b10001000,
0b10001110,
0b11101000,
0b11101110,
}
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceSk6822SPI::construct(const QJsonObject &deviceConfig)
@@ -60,16 +60,17 @@ LedDevice* LedDeviceSk6822SPI::construct(const QJsonObject &deviceConfig)
bool LedDeviceSk6822SPI::init(const QJsonObject &deviceConfig)
{
_baudRate_Hz = 2230000;
if ( !ProviderSpi::init(deviceConfig) )
bool isInitOK = ProviderSpi::init(deviceConfig);
if ( isInitOK )
{
return false;
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);
}
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);
return true;
return isInitOK;
}
int LedDeviceSk6822SPI::write(const std::vector<ColorRgb> &ledValues)
@@ -80,8 +81,8 @@ int LedDeviceSk6822SPI::write(const std::vector<ColorRgb> &ledValues)
for (const ColorRgb& color : ledValues)
{
uint32_t colorBits = ((unsigned int)color.red << 16)
| ((unsigned int)color.green << 8)
| color.blue;
| ((unsigned int)color.green << 8)
| color.blue;
for (int j=SPI_BYTES_PER_LED - 1; j>=0; j--)
{
@@ -93,7 +94,7 @@ int LedDeviceSk6822SPI::write(const std::vector<ColorRgb> &ledValues)
}
/*
/*
// debug the whole SPI packet
char debug_line[2048];
int ptr=0;
@@ -104,14 +105,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());

View File

@@ -1,6 +1,6 @@
#pragma once
// hyperion incluse
// hyperion includes
#include "ProviderSpi.h"
///
@@ -14,7 +14,7 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceSk6822SPI(const QJsonObject &deviceConfig);
explicit LedDeviceSk6822SPI(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
@@ -24,7 +24,7 @@ public:
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -33,12 +33,11 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
const int SPI_BYTES_PER_COLOUR;
const int SPI_BYTES_WAIT_TIME;
const int SPI_FRAME_END_LATCH_BYTES;
uint8_t bitpair_to_byte[4];
};

View File

@@ -3,7 +3,8 @@
LedDeviceWs2801::LedDeviceWs2801(const QJsonObject &deviceConfig)
: ProviderSpi()
{
_deviceReady = ProviderSpi::init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceWs2801::construct(const QJsonObject &deviceConfig)
@@ -11,6 +12,12 @@ LedDevice* LedDeviceWs2801::construct(const QJsonObject &deviceConfig)
return new LedDeviceWs2801(deviceConfig);
}
bool LedDeviceWs2801::init(const QJsonObject &deviceConfig)
{
bool isInitOK = ProviderSpi::init(deviceConfig);
return isInitOK;
}
int LedDeviceWs2801::write(const std::vector<ColorRgb> &ledValues)
{
const unsigned dataLen = _ledCount * sizeof(ColorRgb);

View File

@@ -1,5 +1,6 @@
#pragma once
// hyperion includes
#include "ProviderSpi.h"
///
@@ -13,11 +14,18 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceWs2801(const QJsonObject &deviceConfig);
explicit LedDeviceWs2801(const QJsonObject &deviceConfig);
/// constructs leddevice
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;
protected:
///
/// Writes the led color values to the led-device
@@ -25,5 +33,5 @@ protected:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
};

View File

@@ -1,6 +1,6 @@
#include "LedDeviceWs2812SPI.h"
/*
/*
From the data sheet:
(TH+TL=1.25μs±600ns)
@@ -34,18 +34,19 @@ Reset time is 300uS = 923 bits = 116 bytes
*/
LedDeviceWs2812SPI::LedDeviceWs2812SPI(const QJsonObject &deviceConfig)
LedDeviceWs2812SPI::LedDeviceWs2812SPI(const QJsonObject &deviceConfig)
: ProviderSpi()
, SPI_BYTES_PER_COLOUR(4)
, SPI_FRAME_END_LATCH_BYTES(116)
, bitpair_to_byte {
0b10001000,
0b10001100,
0b11001000,
0b11001100,
}
, SPI_BYTES_PER_COLOUR(4)
, SPI_FRAME_END_LATCH_BYTES(116)
, bitpair_to_byte {
0b10001000,
0b10001100,
0b11001000,
0b11001100,
}
{
_deviceReady = init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDevice* LedDeviceWs2812SPI::construct(const QJsonObject &deviceConfig)
@@ -56,15 +57,15 @@ LedDevice* LedDeviceWs2812SPI::construct(const QJsonObject &deviceConfig)
bool LedDeviceWs2812SPI::init(const QJsonObject &deviceConfig)
{
_baudRate_Hz = 2600000;
if ( !ProviderSpi::init(deviceConfig) )
bool isInitOK = ProviderSpi::init(deviceConfig);
if ( isInitOK )
{
return false;
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);
}
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);
return true;
return isInitOK;
}
int LedDeviceWs2812SPI::write(const std::vector<ColorRgb> &ledValues)
@@ -75,8 +76,8 @@ int LedDeviceWs2812SPI::write(const std::vector<ColorRgb> &ledValues)
for (const ColorRgb& color : ledValues)
{
uint32_t colorBits = ((unsigned int)color.red << 16)
| ((unsigned int)color.green << 8)
| color.blue;
| ((unsigned int)color.green << 8)
| color.blue;
for (int j=SPI_BYTES_PER_LED - 1; j>=0; j--)
{

View File

@@ -1,6 +1,6 @@
#pragma once
// hyperion incluse
// hyperion includes
#include "ProviderSpi.h"
///
@@ -14,7 +14,7 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceWs2812SPI(const QJsonObject &deviceConfig);
explicit LedDeviceWs2812SPI(const QJsonObject &deviceConfig);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
@@ -24,7 +24,7 @@ public:
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig) override;
private:
///
@@ -33,10 +33,9 @@ private:
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
const int SPI_BYTES_PER_COLOUR;
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];

View File

@@ -1,4 +1,4 @@

// STL includes
#include <cstring>
#include <cstdio>
@@ -7,6 +7,7 @@
// Linux includes
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
// Local Hyperion includes
@@ -28,52 +29,95 @@ ProviderSpi::ProviderSpi()
ProviderSpi::~ProviderSpi()
{
// close(_fid);
}
bool ProviderSpi::init(const QJsonObject &deviceConfig)
{
LedDevice::init(deviceConfig);
bool isInitOK = 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);
return true;
return isInitOK;
}
int ProviderSpi::open()
{
Debug(_log, "_baudRate_Hz %d, _latchTime_ns %d", _baudRate_Hz, _latchTime_ms);
Debug(_log, "_spiDataInvert %d, _spiMode %d", _spiDataInvert, _spiMode);
int retval = -1;
QString errortext;
_deviceReady = false;
const int bitsPerWord = 8;
_fid = ::open(QSTRING_CSTR(_deviceName), O_RDWR);
if (_fid < 0)
if ( init(_devConfig) )
{
Error( _log, "Failed to open device (%s). Error message: %s", QSTRING_CSTR(_deviceName), strerror(errno) );
return -1;
Debug(_log, "_baudRate_Hz %d, _latchTime_ns %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)
{
retval = -2;
}
else
{
if (ioctl(_fid, SPI_IOC_WR_BITS_PER_WORD, &bitsPerWord) == -1 || ioctl(_fid, SPI_IOC_RD_BITS_PER_WORD, &bitsPerWord) == -1)
{
retval = -4;
}
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;
}
}
}
if ( retval < 0 )
{
errortext = QString ("Failed to open device (%1). Error Code: %2").arg(_deviceName, retval);
}
}
if ( retval < 0 )
{
this->setInError( errortext );
}
}
if (ioctl(_fid, SPI_IOC_WR_MODE, &_spiMode) == -1 || ioctl(_fid, SPI_IOC_RD_MODE, &_spiMode) == -1)
{
return -2;
}
return retval;
}
if (ioctl(_fid, SPI_IOC_WR_BITS_PER_WORD, &bitsPerWord) == -1 || ioctl(_fid, SPI_IOC_RD_BITS_PER_WORD, &bitsPerWord) == -1)
{
return -4;
}
void ProviderSpi::close()
{
LedDevice::close();
if (ioctl(_fid, SPI_IOC_WR_MAX_SPEED_HZ, &_baudRate_Hz) == -1 || ioctl(_fid, SPI_IOC_RD_MAX_SPEED_HZ, &_baudRate_Hz) == -1)
// Device specific closing activites
if ( _fid > -1 )
{
return -6;
if ( ::close(_fid) != 0 )
{
Error( _log, "Failed to close device (%s). Error message: %s", QSTRING_CSTR(_deviceName), strerror(errno) );
}
}
return 0;
}
int ProviderSpi::writeBytes(const unsigned size, const uint8_t * data)

View File

@@ -22,19 +22,26 @@ public:
///
/// @param deviceConfig the json device config
/// @return true if success
virtual bool init(const QJsonObject &deviceConfig);
virtual bool init(const QJsonObject &deviceConfig) override;
///
/// Destructor of the LedDevice; closes the output device if it is open
///
virtual ~ProviderSpi();
virtual ~ProviderSpi() override;
///
/// Opens and configures the output device
///
/// @return Zero on succes else negative
///
int open();
int open() override;
public slots:
///
/// Closes the output device.
/// Includes switching-off the device and stopping refreshes
///
virtual void close() override;
protected:
///

View File

@@ -15,92 +15,110 @@ LedDeviceTinkerforge::LedDeviceTinkerforge(const QJsonObject &deviceConfig)
, _ledStrip(nullptr)
, _colorChannelSize(0)
{
init(deviceConfig);
_devConfig = deviceConfig;
_deviceReady = false;
}
LedDeviceTinkerforge::~LedDeviceTinkerforge()
{
// Close the device (if it is opened)
if (_ipConnection != nullptr && _ledStrip != nullptr)
{
switchOff();
}
// Clean up claimed resources
delete _ipConnection;
delete _ledStrip;
}
bool LedDeviceTinkerforge::init(const QJsonObject &deviceConfig)
{
LedDevice::init(deviceConfig);
_host = deviceConfig["output"].toString("127.0.0.1");
_port = deviceConfig["port"].toInt(4223);
_uid = deviceConfig["uid"].toString();
_interval = deviceConfig["rate"].toInt();
if ((unsigned)_ledCount > MAX_NUM_LEDS)
{
Error(_log,"Invalid attempt to write led values. Not more than %d leds are allowed.", MAX_NUM_LEDS);
return -1;
}
if (_colorChannelSize < (unsigned)_ledCount)
{
_redChannel.resize(_ledCount, uint8_t(0));
_greenChannel.resize(_ledCount, uint8_t(0));
_blueChannel.resize(_ledCount, uint8_t(0));
}
_colorChannelSize = _ledCount;
return true;
}
LedDevice* LedDeviceTinkerforge::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceTinkerforge(deviceConfig);
}
bool LedDeviceTinkerforge::init(const QJsonObject &deviceConfig)
{
bool isInitOK = LedDevice::init(deviceConfig);
if (isInitOK)
{
_host = deviceConfig["output"].toString("127.0.0.1");
_port = deviceConfig["port"].toInt(4223);
_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);
this->setInError(errortext);
isInitOK = false;
}
else
{
if (_colorChannelSize < (unsigned)_ledCount)
{
_redChannel.resize(_ledCount, uint8_t(0));
_greenChannel.resize(_ledCount, uint8_t(0));
_blueChannel.resize(_ledCount, uint8_t(0));
}
_colorChannelSize = _ledCount;
isInitOK = true;
}
}
return isInitOK;
}
int LedDeviceTinkerforge::open()
{
// Check if connection is already createds
if (_ipConnection != nullptr)
int retval = -1;
QString errortext;
_deviceReady = false;
if ( init(_devConfig) )
{
Error(_log, "Attempt to open existing connection; close before opening");
return 0;
// Check if connection is already createds
if (_ipConnection != nullptr)
{
Error(_log, "Attempt to open existing connection; close before opening");
}
else
{
// Initialise a new connection
_ipConnection = new IPConnection;
ipcon_create(_ipConnection);
int connectionStatus = ipcon_connect(_ipConnection, QSTRING_CSTR(_host), _port);
if (connectionStatus < 0)
{
Error(_log, "Attempt to connect to master brick (%s:%d) failed with status %d", QSTRING_CSTR(_host), _port, connectionStatus);
}
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;
}
}
}
// On error/exceptions, set LedDevice in error
if ( retval < 0 )
{
this->setInError( "Error opening device!" );
}
}
// Initialise a new connection
_ipConnection = new IPConnection;
ipcon_create(_ipConnection);
int connectionStatus = ipcon_connect(_ipConnection, QSTRING_CSTR(_host), _port);
if (connectionStatus < 0)
{
Error(_log, "Attempt to connect to master brick (%s:%d) failed with status %d", QSTRING_CSTR(_host), _port, connectionStatus);
return 0;
}
// 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);
return 0;
}
return 1;
return retval;
}
int LedDeviceTinkerforge::write(const std::vector<ColorRgb> &ledValues)
{
if(!_deviceReady)
return 0;
auto redIt = _redChannel.begin();
auto greenIt = _greenChannel.begin();
auto blueIt = _blueChannel.begin();

View File

@@ -8,7 +8,6 @@
// Hyperion-Leddevice includes
#include <leddevice/LedDevice.h>
extern "C" {
#include <tinkerforge/ip_connection.h>
#include <tinkerforge/bricklet_led_strip.h>
@@ -22,26 +21,27 @@ public:
///
/// @param deviceConfig json device config
///
LedDeviceTinkerforge(const QJsonObject &deviceConfig);
explicit LedDeviceTinkerforge(const QJsonObject &deviceConfig);
virtual ~LedDeviceTinkerforge();
virtual ~LedDeviceTinkerforge() override;
/// 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);
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
bool init(const QJsonObject &deviceConfig) override;
protected:
///
/// Attempts to open a connection to the master bricklet and the led strip bricklet.
///
/// @return Zero on succes else negative
///
int open();
virtual int open() override;
private:
///
@@ -51,7 +51,7 @@ private:
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
virtual int write(const std::vector<ColorRgb> &ledValues) override;
///
/// Writes the data to the led strip blicklet

View File

@@ -11,9 +11,9 @@
"latchTime": {
"type": "integer",
"title":"edt_dev_spec_latchtime_title",
"default": 1,
"default": 0,
"append" : "edt_append_ms",
"minimum": 1,
"minimum": 0,
"maximum": 1000,
"access" : "expert",
"propertyOrder" : 2

View File

@@ -2,7 +2,7 @@
"type":"object",
"required":true,
"properties":{
"output": {
"host": {
"type": "string",
"title":"edt_dev_spec_targetIpHost_title",
"propertyOrder" : 1