Threading and more

- webui remove restarts
- threading for LedDevice
This commit is contained in:
Paulchen-Panther
2019-01-01 19:47:07 +01:00
parent 7b6df922ea
commit 7352ff4d42
24 changed files with 482 additions and 282 deletions

View File

@@ -10,10 +10,9 @@
#include "hyperion/Hyperion.h"
#include <utils/JsonUtils.h>
LedDeviceRegistry LedDevice::_ledDeviceMap = LedDeviceRegistry();
LedDevice::LedDevice()
: QObject()
LedDevice::LedDevice(const QJsonObject& config, QObject* parent)
: QObject(parent)
, _devConfig(config)
, _log(Logger::getInstance("LEDDEVICE"))
, _ledBuffer(0)
, _deviceReady(true)
@@ -24,15 +23,16 @@ LedDevice::LedDevice()
, _componentRegistered(false)
, _enabled(true)
{
LedDevice::getLedDeviceSchemas();
qRegisterMetaType<hyperion::Components>("hyperion::Components");
// setup timer
_refresh_timer.setSingleShot(false);
_refresh_timer.setInterval(0);
connect(&_refresh_timer, SIGNAL(timeout()), this, SLOT(rewriteLeds()));
}
LedDevice::~LedDevice()
{
}
// dummy implemention
int LedDevice::open()
{
@@ -55,17 +55,6 @@ void LedDevice::setEnable(bool enable)
_enabled = enable;
}
int LedDevice::addToDeviceMap(QString name, LedDeviceCreateFuncType funcPtr)
{
_ledDeviceMap.emplace(name,funcPtr);
return 0;
}
const LedDeviceRegistry& LedDevice::getDeviceMap()
{
return _ledDeviceMap;
}
void LedDevice::setActiveDevice(QString dev)
{
_activeDevice = dev;
@@ -88,42 +77,6 @@ bool LedDevice::init(const QJsonObject &deviceConfig)
return true;
}
QJsonObject LedDevice::getLedDeviceSchemas()
{
// make sure the resources are loaded (they may be left out after static linking)
Q_INIT_RESOURCE(LedDeviceSchemas);
// read the json schema from the resource
QDir d(":/leddevices/");
QStringList l = d.entryList();
QJsonObject result, schemaJson;
for(QString &item : l)
{
QString schemaPath(QString(":/leddevices/")+item);
QString devName = item.remove("schema-");
QString data;
if(!FileUtils::readFile(schemaPath, data, Logger::getInstance("LedDevice")))
{
throw std::runtime_error("ERROR: Schema not found: " + item.toStdString());
}
QJsonObject schema;
if(!JsonUtils::parse(schemaPath, data, schema, Logger::getInstance("LedDevice")))
{
throw std::runtime_error("ERROR: Json schema wrong of file: " + item.toStdString());
}
schemaJson = schema;
schemaJson["title"] = QString("edt_dev_spec_header_title");
result[devName] = schemaJson;
}
return result;
}
int LedDevice::setLedValues(const std::vector<ColorRgb>& ledValues)
{
int retval = 0;

View File

@@ -7,10 +7,11 @@
// Leddevice includes
#include <leddevice/LedDeviceFactory.h>
#include <leddevice/LedDeviceWrapper.h>
#include <utils/Logger.h>
#include <leddevice/LedDevice.h>
// following file is auto generated by cmake! it contains all available leddevice headers
// autogen
#include "LedDevice_headers.h"
LedDevice * LedDeviceFactory::construct(const QJsonObject & deviceConfig)
@@ -21,14 +22,7 @@ LedDevice * LedDeviceFactory::construct(const QJsonObject & deviceConfig)
QString type = deviceConfig["type"].toString("UNSPECIFIED").toLower();
#define REGISTER(className) LedDevice::addToDeviceMap(QString(#className).toLower(), LedDevice##className::construct);
// the REGISTER() calls are autogenerated by cmake.
#include "LedDevice_register.cpp"
#undef REGISTER
const LedDeviceRegistry& devList = LedDevice::getDeviceMap();
const LedDeviceRegistry& devList = LedDeviceWrapper::getDeviceMap();
LedDevice* device = nullptr;
try
{
@@ -56,7 +50,5 @@ LedDevice * LedDeviceFactory::construct(const QJsonObject & deviceConfig)
device = LedDeviceFile::construct(QJsonObject());
}
device->open();
return device;
}

