Merge branch 'master' into Razer_Chroma_Support

This commit is contained in:
LordGrey
2020-10-19 22:08:18 +02:00
committed by GitHub
44 changed files with 1698 additions and 1782 deletions

View File

@@ -56,7 +56,18 @@ API::API(Logger *log, bool localConnection, QObject *parent)
//connect(ApiSync::getInstance(), &ApiSync::requestActiveRegister, this, &API::requestActiveRegister, Qt::QueuedConnection);
// connect to possible token responses that has been requested
connect(_authManager, &AuthManager::tokenResponse, this, &API::checkTokenResponse);
connect(_authManager, &AuthManager::tokenResponse, [=] (bool success, QObject *caller, const QString &token, const QString &comment, const QString &id, const int &tan)
{
if (this == caller)
emit onTokenResponse(success, token, comment, id, tan);
});
// connect to possible startInstance responses that has been requested
connect(_instanceManager, &HyperionIManager::startInstanceResponse, [=] (QObject *caller, const int &tan)
{
if (this == caller)
emit onStartInstanceResponse(tan);
});
}
void API::init()
@@ -211,16 +222,19 @@ void API::setVideoMode(VideoMode mode, hyperion::Components callerComp)
QMetaObject::invokeMethod(_hyperion, "setVideoMode", Qt::QueuedConnection, Q_ARG(VideoMode, mode));
}
void API::setEffect(const EffectCmdData &dat, hyperion::Components callerComp)
bool API::setEffect(const EffectCmdData &dat, hyperion::Components callerComp)
{
int res;
if (!dat.args.isEmpty())
{
QMetaObject::invokeMethod(_hyperion, "setEffect", Qt::QueuedConnection, Q_ARG(QString, dat.effectName), Q_ARG(QJsonObject, dat.args), Q_ARG(int, dat.priority), Q_ARG(int, dat.duration), Q_ARG(QString, dat.pythonScript), Q_ARG(QString, dat.origin), Q_ARG(QString, dat.data));
QMetaObject::invokeMethod(_hyperion, "setEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, res), Q_ARG(QString, dat.effectName), Q_ARG(QJsonObject, dat.args), Q_ARG(int, dat.priority), Q_ARG(int, dat.duration), Q_ARG(QString, dat.pythonScript), Q_ARG(QString, dat.origin), Q_ARG(QString, dat.data));
}
else
{
QMetaObject::invokeMethod(_hyperion, "setEffect", Qt::QueuedConnection, Q_ARG(QString, dat.effectName), Q_ARG(int, dat.priority), Q_ARG(int, dat.duration), Q_ARG(QString, dat.origin));
QMetaObject::invokeMethod(_hyperion, "setEffect", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, res), Q_ARG(QString, dat.effectName), Q_ARG(int, dat.priority), Q_ARG(int, dat.duration), Q_ARG(QString, dat.origin));
}
return res >= 0;
}
void API::setSourceAutoSelect(bool state, hyperion::Components callerComp)
@@ -285,9 +299,14 @@ QVector<QVariantMap> API::getAllInstanceData()
return vec;
}
void API::startInstance(quint8 index)
bool API::startInstance(quint8 index, int tan)
{
QMetaObject::invokeMethod(_instanceManager, "startInstance", Qt::QueuedConnection, Q_ARG(quint8, index));
bool res;
(_instanceManager->thread() != this->thread())
? QMetaObject::invokeMethod(_instanceManager, "startInstance", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, res), Q_ARG(quint8, index), Q_ARG(bool, false), Q_ARG(QObject*, this), Q_ARG(int, tan))
: res = _instanceManager->startInstance(index, false, this, tan);
return res;
}
void API::stopInstance(quint8 index)
@@ -407,9 +426,9 @@ QString API::deleteToken(const QString &id)
return "";
}
void API::setNewTokenRequest(const QString &comment, const QString &id)
void API::setNewTokenRequest(const QString &comment, const QString &id, const int &tan)
{
QMetaObject::invokeMethod(_authManager, "setNewTokenRequest", Qt::QueuedConnection, Q_ARG(QObject *, this), Q_ARG(QString, comment), Q_ARG(QString, id));
QMetaObject::invokeMethod(_authManager, "setNewTokenRequest", Qt::QueuedConnection, Q_ARG(QObject *, this), Q_ARG(QString, comment), Q_ARG(QString, id), Q_ARG(int, tan));
}
void API::cancelNewTokenRequest(const QString &comment, const QString &id)
@@ -465,12 +484,11 @@ bool API::getUserToken(QString &userToken)
bool API::isTokenAuthorized(const QString &token)
{
bool res;
QMetaObject::invokeMethod(_authManager, "isTokenAuthorized", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, res), Q_ARG(QString, token));
if (res)
_authorized = true;
(_authManager->thread() != this->thread())
? QMetaObject::invokeMethod(_authManager, "isTokenAuthorized", Qt::BlockingQueuedConnection, Q_RETURN_ARG(bool, _authorized), Q_ARG(QString, token))
: _authorized = _authManager->isTokenAuthorized(token);
return res;
return _authorized;
}
bool API::isUserAuthorized(const QString &password)
@@ -503,12 +521,6 @@ void API::logout()
stopDataConnectionss();
}
void API::checkTokenResponse(bool success, QObject *caller, const QString &token, const QString &comment, const QString &id)
{
if (this == caller)
emit onTokenResponse(success, token, comment, id);
}
void API::stopDataConnectionss()
{
}

View File

