2013-08-17 11:54:16 +02:00
|
|
|
// stl includes
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
// Qt includes
|
|
|
|
#include <QRgb>
|
|
|
|
|
|
|
|
// hyperion-remote includes
|
|
|
|
#include "JsonConnection.h"
|
|
|
|
|
|
|
|
JsonConnection::JsonConnection(const std::string & a, bool printJson) :
|
|
|
|
_printJson(printJson),
|
|
|
|
_socket()
|
|
|
|
{
|
|
|
|
QString address(a.c_str());
|
|
|
|
QStringList parts = address.split(":");
|
|
|
|
if (parts.size() != 2)
|
|
|
|
{
|
|
|
|
throw std::runtime_error(QString("Wrong address: unable to parse address (%1)").arg(address).toStdString());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ok;
|
|
|
|
uint16_t port = parts[1].toUShort(&ok);
|
|
|
|
if (!ok)
|
|
|
|
{
|
|
|
|
throw std::runtime_error(QString("Wrong address: Unable to parse the port number (%1)").arg(parts[1]).toStdString());
|
|
|
|
}
|
|
|
|
|
|
|
|
_socket.connectToHost(parts[0], port);
|
|
|
|
if (!_socket.waitForConnected())
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Unable to connect to host");
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << "Connected to " << a << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
JsonConnection::~JsonConnection()
|
|
|
|
{
|
|
|
|
_socket.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonConnection::setColor(QColor color, int priority, int duration)
|
|
|
|
{
|
|
|
|
std::cout << "Set color to " << color.red() << " " << color.green() << " " << color.blue() << std::endl;
|
|
|
|
|
|
|
|
// create command
|
|
|
|
Json::Value command;
|
|
|
|
command["command"] = "color";
|
|
|
|
command["priority"] = priority;
|
|
|
|
Json::Value & rgbValue = command["color"];
|
|
|
|
rgbValue[0] = color.red();
|
|
|
|
rgbValue[1] = color.green();
|
|
|
|
rgbValue[2] = color.blue();
|
|
|
|
if (duration > 0)
|
|
|
|
{
|
|
|
|
command["duration"] = duration;
|
|
|
|
}
|
|
|
|
|
|
|
|
// send command message
|
|
|
|
Json::Value reply = sendMessage(command);
|
|
|
|
|
|
|
|
// parse reply message
|
|
|
|
parseReply(reply);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonConnection::setImage(QImage image, int priority, int duration)
|
|
|
|
{
|
|
|
|
std::cout << "Set image has size: " << image.width() << "x" << image.height() << std::endl;
|
|
|
|
|
|
|
|
// ensure the image has RGB888 format
|
|
|
|
image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
|
|
|
QByteArray binaryImage;
|
|
|
|
binaryImage.reserve(image.width() * image.height() * 3);
|
|
|
|
for (int i = 0; i < image.height(); ++i)
|
|
|
|
{
|
|
|
|
const QRgb * scanline = reinterpret_cast<const QRgb *>(image.scanLine(i));
|
|
|
|
for (int j = 0; j < image.width(); ++j)
|
|
|
|
{
|
|
|
|
binaryImage.append((char) qRed(scanline[j]));
|
|
|
|
binaryImage.append((char) qGreen(scanline[j]));
|
|
|
|
binaryImage.append((char) qBlue(scanline[j]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const QByteArray base64Image = binaryImage.toBase64();
|
|
|
|
|
|
|
|
// create command
|
|
|
|
Json::Value command;
|
|
|
|
command["command"] = "image";
|
|
|
|
command["priority"] = priority;
|
2013-08-17 19:20:19 +02:00
|
|
|
command["imagewidth"] = image.width();
|
|
|
|
command["imageheight"] = image.height();
|
|
|
|
command["imagedata"] = std::string(base64Image.data(), base64Image.size());
|
2013-08-17 11:54:16 +02:00
|
|
|
if (duration > 0)
|
|
|
|
{
|
|
|
|
command["duration"] = duration;
|
|
|
|
}
|
|
|
|
|
|
|
|
// send command message
|
|
|
|
Json::Value reply = sendMessage(command);
|
|
|
|
|
|
|
|
// parse reply message
|
|
|
|
parseReply(reply);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString JsonConnection::getServerInfo()
|
|
|
|
{
|
|
|
|
std::cout << "Get server info" << std::endl;
|
|
|
|
|
|
|
|
// create command
|
|
|
|
Json::Value command;
|
|
|
|
command["command"] = "serverinfo";
|
|
|
|
|
|
|
|
// send command message
|
|
|
|
Json::Value reply = sendMessage(command);
|
|
|
|
|
|
|
|
// parse reply message
|
|
|
|
if (parseReply(reply))
|
|
|
|
{
|
|
|
|
if (!reply.isMember("info") || !reply["info"].isObject())
|
|
|
|
{
|
|
|
|
throw std::runtime_error("No info available in result");
|
|
|
|
}
|
|
|
|
|
|
|
|
const Json::Value & info = reply["info"];
|
|
|
|
return QString(info.toStyledString().c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonConnection::clear(int priority)
|
|
|
|
{
|
|
|
|
std::cout << "Clear priority channel " << priority << std::endl;
|
|
|
|
|
|
|
|
// create command
|
|
|
|
Json::Value command;
|
|
|
|
command["command"] = "clear";
|
|
|
|
command["priority"] = priority;
|
|
|
|
|
|
|
|
// send command message
|
|
|
|
Json::Value reply = sendMessage(command);
|
|
|
|
|
|
|
|
// parse reply message
|
|
|
|
parseReply(reply);
|
|
|
|
}
|
|
|
|
|
|
|
|
void JsonConnection::clearAll()
|
|
|
|
{
|
|
|
|
std::cout << "Clear all priority channels" << std::endl;
|
|
|
|
|
|
|
|
// create command
|
|
|
|
Json::Value command;
|
|
|
|
command["command"] = "clearall";
|
|
|
|
|
|
|
|
// send command message
|
|
|
|
Json::Value reply = sendMessage(command);
|
|
|
|
|
|
|
|
// parse reply message
|
|
|
|
parseReply(reply);
|
|
|
|
}
|
|
|
|
|
2013-08-21 21:50:17 +02:00
|
|
|
void JsonConnection::setTransform(double * saturation, double * value, ColorTransformValues *threshold, ColorTransformValues *gamma, ColorTransformValues *blacklevel, ColorTransformValues *whitelevel)
|
2013-08-17 11:54:16 +02:00
|
|
|
{
|
|
|
|
std::cout << "Set color transforms" << std::endl;
|
|
|
|
|
|
|
|
// create command
|
|
|
|
Json::Value command;
|
|
|
|
command["command"] = "transform";
|
|
|
|
Json::Value & transform = command["transform"];
|
|
|
|
|
2013-08-21 21:50:17 +02:00
|
|
|
if (saturation != nullptr)
|
|
|
|
{
|
|
|
|
transform["saturationGain"] = *saturation;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value != nullptr)
|
|
|
|
{
|
|
|
|
transform["valueGain"] = *value;
|
|
|
|
}
|
|
|
|
|
2013-08-17 11:54:16 +02:00
|
|
|
if (threshold != nullptr)
|
|
|
|
{
|
|
|
|
Json::Value & v = transform["threshold"];
|
|
|
|
v.append(threshold->valueRed);
|
|
|
|
v.append(threshold->valueGreen);
|
|
|
|
v.append(threshold->valueBlue);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gamma != nullptr)
|
|
|
|
{
|
|
|
|
Json::Value & v = transform["gamma"];
|
2013-08-21 18:09:50 +02:00
|
|
|
v.append(gamma->valueRed);
|
|
|
|
v.append(gamma->valueGreen);
|
|
|
|
v.append(gamma->valueBlue);
|
2013-08-17 11:54:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (blacklevel != nullptr)
|
|
|
|
{
|
|
|
|
Json::Value & v = transform["blacklevel"];
|
2013-08-21 18:09:50 +02:00
|
|
|
v.append(blacklevel->valueRed);
|
|
|
|
v.append(blacklevel->valueGreen);
|
|
|
|
v.append(blacklevel->valueBlue);
|
2013-08-17 11:54:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (whitelevel != nullptr)
|
|
|
|
{
|
|
|
|
Json::Value & v = transform["whitelevel"];
|
2013-08-21 18:09:50 +02:00
|
|
|
v.append(whitelevel->valueRed);
|
|
|
|
v.append(whitelevel->valueGreen);
|
|
|
|
v.append(whitelevel->valueBlue);
|
2013-08-17 11:54:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// send command message
|
|
|
|
Json::Value reply = sendMessage(command);
|
|
|
|
|
|
|
|
// parse reply message
|
|
|
|
parseReply(reply);
|
|
|
|
}
|
|
|
|
|
|
|
|
Json::Value JsonConnection::sendMessage(const Json::Value & message)
|
|
|
|
{
|
2013-08-17 15:39:29 +02:00
|
|
|
// serialize message (FastWriter already appends a newline)
|
|
|
|
std::string serializedMessage = Json::FastWriter().write(message);
|
|
|
|
|
2013-08-17 11:54:16 +02:00
|
|
|
// print command if requested
|
|
|
|
if (_printJson)
|
|
|
|
{
|
2013-08-17 15:39:29 +02:00
|
|
|
std::cout << "Command: " << serializedMessage;
|
2013-08-17 11:54:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// write message
|
|
|
|
_socket.write(serializedMessage.c_str());
|
|
|
|
if (!_socket.waitForBytesWritten())
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Error while writing data to host");
|
|
|
|
}
|
|
|
|
|
|
|
|
// read reply data
|
|
|
|
QByteArray serializedReply;
|
|
|
|
while (!serializedReply.contains('\n'))
|
|
|
|
{
|
|
|
|
// receive reply
|
|
|
|
if (!_socket.waitForReadyRead())
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Error while reading data from host");
|
|
|
|
}
|
|
|
|
|
|
|
|
serializedReply += _socket.readAll();
|
|
|
|
}
|
|
|
|
int bytes = serializedReply.indexOf('\n') + 1; // Find the end of message
|
|
|
|
|
2013-08-17 15:39:29 +02:00
|
|
|
// print reply if requested
|
|
|
|
if (_printJson)
|
|
|
|
{
|
|
|
|
std::cout << "Reply: " << std::string(serializedReply.data(), bytes);
|
|
|
|
}
|
|
|
|
|
2013-08-17 11:54:16 +02:00
|
|
|
// parse reply data
|
|
|
|
Json::Reader jsonReader;
|
|
|
|
Json::Value reply;
|
|
|
|
if (!jsonReader.parse(serializedReply.constData(), serializedReply.constData() + bytes, reply))
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Error while parsing reply: invalid json");
|
|
|
|
}
|
|
|
|
|
|
|
|
return reply;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool JsonConnection::parseReply(const Json::Value &reply)
|
|
|
|
{
|
|
|
|
bool success = false;
|
|
|
|
std::string reason = "No error info";
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
success = reply.get("success", false).asBool();
|
|
|
|
if (!success)
|
|
|
|
reason = reply.get("error", reason).asString();
|
|
|
|
}
|
|
|
|
catch (const std::runtime_error &)
|
|
|
|
{
|
2013-08-17 15:39:29 +02:00
|
|
|
// Some json parsing error: ignore and set parsing error
|
2013-08-17 11:54:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!success)
|
|
|
|
{
|
2013-08-18 12:02:17 +02:00
|
|
|
throw std::runtime_error("Error: " + reason);
|
2013-08-17 11:54:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|