View File

@@ -0,0 +1,148 @@
#include <leddevice/LedDeviceWrapper.h>
#include <leddevice/LedDevice.h>
#include <leddevice/LedDeviceFactory.h>
// following file is auto generated by cmake! it contains all available leddevice headers
#include "LedDevice_headers.h"
// util
#include <hyperion/Hyperion.h>
#include <utils/JsonUtils.h>
// qt
#include <QThread>
#include <QDir>
LedDeviceRegistry LedDeviceWrapper::_ledDeviceMap = LedDeviceRegistry();
LedDeviceWrapper::LedDeviceWrapper(Hyperion* hyperion)
: QObject(hyperion)
, _hyperion(hyperion)
, _ledDevice(nullptr)
{
// prepare the device constrcutor map
#define REGISTER(className) LedDeviceWrapper::addToDeviceMap(QString(#className).toLower(), LedDevice##className::construct);
// the REGISTER() calls are autogenerated by cmake.
#include "LedDevice_register.cpp"
#undef REGISTER
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, true);
}
LedDeviceWrapper::~LedDeviceWrapper()
{
stopDeviceThread();
}
void LedDeviceWrapper::createLedDevice(const QJsonObject& config)
{
if(_ledDevice != nullptr)
{
stopDeviceThread();
}
// create thread and device
QThread* thread = new QThread(this);
_ledDevice = LedDeviceFactory::construct(config);
_ledDevice->moveToThread(thread);
// setup thread management
connect(thread, &QThread::started, _ledDevice, &LedDevice::start);
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
connect(thread, &QThread::finished, _ledDevice, &QObject::deleteLater);
// further signals
connect(this, &LedDeviceWrapper::write, _ledDevice, &LedDevice::write);
connect(_ledDevice, &LedDevice::enableStateChanged, this, &LedDeviceWrapper::handleInternalEnableState);
// start the thread
thread->start();
}
const QJsonObject LedDeviceWrapper::getLedDeviceSchemas()
{
// make sure the resources are loaded (they may be left out after static linking)
Q_INIT_RESOURCE(LedDeviceSchemas);
// read the json schema from the resource
QDir d(":/leddevices/");
QStringList l = d.entryList();
QJsonObject result, schemaJson;
for(QString &item : l)
{
QString schemaPath(QString(":/leddevices/")+item);
QString devName = item.remove("schema-");
QString data;
if(!FileUtils::readFile(schemaPath, data, Logger::getInstance("LedDevice")))
{
throw std::runtime_error("ERROR: Schema not found: " + item.toStdString());
}
QJsonObject schema;
if(!JsonUtils::parse(schemaPath, data, schema, Logger::getInstance("LedDevice")))
{
throw std::runtime_error("ERROR: Json schema wrong of file: " + item.toStdString());
}
schemaJson = schema;
schemaJson["title"] = QString("edt_dev_spec_header_title");
result[devName] = schemaJson;
}
return result;
}
int LedDeviceWrapper::addToDeviceMap(QString name, LedDeviceCreateFuncType funcPtr)
{
_ledDeviceMap.emplace(name,funcPtr);
return 0;
}
const LedDeviceRegistry& LedDeviceWrapper::getDeviceMap()
{
return _ledDeviceMap;
}
int LedDeviceWrapper::getLatchTime()
{
return _ledDevice->getLatchTime();
}
const QString & LedDeviceWrapper::getActiveDevice()
{
return _ledDevice->getActiveDevice();
}
const QString & LedDeviceWrapper::getColorOrder()
{
return _ledDevice->getColorOrder();
}
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;
}
}
void LedDeviceWrapper::handleInternalEnableState(bool newState)
{
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, newState);
_enabled = newState;
}
void LedDeviceWrapper::stopDeviceThread()
{
_ledDevice->switchOff();
QThread* oldThread = _ledDevice->thread();
delete _ledDevice; // fast desctruction
oldThread->quit(); // non blocking
}

