mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Merge remote-tracking branch 'refs/remotes/hyperion-project/master' into weba
This commit is contained in:
commit
0578cda79a
@ -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.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
197
assets/firmware/arduino/network_bridge/udpraw_serialadalight.py
Executable file
197
assets/firmware/arduino/network_bridge/udpraw_serialadalight.py
Executable 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()
|
||||||
|
|
@ -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:
|
||||||
///
|
///
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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(...)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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 )
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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))
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user