mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
BoblightServer added
Former-commit-id: deb3479ee673d763ad2e5451fcd35a0febedb4f3
This commit is contained in:
parent
85c8ba0100
commit
7300413015
57
include/boblightserver/BoblightServer.h
Normal file
57
include/boblightserver/BoblightServer.h
Normal file
@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
// system includes
|
||||
#include <cstdint>
|
||||
|
||||
// Qt includes
|
||||
#include <QTcpServer>
|
||||
#include <QSet>
|
||||
|
||||
// Hyperion includes
|
||||
#include <hyperion/Hyperion.h>
|
||||
|
||||
class BoblightClientConnection;
|
||||
|
||||
///
|
||||
/// This class creates a TCP server which accepts connections from boblight clients.
|
||||
///
|
||||
class BoblightServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
///
|
||||
/// BoblightServer constructor
|
||||
/// @param hyperion Hyperion instance
|
||||
/// @param port port number on which to start listening for connections
|
||||
///
|
||||
BoblightServer(Hyperion * hyperion, uint16_t port = 19333);
|
||||
~BoblightServer();
|
||||
|
||||
///
|
||||
/// @return the port number on which this TCP listens for incoming connections
|
||||
///
|
||||
uint16_t getPort() const;
|
||||
|
||||
private slots:
|
||||
///
|
||||
/// Slot which is called when a client tries to create a new connection
|
||||
///
|
||||
void newConnection();
|
||||
|
||||
///
|
||||
/// Slot which is called when a client closes a connection
|
||||
/// @param connection The Connection object which is being closed
|
||||
///
|
||||
void closedConnection(BoblightClientConnection * connection);
|
||||
|
||||
private:
|
||||
/// Hyperion instance
|
||||
Hyperion * _hyperion;
|
||||
|
||||
/// The TCP server object
|
||||
QTcpServer _server;
|
||||
|
||||
/// List with open connections
|
||||
QSet<BoblightClientConnection *> _openConnections;
|
||||
};
|
@ -52,6 +52,17 @@ public:
|
||||
///
|
||||
void process(const RgbImage& image, std::vector<RgbColor>& ledColors);
|
||||
|
||||
///
|
||||
/// Get the hscan and vscan parameters for a single led
|
||||
///
|
||||
/// @param[in] led Index of the led
|
||||
/// @param[out] hscanBegin begin of the hscan
|
||||
/// @param[out] hscanEnd end of the hscan
|
||||
/// @param[out] vscanBegin begin of the hscan
|
||||
/// @param[out] vscanEnd end of the hscan
|
||||
/// @return true if the parameters could be retrieved
|
||||
bool getScanParameters(size_t led, double & hscanBegin, double & hscanEnd, double & vscanBegin, double & vscanEnd) const;
|
||||
|
||||
private:
|
||||
/// Friend declaration of the factory for creating ImageProcessor's
|
||||
friend class ImageProcessorFactory;
|
||||
|
@ -8,5 +8,6 @@ add_subdirectory(dispmanx-grabber)
|
||||
add_subdirectory(hyperion)
|
||||
add_subdirectory(jsonserver)
|
||||
add_subdirectory(protoserver)
|
||||
add_subdirectory(boblightserver)
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory(xbmcvideochecker)
|
||||
|
217
libsrc/boblightserver/BoblightClientConnection.cpp
Normal file
217
libsrc/boblightserver/BoblightClientConnection.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
// system includes
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include <iomanip>
|
||||
#include <cstdio>
|
||||
|
||||
// stl includes
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
|
||||
// Qt includes
|
||||
#include <QResource>
|
||||
#include <QDateTime>
|
||||
|
||||
// hyperion util includes
|
||||
#include "hyperion/ImageProcessorFactory.h"
|
||||
#include "hyperion/ImageProcessor.h"
|
||||
#include "utils/RgbColor.h"
|
||||
|
||||
// project includes
|
||||
#include "BoblightClientConnection.h"
|
||||
|
||||
BoblightClientConnection::BoblightClientConnection(QTcpSocket *socket, Hyperion * hyperion) :
|
||||
QObject(),
|
||||
_locale(QLocale::C),
|
||||
_socket(socket),
|
||||
_imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor()),
|
||||
_hyperion(hyperion),
|
||||
_receiveBuffer(),
|
||||
_priority(255),
|
||||
_ledColors(hyperion->getLedCount(), RgbColor::BLACK)
|
||||
{
|
||||
// initalize the locale. Start with the default C-locale
|
||||
_locale.setNumberOptions(QLocale::OmitGroupSeparator | QLocale::RejectGroupSeparator);
|
||||
|
||||
// connect internal signals and slots
|
||||
connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
|
||||
connect(_socket, SIGNAL(readyRead()), this, SLOT(readData()));
|
||||
}
|
||||
|
||||
BoblightClientConnection::~BoblightClientConnection()
|
||||
{
|
||||
if (_priority < 255)
|
||||
{
|
||||
// clear the current channel
|
||||
_hyperion->clear(_priority);
|
||||
_priority = 255;
|
||||
}
|
||||
|
||||
delete _socket;
|
||||
}
|
||||
|
||||
void BoblightClientConnection::readData()
|
||||
{
|
||||
_receiveBuffer += _socket->readAll();
|
||||
|
||||
int bytes = _receiveBuffer.indexOf('\n') + 1;
|
||||
while(bytes > 0)
|
||||
{
|
||||
// create message string (strip the newline)
|
||||
QString message = QString::fromAscii(_receiveBuffer.data(), bytes-1);
|
||||
|
||||
// remove message data from buffer
|
||||
_receiveBuffer = _receiveBuffer.mid(bytes);
|
||||
|
||||
// handle message
|
||||
handleMessage(message);
|
||||
|
||||
// try too look up '\n' again
|
||||
bytes = _receiveBuffer.indexOf('\n') + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void BoblightClientConnection::socketClosed()
|
||||
{
|
||||
if (_priority < 255)
|
||||
{
|
||||
// clear the current channel
|
||||
_hyperion->clear(_priority);
|
||||
_priority = 255;
|
||||
}
|
||||
|
||||
emit connectionClosed(this);
|
||||
}
|
||||
|
||||
void BoblightClientConnection::handleMessage(const QString & message)
|
||||
{
|
||||
//std::cout << "boblight message: " << message.toStdString() << std::endl;
|
||||
|
||||
QStringList messageParts = message.split(" ", QString::SkipEmptyParts);
|
||||
|
||||
if (messageParts.size() > 0)
|
||||
{
|
||||
if (messageParts[0] == "hello")
|
||||
{
|
||||
sendMessage("hello\n");
|
||||
return;
|
||||
}
|
||||
else if (messageParts[0] == "ping")
|
||||
{
|
||||
sendMessage("ping 1\n");
|
||||
return;
|
||||
}
|
||||
else if (messageParts[0] == "get" && messageParts.size() > 1)
|
||||
{
|
||||
if (messageParts[1] == "version")
|
||||
{
|
||||
sendMessage("version 5\n");
|
||||
return;
|
||||
}
|
||||
else if (messageParts[1] == "lights")
|
||||
{
|
||||
sendLightMessage();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (messageParts[0] == "set" && messageParts.size() > 2)
|
||||
{
|
||||
if (messageParts.size() > 3 && messageParts[1] == "light")
|
||||
{
|
||||
bool rc;
|
||||
unsigned ledIndex = messageParts[2].toUInt(&rc);
|
||||
if (rc && ledIndex < _ledColors.size())
|
||||
{
|
||||
if (messageParts[3] == "rgb" && messageParts.size() == 7)
|
||||
{
|
||||
bool rc1, rc2, rc3;
|
||||
uint8_t red = 255 * messageParts[4].toFloat(&rc1);
|
||||
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 = 255 * messageParts[4].toFloat(&rc1);
|
||||
}
|
||||
|
||||
uint8_t green = 255 * messageParts[5].toFloat(&rc2);
|
||||
uint8_t blue = 255 * messageParts[6].toFloat(&rc3);
|
||||
|
||||
if (rc1 && rc2 && rc3)
|
||||
{
|
||||
RgbColor & rgb = _ledColors[ledIndex];
|
||||
rgb.red = red;
|
||||
rgb.green = green;
|
||||
rgb.blue = blue;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(messageParts[3] == "speed" ||
|
||||
messageParts[3] == "interpolation" ||
|
||||
messageParts[3] == "use" ||
|
||||
messageParts[3] == "singlechange")
|
||||
{
|
||||
// these message are ignored by Hyperion
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (messageParts.size() == 3 && messageParts[1] == "priority")
|
||||
{
|
||||
bool rc;
|
||||
int prio = messageParts[2].toInt(&rc);
|
||||
if (rc && prio != _priority)
|
||||
{
|
||||
if (_priority < 255)
|
||||
{
|
||||
// clear the current channel
|
||||
_hyperion->clear(_priority);
|
||||
}
|
||||
|
||||
_priority = prio;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (messageParts[0] == "sync")
|
||||
{
|
||||
// send current color values to hyperion
|
||||
if (_priority < 255)
|
||||
{
|
||||
_hyperion->setColors(_priority, _ledColors, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "unknown boblight message: " << message.toStdString() << std::endl;
|
||||
}
|
||||
|
||||
void BoblightClientConnection::sendMessage(const std::string & message)
|
||||
{
|
||||
//std::cout << "send boblight message: " << message;
|
||||
_socket->write(message.c_str(), message.size());
|
||||
}
|
||||
|
||||
void BoblightClientConnection::sendMessage(const char * message, int size)
|
||||
{
|
||||
//std::cout << "send boblight message: " << std::string(message, size);
|
||||
_socket->write(message, size);
|
||||
}
|
||||
|
||||
void BoblightClientConnection::sendLightMessage()
|
||||
{
|
||||
char buffer[256];
|
||||
int n = snprintf(buffer, sizeof(buffer), "lights %d\n", _hyperion->getLedCount());
|
||||
sendMessage(buffer, n);
|
||||
|
||||
for (unsigned i = 0; i < _hyperion->getLedCount(); ++i)
|
||||
{
|
||||
double h0, h1, v0, v1;
|
||||
_imageProcessor->getScanParameters(i, h0, h1, v0, v1);
|
||||
n = snprintf(buffer, sizeof(buffer), "light %03d scan %f %f %f %f\n", i, 100*v0, 100*v1, 100*h0, 100*h1);
|
||||
sendMessage(buffer, n);
|
||||
}
|
||||
}
|
103
libsrc/boblightserver/BoblightClientConnection.h
Normal file
103
libsrc/boblightserver/BoblightClientConnection.h
Normal file
@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
// stl includes
|
||||
#include <string>
|
||||
|
||||
// Qt includes
|
||||
#include <QByteArray>
|
||||
#include <QTcpSocket>
|
||||
#include <QLocale>
|
||||
|
||||
// Hyperion includes
|
||||
#include <hyperion/Hyperion.h>
|
||||
|
||||
class ImageProcessor;
|
||||
|
||||
///
|
||||
/// The Connection object created by \a BoblightServer when a new connection is establshed
|
||||
///
|
||||
class BoblightClientConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
///
|
||||
/// Constructor
|
||||
/// @param socket The Socket object for this connection
|
||||
/// @param hyperion The Hyperion server
|
||||
///
|
||||
BoblightClientConnection(QTcpSocket * socket, Hyperion * hyperion);
|
||||
|
||||
///
|
||||
/// Destructor
|
||||
///
|
||||
~BoblightClientConnection();
|
||||
|
||||
signals:
|
||||
///
|
||||
/// Signal which is emitted when the connection is being closed
|
||||
/// @param connection This connection object
|
||||
///
|
||||
void connectionClosed(BoblightClientConnection * connection);
|
||||
|
||||
private slots:
|
||||
///
|
||||
/// Slot called when new data has arrived
|
||||
///
|
||||
void readData();
|
||||
|
||||
///
|
||||
/// Slot called when this connection is being closed
|
||||
///
|
||||
void socketClosed();
|
||||
|
||||
private:
|
||||
///
|
||||
/// Handle an incoming boblight message
|
||||
///
|
||||
/// @param message the incoming message as string
|
||||
///
|
||||
void handleMessage(const QString &message);
|
||||
|
||||
///
|
||||
/// Send a message to the connected client
|
||||
///
|
||||
/// @param message The boblight message to send
|
||||
///
|
||||
void sendMessage(const std::string &message);
|
||||
|
||||
///
|
||||
/// Send a message to the connected client
|
||||
///
|
||||
/// @param message The boblight message to send
|
||||
/// @param size The size of the message
|
||||
///
|
||||
void sendMessage(const char * message, int size);
|
||||
|
||||
///
|
||||
/// Send a lights message the to connected client
|
||||
///
|
||||
void sendLightMessage();
|
||||
|
||||
private:
|
||||
/// Locale used for parsing floating point values
|
||||
QLocale _locale;
|
||||
|
||||
/// The TCP-Socket that is connected tot the boblight-client
|
||||
QTcpSocket * _socket;
|
||||
|
||||
/// The processor for translating images to led-values
|
||||
ImageProcessor * _imageProcessor;
|
||||
|
||||
/// Link to Hyperion for writing led-values to a priority channel
|
||||
Hyperion * _hyperion;
|
||||
|
||||
/// The buffer used for reading data from the socket
|
||||
QByteArray _receiveBuffer;
|
||||
|
||||
/// The priority used by this connection
|
||||
int _priority;
|
||||
|
||||
/// The latest led color data
|
||||
std::vector<RgbColor> _ledColors;
|
||||
};
|
57
libsrc/boblightserver/BoblightServer.cpp
Normal file
57
libsrc/boblightserver/BoblightServer.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
// system includes
|
||||
#include <stdexcept>
|
||||
|
||||
// project includes
|
||||
#include <boblightserver/BoblightServer.h>
|
||||
#include "BoblightClientConnection.h"
|
||||
|
||||
BoblightServer::BoblightServer(Hyperion *hyperion, uint16_t port) :
|
||||
QObject(),
|
||||
_hyperion(hyperion),
|
||||
_server(),
|
||||
_openConnections()
|
||||
{
|
||||
if (!_server.listen(QHostAddress::Any, port))
|
||||
{
|
||||
throw std::runtime_error("Boblight server could not bind to port");
|
||||
}
|
||||
|
||||
// Set trigger for incoming connections
|
||||
connect(&_server, SIGNAL(newConnection()), this, SLOT(newConnection()));
|
||||
}
|
||||
|
||||
BoblightServer::~BoblightServer()
|
||||
{
|
||||
foreach (BoblightClientConnection * connection, _openConnections) {
|
||||
delete connection;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t BoblightServer::getPort() const
|
||||
{
|
||||
return _server.serverPort();
|
||||
}
|
||||
|
||||
void BoblightServer::newConnection()
|
||||
{
|
||||
QTcpSocket * socket = _server.nextPendingConnection();
|
||||
|
||||
if (socket != nullptr)
|
||||
{
|
||||
std::cout << "New boblight connection" << std::endl;
|
||||
BoblightClientConnection * connection = new BoblightClientConnection(socket, _hyperion);
|
||||
_openConnections.insert(connection);
|
||||
|
||||
// register slot for cleaning up after the connection closed
|
||||
connect(connection, SIGNAL(connectionClosed(BoblightClientConnection*)), this, SLOT(closedConnection(BoblightClientConnection*)));
|
||||
}
|
||||
}
|
||||
|
||||
void BoblightServer::closedConnection(BoblightClientConnection *connection)
|
||||
{
|
||||
std::cout << "Boblight connection closed" << std::endl;
|
||||
_openConnections.remove(connection);
|
||||
|
||||
// schedule to delete the connection object
|
||||
connection->deleteLater();
|
||||
}
|
36
libsrc/boblightserver/CMakeLists.txt
Normal file
36
libsrc/boblightserver/CMakeLists.txt
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
# Define the current source locations
|
||||
set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/boblightserver)
|
||||
set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/boblightserver)
|
||||
|
||||
# Group the headers that go through the MOC compiler
|
||||
set(BoblightServer_QT_HEADERS
|
||||
${CURRENT_HEADER_DIR}/BoblightServer.h
|
||||
${CURRENT_SOURCE_DIR}/BoblightClientConnection.h
|
||||
)
|
||||
|
||||
set(BoblightServer_HEADERS
|
||||
)
|
||||
|
||||
set(BoblightServer_SOURCES
|
||||
${CURRENT_SOURCE_DIR}/BoblightServer.cpp
|
||||
${CURRENT_SOURCE_DIR}/BoblightClientConnection.cpp
|
||||
)
|
||||
|
||||
qt4_wrap_cpp(BoblightServer_HEADERS_MOC ${BoblightServer_QT_HEADERS})
|
||||
|
||||
add_library(boblightserver
|
||||
${BoblightServer_HEADERS}
|
||||
${BoblightServer_QT_HEADERS}
|
||||
${BoblightServer_SOURCES}
|
||||
${BoblightServer_HEADERS_MOC}
|
||||
)
|
||||
|
||||
target_link_libraries(boblightserver
|
||||
hyperion
|
||||
hyperion-utils)
|
||||
|
||||
qt4_use_modules(boblightserver
|
||||
Core
|
||||
Gui
|
||||
Network)
|
@ -67,6 +67,20 @@ void ImageProcessor::process(const RgbImage& image, std::vector<RgbColor>& ledCo
|
||||
mImageToLeds->getMeanLedColor(image, ledColors);
|
||||
}
|
||||
|
||||
bool ImageProcessor::getScanParameters(size_t led, double &hscanBegin, double &hscanEnd, double &vscanBegin, double &vscanEnd) const
|
||||
{
|
||||
if (led < mLedString.leds().size())
|
||||
{
|
||||
const Led & l = mLedString.leds()[led];
|
||||
hscanBegin = l.minX_frac;
|
||||
hscanEnd = l.maxX_frac;
|
||||
vscanBegin = l.minY_frac;
|
||||
vscanEnd = l.maxY_frac;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ImageProcessor::verifyBorder(const RgbImage& image)
|
||||
{
|
||||
if(_enableBlackBorderRemoval && _borderProcessor->process(image))
|
||||
|
@ -295,6 +295,20 @@
|
||||
"additionalProperties" : false
|
||||
},
|
||||
"protoServer" :
|
||||
{
|
||||
"type" : "object",
|
||||
"required" : false,
|
||||
"properties" : {
|
||||
"port" : {
|
||||
"type" : "integer",
|
||||
"required" : true,
|
||||
"minimum" : 0,
|
||||
"maximum" : 65535
|
||||
}
|
||||
},
|
||||
"additionalProperties" : false
|
||||
},
|
||||
"boblightServer" :
|
||||
{
|
||||
"type" : "object",
|
||||
"required" : false,
|
||||
|
@ -42,7 +42,7 @@ void JsonClientConnection::readData()
|
||||
_receiveBuffer += _socket->readAll();
|
||||
|
||||
int bytes = _receiveBuffer.indexOf('\n') + 1;
|
||||
if (bytes != 0)
|
||||
while(bytes > 0)
|
||||
{
|
||||
// create message string
|
||||
std::string message(_receiveBuffer.data(), bytes);
|
||||
@ -52,6 +52,9 @@ void JsonClientConnection::readData()
|
||||
|
||||
// handle message
|
||||
handleMessage(message);
|
||||
|
||||
// try too look up '\n' again
|
||||
bytes = _receiveBuffer.indexOf('\n') + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,4 +8,5 @@ target_link_libraries(hyperiond
|
||||
dispmanx-grabber
|
||||
xbmcvideochecker
|
||||
jsonserver
|
||||
protoserver)
|
||||
protoserver
|
||||
boblightserver)
|
||||
|
@ -26,6 +26,9 @@
|
||||
// ProtoServer includes
|
||||
#include <protoserver/ProtoServer.h>
|
||||
|
||||
// BoblightServer includes
|
||||
#include <boblightserver/BoblightServer.h>
|
||||
|
||||
void signal_handler(const int signum)
|
||||
{
|
||||
QCoreApplication::quit();
|
||||
@ -153,6 +156,15 @@ int main(int argc, char** argv)
|
||||
std::cout << "Proto server created and started on port " << protoServer->getPort() << std::endl;
|
||||
}
|
||||
|
||||
// Create Boblight server if configuration is present
|
||||
BoblightServer * boblightServer = nullptr;
|
||||
if (config.isMember("boblightServer"))
|
||||
{
|
||||
const Json::Value & boblightServerConfig = config["boblightServer"];
|
||||
boblightServer = new BoblightServer(&hyperion, boblightServerConfig["port"].asUInt());
|
||||
std::cout << "Boblight server created and started on port " << boblightServer->getPort() << std::endl;
|
||||
}
|
||||
|
||||
// run the application
|
||||
int rc = app.exec();
|
||||
std::cout << "Application closed with code " << rc << std::endl;
|
||||
|
Loading…
Reference in New Issue
Block a user