View File

@@ -201,7 +201,7 @@ void PhilipsHueBridge::resolveReply(QNetworkReply* reply)
void PhilipsHueBridge::post(QString route, QString content)
{
Debug(log, "Post %s: %s", QSTRING_CSTR(QString("http://IP/api/USR/%1").arg(route)), QSTRING_CSTR(content));
//Debug(log, "Post %s: %s", QSTRING_CSTR(QString("http://IP/api/USR/%1").arg(route)), QSTRING_CSTR(content));
QNetworkRequest request(QString("http://%1/api/%2/%3").arg(host).arg(username).arg(route));
manager.put(request, content.toLatin1());
@@ -214,7 +214,7 @@ const std::set<QString> PhilipsHueLight::GAMUT_B_MODEL_IDS =
const std::set<QString> PhilipsHueLight::GAMUT_C_MODEL_IDS =
{ "LLC020", "LST002", "LCT011", "LCT012", "LCT010", "LCT014" };
PhilipsHueLight::PhilipsHueLight(Logger* log, PhilipsHueBridge& bridge, unsigned int id, QJsonObject values)
PhilipsHueLight::PhilipsHueLight(Logger* log, PhilipsHueBridge* bridge, unsigned int id, QJsonObject values)
: log(log)
, bridge(bridge)
, id(id)
@@ -297,7 +297,7 @@ PhilipsHueLight::~PhilipsHueLight()
void PhilipsHueLight::set(QString state)
{
bridge.post(QString("lights/%1/state").arg(id), state);
bridge->post(QString("lights/%1/state").arg(id), state);
}
void PhilipsHueLight::setOn(bool on)
@@ -345,18 +345,25 @@ LedDevice* LedDevicePhilipsHue::construct(const QJsonObject &deviceConfig)
}
LedDevicePhilipsHue::LedDevicePhilipsHue(const QJsonObject& deviceConfig)
: LedDevice()
, bridge(_log, deviceConfig["output"].toString(), deviceConfig["username"].toString())
: LedDevice(deviceConfig)
, _bridge(nullptr)
{
_deviceReady = init(deviceConfig);
connect(&bridge, &PhilipsHueBridge::newLights, this, &LedDevicePhilipsHue::newLights);
connect(this, &LedDevice::enableStateChanged, this, &LedDevicePhilipsHue::stateChanged);
}
LedDevicePhilipsHue::~LedDevicePhilipsHue()
{
switchOff();
delete _bridge;
}
void LedDevicePhilipsHue::start()
{
_bridge = new PhilipsHueBridge(_log, _devConfig["output"].toString(), _devConfig["username"].toString());
_deviceReady = init(_devConfig);
connect(_bridge, &PhilipsHueBridge::newLights, this, &LedDevicePhilipsHue::newLights);
connect(this, &LedDevice::enableStateChanged, this, &LedDevicePhilipsHue::stateChanged);
}
bool LedDevicePhilipsHue::init(const QJsonObject &deviceConfig)
@@ -374,7 +381,7 @@ bool LedDevicePhilipsHue::init(const QJsonObject &deviceConfig)
lightIds.push_back(i.toInt());
}
// get light info from bridge
bridge.bConnect();
_bridge->bConnect();
// adapt latchTime to count of user lightIds (bridge 10Hz max overall)
newDC.insert("latchTime",QJsonValue(100*(int)lightIds.size()));
@@ -399,7 +406,7 @@ void LedDevicePhilipsHue::newLights(QMap<quint16, QJsonObject> map)
{
if (map.contains(id))
{
lights.push_back(PhilipsHueLight(_log, bridge, id, map.value(id)));
lights.push_back(PhilipsHueLight(_log, _bridge, id, map.value(id)));
}
else
{
@@ -427,7 +434,6 @@ int LedDevicePhilipsHue::write(const std::vector<ColorRgb> & ledValues)
{
// Get color.
ColorRgb color = ledValues.at(idx);
// Scale colors from [0, 255] to [0, 1] and convert to xy space.
CiColor xy = CiColor::rgbToCiColor(color.red / 255.0f, color.green / 255.0f, color.blue / 255.0f,
light.getColorSpace());
@@ -453,7 +459,7 @@ int LedDevicePhilipsHue::write(const std::vector<ColorRgb> & ledValues)
void LedDevicePhilipsHue::stateChanged(bool newState)
{
if(newState)
bridge.bConnect();
_bridge->bConnect();
else
lights.clear();
}

View File

@@ -139,7 +139,7 @@ class PhilipsHueLight
{
private:
Logger* log;
PhilipsHueBridge& bridge;
PhilipsHueBridge* bridge;
/// light id
unsigned int id;
bool on;
@@ -172,7 +172,7 @@ public:
/// @param bridge the bridge
/// @param id the light id
///
PhilipsHueLight(Logger* log, PhilipsHueBridge& bridge, unsigned int id, QJsonObject values);
PhilipsHueLight(Logger* log, PhilipsHueBridge* bridge, unsigned int id, QJsonObject values);
~PhilipsHueLight();
///
@@ -227,6 +227,10 @@ public:
/// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
public slots:
/// thread start
virtual void start();
private slots:
/// creates new PhilipsHueLight(s) based on user lightid with bridge feedback
///
@@ -249,7 +253,7 @@ protected:
private:
/// bridge class
PhilipsHueBridge bridge;
PhilipsHueBridge* _bridge;
///
bool switchOffOnBlack;

View File

@@ -40,7 +40,7 @@ bool LedDeviceTinkerforge::init(const QJsonObject &deviceConfig)
_uid = deviceConfig["uid"].toString();
_interval = deviceConfig["rate"].toInt();
if ((unsigned)_ledCount > MAX_NUM_LEDS)
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;
@@ -68,7 +68,7 @@ int LedDeviceTinkerforge::open()
if (_ipConnection != nullptr)
{
Error(_log, "Attempt to open existing connection; close before opening");
return -1;
return 0;
}
// Initialise a new connection
@@ -76,10 +76,10 @@ int LedDeviceTinkerforge::open()
ipcon_create(_ipConnection);
int connectionStatus = ipcon_connect(_ipConnection, QSTRING_CSTR(_host), _port);
if (connectionStatus < 0)
if (connectionStatus < 0)
{
Warning(_log, "Attempt to connect to master brick (%s:%d) failed with status %d", QSTRING_CSTR(_host), _port, connectionStatus);
return -1;
Error(_log, "Attempt to connect to master brick (%s:%d) failed with status %d", QSTRING_CSTR(_host), _port, connectionStatus);
return 0;
}
// Create the 'LedStrip'
@@ -87,17 +87,20 @@ int LedDeviceTinkerforge::open()
led_strip_create(_ledStrip, QSTRING_CSTR(_uid), _ipConnection);
int frameStatus = led_strip_set_frame_duration(_ledStrip, _interval);
if (frameStatus < 0)
if (frameStatus < 0)
{
Error(_log,"Attempt to connect to led strip bricklet (led_strip_set_frame_duration()) failed with status %d", frameStatus);
return -1;
return 0;
}
return 0;
return 1;
}
int LedDeviceTinkerforge::write(const std::vector<ColorRgb> &ledValues)
{
if(!_deviceReady)
return 0;
auto redIt = _redChannel.begin();
auto greenIt = _greenChannel.begin();
auto blueIt = _blueChannel.begin();
@@ -115,7 +118,7 @@ int LedDeviceTinkerforge::write(const std::vector<ColorRgb> &ledValues)
return transferLedData(_ledStrip, 0, _colorChannelSize, _redChannel.data(), _greenChannel.data(), _blueChannel.data());
}
int LedDeviceTinkerforge::transferLedData(LEDStrip *ledStrip, unsigned index, unsigned length, uint8_t *redChannel, uint8_t *greenChannel, uint8_t *blueChannel)
int LedDeviceTinkerforge::transferLedData(LEDStrip *ledStrip, unsigned index, unsigned length, uint8_t *redChannel, uint8_t *greenChannel, uint8_t *blueChannel)
{
if (length == 0 || index >= length || length > MAX_NUM_LEDS)
{