mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
Merge branch 'master' into Razer_Chroma_Support
This commit is contained in:
@@ -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()
|
||||
{
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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];
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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());
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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));
|
||||
}
|
@@ -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
|
@@ -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;
|
||||
|
||||
|
@@ -38,10 +38,7 @@ ProviderRestApi::ProviderRestApi()
|
||||
|
||||
ProviderRestApi::~ProviderRestApi()
|
||||
{
|
||||
if (_networkManager != nullptr)
|
||||
{
|
||||
delete _networkManager;
|
||||
}
|
||||
delete _networkManager;
|
||||
}
|
||||
|
||||
void ProviderRestApi::setUrl(const QUrl& url)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
@@ -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>"
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user