Merge remote-tracking branch 'refs/remotes/hyperion-project/master' into weba

This commit is contained in:
brindosch 2017-01-24 21:30:00 +01:00
commit 0578cda79a
16 changed files with 350 additions and 128 deletions

View File

@ -9,10 +9,11 @@
set following values to your needs set following values to your needs
**************************************/ **************************************/
#define INITAL_LED_TEST_ENABLED true #define INITIAL_LED_TEST_ENABLED true
#define INITIAL_LED_TEST_BRIGHTNESS 32 // 0..255
// Number of leds in your strip. set to "1" and ANALOG_OUTPUT_ENABLED to "true" to activate analog only // Number of leds in your strip. set to "1" and ANALOG_OUTPUT_ENABLED to "true" to activate analog only
#define NUM_LEDS 100 #define MAX_LEDS 100
// type of your led controller, possible values, see below // type of your led controller, possible values, see below
#define LED_TYPE WS2812B #define LED_TYPE WS2812B
@ -54,8 +55,9 @@
#define COLOR_CORRECTION TypicalLEDStrip // predefined fastled color correction #define COLOR_CORRECTION TypicalLEDStrip // predefined fastled color correction
//#define COLOR_CORRECTION CRGB(255,255,255) // or RGB value describing the color correction //#define COLOR_CORRECTION CRGB(255,255,255) // or RGB value describing the color correction
// Baudrate, higher rate allows faster refresh rate and more LEDs (defined in /etc/boblight.conf) // Baudrate, higher rate allows faster refresh rate and more LEDs
#define serialRate 460800 // use 115200 for ftdi based boards #define serialRate 460800 // use 115200 for ftdi based boards
//#define serialRate 115200 // use 115200 for ftdi based boards
/************************************** /**************************************
@ -70,7 +72,7 @@ uint8_t prefix[] = {'A', 'd', 'a'}, hi, lo, chk, i;
unsigned long endTime; unsigned long endTime;
// Define the array of leds // Define the array of leds
CRGB leds[NUM_LEDS]; CRGB leds[MAX_LEDS];
// set rgb to analog led stripe // set rgb to analog led stripe
void showAnalogRGB(const CRGB& led) { void showAnalogRGB(const CRGB& led) {
@ -86,7 +88,7 @@ void showAnalogRGB(const CRGB& led) {
// set color to all leds // set color to all leds
void showColor(const CRGB& led) { void showColor(const CRGB& led) {
#if NUM_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false #if MAX_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false
LEDS.showColor(led); LEDS.showColor(led);
#endif #endif
showAnalogRGB(led); showAnalogRGB(led);
@ -94,8 +96,8 @@ void showColor(const CRGB& led) {
// switch of digital and analog leds // switch of digital and analog leds
void switchOff() { void switchOff() {
#if NUM_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false #if MAX_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false
memset(leds, 0, NUM_LEDS * sizeof(struct CRGB)); memset(leds, 0, MAX_LEDS * sizeof(struct CRGB));
FastLED.show(); FastLED.show();
#endif #endif
showAnalogRGB(leds[0]); showAnalogRGB(leds[0]);
@ -118,25 +120,25 @@ bool checkIncommingData() {
// main function that setups and runs the code // main function that setups and runs the code
void setup() { void setup() {
Serial.begin(serialRate);
// additional ground pin to make wiring a bit easier
pinMode(ANALOG_GROUND_PIN, OUTPUT);
digitalWrite(ANALOG_GROUND_PIN, LOW);
// analog output // analog output
if (ANALOG_OUTPUT_ENABLED) { if (ANALOG_OUTPUT_ENABLED) {
// additional ground pin to make wiring a bit easier
pinMode(ANALOG_GROUND_PIN, OUTPUT);
digitalWrite(ANALOG_GROUND_PIN, LOW);
pinMode(ANALOG_BLUE_PIN , OUTPUT); pinMode(ANALOG_BLUE_PIN , OUTPUT);
pinMode(ANALOG_RED_PIN , OUTPUT); pinMode(ANALOG_RED_PIN , OUTPUT);
pinMode(ANALOG_GREEN_PIN, OUTPUT); pinMode(ANALOG_GREEN_PIN, OUTPUT);
} }
// Uncomment/edit one of the following lines for your leds arrangement. // Uncomment/edit one of the following lines for your leds arrangement.
int ledCount = NUM_LEDS; int ledCount = MAX_LEDS;
if (ANALOG_MODE == ANALOG_MODE_LAST_LED) { if (ANALOG_MODE == ANALOG_MODE_LAST_LED) {
ledCount--; ledCount--;
} }
#if NUM_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false #if MAX_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false
FastLED.addLeds<LED_TYPE, LED_PINS, COLOR_ORDER>(leds, ledCount); FastLED.addLeds<LED_TYPE, LED_PINS, COLOR_ORDER>(leds, ledCount);
#endif #endif
@ -147,14 +149,14 @@ void setup() {
FastLED.setDither ( DITHER_MODE ); FastLED.setDither ( DITHER_MODE );
// initial RGB flash // initial RGB flash
#if INITAL_LED_TEST_ENABLED == true #if INITIAL_LED_TEST_ENABLED == true
showColor(CRGB(255, 0, 0)); delay(400); Serial.println("initial test");
showColor(CRGB(0, 255, 0)); delay(400); showColor(CRGB(INITIAL_LED_TEST_BRIGHTNESS, 0, 0)); delay(400);
showColor(CRGB(0, 0, 255)); delay(400); showColor(CRGB(0, INITIAL_LED_TEST_BRIGHTNESS, 0)); delay(400);
showColor(CRGB(0, 0, INITIAL_LED_TEST_BRIGHTNESS )); delay(400);
#endif #endif
showColor(CRGB(0, 0, 0)); showColor(CRGB(0, 0, 0));
Serial.begin(serialRate);
Serial.print("Ada\n"); // Send "Magic Word" string to host Serial.print("Ada\n"); // Send "Magic Word" string to host
@ -183,14 +185,16 @@ void setup() {
// if checksum does not match go back to wait // if checksum does not match go back to wait
if (chk != (hi ^ lo ^ 0x55)) continue; if (chk != (hi ^ lo ^ 0x55)) continue;
memset(leds, 0, NUM_LEDS * sizeof(struct CRGB)); memset(leds, 0, MAX_LEDS * sizeof(struct CRGB));
transmissionSuccess = true; transmissionSuccess = true;
sum_r = 0; sum_r = 0;
sum_g = 0; sum_g = 0;
sum_b = 0; sum_b = 0;
int num_leds = (hi<<8) + lo + 1;
// read the transmission data and set LED values // read the transmission data and set LED values
for (uint8_t idx = 0; idx < NUM_LEDS; idx++) { for (uint8_t idx = 0; idx < min(num_leds,MAX_LEDS); idx++) {
byte r, g, b; byte r, g, b;
if (!checkIncommingData()) { if (!checkIncommingData()) {
transmissionSuccess = false; transmissionSuccess = false;
@ -220,22 +224,22 @@ void setup() {
// shows new values // shows new values
if (transmissionSuccess) { if (transmissionSuccess) {
endTime = millis() + OFF_TIMEOUT; endTime = millis() + OFF_TIMEOUT;
#if NUM_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false #if MAX_LEDS > 1 || ANALOG_OUTPUT_ENABLED == false
FastLED.show(); FastLED.show();
#endif #endif
#if ANALOG_OUTPUT_ENABLED == true #if ANALOG_OUTPUT_ENABLED == true
#if ANALOG_MODE == ANALOG_MODE_LAST_LED #if ANALOG_MODE == ANALOG_MODE_LAST_LED
showAnalogRGB(leds[NUM_LEDS-1]); showAnalogRGB(leds[MAX_LEDS-1]);
#else #else
showAnalogRGB(CRGB(sum_r/NUM_LEDS, sum_g/NUM_LEDS, sum_b/NUM_LEDS)); showAnalogRGB(CRGB(sum_r/MAX_LEDS, sum_g/MAX_LEDS, sum_b/MAX_LEDS));
#endif #endif
#endif #endif
} }
} }
} // end of setup } // end of setup
void loop() { void loop() {
// Not used. See note in setup() function. // Not used. See note in setup() function.
} }

View File

@ -0,0 +1,197 @@
#!/usr/bin/env python
#
# Simple UDP to Serial redirector.
# Author: https://github.com/penfold42
# raw udp packets to raw serial:
# python.exe udp_adalight.py -P 2801 COM4 115200
# raw udp packets to adalight serial protocol:
# python.exe udp_adalight.py -a -P 2801 COM4 115200
# Derived from: https://github.com/pyserial/pyserial/blob/master/examples/tcp_serial_redirect.py
#
# (C) 2002-2016 Chris Liechti <cliechti@gmx.net>
#
# SPDX-License-Identifier: BSD-3-Clause
import sys
import socket
import serial
import serial.threaded
import time
class SerialToNet(serial.threaded.Protocol):
"""serial->socket"""
def __init__(self):
self.socket = None
def __call__(self):
return self
def data_received(self, data):
if self.socket is not None:
self.socket.sendall(data)
if __name__ == '__main__': # noqa
import argparse
parser = argparse.ArgumentParser(
description='Simple UDP to Serial redirector.',
epilog="""\
NOTE: no security measures are implemented. Anyone can remotely connect
to this service over the network.
""")
parser.add_argument(
'SERIALPORT',
help="serial port name")
parser.add_argument(
'BAUDRATE',
type=int,
nargs='?',
help='set baud rate, default: %(default)s',
default=115200)
parser.add_argument(
'-q', '--quiet',
action='store_true',
help='suppress non error messages',
default=False)
parser.add_argument(
'-a', '--ada',
action='store_true',
help='prepend adalight header to serial packets',
default=False)
parser.add_argument(
'--develop',
action='store_true',
help='Development mode, prints Python internals on errors',
default=False)
group = parser.add_argument_group('serial port')
group.add_argument(
"--parity",
choices=['N', 'E', 'O', 'S', 'M'],
type=lambda c: c.upper(),
help="set parity, one of {N E O S M}, default: N",
default='N')
group.add_argument(
'--rtscts',
action='store_true',
help='enable RTS/CTS flow control (default off)',
default=False)
group.add_argument(
'--xonxoff',
action='store_true',
help='enable software flow control (default off)',
default=False)
group.add_argument(
'--rts',
type=int,
help='set initial RTS line state (possible values: 0, 1)',
default=None)
group.add_argument(
'--dtr',
type=int,
help='set initial DTR line state (possible values: 0, 1)',
default=None)
group = parser.add_argument_group('network settings')
exclusive_group = group.add_mutually_exclusive_group()
exclusive_group.add_argument(
'-P', '--localport',
type=int,
help='local UDP port',
default=2801)
args = parser.parse_args()
# connect to serial port
ser = serial.serial_for_url(args.SERIALPORT, do_not_open=True)
ser.baudrate = args.BAUDRATE
ser.parity = args.parity
ser.rtscts = args.rtscts
ser.xonxoff = args.xonxoff
if args.rts is not None:
ser.rts = args.rts
if args.dtr is not None:
ser.dtr = args.dtr
if not args.quiet:
sys.stderr.write(
'--- UDP to Serial redirector\n'
'--- listening on udp port {a.localport}\n'
'--- sending to {p.name} {p.baudrate},{p.bytesize}{p.parity}{p.stopbits}\n'
'--- type Ctrl-C / BREAK to quit\n'.format(p=ser, a=args))
try:
ser.open()
except serial.SerialException as e:
sys.stderr.write('Could not open serial port {}: {}\n'.format(ser.name, e))
sys.exit(1)
ser_to_net = SerialToNet()
serial_worker = serial.threaded.ReaderThread(ser, ser_to_net)
serial_worker.start()
srv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(('', args.localport))
try:
intentional_exit = False
while True:
try:
while True:
try:
data,addr = srv.recvfrom(1024)
if not data:
break
if args.ada:
numleds = len(data)/3
hi = (numleds-1)/256
lo = (numleds-1)&255
sum = hi^lo^0x55
ser.write ("Ada"+ chr(hi) + chr(lo) + chr(sum))
ser.write(data) # get a bunch of bytes and send them
except socket.error as msg:
if args.develop:
raise
sys.stderr.write('ERROR: {}\n'.format(msg))
# probably got disconnected
break
except KeyboardInterrupt:
intentional_exit = True
raise
except socket.error as msg:
if args.develop:
raise
sys.stderr.write('ERROR: {}\n'.format(msg))
finally:
ser_to_net.socket = None
sys.stderr.write('Disconnected\n')
except KeyboardInterrupt:
pass
sys.stderr.write('\n--- exit ---\n')
serial_worker.stop()

View File

@ -70,7 +70,7 @@ public:
/// ///
/// free all alocated objects, should be called only from constructor or before restarting hyperion /// free all alocated objects, should be called only from constructor or before restarting hyperion
/// ///
void freeObjects(); void freeObjects(bool emitCloseSignal=false);
static Hyperion* initInstance(const QJsonObject& qjsonConfig, const QString configFile); static Hyperion* initInstance(const QJsonObject& qjsonConfig, const QString configFile);
static Hyperion* getInstance(); static Hyperion* getInstance();
@ -289,6 +289,7 @@ signals:
void imageToLedsMappingChanged(int mappingType); void imageToLedsMappingChanged(int mappingType);
void emitImage(int priority, const Image<ColorRgb> & image, const int timeout_ms); void emitImage(int priority, const Image<ColorRgb> & image, const int timeout_ms);
void closing();
private slots: private slots:
/// ///

View File

@ -21,8 +21,8 @@ public:
static int load(const QString& schema, const QString& config, QJsonObject& json) static int load(const QString& schema, const QString& config, QJsonObject& json)
{ {
// Load the schema and the config trees // Load the schema and the config trees
QJsonObject schemaTree = readJson(schema); QJsonObject schemaTree = readSchema(schema);
QJsonObject configTree = readJson(config); QJsonObject configTree = readConfig(config);
// create the validator // create the validator
QJsonSchemaChecker schemaChecker; QJsonSchemaChecker schemaChecker;
@ -45,15 +45,15 @@ public:
return 0; return 0;
} }
static QJsonObject readJson(const QString& path) static QJsonObject readConfig(const QString& path)
{ {
QFile file(path); QFile file(path);
QJsonParseError error; QJsonParseError error;
if (!file.open(QIODevice::ReadOnly)) if (!file.open(QIODevice::ReadOnly))
{ {
std::stringstream sstream; std::stringstream sstream;
sstream << "Configuration file not found: " << file.errorString().toStdString(); sstream << "Configuration file not found: '" << path.toStdString() << "' (" << file.errorString().toStdString() << ")";
throw std::runtime_error(sstream.str()); throw std::runtime_error(sstream.str());
} }
@ -61,12 +61,13 @@ public:
config.remove(QRegularExpression("([^:]?\\/\\/.*)")); config.remove(QRegularExpression("([^:]?\\/\\/.*)"));
QJsonDocument doc = QJsonDocument::fromJson(config.toUtf8(), &error); QJsonDocument doc = QJsonDocument::fromJson(config.toUtf8(), &error);
file.close();
if (error.error != QJsonParseError::NoError) if (error.error != QJsonParseError::NoError)
{ {
// report to the user the failure and their locations in the document. // report to the user the failure and their locations in the document.
int errorLine(0), errorColumn(0); int errorLine(0), errorColumn(0);
for( int i=0, count=qMin( error.offset,config.size()); i<count; ++i ) for( int i=0, count=qMin( error.offset,config.size()); i<count; ++i )
{ {
++errorColumn; ++errorColumn;
@ -76,13 +77,51 @@ public:
++errorLine; ++errorLine;
} }
} }
std::stringstream sstream; std::stringstream sstream;
sstream << "Failed to parse configuration: " << error.errorString().toStdString() << " at Line: " << errorLine << ", Column: " << errorColumn; sstream << "Failed to parse configuration: " << error.errorString().toStdString() << " at Line: " << errorLine << ", Column: " << errorColumn;
throw std::runtime_error(sstream.str()); throw std::runtime_error(sstream.str());
} }
return doc.object();
}
static QJsonObject readSchema(const QString& path)
{
QFile schemaData(path);
QJsonParseError error;
if (!schemaData.open(QIODevice::ReadOnly))
{
std::stringstream sstream;
sstream << "Schema not found: '" << path.toStdString() << "' (" << schemaData.errorString().toStdString() << ")";
throw std::runtime_error(sstream.str());
}
QByteArray schema = schemaData.readAll();
QJsonDocument doc = QJsonDocument::fromJson(schema, &error);
schemaData.close();
file.close(); if (error.error != QJsonParseError::NoError)
{
// report to the user the failure and their locations in the document.
int errorLine(0), errorColumn(0);
for( int i=0, count=qMin( error.offset,schema.size()); i<count; ++i )
{
++errorColumn;
if(schema.at(i) == '\n' )
{
errorColumn = 0;
++errorLine;
}
}
std::stringstream sstream;
sstream << "ERROR: Json schema wrong: " << error.errorString().toStdString() << " at Line: " << errorLine << ", Column: " << errorColumn;
throw std::runtime_error(sstream.str());
}
return doc.object(); return doc.object();
} }

View File

@ -67,14 +67,6 @@ private:
/// ///
void setMessage(const std::string & message); void setMessage(const std::string & message);
///
/// Retrieves all references from the json-value as specified by the schema
///
/// @param[in] value The json-value
/// @param[in] schema The schema
///
void collectDependencies(const QJsonValue & value, const QJsonObject &schema);
private: private:
// attribute check functions // attribute check functions
/// ///
@ -106,15 +98,6 @@ private:
/// ///
void checkAdditionalProperties(const QJsonObject & value, const QJsonValue & schema, const QStringList & ignoredProperties); void checkAdditionalProperties(const QJsonObject & value, const QJsonValue & schema, const QStringList & ignoredProperties);
///
/// Checks if references are configued and used correctly. If this is not the case _error is set
/// to true and an error-message is added to the message-queue.
///
/// @param value The given json-object
/// @param schemaLink The schema of the json-object
///
void checkDependencies(const QJsonValue & value, const QJsonValue & schemaLink);
/// ///
/// Checks if the given value is larger or equal to the specified value. If this is not the case /// Checks if the given value is larger or equal to the specified value. If this is not the case
/// _error is set to true and an error-message is added to the message-queue. /// _error is set to true and an error-message is added to the message-queue.

View File

@ -74,6 +74,7 @@ V4L2Grabber::~V4L2Grabber()
void V4L2Grabber::uninit() void V4L2Grabber::uninit()
{ {
Debug(_log,"uninit grabber: %s", _deviceName.c_str());
// stop if the grabber was not stopped // stop if the grabber was not stopped
if (_initialized) if (_initialized)
{ {

View File

@ -27,6 +27,8 @@ GrabberWrapper::GrabberWrapper(std::string grabberName, const int priority, hype
GrabberWrapper::~GrabberWrapper() GrabberWrapper::~GrabberWrapper()
{ {
stop();
Debug(_log,"Close grabber: %s", _grabberName.c_str());
delete _processor; delete _processor;
} }

View File

@ -447,8 +447,13 @@ Hyperion::Hyperion(const QJsonObject &qjsonConfig, const QString configFile)
} }
void Hyperion::freeObjects() void Hyperion::freeObjects(bool emitCloseSignal)
{ {
if (emitCloseSignal)
{
emit closing();
}
// switch off all leds // switch off all leds
clearall(); clearall();
_device->switchOff(); _device->switchOff();
@ -462,7 +467,7 @@ void Hyperion::freeObjects()
Hyperion::~Hyperion() Hyperion::~Hyperion()
{ {
freeObjects(); freeObjects(false);
} }
unsigned Hyperion::getLedCount() const unsigned Hyperion::getLedCount() const

View File

@ -892,7 +892,7 @@ void JsonClientConnection::handleConfigCommand(const QJsonObject& message, const
} }
else if (subcommand == "reload") else if (subcommand == "reload")
{ {
_hyperion->freeObjects(); _hyperion->freeObjects(true);
Process::restartHyperion(); Process::restartHyperion();
sendErrorReply("failed to restart hyperion", full_command, tan); sendErrorReply("failed to restart hyperion", full_command, tan);
} }
@ -912,7 +912,7 @@ void JsonClientConnection::handleConfigGetCommand(const QJsonObject& message, co
try try
{ {
result["result"] = QJsonFactory::readJson(QString::fromStdString(_hyperion->getConfigFileName())); result["result"] = QJsonFactory::readConfig(QString::fromStdString(_hyperion->getConfigFileName()));
} }
catch(...) catch(...)
{ {

View File

@ -115,6 +115,7 @@ void QJsonSchemaChecker::validate(const QJsonValue & value, const QJsonObject &s
else else
{ {
// no check function defined for this attribute // no check function defined for this attribute
_error = true;
setMessage(std::string("No check function defined for attribute ") + attribute.toStdString()); setMessage(std::string("No check function defined for attribute ") + attribute.toStdString());
continue; continue;
} }

View File

@ -73,6 +73,13 @@ static inline void printErrorToReply (QtHttpReply * reply, QString errorMessage)
reply->appendRawData (errorMessage.toLocal8Bit ()); reply->appendRawData (errorMessage.toLocal8Bit ());
} }
static inline void printError404ToReply (QtHttpReply * reply, QString errorMessage)
{
reply->setStatusCode(QtHttpReply::NotFound);
reply->addHeader ("Content-Type", QByteArrayLiteral ("text/plain"));
reply->appendRawData (errorMessage.toLocal8Bit ());
}
void StaticFileServing::onRequestNeedsReply (QtHttpRequest * request, QtHttpReply * reply) void StaticFileServing::onRequestNeedsReply (QtHttpRequest * request, QtHttpReply * reply)
{ {
QString command = request->getCommand (); QString command = request->getCommand ();
@ -103,7 +110,7 @@ void StaticFileServing::onRequestNeedsReply (QtHttpRequest * request, QtHttpRepl
Q_INIT_RESOURCE(WebConfig); Q_INIT_RESOURCE(WebConfig);
QFileInfo info(_baseUrl % "/" % path); QFileInfo info(_baseUrl % "/" % path);
if ( path == "/" || path.isEmpty() || ! info.exists() ) if ( path == "/" || path.isEmpty() )
{ {
path = "index.html"; path = "index.html";
} }
@ -134,7 +141,7 @@ void StaticFileServing::onRequestNeedsReply (QtHttpRequest * request, QtHttpRepl
} }
else else
{ {
printErrorToReply (reply, "Requested file " % path % " couldn't be found !"); printError404ToReply (reply, "404 Not Found\n" % path % " couldn't be found !");
} }
} }
else else

View File

@ -23,7 +23,7 @@ WebConfig::WebConfig(QObject * parent)
_baseUrl = webconfigConfig["document_root"].toString(_baseUrl); _baseUrl = webconfigConfig["document_root"].toString(_baseUrl);
} }
if (_baseUrl != ":/webconfig") if ( (_baseUrl != ":/webconfig") && !_baseUrl.trimmed().isEmpty())
{ {
QFileInfo info(_baseUrl); QFileInfo info(_baseUrl);
if (!info.exists() || !info.isDir()) if (!info.exists() || !info.isDir())
@ -32,6 +32,8 @@ WebConfig::WebConfig(QObject * parent)
_baseUrl = WEBCONFIG_DEFAULT_PATH; _baseUrl = WEBCONFIG_DEFAULT_PATH;
} }
} }
else
_baseUrl = WEBCONFIG_DEFAULT_PATH;
Debug(log, "WebUI initialized, document root: %s", _baseUrl.toUtf8().constData()); Debug(log, "WebUI initialized, document root: %s", _baseUrl.toUtf8().constData());
if ( webconfigEnable ) if ( webconfigEnable )

View File

@ -1,11 +1,18 @@
SET(Hyperiond_QT_HEADERS
hyperiond.h
)
QT5_WRAP_CPP(Hyperiond_HEADERS_MOC ${Hyperiond_QT_HEADERS})
add_executable(hyperiond add_executable(hyperiond
${Hyperiond_QT_HEADERS}
${Hyperiond_HEADERS_MOC}
configMigratorBase.cpp configMigratorBase.cpp
configMigratorBase.h configMigratorBase.h
configMigrator.cpp configMigrator.cpp
configMigrator.h configMigrator.h
hyperiond.cpp hyperiond.cpp
hyperiond.h
main.cpp main.cpp
) )

View File

@ -79,6 +79,13 @@ HyperionDaemon::HyperionDaemon(QString configFile, QObject *parent)
HyperionDaemon::~HyperionDaemon() HyperionDaemon::~HyperionDaemon()
{ {
freeObjects();
delete _hyperion;
}
void HyperionDaemon::freeObjects()
{
Debug(_log, "destroy grabbers and network stuff");
delete _amlGrabber; delete _amlGrabber;
delete _dispmanx; delete _dispmanx;
delete _fbGrabber; delete _fbGrabber;
@ -92,8 +99,17 @@ HyperionDaemon::~HyperionDaemon()
delete _protoServer; delete _protoServer;
delete _boblightServer; delete _boblightServer;
delete _udpListener; delete _udpListener;
delete _hyperion;
_v4l2Grabbers.clear();
_amlGrabber = nullptr;
_dispmanx = nullptr;
_fbGrabber = nullptr;
_osxGrabber = nullptr;
_kodiVideoChecker = nullptr;
_jsonServer = nullptr;
_protoServer = nullptr;
_boblightServer = nullptr;
_udpListener = nullptr;
} }
void HyperionDaemon::run() void HyperionDaemon::run()
@ -113,56 +129,33 @@ void HyperionDaemon::run()
#endif #endif
Info(_log, "Hyperion started"); Info(_log, "Hyperion started");
connect(_hyperion,SIGNAL(closing()),this,SLOT(freeObjects()));
} }
int HyperionDaemon::tryLoadConfig(const QString & configFile, const int schemaVersion) int HyperionDaemon::tryLoadConfig(const QString & configFile, const int schemaVersion)
{ {
// make sure the resources are loaded (they may be left out after static linking) // make sure the resources are loaded (they may be left out after static linking)
Q_INIT_RESOURCE(resource); Q_INIT_RESOURCE(resource);
QJsonParseError error;
// read the json schema from the resource // read the json schema from the resource
QString schemaFile = ":/hyperion-schema"; QString schemaFile = ":/hyperion-schema";
if (schemaVersion > 0) if (schemaVersion > 0)
schemaFile += "-" + QString::number(schemaVersion); schemaFile += "-" + QString::number(schemaVersion);
QFile schemaData(schemaFile);
if (!schemaData.open(QIODevice::ReadOnly))
{
std::stringstream error;
error << "Schema not found or not supported: " << schemaData.errorString().toStdString();
throw std::runtime_error(error.str());
}
QByteArray schema = schemaData.readAll();
QJsonDocument schemaJson = QJsonDocument::fromJson(schema, &error);
schemaData.close();
if (error.error != QJsonParseError::NoError)
{
// report to the user the failure and their locations in the document.
int errorLine(0), errorColumn(0);
for( int i=0, count=qMin( error.offset,schema.size()); i<count; ++i )
{
++errorColumn;
if(schema.at(i) == '\n' )
{
errorColumn = 0;
++errorLine;
}
}
std::stringstream sstream;
sstream << "ERROR: Json schema wrong: " << error.errorString().toStdString() << " at Line: " << errorLine << ", Column: " << errorColumn;
throw std::runtime_error(sstream.str()); QJsonObject schemaJson;
try
{
schemaJson = QJsonFactory::readSchema(schemaFile);
}
catch(const std::runtime_error& error)
{
throw std::runtime_error(error.what());
} }
QJsonSchemaChecker schemaChecker; QJsonSchemaChecker schemaChecker;
schemaChecker.setSchema(schemaJson.object()); schemaChecker.setSchema(schemaJson);
_qconfig = QJsonFactory::readJson(configFile); _qconfig = QJsonFactory::readConfig(configFile);
if (!schemaChecker.validate(_qconfig)) if (!schemaChecker.validate(_qconfig))
{ {
for (std::list<std::string>::const_iterator i = schemaChecker.getMessages().begin(); i != schemaChecker.getMessages().end(); ++i) for (std::list<std::string>::const_iterator i = schemaChecker.getMessages().begin(); i != schemaChecker.getMessages().end(); ++i)
@ -177,7 +170,6 @@ int HyperionDaemon::tryLoadConfig(const QString & configFile, const int schemaVe
return generalConfig["configVersion"].toInt(-1); return generalConfig["configVersion"].toInt(-1);
} }
void HyperionDaemon::loadConfig(const QString & configFile, const int neededConfigVersion) void HyperionDaemon::loadConfig(const QString & configFile, const int neededConfigVersion)
{ {
Info(_log, "Selected configuration file: %s", configFile.toUtf8().constData()); Info(_log, "Selected configuration file: %s", configFile.toUtf8().constData());
@ -472,7 +464,7 @@ void HyperionDaemon::createSystemFrameGrabber()
else if (type == "x11") createGrabberX11(grabberConfig); else if (type == "x11") createGrabberX11(grabberConfig);
else { Warning( _log, "unknown framegrabber type '%s'", type.toUtf8().constData()); grabberCompState = false; } else { Warning( _log, "unknown framegrabber type '%s'", type.toUtf8().constData()); grabberCompState = false; }
_hyperion->getComponentRegister().componentStateChanged(hyperion::COMP_GRABBER, grabberCompState); // _hyperion->getComponentRegister().componentStateChanged(hyperion::COMP_GRABBER, grabberCompState);
_hyperion->setComponentState(hyperion::COMP_GRABBER, grabberCompState ); _hyperion->setComponentState(hyperion::COMP_GRABBER, grabberCompState );
} }
} }

View File

@ -49,6 +49,7 @@
class HyperionDaemon : public QObject class HyperionDaemon : public QObject
{ {
Q_OBJECT
public: public:
HyperionDaemon(QString configFile, QObject *parent=nullptr); HyperionDaemon(QString configFile, QObject *parent=nullptr);
~HyperionDaemon(); ~HyperionDaemon();
@ -65,6 +66,9 @@ public:
void createGrabberV4L2(); void createGrabberV4L2();
void createSystemFrameGrabber(); void createSystemFrameGrabber();
public slots:
void freeObjects();
private: private:
void createGrabberDispmanx(); void createGrabberDispmanx();
void createGrabberAmlogic(); void createGrabberAmlogic();

View File

@ -16,53 +16,30 @@ bool loadConfig(const QString & configFile)
{ {
// make sure the resources are loaded (they may be left out after static linking) // make sure the resources are loaded (they may be left out after static linking)
Q_INIT_RESOURCE(resource); Q_INIT_RESOURCE(resource);
QJsonParseError error;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// read and set the json schema from the resource // read and set the json schema from the resource
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
QFile schemaData(":/hyperion-schema-"+QString::number(CURRENT_CONFIG_VERSION)); QJsonObject schemaJson;
if (!schemaData.open(QIODevice::ReadOnly)) try
{ {
std::stringstream error; schemaJson = QJsonFactory::readSchema(":/hyperion-schema");
error << "Schema not found: " << schemaData.errorString().toStdString();
throw std::runtime_error(error.str());
} }
catch(const std::runtime_error& error)
QByteArray schema = schemaData.readAll();
QJsonDocument schemaJson = QJsonDocument::fromJson(schema, &error);
if (error.error != QJsonParseError::NoError)
{ {
// report to the user the failure and their locations in the document. throw std::runtime_error(error.what());
int errorLine(0), errorColumn(0);
for( int i=0, count=qMin( error.offset,schema.size()); i<count; ++i )
{
++errorColumn;
if(schema.at(i) == '\n' )
{
errorColumn = 0;
++errorLine;
}
}
std::stringstream sstream;
sstream << "Schema error: " << error.errorString().toStdString() << " at Line: " << errorLine << ", Column: " << errorColumn;
throw std::runtime_error(sstream.str());
} }
QJsonSchemaChecker schemaChecker; QJsonSchemaChecker schemaChecker;
schemaChecker.setSchema(schemaJson.object()); schemaChecker.setSchema(schemaJson);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// read and validate the configuration file from the command line // read and validate the configuration file from the command line
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
const QJsonObject jsonConfig = QJsonFactory::readJson(configFile); const QJsonObject jsonConfig = QJsonFactory::readConfig(configFile);
if (!schemaChecker.validate(jsonConfig)) if (!schemaChecker.validate(jsonConfig))
{ {