Various Cleanups (#1075)

* LedDevice - Address clang findings

* Fix Windows Warnings

* Ensure newInput is initialised

* Clean-up unused elements for Plaform Capture

* Fix initialization problem and spellings

* Address clang findings and spelling corrections

* LedDevice clean-ups

* Cleanups

* Align that getLedCount is int

* Have "display" as default for Grabbers

* Fix config during start-up for missing elements

* Framegrabber Clean-up - Remove non supported grabbers from selection, filter valid options

* Typo

* Framegrabber.json - Fix property numbering

* Preselect active Grabbertype

* Sort Grabbernames

* Align options with selected element

* Fix deletion of pointer to incomplete type 'BonjourBrowserWrapper'

* Address macOS compile warnings

* Have default layout = 1 LED only to avoid errors as in #673

* Address lgtm findings

* Address finding that params passed to LedDevice discovery were not considered

* Cleanups after merging with latest master

* Update Changelog

* Address lgtm findings

* Fix comment

* Test Fix

* Fix Python Warning

* Handle Dummy Device assignment correctly

* Address delete called on non-final 'commandline::Option' that has virtual functions but non-virtual destructor

* Correct that QTimer.start accepts only int

* Have Release Python GIL & reset threat state chnage downward compatible

* Correct format specifier

* LedDevice - add assertions

* Readonly DB - Fix merge issue

* Smoothing - Fix wrong defaults

* LedDevice - correct assertion

* Show smoothing config set# in debug and related values.

* Suppress error on windows, if default file is "/dev/null"

* CMAKE - Allow to define QT_BASE_DIR dynamically via environment-variable

* Ignore Visual Studio specific files

Co-authored-by: Paulchen Panther <16664240+Paulchen-Panther@users.noreply.github.com>
This commit is contained in:
LordGrey 2020-11-14 17:58:56 +01:00 committed by GitHub
parent d28540a7fe
commit efc2046ab5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
93 changed files with 1140 additions and 1172 deletions

4
.gitignore vendored
View File

@ -25,3 +25,7 @@ libsrc/flatbufserver/hyperion_request_generated.h
# Kdevelop project files # Kdevelop project files
*.kdev* *.kdev*
# Visual Studio 2015/2017/2019 cache/options directory
.vs/
CMakeSettings.json

View File

@ -9,20 +9,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Breaking ### Breaking
### Added ### Added
- Cololight support (Cololight Plus & Strip) incl. configuration wizard - Grabber: DirectX9 support (#1039)
- Provide additional details on Hardware/CPU information
- Allow execution with option "--version", while another hyperion daemon is running
- New language support: Russian and Chinese (simplified) (#1005)
- Added libcec to deb/rpm dependency list
- Updated some language files
- New LED Device SK9822 (#1005)
- Support SK9822 type LEDs with adaptive brightness control via SPI (#1017)
- Provide additional details on Hardware/CPU information (#1045)
- Allow execution with option "--version", while another hyperion daemon is running
- New blackbar detection mode "Letterbox", that considers only bars at the top and bottom of picture - New blackbar detection mode "Letterbox", that considers only bars at the top and bottom of picture
- Systray icons added - Issue #925 (#1040)
- DirectX9 Grabber (#1039) - LED-Devices: Cololight support (Cololight Plus & Strip) incl. configuration wizard
- Added DirectX SDK to CompileHowto - LED-Devices: SK9822 support (#1005,#1017)
- UX: New language support: Russian and Chinese (simplified) (#1005)
- UX: Additional details on Hardware/CPU information (#1045)
- UX: Systray icons added - Issue #925 (#1040)
- Read-Only configuration database support
- Hide Window Systray icon on Hyperion exit & Install DirectX Redistributable - Hide Window Systray icon on Hyperion exit & Install DirectX Redistributable
- Read-Only configuration database support - Read-Only configuration database support
@ -30,26 +27,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- boblight: reduce cpu time spent on memcopy and parsing rgb values (#1016) - boblight: reduce cpu time spent on memcopy and parsing rgb values (#1016)
- Windows Installer/Uninstaller notification when Hyperion is running (#1033) - Windows Installer/Uninstaller notification when Hyperion is running (#1033)
- Updated Windows Dependencies - Updated Windows Dependencies
- Documentation: Optimized images (#1058)
- UX: Default LED-layout is now one LED only to avoid errors as in #673
- UX: Change links from http to https (#1067)
- Change links from http to https (#1067)
- Cleanup packages.cmake & extend NSIS plugin directory - Cleanup packages.cmake & extend NSIS plugin directory
- Optimize images (#1058) - Optimize images (#1058)
- Update LICENSE
- Change links from http to https (#1067)
- UI: Separate LED-Layout creation from UI code
- Docs: Refreshed EN JSON API documentation - Docs: Refreshed EN JSON API documentation
### Fixed ### Fixed
- Properly save Hue light state between sessions (#1014) - Color calibration for Kodi 18 (#1044)
- AVAHI included in Webserver (#996) - LED-Devices: Karatelight, allow an 8-LED configuration (#1037)
- Also allow an 8-LED configuration when using Karatelight (#1037) - LED-Devices: Save Hue light state between sessions (#1014)
- Fix #1007 - LED's retain last state after clearing a source (#1008) - LED-Devices: LED's retain last state after clearing a source (#1008)
- Fix Lightpack issue #1015 (#1049) - LED-Devices: Lightpack issue #1015 (#1049)
- Fix #771 color calibration for Kodi 18 (#1044)
- Fix various JSON API issues (#1036) - Fix various JSON API issues (#1036)
- Fix issue #909, Have ratio correction first and then scale (#1047) - Fix issue #909, Have ratio correction first and then scale (#1047)
- Fix display argument in hyperion-qt (#1027) - Fix display argument in hyperion-qt (#1027)
- Fix typos (#1051)
- Fix Python reset thread state - Fix Python reset thread state
- AVAHI included in Webserver (#996)
- Fix add libcec to deb/rpm dependency list
- Fix Hyperion configuration is corrected during start-up, if required
### Removed ### Removed
- Replace Multi-Lightpack by multi-instance Lightpack configuration (#1049) - Replace Multi-Lightpack by multi-instance Lightpack configuration (#1049)

View File

@ -302,13 +302,41 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
# Qt5 default install path with msvc2017 64bit component # Qt5 default install path with msvc2017 64bit component
# The Qt5_DIR should point to Qt5Config.cmake -> C:/Qt/5.xx/msvc2017_64/lib/cmake/Qt5 # The Qt5_DIR should point to Qt5Config.cmake -> C:/Qt/5.xx/msvc2017_64/lib/cmake/Qt5
# The CMAKE_PREFIX_PATH should point to the install directory -> C:/Qt/5.xx/msvc2017_64 # The CMAKE_PREFIX_PATH should point to the install directory -> C:/Qt/5.xx/msvc2017_64
FIRSTSUBDIR(SUBDIRQT "C:/Qt") #
SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "${SUBDIRQT}/msvc2019_64") # Alternatively, use Qt5_BASE_DIR environment variable to point to Qt version to be used
if (NOT DEFINED ENV{Qt5_DIR}) # In MSVC19 add into CMakeSettings.json
message(STATUS "Set Qt5 module path: ${SUBDIRQT}") #
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${SUBDIRQT}/msvc2019_64/lib/cmake/Qt5") # "environments": [
# {
# "Qt5_BASE_DIR": "D:/Qt/5.15.1/msvc2019_64"
# }
# ]
if (NOT DEFINED ENV{Qt5_BASE_DIR})
FIRSTSUBDIR(SUBDIRQT "C:/Qt")
SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "${SUBDIRQT}/msvc2019_64")
else()
message(STATUS "Qt5_BASE_DIR: $ENV{Qt5_BASE_DIR}")
message(STATUS "Add Qt5_BASE_DIR: $ENV{Qt5_BASE_DIR} to CMAKE_PREFIX_PATH")
SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "$ENV{Qt5_BASE_DIR}")
endif() endif()
if (NOT DEFINED ENV{Qt5_DIR})
if (NOT DEFINED ENV{Qt5_BASE_DIR})
SET (qt_module_path "${SUBDIRQT}/msvc2019_64/lib/cmake/Qt5")
else ()
SET (qt_module_path "$ENV{Qt5_BASE_DIR}/lib/cmake/Qt5")
endif()
else()
SET (qt_module_path "$ENV{Qt5_DIR}")
endif()
message(STATUS "Add ${qt_module_path} to CMAKE_MODULE_PATH")
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${qt_module_path}")
#message(STATUS "CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}")
#message(STATUS "CMAKE_MODULE_PATH: ${CMAKE_MODULE_PATH}")
# Search for DirectX9 # Search for DirectX9
if (ENABLE_DX) if (ENABLE_DX)
find_package(DirectX9 REQUIRED) find_package(DirectX9 REQUIRED)

View File

@ -21,6 +21,7 @@ import socket
import serial import serial
import serial.threaded import serial.threaded
from __future__ import division
class SerialToNet(serial.threaded.Protocol): class SerialToNet(serial.threaded.Protocol):
"""serial->socket""" """serial->socket"""
@ -152,7 +153,7 @@ to this service over the network.
srv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) srv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(('', args.localport)) srv.bind(('0.0.0.0', args.localport))
try: try:
intentional_exit = False intentional_exit = False

View File

@ -50,7 +50,7 @@
<label class="ltdlabel" for="ip_cl_top" data-i18n="conf_leds_layout_cl_top">Top</label> <label class="ltdlabel" for="ip_cl_top" data-i18n="conf_leds_layout_cl_top">Top</label>
</td> </td>
<td class="itd input-group"> <td class="itd input-group">
<input class="form-control ledCLconstr " id="ip_cl_top" type="number" value="10" min="0" step="1"></input> <input class="form-control ledCLconstr " id="ip_cl_top" type="number" value="1" min="0" step="1"></input>
<div class="input-group-addon" data-i18n="edt_append_leds">LEDs</div> <div class="input-group-addon" data-i18n="edt_append_leds">LEDs</div>
</td> </td>
</tr> </tr>
@ -59,7 +59,7 @@
<label class="ltdlabel" for="ip_cl_bottom" data-i18n="conf_leds_layout_cl_bottom">Bottom</label> <label class="ltdlabel" for="ip_cl_bottom" data-i18n="conf_leds_layout_cl_bottom">Bottom</label>
</td> </td>
<td class="itd input-group"> <td class="itd input-group">
<input class="form-control ledCLconstr" id="ip_cl_bottom" type="number" value="10" min="0" step="1"></input> <input class="form-control ledCLconstr" id="ip_cl_bottom" type="number" value="0" min="0" step="1"></input>
<div class="input-group-addon" data-i18n="edt_append_leds">LEDs</div> <div class="input-group-addon" data-i18n="edt_append_leds">LEDs</div>
</td> </td>
</tr> </tr>
@ -68,7 +68,7 @@
<label class="ltdlabel" for="ip_cl_left" data-i18n="conf_leds_layout_cl_left">Left</label> <label class="ltdlabel" for="ip_cl_left" data-i18n="conf_leds_layout_cl_left">Left</label>
</td> </td>
<td class="itd input-group"> <td class="itd input-group">
<input class="form-control ledCLconstr" id="ip_cl_left" type="number" value="6" min="0" step="1"></input> <input class="form-control ledCLconstr" id="ip_cl_left" type="number" value="0" min="0" step="1"></input>
<div class="input-group-addon" data-i18n="edt_append_leds">LEDs</div> <div class="input-group-addon" data-i18n="edt_append_leds">LEDs</div>
</td> </td>
</tr> </tr>
@ -77,7 +77,7 @@
<label class="ltdlabel" for="ip_cl_right" data-i18n="conf_leds_layout_cl_right">Right</label> <label class="ltdlabel" for="ip_cl_right" data-i18n="conf_leds_layout_cl_right">Right</label>
</td> </td>
<td class="itd input-group"> <td class="itd input-group">
<input class="form-control ledCLconstr" id="ip_cl_right" type="number" value="6" min="0" step="1"></input> <input class="form-control ledCLconstr" id="ip_cl_right" type="number" value="0" min="0" step="1"></input>
<div class="input-group-addon" data-i18n="edt_append_leds">LEDs</div> <div class="input-group-addon" data-i18n="edt_append_leds">LEDs</div>
</td> </td>
</tr> </tr>
@ -266,7 +266,7 @@
<label class="ltdlabel" for="ip_ma_ledshoriz" data-i18n="conf_leds_layout_ma_horiz">Horizontal</label> <label class="ltdlabel" for="ip_ma_ledshoriz" data-i18n="conf_leds_layout_ma_horiz">Horizontal</label>
</td> </td>
<td class="itd input-group"> <td class="itd input-group">
<input class="form-control ledMAconstr" id="ip_ma_ledshoriz" type="number" value="10" min="1" step="1"></input> <input class="form-control ledMAconstr" id="ip_ma_ledshoriz" type="number" value="1" min="1" step="1"></input>
<div class="input-group-addon" data-i18n="edt_append_leds">LEDs</div> <div class="input-group-addon" data-i18n="edt_append_leds">LEDs</div>
</td> </td>
</tr> </tr>
@ -275,7 +275,7 @@
<label class="ltdlabel" for="ip_ma_ledsvert" data-i18n="conf_leds_layout_ma_vert">Vertical</label> <label class="ltdlabel" for="ip_ma_ledsvert" data-i18n="conf_leds_layout_ma_vert">Vertical</label>
</td> </td>
<td class="itd input-group"> <td class="itd input-group">
<input class="form-control ledMAconstr" id="ip_ma_ledsvert" type="number" value="10" min="1" step="1"></input> <input class="form-control ledMAconstr" id="ip_ma_ledsvert" type="number" value="1" min="1" step="1"></input>
<div class="input-group-addon" data-i18n="edt_append_leds">LEDs</div> <div class="input-group-addon" data-i18n="edt_append_leds">LEDs</div>
</td> </td>
</tr> </tr>

View File

@ -237,11 +237,11 @@ $(document).ready(function () {
} }
} }
if (window.serverInfo.grabbers.active) if (window.serverInfo.grabbers.active)
{ {
var activegrabber = window.serverInfo.grabbers.active.toLowerCase(); var activegrabber = window.serverInfo.grabbers.active.toLowerCase();
$("#" + selector + " option[value='" + activegrabber + "']").attr('selected', 'selected'); $("#" + selector + " option[value='" + activegrabber + "']").attr('selected', 'selected');
} }
var selectedType = $("#root_framegrabber_type").val(); var selectedType = $("#root_framegrabber_type").val();
filerFgGrabberOptions(selectedType); filerFgGrabberOptions(selectedType);

View File

@ -359,10 +359,10 @@ function migrateLedConfig(slConfig){
//Default Classic layout //Default Classic layout
newLedConfig.classic = { newLedConfig.classic = {
"top" : 8, "top" : 1,
"bottom" : 8, "bottom" : 0,
"left" : 5, "left" : 0,
"right" : 5, "right" : 0,
"glength" : 0, "glength" : 0,
"gpos" : 0, "gpos" : 0,
"position" : 0, "position" : 0,
@ -386,8 +386,8 @@ function migrateLedConfig(slConfig){
newLedConfig.classic.overlap = slConfig.overlap; newLedConfig.classic.overlap = slConfig.overlap;
//Default Matrix layout //Default Matrix layout
newLedConfig["matrix"] = { "ledshoriz": 10, newLedConfig["matrix"] = { "ledshoriz": 1,
"ledsvert" : 10, "ledsvert" : 1,
"cabling" : "snake", "cabling" : "snake",
"start" : "top-left" "start" : "top-left"
} }

View File

@ -454,9 +454,9 @@ function requestAdjustment(type, value, complete)
sendToHyperion("adjustment", "", '"adjustment": {"'+type+'": '+value+'}'); sendToHyperion("adjustment", "", '"adjustment": {"'+type+'": '+value+'}');
} }
async function requestLedDeviceDiscovery(type) async function requestLedDeviceDiscovery(type, params)
{ {
let data = { ledDeviceType: type }; let data = { ledDeviceType: type, params: params };
return sendAsyncToHyperion("leddevice", "discover", data, Math.floor(Math.random() * 1000) ); return sendAsyncToHyperion("leddevice", "discover", data, Math.floor(Math.random() * 1000) );
} }

View File

@ -389,7 +389,7 @@ function showInfoDialog(type,header,message)
$(document).on('click', '[data-dismiss-modal]', function () { $(document).on('click', '[data-dismiss-modal]', function () {
var target = $(this).attr('data-dismiss-modal'); var target = $(this).attr('data-dismiss-modal');
$(target).modal('hide'); $.find(target).modal.hide();
}); });
} }

View File

@ -424,7 +424,7 @@ function startWizardCC() {
} }
//create html //create html
$('#wiz_header').html('<i class="fa fa-magic fa-fw"></i>' + $.i18n('wiz_cc_title')); $('#wiz_header').html('<i class="fa fa-magic fa-fw"></i>' + $.i18n('wiz_cc_title'));
$('#wizp1_body').html('<h4 style="font-weight:bold;text-transform:uppercase;">' + $.i18n('wiz_cc_title') + '</h4><p>' + $.i18n('wiz_cc_intro1') + '</p><label>' + $.i18n('wiz_cc_kwebs') + '</label><input class="form-control" style="width:170px;margin:auto" id="wiz_cc_kodiip" type="text" placeholder="' + kodiAddress + '" value="' + kodiAddress + '" /><span id="kodi_status"></span><span id="multi_cali"></span>'); $('#wizp1_body').html('<h4 style="font-weight:bold;text-transform:uppercase;">' + $.i18n('wiz_cc_title') + '</h4><p>' + $.i18n('wiz_cc_intro1') + '</p><label>' + $.i18n('wiz_cc_kwebs') + '</label><input class="form-control" style="width:170px;margin:auto" id="wiz_cc_kodiip" type="text" placeholder="' + kodiAddress + '" value="' + kodiAddress + '" /><span id="kodi_status"></span><span id="multi_cali"></span>');
$('#wizp1_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_cont" disabled="disabled"><i class="fa fa-fw fa-check"></i>' + $.i18n('general_btn_continue') + '</button><button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>'); $('#wizp1_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_cont" disabled="disabled"><i class="fa fa-fw fa-check"></i>' + $.i18n('general_btn_continue') + '</button><button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>');
$('#wizp2_body').html('<div id="wiz_cc_desc" style="font-weight:bold"></div><div id="editor_container_wiz"></div>'); $('#wizp2_body').html('<div id="wiz_cc_desc" style="font-weight:bold"></div><div id="editor_container_wiz"></div>');
$('#wizp2_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_back"><i class="fa fa-fw fa-chevron-left"></i>' + $.i18n('general_btn_back') + '</button><button type="button" class="btn btn-primary" id="btn_wiz_next">' + $.i18n('general_btn_next') + '<i style="margin-left:4px;"class="fa fa-fw fa-chevron-right"></i></button><button type="button" class="btn btn-warning" id="btn_wiz_save" style="display:none"><i class="fa fa-fw fa-save"></i>' + $.i18n('general_btn_save') + '</button><button type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>'); $('#wizp2_footer').html('<button type="button" class="btn btn-primary" id="btn_wiz_back"><i class="fa fa-fw fa-chevron-left"></i>' + $.i18n('general_btn_back') + '</button><button type="button" class="btn btn-primary" id="btn_wiz_next">' + $.i18n('general_btn_next') + '<i style="margin-left:4px;"class="fa fa-fw fa-chevron-right"></i></button><button type="button" class="btn btn-warning" id="btn_wiz_save" style="display:none"><i class="fa fa-fw fa-save"></i>' + $.i18n('general_btn_save') + '</button><button type="button" class="btn btn-danger" id="btn_wiz_abort"><i class="fa fa-fw fa-close"></i>' + $.i18n('general_btn_cancel') + '</button>');
@ -439,6 +439,8 @@ function startWizardCC() {
$('#wiz_cc_kodiip').off().on('change', function () { $('#wiz_cc_kodiip').off().on('change', function () {
kodiAddress = $(this).val().trim(); kodiAddress = $(this).val().trim();
$('#wizp1_body').find("kodiAddress").val(kodiAddress);
$('#kodi_status').html(''); $('#kodi_status').html('');
// Remove Kodi's default Web-Socket port (9090) from display and ensure Kodi's default REST-API port (8080) is mapped to web-socket port to ease migration // Remove Kodi's default Web-Socket port (9090) from display and ensure Kodi's default REST-API port (8080) is mapped to web-socket port to ease migration
@ -1585,7 +1587,7 @@ function beginWizardAtmoOrb() {
lights = []; lights = [];
configuredLights = []; configuredLights = [];
configruedOrbIds = conf_editor.getEditor("root.specificOptions.orbIds").getValue().trim(); var configruedOrbIds = conf_editor.getEditor("root.specificOptions.orbIds").getValue().trim();
if (configruedOrbIds.length !== 0) { if (configruedOrbIds.length !== 0) {
configuredLights = configruedOrbIds.split(",").map(Number); configuredLights = configruedOrbIds.split(",").map(Number);
} }
@ -1648,13 +1650,16 @@ function beginWizardAtmoOrb() {
async function discover_atmoorb_lights(multiCastGroup, multiCastPort) { async function discover_atmoorb_lights(multiCastGroup, multiCastPort) {
var light = {}; var light = {};
if (multiCastGroup === "") var params = {};
multiCastGroup = "239.255.255.250"; if (multiCastGroup !== "")
{
params.multiCastGroup = multiCastGroup;
}
if (multiCastPort === "") if (multiCastPort !== 0)
multiCastPort = 49692; {
params.multiCastPort = multiCastPort;
let params = { multiCastGroup: multiCastGroup, multiCastPort: multiCastPort }; }
// Get discovered lights // Get discovered lights
const res = await requestLedDeviceDiscovery('atmoorb', params); const res = await requestLedDeviceDiscovery('atmoorb', params);

View File

@ -120,7 +120,7 @@
"backgroundEffect" : "backgroundEffect" :
{ {
"enable" : true, "enable" : false,
"type" : "effect", "type" : "effect",
"color" : [255,138,0], "color" : [255,138,0],
"effect" : "Warm mood blobs" "effect" : "Warm mood blobs"
@ -197,10 +197,10 @@
{ {
"classic": "classic":
{ {
"top" : 8, "top" : 1,
"bottom" : 8, "bottom" : 0,
"left" : 5, "left" : 0,
"right" : 5, "right" : 0,
"glength" : 0, "glength" : 0,
"gpos" : 0, "gpos" : 0,
"position" : 0, "position" : 0,
@ -221,8 +221,8 @@
"matrix": "matrix":
{ {
"ledshoriz": 10, "ledshoriz": 1,
"ledsvert" : 10, "ledsvert" : 1,
"cabling" : "snake", "cabling" : "snake",
"start" : "top-left" "start" : "top-left"
} }
@ -231,160 +231,10 @@
"leds": "leds":
[ [
{ {
"hmax": 0.125, "hmax": 1,
"hmin": 0, "hmin": 0,
"vmax": 0.08, "vmax": 0.08,
"vmin": 0 "vmin": 0
},
{
"hmax": 0.25,
"hmin": 0.125,
"vmax": 0.08,
"vmin": 0
},
{
"hmax": 0.375,
"hmin": 0.25,
"vmax": 0.08,
"vmin": 0
},
{
"hmax": 0.5,
"hmin": 0.375,
"vmax": 0.08,
"vmin": 0
},
{
"hmax": 0.625,
"hmin": 0.5,
"vmax": 0.08,
"vmin": 0
},
{
"hmax": 0.75,
"hmin": 0.625,
"vmax": 0.08,
"vmin": 0
},
{
"hmax": 0.875,
"hmin": 0.75,
"vmax": 0.08,
"vmin": 0
},
{
"hmax": 1,
"hmin": 0.875,
"vmax": 0.08,
"vmin": 0
},
{
"hmax": 1,
"hmin": 0.95,
"vmax": 0.2,
"vmin": 0
},
{
"hmax": 1,
"hmin": 0.95,
"vmax": 0.4,
"vmin": 0.2
},
{
"hmax": 1,
"hmin": 0.95,
"vmax": 0.6,
"vmin": 0.4
},
{
"hmax": 1,
"hmin": 0.95,
"vmax": 0.8,
"vmin": 0.6
},
{
"hmax": 1,
"hmin": 0.95,
"vmax": 1,
"vmin": 0.8
},
{
"hmax": 1,
"hmin": 0.875,
"vmax": 1,
"vmin": 0.92
},
{
"hmax": 0.875,
"hmin": 0.75,
"vmax": 1,
"vmin": 0.92
},
{
"hmax": 0.75,
"hmin": 0.625,
"vmax": 1,
"vmin": 0.92
},
{
"hmax": 0.625,
"hmin": 0.5,
"vmax": 1,
"vmin": 0.92
},
{
"hmax": 0.5,
"hmin": 0.375,
"vmax": 1,
"vmin": 0.92
},
{
"hmax": 0.375,
"hmin": 0.25,
"vmax": 1,
"vmin": 0.92
},
{
"hmax": 0.25,
"hmin": 0.125,
"vmax": 1,
"vmin": 0.92
},
{
"hmax": 0.125,
"hmin": 0,
"vmax": 1,
"vmin": 0.92
},
{
"hmax": 0.05,
"hmin": 0,
"vmax": 1,
"vmin": 0.8
},
{
"hmax": 0.05,
"hmin": 0,
"vmax": 0.8,
"vmin": 0.6
},
{
"hmax": 0.05,
"hmin": 0,
"vmax": 0.6,
"vmin": 0.4
},
{
"hmax": 0.05,
"hmin": 0,
"vmax": 0.4,
"vmin": 0.2
},
{
"hmax": 0.05,
"hmin": 0,
"vmax": 0.2,
"vmin": 0
} }
] ]
} }

View File

@ -11,7 +11,7 @@ namespace hyperion
/// ///
struct BlackBorder struct BlackBorder
{ {
/// Falg indicating if the border is unknown /// Flag indicating if the border is unknown
bool unknown; bool unknown;
/// The size of the detected horizontal border /// The size of the detected horizontal border
@ -48,7 +48,7 @@ namespace hyperion
public: public:
/// ///
/// Constructs a black-border detector /// Constructs a black-border detector
/// @param[in] blackborderThreshold The threshold which the blackborder detector should use /// @param[in] threshold The threshold which the black-border detector should use
/// ///
BlackBorderDetector(double threshold); BlackBorderDetector(double threshold);
@ -67,9 +67,9 @@ namespace hyperion
template <typename Pixel_T> template <typename Pixel_T>
BlackBorder process(const Image<Pixel_T> & image) const BlackBorder process(const Image<Pixel_T> & image) const
{ {
// test center and 33%, 66% of width/heigth // test centre and 33%, 66% of width/height
// 33 and 66 will check left and top // 33 and 66 will check left and top
// center will check right and bottom sids // centre will check right and bottom sides
int width = image.width(); int width = image.width();
int height = image.height(); int height = image.height();
int width33percent = width / 3; int width33percent = width / 3;
@ -281,7 +281,7 @@ namespace hyperion
private: private:
/// ///
/// Checks if a given color is considered black and therefor could be part of the border. /// Checks if a given color is considered black and therefore could be part of the border.
/// ///
/// @param[in] color The color to check /// @param[in] color The color to check
/// ///
@ -295,7 +295,7 @@ namespace hyperion
} }
private: private:
/// Threshold for the blackborder detector [0 .. 255] /// Threshold for the black-border detector [0 .. 255]
const uint8_t _blackborderThreshold; const uint8_t _blackborderThreshold;
}; };

View File

@ -44,14 +44,14 @@ namespace hyperion
void setEnabled(bool enable); void setEnabled(bool enable);
/// ///
/// Sets the _hardDisabled state, if True prevents the enable from COMP_BLACKBORDER state emit (mimiks wrong state to external!) /// Sets the _hardDisabled state, if True prevents the enable from COMP_BLACKBORDER state emit (mimics wrong state to external!)
/// It's not possible to enable bb from this method, if the user requsted a disable! /// It's not possible to enable black-border detection from this method, if the user requested a disable!
/// @param disable The new state /// @param disable The new state
/// ///
void setHardDisable(bool disable); void setHardDisable(bool disable);
/// ///
/// Processes the image. This performs detecion of black-border on the given image and /// Processes the image. This performs detection of black-border on the given image and
/// updates the current border accordingly. If the current border is updated the method call /// updates the current border accordingly. If the current border is updated the method call
/// will return true else false /// will return true else false
/// ///
@ -64,10 +64,11 @@ namespace hyperion
{ {
// get the border for the single image // get the border for the single image
BlackBorder imageBorder; BlackBorder imageBorder;
imageBorder.horizontalSize = 0;
imageBorder.verticalSize = 0;
if (!enabled()) if (!enabled())
{ {
imageBorder.horizontalSize = 0;
imageBorder.verticalSize = 0;
imageBorder.unknown=true; imageBorder.unknown=true;
_currentBorder = imageBorder; _currentBorder = imageBorder;
return true; return true;
@ -98,7 +99,7 @@ namespace hyperion
private slots: private slots:
/// ///
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor /// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
/// @param type settingyType from enum /// @param type settingType from enum
/// @param config configuration object /// @param config configuration object
/// ///
void handleSettingsUpdate(settings::type type, const QJsonDocument& config); void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
@ -121,7 +122,7 @@ namespace hyperion
/// ///
bool updateBorder(const BlackBorder & newDetectedBorder); bool updateBorder(const BlackBorder & newDetectedBorder);
/// flag for blackborder detector usage /// flag for black-border detector usage
bool _enabled; bool _enabled;
/// The number of unknown-borders detected before it becomes the current border /// The number of unknown-borders detected before it becomes the current border
@ -133,13 +134,13 @@ namespace hyperion
// The number of frames that are "ignored" before a new border gets set as _previousDetectedBorder // The number of frames that are "ignored" before a new border gets set as _previousDetectedBorder
unsigned _maxInconsistentCnt; unsigned _maxInconsistentCnt;
/// The number of pixels to increase a detected border for removing blury pixels /// The number of pixels to increase a detected border for removing blurry pixels
unsigned _blurRemoveCnt; unsigned _blurRemoveCnt;
/// The border detection mode /// The border detection mode
QString _detectionMode; QString _detectionMode;
/// The blackborder detector /// The black-border detector
BlackBorderDetector* _detector; BlackBorderDetector* _detector;
/// The current detected border /// The current detected border
@ -148,9 +149,9 @@ namespace hyperion
/// The border detected in the previous frame /// The border detected in the previous frame
BlackBorder _previousDetectedBorder; BlackBorder _previousDetectedBorder;
/// The number of frame the previous detected border matched the incomming border /// The number of frame the previous detected border matched the incoming border
unsigned _consistentCnt; unsigned _consistentCnt;
/// The number of frame the previous detected border NOT matched the incomming border /// The number of frame the previous detected border NOT matched the incoming border
unsigned _inconsistentCnt; unsigned _inconsistentCnt;
/// old threshold /// old threshold
double _oldThreshold; double _oldThreshold;

View File

@ -19,7 +19,7 @@ private:
/// @brief Browse for hyperion services in bonjour, constructed from HyperionDaemon /// @brief Browse for hyperion services in bonjour, constructed from HyperionDaemon
/// Searching for hyperion http service by default /// Searching for hyperion http service by default
/// ///
BonjourBrowserWrapper(QObject * parent = 0); BonjourBrowserWrapper(QObject * parent = nullptr);
public: public:
@ -30,36 +30,36 @@ public:
/// ///
/// @brief Get all available sessions /// @brief Get all available sessions
/// ///
QMap<QString,BonjourRecord> getAllServices() { return _hyperionSessions; }; QMap<QString, BonjourRecord> getAllServices() { return _hyperionSessions; }
static BonjourBrowserWrapper* instance; static BonjourBrowserWrapper* instance;
static BonjourBrowserWrapper* getInstance(){ return instance; }; static BonjourBrowserWrapper *getInstance() { return instance; }
signals: signals:
/// ///
/// @brief Emits whenever a change happend /// @brief Emits whenever a change happend
/// ///
void browserChange(const QMap<QString,BonjourRecord>& bRegisters); void browserChange( const QMap<QString, BonjourRecord> &bRegisters );
private: private:
/// map of service names and browsers /// map of service names and browsers
QMap< QString, BonjourServiceBrowser* > _browsedServices; QMap<QString, BonjourServiceBrowser *> _browsedServices;
/// Resolver /// Resolver
BonjourServiceResolver* _bonjourResolver; BonjourServiceResolver *_bonjourResolver;
// contains all current active service sessions // contains all current active service sessions
QMap<QString,BonjourRecord> _hyperionSessions; QMap<QString, BonjourRecord> _hyperionSessions;
QString _bonjourCurrentServiceToResolve; QString _bonjourCurrentServiceToResolve;
/// timer to resolve changes /// timer to resolve changes
QTimer* _timerBonjourResolver; QTimer *_timerBonjourResolver;
private slots: private slots:
/// ///
/// @brief is called whenever a BonjourServiceBrowser emits change /// @brief is called whenever a BonjourServiceBrowser emits change
void currentBonjourRecordsChanged(const QList<BonjourRecord> &list); void currentBonjourRecordsChanged( const QList<BonjourRecord> &list );
/// @brief new record resolved /// @brief new record resolved
void bonjourRecordResolved(const QHostInfo &hostInfo, int port); void bonjourRecordResolved( const QHostInfo &hostInfo, int port );
/// ///
/// @brief timer slot which updates regularly entries /// @brief timer slot which updates regularly entries

View File

@ -33,6 +33,8 @@ public:
QString value(Parser &parser) const; QString value(Parser &parser) const;
const char* getCString(Parser &parser) const; const char* getCString(Parser &parser) const;
virtual ~Option();
protected: protected:
QString _error; QString _error;
}; };

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include <QtCore> #include <QtCore>
#include <QtGui>
#include "ColorOption.h" #include "ColorOption.h"
#include "ColorsOption.h" #include "ColorsOption.h"
#include "DoubleOption.h" #include "DoubleOption.h"
@ -24,8 +23,8 @@ protected:
/* No public inheritance because we need to modify a few methods */ /* No public inheritance because we need to modify a few methods */
QCommandLineParser _parser; QCommandLineParser _parser;
QStringList _getNames(const char shortOption, const QString longOption); QStringList _getNames(const char shortOption, const QString& longOption);
QString _getDescription(const QString description, const QString default_=QString()); QString _getDescription(const QString& description, const QString& default_=QString());
public: public:
~Parser() override; ~Parser() override;
@ -97,24 +96,24 @@ public:
{ {
if(description.size()) if(description.size())
setApplicationDescription(description); setApplicationDescription(description);
}; }
QCommandLineOption addHelpOption() QCommandLineOption addHelpOption()
{ {
return _parser.addHelpOption(); return _parser.addHelpOption();
}; }
bool addOption(Option &option); bool addOption(Option &option);
bool addOption(Option *option); bool addOption(Option *option);
void addPositionalArgument(const QString &name, const QString &description, const QString &syntax = QString()) void addPositionalArgument(const QString &name, const QString &description, const QString &syntax = QString())
{ {
_parser.addPositionalArgument(name, description, syntax); _parser.addPositionalArgument(name, description, syntax);
}; }
QCommandLineOption addVersionOption() QCommandLineOption addVersionOption()
{ {
return _parser.addVersionOption(); return _parser.addVersionOption();
}; }
QString applicationDescription() const QString applicationDescription() const
{ {
@ -166,7 +165,7 @@ public:
_parser.setSingleDashWordOptionMode(singleDashWordOptionMode); _parser.setSingleDashWordOptionMode(singleDashWordOptionMode);
} }
void showHelp(int exitCode = 0) [[ noreturn ]] void showHelp(int exitCode = 0)
{ {
_parser.showHelp(exitCode); _parser.showHelp(exitCode);
} }

View File

@ -1,11 +1,5 @@
#pragma once #pragma once
// Python includes
// collide of qt slots macro
#undef slots
#include "Python.h"
#define slots
// Qt includes // Qt includes
#include <QThread> #include <QThread>
#include <QJsonObject> #include <QJsonObject>
@ -44,13 +38,13 @@ public:
int getPriority() const { return _priority; } int getPriority() const { return _priority; }
/// ///
/// @brief Set manual interuption to true, /// @brief Set manual interruption to true,
/// Note: DO NOT USE QThread::interuption! /// Note: DO NOT USE QThread::interruption!
/// ///
void requestInterruption() { _interupt = true; } void requestInterruption() { _interupt = true; }
/// ///
/// @brief Check if the interuption flag has been set /// @brief Check if the interruption flag has been set
/// @return The flag state /// @return The flag state
/// ///
bool isInterruptionRequested() { return _interupt; } bool isInterruptionRequested() { return _interupt; }
@ -88,7 +82,7 @@ private:
QVector<ColorRgb> _colors; QVector<ColorRgb> _colors;
Logger *_log; Logger *_log;
// Reflects whenever this effects should interupt (timeout or external request) // Reflects whenever this effects should interrupt (timeout or external request)
std::atomic<bool> _interupt {}; std::atomic<bool> _interupt {};
QSize _imageSize; QSize _imageSize;

View File

@ -15,7 +15,7 @@ private:
public: public:
static EffectFileHandler* efhInstance; static EffectFileHandler* efhInstance;
static EffectFileHandler* getInstance() { return efhInstance; }; static EffectFileHandler* getInstance() { return efhInstance; }
/// ///
/// @brief Get all available effects /// @brief Get all available effects

View File

@ -37,7 +37,7 @@ public:
/// ///
/// @brief Apply new width/height values, overwrite Grabber.h implementation as qt doesn't use width/height, just pixelDecimation to calc dimensions /// @brief Apply new width/height values, overwrite Grabber.h implementation as qt doesn't use width/height, just pixelDecimation to calc dimensions
/// ///
bool setWidthHeight(int width, int height) override { return true; }; bool setWidthHeight(int width, int height) override { return true; }
/// ///
/// @brief Apply new pixelDecimation /// @brief Apply new pixelDecimation

View File

@ -45,7 +45,7 @@ public:
/// ///
/// @brief Apply new width/height values, overwrite Grabber.h implementation as X11 doesn't use width/height, just pixelDecimation to calc dimensions /// @brief Apply new width/height values, overwrite Grabber.h implementation as X11 doesn't use width/height, just pixelDecimation to calc dimensions
/// ///
bool setWidthHeight(int width, int height) override { return true; }; bool setWidthHeight(int width, int height) override { return true; }
/// ///
/// @brief Apply new pixelDecimation /// @brief Apply new pixelDecimation

View File

@ -15,7 +15,7 @@ public:
~XcbWrapper() override; ~XcbWrapper() override;
public slots: public slots:
virtual void action(); void action() override;
private: private:
XcbGrabber _grabber; XcbGrabber _grabber;

View File

@ -21,7 +21,7 @@ class AuthManager : public QObject
private: private:
friend class HyperionDaemon; friend class HyperionDaemon;
/// constructor is private, can be called from HyperionDaemon /// constructor is private, can be called from HyperionDaemon
AuthManager(QObject *parent = 0, bool readonlyMode = false); AuthManager(QObject *parent = nullptr, bool readonlyMode = false);
public: public:
struct AuthDefinition struct AuthDefinition

View File

@ -19,14 +19,14 @@ public:
// listen for config changes // listen for config changes
connect(_hyperion, &Hyperion::settingsChanged, this, &BGEffectHandler::handleSettingsUpdate); connect(_hyperion, &Hyperion::settingsChanged, this, &BGEffectHandler::handleSettingsUpdate);
// init // initialization
handleSettingsUpdate(settings::BGEFFECT, _hyperion->getSetting(settings::BGEFFECT)); handleSettingsUpdate(settings::BGEFFECT, _hyperion->getSetting(settings::BGEFFECT));
}; }
private slots: private slots:
/// ///
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor /// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
/// @param type settingyType from enum /// @param type settingType from enum
/// @param config configuration object /// @param config configuration object
/// ///
void handleSettingsUpdate(settings::type type, const QJsonDocument& config) void handleSettingsUpdate(settings::type type, const QJsonDocument& config)
@ -36,7 +36,7 @@ private slots:
const QJsonObject& BGEffectConfig = config.object(); const QJsonObject& BGEffectConfig = config.object();
#define BGCONFIG_ARRAY bgColorConfig.toArray() #define BGCONFIG_ARRAY bgColorConfig.toArray()
// clear bg prioritiy // clear background priority
_hyperion->clear(254); _hyperion->clear(254);
// initial background effect/color // initial background effect/color
if (BGEffectConfig["enable"].toBool(true)) if (BGEffectConfig["enable"].toBool(true))
@ -48,24 +48,24 @@ private slots:
{ {
std::vector<ColorRgb> bg_color = { std::vector<ColorRgb> bg_color = {
ColorRgb { ColorRgb {
(uint8_t)BGCONFIG_ARRAY.at(0).toInt(0), static_cast<uint8_t>(BGCONFIG_ARRAY.at(0).toInt(0)),
(uint8_t)BGCONFIG_ARRAY.at(1).toInt(0), static_cast<uint8_t>(BGCONFIG_ARRAY.at(1).toInt(0)),
(uint8_t)BGCONFIG_ARRAY.at(2).toInt(0) static_cast<uint8_t>(BGCONFIG_ARRAY.at(2).toInt(0))
} }
}; };
_hyperion->setColor(254, bg_color); _hyperion->setColor(254, bg_color);
Info(Logger::getInstance("HYPERION"),"Inital background color set (%d %d %d)",bg_color.at(0).red, bg_color.at(0).green, bg_color.at(0).blue); Info(Logger::getInstance("HYPERION"),"Initial background color set (%d %d %d)",bg_color.at(0).red, bg_color.at(0).green, bg_color.at(0).blue);
} }
else else
{ {
int result = _hyperion->setEffect(bgEffectConfig, 254); int result = _hyperion->setEffect(bgEffectConfig, 254);
Info(Logger::getInstance("HYPERION"),"Inital background effect '%s' %s", QSTRING_CSTR(bgEffectConfig), ((result == 0) ? "started" : "failed")); Info(Logger::getInstance("HYPERION"),"Initial background effect '%s' %s", QSTRING_CSTR(bgEffectConfig), ((result == 0) ? "started" : "failed"));
} }
} }
#undef BGCONFIG_ARRAY #undef BGCONFIG_ARRAY
} }
}; }
private: private:
/// Hyperion instance pointer /// Hyperion instance pointer

View File

@ -111,7 +111,7 @@ public slots:
/// ///
/// Returns the number of attached leds /// Returns the number of attached leds
/// ///
unsigned getLedCount() const; int getLedCount() const;
/// ///
/// @brief Register a new input by priority, the priority is not active (timeout -100 isn't muxer recognized) until you start to update the data with setInput() /// @brief Register a new input by priority, the priority is not active (timeout -100 isn't muxer recognized) until you start to update the data with setInput()
@ -298,7 +298,7 @@ public slots:
/// ///
/// @return The information of the given, a not found priority will return lowest priority as fallback /// @return The information of the given, a not found priority will return lowest priority as fallback
/// ///
InputInfo getPriorityInfo(int priority) const; PriorityMuxer::InputInfo getPriorityInfo(int priority) const;
/// ############# /// #############
/// SETTINGSMANAGER /// SETTINGSMANAGER
@ -527,7 +527,7 @@ private:
Logger * _log; Logger * _log;
/// count of hardware leds /// count of hardware leds
unsigned _hwLedCount; int _hwLedCount;
QSize _ledGridSize; QSize _ledGridSize;

View File

@ -19,9 +19,9 @@
class Hyperion; class Hyperion;
/// ///
/// The ImageProcessor translates an RGB-image to RGB-values for the leds. The processing is /// The ImageProcessor translates an RGB-image to RGB-values for the LEDs. The processing is
/// performed in two steps. First the average color per led-region is computed. Second a /// performed in two steps. First the average color per led-region is computed. Second a
/// color-tranform is applied based on a gamma-correction. /// color-transform is applied based on a gamma-correction.
/// ///
class ImageProcessor : public QObject class ImageProcessor : public QObject
{ {
@ -39,7 +39,7 @@ public:
~ImageProcessor() override; ~ImageProcessor() override;
/// ///
/// Specifies the width and height of 'incomming' images. This will resize the buffer-image to /// Specifies the width and height of 'incoming' images. This will resize the buffer-image to
/// match the given size. /// match the given size.
/// NB All earlier obtained references will be invalid. /// NB All earlier obtained references will be invalid.
/// ///
@ -53,7 +53,7 @@ public:
/// ///
void setLedString(const LedString& ledString); void setLedString(const LedString& ledString);
/// Returns starte of black border detector /// Returns state of black border detector
bool blackBorderDetectorEnabled() const; bool blackBorderDetectorEnabled() const;
/// Returns the current _userMappingType, this may not be the current applied type! /// Returns the current _userMappingType, this may not be the current applied type!
@ -66,7 +66,7 @@ public:
static QString mappingTypeToStr(int mappingType); static QString mappingTypeToStr(int mappingType);
/// ///
/// @brief Set the Hyperion::update() requestes led mapping type. This type is used in favour of type set with setLedMappingType. /// @brief Set the Hyperion::update() request LED mapping type. This type is used in favour of type set with setLedMappingType.
/// If you don't want to force a mapType set this to -1 (user choice will be set) /// If you don't want to force a mapType set this to -1 (user choice will be set)
/// @param mapType The new mapping type /// @param mapType The new mapping type
/// ///
@ -85,7 +85,7 @@ public slots:
public: public:
/// ///
/// Specifies the width and height of 'incomming' images. This will resize the buffer-image to /// Specifies the width and height of 'incoming' images. This will resize the buffer-image to
/// match the given size. /// match the given size.
/// NB All earlier obtained references will be invalid. /// NB All earlier obtained references will be invalid.
/// ///
@ -117,7 +117,7 @@ public:
// Check black border detection // Check black border detection
verifyBorder(image); verifyBorder(image);
// Create a result vector and call the 'in place' functionl // Create a result vector and call the 'in place' function
switch (_mappingType) switch (_mappingType)
{ {
case 1: colors = _imageToLeds->getUniLedColor(image); break; case 1: colors = _imageToLeds->getUniLedColor(image); break;
@ -225,7 +225,7 @@ private:
/// The processor for black border detection /// The processor for black border detection
hyperion::BlackBorderProcessor * _borderProcessor; hyperion::BlackBorderProcessor * _borderProcessor;
/// The mapping of image-pixels to leds /// The mapping of image-pixels to LEDs
hyperion::ImageToLedsMap* _imageToLeds; hyperion::ImageToLedsMap* _imageToLeds;
/// Type of image 2 led mapping /// Type of image 2 led mapping

View File

@ -175,7 +175,7 @@ namespace hyperion
return ColorRgb::BLACK; return ColorRgb::BLACK;
} }
// Accumulate the sum of each seperate color channel // Accumulate the sum of each separate color channel
uint_fast32_t cummRed = 0; uint_fast32_t cummRed = 0;
uint_fast32_t cummGreen = 0; uint_fast32_t cummGreen = 0;
uint_fast32_t cummBlue = 0; uint_fast32_t cummBlue = 0;
@ -209,7 +209,7 @@ namespace hyperion
template <typename Pixel_T> template <typename Pixel_T>
ColorRgb calcMeanColor(const Image<Pixel_T> & image) const ColorRgb calcMeanColor(const Image<Pixel_T> & image) const
{ {
// Accumulate the sum of each seperate color channel // Accumulate the sum of each separate color channel
uint_fast32_t cummRed = 0; uint_fast32_t cummRed = 0;
uint_fast32_t cummGreen = 0; uint_fast32_t cummGreen = 0;
uint_fast32_t cummBlue = 0; uint_fast32_t cummBlue = 0;

View File

@ -107,16 +107,6 @@ struct Led
class LedString class LedString
{ {
public: public:
///
/// Constructs the LedString with no leds
///
LedString();
///
/// Destructor of this LedString
///
~LedString();
/// ///
/// Returns the led specifications /// Returns the led specifications
/// ///

View File

@ -11,22 +11,22 @@
/// ///
/// The LedColorTransform is responsible for performing color transformation from 'raw' colors /// The LedColorTransform is responsible for performing color transformation from 'raw' colors
/// received as input to colors mapped to match the color-properties of the leds. /// received as input to colors mapped to match the color-properties of the LEDs.
/// ///
class MultiColorAdjustment class MultiColorAdjustment
{ {
public: public:
MultiColorAdjustment(unsigned ledCnt); MultiColorAdjustment(int ledCnt);
~MultiColorAdjustment(); ~MultiColorAdjustment();
/** /**
* Adds a new ColorAdjustment to this MultiColorTransform * Adds a new ColorAdjustment to this MultiColorTransform
* *
* @param adjustment The new ColorAdjustment (ownership is transfered) * @param adjustment The new ColorAdjustment (ownership is transferred)
*/ */
void addAdjustment(ColorAdjustment * adjustment); void addAdjustment(ColorAdjustment * adjustment);
void setAdjustmentForLed(const QString& id, unsigned startLed, unsigned endLed); void setAdjustmentForLed(const QString& id, int startLed, int endLed);
bool verifyAdjustments() const; bool verifyAdjustments() const;

View File

@ -58,10 +58,10 @@ public:
const static int LOWEST_PRIORITY; const static int LOWEST_PRIORITY;
/// ///
/// Constructs the PriorityMuxer for the given number of leds (used to switch to black when /// Constructs the PriorityMuxer for the given number of LEDs (used to switch to black when
/// there are no priority channels /// there are no priority channels
/// ///
/// @param ledCount The number of leds /// @param ledCount The number of LEDs
/// ///
PriorityMuxer(int ledCount, QObject * parent); PriorityMuxer(int ledCount, QObject * parent);
@ -87,18 +87,18 @@ public:
/// @brief Get the state of source auto selection /// @brief Get the state of source auto selection
/// @return True if enabled, else false /// @return True if enabled, else false
/// ///
bool isSourceAutoSelectEnabled() const { return _sourceAutoSelectEnabled; }; bool isSourceAutoSelectEnabled() const { return _sourceAutoSelectEnabled; }
/// ///
/// @brief Overwrite current lowest piority with manual selection; On success disables aito selection /// @brief Overwrite current lowest priority with manual selection; On success disables auto selection
/// @param priority The /// @param priority The
/// @return True on success, false if priority not found /// @return True on success, false if priority not found
/// ///
bool setPriority(uint8_t priority); bool setPriority(int priority);
/// ///
/// @brief Update all ledColos with min length of >= 1 to fit the new led length /// @brief Update all LED-Colors with min length of >= 1 to fit the new led length
/// @param[in] ledCount The count of leds /// @param[in] ledCount The count of LEDs
/// ///
void updateLedColorsLength(int ledCount); void updateLedColorsLength(int ledCount);
@ -146,13 +146,13 @@ public:
/// @param[in] priority The priority of the channel /// @param[in] priority The priority of the channel
/// @param[in] component The component of the channel /// @param[in] component The component of the channel
/// @param[in] origin Who set the channel (CustomString@IP) /// @param[in] origin Who set the channel (CustomString@IP)
/// @param[in] owner Speicifc owner string, might be empty /// @param[in] owner Specific owner string, might be empty
/// @param[in] smooth_cfg The smooth id to use /// @param[in] smooth_cfg The smooth id to use
/// ///
void registerInput(int priority, hyperion::Components component, const QString& origin = "System", const QString& owner = "", unsigned smooth_cfg = SMOOTHING_MODE_DEFAULT); void registerInput(int priority, hyperion::Components component, const QString& origin = "System", const QString& owner = "", unsigned smooth_cfg = SMOOTHING_MODE_DEFAULT);
/// ///
/// @brief Update the current color of a priority (prev registered with registerInput()) /// @brief Update the current color of a priority (previous registered with registerInput())
/// @param priority The priority to update /// @param priority The priority to update
/// @param ledColors The colors /// @param ledColors The colors
/// @param timeout_ms The new timeout (defaults to -1 endless) /// @param timeout_ms The new timeout (defaults to -1 endless)
@ -174,7 +174,7 @@ public:
/// @param priority The priority /// @param priority The priority
/// @return True on success false if not found /// @return True on success false if not found
/// ///
bool setInputInactive(quint8 priority); bool setInputInactive(int priority);
/// ///
/// Clears the specified priority channel and update _currentPriority on success /// Clears the specified priority channel and update _currentPriority on success
@ -182,7 +182,7 @@ public:
/// @param[in] priority The priority of the channel to clear /// @param[in] priority The priority of the channel to clear
/// @return True if priority has been cleared else false (not found) /// @return True if priority has been cleared else false (not found)
/// ///
bool clearInput(uint8_t priority); bool clearInput(int priority);
/// ///
/// Clears all priority channels /// Clears all priority channels
@ -190,7 +190,7 @@ public:
void clearAll(bool forceClearAll=false); void clearAll(bool forceClearAll=false);
/// ///
/// @brief Queue a manual push where muxer doesn't recognize them (e.g. continous single color pushes) /// @brief Queue a manual push where muxer doesn't recognize them (e.g. continuous single color pushes)
/// ///
void queuePush() { emit timeRunner(); } void queuePush() { emit timeRunner(); }

View File

@ -3,14 +3,14 @@
#include <utils/Logger.h> #include <utils/Logger.h>
#include <utils/settings.h> #include <utils/settings.h>
// qt incl // qt includes
#include <QJsonObject> #include <QJsonObject>
class Hyperion; class Hyperion;
class SettingsTable; class SettingsTable;
/// ///
/// @brief Manage the settings read write from/to config file, on settings changed will emit a signal to update components accordingly /// @brief Manage the settings read write from/to configuration file, on settings changed will emit a signal to update components accordingly
/// ///
class SettingsManager : public QObject class SettingsManager : public QObject
{ {
@ -24,7 +24,7 @@ public:
SettingsManager(quint8 instance, QObject* parent = nullptr, bool readonlyMode = false); SettingsManager(quint8 instance, QObject* parent = nullptr, bool readonlyMode = false);
/// ///
/// @brief Save a complete json config /// @brief Save a complete json configuration
/// @param config The entire config object /// @param config The entire config object
/// @param correct If true will correct json against schema before save /// @param correct If true will correct json against schema before save
/// @return True on success else false /// @return True on success else false
@ -32,7 +32,7 @@ public:
bool saveSettings(QJsonObject config, bool correct = false); bool saveSettings(QJsonObject config, bool correct = false);
/// ///
/// @brief get a single setting json from config /// @brief get a single setting json from configuration
/// @param type The settings::type from enum /// @param type The settings::type from enum
/// @return The requested json data as QJsonDocument /// @return The requested json data as QJsonDocument
/// ///
@ -42,11 +42,11 @@ public:
/// @brief get the full settings object of this instance (with global settings) /// @brief get the full settings object of this instance (with global settings)
/// @return The requested json /// @return The requested json
/// ///
const QJsonObject & getSettings() const { return _qconfig; }; const QJsonObject & getSettings() const { return _qconfig; }
signals: signals:
/// ///
/// @brief Emits whenever a config part changed. /// @brief Emits whenever a configuration part changed.
/// @param type The settings type from enum /// @param type The settings type from enum
/// @param data The data as QJsonDocument /// @param data The data as QJsonDocument
/// ///
@ -54,7 +54,7 @@ signals:
private: private:
/// ///
/// @brief Add possile migrations steps for config here /// @brief Add possible migrations steps for configuration here
/// @param config The configuration object /// @param config The configuration object
/// @return True when a migration has been triggered /// @return True when a migration has been triggered
/// ///
@ -73,7 +73,7 @@ private:
/// the schema /// the schema
static QJsonObject schemaJson; static QJsonObject schemaJson;
/// the current config of this instance /// the current configuration of this instance
QJsonObject _qconfig; QJsonObject _qconfig;
bool _readonlyMode; bool _readonlyMode;

View File

@ -62,7 +62,7 @@ public:
/// ///
/// @param[in] ledCount Number of device LEDs, 0 = unknown number /// @param[in] ledCount Number of device LEDs, 0 = unknown number
/// ///
void setLedCount(unsigned int ledCount); void setLedCount(int ledCount);
/// ///
/// @brief Set a device's latch time. /// @brief Set a device's latch time.
@ -87,9 +87,11 @@ public:
/// @brief Discover devices of this type available (for configuration). /// @brief Discover devices of this type available (for configuration).
/// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways. /// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways.
/// ///
/// @param[in] params Parameters used to overwrite discovery default behaviour
///
/// @return A JSON structure holding a list of devices found /// @return A JSON structure holding a list of devices found
/// ///
virtual QJsonObject discover(); virtual QJsonObject discover(const QJsonObject& params);
/// ///
/// @brief Discover first device of this type available (for configuration). /// @brief Discover first device of this type available (for configuration).
@ -116,7 +118,7 @@ public:
/// ///
/// @param[in] params Parameters to address device /// @param[in] params Parameters to address device
/// ///
virtual void identify(const QJsonObject& params) {} virtual void identify(const QJsonObject& /*params*/) {}
/// ///
/// @brief Check, if device is properly initialised /// @brief Check, if device is properly initialised
@ -193,7 +195,7 @@ public slots:
/// ///
/// @return Number of device's LEDs, 0 = unknown number /// @return Number of device's LEDs, 0 = unknown number
/// ///
unsigned int getLedCount() const { return _ledCount; } int getLedCount() const { return _ledCount; }
/// ///
/// @brief Get the current active LED-device type. /// @brief Get the current active LED-device type.
@ -348,7 +350,7 @@ protected:
/// @param size of the array /// @param size of the array
/// @param number Number of array items to be converted. /// @param number Number of array items to be converted.
/// @return array as string of hex values /// @return array as string of hex values
QString uint8_t_to_hex_string(const uint8_t * data, const qint64 size, qint64 number = -1) const; QString uint8_t_to_hex_string(const uint8_t * data, const int size, int number = -1) const;
/// ///
/// @brief Converts a ByteArray to hex string. /// @brief Converts a ByteArray to hex string.

View File

@ -66,65 +66,62 @@ public:
/// @brief Overwrite description address /// @brief Overwrite description address
/// @param addr new address /// @param addr new address
/// ///
void setDescriptionAddress(const QString& addr) { _descAddress = addr; }; void setDescriptionAddress( const QString &addr ) { _descAddress = addr; }
/// ///
/// @brief Set uuid /// @brief Set uuid
/// @param uuid The uuid /// @param uuid The uuid
/// ///
void setUuid(const QString& uuid) { _uuid = uuid; }; void setUuid( const QString &uuid ) { _uuid = uuid; }
/// ///
/// @brief set new flatbuffer server port /// @brief set new flatbuffer server port
/// ///
void setFlatBufPort(quint16 port) { _fbsPort = QString::number(port); }; void setFlatBufPort( quint16 port ){_fbsPort = QString::number( port ); }
/// ///
/// @brief Get current flatbuffer server port /// @brief Get current flatbuffer server port
/// ///
quint16 getFlatBufPort() const { return _fbsPort.toInt(); }; quint16 getFlatBufPort() const
{
return _fbsPort.toInt();
}
/// ///
/// @brief set new protobuf server port /// @brief set new protobuf server port
/// ///
void setProtoBufPort(quint16 port) { _pbsPort = QString::number(port); }; void setProtoBufPort( quint16 port ) { _pbsPort = QString::number( port ); }
/// ///
/// @brief Get current protobuf server port /// @brief Get current protobuf server port
/// ///
quint16 getProtoBufPort() const { return _pbsPort.toInt(); }; quint16 getProtoBufPort() const { return _pbsPort.toInt(); }
/// ///
/// @brief set new json server port /// @brief set new json server port
/// ///
void setJsonServerPort(quint16 port) { _jssPort = QString::number(port); }; void setJsonServerPort( quint16 port ) { _jssPort = QString::number( port ); }
/// ///
/// @brief get new json server port /// @brief get new json server port
/// ///
quint16 getJsonServerPort() const { return _jssPort.toInt(); }; quint16 getJsonServerPort() const { return _jssPort.toInt(); }
/// ///
/// @brief set new ssl server port /// @brief set new ssl server port
/// ///
void setSSLServerPort(quint16 port) { _sslPort = QString::number(port); }; void setSSLServerPort( quint16 port ) { _sslPort = QString::number( port ); }
/// ///
/// @brief get new ssl server port /// @brief get new ssl server port
/// ///
quint16 getSSLServerPort() const { return _sslPort.toInt(); }; quint16 getSSLServerPort() const { return _sslPort.toInt(); }
/// ///
/// @brief set new hyperion name /// @brief set new hyperion name
/// ///
void setHyperionName(const QString &name) { _name = name; }; void setHyperionName( const QString &name ) { _name = name; }
/// ///
/// @brief get hyperion name /// @brief get hyperion name
/// ///
QString getHyperionName() const { return _name; }; QString getHyperionName() const { return _name; }
signals: signals:
/// ///
/// @brief Emits whenever a new SSDP search "man : ssdp:discover" is received along with the service type /// @brief Emits whenever a new SSDP search "man : ssdp:discover" is received along with the service type
@ -133,23 +130,18 @@ signals:
/// @param address The ip of the caller /// @param address The ip of the caller
/// @param port The port of the caller /// @param port The port of the caller
/// ///
void msearchRequestReceived(const QString& target, const QString& mx, const QString address, quint16 port); void msearchRequestReceived( const QString &target,
const QString &mx,
const QString address,
quint16 port );
private: private:
Logger* _log; Logger *_log;
QUdpSocket* _udpSocket; QUdpSocket *_udpSocket;
QString _serverHeader, QString _serverHeader, _uuid, _fbsPort, _pbsPort, _jssPort, _sslPort, _name, _descAddress;
_uuid, bool _running;
_fbsPort,
_pbsPort,
_jssPort,
_sslPort,
_name,
_descAddress;
bool _running;
private slots: private slots:
void readPendingDatagrams(); void readPendingDatagrams();
}; };

View File

@ -38,7 +38,7 @@ public:
_height(other._height), _height(other._height),
_pixels(new Pixel_T[other._width * other._height + 1]) _pixels(new Pixel_T[other._width * other._height + 1])
{ {
memcpy(_pixels, other._pixels, (long) other._width * other._height * sizeof(Pixel_T)); memcpy(_pixels, other._pixels, static_cast<ulong>(other._width) * static_cast<ulong>(other._height) * sizeof(Pixel_T));
} }
ImageData& operator=(ImageData rhs) ImageData& operator=(ImageData rhs)
@ -150,7 +150,7 @@ public:
ssize_t size() const ssize_t size() const
{ {
return (ssize_t) _width * _height * sizeof(Pixel_T); return static_cast<ssize_t>(_width) * static_cast<ssize_t>(_height) * sizeof(Pixel_T);
} }
void clear() void clear()
@ -163,7 +163,7 @@ public:
_pixels = new Pixel_T[2]; _pixels = new Pixel_T[2];
} }
memset(_pixels, 0, (unsigned long) _width * _height * sizeof(Pixel_T)); memset(_pixels, 0, static_cast<unsigned long>(_width) * static_cast<unsigned long>(_height) * sizeof(Pixel_T));
} }
private: private:

View File

@ -16,7 +16,7 @@ class NetOrigin : public QObject
Q_OBJECT Q_OBJECT
private: private:
friend class HyperionDaemon; friend class HyperionDaemon;
NetOrigin(QObject* parent = 0, Logger* log = Logger::getInstance("NETWORK")); NetOrigin(QObject* parent = nullptr, Logger* log = Logger::getInstance("NETWORK"));
public: public:
/// ///
@ -33,8 +33,8 @@ public:
/// ///
bool isLocalAddress(const QHostAddress& address, const QHostAddress& local) const; bool isLocalAddress(const QHostAddress& address, const QHostAddress& local) const;
static NetOrigin* getInstance(){ return instance; }; static NetOrigin *getInstance() { return instance; }
static NetOrigin* instance; static NetOrigin *instance;
private slots: private slots:
/// ///

View File

@ -19,9 +19,6 @@ public:
/// @param adjustB /// @param adjustB
RgbChannelAdjustment(uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, QString channelName=""); RgbChannelAdjustment(uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, QString channelName="");
/// Destructor
~RgbChannelAdjustment();
/// ///
/// Transform the given array value /// Transform the given array value
/// ///

View File

@ -36,9 +36,9 @@ namespace hyperion {
{ {
std::vector<ColorRgb> fg_color = { std::vector<ColorRgb> fg_color = {
ColorRgb { ColorRgb {
(uint8_t)FGCONFIG_ARRAY.at(0).toInt(0), static_cast<uint8_t>(FGCONFIG_ARRAY.at(0).toInt(0)),
(uint8_t)FGCONFIG_ARRAY.at(1).toInt(0), static_cast<uint8_t>(FGCONFIG_ARRAY.at(1).toInt(0)),
(uint8_t)FGCONFIG_ARRAY.at(2).toInt(0) static_cast<uint8_t>(FGCONFIG_ARRAY.at(2).toInt(0))
} }
}; };
hyperion->setColor(FG_PRIORITY, fg_color, fg_duration_ms); hyperion->setColor(FG_PRIORITY, fg_color, fg_duration_ms);
@ -62,22 +62,22 @@ namespace hyperion {
{ {
const double backlightThreshold = colorConfig["backlightThreshold"].toDouble(0.0); const double backlightThreshold = colorConfig["backlightThreshold"].toDouble(0.0);
const bool backlightColored = colorConfig["backlightColored"].toBool(false); const bool backlightColored = colorConfig["backlightColored"].toBool(false);
const double brightness = colorConfig["brightness"].toInt(100); const int brightness = colorConfig["brightness"].toInt(100);
const double brightnessComp = colorConfig["brightnessCompensation"].toInt(100); const int brightnessComp = colorConfig["brightnessCompensation"].toInt(100);
const double gammaR = colorConfig["gammaRed"].toDouble(1.0); const double gammaR = colorConfig["gammaRed"].toDouble(1.0);
const double gammaG = colorConfig["gammaGreen"].toDouble(1.0); const double gammaG = colorConfig["gammaGreen"].toDouble(1.0);
const double gammaB = colorConfig["gammaBlue"].toDouble(1.0); const double gammaB = colorConfig["gammaBlue"].toDouble(1.0);
return RgbTransform(gammaR, gammaG, gammaB, backlightThreshold, backlightColored, brightness, brightnessComp); return RgbTransform(gammaR, gammaG, gammaB, backlightThreshold, backlightColored, static_cast<uint8_t>(brightness), static_cast<uint8_t>(brightnessComp));
} }
RgbChannelAdjustment createRgbChannelAdjustment(const QJsonObject& colorConfig, const QString& channelName, int defaultR, int defaultG, int defaultB) RgbChannelAdjustment createRgbChannelAdjustment(const QJsonObject& colorConfig, const QString& channelName, int defaultR, int defaultG, int defaultB)
{ {
const QJsonArray& channelConfig = colorConfig[channelName].toArray(); const QJsonArray& channelConfig = colorConfig[channelName].toArray();
return RgbChannelAdjustment( return RgbChannelAdjustment(
channelConfig[0].toInt(defaultR), static_cast<uint8_t>(channelConfig[0].toInt(defaultR)),
channelConfig[1].toInt(defaultG), static_cast<uint8_t>(channelConfig[1].toInt(defaultG)),
channelConfig[2].toInt(defaultB), static_cast<uint8_t>(channelConfig[2].toInt(defaultB)),
"ChannelAdjust_" + channelName.toUpper() "ChannelAdjust_" + channelName.toUpper()
); );
} }
@ -101,7 +101,7 @@ namespace hyperion {
return adjustment; return adjustment;
} }
MultiColorAdjustment * createLedColorsAdjustment(unsigned ledCnt, const QJsonObject & colorConfig) MultiColorAdjustment * createLedColorsAdjustment(int ledCnt, const QJsonObject & colorConfig)
{ {
// Create the result, the transforms are added to this // Create the result, the transforms are added to this
MultiColorAdjustment * adjustment = new MultiColorAdjustment(ledCnt); MultiColorAdjustment * adjustment = new MultiColorAdjustment(ledCnt);
@ -233,7 +233,7 @@ namespace hyperion {
std::sort(midPointsY.begin(), midPointsY.end()); std::sort(midPointsY.begin(), midPointsY.end());
midPointsY.erase(std::unique(midPointsY.begin(), midPointsY.end()), midPointsY.end()); midPointsY.erase(std::unique(midPointsY.begin(), midPointsY.end()), midPointsY.end());
QSize gridSize( midPointsX.size(), midPointsY.size() ); QSize gridSize( static_cast<int>(midPointsX.size()), static_cast<int>(midPointsY.size()) );
// Correct the grid in case it is malformed in width vs height // Correct the grid in case it is malformed in width vs height
// Expected is at least 50% of width <-> height // Expected is at least 50% of width <-> height

View File

@ -48,7 +48,7 @@ public:
{ {
case QJsonValue::Array: case QJsonValue::Array:
{ {
for (const QJsonValue &v : value.toArray()) for (const QJsonValueRef v : value.toArray())
{ {
ret = getDefaultValue(v); ret = getDefaultValue(v);
if (!ret.isEmpty()) if (!ret.isEmpty())

View File

@ -33,7 +33,7 @@ class WebServer : public QObject
Q_OBJECT Q_OBJECT
public: public:
WebServer (const QJsonDocument& config, bool useSsl, QObject * parent = 0); WebServer (const QJsonDocument& config, bool useSsl, QObject * parent = nullptr);
~WebServer () override; ~WebServer () override;

View File

@ -473,6 +473,7 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
{ {
grabbers["active"] = GrabberWrapper::getInstance()->getActive(); grabbers["active"] = GrabberWrapper::getInstance()->getActive();
} }
// get available grabbers // get available grabbers
for (auto grabber : GrabberWrapper::availableGrabbers()) for (auto grabber : GrabberWrapper::availableGrabbers())
{ {
@ -688,12 +689,13 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
if (subsArr.contains("all")) if (subsArr.contains("all"))
{ {
subsArr = QJsonArray(); subsArr = QJsonArray();
for (const auto &entry : _jsonCB->getCommands()) for (const auto& entry : _jsonCB->getCommands())
{ {
subsArr.append(entry); subsArr.append(entry);
} }
} }
for (const auto &entry : subsArr)
for (const QJsonValueRef entry : subsArr)
{ {
// config callbacks just if auth is set // config callbacks just if auth is set
if ((entry == "settings-update" || entry == "token-update") && !API::isAdminAuthorized()) if ((entry == "settings-update" || entry == "token-update") && !API::isAdminAuthorized())
@ -1416,7 +1418,8 @@ void JsonAPI::handleLedDeviceCommand(const QJsonObject &message, const QString &
if (subc == "discover") if (subc == "discover")
{ {
ledDevice = LedDeviceFactory::construct(config); ledDevice = LedDeviceFactory::construct(config);
const QJsonObject devicesDiscovered = ledDevice->discover(); const QJsonObject &params = message["params"].toObject();
const QJsonObject devicesDiscovered = ledDevice->discover(params);
Debug(_log, "response: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() ); Debug(_log, "response: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );

View File

@ -386,7 +386,7 @@ void BoblightClientConnection::sendLightMessage()
sendMessage(QByteArray(buffer, n)); sendMessage(QByteArray(buffer, n));
double h0, h1, v0, v1; double h0, h1, v0, v1;
for (unsigned i = 0; i < _hyperion->getLedCount(); ++i) for (int i = 0; i < _hyperion->getLedCount(); ++i)
{ {
_imageProcessor->getScanParameters(i, h0, h1, v0, v1); _imageProcessor->getScanParameters(i, h0, h1, v0, v1);
n = snprintf(buffer, sizeof(buffer), "light %03d scan %f %f %f %f\n", i, 100*v0, 100*v1, 100*h0, 100*h1); n = snprintf(buffer, sizeof(buffer), "light %03d scan %f %f %f %f\n", i, 100*v0, 100*v1, 100*h0, 100*h1);

View File

@ -17,7 +17,7 @@ class ImageProcessor;
class Hyperion; class Hyperion;
/// ///
/// The Connection object created by \a BoblightServer when a new connection is establshed /// The Connection object created by \a BoblightServer when a new connection is established
/// ///
class BoblightClientConnection : public QObject class BoblightClientConnection : public QObject
{ {

View File

@ -21,6 +21,11 @@ Option::Option(const QCommandLineOption &other)
: QCommandLineOption(other) : QCommandLineOption(other)
{} {}
Option::~Option()
{
}
QString Option::value(Parser &parser) const QString Option::value(Parser &parser) const
{ {
return parser.value(*this); return parser.value(*this);

View File

@ -1,5 +1,3 @@
#include <QtDebug>
#include <QtGui>
#include "commandline/Parser.h" #include "commandline/Parser.h"
using namespace commandline; using namespace commandline;
@ -21,7 +19,7 @@ bool Parser::parse(const QStringList &arguments)
QString value = this->value(*option); QString value = this->value(*option);
if (!option->validate(*this, value)) { if (!option->validate(*this, value)) {
const QString error = option->getError(); const QString error = option->getError();
if (error.size()) { if (!error.isEmpty()) {
_errorText = tr("%1 is not a valid option for %2\n%3").arg(value, option->name(), error); _errorText = tr("%1 is not a valid option for %2\n%3").arg(value, option->name(), error);
} }
else else
@ -44,15 +42,14 @@ void Parser::process(const QStringList &arguments)
} }
} }
void Parser::process(const QCoreApplication &app) void Parser::process(const QCoreApplication& /*app*/)
{ {
Q_UNUSED(app);
process(QCoreApplication::arguments()); process(QCoreApplication::arguments());
} }
QString Parser::errorText() const QString Parser::errorText() const
{ {
return (_errorText.size()) ? _errorText : _parser.errorText(); return (!_errorText.isEmpty()) ? _errorText : _parser.errorText();
} }
bool Parser::addOption(Option &option) bool Parser::addOption(Option &option)
@ -66,27 +63,27 @@ bool Parser::addOption(Option * const option)
return _parser.addOption(*option); return _parser.addOption(*option);
} }
QStringList Parser::_getNames(const char shortOption, const QString longOption) QStringList Parser::_getNames(const char shortOption, const QString& longOption)
{ {
QStringList names; QStringList names;
if (shortOption != 0x0) if (shortOption != 0x0)
{ {
names << QString(shortOption); names << QString(shortOption);
} }
if (longOption.size()) if (longOption.size() != 0)
{ {
names << longOption; names << longOption;
} }
return names; return names;
} }
QString Parser::_getDescription(const QString description, const QString default_) QString Parser::_getDescription(const QString& description, const QString& default_)
{ {
/* Add the translations if available */ /* Add the translations if available */
QString formattedDescription(tr(qPrintable(description))); QString formattedDescription(tr(qPrintable(description)));
/* Fill in the default if needed */ /* Fill in the default if needed */
if (default_.size()) if (!default_.isEmpty())
{ {
if(!formattedDescription.contains("%1")) if(!formattedDescription.contains("%1"))
{ {

View File

@ -56,8 +56,8 @@ void Effect::setModuleParameters()
PyModule_AddObject(module, "__effectObj", PyCapsule_New((void*)this, "hyperion.__effectObj", nullptr)); PyModule_AddObject(module, "__effectObj", PyCapsule_New((void*)this, "hyperion.__effectObj", nullptr));
// add ledCount variable to the interpreter // add ledCount variable to the interpreter
unsigned ledCount = 0; int ledCount = 0;
QMetaObject::invokeMethod(_hyperion, "getLedCount", Qt::BlockingQueuedConnection, Q_RETURN_ARG(unsigned, ledCount)); QMetaObject::invokeMethod(_hyperion, "getLedCount", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, ledCount));
PyObject_SetAttrString(module, "ledCount", Py_BuildValue("i", ledCount)); PyObject_SetAttrString(module, "ledCount", Py_BuildValue("i", ledCount));
// add minimumWriteTime variable to the interpreter // add minimumWriteTime variable to the interpreter

View File

@ -138,7 +138,7 @@ PyObject* EffectModule::wrapSetColor(PyObject *self, PyObject *args)
int argCount = PyTuple_Size(args); int argCount = PyTuple_Size(args);
if (argCount == 3) if (argCount == 3)
{ {
// three seperate arguments for red, green, and blue // three separate arguments for red, green, and blue
ColorRgb color; ColorRgb color;
if (PyArg_ParseTuple(args, "bbb", &color.red, &color.green, &color.blue)) if (PyArg_ParseTuple(args, "bbb", &color.red, &color.green, &color.blue))
{ {
@ -158,7 +158,7 @@ PyObject* EffectModule::wrapSetColor(PyObject *self, PyObject *args)
if (PyByteArray_Check(bytearray)) if (PyByteArray_Check(bytearray))
{ {
size_t length = PyByteArray_Size(bytearray); size_t length = PyByteArray_Size(bytearray);
if (length == 3 * getEffect()->_hyperion->getLedCount()) if (length == 3 * static_cast<size_t>(getEffect()->_hyperion->getLedCount()))
{ {
char * data = PyByteArray_AS_STRING(bytearray); char * data = PyByteArray_AS_STRING(bytearray);
memcpy(getEffect()->_colors.data(), data, length); memcpy(getEffect()->_colors.data(), data, length);

View File

@ -7,14 +7,14 @@ using namespace hyperion;
ComponentRegister::ComponentRegister(Hyperion* hyperion) ComponentRegister::ComponentRegister(Hyperion* hyperion)
: _hyperion(hyperion) : _hyperion(hyperion)
, _log(Logger::getInstance("COMPONENTREG")) , _log(Logger::getInstance("COMPONENTREG"))
{ {
// init all comps to false // init all comps to false
QVector<hyperion::Components> vect; QVector<hyperion::Components> vect;
vect << COMP_ALL << COMP_SMOOTHING << COMP_BLACKBORDER << COMP_FORWARDER << COMP_BOBLIGHTSERVER << COMP_GRABBER << COMP_V4L << COMP_LEDDEVICE; vect << COMP_ALL << COMP_SMOOTHING << COMP_BLACKBORDER << COMP_FORWARDER << COMP_BOBLIGHTSERVER << COMP_GRABBER << COMP_V4L << COMP_LEDDEVICE;
for(auto e : vect) for(auto e : vect)
{ {
_componentStates.emplace(e, ((e == COMP_ALL) ? true : false)); _componentStates.emplace(e, (e == COMP_ALL));
} }
connect(_hyperion, &Hyperion::compStateChangeRequest, this, &ComponentRegister::handleCompStateChangeRequest); connect(_hyperion, &Hyperion::compStateChangeRequest, this, &ComponentRegister::handleCompStateChangeRequest);
@ -36,7 +36,7 @@ void ComponentRegister::setNewComponentState(hyperion::Components comp, bool act
Debug( _log, "%s: %s", componentToString(comp), (activated? "enabled" : "disabled")); Debug( _log, "%s: %s", componentToString(comp), (activated? "enabled" : "disabled"));
_componentStates[comp] = activated; _componentStates[comp] = activated;
// emit component has changed state // emit component has changed state
emit updatedComponentState(comp, activated); emit updatedComponentState(comp, activated);
} }
} }
@ -48,28 +48,34 @@ void ComponentRegister::handleCompStateChangeRequest(hyperion::Components comps,
if(!activated && _prevComponentStates.empty()) if(!activated && _prevComponentStates.empty())
{ {
Debug(_log,"Disable Hyperion, store current component states"); Debug(_log,"Disable Hyperion, store current component states");
for(const auto comp : _componentStates) for(const auto &comp : _componentStates)
{ {
// save state // save state
_prevComponentStates.emplace(comp.first, comp.second); _prevComponentStates.emplace(comp.first, comp.second);
// disable if enabled // disable if enabled
if(comp.second) if(comp.second)
{
emit _hyperion->compStateChangeRequest(comp.first, false); emit _hyperion->compStateChangeRequest(comp.first, false);
}
} }
setNewComponentState(COMP_ALL, false); setNewComponentState(COMP_ALL, false);
} }
else if(activated && !_prevComponentStates.empty()) else
{ {
Debug(_log,"Enable Hyperion, recover previous component states"); if(activated && !_prevComponentStates.empty())
for(const auto comp : _prevComponentStates)
{ {
// if comp was enabled, enable again Debug(_log,"Enable Hyperion, recover previous component states");
if(comp.second) for(const auto &comp : _prevComponentStates)
emit _hyperion->compStateChangeRequest(comp.first, true); {
// if comp was enabled, enable again
if(comp.second)
{
emit _hyperion->compStateChangeRequest(comp.first, true);
}
}
_prevComponentStates.clear();
setNewComponentState(COMP_ALL, true);
} }
_prevComponentStates.clear();
setNewComponentState(COMP_ALL, true);
} }
_inProgress = false; _inProgress = false;
} }

View File

@ -18,7 +18,7 @@
#include <utils/GlobalSignals.h> #include <utils/GlobalSignals.h>
#include <utils/Logger.h> #include <utils/Logger.h>
// Leddevice includes // LedDevice includes
#include <leddevice/LedDeviceWrapper.h> #include <leddevice/LedDeviceWrapper.h>
#include <hyperion/MultiColorAdjustment.h> #include <hyperion/MultiColorAdjustment.h>
@ -46,14 +46,19 @@ Hyperion::Hyperion(quint8 instance, bool readonlyMode)
, _componentRegister(this) , _componentRegister(this)
, _ledString(hyperion::createLedString(getSetting(settings::LEDS).array(), hyperion::createColorOrder(getSetting(settings::DEVICE).object()))) , _ledString(hyperion::createLedString(getSetting(settings::LEDS).array(), hyperion::createColorOrder(getSetting(settings::DEVICE).object())))
, _imageProcessor(new ImageProcessor(_ledString, this)) , _imageProcessor(new ImageProcessor(_ledString, this))
, _muxer(_ledString.leds().size(), this) , _muxer(static_cast<int>(_ledString.leds().size()), this)
, _raw2ledAdjustment(hyperion::createLedColorsAdjustment(_ledString.leds().size(), getSetting(settings::COLOR).object())) , _raw2ledAdjustment(hyperion::createLedColorsAdjustment(static_cast<int>(_ledString.leds().size()), getSetting(settings::COLOR).object()))
, _ledDeviceWrapper(nullptr)
, _deviceSmooth(nullptr)
, _effectEngine(nullptr) , _effectEngine(nullptr)
, _messageForwarder(nullptr) , _messageForwarder(nullptr)
, _log(Logger::getInstance("HYPERION")) , _log(Logger::getInstance("HYPERION"))
, _hwLedCount() , _hwLedCount()
, _ledGridSize(hyperion::getLedLayoutGridSize(getSetting(settings::LEDS).array())) , _ledGridSize(hyperion::getLedLayoutGridSize(getSetting(settings::LEDS).array()))
, _BGEffectHandler(nullptr)
,_captureCont(nullptr)
, _ledBuffer(_ledString.leds().size(), ColorRgb::BLACK) , _ledBuffer(_ledString.leds().size(), ColorRgb::BLACK)
, _boblightServer(nullptr)
, _readOnlyMode(readonlyMode) , _readOnlyMode(readonlyMode)
{ {
@ -78,9 +83,9 @@ void Hyperion::start()
} }
// handle hwLedCount // handle hwLedCount
_hwLedCount = qMax(unsigned(getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount())), getLedCount()); _hwLedCount = qMax(getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount()), getLedCount());
// init colororder vector // Initialize colororder vector
for (const Led& led : _ledString.leds()) for (const Led& led : _ledString.leds())
{ {
_ledStringColorOrder.push_back(led.colorOrder); _ledStringColorOrder.push_back(led.colorOrder);
@ -97,12 +102,14 @@ void Hyperion::start()
// listen for settings updates of this instance (LEDS & COLOR) // listen for settings updates of this instance (LEDS & COLOR)
connect(_settingsManager, &SettingsManager::settingsChanged, this, &Hyperion::handleSettingsUpdate); connect(_settingsManager, &SettingsManager::settingsChanged, this, &Hyperion::handleSettingsUpdate);
#if 0
// set color correction activity state // set color correction activity state
const QJsonObject color = getSetting(settings::COLOR).object(); const QJsonObject color = getSetting(settings::COLOR).object();
#endif
// initialize leddevices // initialize LED-devices
QJsonObject ledDevice = getSetting(settings::DEVICE).object(); QJsonObject ledDevice = getSetting(settings::DEVICE).object();
ledDevice["currentLedCount"] = int(_hwLedCount); // Inject led count info ledDevice["currentLedCount"] = _hwLedCount; // Inject led count info
_ledDeviceWrapper = new LedDeviceWrapper(this); _ledDeviceWrapper = new LedDeviceWrapper(this);
connect(this, &Hyperion::compStateChangeRequest, _ledDeviceWrapper, &LedDeviceWrapper::handleComponentState); connect(this, &Hyperion::compStateChangeRequest, _ledDeviceWrapper, &LedDeviceWrapper::handleComponentState);
@ -115,7 +122,9 @@ void Hyperion::start()
// create the message forwarder only on main instance // create the message forwarder only on main instance
if (_instIndex == 0) if (_instIndex == 0)
{
_messageForwarder = new MessageForwarder(this); _messageForwarder = new MessageForwarder(this);
}
// create the effect engine; needs to be initialized after smoothing! // create the effect engine; needs to be initialized after smoothing!
_effectEngine = new EffectEngine(this); _effectEngine = new EffectEngine(this);
@ -136,14 +145,14 @@ void Hyperion::start()
connect(GlobalSignals::getInstance(), &GlobalSignals::setGlobalColor, this, &Hyperion::setColor); connect(GlobalSignals::getInstance(), &GlobalSignals::setGlobalColor, this, &Hyperion::setColor);
connect(GlobalSignals::getInstance(), &GlobalSignals::setGlobalImage, this, &Hyperion::setInputImage); connect(GlobalSignals::getInstance(), &GlobalSignals::setGlobalImage, this, &Hyperion::setInputImage);
// if there is no startup / background eff and no sending capture interface we probably want to push once BLACK (as PrioMuxer won't emit a prioritiy change) // if there is no startup / background effect and no sending capture interface we probably want to push once BLACK (as PrioMuxer won't emit a priority change)
update(); update();
// boblight, can't live in global scope as it depends on layout // boblight, can't live in global scope as it depends on layout
_boblightServer = new BoblightServer(this, getSetting(settings::BOBLSERVER)); _boblightServer = new BoblightServer(this, getSetting(settings::BOBLSERVER));
connect(this, &Hyperion::settingsChanged, _boblightServer, &BoblightServer::handleSettingsUpdate); connect(this, &Hyperion::settingsChanged, _boblightServer, &BoblightServer::handleSettingsUpdate);
// instance inited, enter thread event loop // instance initiated, enter thread event loop
emit started(); emit started();
} }
@ -178,7 +187,7 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co
const QJsonObject obj = config.object(); const QJsonObject obj = config.object();
// change in color recreate ledAdjustments // change in color recreate ledAdjustments
delete _raw2ledAdjustment; delete _raw2ledAdjustment;
_raw2ledAdjustment = hyperion::createLedColorsAdjustment(_ledString.leds().size(), obj); _raw2ledAdjustment = hyperion::createLedColorsAdjustment(static_cast<int>(_ledString.leds().size()), obj);
if (!_raw2ledAdjustment->verifyAdjustments()) if (!_raw2ledAdjustment->verifyAdjustments())
{ {
@ -189,13 +198,13 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co
{ {
const QJsonArray leds = config.array(); const QJsonArray leds = config.array();
// stop and cache all running effects, as effects depend heavily on ledlayout // stop and cache all running effects, as effects depend heavily on LED-layout
_effectEngine->cacheRunningEffects(); _effectEngine->cacheRunningEffects();
// ledstring, img processor, muxer, ledGridSize (eff engine image based effects), _ledBuffer and ByteOrder of ledstring // ledstring, img processor, muxer, ledGridSize (effect-engine image based effects), _ledBuffer and ByteOrder of ledstring
_ledString = hyperion::createLedString(leds, hyperion::createColorOrder(getSetting(settings::DEVICE).object())); _ledString = hyperion::createLedString(leds, hyperion::createColorOrder(getSetting(settings::DEVICE).object()));
_imageProcessor->setLedString(_ledString); _imageProcessor->setLedString(_ledString);
_muxer.updateLedColorsLength(_ledString.leds().size()); _muxer.updateLedColorsLength(static_cast<int>(_ledString.leds().size()));
_ledGridSize = hyperion::getLedLayoutGridSize(leds); _ledGridSize = hyperion::getLedLayoutGridSize(leds);
std::vector<ColorRgb> color(_ledString.leds().size(), ColorRgb{0,0,0}); std::vector<ColorRgb> color(_ledString.leds().size(), ColorRgb{0,0,0});
@ -208,11 +217,11 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co
} }
// handle hwLedCount update // handle hwLedCount update
_hwLedCount = qMax(unsigned(getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount())), getLedCount()); _hwLedCount = qMax(getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount()), getLedCount());
// change in leds are also reflected in adjustment // change in leds are also reflected in adjustment
delete _raw2ledAdjustment; delete _raw2ledAdjustment;
_raw2ledAdjustment = hyperion::createLedColorsAdjustment(_ledString.leds().size(), getSetting(settings::COLOR).object()); _raw2ledAdjustment = hyperion::createLedColorsAdjustment(static_cast<int>(_ledString.leds().size()), getSetting(settings::COLOR).object());
// start cached effects // start cached effects
_effectEngine->startCachedEffects(); _effectEngine->startCachedEffects();
@ -222,7 +231,7 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co
QJsonObject dev = config.object(); QJsonObject dev = config.object();
// handle hwLedCount update // handle hwLedCount update
_hwLedCount = qMax(unsigned(dev["hardwareLedCount"].toInt(getLedCount())), getLedCount()); _hwLedCount = qMax(dev["hardwareLedCount"].toInt(getLedCount()), getLedCount());
// force ledString update, if device ByteOrder changed // force ledString update, if device ByteOrder changed
if(_ledDeviceWrapper->getColorOrder() != dev["colorOrder"].toString("rgb")) if(_ledDeviceWrapper->getColorOrder() != dev["colorOrder"].toString("rgb"))
@ -238,7 +247,7 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co
} }
// do always reinit until the led devices can handle dynamic changes // do always reinit until the led devices can handle dynamic changes
dev["currentLedCount"] = int(_hwLedCount); // Inject led count info dev["currentLedCount"] = _hwLedCount; // Inject led count info
_ledDeviceWrapper->createLedDevice(dev); _ledDeviceWrapper->createLedDevice(dev);
// TODO: Check, if framegrabber frequency is lower than latchtime..., if yes, stop // TODO: Check, if framegrabber frequency is lower than latchtime..., if yes, stop
@ -277,9 +286,9 @@ unsigned Hyperion::updateSmoothingConfig(unsigned id, int settlingTime_ms, doubl
return _deviceSmooth->updateConfig(id, settlingTime_ms, ledUpdateFrequency_hz, updateDelay); return _deviceSmooth->updateConfig(id, settlingTime_ms, ledUpdateFrequency_hz, updateDelay);
} }
unsigned Hyperion::getLedCount() const int Hyperion::getLedCount() const
{ {
return _ledString.leds().size(); return static_cast<int>(_ledString.leds().size());
} }
void Hyperion::setSourceAutoSelect(bool state) void Hyperion::setSourceAutoSelect(bool state)
@ -323,7 +332,9 @@ bool Hyperion::setInput(int priority, const std::vector<ColorRgb>& ledColors, in
{ {
// clear effect if this call does not come from an effect // clear effect if this call does not come from an effect
if(clearEffect) if(clearEffect)
{
_effectEngine->channelCleared(priority); _effectEngine->channelCleared(priority);
}
// if this priority is visible, update immediately // if this priority is visible, update immediately
if(priority == _muxer.getCurrentPriority()) if(priority == _muxer.getCurrentPriority())
@ -348,7 +359,9 @@ bool Hyperion::setInputImage(int priority, const Image<ColorRgb>& image, int64_t
{ {
// clear effect if this call does not come from an effect // clear effect if this call does not come from an effect
if(clearEffect) if(clearEffect)
{
_effectEngine->channelCleared(priority); _effectEngine->channelCleared(priority);
}
// if this priority is visible, update immediately // if this priority is visible, update immediately
if(priority == _muxer.getCurrentPriority()) if(priority == _muxer.getCurrentPriority())
@ -370,7 +383,9 @@ void Hyperion::setColor(int priority, const std::vector<ColorRgb> &ledColors, in
{ {
// clear effect if this call does not come from an effect // clear effect if this call does not come from an effect
if (clearEffects) if (clearEffects)
{
_effectEngine->channelCleared(priority); _effectEngine->channelCleared(priority);
}
// create full led vector from single/multiple colors // create full led vector from single/multiple colors
size_t size = _ledString.leds().size(); size_t size = _ledString.leds().size();
@ -381,13 +396,17 @@ void Hyperion::setColor(int priority, const std::vector<ColorRgb> &ledColors, in
{ {
newLedColors.emplace_back(entry); newLedColors.emplace_back(entry);
if (newLedColors.size() == size) if (newLedColors.size() == size)
{
goto end; goto end;
}
} }
} }
end: end:
if (getPriorityInfo(priority).componentId != hyperion::COMP_COLOR) if (getPriorityInfo(priority).componentId != hyperion::COMP_COLOR)
{
clear(priority); clear(priority);
}
// register color // register color
registerInput(priority, hyperion::COMP_COLOR, origin); registerInput(priority, hyperion::COMP_COLOR, origin);
@ -414,13 +433,14 @@ void Hyperion::adjustmentsUpdated()
bool Hyperion::clear(int priority, bool forceClearAll) bool Hyperion::clear(int priority, bool forceClearAll)
{ {
bool isCleared = false;
if (priority < 0) if (priority < 0)
{ {
_muxer.clearAll(forceClearAll); _muxer.clearAll(forceClearAll);
// send clearall signal to the effect engine // send clearall signal to the effect engine
_effectEngine->allChannelsCleared(); _effectEngine->allChannelsCleared();
return true; isCleared = true;
} }
else else
{ {
@ -429,9 +449,11 @@ bool Hyperion::clear(int priority, bool forceClearAll)
_effectEngine->channelCleared(priority); _effectEngine->channelCleared(priority);
if (_muxer.clearInput(priority)) if (_muxer.clearInput(priority))
return true; {
isCleared = true;
}
} }
return false; return isCleared;
} }
int Hyperion::getCurrentPriority() const int Hyperion::getCurrentPriority() const
@ -532,9 +554,9 @@ void Hyperion::handleVisibleComponentChanged(hyperion::Components comp)
void Hyperion::handlePriorityChangedLedDevice(const quint8& priority) void Hyperion::handlePriorityChangedLedDevice(const quint8& priority)
{ {
quint8 previousPriority = _muxer.getPreviousPriority(); int previousPriority = _muxer.getPreviousPriority();
Debug(_log,"priority[%u], previousPriority[%u]", priority, previousPriority); Debug(_log,"priority[%d], previousPriority[%d]", priority, previousPriority);
if ( priority == PriorityMuxer::LOWEST_PRIORITY) if ( priority == PriorityMuxer::LOWEST_PRIORITY)
{ {
Debug(_log,"No source left -> switch LED-Device off"); Debug(_log,"No source left -> switch LED-Device off");
@ -604,8 +626,8 @@ void Hyperion::update()
i++; i++;
} }
// fill additional hw leds with black // fill additional hardware LEDs with black
if ( _hwLedCount > _ledBuffer.size() ) if ( _hwLedCount > static_cast<int>(_ledBuffer.size()) )
{ {
_ledBuffer.resize(_hwLedCount, ColorRgb::BLACK); _ledBuffer.resize(_hwLedCount, ColorRgb::BLACK);
} }
@ -623,16 +645,18 @@ void Hyperion::update()
{ {
_deviceSmooth->selectConfig(priorityInfo.smooth_cfg); _deviceSmooth->selectConfig(priorityInfo.smooth_cfg);
// feed smoothing in pause mode to maintain a smooth transistion back to smooth mode // feed smoothing in pause mode to maintain a smooth transition back to smooth mode
if (_deviceSmooth->enabled() || _deviceSmooth->pause()) if (_deviceSmooth->enabled() || _deviceSmooth->pause())
{ {
_deviceSmooth->updateLedValues(_ledBuffer); _deviceSmooth->updateLedValues(_ledBuffer);
} }
} }
} }
//else #if 0
//{ else
// /LEDDevice is disabled {
// Debug(_log, "LEDDevice is disabled - no update required"); //LEDDevice is disabled
//} Debug(_log, "LEDDevice is disabled - no update required");
}
#endif
} }

View File

@ -5,16 +5,6 @@
// hyperion includes // hyperion includes
#include <hyperion/LedString.h> #include <hyperion/LedString.h>
LedString::LedString()
{
// empty
}
LedString::~LedString()
{
// empty
}
std::vector<Led>& LedString::leds() std::vector<Led>& LedString::leds()
{ {
return mLeds; return mLeds;

View File

@ -22,7 +22,7 @@ const int64_t MS_PER_MICRO = 1000;
/// Clamps the rounded values to the byte-interval of [0, 255]. /// Clamps the rounded values to the byte-interval of [0, 255].
ALWAYS_INLINE long clampRounded(const floatT x) { ALWAYS_INLINE long clampRounded(const floatT x) {
return std::min(255l, std::max(0l, std::lroundf(x))); return std::min(255L, std::max(0L, std::lroundf(x)));
} }
/// The number of bits that are used for shifting the fixed point values /// The number of bits that are used for shifting the fixed point values
@ -43,15 +43,16 @@ const char* SETTINGS_KEY_DECAY = "decay";
using namespace hyperion; using namespace hyperion;
const int64_t DEFAUL_SETTLINGTIME = 200; // settlingtime in ms const int64_t DEFAUL_SETTLINGTIME = 200; // settlingtime in ms
const double DEFAUL_UPDATEFREQUENCY = 25; // updatefrequncy in hz const int DEFAUL_UPDATEFREQUENCY = 25; // updatefrequncy in hz
const int64_t DEFAUL_UPDATEINTERVALL = static_cast<int64_t>(1000 / DEFAUL_UPDATEFREQUENCY); // updateintervall in ms
constexpr std::chrono::milliseconds DEFAUL_UPDATEINTERVALL{1000/ DEFAUL_UPDATEFREQUENCY};
const unsigned DEFAUL_OUTPUTDEPLAY = 0; // outputdelay in ms const unsigned DEFAUL_OUTPUTDEPLAY = 0; // outputdelay in ms
LinearColorSmoothing::LinearColorSmoothing(const QJsonDocument &config, Hyperion *hyperion) LinearColorSmoothing::LinearColorSmoothing(const QJsonDocument &config, Hyperion *hyperion)
: QObject(hyperion) : QObject(hyperion)
, _log(Logger::getInstance("SMOOTHING")) , _log(Logger::getInstance("SMOOTHING"))
, _hyperion(hyperion) , _hyperion(hyperion)
, _updateInterval(DEFAUL_UPDATEINTERVALL) , _updateInterval(DEFAUL_UPDATEINTERVALL.count())
, _settlingTime(DEFAUL_SETTLINGTIME) , _settlingTime(DEFAUL_SETTLINGTIME)
, _timer(new QTimer(this)) , _timer(new QTimer(this))
, _outputDelay(DEFAUL_OUTPUTDEPLAY) , _outputDelay(DEFAUL_OUTPUTDEPLAY)
@ -61,7 +62,7 @@ LinearColorSmoothing::LinearColorSmoothing(const QJsonDocument &config, Hyperion
, _pause(false) , _pause(false)
, _currentConfigId(0) , _currentConfigId(0)
, _enabled(false) , _enabled(false)
, tempValues(std::vector<uint64_t>(0, 0l)) , tempValues(std::vector<uint64_t>(0, 0L))
{ {
// init cfg 0 (default) // init cfg 0 (default)
addConfig(DEFAUL_SETTLINGTIME, DEFAUL_UPDATEFREQUENCY, DEFAUL_OUTPUTDEPLAY); addConfig(DEFAUL_SETTLINGTIME, DEFAUL_UPDATEFREQUENCY, DEFAUL_OUTPUTDEPLAY);
@ -69,7 +70,7 @@ LinearColorSmoothing::LinearColorSmoothing(const QJsonDocument &config, Hyperion
selectConfig(0, true); selectConfig(0, true);
// add pause on cfg 1 // add pause on cfg 1
SMOOTHING_CFG cfg = {SmoothingType::Linear, 0, 0, 0, 0, 0, false}; SMOOTHING_CFG cfg = {SmoothingType::Linear, false, 0, 0, 0, 0, 0, false, 1};
_cfgList.append(cfg); _cfgList.append(cfg);
// listen for comp changes // listen for comp changes
@ -77,7 +78,7 @@ LinearColorSmoothing::LinearColorSmoothing(const QJsonDocument &config, Hyperion
// timer // timer
connect(_timer, &QTimer::timeout, this, &LinearColorSmoothing::updateLeds); connect(_timer, &QTimer::timeout, this, &LinearColorSmoothing::updateLeds);
Info(_log, "LinearColorSmoothing sizeof floatT == %d", (sizeof(floatT))); //Debug(_log, "LinearColorSmoothing sizeof floatT == %d", (sizeof(floatT)));
} }
void LinearColorSmoothing::handleSettingsUpdate(settings::type type, const QJsonDocument &config) void LinearColorSmoothing::handleSettingsUpdate(settings::type type, const QJsonDocument &config)
@ -89,7 +90,9 @@ void LinearColorSmoothing::handleSettingsUpdate(settings::type type, const QJson
QJsonObject obj = config.object(); QJsonObject obj = config.object();
if (enabled() != obj["enable"].toBool(true)) if (enabled() != obj["enable"].toBool(true))
{
setEnable(obj["enable"].toBool(true)); setEnable(obj["enable"].toBool(true));
}
_continuousOutput = obj["continuousOutput"].toBool(true); _continuousOutput = obj["continuousOutput"].toBool(true);
@ -105,7 +108,7 @@ void LinearColorSmoothing::handleSettingsUpdate(settings::type type, const QJson
cfg.pause = false; cfg.pause = false;
cfg.settlingTime = static_cast<int64_t>(obj["time_ms"].toInt(DEFAUL_SETTLINGTIME)); cfg.settlingTime = static_cast<int64_t>(obj["time_ms"].toInt(DEFAUL_SETTLINGTIME));
cfg.updateInterval = static_cast<int64_t>(1000.0 / obj["updateFrequency"].toDouble(DEFAUL_UPDATEFREQUENCY)); cfg.updateInterval = static_cast<int>(1000.0 / obj["updateFrequency"].toDouble(DEFAUL_UPDATEFREQUENCY));
cfg.outputRate = obj[SETTINGS_KEY_OUTPUT_RATE].toDouble(DEFAUL_UPDATEFREQUENCY); cfg.outputRate = obj[SETTINGS_KEY_OUTPUT_RATE].toDouble(DEFAUL_UPDATEFREQUENCY);
cfg.interpolationRate = obj[SETTINGS_KEY_INTERPOLATION_RATE].toDouble(DEFAUL_UPDATEFREQUENCY); cfg.interpolationRate = obj[SETTINGS_KEY_INTERPOLATION_RATE].toDouble(DEFAUL_UPDATEFREQUENCY);
cfg.outputDelay = static_cast<unsigned>(obj["updateDelay"].toInt(DEFAUL_OUTPUTDEPLAY)); cfg.outputDelay = static_cast<unsigned>(obj["updateDelay"].toInt(DEFAUL_OUTPUTDEPLAY));
@ -155,7 +158,7 @@ int LinearColorSmoothing::updateLedValues(const std::vector<ColorRgb> &ledValues
int retval = 0; int retval = 0;
if (!_enabled) if (!_enabled)
{ {
return -1; retval = -1;
} }
else else
{ {
@ -173,13 +176,13 @@ void LinearColorSmoothing::intitializeComponentVectors(const size_t ledCount)
const size_t len = 3 * ledCount; const size_t len = 3 * ledCount;
meanValues = std::vector<floatT>(len, 0.0f); meanValues = std::vector<floatT>(len, 0.0F);
residualErrors = std::vector<floatT>(len, 0.0f); residualErrors = std::vector<floatT>(len, 0.0F);
tempValues = std::vector<uint64_t>(len, 0l); tempValues = std::vector<uint64_t>(len, 0L);
} }
// Zero the temp vector // Zero the temp vector
std::fill(tempValues.begin(), tempValues.end(), 0l); std::fill(tempValues.begin(), tempValues.end(), 0L);
} }
void LinearColorSmoothing::writeDirect() void LinearColorSmoothing::writeDirect()
@ -232,9 +235,9 @@ void LinearColorSmoothing::assembleAndDitherFrame()
// Update the colors // Update the colors
ColorRgb &prev = _previousValues[i]; ColorRgb &prev = _previousValues[i];
prev.red = (uint8_t)ir; prev.red = static_cast<uint8_t>(ir);
prev.green = (uint8_t)ig; prev.green = static_cast<uint8_t>(ig);
prev.blue = (uint8_t)ib; prev.blue = static_cast<uint8_t>(ib);
// Determine the component errors // Determine the component errors
residualErrors[3 * i + 0] = fr - ir; residualErrors[3 * i + 0] = fr - ir;
@ -262,15 +265,15 @@ void LinearColorSmoothing::assembleFrame()
// Update the colors // Update the colors
ColorRgb &prev = _previousValues[i]; ColorRgb &prev = _previousValues[i];
prev.red = (uint8_t)ir; prev.red = static_cast<uint8_t>(ir);
prev.green = (uint8_t)ig; prev.green = static_cast<uint8_t>(ig);
prev.blue = (uint8_t)ib; prev.blue = static_cast<uint8_t>(ib);
} }
} }
ALWAYS_INLINE void LinearColorSmoothing::aggregateComponents(const std::vector<ColorRgb>& colors, std::vector<uint64_t>& weighted, const floatT weight) { ALWAYS_INLINE void LinearColorSmoothing::aggregateComponents(const std::vector<ColorRgb>& colors, std::vector<uint64_t>& weighted, const floatT weight) {
// Determine the integer-scale by converting the weight to fixed point // Determine the integer-scale by converting the weight to fixed point
const uint64_t scale = (1l<<FPShift) * static_cast<double>(weight); const uint64_t scale = (static_cast<uint64_t>(1L)<<FPShift) * static_cast<double>(weight);
const size_t N = colors.size(); const size_t N = colors.size();
@ -309,7 +312,7 @@ void LinearColorSmoothing::interpolateFrame()
const int64_t windowStart = now - (MS_PER_MICRO * _settlingTime); const int64_t windowStart = now - (MS_PER_MICRO * _settlingTime);
/// The total weight of the frames that were included in our window; sum of the individual weights /// The total weight of the frames that were included in our window; sum of the individual weights
floatT fs = 0.0f; floatT fs = 0.0F;
// To calculate the mean component we iterate over all relevant frames; // To calculate the mean component we iterate over all relevant frames;
// from the most recent to the oldest frame that still clips our moving-average window given by time (now) // from the most recent to the oldest frame that still clips our moving-average window given by time (now)
@ -331,7 +334,7 @@ void LinearColorSmoothing::interpolateFrame()
} }
/// The inverse scaling factor for the color components, clamped to (0, 1.0]; 1.0 for fs < 1, 1 : fs otherwise /// The inverse scaling factor for the color components, clamped to (0, 1.0]; 1.0 for fs < 1, 1 : fs otherwise
const floatT inv_fs = ((fs < 1.0f) ? 1.0f : 1.0f / fs) / (1 << SmallShiftBis); const floatT inv_fs = ((fs < 1.0F) ? 1.0F : 1.0F / fs) / (1 << SmallShiftBis);
// Normalize the mean component values for the window (fs) // Normalize the mean component values for the window (fs)
for (size_t i = 0; i < 3 * N; ++i) for (size_t i = 0; i < 3 * N; ++i)
@ -385,8 +388,8 @@ void LinearColorSmoothing::performDecay(const int64_t now) {
if(_updateInterval <= 0 && !(interpolatePending || writePending)) { if(_updateInterval <= 0 && !(interpolatePending || writePending)) {
const int64_t nextActionExpected = std::min(interpolationTarget, writeTarget); const int64_t nextActionExpected = std::min(interpolationTarget, writeTarget);
const int64_t microsTillNextAction = nextActionExpected - now; const int64_t microsTillNextAction = nextActionExpected - now;
const int64_t SLEEP_MAX_MICROS = 1000l; // We want to use usleep for up to 1ms const int64_t SLEEP_MAX_MICROS = 1000L; // We want to use usleep for up to 1ms
const int64_t SLEEP_RES_MICROS = 100l; // Expected resolution is >= 100µs on stock linux const int64_t SLEEP_RES_MICROS = 100L; // Expected resolution is >= 100µs on stock linux
if(microsTillNextAction > SLEEP_RES_MICROS) { if(microsTillNextAction > SLEEP_RES_MICROS) {
const int64_t wait = std::min(microsTillNextAction - SLEEP_RES_MICROS, SLEEP_MAX_MICROS); const int64_t wait = std::min(microsTillNextAction - SLEEP_RES_MICROS, SLEEP_MAX_MICROS);
@ -398,12 +401,12 @@ void LinearColorSmoothing::performDecay(const int64_t now) {
// Write stats every 30 sec // Write stats every 30 sec
if ((now > (_renderedStatTime + 30 * 1000000)) && (_renderedCounter > _renderedStatCounter)) if ((now > (_renderedStatTime + 30 * 1000000)) && (_renderedCounter > _renderedStatCounter))
{ {
Info(_log, "decay - rendered frames [%d] (%f/s), interpolated frames [%d] (%f/s) in [%f ms]" Debug(_log, "decay - rendered frames [%d] (%f/s), interpolated frames [%d] (%f/s) in [%f ms]"
, _renderedCounter - _renderedStatCounter , _renderedCounter - _renderedStatCounter
, (1.0f * (_renderedCounter - _renderedStatCounter) / ((now - _renderedStatTime) / 1000000.0f)) , (1.0F * (_renderedCounter - _renderedStatCounter) / ((now - _renderedStatTime) / 1000000.0F))
, _interpolationCounter - _interpolationStatCounter , _interpolationCounter - _interpolationStatCounter
, (1.0f * (_interpolationCounter - _interpolationStatCounter) / ((now - _renderedStatTime) / 1000000.0f)) , (1.0F * (_interpolationCounter - _interpolationStatCounter) / ((now - _renderedStatTime) / 1000000.0F))
, (now - _renderedStatTime) / 1000.0f , (now - _renderedStatTime) / 1000.0F
); );
_renderedStatTime = now; _renderedStatTime = now;
_renderedStatCounter = _renderedCounter; _renderedStatCounter = _renderedCounter;
@ -413,7 +416,7 @@ void LinearColorSmoothing::performDecay(const int64_t now) {
void LinearColorSmoothing::performLinear(const int64_t now) { void LinearColorSmoothing::performLinear(const int64_t now) {
const int64_t deltaTime = _targetTime - now; const int64_t deltaTime = _targetTime - now;
const float k = 1.0f - 1.0f * deltaTime / (_targetTime - _previousWriteTime); const float k = 1.0F - 1.0F * deltaTime / (_targetTime - _previousWriteTime);
const size_t N = _previousValues.size(); const size_t N = _previousValues.size();
for (size_t i = 0; i < N; ++i) for (size_t i = 0; i < N; ++i)
@ -461,7 +464,7 @@ void LinearColorSmoothing::updateLeds()
void LinearColorSmoothing::rememberFrame(const std::vector<ColorRgb> &ledColors) void LinearColorSmoothing::rememberFrame(const std::vector<ColorRgb> &ledColors)
{ {
//Info(_log, "rememberFrame - before _frameQueue.size() [%d]", _frameQueue.size()); //Debug(_log, "rememberFrame - before _frameQueue.size() [%d]", _frameQueue.size());
const int64_t now = micros(); const int64_t now = micros();
@ -478,7 +481,7 @@ void LinearColorSmoothing::rememberFrame(const std::vector<ColorRgb> &ledColors)
if (p > 0) if (p > 0)
{ {
//Info(_log, "rememberFrame - erasing %d frames", p); //Debug(_log, "rememberFrame - erasing %d frames", p);
_frameQueue.erase(_frameQueue.begin(), _frameQueue.begin() + p); _frameQueue.erase(_frameQueue.begin(), _frameQueue.begin() + p);
} }
@ -486,7 +489,7 @@ void LinearColorSmoothing::rememberFrame(const std::vector<ColorRgb> &ledColors)
const REMEMBERED_FRAME frame = REMEMBERED_FRAME(now, ledColors); const REMEMBERED_FRAME frame = REMEMBERED_FRAME(now, ledColors);
_frameQueue.push_back(frame); _frameQueue.push_back(frame);
//Info(_log, "rememberFrame - after _frameQueue.size() [%d]", _frameQueue.size()); //Debug(_log, "rememberFrame - after _frameQueue.size() [%d]", _frameQueue.size());
} }
@ -518,10 +521,12 @@ void LinearColorSmoothing::queueColors(const std::vector<ColorRgb> &ledColors)
{ {
// Push new colors in the delay-buffer // Push new colors in the delay-buffer
if (_writeToLedsEnable) if (_writeToLedsEnable)
{
_outputQueue.push_back(ledColors); _outputQueue.push_back(ledColors);
}
// If the delay-buffer is filled pop the front and write to device // If the delay-buffer is filled pop the front and write to device
if (_outputQueue.size() > 0) if (!_outputQueue.empty())
{ {
if (_outputQueue.size() > _outputDelay || !_writeToLedsEnable) if (_outputQueue.size() > _outputDelay || !_writeToLedsEnable)
{ {
@ -581,7 +586,7 @@ unsigned LinearColorSmoothing::addConfig(int settlingTime_ms, double ledUpdateFr
SmoothingType::Linear, SmoothingType::Linear,
false, false,
settlingTime_ms, settlingTime_ms,
int64_t(1000.0 / ledUpdateFrequency_hz), static_cast<int>(1000.0 / ledUpdateFrequency_hz),
ledUpdateFrequency_hz, ledUpdateFrequency_hz,
ledUpdateFrequency_hz, ledUpdateFrequency_hz,
updateDelay, updateDelay,
@ -603,7 +608,7 @@ unsigned LinearColorSmoothing::updateConfig(unsigned cfgID, int settlingTime_ms,
SmoothingType::Linear, SmoothingType::Linear,
false, false,
settlingTime_ms, settlingTime_ms,
int64_t(1000.0 / ledUpdateFrequency_hz), static_cast<int>(1000.0 / ledUpdateFrequency_hz),
ledUpdateFrequency_hz, ledUpdateFrequency_hz,
ledUpdateFrequency_hz, ledUpdateFrequency_hz,
updateDelay, updateDelay,
@ -630,7 +635,7 @@ bool LinearColorSmoothing::selectConfig(unsigned cfg, bool force)
} }
//Debug( _log, "selectConfig FORCED - _currentConfigId [%u], force [%d]", cfg, force); //Debug( _log, "selectConfig FORCED - _currentConfigId [%u], force [%d]", cfg, force);
if (cfg < (unsigned)_cfgList.count()) if (cfg < static_cast<uint>(_cfgList.count()) )
{ {
_smoothingType = _cfgList[cfg].smoothingType; _smoothingType = _cfgList[cfg].smoothingType;
_settlingTime = _cfgList[cfg].settlingTime; _settlingTime = _cfgList[cfg].settlingTime;
@ -642,14 +647,14 @@ bool LinearColorSmoothing::selectConfig(unsigned cfg, bool force)
_interpolationIntervalMicros = int64_t(1000000.0 / _interpolationRate); _interpolationIntervalMicros = int64_t(1000000.0 / _interpolationRate);
_dithering = _cfgList[cfg].dithering; _dithering = _cfgList[cfg].dithering;
_decay = _cfgList[cfg].decay; _decay = _cfgList[cfg].decay;
_invWindow = 1.0f / (MS_PER_MICRO * _settlingTime); _invWindow = 1.0F / (MS_PER_MICRO * _settlingTime);
// Set _weightFrame based on the given decay // Set _weightFrame based on the given decay
const float decay = _decay; const float decay = _decay;
const floatT inv_window = _invWindow; const floatT inv_window = _invWindow;
// For decay != 1 use power-based approach for calculating the moving average values // For decay != 1 use power-based approach for calculating the moving average values
if(std::abs(decay - 1.0f) > std::numeric_limits<float>::epsilon()) { if(std::abs(decay - 1.0F) > std::numeric_limits<float>::epsilon()) {
// Exponential Decay // Exponential Decay
_weightFrame = [inv_window,decay](const int64_t fs, const int64_t fe, const int64_t ws) { _weightFrame = [inv_window,decay](const int64_t fs, const int64_t fe, const int64_t ws) {
const floatT s = (fs - ws) * inv_window; const floatT s = (fs - ws) * inv_window;
@ -660,7 +665,7 @@ bool LinearColorSmoothing::selectConfig(unsigned cfg, bool force)
} else { } else {
// For decay == 1 use linear interpolation of the moving average values // For decay == 1 use linear interpolation of the moving average values
// Linear Decay // Linear Decay
_weightFrame = [inv_window](const int64_t fs, const int64_t fe, const int64_t ws) { _weightFrame = [inv_window](const int64_t fs, const int64_t fe, const int64_t /*ws*/) {
// Linear weighting = (end - start) * scale // Linear weighting = (end - start) * scale
return static_cast<floatT>((fe - fs) * inv_window); return static_cast<floatT>((fe - fs) * inv_window);
}; };
@ -693,7 +698,7 @@ bool LinearColorSmoothing::selectConfig(unsigned cfg, bool force)
// DebugIf( _pause, _log, "set smoothing cfg: %d, pause", _currentConfigId ); // DebugIf( _pause, _log, "set smoothing cfg: %d, pause", _currentConfigId );
const float thalf = (1.0-std::pow(1.0/2, 1.0/_decay))*_settlingTime; const float thalf = (1.0-std::pow(1.0/2, 1.0/_decay))*_settlingTime;
Info( _log, "%s - Time: %d ms, outputRate %f Hz, interpolationRate: %f Hz, timer: %d ms, Dithering: %d, Decay: %f -> HalfTime: %f ms", _smoothingType == SmoothingType::Decay ? "decay" : "linear", _settlingTime, _outputRate, _interpolationRate, _updateInterval, _dithering ? 1 : 0, _decay, thalf); Debug( _log, "cfg [%d]: Type: %s - Time: %d ms, outputRate %f Hz, interpolationRate: %f Hz, timer: %d ms, Dithering: %d, Decay: %f -> HalfTime: %f ms", cfg, _smoothingType == SmoothingType::Decay ? "decay" : "linear", _settlingTime, _outputRate, _interpolationRate, _updateInterval, _dithering ? 1 : 0, _decay, thalf);
return true; return true;
} }

View File

@ -7,7 +7,7 @@
// Qt includes // Qt includes
#include <QVector> #include <QVector>
// hyperion incluse // hyperion includes
#include <leddevice/LedDevice.h> #include <leddevice/LedDevice.h>
#include <utils/Components.h> #include <utils/Components.h>
@ -30,7 +30,7 @@ enum SmoothingType {
Decay, Decay,
}; };
/// Linear Smooting class /// Linear Smoothing class
/// ///
/// This class processes the requested led values and forwards them to the device after applying /// This class processes the requested led values and forwards them to the device after applying
/// a smoothing effect to LED colors. This class can be handled as a generic LedDevice. /// a smoothing effect to LED colors. This class can be handled as a generic LedDevice.
@ -94,12 +94,12 @@ public:
bool enabled() const { return _enabled && !_pause; } bool enabled() const { return _enabled && !_pause; }
/// ///
/// @brief Add a new smoothing cfg which can be used with selectConfig() /// @brief Add a new smoothing configuration which can be used with selectConfig()
/// @param settlingTime_ms The buffer time /// @param settlingTime_ms The buffer time
/// @param ledUpdateFrequency_hz The frequency of update /// @param ledUpdateFrequency_hz The frequency of update
/// @param updateDelay The delay /// @param updateDelay The delay
/// ///
/// @return The index of the cfg which can be passed to selectConfig() /// @return The index of the configuration, which can be passed to selectConfig()
/// ///
unsigned addConfig(int settlingTime_ms, double ledUpdateFrequency_hz = 25.0, unsigned updateDelay = 0); unsigned addConfig(int settlingTime_ms, double ledUpdateFrequency_hz = 25.0, unsigned updateDelay = 0);
@ -112,12 +112,12 @@ public:
/// @param ledUpdateFrequency_hz The frequency of update /// @param ledUpdateFrequency_hz The frequency of update
/// @param updateDelay The delay /// @param updateDelay The delay
/// ///
/// @return The index of the cfg which can be passed to selectConfig() /// @return The index of the configuration, which can be passed to selectConfig()
/// ///
unsigned updateConfig(unsigned cfgID, int settlingTime_ms, double ledUpdateFrequency_hz = 25.0, unsigned updateDelay = 0); unsigned updateConfig(unsigned cfgID, int settlingTime_ms, double ledUpdateFrequency_hz = 25.0, unsigned updateDelay = 0);
/// ///
/// @brief select a smoothing cfg given by cfg index from addConfig() /// @brief select a smoothing configuration given by cfg index from addConfig()
/// @param cfg The index to use /// @param cfg The index to use
/// @param force Overwrite in any case the current values (used for cfg 0 settings update) /// @param force Overwrite in any case the current values (used for cfg 0 settings update)
/// ///
@ -128,7 +128,7 @@ public:
public slots: public slots:
/// ///
/// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor /// @brief Handle settings update from Hyperion Settingsmanager emit or this constructor
/// @param type settingyType from enum /// @param type settingType from enum
/// @param config configuration object /// @param config configuration object
/// ///
void handleSettingsUpdate(settings::type type, const QJsonDocument &config); void handleSettingsUpdate(settings::type type, const QJsonDocument &config);
@ -167,7 +167,7 @@ private:
Hyperion *_hyperion; Hyperion *_hyperion;
/// The interval at which to update the leds (msec) /// The interval at which to update the leds (msec)
int64_t _updateInterval; int _updateInterval;
/// The time after which the updated led values have been fully applied (msec) /// The time after which the updated led values have been fully applied (msec)
int64_t _settlingTime; int64_t _settlingTime;
@ -243,7 +243,7 @@ private:
/// The interval time in microseconds for interpolation of LED Frames. /// The interval time in microseconds for interpolation of LED Frames.
int64_t _interpolationIntervalMicros; int64_t _interpolationIntervalMicros;
/// Whether to apply temproral dithering to diffuse rounding errors when downsampling to 8-bit RGB colors. /// Whether to apply temporal dithering to diffuse rounding errors when downsampling to 8-bit RGB colors.
bool _dithering; bool _dithering;
/// The decay power > 0. A value of exactly 1 is linear decay, higher numbers indicate a faster decay rate. /// The decay power > 0. A value of exactly 1 is linear decay, higher numbers indicate a faster decay rate.
@ -263,8 +263,8 @@ private:
/// The time of the smoothing window. /// The time of the smoothing window.
int64_t settlingTime; int64_t settlingTime;
/// The interval time in millisecons of the timer used for scheduling LED update operations. A value of 0 indicates sub-millisecond timing. /// The interval time in milliseconds of the timer used for scheduling LED update operations. A value of 0 indicates sub-millisecond timing.
int64_t updateInterval; int updateInterval;
// The rate at which color frames should be written to LED device. // The rate at which color frames should be written to LED device.
double outputRate; double outputRate;
@ -275,13 +275,13 @@ private:
/// The number of frames the output is delayed /// The number of frames the output is delayed
unsigned outputDelay; unsigned outputDelay;
/// Whether to apply temproral dithering to diffuse rounding errors when downsampling to 8-bit RGB colors. Improves color accuracy. /// Whether to apply temporal dithering to diffuse rounding errors when downsampling to 8-bit RGB colors. Improves color accuracy.
bool dithering; bool dithering;
/// The decay power > 0. A value of exactly 1 is linear decay, higher numbers indicate a faster decay rate. /// The decay power > 0. A value of exactly 1 is linear decay, higher numbers indicate a faster decay rate.
double decay; double decay;
}; };
/// smooth config list /// smooth configuration list
QVector<SMOOTHING_CFG> _cfgList; QVector<SMOOTHING_CFG> _cfgList;
unsigned _currentConfigId; unsigned _currentConfigId;
@ -329,7 +329,7 @@ private:
/// Prepares a frame of LED colors by interpolating using the current smoothing window /// Prepares a frame of LED colors by interpolating using the current smoothing window
void interpolateFrame(); void interpolateFrame();
/// Performes a decay-based smoothing effect. The frames are interpolated based on their age and a given decay-power. /// Performs a decay-based smoothing effect. The frames are interpolated based on their age and a given decay-power.
/// ///
/// The ingress frames that were received during the current smoothing window are reduced using a weighted moving average /// The ingress frames that were received during the current smoothing window are reduced using a weighted moving average
/// by applying the weighting-function to the color components of each frame. /// by applying the weighting-function to the color components of each frame.

View File

@ -2,7 +2,7 @@
#include <utils/Logger.h> #include <utils/Logger.h>
#include <hyperion/MultiColorAdjustment.h> #include <hyperion/MultiColorAdjustment.h>
MultiColorAdjustment::MultiColorAdjustment(unsigned ledCnt) MultiColorAdjustment::MultiColorAdjustment(int ledCnt)
: _ledAdjustments(ledCnt, nullptr) : _ledAdjustments(ledCnt, nullptr)
, _log(Logger::getInstance("ADJUSTMENT")) , _log(Logger::getInstance("ADJUSTMENT"))
{ {
@ -25,7 +25,7 @@ void MultiColorAdjustment::addAdjustment(ColorAdjustment * adjustment)
_adjustment.push_back(adjustment); _adjustment.push_back(adjustment);
} }
void MultiColorAdjustment::setAdjustmentForLed(const QString& id, unsigned startLed, unsigned endLed) void MultiColorAdjustment::setAdjustmentForLed(const QString& id, int startLed, int endLed)
{ {
// abort // abort
if(startLed > endLed) if(startLed > endLed)
@ -34,19 +34,19 @@ void MultiColorAdjustment::setAdjustmentForLed(const QString& id, unsigned start
return; return;
} }
// catch wrong values // catch wrong values
if(endLed > _ledAdjustments.size()-1) if(endLed > static_cast<int>(_ledAdjustments.size()-1))
{ {
Warning(_log,"The color calibration 'LED index' field has leds specified which aren't part of your led layout"); Warning(_log,"The color calibration 'LED index' field has LEDs specified which aren't part of your led layout");
endLed = _ledAdjustments.size()-1; endLed = static_cast<int>(_ledAdjustments.size()-1);
} }
// Get the identified adjustment (don't care if is nullptr) // Get the identified adjustment (don't care if is nullptr)
ColorAdjustment * adjustment = getAdjustment(id); ColorAdjustment * adjustment = getAdjustment(id);
//Debug(_log,"ColorAdjustment Profile [%s], startLed[%u], endLed[%u]", QSTRING_CSTR(id), startLed, endLed); //Debug(_log,"ColorAdjustment Profile [%s], startLed[%d], endLed[%d]", QSTRING_CSTR(id), startLed, endLed);
for (unsigned iLed=startLed; iLed<=endLed; ++iLed) for (int iLed=startLed; iLed<=endLed; ++iLed)
{ {
//Debug(_log,"_ledAdjustments [%u] -> [%p]", iLed, adjustment); //Debug(_log,"_ledAdjustments [%d] -> [%p]", iLed, adjustment);
_ledAdjustments[iLed] = adjustment; _ledAdjustments[iLed] = adjustment;
} }
} }

View File

@ -84,7 +84,7 @@ bool PriorityMuxer::setSourceAutoSelectEnabled(bool enable, bool update)
return false; return false;
} }
bool PriorityMuxer::setPriority(uint8_t priority) bool PriorityMuxer::setPriority(int priority)
{ {
if(_activeInputs.contains(priority)) if(_activeInputs.contains(priority))
{ {
@ -141,7 +141,8 @@ hyperion::Components PriorityMuxer::getComponentOfPriority(int priority) const
void PriorityMuxer::registerInput(int priority, hyperion::Components component, const QString& origin, const QString& owner, unsigned smooth_cfg) void PriorityMuxer::registerInput(int priority, hyperion::Components component, const QString& origin, const QString& owner, unsigned smooth_cfg)
{ {
// detect new registers // detect new registers
bool newInput = false, reusedInput = false; bool newInput = false;
bool reusedInput = false;
if (!_activeInputs.contains(priority)) if (!_activeInputs.contains(priority))
newInput = true; newInput = true;
else if(_prevVisComp == component || _activeInputs[priority].componentId == component) else if(_prevVisComp == component || _activeInputs[priority].componentId == component)
@ -165,7 +166,9 @@ void PriorityMuxer::registerInput(int priority, hyperion::Components component,
} }
if (reusedInput) if (reusedInput)
{
emit timeRunner(); emit timeRunner();
}
} }
bool PriorityMuxer::setInput(int priority, const std::vector<ColorRgb>& ledColors, int64_t timeout_ms) bool PriorityMuxer::setInput(int priority, const std::vector<ColorRgb>& ledColors, int64_t timeout_ms)
@ -203,7 +206,9 @@ bool PriorityMuxer::setInput(int priority, const std::vector<ColorRgb>& ledColor
{ {
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive"); Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
if (_currentPriority < priority) if (_currentPriority < priority)
{
emit prioritiesChanged(); emit prioritiesChanged();
}
setCurrentTime(); setCurrentTime();
} }
@ -218,7 +223,7 @@ bool PriorityMuxer::setInputImage(int priority, const Image<ColorRgb>& image, in
return false; return false;
} }
// calc final timeout // calculate final timeout
if(timeout_ms > 0) if(timeout_ms > 0)
timeout_ms = QDateTime::currentMSecsSinceEpoch() + timeout_ms; timeout_ms = QDateTime::currentMSecsSinceEpoch() + timeout_ms;
@ -252,13 +257,13 @@ bool PriorityMuxer::setInputImage(int priority, const Image<ColorRgb>& image, in
return true; return true;
} }
bool PriorityMuxer::setInputInactive(quint8 priority) bool PriorityMuxer::setInputInactive(int priority)
{ {
Image<ColorRgb> image; Image<ColorRgb> image;
return setInputImage(priority, image, -100); return setInputImage(priority, image, -100);
} }
bool PriorityMuxer::clearInput(uint8_t priority) bool PriorityMuxer::clearInput(int priority)
{ {
if (priority < PriorityMuxer::LOWEST_PRIORITY && _activeInputs.remove(priority)) if (priority < PriorityMuxer::LOWEST_PRIORITY && _activeInputs.remove(priority))
{ {
@ -288,7 +293,9 @@ void PriorityMuxer::clearAll(bool forceClearAll)
{ {
const InputInfo info = getInputInfo(key); const InputInfo info = getInputInfo(key);
if ((info.componentId == hyperion::COMP_COLOR || info.componentId == hyperion::COMP_EFFECT || info.componentId == hyperion::COMP_IMAGE) && key < PriorityMuxer::LOWEST_PRIORITY-1) if ((info.componentId == hyperion::COMP_COLOR || info.componentId == hyperion::COMP_EFFECT || info.componentId == hyperion::COMP_IMAGE) && key < PriorityMuxer::LOWEST_PRIORITY-1)
{
clearInput(key); clearInput(key);
}
} }
} }
} }
@ -303,7 +310,7 @@ void PriorityMuxer::setCurrentTime()
{ {
if (infoIt->timeoutTime_ms > 0 && infoIt->timeoutTime_ms <= now) if (infoIt->timeoutTime_ms > 0 && infoIt->timeoutTime_ms <= now)
{ {
quint8 tPrio = infoIt->priority; int tPrio = infoIt->priority;
infoIt = _activeInputs.erase(infoIt); infoIt = _activeInputs.erase(infoIt);
Debug(_log,"Timeout clear for priority %d",tPrio); Debug(_log,"Timeout clear for priority %d",tPrio);
emit prioritiesChanged(); emit prioritiesChanged();
@ -321,7 +328,7 @@ void PriorityMuxer::setCurrentTime()
++infoIt; ++infoIt;
} }
} }
// eval if manual selected prio is still available // evaluate, if manual selected priority is still available
if(!_sourceAutoSelectEnabled) if(!_sourceAutoSelectEnabled)
{ {
if(_activeInputs.contains(_manualSelectedPriority)) if(_activeInputs.contains(_manualSelectedPriority))

View File

@ -11,6 +11,7 @@
"options": "options":
{ {
"enum_titles": ["edt_conf_enum_automatic","AMLogic","DispmanX","DirectX9","Framebuffer","OSX","QT","X11","XCB"] "enum_titles": ["edt_conf_enum_automatic","AMLogic","DispmanX","DirectX9","Framebuffer","OSX","QT","X11","XCB"]
}, },
"default" : "auto", "default" : "auto",
"propertyOrder" : 1 "propertyOrder" : 1

View File

@ -8,22 +8,22 @@
"top": { "top": {
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
"default": 8 "default": 1
}, },
"bottom": { "bottom": {
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
"default": 8 "default": 0
}, },
"left": { "left": {
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
"default": 5 "default": 0
}, },
"right": { "right": {
"type": "integer", "type": "integer",
"minimum": 0, "minimum": 0,
"default": 5 "default": 0
}, },
"glength": { "glength": {
"type": "integer", "type": "integer",

View File

@ -47,7 +47,7 @@
"title" : "edt_conf_smooth_interpolationRate_title", "title" : "edt_conf_smooth_interpolationRate_title",
"minimum" : 1.0, "minimum" : 1.0,
"maximum": 1000.0, "maximum": 1000.0,
"default" : 0, "default" : 1.0,
"append" : "edt_append_hz", "append" : "edt_append_hz",
"propertyOrder" : 5 "propertyOrder" : 5
}, },
@ -57,7 +57,7 @@
"title" : "edt_conf_smooth_outputRate_title", "title" : "edt_conf_smooth_outputRate_title",
"minimum" : 1.0, "minimum" : 1.0,
"maximum": 1000.0, "maximum": 1000.0,
"default" : 0, "default" : 1.0,
"append" : "edt_append_hz", "append" : "edt_append_hz",
"propertyOrder" : 6 "propertyOrder" : 6
}, },

View File

@ -149,7 +149,7 @@ bool LedDevice::init(const QJsonObject &deviceConfig)
_colorOrder = deviceConfig["colorOrder"].toString("RGB"); _colorOrder = deviceConfig["colorOrder"].toString("RGB");
setLedCount( static_cast<unsigned int>( deviceConfig["currentLedCount"].toInt(1) ) ); // property injected to reflect real led count setLedCount( deviceConfig["currentLedCount"].toInt(1) ); // property injected to reflect real led count
setLatchTime( deviceConfig["latchTime"].toInt( _latchTime_ms ) ); setLatchTime( deviceConfig["latchTime"].toInt( _latchTime_ms ) );
setRewriteTime ( deviceConfig["rewriteTime"].toInt( _refreshTimerInterval_ms) ); setRewriteTime ( deviceConfig["rewriteTime"].toInt( _refreshTimerInterval_ms) );
@ -178,11 +178,11 @@ int LedDevice::updateLeds(const std::vector<ColorRgb>& ledValues)
if ( !_isEnabled || !_isOn || !_isDeviceReady || _isDeviceInError ) if ( !_isEnabled || !_isOn || !_isDeviceReady || _isDeviceInError )
{ {
//std::cout << "LedDevice::updateLeds(), LedDevice NOT ready! "; //std::cout << "LedDevice::updateLeds(), LedDevice NOT ready! ";
return -1; retval = -1;
} }
else else
{ {
qint64 elapsedTimeMs = _lastWriteTime.msecsTo(QDateTime::currentDateTime()); qint64 elapsedTimeMs = _lastWriteTime.msecsTo( QDateTime::currentDateTime() );
if (_latchTime_ms == 0 || elapsedTimeMs >= _latchTime_ms) if (_latchTime_ms == 0 || elapsedTimeMs >= _latchTime_ms)
{ {
//std::cout << "LedDevice::updateLeds(), Elapsed time since last write (" << elapsedTimeMs << ") ms > _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl; //std::cout << "LedDevice::updateLeds(), Elapsed time since last write (" << elapsedTimeMs << ") ms > _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
@ -356,7 +356,7 @@ bool LedDevice::restoreState()
return rc; return rc;
} }
QJsonObject LedDevice::discover() QJsonObject LedDevice::discover(const QJsonObject& /*params*/)
{ {
QJsonObject devicesDiscovered; QJsonObject devicesDiscovered;
@ -392,8 +392,9 @@ QJsonObject LedDevice::getProperties(const QJsonObject& params)
return properties; return properties;
} }
void LedDevice::setLedCount(unsigned int ledCount) void LedDevice::setLedCount(int ledCount)
{ {
assert(ledCount >= 0);
_ledCount = ledCount; _ledCount = ledCount;
_ledRGBCount = _ledCount * sizeof(ColorRgb); _ledRGBCount = _ledCount * sizeof(ColorRgb);
_ledRGBWCount = _ledCount * sizeof(ColorRgbw); _ledRGBWCount = _ledCount * sizeof(ColorRgbw);
@ -401,12 +402,14 @@ void LedDevice::setLedCount(unsigned int ledCount)
void LedDevice::setLatchTime( int latchTime_ms ) void LedDevice::setLatchTime( int latchTime_ms )
{ {
assert(latchTime_ms >= 0);
_latchTime_ms = latchTime_ms; _latchTime_ms = latchTime_ms;
Debug(_log, "LatchTime updated to %dms", _latchTime_ms); Debug(_log, "LatchTime updated to %dms", _latchTime_ms);
} }
void LedDevice::setRewriteTime( int rewriteTime_ms ) void LedDevice::setRewriteTime( int rewriteTime_ms )
{ {
assert(rewriteTime_ms >= 0);
_refreshTimerInterval_ms = rewriteTime_ms; _refreshTimerInterval_ms = rewriteTime_ms;
if ( _refreshTimerInterval_ms > 0 ) if ( _refreshTimerInterval_ms > 0 )
@ -441,7 +444,7 @@ void LedDevice::printLedValues(const std::vector<ColorRgb>& ledValues)
std::cout << "]" << std::endl; std::cout << "]" << std::endl;
} }
QString LedDevice::uint8_t_to_hex_string(const uint8_t * data, const qint64 size, qint64 number) const QString LedDevice::uint8_t_to_hex_string(const uint8_t * data, const int size, int number) const
{ {
if ( number <= 0 || number > size) if ( number <= 0 || number > size)
{ {

View File

@ -36,16 +36,17 @@ LedDevice * LedDeviceFactory::construct(const QJsonObject & deviceConfig)
if (device == nullptr) if (device == nullptr)
{ {
Error(log, "Dummy device used, because configured device '%s' is unknown", QSTRING_CSTR(type) );
throw std::runtime_error("unknown device"); throw std::runtime_error("unknown device");
} }
} }
catch(std::exception& e) catch(std::exception& e)
{ {
QString dummyDeviceType = "file";
Error(log, "Dummy device type (%s) used, because configured device '%s' throws error '%s'", QSTRING_CSTR(dummyDeviceType), QSTRING_CSTR(type), e.what());
Error(log, "Dummy device used, because configured device '%s' throws error '%s'", QSTRING_CSTR(type), e.what()); QJsonObject dummyDeviceConfig;
const QJsonObject dummyDeviceConfig; dummyDeviceConfig.insert("type",dummyDeviceType);
device = LedDeviceFile::construct(QJsonObject()); device = LedDeviceFile::construct(dummyDeviceConfig);
} }
return device; return device;

View File

@ -1,7 +1,6 @@
#include "LedDeviceTemplate.h" #include "LedDeviceTemplate.h"
LedDeviceTemplate::LedDeviceTemplate(const QJsonObject &deviceConfig) LedDeviceTemplate::LedDeviceTemplate(const QJsonObject & /*deviceConfig*/)
: LedDevice()
{ {
} }
@ -19,7 +18,7 @@ bool LedDeviceTemplate::init(const QJsonObject &deviceConfig)
{ {
// Initialise LedDevice configuration and execution environment // Initialise LedDevice configuration and execution environment
// ... // ...
if ( 0 /*Error during init*/) if ( false /*Error during init*/)
{ {
//Build an errortext, illustrative //Build an errortext, illustrative
QString errortext = QString ("Error message: %1").arg("errno/text"); QString errortext = QString ("Error message: %1").arg("errno/text");
@ -56,7 +55,7 @@ int LedDeviceTemplate::open()
} }
// On error/exceptions, set LedDevice in error // On error/exceptions, set LedDevice in error
if ( retval < 0 ) if ( false /* retval < 0*/ )
{ {
this->setInError( errortext ); this->setInError( errortext );
} }

View File

@ -146,8 +146,8 @@ QString LedDeviceWrapper::getColorOrder() const
unsigned int LedDeviceWrapper::getLedCount() const unsigned int LedDeviceWrapper::getLedCount() const
{ {
unsigned int value = 0; int value = 0;
QMetaObject::invokeMethod(_ledDevice, "getLedCount", Qt::BlockingQueuedConnection, Q_RETURN_ARG(unsigned int, value)); QMetaObject::invokeMethod(_ledDevice, "getLedCount", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, value));
return value; return value;
} }

View File

@ -190,7 +190,7 @@ void ProviderHID::unblockAfterDelay()
_blockedForDelay = false; _blockedForDelay = false;
} }
QJsonObject ProviderHID::discover() QJsonObject ProviderHID::discover(const QJsonObject& /*params*/)
{ {
QJsonObject devicesDiscovered; QJsonObject devicesDiscovered;
devicesDiscovered.insert("ledDeviceType", _activeDeviceType ); devicesDiscovered.insert("ledDeviceType", _activeDeviceType );

View File

@ -31,9 +31,11 @@ public:
/// ///
/// @brief Discover HIB (USB) devices available (for configuration). /// @brief Discover HIB (USB) devices available (for configuration).
/// ///
/// @param[in] params Parameters used to overwrite discovery default behaviour
///
/// @return A JSON structure holding a list of devices found /// @return A JSON structure holding a list of devices found
/// ///
QJsonObject discover() override; QJsonObject discover(const QJsonObject& params) override;
protected: protected:

View File

@ -55,7 +55,7 @@ bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
QStringList orbIds = QStringUtils::split(deviceConfig["orbIds"].toString().simplified().remove(" "),",", QStringUtils::SplitBehavior::SkipEmptyParts); QStringList orbIds = QStringUtils::split(deviceConfig["orbIds"].toString().simplified().remove(" "),",", QStringUtils::SplitBehavior::SkipEmptyParts);
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() )); Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
Debug(_log, "LedCount : %u", this->getLedCount()); Debug(_log, "LedCount : %d", this->getLedCount());
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() )); Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
Debug(_log, "RefreshTime : %d", _refreshTimerInterval_ms); Debug(_log, "RefreshTime : %d", _refreshTimerInterval_ms);
Debug(_log, "LatchTime : %d", this->getLatchTime()); Debug(_log, "LatchTime : %d", this->getLatchTime());
@ -89,8 +89,8 @@ bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
} }
} }
uint numberOrbs = _orbIds.size(); int numberOrbs = _orbIds.size();
uint configuredLedCount = this->getLedCount(); int configuredLedCount = this->getLedCount();
if ( _orbIds.empty() ) if ( _orbIds.empty() )
{ {
@ -111,7 +111,7 @@ bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
{ {
if ( numberOrbs > configuredLedCount ) if ( numberOrbs > configuredLedCount )
{ {
Info(_log, "%s: More Orbs [%u] than configured LEDs [%u].", QSTRING_CSTR(this->getActiveDeviceType()), numberOrbs, configuredLedCount ); Info(_log, "%s: More Orbs [%d] than configured LEDs [%d].", QSTRING_CSTR(this->getActiveDeviceType()), numberOrbs, configuredLedCount );
} }
isInitOK = true; isInitOK = true;
@ -276,16 +276,21 @@ void LedDeviceAtmoOrb::sendCommand(const QByteArray &bytes)
_udpSocket->writeDatagram(bytes.data(), bytes.size(), _groupAddress, _multiCastGroupPort); _udpSocket->writeDatagram(bytes.data(), bytes.size(), _groupAddress, _multiCastGroupPort);
} }
QJsonObject LedDeviceAtmoOrb::discover() QJsonObject LedDeviceAtmoOrb::discover(const QJsonObject& params)
{ {
//Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
QJsonObject devicesDiscovered; QJsonObject devicesDiscovered;
devicesDiscovered.insert("ledDeviceType", _activeDeviceType ); devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
QJsonArray deviceList; QJsonArray deviceList;
_multicastGroup = params["multiCastGroup"].toString(MULTICAST_GROUP_DEFAULT_ADDRESS);
_multiCastGroupPort = static_cast<quint16>(params["multiCastPort"].toInt(MULTICAST_GROUP_DEFAULT_PORT));
if ( open() == 0 ) if ( open() == 0 )
{ {
Debug ( _log, "Send discovery requests to all AtmoOrbs" ); Debug ( _log, "Send discovery requests to all AtmoOrbs listening to %s:%d", QSTRING_CSTR(_multicastGroup),_multiCastGroupPort );
setColor(0, ColorRgb::BLACK, 8); setColor(0, ColorRgb::BLACK, 8);
if ( _udpSocket->waitForReadyRead(DEFAULT_DISCOVERY_TIMEOUT.count()) ) if ( _udpSocket->waitForReadyRead(DEFAULT_DISCOVERY_TIMEOUT.count()) )

View File

@ -43,9 +43,11 @@ public:
/// ///
/// @brief Discover AtmoOrb devices available (for configuration). /// @brief Discover AtmoOrb devices available (for configuration).
/// ///
/// @param[in] params Parameters used to overwrite discovery default behaviour
///
/// @return A JSON structure holding a list of devices found /// @return A JSON structure holding a list of devices found
/// ///
virtual QJsonObject discover() override; QJsonObject discover(const QJsonObject& params) override;
/// ///
/// @brief Send an update to the AtmoOrb device to identify it. /// @brief Send an update to the AtmoOrb device to identify it.

View File

@ -38,67 +38,6 @@ const char COLOLIGHT_MODEL_IDENTIFIER[] = "OD_WE_QUAN";
const int COLOLIGHT_BEADS_PER_MODULE = 19; const int COLOLIGHT_BEADS_PER_MODULE = 19;
const int COLOLIGHT_MIN_STRIP_SEGMENT_SIZE = 30; const int COLOLIGHT_MIN_STRIP_SEGMENT_SIZE = 30;
enum verbs {
GET = 0x03,
SET = 0x04,
SETEEPROM = 0x07,
SETVAR = 0x0b
};
enum commandTypes {
STATE_OFF = 0x80,
STATE_ON = 0x81,
BRIGTHNESS = 0xCF,
SETCOLOR = 0xFF
};
enum idxTypes {
BRIGTHNESS_CONTROL = 0x01,
COLOR_CONTROL = 0x02,
COLOR_DIRECT_CONTROL = 0x81,
READ_INFO_FROM_STORAGE = 0x86
};
enum bufferMode {
MONOCROME = 0x01,
LIGHTBEAD = 0x02,
};
enum ledLayout {
STRIP_LAYOUT,
MODLUE_LAYOUT
};
enum modelType {
STRIP,
PLUS
};
const uint8_t PACKET_HEADER[] =
{
'S', 'Z', // Tag "SZ"
0x30, 0x30, // Version "00"
0x00, 0x00, // AppID, 0x0000 = TL1 command mode
0x00, 0x00, 0x00, 0x00 // Size
};
const uint8_t PACKET_SECU[] =
{
0x00, 0x00, 0x00, 0x00, // Dict
0x00, 0x00, 0x00, 0x00, // Sum
0x00, 0x00, 0x00, 0x00, // Salt
0x00, 0x00, 0x00, 0x00 // SN
};
const uint8_t TL1_CMD_FIXED_PART[] =
{
0x00, 0x00, 0x00, 0x00, // DISTID
0x00, 0x00, 0x00, 0x00, // SRCID
0x00, // SECU
0x00, // VERB
0x00, // CTAG
0x00 // LENGTH
};
} //End of constants } //End of constants
LedDeviceCololight::LedDeviceCololight(const QJsonObject& deviceConfig) LedDeviceCololight::LedDeviceCololight(const QJsonObject& deviceConfig)
@ -174,7 +113,7 @@ bool LedDeviceCololight::initLedsConfiguration()
if (getLedCount() == 0) if (getLedCount() == 0)
{ {
setLedCount(static_cast<uint>(_devConfig[CONFIG_HW_LED_COUNT].toInt(0))); setLedCount(_devConfig[CONFIG_HW_LED_COUNT].toInt(0));
} }
if (_modelType == STRIP && (getLedCount() % COLOLIGHT_MIN_STRIP_SEGMENT_SIZE != 0)) if (_modelType == STRIP && (getLedCount() % COLOLIGHT_MIN_STRIP_SEGMENT_SIZE != 0))
@ -187,7 +126,7 @@ bool LedDeviceCololight::initLedsConfiguration()
{ {
Debug(_log, "LedCount : %d", getLedCount()); Debug(_log, "LedCount : %d", getLedCount());
uint configuredLedCount = static_cast<uint>(_devConfig["currentLedCount"].toInt(1)); int configuredLedCount = _devConfig["currentLedCount"].toInt(1);
if (getLedCount() < configuredLedCount) if (getLedCount() < configuredLedCount)
{ {
@ -200,7 +139,7 @@ bool LedDeviceCololight::initLedsConfiguration()
{ {
if (getLedCount() > configuredLedCount) if (getLedCount() > configuredLedCount)
{ {
Info(_log, "%s: More LEDs [%u] than configured LEDs in layout [%u].", QSTRING_CSTR(this->getActiveDeviceType()), getLedCount(), configuredLedCount); Info(_log, "%s: More LEDs [%d] than configured LEDs in layout [%d].", QSTRING_CSTR(this->getActiveDeviceType()), getLedCount(), configuredLedCount);
} }
isInitOK = true; isInitOK = true;
} }
@ -269,7 +208,7 @@ bool LedDeviceCololight::getInfo()
{ {
_modelType = MODLUE_LAYOUT; _modelType = MODLUE_LAYOUT;
_distance = ledNum / COLOLIGHT_BEADS_PER_MODULE; _distance = ledNum / COLOLIGHT_BEADS_PER_MODULE;
setLedCount(static_cast<uint>(_distance)); setLedCount(_distance);
} }
} }
else else
@ -455,7 +394,7 @@ bool LedDeviceCololight::sendRequest(const appID appID, const QByteArray& comman
packet.append(static_cast<char>(_sequenceNumber)); packet.append(static_cast<char>(_sequenceNumber));
packet.append(command); packet.append(command);
quint32 size = sizeof(PACKET_SECU) + 1 + command.size(); quint32 size = static_cast<quint32>(static_cast<int>(sizeof(PACKET_SECU)) + 1 + command.size());
qToBigEndian<quint16>(appID, packet.data() + 4); qToBigEndian<quint16>(appID, packet.data() + 4);
@ -606,7 +545,7 @@ bool LedDeviceCololight::powerOff()
return off; return off;
} }
QJsonObject LedDeviceCololight::discover() QJsonObject LedDeviceCololight::discover(const QJsonObject& /*params*/)
{ {
QJsonObject devicesDiscovered; QJsonObject devicesDiscovered;
devicesDiscovered.insert("ledDeviceType", _activeDeviceType); devicesDiscovered.insert("ledDeviceType", _activeDeviceType);

View File

@ -29,6 +29,68 @@ enum effect : uint32_t {
CHRISTMAS = 0x068b0900 CHRISTMAS = 0x068b0900
}; };
enum verbs {
GET = 0x03,
SET = 0x04,
SETEEPROM = 0x07,
SETVAR = 0x0b
};
enum commandTypes {
STATE_OFF = 0x80,
STATE_ON = 0x81,
BRIGTHNESS = 0xCF,
SETCOLOR = 0xFF
};
enum idxTypes {
BRIGTHNESS_CONTROL = 0x01,
COLOR_CONTROL = 0x02,
COLOR_DIRECT_CONTROL = 0x81,
READ_INFO_FROM_STORAGE = 0x86
};
enum bufferMode {
MONOCROME = 0x01,
LIGHTBEAD = 0x02,
};
enum ledLayout {
STRIP_LAYOUT,
MODLUE_LAYOUT
};
enum modelType {
STRIP,
PLUS
};
const uint8_t PACKET_HEADER[] =
{
'S', 'Z', // Tag "SZ"
0x30, 0x30, // Version "00"
0x00, 0x00, // AppID, 0x0000 = TL1 command mode
0x00, 0x00, 0x00, 0x00 // Size
};
const uint8_t PACKET_SECU[] =
{
0x00, 0x00, 0x00, 0x00, // Dict
0x00, 0x00, 0x00, 0x00, // Sum
0x00, 0x00, 0x00, 0x00, // Salt
0x00, 0x00, 0x00, 0x00 // SN
};
const uint8_t TL1_CMD_FIXED_PART[] =
{
0x00, 0x00, 0x00, 0x00, // DISTID
0x00, 0x00, 0x00, 0x00, // SRCID
0x00, // SECU
0x00, // VERB
0x00, // CTAG
0x00 // LENGTH
};
/// ///
/// Implementation of a Cololight LedDevice /// Implementation of a Cololight LedDevice
/// ///
@ -54,9 +116,11 @@ public:
/// ///
/// @brief Discover Cololight devices available (for configuration). /// @brief Discover Cololight devices available (for configuration).
/// ///
/// @param[in] params Parameters used to overwrite discovery default behaviour
///
/// @return A JSON structure holding a list of devices found /// @return A JSON structure holding a list of devices found
/// ///
QJsonObject discover() override; QJsonObject discover(const QJsonObject& params) override;
/// ///
/// @brief Get a Cololight device's resource properties /// @brief Get a Cololight device's resource properties

View File

@ -1,5 +1,9 @@
#include "LedDeviceFadeCandy.h" #include "LedDeviceFadeCandy.h"
#include <QtEndian>
#include <chrono>
// https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types#ssize-t // https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types#ssize-t
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <BaseTsd.h> #include <BaseTsd.h>
@ -8,22 +12,22 @@ typedef SSIZE_T ssize_t;
// Constants // Constants
namespace { namespace {
constexpr std::chrono::milliseconds CONNECT_TIMEOUT{1000};
const signed MAX_NUM_LEDS = 10000; // OPC can handle 21845 LEDs - in theory, fadecandy device should handle 10000 LEDs const int MAX_NUM_LEDS = 10000; // OPC can handle 21845 LEDs - in theory, fadecandy device should handle 10000 LEDs
const unsigned OPC_SET_PIXELS = 0; // OPC command codes const int OPC_SET_PIXELS = 0; // OPC command codes
const unsigned OPC_SYS_EX = 255; // OPC command codes const int OPC_SYS_EX = 255; // OPC command codes
const unsigned OPC_HEADER_SIZE = 4; // OPC header size const int OPC_HEADER_SIZE = 4; // OPC header size
} //End of constants } //End of constants
// TCP elements // TCP elements
const quint16 STREAM_DEFAULT_PORT = 7890; const int STREAM_DEFAULT_PORT = 7890;
LedDeviceFadeCandy::LedDeviceFadeCandy(const QJsonObject &deviceConfig) LedDeviceFadeCandy::LedDeviceFadeCandy(const QJsonObject& deviceConfig)
: LedDevice(deviceConfig) : LedDevice(deviceConfig)
, _client(nullptr) , _client(nullptr)
,_host() , _host()
,_port(STREAM_DEFAULT_PORT) , _port(STREAM_DEFAULT_PORT)
{ {
} }
@ -32,20 +36,20 @@ LedDeviceFadeCandy::~LedDeviceFadeCandy()
delete _client; delete _client;
} }
LedDevice* LedDeviceFadeCandy::construct(const QJsonObject &deviceConfig) LedDevice* LedDeviceFadeCandy::construct(const QJsonObject& deviceConfig)
{ {
return new LedDeviceFadeCandy(deviceConfig); return new LedDeviceFadeCandy(deviceConfig);
} }
bool LedDeviceFadeCandy::init(const QJsonObject &deviceConfig) bool LedDeviceFadeCandy::init(const QJsonObject& deviceConfig)
{ {
bool isInitOK = false; bool isInitOK = false;
if ( LedDevice::init(deviceConfig) ) if (LedDevice::init(deviceConfig))
{ {
if (getLedCount() > MAX_NUM_LEDS) if (getLedCount() > MAX_NUM_LEDS)
{ {
QString errortext = QString ("More LED configured than allowed (%1)").arg(MAX_NUM_LEDS); QString errortext = QString("More LED configured than allowed (%1)").arg(MAX_NUM_LEDS);
this->setInError(errortext); this->setInError(errortext);
isInitOK = false; isInitOK = false;
} }
@ -55,18 +59,18 @@ bool LedDeviceFadeCandy::init(const QJsonObject &deviceConfig)
_port = deviceConfig["port"].toInt(STREAM_DEFAULT_PORT); _port = deviceConfig["port"].toInt(STREAM_DEFAULT_PORT);
//If host not configured the init fails //If host not configured the init fails
if ( _host.isEmpty() ) if (_host.isEmpty())
{ {
this->setInError("No target hostname nor IP defined"); this->setInError("No target hostname nor IP defined");
} }
else else
{ {
_channel = deviceConfig["channel"].toInt(0); _channel = deviceConfig["channel"].toInt(0);
_gamma = deviceConfig["gamma"].toDouble(1.0); _gamma = deviceConfig["gamma"].toDouble(1.0);
_noDither = ! deviceConfig["dither"].toBool(false); _noDither = !deviceConfig["dither"].toBool(false);
_noInterp = ! deviceConfig["interpolation"].toBool(false); _noInterp = !deviceConfig["interpolation"].toBool(false);
_manualLED = deviceConfig["manualLed"].toBool(false); _manualLED = deviceConfig["manualLed"].toBool(false);
_ledOnOff = deviceConfig["ledOn"].toBool(false); _ledOnOff = deviceConfig["ledOn"].toBool(false);
_setFcConfig = deviceConfig["setFcConfig"].toBool(false); _setFcConfig = deviceConfig["setFcConfig"].toBool(false);
_whitePoint_r = 1.0; _whitePoint_r = 1.0;
@ -74,20 +78,19 @@ bool LedDeviceFadeCandy::init(const QJsonObject &deviceConfig)
_whitePoint_b = 1.0; _whitePoint_b = 1.0;
const QJsonArray whitePointConfig = deviceConfig["whitePoint"].toArray(); const QJsonArray whitePointConfig = deviceConfig["whitePoint"].toArray();
if ( !whitePointConfig.isEmpty() && whitePointConfig.size() == 3 ) if (!whitePointConfig.isEmpty() && whitePointConfig.size() == 3)
{ {
_whitePoint_r = whitePointConfig[0].toDouble() / 255.0; _whitePoint_r = whitePointConfig[0].toDouble() / 255.0;
_whitePoint_g = whitePointConfig[1].toDouble() / 255.0; _whitePoint_g = whitePointConfig[1].toDouble() / 255.0;
_whitePoint_b = whitePointConfig[2].toDouble() / 255.0; _whitePoint_b = whitePointConfig[2].toDouble() / 255.0;
} }
_opc_data.resize( _ledRGBCount + OPC_HEADER_SIZE ); _opc_data.resize(static_cast<int>(_ledRGBCount) + OPC_HEADER_SIZE);
_opc_data[0] = _channel; _opc_data[0] = static_cast<char>(_channel);
_opc_data[1] = OPC_SET_PIXELS; _opc_data[1] = OPC_SET_PIXELS;
_opc_data[2] = _ledRGBCount >> 8; qToBigEndian<quint16>(static_cast<quint16>(_ledRGBCount), _opc_data.data() + 2);
_opc_data[3] = _ledRGBCount & 0xff;
if ( initNetwork() ) if (initNetwork())
{ {
isInitOK = true; isInitOK = true;
} }
@ -101,7 +104,7 @@ bool LedDeviceFadeCandy::initNetwork()
{ {
bool isInitOK = false; bool isInitOK = false;
if ( _client == nullptr ) if (_client == nullptr)
{ {
_client = new QTcpSocket(this); _client = new QTcpSocket(this);
isInitOK = true; isInitOK = true;
@ -116,10 +119,10 @@ int LedDeviceFadeCandy::open()
_isDeviceReady = false; _isDeviceReady = false;
// Try to open the LedDevice // Try to open the LedDevice
if ( !tryConnect() ) if (!tryConnect())
{ {
errortext = QString ("Failed to open device."); errortext = QString("Failed to open device.");
this->setInError( errortext ); this->setInError(errortext);
} }
else else
{ {
@ -136,7 +139,7 @@ int LedDeviceFadeCandy::close()
_isDeviceReady = false; _isDeviceReady = false;
// LedDevice specific closing activities // LedDevice specific closing activities
if ( _client != nullptr ) if (_client != nullptr)
{ {
_client->close(); _client->close();
// Everything is OK -> device is closed // Everything is OK -> device is closed
@ -147,7 +150,7 @@ int LedDeviceFadeCandy::close()
bool LedDeviceFadeCandy::isConnected() const bool LedDeviceFadeCandy::isConnected() const
{ {
bool connected = false; bool connected = false;
if ( _client != nullptr ) if (_client != nullptr)
{ {
connected = _client->state() == QAbstractSocket::ConnectedState; connected = _client->state() == QAbstractSocket::ConnectedState;
} }
@ -156,13 +159,13 @@ bool LedDeviceFadeCandy::isConnected() const
bool LedDeviceFadeCandy::tryConnect() bool LedDeviceFadeCandy::tryConnect()
{ {
if ( _client != nullptr ) if (_client != nullptr)
{ {
if ( _client->state() == QAbstractSocket::UnconnectedState ) { if (_client->state() == QAbstractSocket::UnconnectedState) {
_client->connectToHost( _host, _port); _client->connectToHost(_host, static_cast<quint16>(_port));
if ( _client->waitForConnected(1000) ) if (_client->waitForConnected(CONNECT_TIMEOUT.count()))
{ {
Info(_log,"fadecandy/opc: connected to %s:%i on channel %i", QSTRING_CSTR(_host), _port, _channel); Info(_log, "fadecandy/opc: connected to %s:%d on channel %d", QSTRING_CSTR(_host), _port, _channel);
if (_setFcConfig) if (_setFcConfig)
{ {
sendFadeCandyConfiguration(); sendFadeCandyConfiguration();
@ -173,50 +176,48 @@ bool LedDeviceFadeCandy::tryConnect()
return isConnected(); return isConnected();
} }
int LedDeviceFadeCandy::write( const std::vector<ColorRgb> & ledValues ) int LedDeviceFadeCandy::write(const std::vector<ColorRgb>& ledValues)
{ {
uint idx = OPC_HEADER_SIZE; uint idx = OPC_HEADER_SIZE;
for (const ColorRgb& color : ledValues) for (const ColorRgb& color : ledValues)
{ {
_opc_data[idx ] = unsigned( color.red ); _opc_data[idx] = static_cast<char>(color.red);
_opc_data[idx+1] = unsigned( color.green ); _opc_data[idx + 1] = static_cast<char>(color.green);
_opc_data[idx+2] = unsigned( color.blue ); _opc_data[idx + 2] = static_cast<char>(color.blue);
idx += 3; idx += 3;
} }
int retval = transferData()<0 ? -1 : 0; int retval = transferData() < 0 ? -1 : 0;
return retval; return retval;
} }
int LedDeviceFadeCandy::transferData() qint64 LedDeviceFadeCandy::transferData()
{ {
if ( isConnected() || tryConnect() ) if (isConnected() || tryConnect())
{ {
return _client->write( _opc_data, _opc_data.size() ); return _client->write(_opc_data);
} }
return -2; return -2;
} }
int LedDeviceFadeCandy::sendSysEx(uint8_t systemId, uint8_t commandId, const QByteArray& msg) qint64 LedDeviceFadeCandy::sendSysEx(uint8_t systemId, uint8_t commandId, const QByteArray& msg)
{ {
if ( isConnected() ) if (isConnected())
{ {
QByteArray sysExData; QByteArray sysExData;
uint data_size = msg.size() + 4; int data_size = msg.size() + 4;
sysExData.resize( 4 + OPC_HEADER_SIZE ); sysExData.resize(4 + OPC_HEADER_SIZE);
sysExData[0] = 0; sysExData[0] = 0;
sysExData[1] = OPC_SYS_EX; sysExData[1] = static_cast<char>(OPC_SYS_EX);
sysExData[2] = data_size >>8;
sysExData[3] = data_size &0xff; qToBigEndian<quint16>(static_cast<quint16>(data_size), sysExData.data() + 2);
sysExData[4] = systemId >>8; qToBigEndian<quint16>(static_cast<quint16>(systemId), sysExData.data() + 4);
sysExData[5] = systemId &0xff; qToBigEndian<quint16>(static_cast<quint16>(commandId), sysExData.data() + 6);
sysExData[6] = commandId >>8;
sysExData[7] = commandId &0xff;
sysExData += msg; sysExData += msg;
return _client->write( sysExData, sysExData.size() ); return _client->write(sysExData, sysExData.size());
} }
return -1; return -1;
} }
@ -224,9 +225,9 @@ int LedDeviceFadeCandy::sendSysEx(uint8_t systemId, uint8_t commandId, const QBy
void LedDeviceFadeCandy::sendFadeCandyConfiguration() void LedDeviceFadeCandy::sendFadeCandyConfiguration()
{ {
Debug(_log, "send configuration to fadecandy"); Debug(_log, "send configuration to fadecandy");
QString data = "{\"gamma\": "+QString::number(_gamma,'g',4)+", \"whitepoint\": ["+QString::number(_whitePoint_r,'g',4)+", "+QString::number(_whitePoint_g,'g',4)+", "+QString::number(_whitePoint_b,'g',4)+"]}"; QString data = "{\"gamma\": " + QString::number(_gamma, 'g', 4) + ", \"whitepoint\": [" + QString::number(_whitePoint_r, 'g', 4) + ", " + QString::number(_whitePoint_g, 'g', 4) + ", " + QString::number(_whitePoint_b, 'g', 4) + "]}";
sendSysEx(1, 1, data.toLocal8Bit() ); sendSysEx(1, 1, data.toLocal8Bit());
char firmware_data = ((uint8_t)_noDither | ((uint8_t)_noInterp << 1) | ((uint8_t)_manualLED << 2) | ((uint8_t)_ledOnOff << 3) ); char firmware_data = static_cast<char>(static_cast<uint8_t>(_noDither) | (static_cast<uint8_t>(_noInterp) << 1) | (static_cast<uint8_t>(_manualLED) << 2) | (static_cast<uint8_t>(_ledOnOff) << 3));
sendSysEx(1, 2, QByteArray(1,firmware_data) ); sendSysEx(1, 2, QByteArray(1, firmware_data));
} }

View File

@ -40,7 +40,7 @@ public:
/// ///
/// @param deviceConfig Device's configuration as JSON-Object /// @param deviceConfig Device's configuration as JSON-Object
/// ///
explicit LedDeviceFadeCandy(const QJsonObject &deviceConfig); explicit LedDeviceFadeCandy(const QJsonObject& deviceConfig);
/// ///
/// @brief Destructor of the LedDevice /// @brief Destructor of the LedDevice
@ -52,7 +52,7 @@ public:
/// ///
/// @param[in] deviceConfig Device's configuration as JSON-Object /// @param[in] deviceConfig Device's configuration as JSON-Object
/// @return LedDevice constructed /// @return LedDevice constructed
static LedDevice* construct(const QJsonObject &deviceConfig); static LedDevice* construct(const QJsonObject& deviceConfig);
protected: protected:
@ -62,7 +62,7 @@ protected:
/// @param[in] deviceConfig the JSON device configuration /// @param[in] deviceConfig the JSON device configuration
/// @return True, if success /// @return True, if success
/// ///
bool init(const QJsonObject &deviceConfig) override; bool init(const QJsonObject& deviceConfig) override;
/// ///
/// @brief Opens the output device. /// @brief Opens the output device.
@ -84,7 +84,7 @@ protected:
/// @param[in] ledValues The RGB-color per LED /// @param[in] ledValues The RGB-color per LED
/// @return Zero on success, else negative /// @return Zero on success, else negative
/// ///
int write(const std::vector<ColorRgb> & ledValues) override; int write(const std::vector<ColorRgb>& ledValues) override;
private: private:
@ -113,7 +113,7 @@ private:
/// ///
/// @return amount of transferred bytes. -1 error while transferring, -2 error while connecting /// @return amount of transferred bytes. -1 error while transferring, -2 error while connecting
/// ///
int transferData(); qint64 transferData();
/// ///
/// @brief Send system exclusive commands /// @brief Send system exclusive commands
@ -122,7 +122,7 @@ private:
/// @param[in] commandId id of command /// @param[in] commandId id of command
/// @param[in] msg the sysEx message /// @param[in] msg the sysEx message
/// @return amount bytes written, -1 if failed /// @return amount bytes written, -1 if failed
int sendSysEx(uint8_t systemId, uint8_t commandId, const QByteArray& msg); qint64 sendSysEx(uint8_t systemId, uint8_t commandId, const QByteArray& msg);
/// ///
/// @brief Sends the configuration to fadecandy cserver /// @brief Sends the configuration to fadecandy cserver
@ -131,8 +131,8 @@ private:
QTcpSocket* _client; QTcpSocket* _client;
QString _host; QString _host;
uint16_t _port; int _port;
unsigned _channel; int _channel;
QByteArray _opc_data; QByteArray _opc_data;
// fadecandy sysEx // fadecandy sysEx
@ -145,7 +145,6 @@ private:
bool _noInterp; bool _noInterp;
bool _manualLED; bool _manualLED;
bool _ledOnOff; bool _ledOnOff;
}; };
#endif // LEDEVICEFADECANDY_H #endif // LEDEVICEFADECANDY_H

View File

@ -7,6 +7,7 @@
// Qt includes // Qt includes
#include <QEventLoop> #include <QEventLoop>
#include <QNetworkReply> #include <QNetworkReply>
#include <QtEndian>
//std includes //std includes
#include <sstream> #include <sstream>
@ -14,18 +15,17 @@
// Constants // Constants
namespace { namespace {
const bool verbose = false;
const bool verbose = false;
const bool verbose3 = false; const bool verbose3 = false;
// Configuration settings // Configuration settings
const char CONFIG_ADDRESS[] = "host"; const char CONFIG_ADDRESS[] = "host";
//const char CONFIG_PORT[] = "port"; //const char CONFIG_PORT[] = "port";
const char CONFIG_AUTH_TOKEN[] ="token"; const char CONFIG_AUTH_TOKEN[] = "token";
const char CONFIG_PANEL_ORDER_TOP_DOWN[] ="panelOrderTopDown"; const char CONFIG_PANEL_ORDER_TOP_DOWN[] = "panelOrderTopDown";
const char CONFIG_PANEL_ORDER_LEFT_RIGHT[] ="panelOrderLeftRight"; const char CONFIG_PANEL_ORDER_LEFT_RIGHT[] = "panelOrderLeftRight";
const char CONFIG_PANEL_START_POS[] ="panelStartPos"; const char CONFIG_PANEL_START_POS[] = "panelStartPos";
// Panel configuration settings // Panel configuration settings
const char PANEL_LAYOUT[] = "layout"; const char PANEL_LAYOUT[] = "layout";
@ -61,16 +61,19 @@ const char API_BASE_PATH[] = "/api/v1/%1/";
const char API_ROOT[] = ""; const char API_ROOT[] = "";
//const char API_EXT_MODE_STRING_V1[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\"}}"; //const char API_EXT_MODE_STRING_V1[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\"}}";
const char API_EXT_MODE_STRING_V2[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\", \"extControlVersion\" : \"v2\"}}"; const char API_EXT_MODE_STRING_V2[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\", \"extControlVersion\" : \"v2\"}}";
const char API_STATE[] ="state"; const char API_STATE[] = "state";
const char API_PANELLAYOUT[] = "panelLayout"; const char API_PANELLAYOUT[] = "panelLayout";
const char API_EFFECT[] = "effects"; const char API_EFFECT[] = "effects";
//Nanoleaf Control data stream
const int STREAM_FRAME_PANEL_NUM_SIZE = 2;
const int STREAM_FRAME_PANEL_INFO_SIZE = 8;
// Nanoleaf ssdp services // Nanoleaf ssdp services
const char SSDP_ID[] = "ssdp:all"; const char SSDP_ID[] = "ssdp:all";
const char SSDP_FILTER_HEADER[] = "ST"; const char SSDP_FILTER_HEADER[] = "ST";
const char SSDP_CANVAS[] = "nanoleaf:nl29"; const char SSDP_CANVAS[] = "nanoleaf:nl29";
const char SSDP_LIGHTPANELS[] = "nanoleaf_aurora:light"; const char SSDP_LIGHTPANELS[] = "nanoleaf_aurora:light";
} //End of constants } //End of constants
// Nanoleaf Panel Shapetypes // Nanoleaf Panel Shapetypes
@ -81,7 +84,7 @@ enum SHAPETYPES {
CONTROL_SQUARE_PRIMARY, CONTROL_SQUARE_PRIMARY,
CONTROL_SQUARE_PASSIVE, CONTROL_SQUARE_PASSIVE,
POWER_SUPPLY, POWER_SUPPLY,
}; };
// Nanoleaf external control versions // Nanoleaf external control versions
enum EXTCONTROLVERSIONS { enum EXTCONTROLVERSIONS {
@ -89,20 +92,20 @@ enum EXTCONTROLVERSIONS {
EXTCTRLVER_V2 EXTCTRLVER_V2
}; };
LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject &deviceConfig) LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject& deviceConfig)
: ProviderUdp(deviceConfig) : ProviderUdp(deviceConfig)
,_restApi(nullptr) , _restApi(nullptr)
,_apiPort(API_DEFAULT_PORT) , _apiPort(API_DEFAULT_PORT)
,_topDown(true) , _topDown(true)
,_leftRight(true) , _leftRight(true)
,_startPos(0) , _startPos(0)
,_endPos(0) , _endPos(0)
,_extControlVersion (EXTCTRLVER_V2), , _extControlVersion(EXTCTRLVER_V2),
_panelLedCount(0) _panelLedCount(0)
{ {
} }
LedDevice* LedDeviceNanoleaf::construct(const QJsonObject &deviceConfig) LedDevice* LedDeviceNanoleaf::construct(const QJsonObject& deviceConfig)
{ {
return new LedDeviceNanoleaf(deviceConfig); return new LedDeviceNanoleaf(deviceConfig);
} }
@ -113,7 +116,7 @@ LedDeviceNanoleaf::~LedDeviceNanoleaf()
_restApi = nullptr; _restApi = nullptr;
} }
bool LedDeviceNanoleaf::init(const QJsonObject &deviceConfig) bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
{ {
// Overwrite non supported/required features // Overwrite non supported/required features
setLatchTime(0); setLatchTime(0);
@ -121,69 +124,69 @@ bool LedDeviceNanoleaf::init(const QJsonObject &deviceConfig)
if (deviceConfig["rewriteTime"].toInt(0) > 0) if (deviceConfig["rewriteTime"].toInt(0) > 0)
{ {
Info (_log, "Device Nanoleaf does not require rewrites. Refresh time is ignored."); Info(_log, "Device Nanoleaf does not require rewrites. Refresh time is ignored.");
} }
DebugIf(verbose, _log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() ); DebugIf(verbose, _log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData());
bool isInitOK = false; bool isInitOK = false;
if ( LedDevice::init(deviceConfig) ) if (LedDevice::init(deviceConfig))
{ {
uint configuredLedCount = this->getLedCount(); int configuredLedCount = this->getLedCount();
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() )); Debug(_log, "DeviceType : %s", QSTRING_CSTR(this->getActiveDeviceType()));
Debug(_log, "LedCount : %u", configuredLedCount); Debug(_log, "LedCount : %d", configuredLedCount);
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() )); Debug(_log, "ColorOrder : %s", QSTRING_CSTR(this->getColorOrder()));
Debug(_log, "RewriteTime : %d", this->getRewriteTime()); Debug(_log, "RewriteTime : %d", this->getRewriteTime());
Debug(_log, "LatchTime : %d", this->getLatchTime()); Debug(_log, "LatchTime : %d", this->getLatchTime());
// Read panel organisation configuration // Read panel organisation configuration
if ( deviceConfig[ CONFIG_PANEL_ORDER_TOP_DOWN ].isString() ) if (deviceConfig[CONFIG_PANEL_ORDER_TOP_DOWN].isString())
{ {
_topDown = deviceConfig[ CONFIG_PANEL_ORDER_TOP_DOWN ].toString().toInt() == 0; _topDown = deviceConfig[CONFIG_PANEL_ORDER_TOP_DOWN].toString().toInt() == 0;
} }
else else
{ {
_topDown = deviceConfig[ CONFIG_PANEL_ORDER_TOP_DOWN ].toInt() == 0; _topDown = deviceConfig[CONFIG_PANEL_ORDER_TOP_DOWN].toInt() == 0;
} }
if ( deviceConfig[ CONFIG_PANEL_ORDER_LEFT_RIGHT ].isString() ) if (deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].isString())
{ {
_leftRight = deviceConfig[ CONFIG_PANEL_ORDER_LEFT_RIGHT ].toString().toInt() == 0; _leftRight = deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].toString().toInt() == 0;
} }
else else
{ {
_leftRight = deviceConfig[ CONFIG_PANEL_ORDER_LEFT_RIGHT ].toInt() == 0; _leftRight = deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].toInt() == 0;
} }
_startPos = static_cast<uint>( deviceConfig[ CONFIG_PANEL_START_POS ].toInt(0) ); _startPos = deviceConfig[CONFIG_PANEL_START_POS].toInt(0);
// TODO: Allow to handle port dynamically // TODO: Allow to handle port dynamically
//Set hostname as per configuration and_defaultHost default port //Set hostname as per configuration and_defaultHost default port
_hostname = deviceConfig[ CONFIG_ADDRESS ].toString(); _hostname = deviceConfig[CONFIG_ADDRESS].toString();
_apiPort = API_DEFAULT_PORT; _apiPort = API_DEFAULT_PORT;
_authToken = deviceConfig[ CONFIG_AUTH_TOKEN ].toString(); _authToken = deviceConfig[CONFIG_AUTH_TOKEN].toString();
//If host not configured the init failed //If host not configured the init failed
if ( _hostname.isEmpty() ) if (_hostname.isEmpty())
{ {
this->setInError("No target hostname nor IP defined"); this->setInError("No target hostname nor IP defined");
isInitOK = false; isInitOK = false;
} }
else else
{ {
if ( initRestAPI( _hostname, _apiPort, _authToken ) ) if (initRestAPI(_hostname, _apiPort, _authToken))
{ {
// Read LedDevice configuration and validate against device configuration // Read LedDevice configuration and validate against device configuration
if ( initLedsConfiguration() ) if (initLedsConfiguration())
{ {
// Set UDP streaming host and port // Set UDP streaming host and port
_devConfig["host"] = _hostname; _devConfig["host"] = _hostname;
_devConfig["port"] = STREAM_CONTROL_DEFAULT_PORT; _devConfig["port"] = STREAM_CONTROL_DEFAULT_PORT;
isInitOK = ProviderUdp::init(_devConfig); isInitOK = ProviderUdp::init(_devConfig);
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR( _hostname )); Debug(_log, "Hostname/IP : %s", QSTRING_CSTR(_hostname));
Debug(_log, "Port : %d", _port); Debug(_log, "Port : %d", _port);
} }
} }
@ -201,9 +204,9 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
// Read Panel count and panel Ids // Read Panel count and panel Ids
_restApi->setPath(API_ROOT); _restApi->setPath(API_ROOT);
httpResponse response = _restApi->get(); httpResponse response = _restApi->get();
if ( response.error() ) if (response.error())
{ {
this->setInError ( response.getErrorReason() ); this->setInError(response.getErrorReason());
isInitOK = false; isInitOK = false;
} }
else else
@ -215,35 +218,35 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
QString deviceManufacturer = jsonAllPanelInfo[DEV_DATA_MANUFACTURER].toString(); QString deviceManufacturer = jsonAllPanelInfo[DEV_DATA_MANUFACTURER].toString();
_deviceFirmwareVersion = jsonAllPanelInfo[DEV_DATA_FIRMWAREVERSION].toString(); _deviceFirmwareVersion = jsonAllPanelInfo[DEV_DATA_FIRMWAREVERSION].toString();
Debug(_log, "Name : %s", QSTRING_CSTR( deviceName )); Debug(_log, "Name : %s", QSTRING_CSTR(deviceName));
Debug(_log, "Model : %s", QSTRING_CSTR( _deviceModel )); Debug(_log, "Model : %s", QSTRING_CSTR(_deviceModel));
Debug(_log, "Manufacturer : %s", QSTRING_CSTR( deviceManufacturer )); Debug(_log, "Manufacturer : %s", QSTRING_CSTR(deviceManufacturer));
Debug(_log, "FirmwareVersion: %s", QSTRING_CSTR( _deviceFirmwareVersion)); Debug(_log, "FirmwareVersion: %s", QSTRING_CSTR(_deviceFirmwareVersion));
// Get panel details from /panelLayout/layout // Get panel details from /panelLayout/layout
QJsonObject jsonPanelLayout = jsonAllPanelInfo[API_PANELLAYOUT].toObject(); QJsonObject jsonPanelLayout = jsonAllPanelInfo[API_PANELLAYOUT].toObject();
QJsonObject jsonLayout = jsonPanelLayout[PANEL_LAYOUT].toObject(); QJsonObject jsonLayout = jsonPanelLayout[PANEL_LAYOUT].toObject();
uint panelNum = static_cast<uint>(jsonLayout[PANEL_NUM].toInt()); int panelNum = jsonLayout[PANEL_NUM].toInt();
QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray(); QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray();
std::map<uint, std::map<uint, uint>> panelMap; std::map<int, std::map<int, int>> panelMap;
// Loop over all children. // Loop over all children.
for (const QJsonValue value : positionData) foreach(const QJsonValue & value, positionData)
{ {
QJsonObject panelObj = value.toObject(); QJsonObject panelObj = value.toObject();
uint panelId = static_cast<uint>(panelObj[PANEL_ID].toInt()); int panelId = panelObj[PANEL_ID].toInt();
uint panelX = static_cast<uint>(panelObj[PANEL_POS_X].toInt()); int panelX = panelObj[PANEL_POS_X].toInt();
uint panelY = static_cast<uint>(panelObj[PANEL_POS_Y].toInt()); int panelY = panelObj[PANEL_POS_Y].toInt();
uint panelshapeType = static_cast<uint>(panelObj[PANEL_SHAPE_TYPE].toInt()); int panelshapeType = panelObj[PANEL_SHAPE_TYPE].toInt();
//uint panelOrientation = static_cast<uint>(panelObj[PANEL_ORIENTATION].toInt()); //int panelOrientation = panelObj[PANEL_ORIENTATION].toInt();
DebugIf(verbose, _log, "Panel [%u] (%u,%u) - Type: [%u]", panelId, panelX, panelY, panelshapeType ); DebugIf(verbose, _log, "Panel [%d] (%d,%d) - Type: [%d]", panelId, panelX, panelY, panelshapeType);
// Skip Rhythm panels // Skip Rhythm panels
if ( panelshapeType != RHYTM ) if (panelshapeType != RHYTM)
{ {
panelMap[panelY][panelX] = panelId; panelMap[panelY][panelX] = panelId;
} }
@ -254,16 +257,16 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
} }
// Travers panels top down // Travers panels top down
for(auto posY = panelMap.crbegin(); posY != panelMap.crend(); ++posY) for (auto posY = panelMap.crbegin(); posY != panelMap.crend(); ++posY)
{ {
// Sort panels left to right // Sort panels left to right
if ( _leftRight ) if (_leftRight)
{ {
for( auto posX = posY->second.cbegin(); posX != posY->second.cend(); ++posX) for (auto posX = posY->second.cbegin(); posX != posY->second.cend(); ++posX)
{ {
DebugIf(verbose3, _log, "panelMap[%u][%u]=%u", posY->first, posX->first, posX->second ); DebugIf(verbose3, _log, "panelMap[%d][%d]=%d", posY->first, posX->first, posX->second);
if ( _topDown ) if (_topDown)
{ {
_panelIds.push_back(posX->second); _panelIds.push_back(posX->second);
} }
@ -276,11 +279,11 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
else else
{ {
// Sort panels right to left // Sort panels right to left
for( auto posX = posY->second.crbegin(); posX != posY->second.crend(); ++posX) for (auto posX = posY->second.crbegin(); posX != posY->second.crend(); ++posX)
{ {
DebugIf(verbose3, _log, "panelMap[%u][%u]=%u", posY->first, posX->first, posX->second ); DebugIf(verbose3, _log, "panelMap[%d][%d]=%d", posY->first, posX->first, posX->second);
if ( _topDown ) if (_topDown)
{ {
_panelIds.push_back(posX->second); _panelIds.push_back(posX->second);
} }
@ -292,22 +295,22 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
} }
} }
this->_panelLedCount = static_cast<uint>(_panelIds.size()); this->_panelLedCount = _panelIds.size();
_devConfig["hardwareLedCount"] = static_cast<int>(_panelLedCount); _devConfig["hardwareLedCount"] = _panelLedCount;
Debug(_log, "PanelsNum : %u", panelNum); Debug(_log, "PanelsNum : %d", panelNum);
Debug(_log, "PanelLedCount : %u", _panelLedCount); Debug(_log, "PanelLedCount : %d", _panelLedCount);
// Check. if enough panels were found. // Check. if enough panels were found.
uint configuredLedCount = this->getLedCount(); int configuredLedCount = this->getLedCount();
_endPos = _startPos + configuredLedCount - 1; _endPos = _startPos + configuredLedCount - 1;
Debug(_log, "Sort Top>Down : %d", _topDown); Debug(_log, "Sort Top>Down : %d", _topDown);
Debug(_log, "Sort Left>Right: %d", _leftRight); Debug(_log, "Sort Left>Right: %d", _leftRight);
Debug(_log, "Start Panel Pos: %u", _startPos); Debug(_log, "Start Panel Pos: %d", _startPos);
Debug(_log, "End Panel Pos : %u", _endPos); Debug(_log, "End Panel Pos : %d", _endPos);
if (_panelLedCount < configuredLedCount ) if (_panelLedCount < configuredLedCount)
{ {
QString errorReason = QString("Not enough panels [%1] for configured LEDs [%2] found!") QString errorReason = QString("Not enough panels [%1] for configured LEDs [%2] found!")
.arg(_panelLedCount) .arg(_panelLedCount)
@ -317,16 +320,16 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
} }
else else
{ {
if ( _panelLedCount > this->getLedCount() ) if (_panelLedCount > this->getLedCount())
{ {
Info(_log, "%s: More panels [%u] than configured LEDs [%u].", QSTRING_CSTR(this->getActiveDeviceType()), _panelLedCount, configuredLedCount ); Info(_log, "%s: More panels [%d] than configured LEDs [%d].", QSTRING_CSTR(this->getActiveDeviceType()), _panelLedCount, configuredLedCount);
} }
// Check, if start position + number of configured LEDs is greater than number of panels available // Check, if start position + number of configured LEDs is greater than number of panels available
if ( _endPos >= _panelLedCount ) if (_endPos >= _panelLedCount)
{ {
QString errorReason = QString("Start panel [%1] out of range. Start panel position can be max [%2] given [%3] panel available!") QString errorReason = QString("Start panel [%1] out of range. Start panel position can be max [%2] given [%3] panel available!")
.arg(_startPos).arg(_panelLedCount-configuredLedCount).arg(_panelLedCount); .arg(_startPos).arg(_panelLedCount - configuredLedCount).arg(_panelLedCount);
this->setInError(errorReason); this->setInError(errorReason);
isInitOK = false; isInitOK = false;
@ -336,16 +339,16 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
return isInitOK; return isInitOK;
} }
bool LedDeviceNanoleaf::initRestAPI(const QString &hostname, int port, const QString &token ) bool LedDeviceNanoleaf::initRestAPI(const QString& hostname, int port, const QString& token)
{ {
bool isInitOK = false; bool isInitOK = false;
if ( _restApi == nullptr ) if (_restApi == nullptr)
{ {
_restApi = new ProviderRestApi(hostname, port ); _restApi = new ProviderRestApi(hostname, port);
//Base-path is api-path + authentication token //Base-path is api-path + authentication token
_restApi->setBasePath( QString(API_BASE_PATH).arg(token) ); _restApi->setBasePath(QString(API_BASE_PATH).arg(token));
isInitOK = true; isInitOK = true;
} }
@ -360,13 +363,13 @@ int LedDeviceNanoleaf::open()
QJsonDocument responseDoc = changeToExternalControlMode(); QJsonDocument responseDoc = changeToExternalControlMode();
// Resolve port for Light Panels // Resolve port for Light Panels
QJsonObject jsonStreamControllInfo = responseDoc.object(); QJsonObject jsonStreamControllInfo = responseDoc.object();
if ( ! jsonStreamControllInfo.isEmpty() ) if (!jsonStreamControllInfo.isEmpty())
{ {
//Set default streaming port //Set default streaming port
_port = static_cast<uchar>(jsonStreamControllInfo[STREAM_CONTROL_PORT].toInt()); _port = static_cast<uchar>(jsonStreamControllInfo[STREAM_CONTROL_PORT].toInt());
} }
if ( ProviderUdp::open() == 0 ) if (ProviderUdp::open() == 0)
{ {
// Everything is OK, device is ready // Everything is OK, device is ready
_isDeviceReady = true; _isDeviceReady = true;
@ -375,10 +378,10 @@ int LedDeviceNanoleaf::open()
return retval; return retval;
} }
QJsonObject LedDeviceNanoleaf::discover() QJsonObject LedDeviceNanoleaf::discover(const QJsonObject& /*params*/)
{ {
QJsonObject devicesDiscovered; QJsonObject devicesDiscovered;
devicesDiscovered.insert("ledDeviceType", _activeDeviceType ); devicesDiscovered.insert("ledDeviceType", _activeDeviceType);
QJsonArray deviceList; QJsonArray deviceList;
@ -391,41 +394,41 @@ QJsonObject LedDeviceNanoleaf::discover()
discover.setSearchFilter(searchTargetFilter, SSDP_FILTER_HEADER); discover.setSearchFilter(searchTargetFilter, SSDP_FILTER_HEADER);
QString searchTarget = SSDP_ID; QString searchTarget = SSDP_ID;
if ( discover.discoverServices(searchTarget) > 0 ) if (discover.discoverServices(searchTarget) > 0)
{ {
deviceList = discover.getServicesDiscoveredJson(); deviceList = discover.getServicesDiscoveredJson();
} }
devicesDiscovered.insert("devices", deviceList); devicesDiscovered.insert("devices", deviceList);
Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() ); Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
return devicesDiscovered; return devicesDiscovered;
} }
QJsonObject LedDeviceNanoleaf::getProperties(const QJsonObject& params) QJsonObject LedDeviceNanoleaf::getProperties(const QJsonObject& params)
{ {
Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() ); Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
QJsonObject properties; QJsonObject properties;
// Get Nanoleaf device properties // Get Nanoleaf device properties
QString host = params["host"].toString(""); QString host = params["host"].toString("");
if ( !host.isEmpty() ) if (!host.isEmpty())
{ {
QString authToken = params["token"].toString(""); QString authToken = params["token"].toString("");
QString filter = params["filter"].toString(""); QString filter = params["filter"].toString("");
// Resolve hostname and port (or use default API port) // Resolve hostname and port (or use default API port)
QStringList addressparts = QStringUtils::split(host,":", QStringUtils::SplitBehavior::SkipEmptyParts); QStringList addressparts = QStringUtils::split(host, ":", QStringUtils::SplitBehavior::SkipEmptyParts);
QString apiHost = addressparts[0]; QString apiHost = addressparts[0];
int apiPort; int apiPort;
if ( addressparts.size() > 1) if (addressparts.size() > 1)
{ {
apiPort = addressparts[1].toInt(); apiPort = addressparts[1].toInt();
} }
else else
{ {
apiPort = API_DEFAULT_PORT; apiPort = API_DEFAULT_PORT;
} }
initRestAPI(apiHost, apiPort, authToken); initRestAPI(apiHost, apiPort, authToken);
@ -433,40 +436,39 @@ QJsonObject LedDeviceNanoleaf::getProperties(const QJsonObject& params)
// Perform request // Perform request
httpResponse response = _restApi->get(); httpResponse response = _restApi->get();
if ( response.error() ) if (response.error())
{ {
Warning (_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason())); Warning(_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
} }
properties.insert("properties", response.getBody().object()); properties.insert("properties", response.getBody().object());
Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() ); Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData());
} }
return properties; return properties;
} }
void LedDeviceNanoleaf::identify(const QJsonObject& params) void LedDeviceNanoleaf::identify(const QJsonObject& params)
{ {
Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() ); Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
QString host = params["host"].toString(""); QString host = params["host"].toString("");
if ( !host.isEmpty() ) if (!host.isEmpty())
{ {
QString authToken = params["token"].toString(""); QString authToken = params["token"].toString("");
// Resolve hostname and port (or use default API port) // Resolve hostname and port (or use default API port)
QStringList addressparts = QStringUtils::split(host,":", QStringUtils::SplitBehavior::SkipEmptyParts); QStringList addressparts = QStringUtils::split(host, ":", QStringUtils::SplitBehavior::SkipEmptyParts);
QString apiHost = addressparts[0]; QString apiHost = addressparts[0];
int apiPort; int apiPort;
if ( addressparts.size() > 1) if (addressparts.size() > 1)
{ {
apiPort = addressparts[1].toInt(); apiPort = addressparts[1].toInt();
} }
else else
{ {
apiPort = API_DEFAULT_PORT; apiPort = API_DEFAULT_PORT;
} }
initRestAPI(apiHost, apiPort, authToken); initRestAPI(apiHost, apiPort, authToken);
@ -474,33 +476,33 @@ void LedDeviceNanoleaf::identify(const QJsonObject& params)
// Perform request // Perform request
httpResponse response = _restApi->put(); httpResponse response = _restApi->put();
if ( response.error() ) if (response.error())
{ {
Warning (_log, "%s identification failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason())); Warning(_log, "%s identification failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
} }
} }
} }
bool LedDeviceNanoleaf::powerOn() bool LedDeviceNanoleaf::powerOn()
{ {
if ( _isDeviceReady) if (_isDeviceReady)
{ {
changeToExternalControlMode(); changeToExternalControlMode();
//Power-on Nanoleaf device //Power-on Nanoleaf device
_restApi->setPath(API_STATE); _restApi->setPath(API_STATE);
_restApi->put( getOnOffRequest(true) ); _restApi->put(getOnOffRequest(true));
} }
return true; return true;
} }
bool LedDeviceNanoleaf::powerOff() bool LedDeviceNanoleaf::powerOff()
{ {
if ( _isDeviceReady) if (_isDeviceReady)
{ {
//Power-off the Nanoleaf device physically //Power-off the Nanoleaf device physically
_restApi->setPath(API_STATE); _restApi->setPath(API_STATE);
_restApi->put( getOnOffRequest(false) ); _restApi->put(getOnOffRequest(false));
} }
return true; return true;
} }
@ -508,7 +510,7 @@ bool LedDeviceNanoleaf::powerOff()
QString LedDeviceNanoleaf::getOnOffRequest(bool isOn) const QString LedDeviceNanoleaf::getOnOffRequest(bool isOn) const
{ {
QString state = isOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE; QString state = isOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
return QString( "{\"%1\":{\"%2\":%3}}" ).arg(STATE_ON, STATE_ONOFF_VALUE, state); return QString("{\"%1\":{\"%2\":%3}}").arg(STATE_ON, STATE_ONOFF_VALUE, state);
} }
QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode() QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode()
@ -518,15 +520,14 @@ QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode()
//Enable UDP Mode v2 //Enable UDP Mode v2
_restApi->setPath(API_EFFECT); _restApi->setPath(API_EFFECT);
httpResponse response =_restApi->put(API_EXT_MODE_STRING_V2); httpResponse response = _restApi->put(API_EXT_MODE_STRING_V2);
return response.getBody(); return response.getBody();
} }
int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues) int LedDeviceNanoleaf::write(const std::vector<ColorRgb>& ledValues)
{ {
int retVal = 0; int retVal = 0;
uint udpBufferSize;
// //
// nPanels 2B // nPanels 2B
@ -537,35 +538,27 @@ int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
// //
// Note: Nanoleaf Light Panels (Aurora) now support External Control V2 (tested with FW 3.2.0) // Note: Nanoleaf Light Panels (Aurora) now support External Control V2 (tested with FW 3.2.0)
udpBufferSize = _panelLedCount * 8 + 2; int udpBufferSize = STREAM_FRAME_PANEL_NUM_SIZE + _panelLedCount * STREAM_FRAME_PANEL_INFO_SIZE;
std::vector<uint8_t> udpbuffer;
QByteArray udpbuffer;
udpbuffer.resize(udpBufferSize); udpbuffer.resize(udpBufferSize);
uchar lowByte; // lower byte int i = 0;
uchar highByte; // upper byte
uint i=0;
// Set number of panels // Set number of panels
highByte = static_cast<uchar>(_panelLedCount >>8 ); qToBigEndian<quint16>(static_cast<quint16>(_panelLedCount), udpbuffer.data() + i);
lowByte = static_cast<uchar>(_panelLedCount & 0xFF); i += 2;
udpbuffer[i++] = highByte;
udpbuffer[i++] = lowByte;
ColorRgb color; ColorRgb color;
//Maintain LED counter independent from PanelCounter //Maintain LED counter independent from PanelCounter
uint ledCounter = 0; int ledCounter = 0;
for ( uint panelCounter=0; panelCounter < _panelLedCount; panelCounter++ ) for (int panelCounter = 0; panelCounter < _panelLedCount; panelCounter++)
{ {
uint panelID = _panelIds[panelCounter]; int panelID = _panelIds[panelCounter];
highByte = static_cast<uchar>(panelID >>8 );
lowByte = static_cast<uchar>(panelID & 0xFF);
// Set panels configured // Set panels configured
if( panelCounter >= _startPos && panelCounter <= _endPos ) { if (panelCounter >= _startPos && panelCounter <= _endPos) {
color = static_cast<ColorRgb>(ledValues.at(ledCounter)); color = static_cast<ColorRgb>(ledValues.at(ledCounter));
++ledCounter; ++ledCounter;
} }
@ -573,49 +566,35 @@ int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
{ {
// Set panels not configured to black; // Set panels not configured to black;
color = ColorRgb::BLACK; color = ColorRgb::BLACK;
DebugIf(verbose3, _log, "[%u] >= panelLedCount [%u] => Set to BLACK", panelCounter, _panelLedCount ); DebugIf(verbose3, _log, "[%d] >= panelLedCount [%d] => Set to BLACK", panelCounter, _panelLedCount);
} }
// Set panelID // Set panelID
udpbuffer[i++] = highByte; qToBigEndian<quint16>(static_cast<quint16>(panelID), udpbuffer.data() + i);
udpbuffer[i++] = lowByte; i += 2;
// Set panel's color LEDs // Set panel's color LEDs
udpbuffer[i++] = color.red; udpbuffer[i++] = static_cast<char>(color.red);
udpbuffer[i++] = color.green; udpbuffer[i++] = static_cast<char>(color.green);
udpbuffer[i++] = color.blue; udpbuffer[i++] = static_cast<char>(color.blue);
// Set white LED // Set white LED
udpbuffer[i++] = 0; // W not set manually udpbuffer[i++] = 0; // W not set manually
// Set transition time // Set transition time
unsigned char tranitionTime = 1; // currently fixed at value 1 which corresponds to 100ms unsigned char tranitionTime = 1; // currently fixed at value 1 which corresponds to 100ms
qToBigEndian<quint16>(static_cast<quint16>(tranitionTime), udpbuffer.data() + i);
i += 2;
highByte = static_cast<uchar>(tranitionTime >>8 ); DebugIf(verbose3, _log, "[%u] Color: {%u,%u,%u}", panelCounter, color.red, color.green, color.blue);
lowByte = static_cast<uchar>(tranitionTime & 0xFF);
udpbuffer[i++] = highByte;
udpbuffer[i++] = lowByte;
DebugIf(verbose3, _log, "[%u] Color: {%u,%u,%u}", panelCounter, color.red, color.green, color.blue );
} }
DebugIf(verbose3, _log, "UDP-Address [%s], UDP-Port [%u], udpBufferSize[%u], Bytes to send [%u]", QSTRING_CSTR(_address.toString()), _port, udpBufferSize, i);
DebugIf(verbose3, _log, "[%s]", uint8_vector_to_hex_string(udpbuffer).c_str() );
retVal &= writeBytes( i , udpbuffer.data()); if (verbose3)
DebugIf(verbose3, _log, "writeBytes(): [%d]",retVal); {
Debug(_log, "UDP-Address [%s], UDP-Port [%u], udpBufferSize[%d], Bytes to send [%d]", QSTRING_CSTR(_address.toString()), _port, udpBufferSize, i);
Debug( _log, "packet: [%s]", QSTRING_CSTR(toHex(udpbuffer, 64)));
}
retVal = writeBytes(udpbuffer);
return retVal; return retVal;
} }
std::string LedDeviceNanoleaf::uint8_vector_to_hex_string(const std::vector<uint8_t>& buffer) const
{
std::stringstream ss;
ss << std::hex << std::setfill('0');
std::vector<uint8_t>::const_iterator it;
for (it = buffer.begin(); it != buffer.end(); ++it)
{
ss << " " << std::setw(2) << static_cast<unsigned>(*it);
}
return ss.str();
}

View File

@ -32,7 +32,7 @@ public:
/// ///
/// @param deviceConfig Device's configuration as JSON-Object /// @param deviceConfig Device's configuration as JSON-Object
/// ///
explicit LedDeviceNanoleaf(const QJsonObject &deviceConfig); explicit LedDeviceNanoleaf(const QJsonObject& deviceConfig);
/// ///
/// @brief Destructor of the LED-device /// @brief Destructor of the LED-device
@ -44,14 +44,16 @@ public:
/// ///
/// @param[in] deviceConfig Device's configuration as JSON-Object /// @param[in] deviceConfig Device's configuration as JSON-Object
/// @return LedDevice constructed /// @return LedDevice constructed
static LedDevice* construct(const QJsonObject &deviceConfig); static LedDevice* construct(const QJsonObject& deviceConfig);
/// ///
/// @brief Discover Nanoleaf devices available (for configuration). /// @brief Discover Nanoleaf devices available (for configuration).
/// ///
/// @param[in] params Parameters used to overwrite discovery default behaviour
///
/// @return A JSON structure holding a list of devices found /// @return A JSON structure holding a list of devices found
/// ///
QJsonObject discover() override; QJsonObject discover(const QJsonObject& params) override;
/// ///
/// @brief Get the Nanoleaf device's resource properties /// @brief Get the Nanoleaf device's resource properties
@ -93,7 +95,7 @@ protected:
/// @param[in] deviceConfig the JSON device configuration /// @param[in] deviceConfig the JSON device configuration
/// @return True, if success /// @return True, if success
/// ///
bool init(const QJsonObject &deviceConfig) override; bool init(const QJsonObject& deviceConfig) override;
/// ///
/// @brief Opens the output device. /// @brief Opens the output device.
@ -108,7 +110,7 @@ protected:
/// @param[in] ledValues The RGB-color per LED /// @param[in] ledValues The RGB-color per LED
/// @return Zero on success, else negative /// @return Zero on success, else negative
////// //////
int write(const std::vector<ColorRgb> & ledValues) override; int write(const std::vector<ColorRgb>& ledValues) override;
/// ///
/// @brief Power-/turn on the Nanoleaf device. /// @brief Power-/turn on the Nanoleaf device.
@ -135,7 +137,7 @@ private:
/// ///
/// @return True, if success /// @return True, if success
/// ///
bool initRestAPI(const QString &hostname, int port, const QString &token ); bool initRestAPI(const QString& hostname, int port, const QString& token);
/// ///
/// @brief Get Nanoleaf device details and configuration /// @brief Get Nanoleaf device details and configuration
@ -157,14 +159,7 @@ private:
/// @param isOn True, if to switch on device /// @param isOn True, if to switch on device
/// @return Command to switch device on/off /// @return Command to switch device on/off
/// ///
QString getOnOffRequest (bool isOn ) const; QString getOnOffRequest(bool isOn) const;
///
/// @brief Convert vector to hex string
///
/// @param uint8_t vector
/// @return vector as string of hex values
std::string uint8_vector_to_hex_string( const std::vector<uint8_t>& buffer ) const;
///REST-API wrapper ///REST-API wrapper
ProviderRestApi* _restApi; ProviderRestApi* _restApi;
@ -175,8 +170,8 @@ private:
bool _topDown; bool _topDown;
bool _leftRight; bool _leftRight;
uint _startPos; int _startPos;
uint _endPos; int _endPos;
//Nanoleaf device details //Nanoleaf device details
QString _deviceModel; QString _deviceModel;
@ -184,11 +179,10 @@ private:
ushort _extControlVersion; ushort _extControlVersion;
/// The number of panels with LEDs /// The number of panels with LEDs
uint _panelLedCount; int _panelLedCount;
/// Array of the panel ids. /// Array of the panel ids.
QVector<uint> _panelIds; QVector<int> _panelIds;
}; };
#endif // LEDEVICENANOLEAF_H #endif // LEDEVICENANOLEAF_H

View File

@ -6,11 +6,11 @@
#include <chrono> #include <chrono>
bool verbose = false;
// Constants // Constants
namespace { namespace {
bool verbose = false;
// Configuration settings // Configuration settings
const char CONFIG_ADDRESS[] = "output"; const char CONFIG_ADDRESS[] = "output";
//const char CONFIG_PORT[] = "port"; //const char CONFIG_PORT[] = "port";
@ -97,31 +97,6 @@ const int STREAM_SSL_HANDSHAKE_ATTEMPTS = 5;
constexpr std::chrono::milliseconds STREAM_REWRITE_TIME{20}; constexpr std::chrono::milliseconds STREAM_REWRITE_TIME{20};
const int SSL_CIPHERSUITES[2] = { MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, 0 }; const int SSL_CIPHERSUITES[2] = { MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, 0 };
//Streaming message header and payload definition
const uint8_t HEADER[] =
{
'H', 'u', 'e', 'S', 't', 'r', 'e', 'a', 'm', //protocol
0x01, 0x00, //version 1.0
0x01, //sequence number 1
0x00, 0x00, //Reserved write 0s
0x01, //xy Brightness
0x00, // Reserved, write 0s
};
const uint8_t PAYLOAD_PER_LIGHT[] =
{
0x01, 0x00, 0x06, //light ID
//color: 16 bpc
0xff, 0xff,
0xff, 0xff,
0xff, 0xff,
/*
(message.R >> 8) & 0xff, message.R & 0xff,
(message.G >> 8) & 0xff, message.G & 0xff,
(message.B >> 8) & 0xff, message.B & 0xff
*/
};
} //End of constants } //End of constants
bool operator ==(const CiColor& p1, const CiColor& p2) bool operator ==(const CiColor& p1, const CiColor& p2)
@ -301,7 +276,7 @@ bool LedDevicePhilipsHueBridge::init(const QJsonObject &deviceConfig)
{ {
log( "DeviceType", "%s", QSTRING_CSTR( this->getActiveDeviceType() ) ); log( "DeviceType", "%s", QSTRING_CSTR( this->getActiveDeviceType() ) );
log( "LedCount", "%u", this->getLedCount() ); log( "LedCount", "%d", this->getLedCount() );
log( "ColorOrder", "%s", QSTRING_CSTR( this->getColorOrder() ) ); log( "ColorOrder", "%s", QSTRING_CSTR( this->getColorOrder() ) );
log( "RefreshTime", "%d", _refreshTimerInterval_ms ); log( "RefreshTime", "%d", _refreshTimerInterval_ms );
log( "LatchTime", "%d", this->getLatchTime() ); log( "LatchTime", "%d", this->getLatchTime() );
@ -313,7 +288,7 @@ bool LedDevicePhilipsHueBridge::init(const QJsonObject &deviceConfig)
if ( address.isEmpty() ) if ( address.isEmpty() )
{ {
this->setInError("No target hostname nor IP defined"); this->setInError("No target hostname nor IP defined");
return false; isInitOK = false;
} }
else else
{ {
@ -485,7 +460,7 @@ void LedDevicePhilipsHueBridge::setBridgeConfig(const QJsonDocument &doc)
log( "Bridge-ID", "%s", QSTRING_CSTR( deviceBridgeID )); log( "Bridge-ID", "%s", QSTRING_CSTR( deviceBridgeID ));
log( "SoftwareVersion", "%s", QSTRING_CSTR( _deviceFirmwareVersion )); log( "SoftwareVersion", "%s", QSTRING_CSTR( _deviceFirmwareVersion ));
log( "API-Version", "%u.%u.%u", _api_major, _api_minor, _api_patch ); log( "API-Version", "%u.%u.%u", _api_major, _api_minor, _api_patch );
log( "EntertainmentReady", "%d", _isHueEntertainmentReady ); log( "EntertainmentReady", "%d", static_cast<int>(_isHueEntertainmentReady) );
} }
void LedDevicePhilipsHueBridge::setLightsMap(const QJsonDocument &doc) void LedDevicePhilipsHueBridge::setLightsMap(const QJsonDocument &doc)
@ -511,7 +486,7 @@ void LedDevicePhilipsHueBridge::setLightsMap(const QJsonDocument &doc)
} }
else else
{ {
log( "Lights in Bridge found", "%u", getLedCount() ); log( "Lights in Bridge found", "%d", getLedCount() );
} }
} }
@ -922,7 +897,7 @@ bool LedDevicePhilipsHue::setLights()
if( !lArray.empty() ) if( !lArray.empty() )
{ {
for (const auto id : lArray) for (const QJsonValueRef id : lArray)
{ {
unsigned int lightId = id.toString().toUInt(); unsigned int lightId = id.toString().toUInt();
if( lightId > 0 ) if( lightId > 0 )
@ -1253,7 +1228,7 @@ QByteArray LedDevicePhilipsHue::prepareStreamData() const
{ {
QByteArray msg; QByteArray msg;
msg.reserve(static_cast<int>(sizeof(HEADER) + sizeof(PAYLOAD_PER_LIGHT) * _lights.size())); msg.reserve(static_cast<int>(sizeof(HEADER) + sizeof(PAYLOAD_PER_LIGHT) * _lights.size()));
msg.append((const char*)HEADER, sizeof(HEADER)); msg.append(reinterpret_cast<const char*>(HEADER), sizeof(HEADER));
for (const PhilipsHueLight& light : _lights) for (const PhilipsHueLight& light : _lights)
{ {
@ -1268,7 +1243,7 @@ QByteArray LedDevicePhilipsHue::prepareStreamData() const
static_cast<uint8_t>((G >> 8) & 0xff), static_cast<uint8_t>(G & 0xff), static_cast<uint8_t>((G >> 8) & 0xff), static_cast<uint8_t>(G & 0xff),
static_cast<uint8_t>((B >> 8) & 0xff), static_cast<uint8_t>(B & 0xff) static_cast<uint8_t>((B >> 8) & 0xff), static_cast<uint8_t>(B & 0xff)
}; };
msg.append((char*)payload, sizeof(payload)); msg.append(reinterpret_cast<const char *>(payload), sizeof(payload));
} }
return msg; return msg;
@ -1298,17 +1273,17 @@ int LedDevicePhilipsHue::close()
} }
bool LedDevicePhilipsHue::switchOn() bool LedDevicePhilipsHue::switchOn()
{ {
Debug(_log, ""); Debug(_log, "");
bool rc = false; bool rc = false;
if ( _isOn ) if ( _isOn )
{ {
rc = true; rc = true;
} }
else else
{ {
if ( _isEnabled && _isDeviceInitialised ) if ( _isEnabled && _isDeviceInitialised )
{ {
storeState(); storeState();
@ -1319,15 +1294,15 @@ bool LedDevicePhilipsHue::switchOn()
{ {
_isOn = true; _isOn = true;
rc = true; rc = true;
} }
} }
else if ( powerOn() ) else if ( powerOn() )
{ {
_isOn = true; _isOn = true;
rc = true; rc = true;
} }
}
} }
}
return rc; return rc;
} }
@ -1388,7 +1363,7 @@ void LedDevicePhilipsHue::stopBlackTimeoutTimer()
bool LedDevicePhilipsHue::noSignalDetection() bool LedDevicePhilipsHue::noSignalDetection()
{ {
if( _allLightsBlack ) if( _allLightsBlack && _switchOffOnBlack)
{ {
if( !_stopConnection && _isInitLeds ) if( !_stopConnection && _isInitLeds )
{ {
@ -1614,7 +1589,7 @@ bool LedDevicePhilipsHue::restoreState()
return rc; return rc;
} }
QJsonObject LedDevicePhilipsHue::discover() QJsonObject LedDevicePhilipsHue::discover(const QJsonObject& /*params*/)
{ {
QJsonObject devicesDiscovered; QJsonObject devicesDiscovered;
devicesDiscovered.insert("ledDeviceType", _activeDeviceType ); devicesDiscovered.insert("ledDeviceType", _activeDeviceType );

View File

@ -17,6 +17,31 @@
#include "ProviderRestApi.h" #include "ProviderRestApi.h"
#include "ProviderUdpSSL.h" #include "ProviderUdpSSL.h"
//Streaming message header and payload definition
const uint8_t HEADER[] =
{
'H', 'u', 'e', 'S', 't', 'r', 'e', 'a', 'm', //protocol
0x01, 0x00, //version 1.0
0x01, //sequence number 1
0x00, 0x00, //Reserved write 0s
0x01, //xy Brightness
0x00, // Reserved, write 0s
};
const uint8_t PAYLOAD_PER_LIGHT[] =
{
0x01, 0x00, 0x06, //light ID
//color: 16 bpc
0xff, 0xff,
0xff, 0xff,
0xff, 0xff,
/*
(message.R >> 8) & 0xff, message.R & 0xff,
(message.G >> 8) & 0xff, message.G & 0xff,
(message.B >> 8) & 0xff, message.B & 0xff
*/
};
/** /**
* A XY color point in the color space of the hue system without brightness. * A XY color point in the color space of the hue system without brightness.
*/ */
@ -326,7 +351,7 @@ public:
/// ///
/// @brief Destructor of the LED-device /// @brief Destructor of the LED-device
/// ///
~LedDevicePhilipsHue(); ~LedDevicePhilipsHue() override;
/// ///
/// @brief Constructs the LED-device /// @brief Constructs the LED-device
@ -339,9 +364,11 @@ public:
/// @brief Discover devices of this type available (for configuration). /// @brief Discover devices of this type available (for configuration).
/// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways. /// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways.
/// ///
/// @param[in] params Parameters used to overwrite discovery default behaviour
///
/// @return A JSON structure holding a list of devices found /// @return A JSON structure holding a list of devices found
/// ///
QJsonObject discover() override; QJsonObject discover(const QJsonObject& params) override;
/// ///
/// @brief Get the Hue Bridge device's resource properties /// @brief Get the Hue Bridge device's resource properties

View File

@ -17,7 +17,7 @@ const quint16 STREAM_DEFAULT_PORT = 19446;
const int API_DEFAULT_PORT = -1; //Use default port per communication scheme const int API_DEFAULT_PORT = -1; //Use default port per communication scheme
const char API_BASE_PATH[] = "/json/"; const char API_BASE_PATH[] = "/json/";
const char API_PATH_INFO[] = "info"; //const char API_PATH_INFO[] = "info";
const char API_PATH_STATE[] = "state"; const char API_PATH_STATE[] = "state";
// List of State Information // List of State Information
@ -60,9 +60,9 @@ bool LedDeviceWled::init(const QJsonObject &deviceConfig)
if ( LedDevice::init(deviceConfig) ) if ( LedDevice::init(deviceConfig) )
{ {
// Initialise LedDevice configuration and execution environment // Initialise LedDevice configuration and execution environment
uint configuredLedCount = this->getLedCount(); int configuredLedCount = this->getLedCount();
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() )); Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
Debug(_log, "LedCount : %u", configuredLedCount); Debug(_log, "LedCount : %d", configuredLedCount);
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() )); Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
Debug(_log, "LatchTime : %d", this->getLatchTime()); Debug(_log, "LatchTime : %d", this->getLatchTime());
@ -166,7 +166,7 @@ bool LedDeviceWled::powerOff()
return off; return off;
} }
QJsonObject LedDeviceWled::discover() QJsonObject LedDeviceWled::discover(const QJsonObject& /*params*/)
{ {
QJsonObject devicesDiscovered; QJsonObject devicesDiscovered;
devicesDiscovered.insert("ledDeviceType", _activeDeviceType ); devicesDiscovered.insert("ledDeviceType", _activeDeviceType );

View File

@ -37,9 +37,11 @@ public:
/// ///
/// @brief Discover WLED devices available (for configuration). /// @brief Discover WLED devices available (for configuration).
/// ///
/// @param[in] params Parameters used to overwrite discovery default behaviour
///
/// @return A JSON structure holding a list of devices found /// @return A JSON structure holding a list of devices found
/// ///
QJsonObject discover() override; QJsonObject discover(const QJsonObject& params) override;
/// ///
/// @brief Get the WLED device's resource properties /// @brief Get the WLED device's resource properties

View File

@ -247,7 +247,7 @@ int YeelightLight::writeCommand( const QJsonDocument &command, QJsonArray &resul
if ( elapsedTime < _waitTimeQuota ) if ( elapsedTime < _waitTimeQuota )
{ {
int waitTime = _waitTimeQuota; int waitTime = _waitTimeQuota;
log ( 1, "writeCommand():", "Wait %dms, elapsedTime: %dms < quotaTime: %dms", waitTime, elapsedTime, _waitTimeQuota); log ( 1, "writeCommand():", "Wait %dms, elapsedTime: %dms < quotaTime: %dms", waitTime, static_cast<int>(elapsedTime), _waitTimeQuota);
// Wait time (in ms) before doing next write to not overrun Yeelight command quota // Wait time (in ms) before doing next write to not overrun Yeelight command quota
std::this_thread::sleep_for(std::chrono::milliseconds(_waitTimeQuota)); std::this_thread::sleep_for(std::chrono::milliseconds(_waitTimeQuota));
@ -452,7 +452,7 @@ YeelightResponse YeelightLight::handleResponse(int correlationID, QByteArray con
// Debug output // Debug output
if(!yeeResponse.getResult().empty()) if(!yeeResponse.getResult().empty())
{ {
for(const auto item : yeeResponse.getResult()) for(const QJsonValueRef item : yeeResponse.getResult())
{ {
log ( 3, "Result:", "%s", QSTRING_CSTR( item.toString() )); log ( 3, "Result:", "%s", QSTRING_CSTR( item.toString() ));
} }
@ -524,7 +524,7 @@ QJsonObject YeelightLight::getProperties()
if( !result.empty()) if( !result.empty())
{ {
int i = 0; int i = 0;
for(const auto item : result) for(const QJsonValueRef item : result)
{ {
log (1,"Property:", "%s = %s", QSTRING_CSTR( propertyList.at(i).toString() ), QSTRING_CSTR( item.toString() )); log (1,"Property:", "%s = %s", QSTRING_CSTR( propertyList.at(i).toString() ), QSTRING_CSTR( item.toString() ));
properties.insert( propertyList.at(i).toString(), item ); properties.insert( propertyList.at(i).toString(), item );
@ -1008,7 +1008,7 @@ bool LedDeviceYeelight::init(const QJsonObject &deviceConfig)
if ( LedDevice::init(deviceConfig) ) if ( LedDevice::init(deviceConfig) )
{ {
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() )); Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
Debug(_log, "LedCount : %u", this->getLedCount()); Debug(_log, "LedCount : %d", this->getLedCount());
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() )); Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
Debug(_log, "RewriteTime : %d", this->getRewriteTime()); Debug(_log, "RewriteTime : %d", this->getRewriteTime());
Debug(_log, "LatchTime : %d", this->getLatchTime()); Debug(_log, "LatchTime : %d", this->getLatchTime());
@ -1073,8 +1073,8 @@ bool LedDeviceYeelight::init(const QJsonObject &deviceConfig)
Debug(_log, "Debuglevel : %d", _debuglevel); Debug(_log, "Debuglevel : %d", _debuglevel);
QJsonArray configuredYeelightLights = _devConfig[CONFIG_LIGHTS].toArray(); QJsonArray configuredYeelightLights = _devConfig[CONFIG_LIGHTS].toArray();
uint configuredYeelightsCount = 0; int configuredYeelightsCount = 0;
for (const QJsonValue light : configuredYeelightLights) for (const QJsonValueRef light : configuredYeelightLights)
{ {
QString host = light.toObject().value("host").toString(); QString host = light.toObject().value("host").toString();
int port = light.toObject().value("port").toInt(API_DEFAULT_PORT); int port = light.toObject().value("port").toInt(API_DEFAULT_PORT);
@ -1085,9 +1085,9 @@ bool LedDeviceYeelight::init(const QJsonObject &deviceConfig)
++configuredYeelightsCount; ++configuredYeelightsCount;
} }
} }
Debug(_log, "Light configured : %u", configuredYeelightsCount ); Debug(_log, "Light configured : %d", configuredYeelightsCount );
uint configuredLedCount = this->getLedCount(); int configuredLedCount = this->getLedCount();
if (configuredYeelightsCount < configuredLedCount ) if (configuredYeelightsCount < configuredLedCount )
{ {
QString errorReason = QString("Not enough Yeelights [%1] for configured LEDs [%2] found!") QString errorReason = QString("Not enough Yeelights [%1] for configured LEDs [%2] found!")
@ -1101,7 +1101,7 @@ bool LedDeviceYeelight::init(const QJsonObject &deviceConfig)
if ( configuredYeelightsCount > configuredLedCount ) if ( configuredYeelightsCount > configuredLedCount )
{ {
Warning(_log, "More Yeelights defined [%u] than configured LEDs [%u].", configuredYeelightsCount, configuredLedCount ); Warning(_log, "More Yeelights defined [%d] than configured LEDs [%d].", configuredYeelightsCount, configuredLedCount );
} }
_lightsAddressList.clear(); _lightsAddressList.clear();
@ -1347,7 +1347,7 @@ bool LedDeviceYeelight::restoreState()
return rc; return rc;
} }
QJsonObject LedDeviceYeelight::discover() QJsonObject LedDeviceYeelight::discover(const QJsonObject& /*params*/)
{ {
QJsonObject devicesDiscovered; QJsonObject devicesDiscovered;
devicesDiscovered.insert("ledDeviceType", _activeDeviceType ); devicesDiscovered.insert("ledDeviceType", _activeDeviceType );

View File

@ -435,12 +435,11 @@ public:
/// ///
static LedDevice* construct(const QJsonObject &deviceConfig); static LedDevice* construct(const QJsonObject &deviceConfig);
/// /// @param[in] params Parameters used to overwrite discovery default behaviour
/// @brief Discover Yeelight devices available (for configuration).
/// ///
/// @return A JSON structure holding a list of devices found /// @return A JSON structure holding a list of devices found
/// ///
QJsonObject discover() override; QJsonObject discover(const QJsonObject& params) override;
/// ///
/// @brief Get a Yeelight device's resource properties /// @brief Get a Yeelight device's resource properties

View File

@ -1,4 +1,3 @@
// STL includes // STL includes
#include <cstring> #include <cstring>
#include <cstdio> #include <cstdio>
@ -16,9 +15,9 @@
const ushort MAX_PORT = 65535; const ushort MAX_PORT = 65535;
ProviderUdp::ProviderUdp(const QJsonObject &deviceConfig) ProviderUdp::ProviderUdp(const QJsonObject& deviceConfig)
: LedDevice(deviceConfig) : LedDevice(deviceConfig)
, _udpSocket (nullptr) , _udpSocket(nullptr)
, _port(1) , _port(1)
, _defaultHost("127.0.0.1") , _defaultHost("127.0.0.1")
{ {
@ -30,48 +29,48 @@ ProviderUdp::~ProviderUdp()
delete _udpSocket; delete _udpSocket;
} }
bool ProviderUdp::init(const QJsonObject &deviceConfig) bool ProviderUdp::init(const QJsonObject& deviceConfig)
{ {
bool isInitOK = false; bool isInitOK = false;
// Initialise sub-class // Initialise sub-class
if ( LedDevice::init(deviceConfig) ) if (LedDevice::init(deviceConfig))
{ {
QString host = deviceConfig["host"].toString(_defaultHost); QString host = deviceConfig["host"].toString(_defaultHost);
if (_address.setAddress(host) ) if (_address.setAddress(host))
{ {
Debug( _log, "Successfully parsed %s as an IP-address.", QSTRING_CSTR(_address.toString())); Debug(_log, "Successfully parsed %s as an IP-address.", QSTRING_CSTR(_address.toString()));
} }
else else
{ {
QHostInfo hostInfo = QHostInfo::fromName(host); QHostInfo hostInfo = QHostInfo::fromName(host);
if ( hostInfo.error() == QHostInfo::NoError ) if (hostInfo.error() == QHostInfo::NoError)
{ {
_address = hostInfo.addresses().first(); _address = hostInfo.addresses().first();
Debug( _log, "Successfully resolved IP-address (%s) for hostname (%s).", QSTRING_CSTR(_address.toString()), QSTRING_CSTR(host)); Debug(_log, "Successfully resolved IP-address (%s) for hostname (%s).", QSTRING_CSTR(_address.toString()), QSTRING_CSTR(host));
} }
else else
{ {
QString errortext = QString ("Failed resolving IP-address for [%1], (%2) %3").arg(host).arg(hostInfo.error()).arg(hostInfo.errorString()); QString errortext = QString("Failed resolving IP-address for [%1], (%2) %3").arg(host).arg(hostInfo.error()).arg(hostInfo.errorString());
this->setInError ( errortext ); this->setInError(errortext);
isInitOK = false; isInitOK = false;
} }
} }
if ( !_isDeviceInError ) if (!_isDeviceInError)
{ {
int config_port = deviceConfig["port"].toInt(_port); int config_port = deviceConfig["port"].toInt(_port);
if ( config_port <= 0 || config_port > MAX_PORT ) if (config_port <= 0 || config_port > MAX_PORT)
{ {
QString errortext = QString ("Invalid target port [%1]!").arg(config_port); QString errortext = QString("Invalid target port [%1]!").arg(config_port);
this->setInError ( errortext ); this->setInError(errortext);
isInitOK = false; isInitOK = false;
} }
else else
{ {
_port = static_cast<int>(config_port); _port = static_cast<quint16>(config_port);
Debug( _log, "UDP socket will write to %s:%u", QSTRING_CSTR(_address.toString()) , _port ); Debug(_log, "UDP socket will write to %s:%u", QSTRING_CSTR(_address.toString()), _port);
_udpSocket = new QUdpSocket(this); _udpSocket = new QUdpSocket(this);
@ -88,16 +87,16 @@ int ProviderUdp::open()
_isDeviceReady = false; _isDeviceReady = false;
// Try to bind the UDP-Socket // Try to bind the UDP-Socket
if ( _udpSocket != nullptr ) if (_udpSocket != nullptr)
{ {
if ( _udpSocket->state() != QAbstractSocket::BoundState ) if (_udpSocket->state() != QAbstractSocket::BoundState)
{ {
QHostAddress localAddress = QHostAddress::Any; QHostAddress localAddress = QHostAddress::Any;
quint16 localPort = 0; quint16 localPort = 0;
if ( !_udpSocket->bind(localAddress, localPort) ) if (!_udpSocket->bind(localAddress, localPort))
{ {
QString warntext = QString ("Could not bind local address: %1, (%2) %3").arg(localAddress.toString()).arg(_udpSocket->error()).arg(_udpSocket->errorString()); QString warntext = QString("Could not bind local address: %1, (%2) %3").arg(localAddress.toString()).arg(_udpSocket->error()).arg(_udpSocket->errorString());
Warning ( _log, "%s", QSTRING_CSTR(warntext)); Warning(_log, "%s", QSTRING_CSTR(warntext));
} }
} }
// Everything is OK, device is ready // Everything is OK, device is ready
@ -106,7 +105,7 @@ int ProviderUdp::open()
} }
else else
{ {
this->setInError( " Open error. UDP Socket not initialised!" ); this->setInError(" Open error. UDP Socket not initialised!");
} }
return retval; return retval;
} }
@ -116,12 +115,12 @@ int ProviderUdp::close()
int retval = 0; int retval = 0;
_isDeviceReady = false; _isDeviceReady = false;
if ( _udpSocket != nullptr ) if (_udpSocket != nullptr)
{ {
// Test, if device requires closing // Test, if device requires closing
if ( _udpSocket->isOpen() ) if (_udpSocket->isOpen())
{ {
Debug(_log,"Close UDP-device: %s", QSTRING_CSTR( this->getActiveDeviceType() ) ); Debug(_log, "Close UDP-device: %s", QSTRING_CSTR(this->getActiveDeviceType()));
_udpSocket->close(); _udpSocket->close();
// Everything is OK -> device is closed // Everything is OK -> device is closed
} }
@ -129,22 +128,28 @@ int ProviderUdp::close()
return retval; return retval;
} }
int ProviderUdp::writeBytes(const unsigned size, const uint8_t * data) int ProviderUdp::writeBytes(const unsigned size, const uint8_t* data)
{ {
qint64 retVal = _udpSocket->writeDatagram((const char *)data,size,_address,_port); int rc = 0;
qint64 bytesWritten = _udpSocket->writeDatagram(reinterpret_cast<const char*>(data), size, _address, _port);
WarningIf((retVal<0), _log, "&s", QSTRING_CSTR(QString if (bytesWritten == -1 || bytesWritten != size)
("(%1:%2) Write Error: (%3) %4").arg(_address.toString()).arg(_port).arg(_udpSocket->error()).arg(_udpSocket->errorString()))); {
Warning(_log, "%s", QSTRING_CSTR(QString("(%1:%2) Write Error: (%3) %4").arg(_address.toString()).arg(_port).arg(_udpSocket->error()).arg(_udpSocket->errorString())));
return retVal; rc = -1;
}
return rc;
} }
int ProviderUdp::writeBytes(const QByteArray &bytes) int ProviderUdp::writeBytes(const QByteArray& bytes)
{ {
qint64 retVal = _udpSocket->writeDatagram(bytes,_address,_port); int rc = 0;
qint64 bytesWritten = _udpSocket->writeDatagram(bytes, _address, _port);
WarningIf((retVal<0), _log, "&s", QSTRING_CSTR(QString if (bytesWritten == -1 || bytesWritten != bytes.size())
("(%1:%2) Write Error: (%3) %4").arg(_address.toString()).arg(_port).arg(_udpSocket->error()).arg(_udpSocket->errorString()))); {
Warning(_log, "%s", QSTRING_CSTR(QString("(%1:%2) Write Error: (%3) %4").arg(_address.toString()).arg(_port).arg(_udpSocket->error()).arg(_udpSocket->errorString())));
return retVal; rc = -1;
}
return rc;
} }

View File

@ -21,7 +21,7 @@ public:
/// ///
/// @brief Constructs an UDP LED-device /// @brief Constructs an UDP LED-device
/// ///
ProviderUdp(const QJsonObject &deviceConfig); ProviderUdp(const QJsonObject& deviceConfig);
/// ///
/// @brief Destructor of the UDP LED-device /// @brief Destructor of the UDP LED-device
@ -38,7 +38,7 @@ protected:
/// @param[in] deviceConfig the JSON device configuration /// @param[in] deviceConfig the JSON device configuration
/// @return True, if success /// @return True, if success
/// ///
bool init(const QJsonObject &deviceConfig) override; bool init(const QJsonObject& deviceConfig) override;
/// ///
/// @brief Opens the output device. /// @brief Opens the output device.
@ -62,7 +62,7 @@ protected:
/// ///
/// @return Zero on success, else negative /// @return Zero on success, else negative
/// ///
int writeBytes(const unsigned size, const uint8_t *data); int writeBytes(const unsigned size, const uint8_t* data);
/// ///
/// @brief Writes the given bytes to the UDP-device /// @brief Writes the given bytes to the UDP-device
@ -71,10 +71,10 @@ protected:
/// ///
/// @return Zero on success, else negative /// @return Zero on success, else negative
/// ///
int writeBytes(const QByteArray &bytes); int writeBytes(const QByteArray& bytes);
/// ///
QUdpSocket * _udpSocket; QUdpSocket* _udpSocket;
QHostAddress _address; QHostAddress _address;
quint16 _port; quint16 _port;
QString _defaultHost; QString _defaultHost;

View File

@ -26,6 +26,14 @@ bool LedDeviceFile::init(const QJsonObject &deviceConfig)
bool initOK = LedDevice::init(deviceConfig); bool initOK = LedDevice::init(deviceConfig);
_fileName = deviceConfig["output"].toString("/dev/null"); _fileName = deviceConfig["output"].toString("/dev/null");
#if _WIN32
if (_fileName == "/dev/null" )
{
_fileName = "NULL";
}
#endif
_printTimeStamp = deviceConfig["printTimeStamp"].toBool(false); _printTimeStamp = deviceConfig["printTimeStamp"].toBool(false);
initFile(_fileName); initFile(_fileName);

View File

@ -1,5 +1,7 @@
#include "LedDeviceAdalight.h" #include "LedDeviceAdalight.h"
#include <QtEndian>
#include <cassert> #include <cassert>
LedDeviceAdalight::LedDeviceAdalight(const QJsonObject &deviceConfig) LedDeviceAdalight::LedDeviceAdalight(const QJsonObject &deviceConfig)
@ -50,8 +52,7 @@ bool LedDeviceAdalight::init(const QJsonObject &deviceConfig)
_ledBuffer[0] = 'A'; _ledBuffer[0] = 'A';
_ledBuffer[1] = 'd'; _ledBuffer[1] = 'd';
_ledBuffer[2] = 'a'; _ledBuffer[2] = 'a';
_ledBuffer[3] = (totalLedCount >> 8) & 0xFF; // LED count high byte qToBigEndian<quint16>(static_cast<quint16>(totalLedCount), &_ledBuffer[3]);
_ledBuffer[4] = totalLedCount & 0xFF; // LED count low byte
_ledBuffer[5] = _ledBuffer[3] ^ _ledBuffer[4] ^ 0x55; // Checksum _ledBuffer[5] = _ledBuffer[3] ^ _ledBuffer[4] ^ 0x55; // Checksum
Debug( _log, "Adalight header for %d leds: %c%c%c 0x%02x 0x%02x 0x%02x", _ledCount, Debug( _log, "Adalight header for %d leds: %c%c%c 0x%02x 0x%02x 0x%02x", _ledCount,

View File

@ -34,7 +34,7 @@ bool ProviderRs232::init(const QJsonObject &deviceConfig)
{ {
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() )); Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
Debug(_log, "LedCount : %u", this->getLedCount()); Debug(_log, "LedCount : %d", this->getLedCount());
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() )); Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
Debug(_log, "RefreshTime : %d", _refreshTimerInterval_ms); Debug(_log, "RefreshTime : %d", _refreshTimerInterval_ms);
Debug(_log, "LatchTime : %d", this->getLatchTime()); Debug(_log, "LatchTime : %d", this->getLatchTime());
@ -256,7 +256,7 @@ QString ProviderRs232::discoverFirst()
return ""; return "";
} }
QJsonObject ProviderRs232::discover() QJsonObject ProviderRs232::discover(const QJsonObject& /*params*/)
{ {
QJsonObject devicesDiscovered; QJsonObject devicesDiscovered;
devicesDiscovered.insert("ledDeviceType", _activeDeviceType ); devicesDiscovered.insert("ledDeviceType", _activeDeviceType );

View File

@ -66,12 +66,11 @@ protected:
/// ///
QString discoverFirst() override; QString discoverFirst() override;
/// /// @param[in] params Parameters used to overwrite discovery default behaviour
/// @brief Discover RS232 serial devices available (for configuration).
/// ///
/// @return A JSON structure holding a list of devices found /// @return A JSON structure holding a list of devices found
/// ///
QJsonObject discover() override; QJsonObject discover(const QJsonObject& params) override;
/// ///
/// @brief Write the given bytes to the RS232-device /// @brief Write the given bytes to the RS232-device

View File

@ -214,7 +214,7 @@ void ProtoClientConnection::handleNotImplemented()
void ProtoClientConnection::sendMessage(const google::protobuf::Message &message) void ProtoClientConnection::sendMessage(const google::protobuf::Message &message)
{ {
std::string serializedReply = message.SerializeAsString(); std::string serializedReply = message.SerializeAsString();
uint32_t size = serializedReply.size(); uint32_t size = static_cast<uint32_t>(serializedReply.size());
uint8_t sizeData[] = {uint8_t(size >> 24), uint8_t(size >> 16), uint8_t(size >> 8), uint8_t(size)}; uint8_t sizeData[] = {uint8_t(size >> 24), uint8_t(size >> 16), uint8_t(size >> 8), uint8_t(size)};
_socket->write((const char *) sizeData, sizeof(sizeData)); _socket->write((const char *) sizeData, sizeof(sizeData));
_socket->write(serializedReply.data(), serializedReply.length()); _socket->write(serializedReply.data(), serializedReply.length());

View File

@ -1,7 +1,3 @@
#undef slots
#include <Python.h>
#define slots
// utils // utils
#include <utils/Logger.h> #include <utils/Logger.h>
@ -48,7 +44,11 @@ PythonInit::PythonInit()
throw std::runtime_error("Initializing Python failed!"); throw std::runtime_error("Initializing Python failed!");
} }
#if (PY_VERSION_HEX < 0x03090000)
// PyEval_InitThreads became deprecated in Python 3.9 and will be removed in Python 3.11
PyEval_InitThreads(); // Create the GIL PyEval_InitThreads(); // Create the GIL
#endif
mainThreadState = PyEval_SaveThread(); mainThreadState = PyEval_SaveThread();
} }

View File

@ -19,8 +19,12 @@ PythonProgram::PythonProgram(const QString & name, Logger * log) :
_tstate = Py_NewInterpreter(); _tstate = Py_NewInterpreter();
if(_tstate == nullptr) if(_tstate == nullptr)
{ {
#if (PY_VERSION_HEX >= 0x03020000)
PyThreadState_Swap(mainThreadState); PyThreadState_Swap(mainThreadState);
PyEval_SaveThread(); PyEval_SaveThread();
#else
PyEval_ReleaseLock();
#endif
Error(_log, "Failed to get thread state for %s",QSTRING_CSTR(_name)); Error(_log, "Failed to get thread state for %s",QSTRING_CSTR(_name));
return; return;
} }
@ -55,8 +59,12 @@ PythonProgram::~PythonProgram()
// Clean up the thread state // Clean up the thread state
Py_EndInterpreter(_tstate); Py_EndInterpreter(_tstate);
#if (PY_VERSION_HEX >= 0x03020000)
PyThreadState_Swap(mainThreadState); PyThreadState_Swap(mainThreadState);
PyEval_SaveThread(); PyEval_SaveThread();
#else
PyEval_ReleaseLock();
#endif
} }
void PythonProgram::execute(const QByteArray & python_code) void PythonProgram::execute(const QByteArray & python_code)

View File

@ -15,10 +15,6 @@ RgbChannelAdjustment::RgbChannelAdjustment(uint8_t adjustR, uint8_t adjustG, uin
setAdjustment(adjustR, adjustG, adjustB); setAdjustment(adjustR, adjustG, adjustB);
} }
RgbChannelAdjustment::~RgbChannelAdjustment()
{
}
void RgbChannelAdjustment::resetInitialized() void RgbChannelAdjustment::resetInitialized()
{ {
//Debug(_log, "initialize mapping with %d,%d,%d", _adjust[RED], _adjust[GREEN], _adjust[BLUE]); //Debug(_log, "initialize mapping with %d,%d,%d", _adjust[RED], _adjust[GREEN], _adjust[BLUE]);

View File

@ -7,10 +7,22 @@ namespace RGBW {
WhiteAlgorithm stringToWhiteAlgorithm(const QString& str) WhiteAlgorithm stringToWhiteAlgorithm(const QString& str)
{ {
if (str == "subtract_minimum") return WhiteAlgorithm::SUBTRACT_MINIMUM; if (str == "subtract_minimum")
if (str == "sub_min_warm_adjust") return WhiteAlgorithm::SUB_MIN_WARM_ADJUST; {
if (str == "sub_min_cool_adjust") return WhiteAlgorithm::SUB_MIN_COOL_ADJUST; return WhiteAlgorithm::SUBTRACT_MINIMUM;
if (str.isEmpty() || str == "white_off") return WhiteAlgorithm::WHITE_OFF; }
if (str == "sub_min_warm_adjust")
{
return WhiteAlgorithm::SUB_MIN_WARM_ADJUST;
}
if (str == "sub_min_cool_adjust")
{
return WhiteAlgorithm::SUB_MIN_COOL_ADJUST;
}
if (str.isEmpty() || str == "white_off")
{
return WhiteAlgorithm::WHITE_OFF;
}
return WhiteAlgorithm::INVALID; return WhiteAlgorithm::INVALID;
} }
@ -20,7 +32,7 @@ void Rgb_to_Rgbw(ColorRgb input, ColorRgbw * output, WhiteAlgorithm algorithm)
{ {
case WhiteAlgorithm::SUBTRACT_MINIMUM: case WhiteAlgorithm::SUBTRACT_MINIMUM:
{ {
output->white = qMin(qMin(input.red, input.green), input.blue); output->white = static_cast<uint8_t>(qMin(qMin(input.red, input.green), input.blue));
output->red = input.red - output->white; output->red = input.red - output->white;
output->green = input.green - output->white; output->green = input.green - output->white;
output->blue = input.blue - output->white; output->blue = input.blue - output->white;
@ -31,14 +43,14 @@ void Rgb_to_Rgbw(ColorRgb input, ColorRgbw * output, WhiteAlgorithm algorithm)
{ {
// http://forum.garagecube.com/viewtopic.php?t=10178 // http://forum.garagecube.com/viewtopic.php?t=10178
// warm white // warm white
const float F1(0.274); const double F1(0.274);
const float F2(0.454); const double F2(0.454);
const float F3(2.333); const double F3(2.333);
output->white = qMin(input.red*F1,qMin(input.green*F2,input.blue*F3)); output->white = static_cast<uint8_t>(qMin(input.red*F1,qMin(input.green*F2,input.blue*F3)));
output->red = input.red - output->white/F1; output->red = input.red - static_cast<uint8_t>(output->white/F1);
output->green = input.green - output->white/F2; output->green = input.green - static_cast<uint8_t>(output->white/F2);
output->blue = input.blue - output->white/F3; output->blue = input.blue - static_cast<uint8_t>(output->white/F3);
break; break;
} }
@ -46,14 +58,14 @@ void Rgb_to_Rgbw(ColorRgb input, ColorRgbw * output, WhiteAlgorithm algorithm)
{ {
// http://forum.garagecube.com/viewtopic.php?t=10178 // http://forum.garagecube.com/viewtopic.php?t=10178
// cold white // cold white
const float F1(0.299); const double F1(0.299);
const float F2(0.587); const double F2(0.587);
const float F3(0.114); const double F3(0.114);
output->white = qMin(input.red*F1,qMin(input.green*F2,input.blue*F3)); output->white = static_cast<uint8_t>(qMin(input.red*F1,qMin(input.green*F2,input.blue*F3)));
output->red = input.red - output->white/F1; output->red = input.red - static_cast<uint8_t>(output->white/F1);
output->green = input.green - output->white/F2; output->green = input.green - static_cast<uint8_t>(output->white/F2);
output->blue = input.blue - output->white/F3; output->blue = input.blue - static_cast<uint8_t>(output->white/F3);
break; break;
} }

View File

@ -242,7 +242,7 @@ void QtHttpClientWrapper::onReplySendHeadersRequested (void)
{ {
QByteArray data; QByteArray data;
// HTTP Version + Status Code + Status Msg // HTTP Version + Status Code + Status Msg
data.append (QtHttpServer::HTTP_VERSION); data.append (QtHttpServer::HTTP_VERSION.toUtf8());
data.append (SPACE); data.append (SPACE);
data.append (QByteArray::number (reply->getStatusCode ())); data.append (QByteArray::number (reply->getStatusCode ()));
data.append (SPACE); data.append (SPACE);

View File

@ -223,7 +223,7 @@ void WebSocketClient::sendClose(int status, QString reason)
sendBuffer.append(quint8(length)); sendBuffer.append(quint8(length));
} }
sendBuffer.append(reason); sendBuffer.append(reason.toUtf8());
_socket->write(sendBuffer); _socket->write(sendBuffer);
_socket->flush(); _socket->flush();

View File

@ -27,7 +27,9 @@ int count(std::initializer_list<bool> values)
int count = 0; int count = 0;
for (bool value : values) { for (bool value : values) {
if (value) if (value)
{
count++; count++;
}
} }
return count; return count;
} }
@ -43,14 +45,16 @@ void showHelp(Option & option){
qWarning() << qPrintable(QString("\t%1\t%2\t%3").arg(shortOption, longOption, option.description())); qWarning() << qPrintable(QString("\t%1\t%2\t%3").arg(shortOption, longOption, option.description()));
} }
int getInstaneIdbyName(const QJsonObject & reply, const QString name){ int getInstaneIdbyName(const QJsonObject & reply, const QString & name){
if(reply.contains("instance")){ if(reply.contains("instance")){
QJsonArray list = reply.value("instance").toArray(); QJsonArray list = reply.value("instance").toArray();
for (const auto & entry : list) { for (const QJsonValueRef entry : list) {
const QJsonObject obj = entry.toObject(); const QJsonObject obj = entry.toObject();
if(obj["friendly_name"] == name && obj["running"].toBool()) if(obj["friendly_name"] == name && obj["running"].toBool())
{
return obj["instance"].toInt(); return obj["instance"].toInt();
}
} }
} }
std::cout << "Can't find a running instance with name '" << name.toStdString()<< "' at this Hyperion server, will use first instance" << std::endl; std::cout << "Can't find a running instance with name '" << name.toStdString()<< "' at this Hyperion server, will use first instance" << std::endl;
@ -78,23 +82,23 @@ int main(int argc, char * argv[])
try try
{ {
// create the option parser and initialize all parameters // create the option parser and initialize all parameters
Parser parser("Application to send a command to hyperion using the Json interface"); Parser parser("Application to send a command to hyperion using the JSON interface");
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// art variable definition append art to Parser short-, long option description, optional default value // // art variable definition append art to Parser short-, long option description, optional default value //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Option & argAddress = parser.add<Option> ('a', "address" , "Set the address of the hyperion server [default: %1]", "127.0.0.1:19444"); Option & argAddress = parser.add<Option> ('a', "address" , "Set the address of the hyperion server [default: %1]", "127.0.0.1:19444");
Option & argToken = parser.add<Option> ('t', "token " , "If authorization tokens are required, this token is used"); Option & argToken = parser.add<Option> ('t', "token " , "If authorization tokens are required, this token is used");
Option & argInstance = parser.add<Option> ('I', "instance" , "Select a specific target instance by name for your command. By befault it uses always the first instance"); Option & argInstance = parser.add<Option> ('I', "instance" , "Select a specific target instance by name for your command. By default it uses always the first instance");
IntOption & argPriority = parser.add<IntOption> ('p', "priority" , "Used to the provided priority channel (suggested 2-99) [default: %1]", "50"); IntOption & argPriority = parser.add<IntOption> ('p', "priority" , "Used to the provided priority channel (suggested 2-99) [default: %1]", "50");
IntOption & argDuration = parser.add<IntOption> ('d', "duration" , "Specify how long the leds should be switched on in milliseconds [default: infinity]"); IntOption & argDuration = parser.add<IntOption> ('d', "duration" , "Specify how long the LEDs should be switched on in milliseconds [default: infinity]");
ColorsOption & argColor = parser.add<ColorsOption> ('c', "color" , "Set all leds to a constant color (either RRGGBB hex getColors or a color name. The color may be repeated multiple time like: RRGGBBRRGGBB)"); ColorsOption & argColor = parser.add<ColorsOption> ('c', "color" , "Set all LEDs to a constant color (either RRGGBB hex getColors or a color name. The color may be repeated multiple time like: RRGGBBRRGGBB)");
ImageOption & argImage = parser.add<ImageOption> ('i', "image" , "Set the leds to the colors according to the given image file"); ImageOption & argImage = parser.add<ImageOption> ('i', "image" , "Set the LEDs to the colors according to the given image file");
Option & argEffect = parser.add<Option> ('e', "effect" , "Enable the effect with the given name"); Option & argEffect = parser.add<Option> ('e', "effect" , "Enable the effect with the given name");
Option & argEffectFile = parser.add<Option> (0x0, "effectFile" , "Arguments to use in combination with --createEffect"); Option & argEffectFile = parser.add<Option> (0x0, "effectFile" , "Arguments to use in combination with --createEffect");
Option & argEffectArgs = parser.add<Option> (0x0, "effectArgs" , "Arguments to use in combination with the specified effect. Should be a Json object string.", ""); Option & argEffectArgs = parser.add<Option> (0x0, "effectArgs" , "Arguments to use in combination with the specified effect. Should be a JSON object string.", "");
Option & argCreateEffect = parser.add<Option> (0x0, "createEffect" , "Write a new Json Effect configuration file.\nFirst parameter = Effect name.\nSecond parameter = Effect file (--effectFile).\nLast parameter = Effect arguments (--effectArgs.)", ""); Option & argCreateEffect = parser.add<Option> (0x0, "createEffect" , "Write a new JSON Effect configuration file.\nFirst parameter = Effect name.\nSecond parameter = Effect file (--effectFile).\nLast parameter = Effect arguments (--effectArgs.)", "");
Option & argDeleteEffect = parser.add<Option> (0x0, "deleteEffect" , "Delete a custom created Json Effect configuration file."); Option & argDeleteEffect = parser.add<Option> (0x0, "deleteEffect" , "Delete a custom created JSON Effect configuration file.");
BooleanOption & argServerInfo = parser.add<BooleanOption>('l', "list" , "List server info and active effects with priority and duration"); BooleanOption & argServerInfo = parser.add<BooleanOption>('l', "list" , "List server info and active effects with priority and duration");
BooleanOption & argSysInfo = parser.add<BooleanOption>('s', "sysinfo" , "show system info"); BooleanOption & argSysInfo = parser.add<BooleanOption>('s', "sysinfo" , "show system info");
BooleanOption & argClear = parser.add<BooleanOption>('x', "clear" , "Clear data for the priority channel provided by the -p option"); BooleanOption & argClear = parser.add<BooleanOption>('x', "clear" , "Clear data for the priority channel provided by the -p option");
@ -102,12 +106,12 @@ int main(int argc, char * argv[])
Option & argEnableComponent = parser.add<Option> ('E', "enable" , "Enable the Component with the given name. Available Components are [SMOOTHING, BLACKBORDER, FORWARDER, BOBLIGHT_SERVER, GRABBER, V4L, LEDDEVICE]"); Option & argEnableComponent = parser.add<Option> ('E', "enable" , "Enable the Component with the given name. Available Components are [SMOOTHING, BLACKBORDER, FORWARDER, BOBLIGHT_SERVER, GRABBER, V4L, LEDDEVICE]");
Option & argDisableComponent = parser.add<Option> ('D', "disable" , "Disable the Component with the given name. Available Components are [SMOOTHING, BLACKBORDER, FORWARDER, BOBLIGHT_SERVER, GRABBER, V4L, LEDDEVICE]"); Option & argDisableComponent = parser.add<Option> ('D', "disable" , "Disable the Component with the given name. Available Components are [SMOOTHING, BLACKBORDER, FORWARDER, BOBLIGHT_SERVER, GRABBER, V4L, LEDDEVICE]");
Option & argId = parser.add<Option> ('q', "qualifier" , "Identifier(qualifier) of the adjustment to set"); Option & argId = parser.add<Option> ('q', "qualifier" , "Identifier(qualifier) of the adjustment to set");
IntOption & argBrightness = parser.add<IntOption> ('L', "brightness" , "Set the brightness gain of the leds"); IntOption & argBrightness = parser.add<IntOption> ('L', "brightness" , "Set the brightness gain of the LEDs");
IntOption & argBrightnessC = parser.add<IntOption> (0x0, "brightnessCompensation" , "Set the brightness compensation"); IntOption & argBrightnessC = parser.add<IntOption> (0x0, "brightnessCompensation" , "Set the brightness compensation");
IntOption & argBacklightThreshold = parser.add<IntOption> ('n', "backlightThreshold" , "threshold for activating backlight (minimum brightness)"); IntOption & argBacklightThreshold = parser.add<IntOption> ('n', "backlightThreshold" , "threshold for activating backlight (minimum brightness)");
IntOption & argBacklightColored = parser.add<IntOption> (0x0, "backlightColored" , "0 = white backlight; 1 = colored backlight"); IntOption & argBacklightColored = parser.add<IntOption> (0x0, "backlightColored" , "0 = white backlight; 1 = colored backlight");
DoubleOption & argGamma = parser.add<DoubleOption> ('g', "gamma" , "Set the overall gamma of the leds"); DoubleOption & argGamma = parser.add<DoubleOption> ('g', "gamma" , "Set the overall gamma of the LEDs");
BooleanOption & argPrint = parser.add<BooleanOption>(0x0, "print" , "Print the json input and output messages on stdout"); BooleanOption & argPrint = parser.add<BooleanOption>(0x0, "print" , "Print the JSON input and output messages on stdout");
BooleanOption & argHelp = parser.add<BooleanOption>('h', "help" , "Show this help message and exit"); BooleanOption & argHelp = parser.add<BooleanOption>('h', "help" , "Show this help message and exit");
ColorOption & argRAdjust = parser.add<ColorOption> ('R', "redAdjustment" , "Set the adjustment of the red color (requires colors in hex format as RRGGBB)"); ColorOption & argRAdjust = parser.add<ColorOption> ('R', "redAdjustment" , "Set the adjustment of the red color (requires colors in hex format as RRGGBB)");
ColorOption & argGAdjust = parser.add<ColorOption> ('G', "greenAdjustment" , "Set the adjustment of the green color (requires colors in hex format as RRGGBB)"); ColorOption & argGAdjust = parser.add<ColorOption> ('G', "greenAdjustment" , "Set the adjustment of the green color (requires colors in hex format as RRGGBB)");
@ -117,15 +121,15 @@ int main(int argc, char * argv[])
ColorOption & argYAdjust = parser.add<ColorOption> ('Y', "yellowAdjustment" , "Set the adjustment of the yellow color (requires colors in hex format as RRGGBB)"); ColorOption & argYAdjust = parser.add<ColorOption> ('Y', "yellowAdjustment" , "Set the adjustment of the yellow color (requires colors in hex format as RRGGBB)");
ColorOption & argWAdjust = parser.add<ColorOption> ('W', "whiteAdjustment" , "Set the adjustment of the white color (requires colors in hex format as RRGGBB)"); ColorOption & argWAdjust = parser.add<ColorOption> ('W', "whiteAdjustment" , "Set the adjustment of the white color (requires colors in hex format as RRGGBB)");
ColorOption & argbAdjust = parser.add<ColorOption> ('b', "blackAdjustment" , "Set the adjustment of the black color (requires colors in hex format as RRGGBB)"); ColorOption & argbAdjust = parser.add<ColorOption> ('b', "blackAdjustment" , "Set the adjustment of the black color (requires colors in hex format as RRGGBB)");
Option & argMapping = parser.add<Option> ('m', "ledMapping" , "Set the methode for image to led mapping valid values: multicolor_mean, unicolor_mean"); Option & argMapping = parser.add<Option> ('m', "ledMapping" , "Set the method for image to led mapping valid values: multi color_mean, uni-color_mean");
Option & argVideoMode = parser.add<Option> ('V', "videoMode" , "Set the video mode valid values: 2D, 3DSBS, 3DTAB"); Option & argVideoMode = parser.add<Option> ('V', "videoMode" , "Set the video mode valid values: 2D, 3DSBS, 3DTAB");
IntOption & argSource = parser.add<IntOption> (0x0, "sourceSelect" , "Set current active priority channel and deactivate auto source switching"); IntOption & argSource = parser.add<IntOption> (0x0, "sourceSelect" , "Set current active priority channel and deactivate auto source switching");
BooleanOption & argSourceAuto = parser.add<BooleanOption>(0x0, "sourceAutoSelect" , "Enables auto source, if disabled prio by manual selecting input source"); BooleanOption & argSourceAuto = parser.add<BooleanOption>(0x0, "sourceAutoSelect" , "Enables auto source, if disabled prio by manual selecting input source");
BooleanOption & argOff = parser.add<BooleanOption>(0x0, "off" , "Deactivates hyperion"); BooleanOption & argOff = parser.add<BooleanOption>(0x0, "off" , "Deactivates hyperion");
BooleanOption & argOn = parser.add<BooleanOption>(0x0, "on" , "Activates hyperion"); BooleanOption & argOn = parser.add<BooleanOption>(0x0, "on" , "Activates hyperion");
BooleanOption & argConfigGet = parser.add<BooleanOption>(0x0, "configGet" , "Print the current loaded Hyperion configuration file"); BooleanOption & argConfigGet = parser.add<BooleanOption>(0x0, "configGet" , "Print the current loaded Hyperion configuration file");
BooleanOption & argSchemaGet = parser.add<BooleanOption>(0x0, "schemaGet" , "Print the json schema for Hyperion configuration"); BooleanOption & argSchemaGet = parser.add<BooleanOption>(0x0, "schemaGet" , "Print the JSON schema for Hyperion configuration");
Option & argConfigSet = parser.add<Option> (0x0, "configSet" , "Write to the actual loaded configuration file. Should be a Json object string."); Option & argConfigSet = parser.add<Option> (0x0, "configSet" , "Write to the actual loaded configuration file. Should be a JSON object string.");
// parse all _options // parse all _options
parser.process(app); parser.process(app);
@ -197,7 +201,9 @@ int main(int argc, char * argv[])
// authorization token specified. Use it first // authorization token specified. Use it first
if (parser.isSet(argToken)) if (parser.isSet(argToken))
{
connection.setToken(argToken.value(parser)); connection.setToken(argToken.value(parser));
}
// If a specific Hyperion instance is given, set it // If a specific Hyperion instance is given, set it
if (parser.isSet(argInstance)) if (parser.isSet(argInstance))
@ -316,7 +322,7 @@ int main(int argc, char * argv[])
} }
catch (const std::runtime_error & e) catch (const std::runtime_error & e)
{ {
// An error occured. Display error and quit // An error occurred. Display error and quit
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
return 1; return 1;
} }

View File

@ -61,30 +61,30 @@
HyperionDaemon *HyperionDaemon::daemon = nullptr; HyperionDaemon *HyperionDaemon::daemon = nullptr;
HyperionDaemon::HyperionDaemon(const QString rootPath, QObject *parent, bool logLvlOverwrite, bool readonlyMode) HyperionDaemon::HyperionDaemon(const QString& rootPath, QObject* parent, bool logLvlOverwrite, bool readonlyMode)
: QObject(parent), _log(Logger::getInstance("DAEMON")) : QObject(parent), _log(Logger::getInstance("DAEMON"))
, _instanceManager(new HyperionIManager(rootPath, this, readonlyMode)) , _instanceManager(new HyperionIManager(rootPath, this, readonlyMode))
, _authManager(new AuthManager(this, readonlyMode)) , _authManager(new AuthManager(this, readonlyMode))
#ifdef ENABLE_AVAHI #ifdef ENABLE_AVAHI
, _bonjourBrowserWrapper(new BonjourBrowserWrapper()) , _bonjourBrowserWrapper(new BonjourBrowserWrapper())
#endif #endif
, _netOrigin(new NetOrigin(this)) , _netOrigin(new NetOrigin(this))
, _pyInit(new PythonInit()) , _pyInit(new PythonInit())
, _webserver(nullptr) , _webserver(nullptr)
, _sslWebserver(nullptr) , _sslWebserver(nullptr)
, _jsonServer(nullptr) , _jsonServer(nullptr)
, _v4l2Grabber(nullptr) , _v4l2Grabber(nullptr)
, _dispmanx(nullptr) , _dispmanx(nullptr)
, _x11Grabber(nullptr) , _x11Grabber(nullptr)
, _xcbGrabber(nullptr) , _xcbGrabber(nullptr)
, _amlGrabber(nullptr) , _amlGrabber(nullptr)
, _fbGrabber(nullptr) , _fbGrabber(nullptr)
, _osxGrabber(nullptr) , _osxGrabber(nullptr)
, _qtGrabber(nullptr) , _qtGrabber(nullptr)
, _dxGrabber(nullptr) , _dxGrabber(nullptr)
, _ssdp(nullptr) , _ssdp(nullptr)
, _cecHandler(nullptr) , _cecHandler(nullptr)
, _currVideoMode(VideoMode::VIDEO_2D) , _currVideoMode(VideoMode::VIDEO_2D)
{ {
HyperionDaemon::daemon = this; HyperionDaemon::daemon = this;
@ -101,12 +101,14 @@ HyperionDaemon::HyperionDaemon(const QString rootPath, QObject *parent, bool log
// set inital log lvl if the loglvl wasn't overwritten by arg // set inital log lvl if the loglvl wasn't overwritten by arg
if (!logLvlOverwrite) if (!logLvlOverwrite)
{
handleSettingsUpdate(settings::LOGGER, getSetting(settings::LOGGER)); handleSettingsUpdate(settings::LOGGER, getSetting(settings::LOGGER));
}
createCecHandler(); createCecHandler();
// init EffectFileHandler // init EffectFileHandler
EffectFileHandler *efh = new EffectFileHandler(rootPath, getSetting(settings::EFFECTS), this); EffectFileHandler* efh = new EffectFileHandler(rootPath, getSetting(settings::EFFECTS), this);
connect(this, &HyperionDaemon::settingsChanged, efh, &EffectFileHandler::handleSettingsUpdate); connect(this, &HyperionDaemon::settingsChanged, efh, &EffectFileHandler::handleSettingsUpdate);
// connect and apply settings for AuthManager // connect and apply settings for AuthManager
@ -135,7 +137,7 @@ HyperionDaemon::HyperionDaemon(const QString rootPath, QObject *parent, bool log
// return videoMode changes from Daemon to HyperionIManager // return videoMode changes from Daemon to HyperionIManager
connect(this, &HyperionDaemon::videoMode, _instanceManager, &HyperionIManager::newVideoMode); connect(this, &HyperionDaemon::videoMode, _instanceManager, &HyperionIManager::newVideoMode);
// ---- grabber ----- // ---- grabber -----
#if !defined(ENABLE_DISPMANX) && !defined(ENABLE_OSX) && !defined(ENABLE_FB) && !defined(ENABLE_X11) && !defined(ENABLE_XCB) && !defined(ENABLE_AMLOGIC) && !defined(ENABLE_QT) && !defined(ENABLE_DX) #if !defined(ENABLE_DISPMANX) && !defined(ENABLE_OSX) && !defined(ENABLE_FB) && !defined(ENABLE_X11) && !defined(ENABLE_XCB) && !defined(ENABLE_AMLOGIC) && !defined(ENABLE_QT) && !defined(ENABLE_DX)
Info(_log, "No platform capture supported on this platform"); Info(_log, "No platform capture supported on this platform");
#endif #endif
@ -178,7 +180,7 @@ void HyperionDaemon::freeObjects()
delete _jsonServer; delete _jsonServer;
_jsonServer = nullptr; _jsonServer = nullptr;
if (_flatBufferServer) if (_flatBufferServer != nullptr)
{ {
auto flatBufferServerThread = _flatBufferServer->thread(); auto flatBufferServerThread = _flatBufferServer->thread();
flatBufferServerThread->quit(); flatBufferServerThread->quit();
@ -187,7 +189,7 @@ void HyperionDaemon::freeObjects()
_flatBufferServer = nullptr; _flatBufferServer = nullptr;
} }
if (_protoServer) if (_protoServer != nullptr)
{ {
auto protoServerThread = _protoServer->thread(); auto protoServerThread = _protoServer->thread();
protoServerThread->quit(); protoServerThread->quit();
@ -197,7 +199,7 @@ void HyperionDaemon::freeObjects()
} }
//ssdp before webserver //ssdp before webserver
if (_ssdp) if (_ssdp != nullptr)
{ {
auto ssdpThread = _ssdp->thread(); auto ssdpThread = _ssdp->thread();
ssdpThread->quit(); ssdpThread->quit();
@ -206,18 +208,18 @@ void HyperionDaemon::freeObjects()
_ssdp = nullptr; _ssdp = nullptr;
} }
if(_webserver) if (_webserver != nullptr)
{ {
auto webserverThread =_webserver->thread(); auto webserverThread = _webserver->thread();
webserverThread->quit(); webserverThread->quit();
webserverThread->wait(); webserverThread->wait();
delete webserverThread; delete webserverThread;
_webserver = nullptr; _webserver = nullptr;
} }
if (_sslWebserver) if (_sslWebserver != nullptr)
{ {
auto sslWebserverThread =_sslWebserver->thread(); auto sslWebserverThread = _sslWebserver->thread();
sslWebserverThread->quit(); sslWebserverThread->quit();
sslWebserverThread->wait(); sslWebserverThread->wait();
delete sslWebserverThread; delete sslWebserverThread;
@ -225,7 +227,7 @@ void HyperionDaemon::freeObjects()
} }
#ifdef ENABLE_CEC #ifdef ENABLE_CEC
if (_cecHandler) if (_cecHandler != nullptr)
{ {
auto cecHandlerThread = _cecHandler->thread(); auto cecHandlerThread = _cecHandler->thread();
cecHandlerThread->quit(); cecHandlerThread->quit();
@ -239,7 +241,11 @@ void HyperionDaemon::freeObjects()
// stop Hyperions (non blocking) // stop Hyperions (non blocking)
_instanceManager->stopAll(); _instanceManager->stopAll();
#ifdef ENABLE_AVAHI
delete _bonjourBrowserWrapper; delete _bonjourBrowserWrapper;
_bonjourBrowserWrapper = nullptr;
#endif
delete _amlGrabber; delete _amlGrabber;
delete _dispmanx; delete _dispmanx;
delete _fbGrabber; delete _fbGrabber;
@ -249,7 +255,7 @@ void HyperionDaemon::freeObjects()
delete _v4l2Grabber; delete _v4l2Grabber;
_v4l2Grabber = nullptr; _v4l2Grabber = nullptr;
_bonjourBrowserWrapper = nullptr;
_amlGrabber = nullptr; _amlGrabber = nullptr;
_dispmanx = nullptr; _dispmanx = nullptr;
_fbGrabber = nullptr; _fbGrabber = nullptr;
@ -266,7 +272,7 @@ void HyperionDaemon::startNetworkServices()
// Create FlatBuffer server in thread // Create FlatBuffer server in thread
_flatBufferServer = new FlatBufferServer(getSetting(settings::FLATBUFSERVER)); _flatBufferServer = new FlatBufferServer(getSetting(settings::FLATBUFSERVER));
QThread *fbThread = new QThread(this); QThread* fbThread = new QThread(this);
fbThread->setObjectName("FlatBufferServerThread"); fbThread->setObjectName("FlatBufferServerThread");
_flatBufferServer->moveToThread(fbThread); _flatBufferServer->moveToThread(fbThread);
connect(fbThread, &QThread::started, _flatBufferServer, &FlatBufferServer::initServer); connect(fbThread, &QThread::started, _flatBufferServer, &FlatBufferServer::initServer);
@ -276,7 +282,7 @@ void HyperionDaemon::startNetworkServices()
// Create Proto server in thread // Create Proto server in thread
_protoServer = new ProtoServer(getSetting(settings::PROTOSERVER)); _protoServer = new ProtoServer(getSetting(settings::PROTOSERVER));
QThread *pThread = new QThread(this); QThread* pThread = new QThread(this);
pThread->setObjectName("ProtoServerThread"); pThread->setObjectName("ProtoServerThread");
_protoServer->moveToThread(pThread); _protoServer->moveToThread(pThread);
connect(pThread, &QThread::started, _protoServer, &ProtoServer::initServer); connect(pThread, &QThread::started, _protoServer, &ProtoServer::initServer);
@ -286,7 +292,7 @@ void HyperionDaemon::startNetworkServices()
// Create Webserver in thread // Create Webserver in thread
_webserver = new WebServer(getSetting(settings::WEBSERVER), false); _webserver = new WebServer(getSetting(settings::WEBSERVER), false);
QThread *wsThread = new QThread(this); QThread* wsThread = new QThread(this);
wsThread->setObjectName("WebServerThread"); wsThread->setObjectName("WebServerThread");
_webserver->moveToThread(wsThread); _webserver->moveToThread(wsThread);
connect(wsThread, &QThread::started, _webserver, &WebServer::initServer); connect(wsThread, &QThread::started, _webserver, &WebServer::initServer);
@ -296,7 +302,7 @@ void HyperionDaemon::startNetworkServices()
// Create SSL Webserver in thread // Create SSL Webserver in thread
_sslWebserver = new WebServer(getSetting(settings::WEBSERVER), true); _sslWebserver = new WebServer(getSetting(settings::WEBSERVER), true);
QThread *sslWsThread = new QThread(this); QThread* sslWsThread = new QThread(this);
sslWsThread->setObjectName("SSLWebServerThread"); sslWsThread->setObjectName("SSLWebServerThread");
_sslWebserver->moveToThread(sslWsThread); _sslWebserver->moveToThread(sslWsThread);
connect(sslWsThread, &QThread::started, _sslWebserver, &WebServer::initServer); connect(sslWsThread, &QThread::started, _sslWebserver, &WebServer::initServer);
@ -306,12 +312,12 @@ void HyperionDaemon::startNetworkServices()
// Create SSDP server in thread // Create SSDP server in thread
_ssdp = new SSDPHandler(_webserver, _ssdp = new SSDPHandler(_webserver,
getSetting(settings::FLATBUFSERVER).object()["port"].toInt(), getSetting(settings::FLATBUFSERVER).object()["port"].toInt(),
getSetting(settings::PROTOSERVER).object()["port"].toInt(), getSetting(settings::PROTOSERVER).object()["port"].toInt(),
getSetting(settings::JSONSERVER).object()["port"].toInt(), getSetting(settings::JSONSERVER).object()["port"].toInt(),
getSetting(settings::WEBSERVER).object()["sslPort"].toInt(), getSetting(settings::WEBSERVER).object()["sslPort"].toInt(),
getSetting(settings::GENERAL).object()["name"].toString()); getSetting(settings::GENERAL).object()["name"].toString());
QThread *ssdpThread = new QThread(this); QThread* ssdpThread = new QThread(this);
ssdpThread->setObjectName("SSDPThread"); ssdpThread->setObjectName("SSDPThread");
_ssdp->moveToThread(ssdpThread); _ssdp->moveToThread(ssdpThread);
connect(ssdpThread, &QThread::started, _ssdp, &SSDPHandler::initServer); connect(ssdpThread, &QThread::started, _ssdp, &SSDPHandler::initServer);
@ -321,26 +327,34 @@ void HyperionDaemon::startNetworkServices()
ssdpThread->start(); ssdpThread->start();
} }
void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJsonDocument &config) void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJsonDocument& config)
{ {
if (settingsType == settings::LOGGER) if (settingsType == settings::LOGGER)
{ {
const QJsonObject &logConfig = config.object(); const QJsonObject& logConfig = config.object();
std::string level = logConfig["level"].toString("warn").toStdString(); // silent warn verbose debug std::string level = logConfig["level"].toString("warn").toStdString(); // silent warn verbose debug
if (level == "silent") if (level == "silent")
{
Logger::setLogLevel(Logger::OFF); Logger::setLogLevel(Logger::OFF);
}
else if (level == "warn") else if (level == "warn")
{
Logger::setLogLevel(Logger::LogLevel::WARNING); Logger::setLogLevel(Logger::LogLevel::WARNING);
}
else if (level == "verbose") else if (level == "verbose")
{
Logger::setLogLevel(Logger::INFO); Logger::setLogLevel(Logger::INFO);
}
else if (level == "debug") else if (level == "debug")
{
Logger::setLogLevel(Logger::DEBUG); Logger::setLogLevel(Logger::DEBUG);
}
} }
if (settingsType == settings::SYSTEMCAPTURE) if (settingsType == settings::SYSTEMCAPTURE)
{ {
const QJsonObject &grabberConfig = config.object(); const QJsonObject& grabberConfig = config.object();
_grabber_width = grabberConfig["width"].toInt(96); _grabber_width = grabberConfig["width"].toInt(96);
_grabber_height = grabberConfig["height"].toInt(96); _grabber_height = grabberConfig["height"].toInt(96);
@ -354,11 +368,11 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
_grabber_ge2d_mode = grabberConfig["ge2d_mode"].toInt(0); _grabber_ge2d_mode = grabberConfig["ge2d_mode"].toInt(0);
_grabber_device = grabberConfig["amlogic_grabber"].toString("amvideocap0"); _grabber_device = grabberConfig["amlogic_grabber"].toString("amvideocap0");
#ifdef ENABLE_OSX #ifdef ENABLE_OSX
QString type = "osx"; QString type = "osx";
#else #else
QString type = grabberConfig["type"].toString("auto"); QString type = grabberConfig["type"].toString("auto");
#endif #endif
// auto eval of type // auto eval of type
if (type == "auto") if (type == "auto")
@ -369,33 +383,36 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
type = "dispmanx"; type = "dispmanx";
} }
// amlogic -> /dev/amvideo exists // amlogic -> /dev/amvideo exists
else if (QFile::exists("/dev/amvideo"))
{
type = "amlogic";
if (!QFile::exists("/dev/" + _grabber_device))
{
Error(_log, "grabber device '%s' for type amlogic not found!", QSTRING_CSTR(_grabber_device));
}
}
else else
{ {
// x11 -> if DISPLAY is set if (QFile::exists("/dev/amvideo"))
QByteArray envDisplay = qgetenv("DISPLAY");
if ( !envDisplay.isEmpty() )
{ {
#if defined(ENABLE_X11) type = "amlogic";
type = "x11";
#elif defined(ENABLE_XCB) if (!QFile::exists("/dev/" + _grabber_device))
type = "xcb"; {
#else Error(_log, "grabber device '%s' for type amlogic not found!", QSTRING_CSTR(_grabber_device));
type = "qt"; }
#endif
} }
// qt -> if nothing other applies
else else
{ {
type = "qt"; // x11 -> if DISPLAY is set
QByteArray envDisplay = qgetenv("DISPLAY");
if (!envDisplay.isEmpty())
{
#if defined(ENABLE_X11)
type = "x11";
#elif defined(ENABLE_XCB)
type = "xcb";
#else
type = "qt";
#endif
}
// qt -> if nothing other applies
else
{
type = "qt";
}
} }
} }
} }
@ -406,7 +423,7 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
// stop all capture interfaces // stop all capture interfaces
#ifdef ENABLE_FB #ifdef ENABLE_FB
if(_fbGrabber != nullptr) if (_fbGrabber != nullptr)
{ {
_fbGrabber->stop(); _fbGrabber->stop();
delete _fbGrabber; delete _fbGrabber;
@ -414,7 +431,7 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
} }
#endif #endif
#ifdef ENABLE_DISPMANX #ifdef ENABLE_DISPMANX
if(_dispmanx != nullptr) if (_dispmanx != nullptr)
{ {
_dispmanx->stop(); _dispmanx->stop();
delete _dispmanx; delete _dispmanx;
@ -422,7 +439,7 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
} }
#endif #endif
#ifdef ENABLE_AMLOGIC #ifdef ENABLE_AMLOGIC
if(_amlGrabber != nullptr) if (_amlGrabber != nullptr)
{ {
_amlGrabber->stop(); _amlGrabber->stop();
delete _amlGrabber; delete _amlGrabber;
@ -430,7 +447,7 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
} }
#endif #endif
#ifdef ENABLE_OSX #ifdef ENABLE_OSX
if(_osxGrabber != nullptr) if (_osxGrabber != nullptr)
{ {
_osxGrabber->stop(); _osxGrabber->stop();
delete _osxGrabber; delete _osxGrabber;
@ -438,23 +455,23 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
} }
#endif #endif
#ifdef ENABLE_X11 #ifdef ENABLE_X11
if(_x11Grabber != nullptr) if (_x11Grabber != nullptr)
{ {
_x11Grabber->stop(); _x11Grabber->stop();
delete _x11Grabber; delete _x11Grabber;
_x11Grabber = nullptr; _x11Grabber = nullptr;
} }
#endif #endif
#ifdef ENABLE_XCB #ifdef ENABLE_XCB
if(_xcbGrabber != nullptr) if (_xcbGrabber != nullptr)
{ {
_xcbGrabber->stop(); _xcbGrabber->stop();
delete _xcbGrabber; delete _xcbGrabber;
_xcbGrabber = nullptr; _xcbGrabber = nullptr;
} }
#endif #endif
#ifdef ENABLE_QT #ifdef ENABLE_QT
if(_qtGrabber != nullptr) if (_qtGrabber != nullptr)
{ {
_qtGrabber->stop(); _qtGrabber->stop();
delete _qtGrabber; delete _qtGrabber;
@ -462,7 +479,7 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
} }
#endif #endif
#ifdef ENABLE_DX #ifdef ENABLE_DX
if(_dxGrabber != nullptr) if (_dxGrabber != nullptr)
{ {
_dxGrabber->stop(); _dxGrabber->stop();
delete _dxGrabber; delete _dxGrabber;
@ -474,7 +491,9 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
if (type == "framebuffer") if (type == "framebuffer")
{ {
if (_fbGrabber == nullptr) if (_fbGrabber == nullptr)
{
createGrabberFramebuffer(grabberConfig); createGrabberFramebuffer(grabberConfig);
}
#ifdef ENABLE_FB #ifdef ENABLE_FB
_fbGrabber->tryStart(); _fbGrabber->tryStart();
#endif #endif
@ -482,7 +501,9 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
else if (type == "dispmanx") else if (type == "dispmanx")
{ {
if (_dispmanx == nullptr) if (_dispmanx == nullptr)
{
createGrabberDispmanx(); createGrabberDispmanx();
}
#ifdef ENABLE_DISPMANX #ifdef ENABLE_DISPMANX
_dispmanx->tryStart(); _dispmanx->tryStart();
#endif #endif
@ -490,7 +511,9 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
else if (type == "amlogic") else if (type == "amlogic")
{ {
if (_amlGrabber == nullptr) if (_amlGrabber == nullptr)
{
createGrabberAmlogic(); createGrabberAmlogic();
}
#ifdef ENABLE_AMLOGIC #ifdef ENABLE_AMLOGIC
_amlGrabber->tryStart(); _amlGrabber->tryStart();
#endif #endif
@ -498,7 +521,9 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
else if (type == "osx") else if (type == "osx")
{ {
if (_osxGrabber == nullptr) if (_osxGrabber == nullptr)
{
createGrabberOsx(grabberConfig); createGrabberOsx(grabberConfig);
}
#ifdef ENABLE_OSX #ifdef ENABLE_OSX
_osxGrabber->tryStart(); _osxGrabber->tryStart();
#endif #endif
@ -506,7 +531,9 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
else if (type == "x11") else if (type == "x11")
{ {
if (_x11Grabber == nullptr) if (_x11Grabber == nullptr)
{
createGrabberX11(grabberConfig); createGrabberX11(grabberConfig);
}
#ifdef ENABLE_X11 #ifdef ENABLE_X11
_x11Grabber->tryStart(); _x11Grabber->tryStart();
#endif #endif
@ -514,7 +541,9 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
else if (type == "xcb") else if (type == "xcb")
{ {
if (_xcbGrabber == nullptr) if (_xcbGrabber == nullptr)
{
createGrabberXcb(grabberConfig); createGrabberXcb(grabberConfig);
}
#ifdef ENABLE_XCB #ifdef ENABLE_XCB
_xcbGrabber->tryStart(); _xcbGrabber->tryStart();
#endif #endif
@ -522,7 +551,9 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
else if (type == "qt") else if (type == "qt")
{ {
if (_qtGrabber == nullptr) if (_qtGrabber == nullptr)
{
createGrabberQt(grabberConfig); createGrabberQt(grabberConfig);
}
#ifdef ENABLE_QT #ifdef ENABLE_QT
_qtGrabber->tryStart(); _qtGrabber->tryStart();
#endif #endif
@ -530,7 +561,9 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
else if (type == "dx") else if (type == "dx")
{ {
if (_dxGrabber == nullptr) if (_dxGrabber == nullptr)
{
createGrabberDx(grabberConfig); createGrabberDx(grabberConfig);
}
#ifdef ENABLE_DX #ifdef ENABLE_DX
_dxGrabber->tryStart(); _dxGrabber->tryStart();
#endif #endif
@ -545,10 +578,13 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
} }
else if (settingsType == settings::V4L2) else if (settingsType == settings::V4L2)
{ {
const QJsonObject &grabberConfig = config.object();
#if defined(ENABLE_CEC) || defined(ENABLE_V4L2)
const QJsonObject& grabberConfig = config.object();
#endif
#ifdef ENABLE_CEC #ifdef ENABLE_CEC
QString operation; if (_cecHandler != nullptr && grabberConfig["cecDetection"].toBool(false))
if (_cecHandler && grabberConfig["cecDetection"].toBool(false))
{ {
QMetaObject::invokeMethod(_cecHandler, "start", Qt::QueuedConnection); QMetaObject::invokeMethod(_cecHandler, "start", Qt::QueuedConnection);
} }
@ -559,36 +595,38 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
#endif #endif
if (_v4l2Grabber != nullptr) if (_v4l2Grabber != nullptr)
{
return; return;
}
#ifdef ENABLE_V4L2 #ifdef ENABLE_V4L2
_v4l2Grabber = new V4L2Wrapper( _v4l2Grabber = new V4L2Wrapper(
grabberConfig["device"].toString("auto"), grabberConfig["device"].toString("auto"),
grabberConfig["width"].toInt(0), grabberConfig["width"].toInt(0),
grabberConfig["height"].toInt(0), grabberConfig["height"].toInt(0),
grabberConfig["fps"].toInt(15), grabberConfig["fps"].toInt(15),
grabberConfig["input"].toInt(-1), grabberConfig["input"].toInt(-1),
parseVideoStandard(grabberConfig["standard"].toString("no-change")), parseVideoStandard(grabberConfig["standard"].toString("no-change")),
parsePixelFormat(grabberConfig["pixelFormat"].toString("no-change")), parsePixelFormat(grabberConfig["pixelFormat"].toString("no-change")),
grabberConfig["sizeDecimation"].toInt(8)); grabberConfig["sizeDecimation"].toInt(8));
_v4l2Grabber->setSignalThreshold( _v4l2Grabber->setSignalThreshold(
grabberConfig["redSignalThreshold"].toDouble(0.0) / 100.0, grabberConfig["redSignalThreshold"].toDouble(0.0) / 100.0,
grabberConfig["greenSignalThreshold"].toDouble(0.0) / 100.0, grabberConfig["greenSignalThreshold"].toDouble(0.0) / 100.0,
grabberConfig["blueSignalThreshold"].toDouble(0.0) / 100.0); grabberConfig["blueSignalThreshold"].toDouble(0.0) / 100.0);
_v4l2Grabber->setCropping( _v4l2Grabber->setCropping(
grabberConfig["cropLeft"].toInt(0), grabberConfig["cropLeft"].toInt(0),
grabberConfig["cropRight"].toInt(0), grabberConfig["cropRight"].toInt(0),
grabberConfig["cropTop"].toInt(0), grabberConfig["cropTop"].toInt(0),
grabberConfig["cropBottom"].toInt(0)); grabberConfig["cropBottom"].toInt(0));
_v4l2Grabber->setCecDetectionEnable(grabberConfig["cecDetection"].toBool(true)); _v4l2Grabber->setCecDetectionEnable(grabberConfig["cecDetection"].toBool(true));
_v4l2Grabber->setSignalDetectionEnable(grabberConfig["signalDetection"].toBool(true)); _v4l2Grabber->setSignalDetectionEnable(grabberConfig["signalDetection"].toBool(true));
_v4l2Grabber->setSignalDetectionOffset( _v4l2Grabber->setSignalDetectionOffset(
grabberConfig["sDHOffsetMin"].toDouble(0.25), grabberConfig["sDHOffsetMin"].toDouble(0.25),
grabberConfig["sDVOffsetMin"].toDouble(0.25), grabberConfig["sDVOffsetMin"].toDouble(0.25),
grabberConfig["sDHOffsetMax"].toDouble(0.75), grabberConfig["sDHOffsetMax"].toDouble(0.75),
grabberConfig["sDVOffsetMax"].toDouble(0.75)); grabberConfig["sDVOffsetMax"].toDouble(0.75));
Debug(_log, "V4L2 grabber created"); Debug(_log, "V4L2 grabber created");
// connect to HyperionDaemon signal // connect to HyperionDaemon signal
@ -632,13 +670,13 @@ void HyperionDaemon::createGrabberAmlogic()
#endif #endif
} }
void HyperionDaemon::createGrabberX11(const QJsonObject &grabberConfig) void HyperionDaemon::createGrabberX11(const QJsonObject& grabberConfig)
{ {
#ifdef ENABLE_X11 #ifdef ENABLE_X11
_x11Grabber = new X11Wrapper( _x11Grabber = new X11Wrapper(
_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom, _grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom,
grabberConfig["pixelDecimation"].toInt(8), grabberConfig["pixelDecimation"].toInt(8),
_grabber_frequency); _grabber_frequency);
_x11Grabber->setCropping(_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom); _x11Grabber->setCropping(_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom);
// connect to HyperionDaemon signal // connect to HyperionDaemon signal
@ -651,13 +689,13 @@ void HyperionDaemon::createGrabberX11(const QJsonObject &grabberConfig)
#endif #endif
} }
void HyperionDaemon::createGrabberXcb(const QJsonObject &grabberConfig) void HyperionDaemon::createGrabberXcb(const QJsonObject& grabberConfig)
{ {
#ifdef ENABLE_XCB #ifdef ENABLE_XCB
_xcbGrabber = new XcbWrapper( _xcbGrabber = new XcbWrapper(
_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom, _grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom,
grabberConfig["pixelDecimation"].toInt(8), grabberConfig["pixelDecimation"].toInt(8),
_grabber_frequency); _grabber_frequency);
_xcbGrabber->setCropping(_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom); _xcbGrabber->setCropping(_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom);
// connect to HyperionDaemon signal // connect to HyperionDaemon signal
@ -670,14 +708,14 @@ void HyperionDaemon::createGrabberXcb(const QJsonObject &grabberConfig)
#endif #endif
} }
void HyperionDaemon::createGrabberQt(const QJsonObject &grabberConfig) void HyperionDaemon::createGrabberQt(const QJsonObject& grabberConfig)
{ {
#ifdef ENABLE_QT #ifdef ENABLE_QT
_qtGrabber = new QtWrapper( _qtGrabber = new QtWrapper(
_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom, _grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom,
grabberConfig["pixelDecimation"].toInt(8), grabberConfig["pixelDecimation"].toInt(8),
grabberConfig["display"].toInt(0), grabberConfig["display"].toInt(0),
_grabber_frequency); _grabber_frequency);
// connect to HyperionDaemon signal // connect to HyperionDaemon signal
connect(this, &HyperionDaemon::videoMode, _qtGrabber, &QtWrapper::setVideoMode); connect(this, &HyperionDaemon::videoMode, _qtGrabber, &QtWrapper::setVideoMode);
@ -689,14 +727,14 @@ void HyperionDaemon::createGrabberQt(const QJsonObject &grabberConfig)
#endif #endif
} }
void HyperionDaemon::createGrabberDx(const QJsonObject &grabberConfig) void HyperionDaemon::createGrabberDx(const QJsonObject& grabberConfig)
{ {
#ifdef ENABLE_DX #ifdef ENABLE_DX
_dxGrabber = new DirectXWrapper( _dxGrabber = new DirectXWrapper(
_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom, _grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom,
grabberConfig["pixelDecimation"].toInt(8), grabberConfig["pixelDecimation"].toInt(8),
grabberConfig["display"].toInt(0), grabberConfig["display"].toInt(0),
_grabber_frequency); _grabber_frequency);
// connect to HyperionDaemon signal // connect to HyperionDaemon signal
connect(this, &HyperionDaemon::videoMode, _dxGrabber, &DirectXWrapper::setVideoMode); connect(this, &HyperionDaemon::videoMode, _dxGrabber, &DirectXWrapper::setVideoMode);
@ -708,13 +746,13 @@ void HyperionDaemon::createGrabberDx(const QJsonObject &grabberConfig)
#endif #endif
} }
void HyperionDaemon::createGrabberFramebuffer(const QJsonObject &grabberConfig) void HyperionDaemon::createGrabberFramebuffer(const QJsonObject& grabberConfig)
{ {
#ifdef ENABLE_FB #ifdef ENABLE_FB
// Construct and start the framebuffer grabber if the configuration is present // Construct and start the framebuffer grabber if the configuration is present
_fbGrabber = new FramebufferWrapper( _fbGrabber = new FramebufferWrapper(
grabberConfig["device"].toString("/dev/fb0"), grabberConfig["device"].toString("/dev/fb0"),
_grabber_width, _grabber_height, _grabber_frequency); _grabber_width, _grabber_height, _grabber_frequency);
_fbGrabber->setCropping(_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom); _fbGrabber->setCropping(_grabber_cropLeft, _grabber_cropRight, _grabber_cropTop, _grabber_cropBottom);
// connect to HyperionDaemon signal // connect to HyperionDaemon signal
connect(this, &HyperionDaemon::videoMode, _fbGrabber, &FramebufferWrapper::setVideoMode); connect(this, &HyperionDaemon::videoMode, _fbGrabber, &FramebufferWrapper::setVideoMode);
@ -726,13 +764,13 @@ void HyperionDaemon::createGrabberFramebuffer(const QJsonObject &grabberConfig)
#endif #endif
} }
void HyperionDaemon::createGrabberOsx(const QJsonObject &grabberConfig) void HyperionDaemon::createGrabberOsx(const QJsonObject& grabberConfig)
{ {
#ifdef ENABLE_OSX #ifdef ENABLE_OSX
// Construct and start the osx grabber if the configuration is present // Construct and start the osx grabber if the configuration is present
_osxGrabber = new OsxWrapper( _osxGrabber = new OsxWrapper(
grabberConfig["display"].toInt(0), grabberConfig["display"].toInt(0),
_grabber_width, _grabber_height, _grabber_frequency); _grabber_width, _grabber_height, _grabber_frequency);
// connect to HyperionDaemon signal // connect to HyperionDaemon signal
connect(this, &HyperionDaemon::videoMode, _osxGrabber, &OsxWrapper::setVideoMode); connect(this, &HyperionDaemon::videoMode, _osxGrabber, &OsxWrapper::setVideoMode);
@ -749,14 +787,16 @@ void HyperionDaemon::createCecHandler()
#if defined(ENABLE_V4L2) && defined(ENABLE_CEC) #if defined(ENABLE_V4L2) && defined(ENABLE_CEC)
_cecHandler = new CECHandler; _cecHandler = new CECHandler;
QThread * thread = new QThread(this); QThread* thread = new QThread(this);
thread->setObjectName("CECThread"); thread->setObjectName("CECThread");
_cecHandler->moveToThread(thread); _cecHandler->moveToThread(thread);
thread->start(); thread->start();
connect(_cecHandler, &CECHandler::cecEvent, [&] (CECEvent event) { connect(_cecHandler, &CECHandler::cecEvent, [&](CECEvent event) {
if (_v4l2Grabber) if (_v4l2Grabber != nullptr)
{
_v4l2Grabber->handleCecEvent(event); _v4l2Grabber->handleCecEvent(event);
}
}); });
Info(_log, "CEC handler created"); Info(_log, "CEC handler created");

View File

@ -86,18 +86,18 @@ class HyperionDaemon : public QObject
friend SysTray; friend SysTray;
public: public:
HyperionDaemon(QString rootPath, QObject *parent, bool logLvlOverwrite, bool readonlyMode = false); HyperionDaemon(const QString& rootPath, QObject *parent, bool logLvlOverwrite, bool readonlyMode = false);
~HyperionDaemon(); ~HyperionDaemon();
/// ///
/// @brief Get webserver pointer (systray) /// @brief Get webserver pointer (systray)
/// ///
WebServer* getWebServerInstance() { return _webserver; }; WebServer *getWebServerInstance() { return _webserver; }
/// ///
/// @brief Get the current videoMode /// @brief Get the current videoMode
/// ///
VideoMode getVideoMode() const { return _currVideoMode; }; VideoMode getVideoMode() const { return _currVideoMode; }
/// ///
/// @brief get the settings /// @brief get the settings
@ -106,7 +106,7 @@ public:
void startNetworkServices(); void startNetworkServices();
static HyperionDaemon* getInstance() { return daemon; }; static HyperionDaemon* getInstance() { return daemon; }
static HyperionDaemon* daemon; static HyperionDaemon* daemon;
public slots: public slots:

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
import json, sys, glob import json, sys
from os import path from os import path
from jsonschema import Draft3Validator, RefResolver from jsonschema import Draft3Validator, RefResolver

View File

@ -190,12 +190,13 @@ class Draft3Validator(object):
for type in types: for type in types:
if self.is_type(type, "object"): if self.is_type(type, "object"):
if self.is_valid(instance, type): if self.is_valid(instance, type):
return break
elif self.is_type(type, "string"): elif self.is_type(type, "string"):
if self.is_type(instance, type): if self.is_type(instance, type):
return break
else: else:
yield ValidationError(_types_msg(instance, types)) yield ValidationError(_types_msg(instance, types))
return
def validate_properties(self, properties, instance, schema): def validate_properties(self, properties, instance, schema):
if not self.is_type(instance, "object"): if not self.is_type(instance, "object"):