@@ -243,9 +243,10 @@ void JsonAPI::handleEffectCommand(const QJsonObject &message, const QString &com
dat.data = message["imageData"].toString("").toUtf8();
dat.args = message["effect"].toObject()["args"].toObject();
API::setEffect(dat);
sendSuccessReply(command, tan);
if (API::setEffect(dat))
sendSuccessReply(command, tan);
else
sendErrorReply("Effect '" + dat.effectName + "' not found", command, tan);
}
void JsonAPI::handleCreateEffectCommand(const QJsonObject &message, const QString &command, int tan)
@@ -351,8 +352,10 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
item["value"] = LEDcolor;
}
// priorities[priorities.size()] = item;
priorities.append(item);
(priority == currentPriority)
? priorities.prepend(item)
: priorities.append(item);
}
info["priorities"] = priorities;
@@ -1186,7 +1189,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject &message, const QString &
const QString &comment = message["comment"].toString().trimmed();
const bool &acc = message["accept"].toBool(true);
if (acc)
API::setNewTokenRequest(comment, id);
API::setNewTokenRequest(comment, id, tan);
else
API::cancelNewTokenRequest(comment, id);
// client should wait for answer
@@ -1323,9 +1326,10 @@ void JsonAPI::handleInstanceCommand(const QJsonObject &message, const QString &c
if (subc == "startInstance")
{
// silent fail
API::startInstance(inst);
sendSuccessReply(command + "-" + subc, tan);
connect(this, &API::onStartInstanceResponse, [=] (const int &tan) { sendSuccessReply(command + "-" + subc, tan); });
if (!API::startInstance(inst, tan))
sendErrorReply("Can't start Hyperion instance index " + QString::number(inst), command + "-" + subc, tan);
return;
}
@@ -1557,7 +1561,7 @@ void JsonAPI::newPendingTokenRequest(const QString &id, const QString &comment)
sendSuccessDataReply(QJsonDocument(obj), "authorize-tokenRequest", 1);
}
void JsonAPI::handleTokenResponse(bool success, const QString &token, const QString &comment, const QString &id)
void JsonAPI::handleTokenResponse(bool success, const QString &token, const QString &comment, const QString &id, const int &tan)
{
const QString cmd = "authorize-requestToken";
QJsonObject result;
@@ -1566,9 +1570,9 @@ void JsonAPI::handleTokenResponse(bool success, const QString &token, const QStr
result["id"] = id;
if (success)
sendSuccessDataReply(QJsonDocument(result), cmd);
sendSuccessDataReply(QJsonDocument(result), cmd, tan);
else
sendErrorReply("Token request timeout or denied", cmd, 5);
sendErrorReply("Token request timeout or denied", cmd, tan);
}
void JsonAPI::handleInstanceStateChange(InstanceState state, quint8 instance, const QString &name)

View File

@@ -3,11 +3,13 @@
#include <cassert>
#include <iomanip>
#include <cstdio>
#include <cmath>
// stl includes
#include <iostream>
#include <sstream>
#include <iterator>
#include <locale>
// Qt includes
#include <QResource>
@@ -54,18 +56,19 @@ BoblightClientConnection::~BoblightClientConnection()
void BoblightClientConnection::readData()
{
_receiveBuffer += _socket->readAll();
_receiveBuffer.append(_socket->readAll());
int bytes = _receiveBuffer.indexOf('\n') + 1;
while(bytes > 0)
{
// create message string (strip the newline)
QString message = QString::fromLatin1(_receiveBuffer.data(), bytes-1);
// remove message data from buffer
_receiveBuffer = _receiveBuffer.mid(bytes);
const QString message = readMessage(_receiveBuffer.data(), bytes);
// handle trimmed message
handleMessage(message.trimmed());
handleMessage(message);
// remove message data from buffer
_receiveBuffer.remove(0, bytes);
// drop messages if the buffer is too full
if (_receiveBuffer.size() > 100*1024)
@@ -79,6 +82,31 @@ void BoblightClientConnection::readData()
}
}
QString BoblightClientConnection::readMessage(const char *data, const size_t size) const
{
char *end = (char *)data + size - 1;
// Trim left
while (data < end && std::isspace(*data))
{
++data;
}
// Trim right
while (end > data && std::isspace(*end))
{
--end;
}
// create message string (strip the newline)
const int len = end - data + 1;
const QString message = QString::fromLatin1(data, len);
//std::cout << bytes << ": \"" << message.toUtf8().constData() << "\"" << std::endl;
return message;
}
void BoblightClientConnection::socketClosed()
{
// clear the current channel
@@ -88,10 +116,11 @@ void BoblightClientConnection::socketClosed()
emit connectionClosed(this);
}
void BoblightClientConnection::handleMessage(const QString & message)
{
//std::cout << "boblight message: " << message.toStdString() << std::endl;
QStringList messageParts = QStringUtils::split(message," ",QStringUtils::SplitBehavior::SkipEmptyParts);
const QVector<QStringRef> messageParts = QStringUtils::splitRef(message, ' ', QStringUtils::SplitBehavior::SkipEmptyParts);
if (messageParts.size() > 0)
{
if (messageParts[0] == "hello")
@@ -122,32 +151,18 @@ void BoblightClientConnection::handleMessage(const QString & message)
if (messageParts.size() > 3 && messageParts[1] == "light")
{
bool rc;
unsigned ledIndex = messageParts[2].toUInt(&rc);
const unsigned ledIndex = parseUInt(messageParts[2], &rc);
if (rc && ledIndex < _ledColors.size())
{
if (messageParts[3] == "rgb" && messageParts.size() == 7)
{
// replace decimal comma with decimal point
messageParts[4].replace(',', '.');
messageParts[5].replace(',', '.');
messageParts[6].replace(',', '.');
// custom parseByte accepts both ',' and '.' as decimal separator
// no need to replace decimal comma with decimal point
bool rc1, rc2, rc3;
uint8_t red = qMax(0, qMin(255, int(255 * messageParts[4].toFloat(&rc1))));
// check for correct locale should not be needed anymore - please check!
if (!rc1)
{
// maybe a locale issue. switch to a locale with a comma instead of a dot as decimal seperator (or vice versa)
_locale = QLocale((_locale.decimalPoint() == QChar('.')) ? QLocale::Dutch : QLocale::C);
_locale.setNumberOptions(QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator);
// try again
red = qMax(0, qMin(255, int(255 * messageParts[4].toFloat(&rc1))));
}
uint8_t green = qMax(0, qMin(255, int(255 * messageParts[5].toFloat(&rc2))));
uint8_t blue = qMax(0, qMin(255, int(255 * messageParts[6].toFloat(&rc3))));
const uint8_t red = parseByte(messageParts[4], &rc1);
const uint8_t green = parseByte(messageParts[5], &rc2);
const uint8_t blue = parseByte(messageParts[6], &rc3);
if (rc1 && rc2 && rc3)
{
@@ -181,7 +196,7 @@ void BoblightClientConnection::handleMessage(const QString & message)
else if (messageParts.size() == 3 && messageParts[1] == "priority")
{
bool rc;
int prio = messageParts[2].toInt(&rc);
const int prio = static_cast<int>(parseUInt(messageParts[2], &rc));
if (rc && prio != _priority)
{
if (_priority != 0 && _hyperion->getPriorityInfo(_priority).componentId == hyperion::COMP_BOBLIGHTSERVER)
@@ -223,6 +238,146 @@ void BoblightClientConnection::handleMessage(const QString & message)
Debug(_log, "unknown boblight message: %s", QSTRING_CSTR(message));
}
/// Float values 10 to the power of -p for p in 0 .. 8.
const float ipows[] = {
1,
1.0f / 10.0f,
1.0f / 100.0f,
1.0f / 1000.0f,
1.0f / 10000.0f,
1.0f / 100000.0f,
1.0f / 1000000.0f,
1.0f / 10000000.0f,
1.0f / 100000000.0f};
float BoblightClientConnection::parseFloat(const QStringRef& s, bool *ok) const
{
// We parse radix 10
const char MIN_DIGIT = '0';
const char MAX_DIGIT = '9';
const char SEP_POINT = '.';
const char SEP_COMMA = ',';
const int NUM_POWS = 9;
/// The maximum number of characters we want to process
const int MAX_LEN = 18; // Chosen randomly
/// The index of the current character
int q = 0;
/// The integer part of the number
int64_t n = 0;
auto it = s.begin();
#define STEP ((it != s.end()) && (q++ < MAX_LEN))
// parse the integer-part
while (it->unicode() >= MIN_DIGIT && it->unicode() <= MAX_DIGIT && STEP)
{
n = (n * 10) + (it->unicode() - MIN_DIGIT);
++it;
}
/// The resulting float value
float f = static_cast<float>(n);
// parse decimal part
if ((it->unicode() == SEP_POINT || it->unicode() == SEP_COMMA) && STEP)
{
/// The decimal part of the number
int64_t d = 0;
/// The exponent for the scale-factor 10 to the power -e
int e = 0;
++it;
while (it->unicode() >= MIN_DIGIT && it->unicode() <= MAX_DIGIT && STEP)
{
d = (d * 10) + (it->unicode() - MIN_DIGIT);
++e;
++it;
}
const float h = static_cast<float>(d);
// We want to use pre-calculated power whenever possible
if (e < NUM_POWS)
{
f += h * ipows[e];
}
else
{
f += h / std::pow(10.0f, e);
}
}
if (q >= MAX_LEN || q < s.length())
{
if (ok)
{
//std::cout << "FAIL L " << q << ": " << s.toUtf8().constData() << std::endl;
*ok = false;
}
return 0;
}
if (ok)
{
//std::cout << "OK " << d << ": " << s.toUtf8().constData() << std::endl;
*ok = true;
}
return f;
}
unsigned BoblightClientConnection::parseUInt(const QStringRef& s, bool *ok) const
{
// We parse radix 10
const char MIN_DIGIT = '0';
const char MAX_DIGIT = '9';
/// The maximum number of characters we want to process
const int MAX_LEN = 10;
/// The index of the current character
int q = 0;
/// The integer part of the number
int n = 0;
auto it = s.begin();
// parse the integer-part
while (it->unicode() >= MIN_DIGIT && it->unicode() <= MAX_DIGIT && ((it != s.end()) && (q++ < MAX_LEN)))
{
n = (n * 10) + (it->unicode() - MIN_DIGIT);
++it;
}
if (ok)
{
*ok = !(q >= MAX_LEN || q < s.length());
}
return n;
}
uint8_t BoblightClientConnection::parseByte(const QStringRef& s, bool *ok) const
{
const int LO = 0;
const int HI = 255;
#if defined(FAST_FLOAT_PARSE)
const float d = parseFloat(s, ok);
#else
const float d = s.toFloat(ok);
#endif
// Clamp to byte range 0 to 255
return static_cast<uint8_t>(qBound(LO, int(HI * d), HI)); // qBound args are in order min, value, max; see: https://doc.qt.io/qt-5/qtglobal.html#qBound
}
void BoblightClientConnection::sendLightMessage()
{
char buffer[256];

View File

@@ -4,11 +4,15 @@
#include <QByteArray>
#include <QTcpSocket>
#include <QLocale>
#include <QString>
// utils includes
#include <utils/Logger.h>
#include <utils/ColorRgb.h>
/// Whether to parse floats with an eye on performance
#define FAST_FLOAT_PARSE
class ImageProcessor;
class Hyperion;
@@ -70,6 +74,42 @@ private:
///
void sendLightMessage();
///
/// Interpret the float value "0.0" to "1.0" of the QString byte values 0 .. 255
///
/// @param s the string to parse
/// @param ok whether the result is ok
/// @return the parsed byte value in range 0 to 255, or 0
///
uint8_t parseByte(const QStringRef& s, bool *ok = nullptr) const;
///
/// Parse the given QString as unsigned int value.
///
/// @param s the string to parse
/// @param ok whether the result is ok
/// @return the parsed unsigned int value
///
unsigned parseUInt(const QStringRef& s, bool *ok = nullptr) const;
///
/// Parse the given QString as float value, e.g. the 16-bit (wide char) QString "1" shall represent 1, "0.5" is 0.5 and so on.
///
/// @param s the string to parse
/// @param ok whether the result is ok
/// @return the parsed float value, or 0
///
float parseFloat(const QStringRef& s, bool *ok = nullptr) const;
///
/// Read an incoming boblight message as QString
///
/// @param data the char data buffer of the incoming message
/// @param size the length of the buffer buffer
/// @returns the incoming boblight message as QString
///
QString readMessage(const char *data, const size_t size) const;
private:
/// Locale used for parsing floating point values
QLocale _locale;

View File

@@ -141,8 +141,6 @@ int EffectEngine::runEffect(const QString &effectName, int priority, int timeout
int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin, unsigned smoothCfg, const QString &imageData)
{
Info( _log, "Run effect \"%s\" on channel %d", QSTRING_CSTR(effectName), priority);
if (pythonScript.isEmpty())
{
const EffectDefinition *effectDefinition = nullptr;
@@ -157,12 +155,14 @@ int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args,
if (effectDefinition == nullptr)
{
// no such effect
Error(_log, "Effect %s not found", QSTRING_CSTR(effectName));
Error(_log, "Effect \"%s\" not found", QSTRING_CSTR(effectName));
return -1;
}
Info( _log, "Run effect \"%s\" on channel %d", QSTRING_CSTR(effectName), priority);
return runEffectScript(effectDefinition->script, effectName, (args.isEmpty() ? effectDefinition->args : args), priority, timeout, origin, effectDefinition->smoothCfg);
}
Info( _log, "Run effect \"%s\" on channel %d", QSTRING_CSTR(effectName), priority);
return runEffectScript(pythonScript, effectName, args, priority, timeout, origin, smoothCfg, imageData);
}

View File

@@ -208,7 +208,7 @@ void EffectFileHandler::updateEffects()
{
if(directory.mkpath(path))
{
Info(_log, "New Effect path \"%s\" created successfull", QSTRING_CSTR(path) );
Info(_log, "New Effect path \"%s\" created successfully", QSTRING_CSTR(path) );
}
else
{

View File

@@ -150,18 +150,18 @@ bool AuthManager::resetHyperionUser()
return _authTable->resetHyperionUser();
}
void AuthManager::setNewTokenRequest(QObject *caller, const QString &comment, const QString &id)
void AuthManager::setNewTokenRequest(QObject *caller, const QString &comment, const QString &id, const int &tan)
{
if (!_pendingRequests.contains(id))
{
AuthDefinition newDef{id, comment, caller, uint64_t(QDateTime::currentMSecsSinceEpoch() + 180000)};
AuthDefinition newDef{id, comment, caller, tan, uint64_t(QDateTime::currentMSecsSinceEpoch() + 180000)};
_pendingRequests[id] = newDef;
_timer->start();
emit newPendingTokenRequest(id, comment);
}
}
void AuthManager::cancelNewTokenRequest(QObject *caller, const QString &comment, const QString &id)
void AuthManager::cancelNewTokenRequest(QObject *caller, const QString &, const QString &id)
{
if (_pendingRequests.contains(id))
{
@@ -182,12 +182,12 @@ void AuthManager::handlePendingTokenRequest(const QString &id, bool accept)
{
const QString token = QUuid::createUuid().toString().remove("{").remove("}");
_authTable->createToken(token, def.comment, id);
emit tokenResponse(true, def.caller, token, def.comment, id);
emit tokenResponse(true, def.caller, token, def.comment, id, def.tan);
emit tokenChange(getTokenList());
}
else
{
emit tokenResponse(false, def.caller, QString(), def.comment, id);
emit tokenResponse(false, def.caller, QString(), def.comment, id, def.tan);
}
}
}
@@ -249,7 +249,7 @@ void AuthManager::checkTimeout()
const AuthDefinition &def = i.value();
if (def.timeoutTime <= now)
{
emit tokenResponse(false, def.caller, QString(), def.comment, def.id);
emit tokenResponse(false, def.caller, QString(), def.comment, def.id, def.tan);
_pendingRequests.remove(i.key());
}
}

View File

@@ -87,7 +87,7 @@ void Hyperion::start()
// connect Hyperion::update with Muxer visible priority changes as muxer updates independent
connect(&_muxer, &PriorityMuxer::visiblePriorityChanged, this, &Hyperion::update);
connect(&_muxer, &PriorityMuxer::visiblePriorityChanged, this, &Hyperion::handlPriorityChangedLedDevice);
connect(&_muxer, &PriorityMuxer::visiblePriorityChanged, this, &Hyperion::handlePriorityChangedLedDevice);
connect(&_muxer, &PriorityMuxer::visibleComponentChanged, this, &Hyperion::handleVisibleComponentChanged);
// listens for ComponentRegister changes of COMP_ALL to perform core enable/disable actions
@@ -531,7 +531,7 @@ void Hyperion::handleVisibleComponentChanged(hyperion::Components comp)
_raw2ledAdjustment->setBacklightEnabled((comp != hyperion::COMP_COLOR && comp != hyperion::COMP_EFFECT));
}
void Hyperion::handlPriorityChangedLedDevice(const quint8& priority)
void Hyperion::handlePriorityChangedLedDevice(const quint8& priority)
{
quint8 previousPriority = _muxer.getPreviousPriority();

View File

@@ -67,7 +67,7 @@ void HyperionIManager::toggleStateAllInstances(bool pause)
}
}
bool HyperionIManager::startInstance(quint8 inst, bool block)
bool HyperionIManager::startInstance(quint8 inst, bool block, QObject* caller, int tan)
{
if(_instanceTable->instanceExist(inst))
{
@@ -104,6 +104,12 @@ bool HyperionIManager::startInstance(quint8 inst, bool block)
while(!hyperionThread->isRunning()){};
}
if (!_pendingRequests.contains(inst) && caller != nullptr)
{
PendingRequests newDef{caller, tan};
_pendingRequests[inst] = newDef;
}
return true;
}
Debug(_log,"Can't start Hyperion instance index '%d' with name '%s' it's already running or queued for start", inst, QSTRING_CSTR(_instanceTable->getNamebyIndex(inst)));
@@ -211,4 +217,11 @@ void HyperionIManager::handleStarted()
_runningInstances.insert(instance, hyperion);
emit instanceStateChanged(InstanceState::H_STARTED, instance);
emit change();
if (_pendingRequests.contains(instance))
{
PendingRequests def = _pendingRequests.take(instance);
emit startInstanceResponse(def.caller, def.tan);
_pendingRequests.remove(instance);
}
}

View File

@@ -142,9 +142,11 @@ hyperion::Components PriorityMuxer::getComponentOfPriority(int priority) const
void PriorityMuxer::registerInput(int priority, hyperion::Components component, const QString& origin, const QString& owner, unsigned smooth_cfg)
{
// detect new registers
bool newInput = false;
if(!_activeInputs.contains(priority))
bool newInput, reusedInput = false;
if (!_activeInputs.contains(priority))
newInput = true;
else
reusedInput = true;
InputInfo& input = _activeInputs[priority];
input.priority = priority;
@@ -154,12 +156,15 @@ void PriorityMuxer::registerInput(int priority, hyperion::Components component,
input.smooth_cfg = smooth_cfg;
input.owner = owner;
if(newInput)
if (newInput)
{
Debug(_log,"Register new input '%s/%s' with priority %d as inactive", QSTRING_CSTR(origin), hyperion::componentToIdString(component), priority);
emit prioritiesChanged();
if (!_sourceAutoSelectEnabled) // emit 'prioritiesChanged' only on when _sourceAutoSelectEnabled is false
emit prioritiesChanged();
return;
}
if (reusedInput) emit prioritiesChanged();
}
bool PriorityMuxer::setInput(int priority, const std::vector<ColorRgb>& ledColors, int64_t timeout_ms)
@@ -339,7 +344,6 @@ void PriorityMuxer::setCurrentTime()
_prevVisComp = comp;
emit visibleComponentChanged(comp);
}
emit prioritiesChanged();
}
}

View File

@@ -3,10 +3,6 @@
LedDeviceTemplate::LedDeviceTemplate(const QJsonObject &deviceConfig)
: LedDevice()
{
_devConfig = deviceConfig;
_isDeviceReady = false;
_activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDeviceTemplate::construct(const QJsonObject &deviceConfig)

View File

@@ -35,6 +35,7 @@ enum DATA_VERSION_INDEXES{
LedDeviceLightpack::LedDeviceLightpack(const QJsonObject &deviceConfig)
: LedDevice(deviceConfig)
, _libusbContext(nullptr)
, _device(nullptr)
, _deviceHandle(nullptr)
, _busNumber(-1)
, _addressNumber(-1)
@@ -80,17 +81,28 @@ bool LedDeviceLightpack::init(const QJsonObject &deviceConfig)
else
{
Debug(_log, "USB context initialized");
//libusb_set_debug(_libusbContext, 3);
if ( _log->getMinLevel() == Logger::LogLevel::DEBUG )
{
int logLevel = LIBUSB_LOG_LEVEL_INFO;
#if LIBUSB_API_VERSION >= 0x01000106
libusb_set_option(_libusbContext, LIBUSB_OPTION_LOG_LEVEL, logLevel);
#else
libusb_set_debug(_libusbContext, logLevel);
#endif
}
// retrieve the list of USB devices
libusb_device ** deviceList;
ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
bool deviceFound = true;
// iterate the list of devices
for (ssize_t i = 0 ; i < deviceCount; ++i)
{
// try to open and initialize the device
if (testAndOpen(deviceList[i], _serialNumber) == 0)
deviceFound = searchDevice(deviceList[i], _serialNumber);
if ( deviceFound )
{
_device = deviceList[i];
// a device was successfully opened. break from list
@@ -101,7 +113,7 @@ bool LedDeviceLightpack::init(const QJsonObject &deviceConfig)
// free the device list
libusb_free_device_list(deviceList, 1);
if (_deviceHandle == nullptr)
if (!deviceFound)
{
QString errortext;
if (_serialNumber.isEmpty())
@@ -110,12 +122,16 @@ bool LedDeviceLightpack::init(const QJsonObject &deviceConfig)
}
else
{
errortext = QString ("No Lightpack device has been found with serial %1").arg( _serialNumber);
errortext = QString ("No Lightpack device found with serial %1").arg( _serialNumber);
}
this->setInError( errortext );
}
else
{
// set the led buffer size (command + 6 bytes per led)
_ledBuffer = std::vector<uint8_t>(1 + _hwLedCount * 6, 0);
_ledBuffer[0] = CMD_UPDATE_LEDS;
isInitOK = true;
}
}
@@ -128,18 +144,29 @@ int LedDeviceLightpack::open()
int retval = -1;
_isDeviceReady = false;
if ( libusb_open(_device, &_deviceHandle) != LIBUSB_SUCCESS )
if ( _device != nullptr)
{
QString errortext = QString ("Failed to open [%1]").arg(_serialNumber);
this->setInError(errortext);
}
else
{
// Everything is OK -> enable device
_isDeviceReady = true;
retval = 0;
}
openDevice(_device, &_deviceHandle);
if ( _deviceHandle == nullptr )
{
QString errortext = QString ("Failed to open device with serial [%1]").arg(_serialNumber);
this->setInError(errortext);
retval = -1;
}
else
{
disableSmoothing();
{
// Everything is OK
_isDeviceReady = true;
_isOpen = true;
Info(_log, "Lightpack device successfully opened");
retval = 0;
}
}
}
return retval;
}
@@ -147,75 +174,64 @@ int LedDeviceLightpack::close()
{
int retval = 0;
_isDeviceReady = false;
_isOpen = false;
// LedDevice specific closing activities
if (_deviceHandle != nullptr)
if ( _deviceHandle != nullptr)
{
_isOpen = false;
libusb_release_interface(_deviceHandle, LIGHTPACK_INTERFACE);
libusb_attach_kernel_driver(_deviceHandle, LIGHTPACK_INTERFACE);
libusb_close(_deviceHandle);
closeDevice(_deviceHandle);
_deviceHandle = nullptr;
}
return retval;
}
int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requestedSerialNumber)
bool LedDeviceLightpack::searchDevice(libusb_device * device, const QString & requestedSerialNumber)
{
bool lightPackFound = false;
libusb_device_descriptor deviceDescriptor;
int error = libusb_get_device_descriptor(device, &deviceDescriptor);
if (error != LIBUSB_SUCCESS)
{
Error(_log, "Error while retrieving device descriptor(%d): %s", error, libusb_error_name(error));
return -1;
return false;
}
#define UNO_VENDOR_ID 0x2341
#define UNO_PRODUCT_ID 0x43
if ((deviceDescriptor.idVendor == USB_VENDOR_ID && deviceDescriptor.idProduct == USB_PRODUCT_ID) ||
(deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID))
(deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID))
{
Info(_log, "Found a Lightpack device. Retrieving more information...");
Debug(_log, "vendorIdentifier : %s", QSTRING_CSTR(QString("0x%1").arg(static_cast<ushort>(deviceDescriptor.idVendor),0,16)));
Debug(_log, "productIdentifier: %s", QSTRING_CSTR(QString("0x%1").arg(static_cast<ushort>(deviceDescriptor.idProduct),0,16)));
Debug(_log, "release_number : %s", QSTRING_CSTR(QString("0x%1").arg(static_cast<ushort>(deviceDescriptor.bcdDevice),0,16)));
Debug(_log, "manufacturer : %s", QSTRING_CSTR(getProperty(device, deviceDescriptor.iManufacturer)));
// get the hardware address
int busNumber = libusb_get_bus_number(device);
int addressNumber = libusb_get_device_address(device);
// get the serial number
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);
}
catch (int e)
{
Error(_log, "unable to retrieve serial number from Lightpack device(%d): %s", e, libusb_error_name(e));
serialNumber = "";
}
}
QString serialNumber = LedDeviceLightpack::getProperty(device, deviceDescriptor.iSerialNumber);
Debug(_log,"Lightpack device found: bus=%d address=%d serial=%s", busNumber, addressNumber, QSTRING_CSTR(serialNumber));
// check if this is the device we are looking for
if (requestedSerialNumber.isEmpty() || requestedSerialNumber == serialNumber)
{
// This is it!
// TODO: Check, if exceptions via try/catch need to be replaced in Qt environment
try
libusb_device_handle * deviceHandle;
if ( openDevice(device, &deviceHandle ) == 0 )
{
_deviceHandle = openDevice(device);
_serialNumber = serialNumber;
_busNumber = busNumber;
_addressNumber = addressNumber;
Info(_log, "Lightpack device successfully opened");
// get the firmware version
uint8_t buffer[256];
error = libusb_control_transfer(
_deviceHandle,
deviceHandle,
static_cast<uint8_t>( LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE),
0x01,
0x0100,
@@ -231,13 +247,12 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
_firmwareVersion.minorVersion = buffer[INDEX_FW_VER_MINOR];
}
#if 0
// FOR TESTING PURPOSE: FORCE MAJOR VERSION TO 6
_firmwareVersion.majorVersion = 6;
#endif
// disable smoothing of the chosen device
disableSmoothing();
// determine the number of leds
// determine the number of LEDs
if (_firmwareVersion.majorVersion == 4)
{
_hwLedCount = 8;
@@ -257,24 +272,20 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
{
_bitsPerChannel = 8;
}
closeDevice(deviceHandle);
// set the led buffer size (command + 6 bytes per led)
_ledBuffer = std::vector<uint8_t>(1 + _hwLedCount * 6, 0);
_ledBuffer[0] = CMD_UPDATE_LEDS;
Debug(_log, "Lightpack device found: bus=%d address=%d serial=%s version=%d.%d.", _busNumber, _addressNumber, QSTRING_CSTR(_serialNumber), _firmwareVersion.majorVersion, _firmwareVersion.minorVersion );
lightPackFound = true;
// return success
Debug(_log, "Lightpack device opened: bus=%d address=%d serial=%s version=%d.%d.", _busNumber, _addressNumber, QSTRING_CSTR(_serialNumber), _firmwareVersion.majorVersion, _firmwareVersion.minorVersion );
return 0;
}
catch(int e)
else
{
_deviceHandle = nullptr;
Warning(_log, "Unable to open Lightpack device. Searching for other device(%d): %s", e, libusb_error_name(e));
Warning(_log, "Unable to open Lightpack device. Searching for other device");
}
}
}
return -1;
return lightPackFound;
}
int LedDeviceLightpack::write(const std::vector<ColorRgb> &ledValues)
@@ -322,24 +333,23 @@ const QString &LedDeviceLightpack::getSerialNumber() const
int LedDeviceLightpack::writeBytes(uint8_t *data, int size)
{
// std::cout << "Writing " << size << " bytes: ";
// for (int i = 0; i < size ; ++i) printf("%02x ", data[i]);
// std::cout << std::endl;
int rc = 0;
//Debug( _log, "[%s]", QSTRING_CSTR(uint8_t_to_hex_string(data, size, 32)) );
int error = libusb_control_transfer(_deviceHandle,
static_cast<uint8_t>( LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE ),
0x09,
(2 << 8),
0x00,
data, size, 1000);
static_cast<uint8_t>( LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE ),
0x09,
(2 << 8),
0x00,
data, size, 1000);
if (error == size)
if (error != size)
{
return 0;
rc = -1;
Error(_log, "Unable to write %d bytes to Lightpack device(%d): %s", size, error, libusb_error_name(error));
}
Error(_log, "Unable to write %d bytes to Lightpack device(%d): %s", size, error, libusb_error_name(error));
return error;
return rc;
}
int LedDeviceLightpack::disableSmoothing()
@@ -354,15 +364,16 @@ int LedDeviceLightpack::disableSmoothing()
return rc;
}
libusb_device_handle * LedDeviceLightpack::openDevice(libusb_device *device)
int LedDeviceLightpack::openDevice(libusb_device *device, libusb_device_handle ** deviceHandle)
{
int rc = 0;
libusb_device_handle * handle = nullptr;
Logger * log = Logger::getInstance("LedDevice");
int error = libusb_open(device, &handle);
if (error != LIBUSB_SUCCESS)
{
Error(log, "unable to open device(%d): %s", error, libusb_error_name(error));
throw error;
Error(_log, "unable to open device(%d): %s", error, libusb_error_name(error));
rc = -1;
}
// detach kernel driver if it is active
@@ -371,42 +382,65 @@ libusb_device_handle * LedDeviceLightpack::openDevice(libusb_device *device)
error = libusb_detach_kernel_driver(handle, LIGHTPACK_INTERFACE);
if (error != LIBUSB_SUCCESS)
{
Error(log, "unable to detach kernel driver(%d): %s", error, libusb_error_name(error));
Error(_log, "unable to detach kernel driver(%d): %s", error, libusb_error_name(error));
libusb_close(handle);
throw error;
rc = -1;
}
}
error = libusb_claim_interface(handle, LIGHTPACK_INTERFACE);
if (error != LIBUSB_SUCCESS)
{
Error(log, "unable to claim interface(%d): %s", error, libusb_error_name(error));
Error(_log, "unable to claim interface(%d): %s", error, libusb_error_name(error));
libusb_attach_kernel_driver(handle, LIGHTPACK_INTERFACE);
libusb_close(handle);
throw error;
rc = -1;
}
return handle;
*deviceHandle = handle;
return rc;
}
QString LedDeviceLightpack::getString(libusb_device * device, int stringDescriptorIndex)
int LedDeviceLightpack::closeDevice(libusb_device_handle * deviceHandle)
{
libusb_device_handle * handle = nullptr;
int rc = 0;
int error = libusb_open(device, &handle);
int error = libusb_release_interface(deviceHandle, LIGHTPACK_INTERFACE);
if (error != LIBUSB_SUCCESS)
{
throw error;
Debug(_log, "Error while releasing interface (%d): %s", error, libusb_error_name(error));
rc = -1;
}
char buffer[256];
error = libusb_get_string_descriptor_ascii(handle, stringDescriptorIndex, reinterpret_cast<unsigned char *>(buffer), sizeof(buffer));
if (error <= 0)
error = libusb_attach_kernel_driver(deviceHandle, LIGHTPACK_INTERFACE);
if (error != LIBUSB_SUCCESS)
{
libusb_close(handle);
throw error;
Debug(_log, "Error while attaching kernel driver (%d): %s", error, libusb_error_name(error));
rc = -1;
}
libusb_close(handle);
return QString(QByteArray(buffer, error));
libusb_close(deviceHandle);
return rc;
}
QString LedDeviceLightpack::getProperty(libusb_device * device, int stringDescriptorIndex)
{
QString value;
if ( stringDescriptorIndex != 0 )
{
libusb_device_handle * handle = nullptr;
if ( libusb_open(device, &handle) == LIBUSB_SUCCESS )
{
char buffer[256];
int error = libusb_get_string_descriptor_ascii(handle, stringDescriptorIndex, reinterpret_cast<unsigned char *>(buffer), sizeof(buffer));
if (error > 0)
{
value = QString(QByteArray(buffer, error));
}
libusb_close(handle);
}
}
return value;
}

