fix: Move offset and clockwise logic to WledClient

This commit is contained in:
Tobias J. Endres 2025-08-16 15:40:21 +02:00
parent c8a0d2bc1e
commit c1f38cae1c
9 changed files with 1364 additions and 44611 deletions

3
.env
View File

@ -8,7 +8,8 @@ HYPERION_GRABBER_LEDS_BOTTOM="70"
HYPERION_GRABBER_LEDS_RIGHT="20"
HYPERION_GRABBER_LEDS_TOP="70"
HYPERION_GRABBER_LEDS_LEFT="20"
HYPERION_GRABBER_LED_OFFSET="0"
HYPERION_GRABBER_LED_OFFSET="30"
HYPERION_GRABBER_LED_CLOCKWISE="false"
HYPERION_GRABBER_BLACK_BORDER_THRESHOLD="0.2"
HYPERION_GRABBER_SMOOTHING_FACTOR="0.1"

View File

@ -9,9 +9,7 @@ HyperionProcessor::HyperionProcessor(const LedLayout &layout, const QJsonObject
_borderDetector(config.value("blackborderdetector").toObject()),
_lastImageSize(0, 0),
_colorSmoother(config.value("smoothing").toObject()),
_colorAlgorithm(config.value("colorAlgorithm").toString("mean_sqrt")),
_offset(config.value("offset").toInt(0)),
_clockwise(config.value("clockwise").toBool(false))
_colorAlgorithm(config.value("colorAlgorithm").toString("mean_sqrt"))
{
}
@ -44,17 +42,6 @@ QVector<QColor> HyperionProcessor::process(const QImage &image)
// 4. Apply smoothing
QVector<QColor> finalColors = _colorSmoother.smooth(calculatedColors);
// 5. Apply offset if needed
if (_offset != 0 && !finalColors.isEmpty()) {
QVector<QColor> shiftedColors(finalColors.size());
int totalLeds = finalColors.size();
for (int i = 0; i < totalLeds; ++i) {
shiftedColors[(i + _offset) % totalLeds] = finalColors[i];
}
return shiftedColors;
}
return finalColors;
}
@ -84,140 +71,74 @@ void HyperionProcessor::buildLedMap(int imageWidth, int imageHeight, const Black
int ledIndex = 0;
if (_clockwise) {
// Bottom LEDs (reversed)
for (int i = _layout.bottom - 1; i >= 0; --i, ++ledIndex) {
double hScanStart = double(i) / _layout.bottom;
double hScanEnd = double(i + 1) / _layout.bottom;
int xStart = border.verticalSize + int(hScanStart * contentWidth);
int xEnd = border.verticalSize + int(hScanEnd * contentWidth);
int yStart = border.horizontalSize + contentHeight - hSamplingThickness;
int yEnd = border.horizontalSize + contentHeight;
// Bottom LEDs
for (int i = 0; i < _layout.bottom; ++i, ++ledIndex) {
double hScanStart = double(i) / _layout.bottom;
double hScanEnd = double(i + 1) / _layout.bottom;
int xStart = border.verticalSize + int(hScanStart * contentWidth);
int xEnd = border.verticalSize + int(hScanEnd * contentWidth);
int yStart = border.horizontalSize + contentHeight - hSamplingThickness; // Sample from bottom region
int yEnd = border.horizontalSize + contentHeight; // To the very bottom
for (int x = xStart; x < xEnd; ++x) {
for (int y = yStart; y < yEnd; ++y) {
_ledMap[ledIndex].append(QPoint(x, y));
}
qDebug() << "LED" << ledIndex << ": xStart=" << xStart << "xEnd=" << xEnd << "yStart=" << yStart << "yEnd=" << yEnd;
for (int x = xStart; x < xEnd; ++x) {
for (int y = yStart; y < yEnd; ++y) {
_ledMap[ledIndex].append(QPoint(x, y));
}
}
}
// Left LEDs (reversed)
for (int i = _layout.left - 1; i >= 0; --i, ++ledIndex) {
double vScanStart = double(i) / _layout.left;
double vScanEnd = double(i + 1) / _layout.left;
int yStart = border.horizontalSize + int(vScanStart * contentHeight);
int yEnd = border.horizontalSize + int(vScanEnd * contentHeight);
int xStart = border.verticalSize;
int xEnd = border.verticalSize + vSamplingThickness;
// Right LEDs
for (int i = 0; i < _layout.right; ++i, ++ledIndex) {
double vScanStart = double(i) / _layout.right;
double vScanEnd = double(i + 1) / _layout.right;
int yStart = border.horizontalSize + int((1.0 - vScanEnd) * contentHeight); // Sample from top of region
int yEnd = border.horizontalSize + int((1.0 - vScanStart) * contentHeight); // To bottom of region
int xStart = border.verticalSize + contentWidth - vSamplingThickness; // Sample from rightmost region
int xEnd = border.verticalSize + contentWidth; // To the very right
for (int x = xStart; x < xEnd; ++x) {
for (int y = yStart; y < yEnd; ++y) {
_ledMap[ledIndex].append(QPoint(x, y));
}
qDebug() << "LED" << ledIndex << ": xStart=" << xStart << "xEnd=" << xEnd << "yStart=" << yStart << "yEnd=" << yEnd;
for (int x = xStart; x < xEnd; ++x) {
for (int y = yStart; y < yEnd; ++y) {
_ledMap[ledIndex].append(QPoint(x, y));
}
}
}
// Top LEDs (reversed)
for (int i = _layout.top - 1; i >= 0; --i, ++ledIndex) {
double hScanStart = double(i) / _layout.top;
double hScanEnd = double(i + 1) / _layout.top;
int xStart = border.verticalSize + int((1.0 - hScanEnd) * contentWidth);
int xEnd = border.verticalSize + int((1.0 - hScanStart) * contentWidth);
int yStart = border.horizontalSize;
int yEnd = border.horizontalSize + hSamplingThickness;
// Top LEDs
for (int i = 0; i < _layout.top; ++i, ++ledIndex) {
double hScanStart = double(i) / _layout.top;
double hScanEnd = double(i + 1) / _layout.top;
int xStart = border.verticalSize + int((1.0 - hScanEnd) * contentWidth); // Sample from right of region
int xEnd = border.verticalSize + int((1.0 - hScanStart) * contentWidth); // To left of region
int yStart = border.horizontalSize; // Sample from top region
int yEnd = border.horizontalSize + hSamplingThickness; // To bottom of region
for (int x = xStart; x < xEnd; ++x) {
for (int y = yStart; y < yEnd; ++y) {
_ledMap[ledIndex].append(QPoint(x, y));
}
qDebug() << "LED" << ledIndex << ": xStart=" << xStart << "xEnd=" << xEnd << "yStart=" << yStart << "yEnd=" << yEnd;
for (int x = xStart; x < xEnd; ++x) {
for (int y = yStart; y < yEnd; ++y) {
_ledMap[ledIndex].append(QPoint(x, y));
}
}
}
// Right LEDs (reversed)
for (int i = _layout.right - 1; i >= 0; --i, ++ledIndex) {
double vScanStart = double(i) / _layout.right;
double vScanEnd = double(i + 1) / _layout.right;
int yStart = border.horizontalSize + int((1.0 - vScanEnd) * contentHeight);
int yEnd = border.horizontalSize + int((1.0 - vScanStart) * contentHeight);
int xStart = border.verticalSize + contentWidth - vSamplingThickness;
int xEnd = border.verticalSize + contentWidth;
// Left LEDs
for (int i = 0; i < _layout.left; ++i, ++ledIndex) {
double vScanStart = double(i) / _layout.left;
double vScanEnd = double(i + 1) / _layout.left;
int yStart = border.horizontalSize + int(vScanStart * contentHeight); // Sample from top of region
int yEnd = border.horizontalSize + int(vScanEnd * contentHeight); // To bottom of region
int xStart = border.verticalSize; // Sample leftmost region
int xEnd = border.verticalSize + vSamplingThickness; // To right of region
for (int x = xStart; x < xEnd; ++x) {
for (int y = yStart; y < yEnd; ++y) {
_ledMap[ledIndex].append(QPoint(x, y));
}
}
}
} else { // Counter-clockwise (original logic)
// Bottom LEDs
for (int i = 0; i < _layout.bottom; ++i, ++ledIndex) {
double hScanStart = double(i) / _layout.bottom;
double hScanEnd = double(i + 1) / _layout.bottom;
int xStart = border.verticalSize + int(hScanStart * contentWidth);
int xEnd = border.verticalSize + int(hScanEnd * contentWidth);
int yStart = border.horizontalSize + contentHeight - hSamplingThickness; // Sample from bottom region
int yEnd = border.horizontalSize + contentHeight; // To the very bottom
qDebug() << "LED" << ledIndex << ": xStart=" << xStart << "xEnd=" << xEnd << "yStart=" << yStart << "yEnd=" << yEnd;
qDebug() << "LED" << ledIndex << ": xStart=" << xStart << "xEnd=" << xEnd << "yStart=" << yStart << "yEnd=" << yEnd;
for (int x = xStart; x < xEnd; ++x) {
for (int y = yStart; y < yEnd; ++y) {
_ledMap[ledIndex].append(QPoint(x, y));
}
}
}
// Right LEDs
for (int i = 0; i < _layout.right; ++i, ++ledIndex) {
double vScanStart = double(i) / _layout.right;
double vScanEnd = double(i + 1) / _layout.right;
int yStart = border.horizontalSize + int((1.0 - vScanEnd) * contentHeight); // Sample from top of region
int yEnd = border.horizontalSize + int((1.0 - vScanStart) * contentHeight); // To bottom of region
int xStart = border.verticalSize + contentWidth - vSamplingThickness; // Sample from rightmost region
int xEnd = border.verticalSize + contentWidth; // To the very right
qDebug() << "LED" << ledIndex << ": xStart=" << xStart << "xEnd=" << xEnd << "yStart=" << yStart << "yEnd=" << yEnd;
for (int x = xStart; x < xEnd; ++x) {
for (int y = yStart; y < yEnd; ++y) {
_ledMap[ledIndex].append(QPoint(x, y));
}
}
}
// Top LEDs
for (int i = 0; i < _layout.top; ++i, ++ledIndex) {
double hScanStart = double(i) / _layout.top;
double hScanEnd = double(i + 1) / _layout.top;
int xStart = border.verticalSize + int((1.0 - hScanEnd) * contentWidth); // Sample from right of region
int xEnd = border.verticalSize + int((1.0 - hScanStart) * contentWidth); // To left of region
int yStart = border.horizontalSize; // Sample from top region
int yEnd = border.horizontalSize + hSamplingThickness; // To bottom of region
qDebug() << "LED" << ledIndex << ": xStart=" << xStart << "xEnd=" << xEnd << "yStart=" << yStart << "yEnd=" << yEnd;
for (int x = xStart; x < xEnd; ++x) {
for (int y = yStart; y < yEnd; ++y) {
_ledMap[ledIndex].append(QPoint(x, y));
}
}
}
// Left LEDs
for (int i = 0; i < _layout.left; ++i, ++ledIndex) {
double vScanStart = double(i) / _layout.left;
double vScanEnd = double(i + 1) / _layout.left;
int yStart = border.horizontalSize + int(vScanStart * contentHeight); // Sample from top of region
int yEnd = border.horizontalSize + int(vScanEnd * contentHeight); // To bottom of region
int xStart = border.verticalSize; // Sample leftmost region
int xEnd = border.verticalSize + vSamplingThickness; // To right of region
qDebug() << "LED" << ledIndex << ": xStart=" << xStart << "xEnd=" << xEnd << "yStart=" << yStart << "yEnd=" << yEnd;
for (int x = xStart; x < xEnd; ++x) {
for (int y = yStart; y < yEnd; ++y) {
_ledMap[ledIndex].append(QPoint(x, y));
}
for (int x = xStart; x < xEnd; ++x) {
for (int y = yStart; y < yEnd; ++y) {
_ledMap[ledIndex].append(QPoint(x, y));
}
}
}

View File

@ -29,8 +29,6 @@ private:
LedLayout _layout;
QJsonObject _config;
QString _colorAlgorithm;
int _offset;
bool _clockwise;
BlackBorderDetector _borderDetector;
BlackBorder _lastBorder;

Binary file not shown.

View File

@ -1006,100 +1006,25 @@ Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.1/include/stdarg.h \
/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.1/include/stdbool.h \
/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.1/include/stddef.h \
/usr/share/cmake/Modules/CMakeCCompiler.cmake.in \
/usr/share/cmake/Modules/CMakeCCompilerABI.c \
/usr/share/cmake/Modules/CMakeCInformation.cmake \
/usr/share/cmake/Modules/CMakeCXXCompiler.cmake.in \
/usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp \
/usr/share/cmake/Modules/CMakeCXXInformation.cmake \
/usr/share/cmake/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake \
/usr/share/cmake/Modules/CMakeCommonLanguageInclude.cmake \
/usr/share/cmake/Modules/CMakeCompilerIdDetection.cmake \
/usr/share/cmake/Modules/CMakeDetermineCCompiler.cmake \
/usr/share/cmake/Modules/CMakeDetermineCXXCompiler.cmake \
/usr/share/cmake/Modules/CMakeDetermineCompiler.cmake \
/usr/share/cmake/Modules/CMakeDetermineCompilerABI.cmake \
/usr/share/cmake/Modules/CMakeDetermineCompilerId.cmake \
/usr/share/cmake/Modules/CMakeDetermineCompilerSupport.cmake \
/usr/share/cmake/Modules/CMakeDetermineSystem.cmake \
/usr/share/cmake/Modules/CMakeFindBinUtils.cmake \
/usr/share/cmake/Modules/CMakeFindDependencyMacro.cmake \
/usr/share/cmake/Modules/CMakeGenericSystem.cmake \
/usr/share/cmake/Modules/CMakeInitializeConfigs.cmake \
/usr/share/cmake/Modules/CMakeLanguageInformation.cmake \
/usr/share/cmake/Modules/CMakeParseImplicitIncludeInfo.cmake \
/usr/share/cmake/Modules/CMakeParseImplicitLinkInfo.cmake \
/usr/share/cmake/Modules/CMakeParseLibraryArchitecture.cmake \
/usr/share/cmake/Modules/CMakeSystem.cmake.in \
/usr/share/cmake/Modules/CMakeSystemSpecificInformation.cmake \
/usr/share/cmake/Modules/CMakeSystemSpecificInitialize.cmake \
/usr/share/cmake/Modules/CMakeTestCCompiler.cmake \
/usr/share/cmake/Modules/CMakeTestCXXCompiler.cmake \
/usr/share/cmake/Modules/CMakeTestCompilerCommon.cmake \
/usr/share/cmake/Modules/CMakeUnixFindMake.cmake \
/usr/share/cmake/Modules/CheckCSourceCompiles.cmake \
/usr/share/cmake/Modules/CheckCXXCompilerFlag.cmake \
/usr/share/cmake/Modules/CheckCXXSourceCompiles.cmake \
/usr/share/cmake/Modules/CheckIncludeFile.cmake \
/usr/share/cmake/Modules/CheckLibraryExists.cmake \
/usr/share/cmake/Modules/Compiler/ADSP-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/ARMCC-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/ARMClang-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/AppleClang-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/Borland-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/Bruce-C-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/CMakeCommonCompilerMacros.cmake \
/usr/share/cmake/Modules/Compiler/Clang-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/Clang-DetermineCompilerInternal.cmake \
/usr/share/cmake/Modules/Compiler/Compaq-C-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/Compaq-CXX-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/Cray-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/CrayClang-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/Embarcadero-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/Fujitsu-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/GHS-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/GNU-C-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/GNU-C.cmake \
/usr/share/cmake/Modules/Compiler/GNU-CXX-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/GNU-CXX.cmake \
/usr/share/cmake/Modules/Compiler/GNU-FindBinUtils.cmake \
/usr/share/cmake/Modules/Compiler/GNU.cmake \
/usr/share/cmake/Modules/Compiler/HP-C-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/HP-CXX-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/IAR-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/IBMCPP-C-DetermineVersionInternal.cmake \
/usr/share/cmake/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake \
/usr/share/cmake/Modules/Compiler/IBMClang-C-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/IBMClang-CXX-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/Intel-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/LCC-C-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/LCC-CXX-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/MSVC-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/NVHPC-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/NVIDIA-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/OrangeC-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/PGI-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/PathScale-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/SCO-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/SDCC-C-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/SunPro-C-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/SunPro-CXX-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/TI-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/TIClang-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/Tasking-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/TinyCC-C-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/VisualAge-C-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/VisualAge-CXX-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/Watcom-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/XL-C-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/XL-CXX-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/XLClang-C-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/zOS-C-DetermineCompiler.cmake \
/usr/share/cmake/Modules/Compiler/zOS-CXX-DetermineCompiler.cmake \
/usr/share/cmake/Modules/FeatureSummary.cmake \
/usr/share/cmake/Modules/FindOpenGL.cmake \
/usr/share/cmake/Modules/FindPackageHandleStandardArgs.cmake \
@ -1111,13 +1036,9 @@ Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/usr/share/cmake/Modules/Internal/CMakeCLinkerInformation.cmake \
/usr/share/cmake/Modules/Internal/CMakeCXXLinkerInformation.cmake \
/usr/share/cmake/Modules/Internal/CMakeCommonLinkerInformation.cmake \
/usr/share/cmake/Modules/Internal/CMakeDetermineLinkerId.cmake \
/usr/share/cmake/Modules/Internal/CMakeInspectCLinker.cmake \
/usr/share/cmake/Modules/Internal/CMakeInspectCXXLinker.cmake \
/usr/share/cmake/Modules/Internal/CheckCompilerFlag.cmake \
/usr/share/cmake/Modules/Internal/CheckFlagCommonConfig.cmake \
/usr/share/cmake/Modules/Internal/CheckSourceCompiles.cmake \
/usr/share/cmake/Modules/Internal/FeatureTesting.cmake \
/usr/share/cmake/Modules/Linker/GNU-C.cmake \
/usr/share/cmake/Modules/Linker/GNU-CXX.cmake \
/usr/share/cmake/Modules/Linker/GNU.cmake \
@ -1126,7 +1047,6 @@ Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/usr/share/cmake/Modules/Platform/Linker/Linux-GNU-C.cmake \
/usr/share/cmake/Modules/Platform/Linker/Linux-GNU-CXX.cmake \
/usr/share/cmake/Modules/Platform/Linker/Linux-GNU.cmake \
/usr/share/cmake/Modules/Platform/Linux-Determine-CXX.cmake \
/usr/share/cmake/Modules/Platform/Linux-GNU-C.cmake \
/usr/share/cmake/Modules/Platform/Linux-GNU-CXX.cmake \
/usr/share/cmake/Modules/Platform/Linux-GNU.cmake \

View File

@ -181,15 +181,14 @@ int main(int argc, char *argv[])
processorConfig["blackborderdetector"] = blackBorderDetectorConfig;
processorConfig["smoothing"] = smoothingConfig;
processorConfig["colorAlgorithm"] = qgetenv("HYPERION_GRABBER_COLOR_ALGORITHM").isEmpty() ? QString("mean_sqrt") : QString(qgetenv("HYPERION_GRABBER_COLOR_ALGORITHM"));
processorConfig["offset"] = qgetenv("HYPERION_GRABBER_LED_OFFSET").isEmpty() ? 0 : qgetenv("HYPERION_GRABBER_LED_OFFSET").toInt();
processorConfig["clockwise"] = qgetenv("HYPERION_GRABBER_LED_CLOCKWISE").isEmpty() ? false : (qgetenv("HYPERION_GRABBER_LED_CLOCKWISE").toLower() == "true");
processorConfig["offset"] = qgetenv("HYPERION_GRABBER_OFFSET").isEmpty() ? 0 : qgetenv("HYPERION_GRABBER_OFFSET").toInt();
QString wledColorOrder = qgetenv("HYPERION_GRABBER_WLED_COLOR_ORDER").isEmpty() ? QString("GRB") : QString(qgetenv("HYPERION_GRABBER_WLED_COLOR_ORDER"));
// Instantiate components
grabber = new HyperionGrabber(grabberOpts);
processor = new HyperionProcessor(layout, processorConfig);
wledClient = new WledClient(wledAddress, wledPort, wledColorOrder);
wledClient = new WledClient(wledAddress, wledPort, wledColorOrder, processorConfig["offset"].toInt(), processorConfig["clockwise"].toBool());
// Connect grabber to image receiver slot
QObject::connect(grabber, &HyperionGrabber::imageReady, &onImageReady);

45651
output.log

File diff suppressed because it is too large Load Diff

View File

@ -12,14 +12,16 @@ const quint8 DDP_PROTOCOL_DNRGB = 4;
// 4 bytes for DDP header, so 504 bytes for LED data
const int MAX_LED_DATA_PER_PACKET = 504; // 504 bytes / 3 bytes per LED = 168 LEDs
WledClient::WledClient(QString host, ushort port, QString colorOrder, QObject *parent) :
WledClient::WledClient(QString host, ushort port, QString colorOrder, int offset, bool clockwise, QObject *parent) :
QObject(parent),
_wledHost(host),
_wledPort(port),
_colorOrder(colorOrder)
_colorOrder(colorOrder),
_offset(offset),
_clockwise(clockwise)
{
_udpSocket = new QUdpSocket(this);
qDebug() << "WledClient initialized for host:" << _wledHost.toString() << "port:" << _wledPort << "color order:" << _colorOrder;
qDebug() << "WledClient initialized for host:" << _wledHost.toString() << "port:" << _wledPort << "color order:" << _colorOrder << "offset:" << _offset << "clockwise:" << _clockwise;
}
WledClient::~WledClient()
@ -84,7 +86,10 @@ void WledClient::sendImage(const QImage &image)
int y = pixelIndex / rgbImage.width();
QRgb pixel = rgbImage.pixel(x, y);
appendColor(datagram, QColor(pixel));
// Swap R and G for GRB order
datagram.append(qRed(pixel));
datagram.append(qGreen(pixel));
datagram.append(qBlue(pixel));
}
qint64 bytesSent = _udpSocket->writeDatagram(datagram, _wledHost, _wledPort);
@ -104,6 +109,26 @@ void WledClient::setLedsColor(const QVector<QColor> &colors, int timeout)
}
int totalLeds = colors.size();
QVector<QColor> processedColors(totalLeds);
// Apply clockwise reversal if needed
if (_clockwise) {
for (int i = 0; i < totalLeds; ++i) {
processedColors[i] = colors[totalLeds - 1 - i];
}
} else {
processedColors = colors;
}
// Apply offset
if (_offset != 0) {
QVector<QColor> shiftedColors(totalLeds);
for (int i = 0; i < totalLeds; ++i) {
shiftedColors[(i + _offset) % totalLeds] = processedColors[i];
}
processedColors = shiftedColors;
}
int ledsPerPacket = MAX_LED_DATA_PER_PACKET / 3; // 3 bytes per LED (RGB)
qDebug() << "WledClient: setLedsColor - totalLeds:" << totalLeds << "ledsPerPacket:" << ledsPerPacket;
@ -127,7 +152,7 @@ void WledClient::setLedsColor(const QVector<QColor> &colors, int timeout)
qDebug() << "WledClient: Sending packet (setLedsColor) - i:" << i << "startIndex:" << startIndex << "currentLedsInPacket:" << currentLedsInPacket;
for (int j = 0; j < currentLedsInPacket; ++j) {
const QColor &color = colors.at(i + j);
const QColor &color = processedColors.at(i + j);
appendColor(datagram, color);
}
@ -170,7 +195,10 @@ void WledClient::flashLeds(int startIndex, int count, QColor color)
int currentLedsInPacket = qMin(ledsPerPacket, count - i);
for (int j = 0; j < currentLedsInPacket; ++j) {
appendColor(datagram, color);
// Swap R and G for GRB order
datagram.append(color.red());
datagram.append(color.green());
datagram.append(color.blue());
}
qDebug() << "WledClient: Sending flashLeds datagram (hex):" << datagram.toHex();

View File

@ -11,7 +11,7 @@ class WledClient : public QObject
Q_OBJECT
public:
explicit WledClient(QString host, ushort port, QString colorOrder = "GRB", QObject *parent = nullptr);
explicit WledClient(QString host, ushort port, QString colorOrder = "GRB", int offset = 0, bool clockwise = false, QObject *parent = nullptr);
~WledClient();
void sendImage(const QImage &image);
@ -20,11 +20,12 @@ public:
private:
void appendColor(QByteArray &datagram, const QColor &color);
QUdpSocket *_udpSocket;
QHostAddress _wledHost;
ushort _wledPort;
QString _colorOrder;
int _offset;
bool _clockwise;
signals:
void error(QString message);