BoblightServer added

Former-commit-id: deb3479ee673d763ad2e5451fcd35a0febedb4f3
This commit is contained in:
johan
2013-11-08 22:18:10 +01:00
parent 85c8ba0100
commit 7300413015
12 changed files with 528 additions and 2 deletions

View File

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

View 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);
}
}

View 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;
};

View 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();
}

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

View File

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

View File

@@ -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,

View File

@@ -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;
}
}