View File

@@ -105,11 +105,12 @@ protected:
private:
///
/// Test if the device is a (or the) lightpack we are looking for
/// Search for a LightPack Device (first one found or matching a given serial number)
///
/// @return Zero on succes else negative
/// @param[in] requestedSerialNumber serial number of Lightpack to be search
/// @return True on Lightpack found
///
int testAndOpen(libusb_device * device, const QString & requestedSerialNumber);
bool searchDevice(libusb_device * device, const QString & requestedSerialNumber);
/// write bytes to the device
int writeBytes(uint8_t *data, int size);
@@ -123,8 +124,11 @@ private:
int minorVersion;
};
static libusb_device_handle * openDevice(libusb_device * device);
static QString getString(libusb_device * device, int stringDescriptorIndex);
int openDevice(libusb_device *device, libusb_device_handle ** deviceHandle);
int closeDevice(libusb_device_handle * deviceHandle);
QString getProperty(libusb_device * device, int stringDescriptorIndex);
/// libusb context
libusb_context * _libusbContext;

View File

@@ -1,256 +0,0 @@
// stl includes
#include <exception>
#include <cstring>
#include <algorithm>
// Local Hyperion includes
#include "LedDeviceMultiLightpack.h"
// from USB_ID.h (http://code.google.com/p/light-pack/source/browse/CommonHeaders/USB_ID.h)
#define USB_OLD_VENDOR_ID 0x03EB
#define USB_OLD_PRODUCT_ID 0x204F
#define USB_VENDOR_ID 0x1D50
#define USB_PRODUCT_ID 0x6022
bool compareLightpacks(LedDeviceLightpack * lhs, LedDeviceLightpack * rhs)
{
return lhs->getSerialNumber() < rhs->getSerialNumber();
}
LedDeviceMultiLightpack::LedDeviceMultiLightpack(const QJsonObject &deviceConfig)
: LedDevice(deviceConfig)
, _lightpacks()
{
}
LedDeviceMultiLightpack::~LedDeviceMultiLightpack()
{
for (LedDeviceLightpack * device : _lightpacks)
{
delete device;
}
}
LedDevice* LedDeviceMultiLightpack::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceMultiLightpack(deviceConfig);
}
bool LedDeviceMultiLightpack::init(const QJsonObject &deviceConfig)
{
bool isInitOK = false;
// Initialise sub-class
if ( LedDevice::init(deviceConfig) )
{
// retrieve a list with Lightpack serials
QStringList serialList = getLightpackSerials();
// 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
for (auto serial : serialList)
{
QJsonObject devConfig;
devConfig["serial"] = serial;
devConfig["latchTime"] = deviceConfig["latchTime"];
devConfig["rewriteTime"] = deviceConfig["rewriteTime"];
LedDeviceLightpack * device = new LedDeviceLightpack(devConfig);
device->start();
if (device->open() == 0)
{
_lightpacks.push_back(device);
}
else
{
Error(_log, "Error while creating Lightpack device with serial %s", QSTRING_CSTR(serial));
delete device;
}
}
if (_lightpacks.empty())
{
//Warning(_log, "No Lightpack devices were found");
QString errortext = QString ("No Lightpack devices were found");
this->setInError(errortext);
isInitOK = false;
}
else
{
Info(_log, "%d Lightpack devices were found", _lightpacks.size());
isInitOK = true;
}
}
return isInitOK;
}
int LedDeviceMultiLightpack::open()
{
int retval = -1;
_isDeviceReady = false;
int lightsInError = 0;
// open each Lightpack device
for (LedDeviceLightpack * device : _lightpacks)
{
if (device->open() < 0)
{
Error( _log, "Failed to open [%s]", QSTRING_CSTR(device->getSerialNumber()) );
++lightsInError;
}
}
if ( lightsInError < static_cast<int>(_lightpacks.size()) )
{
// Everything is OK -> enable device
_isDeviceReady = true;
retval = 0;
}
else
{
this->setInError( "All Lightpacks failed to be opened!" );
}
return retval;
}
int LedDeviceMultiLightpack::close()
{
_isDeviceReady = false;
for (LedDeviceLightpack * device : _lightpacks)
{
device->close();
}
return 0;
}
int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
{
const ColorRgb * data = ledValues.data();
int size = ledValues.size();
for (LedDeviceLightpack * device : _lightpacks)
{
int count = qMin(static_cast<int>( device->getLedCount()), size);
if (count > 0)
{
if ( device->isOpen() )
{
device->write(data, count);
}
data += count;
size -= count;
}
else
{
Warning(_log, "Unable to write data to Lightpack device: no more led data available");
}
}
return 0;
}
bool LedDeviceMultiLightpack::powerOff()
{
for (LedDeviceLightpack * device : _lightpacks)
{
if ( device->isOpen() )
{
device->powerOff();
}
}
return true;
}
QStringList LedDeviceMultiLightpack::getLightpackSerials()
{
QStringList serialList;
Logger * log = Logger::getInstance("LedDevice");
Debug(log, "Getting list of Lightpack serials");
// initialize the USB context
libusb_context * libusbContext;
int error = libusb_init(&libusbContext);
if (error != LIBUSB_SUCCESS)
{
Error(log,"Error while initializing USB context(%d): %s", error, libusb_error_name(error));
libusbContext = nullptr;
return serialList;
}
//libusb_set_debug(_libusbContext, 3);
Info(log, "USB context initialized in multi Lightpack device");
// 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)
{
libusb_device_descriptor deviceDescriptor;
error = libusb_get_device_descriptor(deviceList[i], &deviceDescriptor);
if (error != LIBUSB_SUCCESS)
{
Error(log, "Error while retrieving device descriptor(%d): %s", error, libusb_error_name(error));
continue;
}
if ((deviceDescriptor.idVendor == USB_VENDOR_ID && deviceDescriptor.idProduct == USB_PRODUCT_ID) ||
(deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID))
{
Info(log, "Found a Lightpack device. Retrieving serial...");
// get the serial number
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);
}
catch (int e)
{
Error(log,"Unable to retrieve serial number(%d): %s", e, libusb_error_name(e));
continue;
}
}
Info(log, "Lightpack device found with serial %s", QSTRING_CSTR(serialNumber));
serialList.append(serialNumber);
}
}
// free the device list
libusb_free_device_list(deviceList, 1);
libusb_exit(libusbContext);
return serialList;
}
QString LedDeviceMultiLightpack::getString(libusb_device * device, int stringDescriptorIndex)
{
libusb_device_handle * handle = nullptr;
int error = libusb_open(device, &handle);
if (error != LIBUSB_SUCCESS)
{
throw error;
}
char buffer[256];
error = libusb_get_string_descriptor_ascii(handle, stringDescriptorIndex, reinterpret_cast<unsigned char *>(buffer), sizeof(buffer));
if (error <= 0)
{
libusb_close(handle);
throw error;
}
libusb_close(handle);
return QString(QByteArray(buffer, error));
}

