Merge branch 'master' into Razer_Chroma_Support

This commit is contained in:
LordGrey 2020-10-19 22:08:18 +02:00 committed by GitHub
commit 384c861f13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 1698 additions and 1782 deletions

View File

@ -149,8 +149,10 @@ jobs:
with:
python-version: '3.x'
- name: Install NSIS
run: choco install --no-progress nsis -y
- name: Install NSIS & copy plugins
run: |
choco install --no-progress nsis -y
copy "cmake\nsis\template\*.dll" "C:\Program Files (x86)\NSIS\Plugins\x86-ansi\"
- name: Install OpenSSL
run: choco install --no-progress openssl -y
@ -171,7 +173,7 @@ jobs:
shell: bash
run: |
mkdir -p windows
mv build/*.zip windows
mv build/*.exe windows
# Upload artifacts
- name: Upload artifacts

View File

@ -113,8 +113,10 @@ jobs:
with:
python-version: '3.x'
- name: Install NSIS
run: choco install --no-progress nsis -y
- name: Install NSIS & copy plugins
run: |
choco install --no-progress nsis -y
copy "cmake\nsis\template\*.dll" "C:\Program Files (x86)\NSIS\Plugins\x86-ansi\"
- name: Install OpenSSL
run: choco install --no-progress openssl -y

3
.gitignore vendored
View File

@ -22,3 +22,6 @@ compile_commands.json
# Autogenerated by flatbuffers
libsrc/flatbufserver/hyperion_reply_generated.h
libsrc/flatbufserver/hyperion_request_generated.h
# Kdevelop project files
*.kdev*

View File

@ -13,9 +13,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
### Fixed
- Also allow an 8-LED configuration when using Karatelight
- Fix Lightpack issue (#1015)
- Fix color calibration for Kodi 18 (Fixes #771)
### Removed
- Replace Multi-Lightpack by multi-instance Lightpack configuration
## [2.0.0-alpha.8](https://github.com/hyperion-project/hyperion.ng/releases/tag/2.0.0-alpha.8) - 2020-09-14
### Added
- Add XCB grabber, a faster and safer alternative for X11 grabbing (#912)

View File

@ -863,13 +863,13 @@
"wiz_cc_btn_stop": "Stop video",
"wiz_cc_btn_switchpic": "Switch picture",
"wiz_cc_chooseid": "Define a name for this color profile.",
"wiz_cc_intro1": "This wizard will guide you through your led calibration. If you are using Kodi, the calibration pictures and videos can be sent directly to it without further actions on your side. If not, you will need to download these files yourself and display them when the wizard needs you to adjust the setting.",
"wiz_cc_kodicon": "Kodi webserver found, proceed with Kodi support.",
"wiz_cc_kodidiscon": "Kodi webserver not found, proceed without Kodi support.",
"wiz_cc_intro1": "This wizard will guide you through your led calibration. If you are using Kodi, the calibration pictures and videos can be sent directly to it. Prerequisite: You need to enable \"Allow remote control from applications on other systems\" in Kodi.<br />Alternatively, you might want downloading these files yourself and display them when the wizard asks you to adjust the setting.",
"wiz_cc_kodicon": "Kodi found, proceed with Kodi support.",
"wiz_cc_kodidiscon": "Kodi not found, proceed without Kodi support.",
"wiz_cc_kodidisconlink": "Download link pictures:",
"wiz_cc_kodimsg_start": "Test success - time to proceed!",
"wiz_cc_kodishould": "Kodi should show the following picture: $1",
"wiz_cc_kwebs": "Kodi webserver (IP:Port)",
"wiz_cc_kwebs": "Kodi webserver (Hostname or IP)",
"wiz_cc_lettvshow": "Let your TV show the following picture: $1",
"wiz_cc_lettvshowm": "Check this with the following pictures: $1",
"wiz_cc_link": "Click me!",

View File

@ -571,6 +571,7 @@ $(document).ready(function() {
var devRPiSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'sk9822', 'ws2812spi'];
var devRPiPWM = ['ws281x'];
var devRPiGPIO = ['piblaster'];
var devNET = ['atmoorb', 'fadecandy', 'philipshue', 'nanoleaf', 'razer', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udph801', 'udpraw', 'wled', 'yeelight'];
var devUSB = ['adalight', 'dmx', 'atmo', 'hyperionusbasp', 'lightpack', 'paintpack', 'rawhid', 'sedu', 'tpm2', 'karate'];

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -384,7 +384,7 @@ Function un.RemoveFromPath
FunctionEnd
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Uninstall sutff
; Uninstall stuff
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
###########################################
@ -810,6 +810,15 @@ FunctionEnd
;--------------------------------
; determine admin versus local install
Function un.onInit
; Check if Hyperion is running
loopIsRunningCheck:
FindProcDLL::FindProc "hyperiond.exe"
IntCmp $R0 1 0 notRunning
MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "Hyperion is running.$\n$\nClose it and press Retry, or press Cancel to exit." IDRETRY loopIsRunningCheck IDCANCEL abortnow
abortnow:
Abort
notRunning:
ClearErrors
UserInfo::GetName
@ -873,6 +882,16 @@ FunctionEnd
;Uninstaller Section
Section "Uninstall"
; Check if Hyperion is running
loopIsRunningCheck:
FindProcDLL::FindProc "hyperiond.exe"
IntCmp $R0 1 0 notRunning
MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "Hyperion is running.$\n$\nClose it and press Retry, or press Cancel to exit." IDRETRY loopIsRunningCheck IDCANCEL abortnow
abortnow:
Abort
notRunning:
ReadRegStr $START_MENU SHCTX \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu"
;MessageBox MB_OK "Start menu is in: $START_MENU"
@ -970,6 +989,16 @@ SectionEnd
; "Program Files" for AllUsers, "My Documents" for JustMe...
Function .onInit
; Check if Hyperion is running
loopIsRunningCheck:
FindProcDLL::FindProc "hyperiond.exe"
IntCmp $R0 1 0 notRunning
MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "Hyperion is running.$\n$\nClose it and press Retry, or press Cancel to exit." IDRETRY loopIsRunningCheck IDCANCEL abortnow
abortnow:
Abort
notRunning:
StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst
ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString"

View File

@ -112,8 +112,9 @@ protected:
/// @param dat The effect data
/// @param callerComp The HYPERION COMPONENT that calls this function! e.g. PROT/FLATBUF
/// REQUIRED dat fields: effectName, priority, duration, origin
/// @return True on success else false
///
void setEffect(const EffectCmdData &dat, hyperion::Components callerComp = hyperion::COMP_INVALID);
bool setEffect(const EffectCmdData &dat, hyperion::Components callerComp = hyperion::COMP_INVALID);
///
/// @brief Set source auto select enabled or disabled
@ -174,8 +175,10 @@ protected:
///
/// @brief Start instance
/// @param index The instance index
/// @param tan The tan
/// @return True on success else false
///
void startInstance(quint8 index);
bool startInstance(quint8 index, int tan = 0);
///
/// @brief Stop instance
@ -277,8 +280,9 @@ protected:
/// @brief Set a new token request
/// @param comment The comment
/// @param id The id
/// @param tan The tan
///
void setNewTokenRequest(const QString &comment, const QString &id);
void setNewTokenRequest(const QString &comment, const QString &id, const int &tan);
///
/// @brief Cancel new token request
@ -367,7 +371,7 @@ signals:
///
/// @brief Emits whenever a new Token request is pending. This signal is just active when ADMIN ACCESS has been granted
/// @param id The id of the request
/// @param id The id of the request
/// @param comment The comment of the request; If the commen is EMPTY the request has been revoked by the caller. So remove it from the pending list
///
void onPendingTokenRequest(const QString &id, const QString &comment);
@ -378,8 +382,15 @@ signals:
/// @param token The new token that is now valid
/// @param comment The comment that was part of the request
/// @param id The id that was part of the request
/// @param tan The tan that was part of the request
///
void onTokenResponse(bool success, const QString &token, const QString &comment, const QString &id);
void onTokenResponse(bool success, const QString &token, const QString &comment, const QString &id, const int &tan);
///
/// @brief Handle emits from HyperionIManager of startInstance request, just if QObject matches with this instance it will emit.
/// @param tan The tan that was part of the request
///
void onStartInstanceResponse(const int &tan);
private slots:
///
@ -388,16 +399,6 @@ private slots:
///
void requestActiveRegister(QObject *callerInstance);
///
/// @brief See onTokenResponse(). Here we validate the caller instance and on success we will emit onTokenResponse()
/// @param success If true the request was accepted else false and no token was created
/// @param caller The origin caller instance who requested this token
/// @param token The new token that is now valid
/// @param comment The comment that was part of the request
/// @param id The id that was part of the request
///
void checkTokenResponse(bool success, QObject *caller, const QString &token, const QString &comment, const QString &id);
private:
void stopDataConnectionss();

View File

@ -65,8 +65,8 @@ public slots:
private slots:
///
/// @brief Handle emits from API of a new Token request.
/// @param id The id of the request
/// @param The comment which needs to be accepted
/// @param id The id of the request
/// @param comment The comment which needs to be accepted
///
void newPendingTokenRequest(const QString &id, const QString &comment);
@ -76,8 +76,9 @@ private slots:
/// @param token The new token that is now valid
/// @param comment The comment that was part of the request
/// @param id The id that was part of the request
/// @param tan The tan that was part of the request
///
void handleTokenResponse(bool success, const QString &token, const QString &comment, const QString &id);
void handleTokenResponse(bool success, const QString &token, const QString &comment, const QString &id, const int &tan);
///
/// @brief Handle whenever the state of a instance (HyperionIManager) changes according to enum instanceState

View File

@ -29,6 +29,7 @@ public:
QString id;
QString comment;
QObject *caller;
int tan;
uint64_t timeoutTime;
QString token;
QString lastUse;
@ -142,16 +143,16 @@ public slots:
/// @param caller The QObject of the caller to deliver the reply
/// @param comment The comment as ident helper
/// @param id The id created by the caller
/// @param tan The tan created by the caller
///
void setNewTokenRequest(QObject *caller, const QString &comment, const QString &id);
void setNewTokenRequest(QObject *caller, const QString &comment, const QString &id, const int &tan = 0);
///
/// @brief Cancel a pending token request with the provided comment and id as identifier helper
/// @param caller The QObject of the caller to deliver the reply
/// @param comment The comment as ident helper
/// @param id The id created by the caller
///
void cancelNewTokenRequest(QObject *caller, const QString &comment, const QString &id);
void cancelNewTokenRequest(QObject *caller, const QString &, const QString &id);
///
/// @brief Handle a token request by id, generate token and inform token caller or deny
@ -200,8 +201,9 @@ signals:
/// @param token The new token that is now valid
/// @param comment The comment that was part of the request
/// @param id The id that was part of the request
/// @param tan The tan that was part of the request
///
void tokenResponse(bool success, QObject *caller, const QString &token, const QString &comment, const QString &id);
void tokenResponse(bool success, QObject *caller, const QString &token, const QString &comment, const QString &id, const int &tan);
///
/// @brief Emits whenever the token list changes

View File

@ -474,7 +474,7 @@ private slots:
void handleNewVideoMode(VideoMode mode) { _currVideoMode = mode; }
void handlPriorityChangedLedDevice(const quint8& priority);
void handlePriorityChangedLedDevice(const quint8& priority);
private:
friend class HyperionDaemon;

View File

@ -28,6 +28,12 @@ class HyperionIManager : public QObject
Q_OBJECT
public:
struct PendingRequests
{
QObject *caller;
int tan;
};
// global instance pointer
static HyperionIManager* getInstance() { return HIMinstance; }
static HyperionIManager* HIMinstance;
@ -54,11 +60,11 @@ public slots:
///
/// @brief Start a Hyperion instance
/// @param instance Instance index
/// @param block If true return when thread has been started
/// @param instance Instance index
/// @param block If true return when thread has been started
/// @return Return true on success, false if not found in db
///
bool startInstance(quint8 inst, bool block = false);
bool startInstance(quint8 inst, bool block = false, QObject *caller = nullptr, int tan = 0);
///
/// @brief Stop a Hyperion instance
@ -110,6 +116,13 @@ signals:
///
void change();
///
/// @brief Emits when the user has requested to start a instance
/// @param caller The origin caller instance who requested
/// @param tan The tan that was part of the request
///
void startInstanceResponse(QObject *caller, const int &tan);
signals:
///////////////////////////////////////
/// FROM HYPERIONDAEMON TO HYPERION ///
@ -180,4 +193,6 @@ private:
const QString _rootPath;
QMap<quint8, Hyperion*> _runningInstances;
QList<quint8> _startQueue;
/// All pending requests
QMap<quint8, PendingRequests> _pendingRequests;
};

View File

@ -20,7 +20,7 @@ class SSDPHandler : public SSDPServer
{
Q_OBJECT
public:
SSDPHandler(WebServer* webserver, quint16 flatBufPort, quint16 jsonServerPort, const QString &name, QObject * parent = nullptr);
SSDPHandler(WebServer* webserver, quint16 flatBufPort, quint16 protoBufPort, quint16 jsonServerPort, quint16 sslPort, const QString &name, QObject * parent = nullptr);
~SSDPHandler() override;
///

View File

@ -85,16 +85,36 @@ public:
quint16 getFlatBufPort() const { return _fbsPort.toInt(); };
///
/// @brief set new jsonserver server port
/// @brief set new protobuf server port
///
void setProtoBufPort(quint16 port) { _pbsPort = QString::number(port); };
///
/// @brief Get current protobuf server port
///
quint16 getProtoBufPort() const { return _pbsPort.toInt(); };
///
/// @brief set new json server port
///
void setJsonServerPort(quint16 port) { _jssPort = QString::number(port); };
///
/// @brief get new jsonserver server port
/// @brief get new json server port
///
quint16 getJsonServerPort() const { return _jssPort.toInt(); };
///
///
/// @brief set new ssl server port
///
void setSSLServerPort(quint16 port) { _sslPort = QString::number(port); };
///
/// @brief get new ssl server port
///
quint16 getSSLServerPort() const { return _sslPort.toInt(); };
///
/// @brief set new hyperion name
///
void setHyperionName(const QString &name) { _name = name; };
@ -119,13 +139,15 @@ private:
Logger* _log;
QUdpSocket* _udpSocket;
QString _serverHeader;
QString _uuid;
QString _fbsPort;
QString _jssPort;
QString _name;
QString _descAddress;
bool _running;
QString _serverHeader,
_uuid,
_fbsPort,
_pbsPort,
_jssPort,
_sslPort,
_name,
_descAddress;
bool _running;
private slots:
void readPendingDatagrams();

View File

@ -3,6 +3,8 @@
#include <QString>
#include <QStringList>
#include <QStringRef>
#include <QVector>
namespace QStringUtils {
@ -13,11 +15,11 @@ enum class SplitBehavior {
inline QStringList split (const QString &string, const QString &sep, SplitBehavior behavior = SplitBehavior::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
return behavior == SplitBehavior::SkipEmptyParts ? string.split(sep, Qt::SkipEmptyParts , cs) : string.split(sep, Qt::KeepEmptyParts , cs);
#else
#else
return behavior == SplitBehavior::SkipEmptyParts ? string.split(sep, QString::SkipEmptyParts , cs) : string.split(sep, QString::KeepEmptyParts , cs);
#endif
#endif
}
inline QStringList split (const QString &string, QChar sep, SplitBehavior behavior = SplitBehavior::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive)
@ -37,6 +39,34 @@ inline QStringList split (const QString &string, const QRegExp &rx, SplitBehavio
return behavior == SplitBehavior::SkipEmptyParts ? string.split(rx, QString::SkipEmptyParts) : string.split(rx, QString::KeepEmptyParts);
#endif
}
inline QVector<QStringRef> splitRef(const QString &string, const QString &sep, SplitBehavior behavior = SplitBehavior::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
return string.splitRef(sep, behavior == SplitBehavior::SkipEmptyParts ? Qt::SkipEmptyParts : Qt::KeepEmptyParts , cs);
#else
return string.splitRef(sep, behavior == SplitBehavior::SkipEmptyParts ? QString::SkipEmptyParts : QString::KeepEmptyParts, cs);
#endif
}
inline QVector<QStringRef> splitRef(const QString &string, QChar sep, SplitBehavior behavior = SplitBehavior::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
return string.splitRef(sep, behavior == SplitBehavior::SkipEmptyParts ? Qt::SkipEmptyParts : Qt::KeepEmptyParts, cs);
#else
return string.splitRef(sep, behavior == SplitBehavior::SkipEmptyParts ? QString::SkipEmptyParts : QString::KeepEmptyParts, cs);
#endif
}
inline QVector<QStringRef> splitRef(const QString &string, const QRegExp &rx, SplitBehavior behavior = SplitBehavior::KeepEmptyParts)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
return string.splitRef(rx,behavior == SplitBehavior::SkipEmptyParts ? Qt::SkipEmptyParts : Qt::KeepEmptyParts);
#else
return string.splitRef(rx, behavior == SplitBehavior::SkipEmptyParts ? QString::SkipEmptyParts : QString::KeepEmptyParts);
#endif
}
}
#endif // QSTRINGUTILS_H

View File

@ -234,12 +234,6 @@ namespace hyperion {
midPointsY.erase(std::unique(midPointsY.begin(), midPointsY.end()), midPointsY.end());
QSize gridSize( midPointsX.size(), midPointsY.size() );
//Debug(_log, "LED layout grid size: %dx%d", gridSize.width(), gridSize.height());
// Limit to 80px for performance reasons
const int pl = 80;
if(gridSize.width() > pl || gridSize.height() > pl)
gridSize.scale(pl, pl, Qt::KeepAspectRatio);
// Correct the grid in case it is malformed in width vs height
// Expected is at least 50% of width <-> height
@ -248,6 +242,13 @@ namespace hyperion {
else if((gridSize.width() / gridSize.height()) < 0.5)
gridSize.setWidth(qMax(1,gridSize.height()/2));
// Limit to 80px for performance reasons
const int pl = 80;
if(gridSize.width() > pl || gridSize.height() > pl)
{
gridSize.scale(pl, pl, Qt::KeepAspectRatio);
}
return gridSize;
}
};

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)
{

View File

@ -34,7 +34,7 @@ int main(int argc, char ** argv)
// create the option parser and initialize all parameters
Parser parser("OSX capture application for Hyperion. Will automatically search a Hyperion server if -a option isn't used. Please note that if you have more than one server running it's more or less random which one will be used.");
Option & argDisplay = parser.add<Option> ('d', "display", "Set the display to capture [default: %1]", "0");
IntOption & argDisplay = parser.add<IntOption> ('d', "display", "Set the display to capture [default: %1]", "0");
IntOption & argFps = parser.add<IntOption> ('f', "framerate", "Capture frame rate [default: %1]", "10", 1, 25);
IntOption & argWidth = parser.add<IntOption> (0x0, "width", "Width of the captured image [default: %1]", "160", 160);
IntOption & argHeight = parser.add<IntOption> (0x0, "height", "Height of the captured image [default: %1]", "160", 160);
@ -54,7 +54,7 @@ int main(int argc, char ** argv)
}
OsxWrapper osxWrapper
(parser.isSet(argDisplay), argWidth.getInt(parser), argHeight.getInt(parser), 1000 / argFps.getInt(parser));
(argDisplay.getInt(parser), argWidth.getInt(parser), argHeight.getInt(parser), 1000 / argFps.getInt(parser));
if (parser.isSet(argScreenshot))
{

View File

@ -34,7 +34,7 @@ int main(int argc, char ** argv)
// create the option parser and initialize all parameters
Parser parser("Qt interface capture application for Hyperion");
Option & argDisplay = parser.add<Option> ('d', "display", "Set the display to capture [default: %1]","0");
IntOption & argDisplay = parser.add<IntOption> ('d', "display", "Set the display to capture [default: %1]", "0");
IntOption & argFps = parser.add<IntOption> ('f', "framerate", "Capture frame rate [default: %1]", "10", 1, 25);
IntOption & argCropLeft = parser.add<IntOption> (0x0, "crop-left", "Number of pixels to crop from the left of the picture before decimation (overrides --crop-width)");
IntOption & argCropRight = parser.add<IntOption> (0x0, "crop-right", "Number of pixels to crop from the right of the picture before decimation (overrides --crop-width)");
@ -63,7 +63,7 @@ int main(int argc, char ** argv)
argCropTop.getInt(parser),
argCropBottom.getInt(parser),
argSizeDecimation.getInt(parser),
parser.isSet(argDisplay));
argDisplay.getInt(parser));
if (parser.isSet(argScreenshot))
{

View File

@ -14,21 +14,5 @@ void CreateConsole()
freopen_s(&fDummy, "CONOUT$", "w", stdout);
freopen_s(&fDummy, "CONOUT$", "w", stderr);
freopen_s(&fDummy, "CONIN$", "r", stdin);
//std::cout.clear();
//std::clog.clear();
//std::cerr.clear();
//std::cin.clear();
/*// std::wcout, std::wclog, std::wcerr, std::wcin
HANDLE hConOut = CreateFile(_T("CONOUT$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
HANDLE hConIn = CreateFile(_T("CONIN$"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
SetStdHandle(STD_OUTPUT_HANDLE, hConOut);
SetStdHandle(STD_ERROR_HANDLE, hConOut);
SetStdHandle(STD_INPUT_HANDLE, hConIn);
std::wcout.clear();
std::wclog.clear();
std::wcerr.clear();
std::wcin.clear();
*/
SetConsoleTitle(TEXT("Hyperion"));
}

View File

@ -302,7 +302,12 @@ void HyperionDaemon::startNetworkServices()
sslWsThread->start();
// Create SSDP server in thread
_ssdp = new SSDPHandler(_webserver, getSetting(settings::FLATBUFSERVER).object()["port"].toInt(), getSetting(settings::JSONSERVER).object()["port"].toInt(), getSetting(settings::GENERAL).object()["name"].toString());
_ssdp = new SSDPHandler(_webserver,
getSetting(settings::FLATBUFSERVER).object()["port"].toInt(),
getSetting(settings::PROTOSERVER).object()["port"].toInt(),
getSetting(settings::JSONSERVER).object()["port"].toInt(),
getSetting(settings::WEBSERVER).object()["sslPort"].toInt(),
getSetting(settings::GENERAL).object()["name"].toString());
QThread *ssdpThread = new QThread(this);
ssdpThread->setObjectName("SSDPThread");
_ssdp->moveToThread(ssdpThread);