Merge remote-tracking branch 'origin/master' into ftdi_basic

This commit is contained in:
LordGrey
2024-05-25 23:35:13 +02:00
388 changed files with 20045 additions and 12428 deletions

View File

@@ -1,32 +1,94 @@
# Define the current source locations
if(ENABLE_EFFECTENGINE)
# Include the python directory. Also include the parent (which is for example /usr/include)
# which may be required when it is not includes by the (cross-) compiler by default.
if (NOT CMAKE_VERSION VERSION_LESS "3.12")
find_package(Python3 COMPONENTS Interpreter Development REQUIRED)
include_directories(${Python3_INCLUDE_DIRS} ${Python3_INCLUDE_DIRS}/..)
add_compile_definitions(PYTHON_VERSION_MAJOR_MINOR=${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR})
else()
find_package (PythonLibs ${PYTHON_VERSION_STRING} EXACT) # Maps PythonLibs to the PythonInterp version of the main cmake
include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}/..)
add_definitions(-DPYTHON_VERSION_MAJOR_MINOR=${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR})
endif()
endif()
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/utils)
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/utils)
FILE ( GLOB_RECURSE Utils_SOURCES "${CURRENT_HEADER_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.h" "${CURRENT_SOURCE_DIR}/*.cpp" )
list(APPEND Utils_SOURCES "${CMAKE_SOURCE_DIR}/dependencies/include/oklab/ok_color.h")
if ( NOT ENABLE_PROFILER )
LIST ( REMOVE_ITEM Utils_SOURCES ${CURRENT_HEADER_DIR}/Profiler.h ${CURRENT_SOURCE_DIR}/Profiler.cpp )
if(ENABLE_PROFILER)
set(PROFILER ${CURRENT_HEADER_DIR}/Profiler.h ${CURRENT_SOURCE_DIR}/Profiler.cpp)
endif()
add_library(hyperion-utils
${Utils_SOURCES}
# Global defines/signal sharing
${CMAKE_SOURCE_DIR}/include/utils/global_defines.h
${CMAKE_SOURCE_DIR}/include/utils/GlobalSignals.h
# JSON Schema Checker
${CMAKE_SOURCE_DIR}/include/utils/jsonschema/QJsonFactory.h
${CMAKE_SOURCE_DIR}/include/utils/jsonschema/QJsonUtils.h
${CMAKE_SOURCE_DIR}/include/utils/jsonschema/QJsonSchemaChecker.h
${CMAKE_SOURCE_DIR}/libsrc/utils/jsonschema/QJsonSchemaChecker.cpp
# Color ARGB/BGR/RGB/RGBA/RGBW etc. structures
${CMAKE_SOURCE_DIR}/include/utils/ColorArgb.h
${CMAKE_SOURCE_DIR}/libsrc/utils/ColorArgb.cpp
${CMAKE_SOURCE_DIR}/include/utils/ColorBgr.h
${CMAKE_SOURCE_DIR}/libsrc/utils/ColorBgr.cpp
${CMAKE_SOURCE_DIR}/include/utils/ColorRgb.h
${CMAKE_SOURCE_DIR}/libsrc/utils/ColorRgb.cpp
${CMAKE_SOURCE_DIR}/include/utils/ColorRgba.h
${CMAKE_SOURCE_DIR}/libsrc/utils/ColorRgba.cpp
${CMAKE_SOURCE_DIR}/include/utils/ColorRgbScalar.h
${CMAKE_SOURCE_DIR}/include/utils/ColorRgbw.h
${CMAKE_SOURCE_DIR}/libsrc/utils/ColorRgbw.cpp
# Image declaration
${CMAKE_SOURCE_DIR}/include/utils/Image.h
${CMAKE_SOURCE_DIR}/include/utils/ImageData.h
# Image resampler
${CMAKE_SOURCE_DIR}/include/utils/ImageResampler.h
${CMAKE_SOURCE_DIR}/libsrc/utils/ImageResampler.cpp
# Color transformation (saturation/luminance) of RGB colors
${CMAKE_SOURCE_DIR}/include/utils/ColorSys.h
${CMAKE_SOURCE_DIR}/libsrc/utils/ColorSys.cpp
# Color transformation (saturation/value) of Okhsv colors
${CMAKE_SOURCE_DIR}/include/utils/OkhsvTransform.h
${CMAKE_SOURCE_DIR}/libsrc/utils/OkhsvTransform.cpp
# Signal handler
${CMAKE_SOURCE_DIR}/include/utils/DefaultSignalHandler.h
${CMAKE_SOURCE_DIR}/libsrc/utils/DefaultSignalHandler.cpp
# File utilities
${CMAKE_SOURCE_DIR}/include/utils/FileUtils.h
${CMAKE_SOURCE_DIR}/libsrc/utils/FileUtils.cpp
# JSON utilities
${CMAKE_SOURCE_DIR}/include/utils/JsonUtils.h
${CMAKE_SOURCE_DIR}/libsrc/utils/JsonUtils.cpp
# Logger
${CMAKE_SOURCE_DIR}/include/utils/Logger.h
${CMAKE_SOURCE_DIR}/libsrc/utils/Logger.cpp
# IP adress/Port checker
${CMAKE_SOURCE_DIR}/include/utils/NetOrigin.h
${CMAKE_SOURCE_DIR}/libsrc/utils/NetOrigin.cpp
${CMAKE_SOURCE_DIR}/include/utils/NetUtils.h
# Process namespace (Hyperion restart)
${CMAKE_SOURCE_DIR}/include/utils/Process.h
${CMAKE_SOURCE_DIR}/libsrc/utils/Process.cpp
# Rgb single color adjustment/correction
${CMAKE_SOURCE_DIR}/include/utils/RgbChannelAdjustment.h
${CMAKE_SOURCE_DIR}/libsrc/utils/RgbChannelAdjustment.cpp
# Color conversion/transformation
${CMAKE_SOURCE_DIR}/include/utils/RgbToRgbw.h
${CMAKE_SOURCE_DIR}/libsrc/utils/RgbToRgbw.cpp
${CMAKE_SOURCE_DIR}/include/utils/RgbTransform.h
${CMAKE_SOURCE_DIR}/libsrc/utils/RgbTransform.cpp
# System info class
${CMAKE_SOURCE_DIR}/include/utils/SysInfo.h
${CMAKE_SOURCE_DIR}/libsrc/utils/SysInfo.cpp
# Grabber pixel formats enumeration
${CMAKE_SOURCE_DIR}/include/utils/PixelFormat.h
# Grabber playing modes enumeration
${CMAKE_SOURCE_DIR}/include/utils/VideoMode.h
# Grabber video standards enumeration
${CMAKE_SOURCE_DIR}/include/utils/VideoStandard.h
# SettingsManager utilities
${CMAKE_SOURCE_DIR}/include/utils/settings.h
# Qt string utilities
${CMAKE_SOURCE_DIR}/include/utils/QStringUtils.h
# QThread sleep class
${CMAKE_SOURCE_DIR}/include/utils/Sleep.h
# Wait event loop function
${CMAKE_SOURCE_DIR}/include/utils/WaitTime.h
# Weak connection
${CMAKE_SOURCE_DIR}/include/utils/WeakConnect.h
# Semver namespace
${CMAKE_SOURCE_DIR}/include/utils/version.hpp
# Utility methods for Hyperion class
${CMAKE_SOURCE_DIR}/include/utils/hyperion.h
# Oklab color space
${CMAKE_SOURCE_DIR}/dependencies/include/oklab/ok_color.h
# Performance tester
${PROFILER}
)
target_link_libraries(hyperion-utils

View File

@@ -29,9 +29,6 @@ void ImageResampler::processImage(const uint8_t * data, int width, int height, i
int cropTop = _cropTop;
int cropBottom = _cropBottom;
int xDestFlip = 0, yDestFlip = 0;
int uOffset = 0, vOffset = 0;
// handle 3D mode
switch (_videoMode)
{
@@ -53,120 +50,175 @@ void ImageResampler::processImage(const uint8_t * data, int width, int height, i
outputImage.resize(outputWidth, outputHeight);
for (int yDest = 0, ySource = cropTop + (_verticalDecimation >> 1); yDest < outputHeight; ySource += _verticalDecimation, ++yDest)
int xDestStart, xDestEnd;
int yDestStart, yDestEnd;
switch (_flipMode)
{
int yOffset = lineLength * ySource;
if (pixelFormat == PixelFormat::NV12)
{
uOffset = (height + ySource / 2) * lineLength;
}
else if (pixelFormat == PixelFormat::I420)
{
uOffset = width * height + (ySource/2) * width/2;
vOffset = width * height * 1.25 + (ySource/2) * width/2;
}
case FlipMode::NO_CHANGE:
xDestStart = 0;
xDestEnd = outputWidth-1;
yDestStart = 0;
yDestEnd = outputHeight-1;
break;
case FlipMode::HORIZONTAL:
xDestStart = 0;
xDestEnd = outputWidth-1;
yDestStart = -(outputHeight-1);
yDestEnd = 0;
break;
case FlipMode::VERTICAL:
xDestStart = -(outputWidth-1);
xDestEnd = 0;
yDestStart = 0;
yDestEnd = outputHeight-1;
break;
case FlipMode::BOTH:
xDestStart = -(outputWidth-1);
xDestEnd = 0;
yDestStart = -(outputHeight-1);
yDestEnd = 0;
break;
}
for (int xDest = 0, xSource = cropLeft + (_horizontalDecimation >> 1); xDest < outputWidth; xSource += _horizontalDecimation, ++xDest)
switch (pixelFormat)
{
case PixelFormat::UYVY:
{
switch (_flipMode)
for (int yDest = yDestStart, ySource = cropTop + (_verticalDecimation >> 1); yDest <= yDestEnd; ySource += _verticalDecimation, ++yDest)
{
case FlipMode::HORIZONTAL:
xDestFlip = xDest;
yDestFlip = outputHeight-yDest-1;
break;
case FlipMode::VERTICAL:
xDestFlip = outputWidth-xDest-1;
yDestFlip = yDest;
break;
case FlipMode::BOTH:
xDestFlip = outputWidth-xDest-1;
yDestFlip = outputHeight-yDest-1;
break;
case FlipMode::NO_CHANGE:
xDestFlip = xDest;
yDestFlip = yDest;
break;
}
ColorRgb &rgb = outputImage(xDestFlip, yDestFlip);
switch (pixelFormat)
{
case PixelFormat::UYVY:
for (int xDest = xDestStart, xSource = cropLeft + (_horizontalDecimation >> 1); xDest <= xDestEnd; xSource += _horizontalDecimation, ++xDest)
{
int index = yOffset + (xSource << 1);
ColorRgb & rgb = outputImage(abs(xDest), abs(yDest));
int index = lineLength * ySource + (xSource << 1);
uint8_t y = data[index+1];
uint8_t u = ((xSource&1) == 0) ? data[index ] : data[index-2];
uint8_t v = ((xSource&1) == 0) ? data[index+2] : data[index ];
ColorSys::yuv2rgb(y, u, v, rgb.red, rgb.green, rgb.blue);
}
break;
case PixelFormat::YUYV:
}
break;
}
case PixelFormat::YUYV:
{
for (int yDest = yDestStart, ySource = cropTop + (_verticalDecimation >> 1); yDest <= yDestEnd; ySource += _verticalDecimation, ++yDest)
{
for (int xDest = xDestStart, xSource = cropLeft + (_horizontalDecimation >> 1); xDest <= xDestEnd; xSource += _horizontalDecimation, ++xDest)
{
int index = yOffset + (xSource << 1);
ColorRgb & rgb = outputImage(abs(xDest), abs(yDest));
int index = lineLength * ySource + (xSource << 1);
uint8_t y = data[index];
uint8_t u = ((xSource&1) == 0) ? data[index+1] : data[index-1];
uint8_t v = ((xSource&1) == 0) ? data[index+3] : data[index+1];
ColorSys::yuv2rgb(y, u, v, rgb.red, rgb.green, rgb.blue);
}
break;
case PixelFormat::BGR16:
}
break;
}
case PixelFormat::BGR16:
{
for (int yDest = yDestStart, ySource = cropTop + (_verticalDecimation >> 1); yDest <= yDestEnd; ySource += _verticalDecimation, ++yDest)
{
for (int xDest = xDestStart, xSource = cropLeft + (_horizontalDecimation >> 1); xDest <= xDestEnd; xSource += _horizontalDecimation, ++xDest)
{
int index = yOffset + (xSource << 1);
ColorRgb & rgb = outputImage(abs(xDest), abs(yDest));
int index = lineLength * ySource + (xSource << 1);
rgb.blue = (data[index] & 0x1f) << 3;
rgb.green = (((data[index+1] & 0x7) << 3) | (data[index] & 0xE0) >> 5) << 2;
rgb.red = (data[index+1] & 0xF8);
}
break;
case PixelFormat::BGR24:
}
break;
}
case PixelFormat::BGR24:
{
for (int yDest = yDestStart, ySource = cropTop + (_verticalDecimation >> 1); yDest <= yDestEnd; ySource += _verticalDecimation, ++yDest)
{
for (int xDest = xDestStart, xSource = cropLeft + (_horizontalDecimation >> 1); xDest <= xDestEnd; xSource += _horizontalDecimation, ++xDest)
{
int index = yOffset + (xSource << 1) + xSource;
ColorRgb & rgb = outputImage(abs(xDest), abs(yDest));
int index = lineLength * ySource + (xSource << 1) + xSource;
rgb.blue = data[index ];
rgb.green = data[index+1];
rgb.red = data[index+2];
}
break;
case PixelFormat::RGB32:
}
break;
}
case PixelFormat::RGB32:
{
for (int yDest = yDestStart, ySource = cropTop + (_verticalDecimation >> 1); yDest <= yDestEnd; ySource += _verticalDecimation, ++yDest)
{
for (int xDest = xDestStart, xSource = cropLeft + (_horizontalDecimation >> 1); xDest <= xDestEnd; xSource += _horizontalDecimation, ++xDest)
{
int index = yOffset + (xSource << 2);
ColorRgb & rgb = outputImage(abs(xDest), abs(yDest));
int index = lineLength * ySource + (xSource << 2);
rgb.red = data[index ];
rgb.green = data[index+1];
rgb.blue = data[index+2];
}
break;
case PixelFormat::BGR32:
}
break;
}
case PixelFormat::BGR32:
{
for (int yDest = yDestStart, ySource = cropTop + (_verticalDecimation >> 1); yDest <= yDestEnd; ySource += _verticalDecimation, ++yDest)
{
for (int xDest = xDestStart, xSource = cropLeft + (_horizontalDecimation >> 1); xDest <= xDestEnd; xSource += _horizontalDecimation, ++xDest)
{
int index = yOffset + (xSource << 2);
ColorRgb & rgb = outputImage(abs(xDest), abs(yDest));
int index = lineLength * ySource + (xSource << 2);
rgb.blue = data[index ];
rgb.green = data[index+1];
rgb.red = data[index+2];
}
break;
case PixelFormat::NV12:
}
break;
}
case PixelFormat::NV12:
{
for (int yDest = yDestStart, ySource = cropTop + (_verticalDecimation >> 1); yDest <= yDestEnd; ySource += _verticalDecimation, ++yDest)
{
int uOffset = (height + ySource / 2) * lineLength;
for (int xDest = xDestStart, xSource = cropLeft + (_horizontalDecimation >> 1); xDest <= xDestEnd; xSource += _horizontalDecimation, ++xDest)
{
uint8_t y = data[yOffset + xSource];
ColorRgb & rgb = outputImage(abs(xDest), abs(yDest));
uint8_t y = data[lineLength * ySource + xSource];
uint8_t u = data[uOffset + ((xSource >> 1) << 1)];
uint8_t v = data[uOffset + ((xSource >> 1) << 1) + 1];
ColorSys::yuv2rgb(y, u, v, rgb.red, rgb.green, rgb.blue);
}
break;
case PixelFormat::I420:
}
break;
}
case PixelFormat::I420:
{
for (int yDest = yDestStart, ySource = cropTop + (_verticalDecimation >> 1); yDest <= yDestEnd; ySource += _verticalDecimation, ++yDest)
{
int uOffset = width * height + (ySource/2) * width/2;
int vOffset = width * height * 1.25 + (ySource/2) * width/2;
for (int xDest = xDestStart, xSource = cropLeft + (_horizontalDecimation >> 1); xDest <= xDestEnd; xSource += _horizontalDecimation, ++xDest)
{
int y = data[yOffset + xSource];
ColorRgb & rgb = outputImage(abs(xDest), abs(yDest));
int y = data[lineLength * ySource + xSource];
int u = data[uOffset + (xSource >> 1)];
int v = data[vOffset + (xSource >> 1)];
ColorSys::yuv2rgb(y, u, v, rgb.red, rgb.green, rgb.blue);
break;
}
break;
#ifdef HAVE_TURBO_JPEG
case PixelFormat::MJPEG:
break;
#endif
case PixelFormat::NO_CHANGE:
Error(Logger::getInstance("ImageResampler"), "Invalid pixel format given");
break;
}
break;
}
case PixelFormat::MJPEG:
break;
case PixelFormat::NO_CHANGE:
Error(Logger::getInstance("ImageResampler"), "Invalid pixel format given");
break;
}
}

View File

@@ -8,25 +8,26 @@
#include <QRegularExpression>
#include <QJsonObject>
#include <QJsonParseError>
#include <QStringList>
namespace JsonUtils {
bool readFile(const QString& path, QJsonObject& obj, Logger* log, bool ignError)
QPair<bool, QStringList> readFile(const QString& path, QJsonObject& obj, Logger* log, bool ignError)
{
QString data;
if(!FileUtils::readFile(path, data, log, ignError))
return false;
{
return qMakePair(false, QStringList(QString("Error reading file: %1").arg(path)));
}
if(!parse(path, data, obj, log))
return false;
return true;
QPair<bool, QStringList> parsingResult = JsonUtils::parse(path, data, obj, log);
return parsingResult;
}
bool readSchema(const QString& path, QJsonObject& obj, Logger* log)
{
QJsonObject schema;
if(!readFile(path, schema, log))
if(!readFile(path, schema, log).first)
return false;
if(!resolveRefs(schema, obj, log))
@@ -35,80 +36,89 @@ namespace JsonUtils {
return true;
}
bool parse(const QString& path, const QString& data, QJsonObject& obj, Logger* log)
QPair<bool, QStringList> parse(const QString& path, const QString& data, QJsonObject& obj, Logger* log)
{
QJsonDocument doc;
if(!parse(path, data, doc, log))
return false;
QPair<bool, QStringList> parsingResult = JsonUtils::parse(path, data, doc, log);
obj = doc.object();
return true;
return parsingResult;
}
bool parse(const QString& path, const QString& data, QJsonArray& arr, Logger* log)
QPair<bool, QStringList> parse(const QString& path, const QString& data, QJsonArray& arr, Logger* log)
{
QJsonDocument doc;
if(!parse(path, data, doc, log))
return false;
QPair<bool, QStringList> parsingResult = JsonUtils::parse(path, data, doc, log);
arr = doc.array();
return true;
return parsingResult;
}
bool parse(const QString& path, const QString& data, QJsonDocument& doc, Logger* log)
QPair<bool, QStringList> parse(const QString& path, const QString& data, QJsonDocument& doc, Logger* log)
{
//remove Comments in data
QString cleanData = data;
QStringList errorList;
QJsonParseError error;
doc = QJsonDocument::fromJson(cleanData.toUtf8(), &error);
doc = QJsonDocument::fromJson(data.toUtf8(), &error);
if (error.error != QJsonParseError::NoError)
{
// report to the user the failure and their locations in the document.
int errorLine(0), errorColumn(0);
int errorLine = 1;
int errorColumn = 1;
for( int i=0, count=qMin( error.offset,cleanData.size()); i<count; ++i )
int lastNewlineIndex = data.lastIndexOf("\n", error.offset - 1);
if (lastNewlineIndex != -1)
{
++errorColumn;
if(data.at(i) == '\n' )
{
errorColumn = 0;
++errorLine;
}
errorColumn = error.offset - lastNewlineIndex ;
}
Error(log, "Failed to parse json data from %s: Error: %s at Line: %i, Column: %i, Data: '%s'", QSTRING_CSTR(path), QSTRING_CSTR(error.errorString()), errorLine, errorColumn, QSTRING_CSTR(data));
return false;
errorLine += data.left(error.offset).count('\n');
const QString errorMessage = QString("JSON parse error: %1, line: %2, column: %3, Data: '%4'")
.arg(error.errorString())
.arg(errorLine)
.arg(errorColumn)
.arg(data);
errorList.push_back(errorMessage);
Error(log, "%s", QSTRING_CSTR(errorMessage));
return qMakePair(false, errorList);
}
return true;
return qMakePair(true, errorList);
}
bool validate(const QString& file, const QJsonObject& json, const QString& schemaPath, Logger* log)
QPair<bool, QStringList> validate(const QString& file, const QJsonObject& json, const QString& schemaPath, Logger* log)
{
// get the schema data
QJsonObject schema;
if(!readFile(schemaPath, schema, log))
return false;
if(!validate(file, json, schema, log))
return false;
return true;
QPair<bool, QStringList> readResult = readFile(schemaPath, schema, log);
if(!readResult.first)
{
return readResult;
}
QPair<bool, QStringList> validationResult = validate(file, json, schema, log);
return validationResult;
}
bool validate(const QString& file, const QJsonObject& json, const QJsonObject& schema, Logger* log)
QPair<bool, QStringList> validate(const QString& file, const QJsonObject& json, const QJsonObject& schema, Logger* log)
{
QStringList errorList;
QJsonSchemaChecker schemaChecker;
schemaChecker.setSchema(schema);
if (!schemaChecker.validate(json).first)
{
const QStringList & errors = schemaChecker.getMessages();
for (auto & error : errors)
const QStringList &errors = schemaChecker.getMessages();
for (const auto& error : errors)
{
Error(log, "While validating schema against json data of '%s':%s", QSTRING_CSTR(file), QSTRING_CSTR(error));
QString errorMessage = QString("JSON parse error: %1")
.arg(error);
errorList.push_back(errorMessage);
Error(log, "%s", QSTRING_CSTR(errorMessage));
}
return false;
return qMakePair(false, errorList);
}
return true;
return qMakePair(true, errorList);
}
bool write(const QString& filename, const QJsonObject& json, Logger* log)

View File

@@ -2,7 +2,6 @@
#include <utils/FileUtils.h>
#include <iostream>
#include <algorithm>
#ifndef _WIN32
#include <syslog.h>
@@ -15,7 +14,8 @@
#include <QFileInfo>
#include <QMutexLocker>
#include <QThreadStorage>
#include <time.h>
#include <QJsonObject>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QRecursiveMutex Logger::MapLock;
@@ -38,6 +38,7 @@ const size_t MAX_IDENTIFICATION_LENGTH = 22;
QAtomicInteger<unsigned int> LoggerCount = 0;
QAtomicInteger<unsigned int> LoggerId = 0;
const int MAX_LOG_MSG_BUFFERED = 500;
const int MaxRepeatCountSize = 200;
QThreadStorage<int> RepeatCount;
QThreadStorage<Logger::T_LOG_MESSAGE> RepeatMessage;
@@ -51,9 +52,8 @@ Logger* Logger::getInstance(const QString & name, const QString & subName, Logge
if (log == nullptr)
{
log = new Logger(name, subName, minLevel);
LoggerMap.insert(name, log); // compat version, replace it with following line if we have 100% c++11
//LoggerMap.emplace(name, log); // not compat with older linux distro's e.g. wheezy
connect(log, &Logger::newLogMessage, LoggerManager::getInstance(), &LoggerManager::handleNewLogMessage);
LoggerMap.insert(name + subName, log);
connect(log, &Logger::newLogMessage, LoggerManager::getInstance().data(), &LoggerManager::handleNewLogMessage);
}
return log;
@@ -65,7 +65,7 @@ void Logger::deleteInstance(const QString & name, const QString & subName)
if (name.isEmpty())
{
for (auto *logger : qAsConst(LoggerMap)) {
for (auto *logger : std::as_const(LoggerMap)) {
delete logger;
}
@@ -105,7 +105,7 @@ Logger::LogLevel Logger::getLogLevel(const QString & name, const QString & subNa
Logger::Logger (const QString & name, const QString & subName, LogLevel minLevel)
: QObject()
, _name(name)
, _subname(subName)
, _subName(subName)
, _syslogEnabled(true)
, _loggerId(LoggerId++)
, _minLevel(static_cast<int>(minLevel))
@@ -151,9 +151,8 @@ void Logger::write(const Logger::T_LOG_MESSAGE & message)
name.resize(MAX_IDENTIFICATION_LENGTH, ' ');
const QDateTime timestamp = QDateTime::fromMSecsSinceEpoch(message.utime);
std::cout << QString("%1 %2 : <%3> %4%5")
.arg(timestamp.toString("yyyy-MM-ddThh:mm:ss.zzz"))
.arg(timestamp.toString(Qt::ISODateWithMs))
.arg(name)
.arg(LogLevelStrings[message.level])
.arg(location)
@@ -161,7 +160,7 @@ void Logger::write(const Logger::T_LOG_MESSAGE & message)
.toStdString()
<< std::endl;
newLogMessage(message);
emit newLogMessage(message);
}
void Logger::Message(LogLevel level, const char* sourceFile, const char* func, unsigned int line, const char* fmt, ...)
@@ -169,8 +168,10 @@ void Logger::Message(LogLevel level, const char* sourceFile, const char* func, u
Logger::LogLevel globalLevel = static_cast<Logger::LogLevel>(int(GLOBAL_MIN_LOG_LEVEL));
if ( (globalLevel == Logger::UNSET && level < _minLevel) // no global level, use level from logger
|| (globalLevel > Logger::UNSET && level < globalLevel) ) // global level set, use global level
|| (globalLevel > Logger::UNSET && level < globalLevel) ) // global level set, use global level
{
return;
}
const size_t max_msg_length = 1024;
char msg[max_msg_length];
@@ -188,32 +189,40 @@ void Logger::Message(LogLevel level, const char* sourceFile, const char* func, u
write(repMsg);
#ifndef _WIN32
if ( _syslogEnabled && repMsg.level >= Logger::WARNING )
{
syslog (LogLevelSysLog[repMsg.level], "Previous line repeats %d times", RepeatCount.localData());
}
#endif
RepeatCount.setLocalData(0);
};
if (RepeatMessage.localData().loggerName == _name &&
RepeatMessage.localData().loggerSubName == _subname &&
RepeatMessage.localData().loggerSubName == _subName &&
RepeatMessage.localData().function == func &&
RepeatMessage.localData().message == msg &&
RepeatMessage.localData().line == line)
{
if (RepeatCount.localData() >= MaxRepeatCountSize)
{
repeatedSummary();
}
else
{
RepeatCount.setLocalData(RepeatCount.localData() + 1);
}
}
else
{
if (RepeatCount.localData())
{
repeatedSummary();
}
Logger::T_LOG_MESSAGE logMsg;
logMsg.loggerName = _name;
logMsg.loggerSubName = _subname;
logMsg.loggerSubName = _subName;
logMsg.function = QString(func);
logMsg.line = line;
logMsg.fileName = FileUtils::getBaseName(sourceFile);
@@ -225,19 +234,56 @@ void Logger::Message(LogLevel level, const char* sourceFile, const char* func, u
write(logMsg);
#ifndef _WIN32
if ( _syslogEnabled && level >= Logger::WARNING )
{
syslog (LogLevelSysLog[level], "%s", msg);
}
#endif
RepeatMessage.setLocalData(logMsg);
}
}
QScopedPointer<LoggerManager> LoggerManager::instance;
LoggerManager::LoggerManager()
: QObject()
, _loggerMaxMsgBufferSize(200)
, _loggerMaxMsgBufferSize(MAX_LOG_MSG_BUFFERED)
{
_logMessageBuffer.reserve(_loggerMaxMsgBufferSize);
}
LoggerManager::~LoggerManager()
{
// delete components
Logger::deleteInstance();
_logMessageBuffer.clear();
}
QJsonArray LoggerManager::getLogMessageBuffer(Logger::LogLevel filter) const
{
QJsonArray messageArray;
{
for (const auto &logLine : std::as_const(_logMessageBuffer))
{
if (logLine.level >= filter)
{
QJsonObject message;
message["loggerName"] = logLine.loggerName;
message["loggerSubName"] = logLine.loggerSubName;
message["function"] = logLine.function;
message["line"] = QString::number(logLine.line);
message["fileName"] = logLine.fileName;
message["message"] = logLine.message;
message["levelString"] = logLine.levelString;
message["utime"] = QString::number(logLine.utime);
messageArray.append(message);
}
}
}
return messageArray;
}
void LoggerManager::handleNewLogMessage(const Logger::T_LOG_MESSAGE & msg)
{
_logMessageBuffer.push_back(msg);
@@ -249,8 +295,12 @@ void LoggerManager::handleNewLogMessage(const Logger::T_LOG_MESSAGE & msg)
emit newLogMessage(msg);
}
LoggerManager* LoggerManager::getInstance()
QScopedPointer<LoggerManager>& LoggerManager::getInstance()
{
static LoggerManager instance;
return &instance;
if (!instance)
{
instance.reset(new LoggerManager());
}
return instance;
}

View File

@@ -1,13 +1,15 @@
#include <utils/NetOrigin.h>
#include <QJsonObject>
#include <QNetworkInterface>
NetOrigin* NetOrigin::instance = nullptr;
NetOrigin::NetOrigin(QObject* parent, Logger* log)
: QObject(parent)
, _log(log)
, _internetAccessAllowed(false)
, _isInternetAccessAllowed(false)
, _isInternetAccessRestricted(false)
, _ipWhitelist()
{
NetOrigin::instance = this;
@@ -15,37 +17,73 @@ NetOrigin::NetOrigin(QObject* parent, Logger* log)
bool NetOrigin::accessAllowed(const QHostAddress& address, const QHostAddress& local) const
{
if(_internetAccessAllowed)
return true;
bool isAllowed {false};
if(_ipWhitelist.contains(address)) // v4 and v6
return true;
if(!isLocalAddress(address, local))
if(isLocalAddress(address, local))
{
Warning(_log,"Client connection with IP address '%s' has been rejected! It's not whitelisted, access denied.",QSTRING_CSTR(address.toString()));
return false;
isAllowed = true;
}
return true;
else
{
if(_isInternetAccessAllowed)
{
if (!_isInternetAccessRestricted)
{
isAllowed = true;
}
else
{
for (const QHostAddress &listAddress : _ipWhitelist)
{
if (address.isEqual(listAddress))
{
isAllowed = true;
break;
}
}
WarningIf(!isAllowed, _log,"Client connection from IP address '%s' has been rejected! It's not whitelisted.",QSTRING_CSTR(address.toString()));
}
}
}
return isAllowed;
}
bool NetOrigin::isLocalAddress(const QHostAddress& address, const QHostAddress& local) const
bool NetOrigin::isLocalAddress(const QHostAddress& ipAddress, const QHostAddress& /*local*/) const
{
if(address.protocol() == QAbstractSocket::IPv4Protocol)
QHostAddress address = ipAddress;
if (address.isLoopback() || address.isLinkLocal())
{
if(!address.isInSubnet(local, 24)) // 255.255.255.xxx; IPv4 0-32
{
return false;
return true;
}
//Convert to IPv4 to check, if an IPv6 address is an IPv4 mapped address
QHostAddress ipv4Address(address.toIPv4Address());
if (ipv4Address != QHostAddress::AnyIPv4) // ipv4Address is not "0.0.0.0"
{
address = ipv4Address;
}
QList<QNetworkInterface> allInterfaces = QNetworkInterface::allInterfaces();
for (const QNetworkInterface &networkInterface : allInterfaces) {
QList<QNetworkAddressEntry> addressEntries = networkInterface.addressEntries();
for (const QNetworkAddressEntry &localNetworkAddressEntry : addressEntries) {
QHostAddress localIP = localNetworkAddressEntry.ip();
if(localIP.protocol() != QAbstractSocket::NetworkLayerProtocol::IPv4Protocol)
{
continue;
}
bool isInSubnet = address.isInSubnet(localIP, localNetworkAddressEntry.prefixLength());
if (isInSubnet)
{
return true;
}
}
}
else if(address.protocol() == QAbstractSocket::IPv6Protocol)
{
if(!address.isInSubnet(local, 64)) // 2001:db8:abcd:0012:XXXX:XXXX:XXXX:XXXX; IPv6 0-128
{
return false;
}
}
return true;
return false;
}
void NetOrigin::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
@@ -53,16 +91,19 @@ void NetOrigin::handleSettingsUpdate(settings::type type, const QJsonDocument& c
if(type == settings::NETWORK)
{
const QJsonObject& obj = config.object();
_internetAccessAllowed = obj["internetAccessAPI"].toBool(false);
_isInternetAccessAllowed = obj["internetAccessAPI"].toBool(false);
_isInternetAccessRestricted = obj["restirctedInternetAccessAPI"].toBool(false);
const QJsonArray arr = obj["ipWhitelist"].toArray();
const QJsonArray& arr = obj["ipWhitelist"].toArray();
_ipWhitelist.clear();
_ipWhitelist.clear();
for(const auto& e : arr)
for(const auto& item : std::as_const(arr))
{
const QString& entry = e.toString("");
const QString& entry = item.toString("");
if(entry.isEmpty())
{
continue;
}
QHostAddress host(entry);
if(host.isNull())

View File

@@ -1,93 +1,92 @@
#ifdef _WIN32
#include <QCoreApplication>
#include <QProcess>
#include <utils/Logger.h>
#include <QString>
#include <QByteArray>
namespace Process {
#include <QCoreApplication>
#include <QProcess>
#include <utils/Logger.h>
#include <QString>
#include <QByteArray>
void restartHyperion(int exitCode)
{
Logger* log = Logger::getInstance("Process");
Info(log, "Restarting hyperion ...");
namespace Process
{
void restartHyperion(int exitCode)
{
Logger* log = Logger::getInstance("Process");
Info(log, "Restarting hyperion ...");
auto arguments = QCoreApplication::arguments();
if (!arguments.contains("--wait-hyperion"))
arguments << "--wait-hyperion";
auto arguments = QCoreApplication::arguments();
if (!arguments.contains("--wait-hyperion"))
arguments << "--wait-hyperion";
QProcess::startDetached(QCoreApplication::applicationFilePath(), arguments);
QProcess::startDetached(QCoreApplication::applicationFilePath(), arguments);
//Exit with non-zero code to ensure service deamon restarts hyperion
QCoreApplication::exit(exitCode);
}
//Exit with non-zero code to ensure service deamon restarts hyperion
QCoreApplication::exit(exitCode);
}
QByteArray command_exec(const QString& /*cmd*/, const QByteArray& /*data*/)
{
return QSTRING_CSTR(QString());
}
};
QByteArray command_exec(const QString& /*cmd*/, const QByteArray& /*data*/)
{
return QSTRING_CSTR(QString());
}
};
#else
#include <utils/Process.h>
#include <utils/Logger.h>
#include <utils/Process.h>
#include <utils/Logger.h>
#include <QCoreApplication>
#include <QProcess>
#include <QStringList>
#include <QCoreApplication>
#include <QProcess>
#include <QStringList>
#include <unistd.h>
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <unistd.h>
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <csignal>
#include <csignal>
#include <QDebug>
#include <QMetaObject>
#include <QDebug>
#include <QMetaObject>
namespace Process {
void restartHyperion(int exitCode)
{
Logger* log = Logger::getInstance("Process");
Info(log, "Restarting hyperion ...");
std::cout << std::endl
<< " *******************************************" << std::endl
<< " * hyperion will restart now *" << std::endl
<< " *******************************************" << std::endl << std::endl;
auto arguments = QCoreApplication::arguments();
if (!arguments.contains("--wait-hyperion"))
arguments << "--wait-hyperion";
QProcess::startDetached(QCoreApplication::applicationFilePath(), arguments);
//Exit with non-zero code to ensure service deamon restarts hyperion
QCoreApplication::exit(exitCode);
}
QByteArray command_exec(const QString& cmd, const QByteArray& /*data*/)
{
char buffer[128];
QString result;
std::shared_ptr<FILE> pipe(popen(cmd.toLocal8Bit().constData(), "r"), pclose);
if (pipe)
namespace Process
{
while (!feof(pipe.get()))
void restartHyperion(int exitCode)
{
if (fgets(buffer, 128, pipe.get()) != nullptr)
result += buffer;
}
}
return QSTRING_CSTR(result);
}
Logger* log = Logger::getInstance("Process");
Info(log, "Restarting hyperion ...");
};
std::cout << std::endl
<< " *******************************************" << std::endl
<< " * hyperion will restart now *" << std::endl
<< " *******************************************" << std::endl << std::endl;
auto arguments = QCoreApplication::arguments();
if (!arguments.contains("--wait-hyperion"))
arguments << "--wait-hyperion";
QProcess::startDetached(QCoreApplication::applicationFilePath(), arguments);
//Exit with non-zero code to ensure service deamon restarts hyperion
QCoreApplication::exit(exitCode);
}
QByteArray command_exec(const QString& cmd, const QByteArray& /*data*/)
{
char buffer[128];
QString result;
std::shared_ptr<FILE> pipe(popen(cmd.toLocal8Bit().constData(), "r"), pclose);
if (pipe)
{
while (!feof(pipe.get()))
{
if (fgets(buffer, 128, pipe.get()) != nullptr)
result += buffer;
}
}
return QSTRING_CSTR(result);
}
};
#endif

View File

@@ -1,16 +1,14 @@
#include <utils/RgbChannelAdjustment.h>
RgbChannelAdjustment::RgbChannelAdjustment(QString channelName)
: _channelName(channelName)
, _log(Logger::getInstance(channelName))
, _brightness(0)
: RgbChannelAdjustment(0, 0, 0, channelName)
{
resetInitialized();
}
RgbChannelAdjustment::RgbChannelAdjustment(uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, QString channelName)
RgbChannelAdjustment::RgbChannelAdjustment(uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, QString channelName )
: _channelName(channelName)
, _log(Logger::getInstance(channelName))
, _log(Logger::getInstance("CHANNEL_" + channelName.toUpper()))
, _brightness(0)
{
setAdjustment(adjustR, adjustG, adjustB);
}

View File

@@ -2,13 +2,15 @@
#include <utils/RgbTransform.h>
RgbTransform::RgbTransform()
: RgbTransform::RgbTransform(1.0, 1.0, 1.0, 0.0, false, 100, 100)
{
init(1.0, 1.0, 1.0, 0.0, false, 100, 100);
}
RgbTransform::RgbTransform(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation)
: _brightness(brightness)
, _brightnessCompensation(brightnessCompensation)
{
init(gammaR, gammaG, gammaB, backlightThreshold, backlightColored, brightness, brightnessCompensation);
init(gammaR, gammaG, gammaB, backlightThreshold, backlightColored, _brightness, _brightnessCompensation);
}
void RgbTransform::init(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation)

View File

@@ -59,13 +59,13 @@ QPair<bool, bool> QJsonSchemaChecker::validate(const QJsonObject& value, bool ig
QJsonObject QJsonSchemaChecker::getAutoCorrectedConfig(const QJsonObject& value, bool ignoreRequired)
{
_ignoreRequired = ignoreRequired;
QStringList sequence = QStringList() << "remove" << "modify" << "create";
const QStringList sequence = QStringList() << "remove" << "modify" << "create";
_error = false;
_schemaError = false;
_messages.clear();
_autoCorrected = value;
for (const QString& correct : qAsConst(sequence))
for (const QString& correct : sequence)
{
_correct = correct;
_currentPath.clear();