View File

@@ -1,92 +0,0 @@
#ifndef LEDEVICEMULTILIGHTPACK_H
#define LEDEVICEMULTILIGHTPACK_H
// stl includes
#include <vector>
#include <cstdint>
#include <QStringList>
#include <QString>
// libusb include
#include <libusb.h>
// Hyperion includes
#include <leddevice/LedDevice.h>
#include "LedDeviceLightpack.h"
///
/// LedDevice implementation for multiple lightpack devices
///
class LedDeviceMultiLightpack : public LedDevice
{
public:
///
/// @brief Constructs a LedDevice of multiple Lightpack LED-devices
///
/// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceMultiLightpack(const QJsonObject &deviceConfig);
///
/// @brief Destructor of the LedDevice
///
~LedDeviceMultiLightpack() override;
///
/// @brief Constructs the LED-device
///
/// @param[in] deviceConfig Device's configuration as JSON-Object
/// @return LedDevice constructed
///
static LedDevice* construct(const QJsonObject &deviceConfig);
protected:
///
/// @brief Initialise the device's configuration
///
/// @param[in] deviceConfig the JSON device configuration
/// @return True, if success
///
bool init(const QJsonObject &deviceConfig) override;
///
/// @brief Opens the output device.
///
/// @return Zero on success (i.e. device is ready), else negative
///
int open() override;
///
/// @brief Closes the output device.
///
/// @return Zero on success (i.e. device is closed), else negative
///
int close() override;
///
/// @brief Power-/turn off the Nanoleaf device.
///
/// @return True if success
///
bool powerOff() override;
///
/// @brief Writes the RGB-Color values to the LEDs.
///
/// @param[in] ledValues The RGB-color per LED
/// @return Zero on success, else negative
///
int write(const std::vector<ColorRgb> & ledValues) override;
private:
static QStringList getLightpackSerials();
static QString getString(libusb_device * device, int stringDescriptorIndex);
/// buffer for led data
std::vector<LedDeviceLightpack *> _lightpacks;
};
#endif // LEDEVICEMULTILIGHTPACK_H

View File

@@ -92,7 +92,7 @@ protected:
///
/// @brief Power-/turn on the WLED device.
///
/// @brief Store the device's original state.
/// @return True if success
///
bool powerOn() override;

View File

@@ -38,10 +38,7 @@ ProviderRestApi::ProviderRestApi()
ProviderRestApi::~ProviderRestApi()
{
if (_networkManager != nullptr)
{
delete _networkManager;
}
delete _networkManager;
}
void ProviderRestApi::setUrl(const QUrl& url)

View File

@@ -18,10 +18,10 @@ bool LedDeviceKarate::init(const QJsonObject &deviceConfig)
// Initialise sub-class
if ( ProviderRs232::init(deviceConfig) )
{
if (_ledCount != 16)
if (_ledCount != 8 && _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);
QString errortext = QString ("%1 channels configured. This should always be 8 or 16!").arg(_ledCount);
this->setInError(errortext);
isInitOK = false;
}

View File

@@ -1,26 +0,0 @@
{
"type":"object",
"required":true,
"properties":{
"latchTime": {
"type": "integer",
"title":"edt_dev_spec_latchtime_title",
"default": 11,
"append" : "edt_append_ms",
"minimum": 0,
"maximum": 1000,
"access" : "expert",
"propertyOrder" : 1
},
"rewriteTime": {
"type": "integer",
"title":"edt_dev_general_rewriteTime_title",
"default": 1000,
"append" : "edt_append_ms",
"minimum": 0,
"access" : "expert",
"propertyOrder" : 2
}
},
"additionalProperties": true
}

View File

@@ -27,6 +27,12 @@ static const QString SSDP_DESCRIPTION = "<?xml version=\"1.0\"?>"
"<modelURL>https://www.hyperion-project.org</modelURL>"
"<serialNumber>%4</serialNumber>"
"<UDN>uuid:%4</UDN>"
"<ports>"
"<jsonServer>%5</jsonServer>"
"<sslServer>%6</sslServer>"
"<protoBuffer>%7</protoBuffer>"
"<flatBuffer>%8</flatBuffer>"
"</ports>"
"<presentationURL>index.html</presentationURL>"
"<iconList>"
"<icon>"

View File

@@ -15,14 +15,16 @@
static const QString SSDP_HYPERION_ST("urn:hyperion-project.org:device:basic:1");
SSDPHandler::SSDPHandler(WebServer* webserver, quint16 flatBufPort, quint16 jsonServerPort, const QString& name, QObject * parent)
SSDPHandler::SSDPHandler(WebServer* webserver, quint16 flatBufPort, quint16 protoBufPort, quint16 jsonServerPort, quint16 sslPort, const QString& name, QObject * parent)
: SSDPServer(parent)
, _webserver(webserver)
, _localAddress()
, _NCA(nullptr)
{
setFlatBufPort(flatBufPort);
setProtoBufPort(protoBufPort);
setJsonServerPort(jsonServerPort);
setSSLServerPort(sslPort);
setHyperionName(name);
}
@@ -85,6 +87,14 @@ void SSDPHandler::handleSettingsUpdate(settings::type type, const QJsonDocument&
}
}
if(type == settings::PROTOSERVER)
{
if(obj["port"].toInt() != SSDPServer::getProtoBufPort())
{
SSDPServer::setProtoBufPort(obj["port"].toInt());
}
}
if(type == settings::JSONSERVER)
{
if(obj["port"].toInt() != SSDPServer::getJsonServerPort())
@@ -93,6 +103,14 @@ void SSDPHandler::handleSettingsUpdate(settings::type type, const QJsonDocument&
}
}
if(type == settings::WEBSERVER)
{
if(obj["sslPort"].toInt() != SSDPServer::getSSLServerPort())
{
SSDPServer::setSSLServerPort(obj["sslPort"].toInt());
}
}
if (type == settings::GENERAL)
{
if (obj["name"].toString() != SSDPServer::getHyperionName())
@@ -199,7 +217,21 @@ QString SSDPHandler::buildDesc() const
/// %2 friendly name Hyperion 2.0.0 (192.168.0.177)
/// %3 modelNumber 2.0.0
/// %4 serialNumber / UDN (H ID) Fjsa723dD0....
return SSDP_DESCRIPTION.arg(getBaseAddress(), QString("Hyperion (%1)").arg(_localAddress), QString(HYPERION_VERSION), _uuid);
/// %5 json port 19444
/// %6 ssl server port 8092
/// %7 protobuf port 19445
/// %8 flatbuf port 19400
return SSDP_DESCRIPTION.arg(
getBaseAddress(),
QString("Hyperion (%1)").arg(_localAddress),
QString(HYPERION_VERSION),
_uuid,
QString::number(SSDPServer::getJsonServerPort()),
QString::number(SSDPServer::getSSLServerPort()),
QString::number(SSDPServer::getProtoBufPort()),
QString::number(SSDPServer::getFlatBufPort())
);
}
void SSDPHandler::sendAnnounceList(bool alive)

View File

@@ -153,7 +153,7 @@ void QtHttpClientWrapper::onClientDataReceived (void)
case RequestParsed: // a valid request has ben fully parsed
{
// Catch websocket header "Upgrade"
if(m_currentRequest->getHeader(QtHttpHeader::Upgrade) == "websocket")
if(m_currentRequest->getHeader(QtHttpHeader::Upgrade).toLower() == "websocket")
{
if(m_websocketClient == Q_NULLPTR)
{