<|start_filename|>libsrc/ssdp/SSDPDescription.h<|end_filename|>
#pragma once

///
/// The xml to fill with data
/// %1 base url                   http://192.168.0.177:80/
/// %2 friendly name              Hyperion 2.0.0 (192.168.0.177)
/// %3 modelNumber                2.0.0
/// %4 serialNumber / UDN (H ID)  Fjsa723dD0....
///
/// def URN urn:schemas-upnp-org:device:Basic:1

static const QString SSDP_DESCRIPTION =	"<?xml version=\"1.0\"?>"
										"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
											"<specVersion>"
												"<major>1</major>"
												"<minor>0</minor>"
											"</specVersion>"
											"<URLBase>%1</URLBase>"
											"<device>"
												"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>"
												"<friendlyName>%2</friendlyName>"
												"<manufacturer>Hyperion Open Source Ambient Lighting</manufacturer>"
												"<manufacturerURL>https://www.hyperion-project.org</manufacturerURL>"
												"<modelDescription>Hyperion Open Source Ambient Light</modelDescription>"
												"<modelName>Hyperion</modelName>"
												"<modelNumber>%3</modelNumber>"
												"<modelURL>https://www.hyperion-project.org</modelURL>"
												"<serialNumber>%4</serialNumber>"
												"<UDN>uuid:%4</UDN>"
												"<ports>"
													"<jsonServer>%5</jsonServer>"
													"<sslServer>%6</sslServer>"
													"<protoBuffer>%7</protoBuffer>"
													"<flatBuffer>%8</flatBuffer>"
												"</ports>"
												"<presentationURL>index.html</presentationURL>"
												"<iconList>"
													"<icon>"
														"<mimetype>image/png</mimetype>"
														"<height>100</height>"
														"<width>100</width>"
														"<depth>32</depth>"
														"<url>img/hyperion/ssdp_icon.png</url>"
													"</icon>"
												"</iconList>"
											"</device>"
										"</root>";


<|start_filename|>include/utils/Process.h<|end_filename|>
#pragma once

#include <QString>
#include <QByteArray>

namespace Process {

void restartHyperion(bool asNewProcess=false);
QByteArray command_exec(const QString& cmd, const QByteArray& data = {});

}


<|start_filename|>libsrc/utils/ColorBgr.cpp<|end_filename|>
// Local includes
#include <utils/ColorBgr.h>

const ColorBgr ColorBgr::BLACK  = {   0,   0,   0 };
const ColorBgr ColorBgr::RED    = {   0,   0, 255 };
const ColorBgr ColorBgr::GREEN  = {   0, 255,   0 };
const ColorBgr ColorBgr::BLUE   = { 255,   0,   0 };
const ColorBgr ColorBgr::YELLOW = {   0, 255, 255 };
const ColorBgr ColorBgr::WHITE  = { 255, 255, 255 };



<|start_filename|>cmake/FindXCB.cmake<|end_filename|>
#.rst:
# FindXCB
# -------
#
# Try to find XCB.
#
# This is a component-based find module, which makes use of the COMPONENTS and
# OPTIONAL_COMPONENTS arguments to find_module.  The following components are
# available::
#
#   XCB
#   ATOM         AUX          COMPOSITE    CURSOR       DAMAGE
#   DPMS         DRI2         DRI3         EVENT        EWMH
#   GLX          ICCCM        IMAGE        KEYSYMS      PRESENT
#   RANDR        RECORD       RENDER       RENDERUTIL   RES
#   SCREENSAVER  SHAPE        SHM          SYNC         UTIL
#   XEVIE        XF86DRI      XFIXES       XINERAMA     XINPUT
#   XKB          XPRINT       XTEST        XV           XVMC
#
# If no components are specified, this module will act as though all components
# except XINPUT (which is considered unstable) were passed to
# OPTIONAL_COMPONENTS.
#
# This module will define the following variables, independently of the
# components searched for or found:
#
# ``XCB_FOUND``
#     True if (the requestion version of) xcb is available
# ``XCB_VERSION``
#     Found xcb version
# ``XCB_TARGETS``
#     A list of all targets imported by this module (note that there may be more
#     than the components that were requested)
# ``XCB_LIBRARIES``
#     This can be passed to target_link_libraries() instead of the imported
#     targets
# ``XCB_INCLUDE_DIRS``
#     This should be passed to target_include_directories() if the targets are
#     not used for linking
# ``XCB_DEFINITIONS``
#     This should be passed to target_compile_options() if the targets are not
#     used for linking
#
# For each searched-for components, ``XCB_<component>_FOUND`` will be set to
# true if the corresponding xcb library was found, and false otherwise.  If
# ``XCB_<component>_FOUND`` is true, the imported target ``XCB::<component>``
# will be defined.  This module will also attempt to determine
# ``XCB_*_VERSION`` variables for each imported target, although
# ``XCB_VERSION`` should normally be sufficient.
#
# In general we recommend using the imported targets, as they are easier to use
# and provide more control.  Bear in mind, however, that if any target is in the
# link interface of an exported library, it must be made available by the
# package config file.
#
# Since pre-1.0.0.

#=============================================================================
# SPDX-FileCopyrightText: 2011 <NAME> <<EMAIL>>
# SPDX-FileCopyrightText: 2013 <NAME> <<EMAIL>>
# SPDX-FileCopyrightText: 2014-2015 <NAME> <<EMAIL>>
#
# SPDX-License-Identifier: BSD-3-Clause
#=============================================================================

include(${CMAKE_SOURCE_DIR}/cmake/ECMFindModuleHelpers.cmake)

ecm_find_package_version_check(XCB)

# Note that this list needs to be ordered such that any component
# appears after its dependencies
set(XCB_known_components
    XCB
    RENDER
    SHAPE
    XFIXES
    SHM
    ATOM
    AUX
    COMPOSITE
    CURSOR
    DAMAGE
    DPMS
    DRI2
    DRI3
    EVENT
    EWMH
    GLX
    ICCCM
    IMAGE
    KEYSYMS
    PRESENT
    RANDR
    RECORD
    RENDERUTIL
    RES
    SCREENSAVER
    SYNC
    UTIL
    XEVIE
    XF86DRI
    XINERAMA
    XINPUT
    XKB
    XPRINT
    XTEST
    XV
    XVMC
)

# XINPUT is unstable; do not include it by default
set(XCB_default_components ${XCB_known_components})
list(REMOVE_ITEM XCB_default_components "XINPUT")

# default component info: xcb components have fairly predictable
# header files, library names and pkg-config names
foreach(_comp ${XCB_known_components})
    string(TOLOWER "${_comp}" _lc_comp)
    set(XCB_${_comp}_component_deps XCB)
    set(XCB_${_comp}_pkg_config "xcb-${_lc_comp}")
    set(XCB_${_comp}_lib "xcb-${_lc_comp}")
    set(XCB_${_comp}_header "xcb/${_lc_comp}.h")
endforeach()
# exceptions
set(XCB_XCB_component_deps)
set(XCB_COMPOSITE_component_deps XCB XFIXES)
set(XCB_DAMAGE_component_deps XCB XFIXES)
set(XCB_IMAGE_component_deps XCB SHM)
set(XCB_RENDERUTIL_component_deps XCB RENDER)
set(XCB_XFIXES_component_deps XCB RENDER SHAPE)
set(XCB_XVMC_component_deps XCB XV)
set(XCB_XV_component_deps XCB SHM)
set(XCB_XCB_pkg_config "xcb")
set(XCB_XCB_lib "xcb")
set(XCB_ATOM_header "xcb/xcb_atom.h")
set(XCB_ATOM_lib "xcb-util")
set(XCB_AUX_header "xcb/xcb_aux.h")
set(XCB_AUX_lib "xcb-util")
set(XCB_CURSOR_header "xcb/xcb_cursor.h")
set(XCB_EVENT_header "xcb/xcb_event.h")
set(XCB_EVENT_lib "xcb-util")
set(XCB_EWMH_header "xcb/xcb_ewmh.h")
set(XCB_ICCCM_header "xcb/xcb_icccm.h")
set(XCB_IMAGE_header "xcb/xcb_image.h")
set(XCB_KEYSYMS_header "xcb/xcb_keysyms.h")
set(XCB_PIXEL_header "xcb/xcb_pixel.h")
set(XCB_RENDERUTIL_header "xcb/xcb_renderutil.h")
set(XCB_RENDERUTIL_lib "xcb-render-util")
set(XCB_UTIL_header "xcb/xcb_util.h")

ecm_find_package_parse_components(XCB
    RESULT_VAR XCB_components
    KNOWN_COMPONENTS ${XCB_known_components}
    DEFAULT_COMPONENTS ${XCB_default_components}
)

list(FIND XCB_components "XINPUT" _XCB_XINPUT_index)
if (NOT _XCB_XINPUT_index EQUAL -1)
    message(AUTHOR_WARNING "XINPUT from XCB was requested: this is EXPERIMENTAL and is likely to unavailable on many systems!")
endif()

ecm_find_package_handle_library_components(XCB
    COMPONENTS ${XCB_components}
)

find_package_handle_standard_args(XCB
    FOUND_VAR
        XCB_FOUND
    REQUIRED_VARS
        XCB_LIBRARIES
    VERSION_VAR
        XCB_VERSION
    HANDLE_COMPONENTS
)

include(FeatureSummary)
set_package_properties(XCB PROPERTIES
    URL "https://xcb.freedesktop.org/"
    DESCRIPTION "X protocol C-language Binding"
)


<|start_filename|>include/utils/Image.h<|end_filename|>
#pragma once

#include <QSharedDataPointer>

#include <utils/ImageData.h>

template <typename Pixel_T>
class Image
{
public:
	typedef Pixel_T pixel_type;

	Image() :
		Image(1, 1, Pixel_T())
	{
	}

	Image(unsigned width, unsigned height) :
		Image(width, height, Pixel_T())

	{
	}

	///
	/// Constructor for an image with specified width and height
	///
	/// @param width The width of the image
	/// @param height The height of the image
	/// @param background The color of the image
	///
	Image(unsigned width, unsigned height, const Pixel_T background) :
		_d_ptr(new ImageData<Pixel_T>(width, height, background))
	{
	}

	///
	/// Copy constructor for an image
	/// @param other The image which will be copied
	///
	Image(const Image & other)
	{
		_d_ptr = other._d_ptr;
	}

	Image& operator=(Image rhs)
	{
		// Define assignment operator in terms of the copy constructor
		// More to read: https://stackoverflow.com/questions/255612/dynamically-allocating-an-array-of-objects?answertab=active#tab-top
		_d_ptr = rhs._d_ptr;
		return *this;
	}

	void swap(Image& s)
	{
		std::swap(this->_d_ptr, s._d_ptr);
	}

	Image(Image&& src) noexcept
	{
		std::swap(this->_d_ptr, src._d_ptr);
	}

	Image& operator=(Image&& src) noexcept
	{
		src.swap(*this);
		return *this;
	}

	///
	/// Destructor
	///
	~Image()
	{
	}

	///
	/// Returns the width of the image
	///
	/// @return The width of the image
	///
	inline unsigned width() const
	{
		return _d_ptr->width();
	}

	///
	/// Returns the height of the image
	///
	/// @return The height of the image
	///
	inline unsigned height() const
	{
		return _d_ptr->height();
	}

	uint8_t red(unsigned pixel) const
	{
		return _d_ptr->red(pixel);
	}

	uint8_t green(unsigned pixel) const
	{
		return _d_ptr->green(pixel);
	}

	///
	/// Returns a const reference to a specified pixel in the image
	///
	/// @param x The x index
	/// @param y The y index
	///
	/// @return const reference to specified pixel
	///
	uint8_t blue(unsigned pixel) const
	{
		return _d_ptr->blue(pixel);
	}

	///
	/// Returns a reference to a specified pixel in the image
	///
	/// @param x The x index
	/// @param y The y index
	const Pixel_T& operator()(unsigned x, unsigned y) const
	{
		return _d_ptr->operator()(x, y);
	}

	///
	/// @return reference to specified pixel
	///
	Pixel_T& operator()(unsigned x, unsigned y)
	{
		return _d_ptr->operator()(x, y);
	}

	/// Resize the image
	/// @param width The width of the image
	/// @param height The height of the image
	void resize(unsigned width, unsigned height)
	{
		_d_ptr->resize(width, height);
	}

	///
	/// Returns a memory pointer to the first pixel in the image
	/// @return The memory pointer to the first pixel
	///
	Pixel_T* memptr()
	{
		return _d_ptr->memptr();
	}

	///
	/// Returns a const memory pointer to the first pixel in the image
	/// @return The const memory pointer to the first pixel
	///
	const Pixel_T* memptr() const
	{
		return _d_ptr->memptr();
	}

	///
	/// Convert image of any color order to a RGB image.
	///
	/// @param[out] image  The image that buffers the output
	///
	void toRgb(Image<ColorRgb>& image) const
	{
		_d_ptr->toRgb(*image._d_ptr);
	}

	///
	/// Get size of buffer
	///
	ssize_t size() const
	{
		return _d_ptr->size();
	}

	///
	/// Clear the image
	///
	void clear()
	{
		_d_ptr->clear();
	}

private:
	template<class T>
	friend class Image;

	///
	/// Translate x and y coordinate to index of the underlying vector
	///
	/// @param x The x index
	/// @param y The y index
	///
	/// @return The index into the underlying data-vector
	///
	inline unsigned toIndex(unsigned x, unsigned y) const
	{
		return _d_ptr->toIndex(x, y);
	}

private:
	QSharedDataPointer<ImageData<Pixel_T>>  _d_ptr;
};



<|start_filename|>cmake/FindDirectX9.cmake<|end_filename|>
# Find the DirectX 9 includes and library
# This module defines:
#  DIRECTX9_INCLUDE_DIRS, where to find d3d9.h, etc.
#  DIRECTX9_LIBRARIES, libraries to link against to use DirectX.
#  DIRECTX9_FOUND, If false, do not try to use DirectX.
#  DIRECTX9_ROOT_DIR, directory where DirectX was installed.

set(DIRECTX9_INCLUDE_PATHS
    "$ENV{DXSDK_DIR}/Include"
    "$ENV{DIRECTX_ROOT}/Include"
    "C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include"
    "C:/Program Files/Microsoft DirectX SDK (June 2010)/Include"
)
find_path(DIRECTX9_INCLUDE_DIRS d3dx9.h ${DIRECTX9_INCLUDE_PATHS} NO_DEFAULT_PATH)

get_filename_component(DIRECTX9_ROOT_DIR "${DIRECTX9_INCLUDE_DIRS}/.." ABSOLUTE)

if (CMAKE_SIZEOF_VOID_P EQUAL 8)
    set(DIRECTX9_LIBRARY_PATHS "${DIRECTX9_ROOT_DIR}/Lib/x64")
else ()
    set(DIRECTX9_LIBRARY_PATHS "${DIRECTX9_ROOT_DIR}/Lib/x86" "${DIRECTX9_ROOT_DIR}/Lib")
endif ()

find_library(DIRECTX9_D3D9_LIBRARY d3d9 ${DIRECTX9_LIBRARY_PATHS} NO_DEFAULT_PATH)
find_library(DIRECTX9_D3DX9_LIBRARY d3dx9 ${DIRECTX9_LIBRARY_PATHS} NO_DEFAULT_PATH)
find_library(DIRECTX9_DXERR_LIBRARY DxErr ${DIRECTX9_LIBRARY_PATHS} NO_DEFAULT_PATH)
set(DIRECTX9_LIBRARIES ${DIRECTX9_D3D9_LIBRARY} ${DIRECTX9_D3DX9_LIBRARY} ${DIRECTX9_DXERR_LIBRARY})

# handle the QUIETLY and REQUIRED arguments and set DIRECTX9_FOUND to TRUE if all listed variables are TRUE
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(DirectX9 DEFAULT_MSG DIRECTX9_ROOT_DIR DIRECTX9_LIBRARIES DIRECTX9_INCLUDE_DIRS)
mark_as_advanced(DIRECTX9_INCLUDE_DIRS DIRECTX9_D3D9_LIBRARY DIRECTX9_D3DX9_LIBRARY DIRECTX9_DXERR_LIBRARY)


<|start_filename|>libsrc/leddevice/dev_net/LedDeviceFadeCandy.h<|end_filename|>
#ifndef LEDEVICEFADECANDY_H
#define LEDEVICEFADECANDY_H

// STL/Qt includes
#include <QTcpSocket>
#include <QString>

// LedDevice includes
#include <leddevice/LedDevice.h>

///
/// Implementation of the LedDevice interface for sending to
/// fadecandy/opc-server via network by using the 'open pixel control' protocol.
///
class LedDeviceFadeCandy : public LedDevice
{
	Q_OBJECT

public:
	///
	/// @brief Constructs a LED-device for fadecandy/opc server
	///
	/// Following code shows all configuration options
	/// @code
	/// "device" :
	/// {
	/// 	"name"          : "MyPi",
	/// 	"type"          : "fadecandy",
	/// 	"output"        : "localhost",
	/// 	"colorOrder"    : "rgb",
	/// 	"setFcConfig"   : false,
	/// 	"gamma"         : 1.0,
	/// 	"whitepoint"    : [1.0, 1.0, 1.0],
	/// 	"dither"        : false,
	/// 	"interpolation" : false,
	/// 	"manualLed"     : false,
	/// 	"ledOn"         : false
	/// },
	///@endcode
	///
	/// @param deviceConfig Device's configuration as JSON-Object
	///
	explicit LedDeviceFadeCandy(const QJsonObject& deviceConfig);

	///
	/// @brief Destructor of the LedDevice
	///
	~LedDeviceFadeCandy() override;

	///
	/// @brief Constructs the LED-device
	///
	/// @param[in] deviceConfig Device's configuration as JSON-Object
	/// @return LedDevice constructed
	static LedDevice* construct(const QJsonObject& deviceConfig);

protected:

	///
	/// @brief Initialise the Nanoleaf device's configuration and network address details
	///
	/// @param[in] deviceConfig the JSON device configuration
	/// @return True, if success
	///
	bool init(const QJsonObject& deviceConfig) override;

	///
	/// @brief Opens the output device.
	///
	/// @return Zero on success (i.e. device is ready), else negative
	///
	int open() override;

	///
	/// @brief Closes the output device.
	///
	/// @return Zero on success (i.e. device is closed), else negative
	///
	int close() override;

	///
	/// @brief Writes the RGB-Color values to the LEDs.
	///
	/// @param[in] ledValues The RGB-color per LED
	/// @return Zero on success, else negative
	///
	int write(const std::vector<ColorRgb>& ledValues) override;

private:

	///
	/// @brief Initialise device's network details
	///
	/// @return True if success
	bool initNetwork();

	///
	/// @brief try to establish connection to opc server, if not connected yet
	///
	/// @return True, if connection is established
	///
	bool tryConnect();

	///
	/// @brief Return the connection state
	///
	/// @return True, if connection established
	///
	bool isConnected() const;

	///
	/// @brief Transfer current opc_data buffer to opc server
	///
	/// @return amount of transferred bytes. -1 error while transferring, -2 error while connecting
	///
	qint64 transferData();

	///
	/// @brief Send system exclusive commands
	///
	/// @param[in] systemId fadecandy device identifier (for standard fadecandy always: 1)
	/// @param[in] commandId id of command
	/// @param[in] msg the sysEx message
	/// @return amount bytes written, -1 if failed
	qint64 sendSysEx(uint8_t systemId, uint8_t commandId, const QByteArray& msg);

	///
	/// @brief Sends the configuration to fadecandy cserver
	///
	void sendFadeCandyConfiguration();

	QTcpSocket* _client;
	QString     _host;
	int    _port;
	int    _channel;
	QByteArray  _opc_data;

	// fadecandy sysEx
	bool        _setFcConfig;
	double      _gamma;
	double      _whitePoint_r;
	double      _whitePoint_g;
	double      _whitePoint_b;
	bool        _noDither;
	bool        _noInterp;
	bool        _manualLED;
	bool        _ledOnOff;
};

#endif // LEDEVICEFADECANDY_H


<|start_filename|>libsrc/leddevice/schemas/schema-dmx.json<|end_filename|>
{
	"type":"object",
	"required":true,
	"properties":{
		"dmxtype": {
			"type": "string",
			"title":"edt_dev_spec_ledType_title",
			"enum" : ["raw", "McCrypt"],
			"default" : "raw",
			"options" : {
				"enum_titles" : ["Raw", "McCrypt"]
			},
			"minimum" : 0,
			"maximum" : 1,
			"propertyOrder" : 1
		},
		"output": {
			"type": "string",
			"title":"edt_dev_spec_outputPath_title",
			"default":"ttyUSB0",
			"propertyOrder" : 2
		},
		"rate": {
			"type": "integer",
			"title":"edt_dev_spec_baudrate_title",
			"default": 250000,
			"propertyOrder" : 3
		},
		"delayAfterConnect": {
			"type": "integer",
			"title":"edt_dev_spec_delayAfterConnect_title",
			"default": 250,
			"propertyOrder" : 4
		},
		"latchTime": {
			"type": "integer",
			"title":"edt_dev_spec_latchtime_title",
			"default": 10,
			"append" : "edt_append_ms",
			"minimum": 0,
			"maximum": 1000,
			"access" : "expert",
			"propertyOrder" : 5
		},
		"rewriteTime": {
			"type": "integer",
			"title":"edt_dev_general_rewriteTime_title",
			"default": 1000,
			"append" : "edt_append_ms",
			"minimum": 0,
			"access" : "expert",
			"propertyOrder" : 6
		}		
	},
	"additionalProperties": true
}


<|start_filename|>libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.h<|end_filename|>
#ifndef LEDEVICEHYPERIONUSBASP_H
#define LEDEVICEHYPERIONUSBASP_H

// stl includes
#include <vector>
#include <cstdint>

// libusb include
#include <libusb.h>

// Hyperion includes
#include <leddevice/LedDevice.h>

///
/// LedDevice implementation for a USBasp programmer with modified firmware (https://github.com/poljvd/hyperion-usbasp)
///
class LedDeviceHyperionUsbasp : public LedDevice
{
public:
	// Commands to the Device
	enum Commands {
		CMD_WRITE_WS2801 = 10,
		CMD_WRITE_WS2812 = 11
	};

	///
	/// Constructs specific LedDevice
	///
	/// @param deviceConfig json device config
	///
	explicit LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig);

	///
	/// Sets configuration
	///
	/// @para#endif // LEDEVICETEMPLATE_Hm deviceConfig the json device config
	/// @return true if success
	bool init(const QJsonObject &deviceConfig) override;

	/// constructs leddevice
	static LedDevice* construct(const QJsonObject &deviceConfig);

	///
	/// Destructor of the LedDevice; closes the output device if it is open
	///
	~LedDeviceHyperionUsbasp() override;

public slots:
	///
	/// Closes the output device.
	/// Includes switching-off the device and stopping refreshes
	///
	int close() override;

protected:
	///
	/// Opens and configures the output device
	///
	/// @return Zero on succes else negative
	///
	int open() override;

	///
	/// Writes the RGB-Color values to the leds.
	///
	/// @param[in] ledValues  The RGB-color per led
	///
	/// @return Zero on success else negative
	///
	int write(const std::vector<ColorRgb>& ledValues) override;

	///
	/// Test if the device is a Hyperion Usbasp device
	///
	/// @return Zero on succes else negative
	///
	int testAndOpen(libusb_device * device);

	static libusb_device_handle * openDevice(libusb_device * device);

	static QString getString(libusb_device * device, int stringDescriptorIndex);

	/// command to write the leds
	uint8_t _writeLedsCommand;

	/// libusb context
	libusb_context * _libusbContext;

	/// libusb device
	libusb_device * _device;

	/// libusb device handle
	libusb_device_handle * _deviceHandle;
};

#endif // LEDEVICEHYPERIONUSBASP_H


<|start_filename|>libsrc/utils/ColorRgba.cpp<|end_filename|>
// Utils includes
#include <utils/ColorRgba.h>

const ColorRgba ColorRgba::BLACK  = {   0,   0,   0, 255 };
const ColorRgba ColorRgba::RED    = { 255,   0,   0, 255 };
const ColorRgba ColorRgba::GREEN  = {   0, 255,   0, 255 };
const ColorRgba ColorRgba::BLUE   = {   0,   0, 255, 255 };
const ColorRgba ColorRgba::YELLOW = { 255, 255,   0, 255 };
const ColorRgba ColorRgba::WHITE  = { 255, 255, 255, 255 };


<|start_filename|>test/TestX11Performance.cpp<|end_filename|>

#include <QElapsedTimer>

#include <utils/Image.h>
#include <utils/ColorRgb.h>

// X11 includes
#include <X11/Xlib.h>
#include <X11/Xutil.h>

void foo_1(int pixelDecimation)
{
	int cropWidth  = 0;
	int cropHeight = 0;

	Image<ColorRgb> image(64, 64);

	 /// Reference to the X11 display (nullptr if not opened)
	Display * x11Display;

	const char * display_name = nullptr;
	x11Display = XOpenDisplay(display_name);

	std::cout << "Opened display: " << x11Display << std::endl;

	XWindowAttributes window_attributes_return;
	XGetWindowAttributes(x11Display, DefaultRootWindow(x11Display), &window_attributes_return);

	int screenWidth  = window_attributes_return.width;
	int screenHeight = window_attributes_return.height;
	std::cout << "[" << screenWidth << "x" << screenHeight <<"]" << std::endl;

	// Update the size of the buffer used to transfer the screenshot
	int width  = (screenWidth  - 2 * cropWidth  + pixelDecimation/2) / pixelDecimation;
	int height = (screenHeight - 2 * cropHeight + pixelDecimation/2) / pixelDecimation;
	image.resize(width, height);

	const int croppedWidth  = screenWidth  - 2*cropWidth;
	const int croppedHeight = screenHeight - 2*cropHeight;

	QElapsedTimer timer;
	timer.start();

	XImage * xImage = XGetImage(x11Display, DefaultRootWindow(x11Display), cropWidth, cropHeight, croppedWidth, croppedHeight, AllPlanes, ZPixmap);

	std::cout << "Captured image: " << xImage << std::endl;

	// Copy the capture XImage to the local image (and apply required decimation)
	ColorRgb * outputPtr = image.memptr();
	for (int iY=(pixelDecimation/2); iY<croppedHeight; iY+=pixelDecimation)
	{
		for (int iX=(pixelDecimation/2); iX<croppedWidth; iX+=pixelDecimation)
		{
			// Extract the pixel from the X11-image
			const uint32_t pixel = uint32_t(XGetPixel(xImage, iX, iY));

			// Assign the color value
			outputPtr->red   = uint8_t((pixel >> 16) & 0xff);
			outputPtr->green = uint8_t((pixel >> 8)  & 0xff);
			outputPtr->blue  = uint8_t((pixel >> 0)  & 0xff);

			// Move to the next output pixel
			++outputPtr;
		}
	}

	// Cleanup allocated resources of the X11 grab
	XDestroyImage(xImage);

	std::cout << "Time required: " << timer.elapsed() << " ms" << std::endl;

	XCloseDisplay(x11Display);
}

void foo_2(int pixelDecimation)
{
	int cropWidth  = 0;
	int cropHeight = 0;

	Image<ColorRgb> image(64, 64);

	 /// Reference to the X11 display (nullptr if not opened)
	Display * x11Display;

	const char * display_name = nullptr;
	x11Display = XOpenDisplay(display_name);

	XWindowAttributes window_attributes_return;
	XGetWindowAttributes(x11Display, DefaultRootWindow(x11Display), &window_attributes_return);

	int screenWidth  = window_attributes_return.width;
	int screenHeight = window_attributes_return.height;
	std::cout << "[" << screenWidth << "x" << screenHeight <<"]" << std::endl;

	// Update the size of the buffer used to transfer the screenshot
	int width  = (screenWidth  - 2 * cropWidth  + pixelDecimation/2) / pixelDecimation;
	int height = (screenHeight - 2 * cropHeight + pixelDecimation/2) / pixelDecimation;
	image.resize(width, height);

	const int croppedWidth  = screenWidth  - 2*cropWidth;
	const int croppedHeight = screenHeight - 2*cropHeight;

	QElapsedTimer timer;
	timer.start();

	// Copy the capture XImage to the local image (and apply required decimation)
	ColorRgb * outputPtr = image.memptr();
	for (int iY=(pixelDecimation/2); iY<croppedHeight; iY+=pixelDecimation)
	{
		for (int iX=(pixelDecimation/2); iX<croppedWidth; iX+=pixelDecimation)
		{
			XImage * xImage = XGetImage(x11Display, DefaultRootWindow(x11Display), iX, iY, 1, 1, AllPlanes, ZPixmap);
			// Extract the pixel from the X11-image
			const uint32_t pixel = uint32_t(XGetPixel(xImage, 0, 0));

			// Assign the color value
			outputPtr->red   = uint8_t((pixel >> 16) & 0xff);
			outputPtr->green = uint8_t((pixel >> 8)  & 0xff);
			outputPtr->blue  = uint8_t((pixel >> 0)  & 0xff);

			// Move to the next output pixel
			++outputPtr;

			// Cleanup allocated resources of the X11 grab
			XDestroyImage(xImage);
		}
	}
	std::cout << "Time required: " << timer.elapsed() << " ms" << std::endl;


	XCloseDisplay(x11Display);
}

int main()
{
	foo_1(10);
	foo_2(10);
	return 0;
}


<|start_filename|>libsrc/leddevice/dev_spi/LedDeviceLpd6803.cpp<|end_filename|>
#include "LedDeviceLpd6803.h"

LedDeviceLpd6803::LedDeviceLpd6803(const QJsonObject &deviceConfig)
	: ProviderSpi(deviceConfig)
{
}

LedDevice* LedDeviceLpd6803::construct(const QJsonObject &deviceConfig)
{
	return new LedDeviceLpd6803(deviceConfig);
}

bool LedDeviceLpd6803::init(const QJsonObject &deviceConfig)
{
	bool isInitOK = false;

	// Initialise sub-class
	if ( ProviderSpi::init(deviceConfig) )
	{
		unsigned messageLength = 4 + 2*_ledCount + _ledCount/8 + 1;
		// Initialise the buffer
		_ledBuffer.resize(messageLength, 0x00);

		isInitOK = true;
	}
	return isInitOK;
}

int LedDeviceLpd6803::write(const std::vector<ColorRgb> &ledValues)
{
	// Copy the colors from the ColorRgb vector to the Ldp6803 data vector
	for (unsigned iLed=0; iLed<(unsigned)_ledCount; ++iLed)
	{
		const ColorRgb& color = ledValues[iLed];

		_ledBuffer[4 + 2 * iLed] = 0x80 | ((color.red & 0xf8) >> 1) | (color.green >> 6);
		_ledBuffer[5 + 2 * iLed] = ((color.green & 0x38) << 2) | (color.blue >> 3);
	}

	// Write the data
	return writeBytes(_ledBuffer.size(), _ledBuffer.data());
}


<|start_filename|>cmake/win/win_rc.cmake<|end_filename|>
# process a .rc file for windows
# Provides (BINARY_NAME)_WIN_RC_PATH with path to generated file
function(generate_win_rc_file BINARY_NAME)
	# target path to store generated files
	set(TARGET_PATH ${CMAKE_BINARY_DIR}/win_rc_file/${BINARY_NAME})
	# assets
	string(REPLACE "/" "\\\\" WIN_RC_ICON_PATH ${CMAKE_SOURCE_DIR}/cmake/nsis/installer.ico)
	# configure the rc file
	configure_file(
		${CMAKE_SOURCE_DIR}/cmake/win/win.rc.in
		${TARGET_PATH}/win.rc
	)
    # provide var for parent scope
  	set(${BINARY_NAME}_WIN_RC_PATH ${TARGET_PATH}/win.rc PARENT_SCOPE)
endfunction()


<|start_filename|>include/commandline/ValidatorOption.h<|end_filename|>
#ifndef HYPERION_COMMANDLINEOPTION_H
#define HYPERION_COMMANDLINEOPTION_H

#include <QtCore>
#include <QtGui>
#include <commandline/Option.h>

namespace commandline
{

class ValidatorOption: public Option
{
protected:
    const QValidator *validator;
    virtual void setValidator(const QValidator *validator);

public:
    ValidatorOption(const QString &name,
                    const QString &description = QString(),
                    const QString &valueName = QString(),
                    const QString &defaultValue = QString(),
                    const QValidator *validator = nullptr)
        : Option(name, description, valueName, defaultValue), validator(validator)
    {}

    ValidatorOption(const QStringList &names,
                    const QString &description = QString(),
                    const QString &valueName = QString(),
                    const QString &defaultValue = QString(),
                    const QValidator *validator = nullptr)
        : Option(names, description, valueName, defaultValue), validator(validator)
    {}

    ValidatorOption(const QCommandLineOption &other,
                    const QValidator *validator = nullptr)
        : Option(other), validator(validator)
    {}

    virtual const QValidator *getValidator() const;
    virtual bool validate(Parser & parser, QString &value) override;
};

}

#endif //HYPERION_COMMANDLINEOPTION_H


<|start_filename|>libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.h<|end_filename|>
#ifndef LEDEVICEWS281X_H
#define LEDEVICEWS281X_H

// LedDevice includes
#include <leddevice/LedDevice.h>
#include <ws2811.h>

///
/// Implementation of the LedDevice interface for writing to WS281x LED-device via pwm.
///
class LedDeviceWS281x : public LedDevice
{
public:

	///
	/// @brief Constructs an WS281x LED-device
	///
	/// @param deviceConfig Device's configuration as JSON-Object
	///
	explicit LedDeviceWS281x(const QJsonObject &deviceConfig);

	///
	/// @brief Destructor of the LedDevice
	///
	~LedDeviceWS281x() override;

	///
	/// @brief Destructor of the LedDevice
	///
	static LedDevice* construct(const QJsonObject &deviceConfig);

protected:

	///
	/// @brief Initialise the device's configuration
	///
	/// @param[in] deviceConfig the JSON device configuration
	/// @return True, if success
	///
	bool init(const QJsonObject &deviceConfig) override;

	///
	/// @brief Opens the output device.
	///
	/// @return Zero on success (i.e. device is ready), else negative
	///
	int open() override;

	///
	/// @brief Closes the output device.
	///
	/// @return Zero on success (i.e. device is closed), else negative
	///
	int close() override;

	///
	/// @brief Writes the RGB-Color values to the LEDs.
	///
	/// @param[in] ledValues The RGB-color per LED
	/// @return Zero on success, else negative
	///
	int write(const std::vector<ColorRgb> & ledValues) override;

private:

	ws2811_t    _led_string;
	int         _channel;
	RGBW::WhiteAlgorithm _whiteAlgorithm;
	ColorRgbw   _temp_rgbw;
};

#endif // LEDEVICEWS281X_H


<|start_filename|>include/protoserver/ProtoServer.h<|end_filename|>
#pragma once

// util
#include <utils/Logger.h>
#include <utils/settings.h>

// qt
#include <QVector>

class QTcpServer;
class ProtoClientConnection;
class NetOrigin;

///
/// @brief This class creates a TCP server which accepts connections wich can then send
/// in Protocol Buffer encoded commands. This interface to Hyperion is used by various
/// third-party applications
///
class ProtoServer : public QObject
{
	Q_OBJECT

public:
	ProtoServer(const QJsonDocument& config, QObject* parent = nullptr);
	~ProtoServer() override;

public slots:
	///
	/// @brief Handle settings update
	/// @param type   The type from enum
	/// @param config The configuration
	///
	void handleSettingsUpdate(settings::type type, const QJsonDocument& config);

	void initServer();

private slots:
	///
	/// @brief Is called whenever a new socket wants to connect
	///
	void newConnection();

	///
	/// @brief is called whenever a client disconnected
	///
	void clientDisconnected();

private:
	///
	/// @brief Start the server with current _port
	///
	void startServer();

	///
	/// @brief Stop server
	///
	void stopServer();


private:
	QTcpServer* _server;
	NetOrigin* _netOrigin;
	Logger* _log;
	int _timeout;
	quint16 _port;
	const QJsonDocument _config;

	QVector<ProtoClientConnection*> _openConnections;
};


<|start_filename|>include/leddevice/LedDeviceFactory.h<|end_filename|>
#ifndef LEDEVICEFACTORY_H
#define LEDEVICEFACTORY_H

class LedDevice;
class QJsonObject;

///
/// The LedDeviceFactory is responsible for constructing 'LedDevices'
///
class LedDeviceFactory
{
public:
	///
	/// Constructs a LedDevice based on the given configuration
	///
	/// @param deviceConfig The configuration of the led-device
	///
	/// @return The constructed LedDevice or nullptr if configuration is invalid. The ownership of
	/// the constructed LedDevice is transferred to the caller
	///
	static LedDevice * construct(const QJsonObject & deviceConfig);
};

#endif // LEDEVICEFACTORY_H


<|start_filename|>include/hyperion/ColorAdjustment.h<|end_filename|>
#pragma once

// STL includes
#include <QString>

// Utils includes
#include <utils/RgbChannelAdjustment.h>
#include <utils/RgbTransform.h>

class ColorAdjustment
{
public:
	/// Unique identifier for this color transform
	QString _id;

	/// The BLACK (RGB-Channel) adjustment
	RgbChannelAdjustment _rgbBlackAdjustment;
	/// The WHITE (RGB-Channel) adjustment
	RgbChannelAdjustment _rgbWhiteAdjustment;
	/// The RED (RGB-Channel) adjustment
	RgbChannelAdjustment _rgbRedAdjustment;
	/// The GREEN (RGB-Channel) adjustment
	RgbChannelAdjustment _rgbGreenAdjustment;
	/// The BLUE (RGB-Channel) adjustment
	RgbChannelAdjustment _rgbBlueAdjustment;
	/// The CYAN (RGB-Channel) adjustment
	RgbChannelAdjustment _rgbCyanAdjustment;
	/// The MAGENTA (RGB-Channel) adjustment
	RgbChannelAdjustment _rgbMagentaAdjustment;
	/// The YELLOW (RGB-Channel) adjustment
	RgbChannelAdjustment _rgbYellowAdjustment;

	RgbTransform _rgbTransform;
};


<|start_filename|>include/ssdp/SSDPDiscover.h<|end_filename|>
#ifndef SSDPDISCOVER_H
#define SSDPDISCOVER_H

#include <QHostAddress>
#include <QMultiMap>
#include <QUrl>
#include <QRegularExpression>

#include <chrono>

class Logger;
class QUdpSocket;

enum class searchType{
	STY_WEBSERVER,
	STY_FLATBUFSERVER,
	STY_JSONSERVER
};

struct SSDPService {
	QString cacheControl;
	QUrl location;
	QString server;
	QString searchTarget;
	QString uniqueServiceName;
	QMap <QString,QString> otherHeaders;
};

// Default values
static const char	DEFAULT_SEARCH_ADDRESS[] = "192.168.127.12";
static const int	DEFAULT_SEARCH_PORT = 1900;
static const char	DEFAULT_FILTER[] = ".*";
static const char	DEFAULT_FILTER_HEADER[] = "ST";

constexpr std::chrono::milliseconds DEFAULT_SSDP_TIMEOUT{5000}; // timeout in ms

///
/// @brief Search for SSDP sessions, used by stand-alone capture binaries
///
class SSDPDiscover : public QObject
{
	Q_OBJECT

public:

	SSDPDiscover(QObject* parent = nullptr);

	///
	/// @brief Search for specified service, results will be returned by signal newService(). Calling this method again will reset all found urns and search again
	/// @param st The service to search for
	///
	void searchForService(const QString &st = "urn:hyperion-project.org:device:basic:1");

	///
	/// @brief Search for specified searchTarget, the method will block until a server has been found or a timeout happened
	/// @param type        The address type one of struct searchType
	/// @param st          The service to search for
	/// @param timeout_ms  The timeout in ms
	/// @return The address+port of web-server or empty if timed out
	///
	QString getFirstService(const searchType &type = searchType::STY_WEBSERVER,const QString &st = "urn:hyperion-project.org:device:basic:1", int timeout_ms = 3000);

	///
	/// @brief Discover services via ssdp.
	///
	/// Records meeting the search target and filter criteria ( setSearchFilter() ) are stored in a map using the given element as a key.
	///
	/// The search result can be accessed via getServicesDiscoveredJson() or getServicesDiscovered()
	///
	/// Usage sample:
	/// @code
	///
	/// SSDPDiscover discover;
	///
	/// discover.skipDuplicateKeys(true);
	/// QString searchTargetFilter = "(.*)IpBridge(.*)";
	/// discover.setSearchFilter(searchTargetFilter, "SERVER");
	/// QString searchTarget = "upnp:rootdevice";
	///
	/// if ( discover.discoverServices(searchTarget) > 0 )
	/// 	deviceList = discover.getServicesDiscoveredJson();
	///
	///@endcode
	///
	/// @param[in] searchTarget The ssdp discovery search target (ST)
	/// @param[in] key Element used as key for the result map
	///
	/// @return Number of service records found (meeting the search & filter criteria)
	///
	int discoverServices(const QString &searchTarget="ssdp:all", const QString &key="LOCATION");

	///
	/// @brief Get services discovered during discoverServices().
	///
	/// Hostname and domain are resolved from IP-address and stored in extra elements
	///
	/// Sample result:
	/// @code
	///
	/// [{
	/// "cache-control": "max-age=100",
	/// "domain": "fritz.box",
	/// "hostname": "ubuntu1910",
	/// "id": "http://192.168.2.152:8081/description.xml",
	/// "ip": "192.168.2.152",
	/// "location": "http://192.168.2.152:8081/description.xml",
	/// "other": { "ext": "", "host": "239.255.255.250:1900", "hue-bridgeid": "000C29FFFED8D52D"},
	/// "port": 8081,
	/// "server": "Linux/3.14.0 UPnP/1.0 IpBridge/1.19.0",
	/// "st": "upnp:rootdevice",
	/// "usn": "uuid:2f402f80-da50-11e1-9b23-000c29d8d52d::upnp:rootdevice"
	/// }]
	///
	///@endcode
	///
	/// @return Discovered services as JSON-document
	///
	QJsonArray getServicesDiscoveredJson() const;

	///
	/// @brief Set the ssdp discovery address (HOST)
	///
	/// @param[in] IP-address used during discovery
	///
	void setAddress ( const QString &address) { _ssdpAddr = QHostAddress(address); }

	///
	/// @brief Set the ssdp discovery port (HOST)
	///
	/// @param[in] port used during discovery
	///
	void setPort ( quint16 port) { _ssdpPort = port; }

	///
	/// @brief Set the ssdp discovery max wait time (MX)
	///
	/// @param[in] maxWaitResponseTime
	///
	void setMaxWaitResponseTime ( int maxWaitResponseTime) { _ssdpMaxWaitResponseTime = maxWaitResponseTime; }

	///
	/// @brief Set the ssdp discovery search target (ST)
	///
	/// @param[in] searchTarget
	///
	void setSearchTarget ( const QString &searchTarget) { _searchTarget = searchTarget; }

	///
	/// @brief Set the ssdp discovery search target filter
	///
	/// @param[in] filter as regular expression
	/// @param[in] filterHeader Header element the filter is applied to
	///
	/// @return True, if valid regular expression
	///
	bool setSearchFilter ( const QString &filter=DEFAULT_FILTER, const QString &filterHeader="ST");

	///
	/// @brief Set the ssdp discovery search target and filter to default values
	///
	void clearSearchFilter () { _filter=DEFAULT_FILTER; _filterHeader="ST"; }

	///
	/// @brief Skip duplicate records with the same key-value
	///
	/// @param[in] skip True: skip records with duplicate key-values, False: Allow duplicate key-values
	///
	void skipDuplicateKeys( bool skip ) { _skipDupKeys = skip; }

signals:
	///
	/// @brief Emits whenever a new service has been found, search started with searchForService()
	///
	/// @param webServer The address+port of web-server "192.168.0.10:8090"
	///
	void newService(const QString &webServer);

private slots:
	void readPendingDatagrams();

private:
	///
	/// @brief Execute ssdp discovery request
	///
	/// @param[in] st Search Target
	///
	void sendSearch(const QString &st);

private:

	Logger* _log;
	QUdpSocket* _udpSocket;
	QHostAddress _ssdpAddr;
	quint16 _ssdpPort;

	int _ssdpMaxWaitResponseTime;
	int	_ssdpTimeout;

	QMultiMap<QString, SSDPService> _services;

	QStringList _usnList;
	QString _searchTarget;

	QString _filter;
	QString _filterHeader;
	QRegularExpression _regExFilter;
	bool _skipDupKeys;
};

#endif // SSDPDISCOVER_H


<|start_filename|>cmake/Toolchain-rpi.cmake<|end_filename|>
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_VERSION 1)

SET(CROSSROOT $ENV{HOME}/crosscompile)
SET(DEVROOT ${CROSSROOT}/raspberrypi)
SET(PIROOT ${DEVROOT}/rootfs)
SET(PITOOLCHAIN ${DEVROOT}/tools)

SET(TOOLROOT ${PITOOLCHAIN}/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf )
SET(QT_BIN_PATH ${CROSSROOT}/Qt5/5.7/gcc_64/bin)

# specify the cross compiler
SET(CMAKE_C_COMPILER   ${TOOLROOT}/bin/arm-linux-gnueabihf-gcc)
SET(CMAKE_CXX_COMPILER ${TOOLROOT}/bin/arm-linux-gnueabihf-g++)
SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "armhf" )

SET(CMAKE_SYSROOT ${PIROOT})
SET(CMAKE_FIND_ROOT_PATH ${PIROOT})

# search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
#SET(CMAKE_FIND_ROOT_PATH_MODE_PACKAGES ONLY)


#SET Flags for linking as dynamic linker config file is not being properly parsed by the toolchain
# see https://solderspot.wordpress.com/2016/02/04/cross-compiling-for-raspberry-pi-part-ii/

SET(FLAGS "-Wl,-rpath-link,${PIROOT}/opt/vc/lib -Wl,-rpath-link,${PIROOT}/lib/arm-linux-gnueabihf -Wl,-rpath-link,${PIROOT}/usr/lib/arm-linux-gnueabihf -Wl,-rpath-link,${PIROOT}/usr/local/lib")

UNSET(CMAKE_C_FLAGS CACHE)
UNSET(CMAKE_CXX_FLAGS CACHE)

SET(CMAKE_CXX_FLAGS ${FLAGS} CACHE STRING "" FORCE)
SET(CMAKE_C_FLAGS ${FLAGS} CACHE STRING "" FORCE)

link_directories(${PIROOT}/lib/arm-linux-gnueabihf)



<|start_filename|>libsrc/utils/ColorArgb.cpp<|end_filename|>
// Utils includes
#include <utils/ColorArgb.h>

const ColorArgb ColorArgb::BLACK  = { 255,   0,   0,   0 };
const ColorArgb ColorArgb::RED    = { 255, 255,   0,   0 };
const ColorArgb ColorArgb::GREEN  = { 255,   0, 255,   0 };
const ColorArgb ColorArgb::BLUE   = { 255,   0,   0, 255 };
const ColorArgb ColorArgb::YELLOW = { 255, 255, 255,   0 };
const ColorArgb ColorArgb::WHITE  = { 255, 255, 255, 255 };


<|start_filename|>libsrc/utils/ColorRgb.cpp<|end_filename|>
// Local includes
#include <utils/ColorRgb.h>

const ColorRgb ColorRgb::BLACK  = {   0,   0,   0 };
const ColorRgb ColorRgb::RED    = { 255,   0,   0 };
const ColorRgb ColorRgb::GREEN  = {   0, 255,   0 };
const ColorRgb ColorRgb::BLUE   = {   0,   0, 255 };
const ColorRgb ColorRgb::YELLOW = { 255, 255,   0 };
const ColorRgb ColorRgb::WHITE  = { 255, 255, 255 };


<|start_filename|>include/commandline/ColorOption.h<|end_filename|>
#ifndef HYPERION_COLOROPTION_H
#define HYPERION_COLOROPTION_H

#include "Option.h"
#include <QColor>
#include <QCommandLineParser>

namespace commandline
{

class ColorOption: public Option
{
protected:
    QColor _color;

public:
    ColorOption(const QString &name,
                const QString &description = QString(),
                const QString &valueName = QString(),
                const QString &defaultValue = QString()
    )
        : Option(name, description, valueName, defaultValue)
    {}
    ColorOption(const QStringList &names,
                const QString &description = QString(),
                const QString &valueName = QString(),
                const QString &defaultValue = QString()
    )
        : Option(names, description, valueName, defaultValue)
    {}
    ColorOption(const QCommandLineOption &other)
        : Option(other)
    {}

    bool validate(Parser & parser, QString & value) override;
    QColor getColor(Parser &parser) const { return _color; }
};

}

#endif //HYPERION_COLOROPTION_H


<|start_filename|>libsrc/utils/Profiler.cpp<|end_filename|>
#include "HyperionConfig.h"
#include <utils/Profiler.h>
#include <utils/FileUtils.h>

#include <QFileInfo>
#include <QString>

struct StopWatchItem {
	const char* sourceFile;
	const char* func;
	unsigned int line;
	clock_t startTime;
};

static unsigned int blockCounter = 0;
static std::map<QString,StopWatchItem> GlobalProfilerMap;
Logger* Profiler::_logger = nullptr;

double getClockDelta(clock_t start)
{
	return ((double)(clock() - start) / CLOCKS_PER_SEC);
}

Profiler::Profiler(const char* sourceFile, const char* func, unsigned int line)
	: _file(sourceFile)
	, _func(func)
	, _line(line)
	, _blockId(blockCounter++)
	, _startTime(clock())
{
	Profiler::initLogger();
	_logger->Message(Logger::DEBUG,_file,_func,_line,">>> enter block %d", _blockId);
}

Profiler::~Profiler()
{
  	_logger->Message( Logger::DEBUG, _file,_func, _line, "<<< exit block %d, executed for %f s", _blockId, getClockDelta(_startTime));
}

void Profiler::initLogger()
{
	if (_logger == nullptr)
		_logger = Logger::getInstance("PROFILER", Logger::DEBUG);
}

void Profiler::TimerStart(const QString& timerName, const char* sourceFile, const char* func, unsigned int line)
{
	std::pair<std::map<QString,StopWatchItem>::iterator,bool> ret;
	Profiler::initLogger();

	StopWatchItem item = {sourceFile, func, line};

	ret = GlobalProfilerMap.emplace(timerName, item);
	if (!ret.second)
	{
		if (ret.first->second.sourceFile == sourceFile && ret.first->second.func == func && ret.first->second.line == line)
		{
			_logger->Message(Logger::DEBUG, sourceFile, func, line, "restart timer '%s'", QSTRING_CSTR(timerName));
			ret.first->second.startTime = clock();
		}
		else
		{
			_logger->Message(Logger::DEBUG, sourceFile, func, line, "ERROR timer '%s' started in multiple locations. First occurence %s:%d:%s()",
			                 QSTRING_CSTR(timerName), FileUtils::getBaseName(ret.first->second.sourceFile).toLocal8Bit().constData(), ret.first->second.line, ret.first->second.func);
		}
	}
	else
	{
		_logger->Message(Logger::DEBUG, sourceFile, func, line, "start timer '%s'", QSTRING_CSTR(timerName));
	}
}


void Profiler::TimerGetTime(const QString& timerName, const char* sourceFile, const char* func, unsigned int line)
{
	std::map<QString,StopWatchItem>::iterator ret = GlobalProfilerMap.find(timerName);
	Profiler::initLogger();
	if (ret != GlobalProfilerMap.end())
	{
		_logger->Message(Logger::DEBUG, sourceFile, func, line, "timer '%s' started at %s:%d:%s() took %f s execution time until here", QSTRING_CSTR(timerName),
		                 FileUtils::getBaseName(ret->second.sourceFile).toLocal8Bit().constData(), ret->second.line, ret->second.func, getClockDelta(ret->second.startTime));
	}
	else
	{
		_logger->Message(Logger::DEBUG, sourceFile, func, line, "ERROR timer '%s' not started", QSTRING_CSTR(timerName));
	}
}


<|start_filename|>include/cec/CECHandler.h<|end_filename|>
#pragma once

#include <QObject>
#include <QVector>

#include <iostream>

#include <libcec/cec.h>

#include <cec/CECEvent.h>

using CECCallbacks         = CEC::ICECCallbacks;
using CECAdapter           = CEC::ICECAdapter;
using CECAdapterDescriptor = CEC::cec_adapter_descriptor;
using CECLogMessage        = CEC::cec_log_message;
using CECKeyPress          = CEC::cec_keypress;
using CECCommand           = CEC::cec_command;
using CECLogicalAddress    = CEC::cec_logical_address;
using CECLogicalAddresses  = CEC::cec_logical_addresses;
using CECMenuState         = CEC::cec_menu_state;
using CECPowerStatus       = CEC::cec_power_status;
using CECVendorId          = CEC::cec_vendor_id;
using CECParameter         = CEC::libcec_parameter;
using CECConfig            = CEC::libcec_configuration;
using CECAlert             = CEC::libcec_alert;

class Logger;

class CECHandler : public QObject
{
	Q_OBJECT
public:
	CECHandler();
	~CECHandler() override;

	QString scan() const;

public slots:
	bool start();
	void stop();

signals:
	void cecEvent(CECEvent event);

private:
	/* CEC Callbacks */
	static void onCecLogMessage           (void * context, const CECLogMessage * message);
	static void onCecKeyPress             (void * context, const CECKeyPress * key);
	static void onCecAlert                (void * context, const CECAlert alert, const CECParameter data);
	static void onCecConfigurationChanged (void * context, const CECConfig * configuration);
	static void onCecCommandReceived      (void * context, const CECCommand * command);
	static void onCecSourceActivated      (void * context, const CECLogicalAddress address, const uint8_t activated);
	static int  onCecMenuStateChanged     (void * context, const CECMenuState state);

	/* CEC Adapter helpers */
	QVector<CECAdapterDescriptor> getAdapters() const;
	bool openAdapter(const CECAdapterDescriptor & descriptor);
	void printAdapter(const CECAdapterDescriptor & descriptor) const;

	/* CEC Helpers */
	CECCallbacks getCallbacks() const;
	CECConfig getConfig() const;

	CECAdapter * _cecAdapter   {};
	CECCallbacks _cecCallbacks {};
	CECConfig    _cecConfig    {};

	Logger * _logger {};
};


<|start_filename|>cmake/FindCEC.cmake<|end_filename|>
# - Try to find CEC
# Once done this will define
#
# CEC_FOUND - system has libcec
# CEC_INCLUDE_DIRS - the libcec include directory
# CEC_LIBRARIES - The libcec libraries

if(PKG_CONFIG_FOUND)
  pkg_check_modules (CEC libcec>=3.0.0)
else()
  find_path(CEC_INCLUDE_DIRS libcec/cec.h)
  find_library(CEC_LIBRARIES cec)
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(CEC DEFAULT_MSG CEC_INCLUDE_DIRS CEC_LIBRARIES)

list(APPEND CEC_DEFINITIONS -DHAVE_LIBCEC=1)
mark_as_advanced(CEC_INCLUDE_DIRS CEC_LIBRARIES CEC_DEFINITIONS)


<|start_filename|>include/db/DBManager.h<|end_filename|>
#pragma once

#include <utils/Logger.h>
#include <QMap>
#include <QVariant>
#include <QPair>
#include <QVector>

class QSqlDatabase;
class QSqlQuery;

typedef QPair<QString,QVariant> CPair;
typedef QVector<CPair> VectorPair;

///
/// @brief Database interface for SQLite3.
///        Inherit this class to create component specific methods based on this interface
///        Usage: setTable(name) once before you use read/write actions
///        To use another database use setDb(newDB) (defaults to "hyperion")
///
///        Incompatible functions with SQlite3:
///        QSqlQuery::size() returns always -1
///
class DBManager : public QObject
{
	Q_OBJECT

public:
	DBManager(QObject* parent = nullptr);
	~DBManager() override;

	/// set root path
	void setRootPath(const QString& rootPath);
	/// define the database to work with
	void setDatabaseName(const QString& dbn) { _dbn = dbn; };
	/// set a table to work with
	void setTable(const QString& table);

	/// get current database object set with setDB()
	QSqlDatabase getDB() const;

	///
	/// @brief Create a table (if required) with the given columns. Older tables will be updated accordingly with missing columns
	///        Does not delete or migrate old columns
	/// @param[in]  columns  The columns of the table. Requires at least one entry!
	/// @return              True on success else false
	///
	bool createTable(QStringList& columns) const;

	///
	/// @brief Create a column if the column already exists returns false and logs error
	/// @param[in]  column   The column of the table
	/// @return              True on success else false
	///
	bool createColumn(const QString& column) const;

	///
	/// @brief Check if at least one record exists in table with the conditions
	/// @param[in]  conditions The search conditions (WHERE)
	/// @return                True on success else false
	///
	bool recordExists(const VectorPair& conditions) const;

	///
	/// @brief Create a new record in table when the conditions find no existing entry. Add additional key:value pairs in columns
	///        DO NOT repeat column keys between 'conditions' and 'columns' as they will be merged on creation
	/// @param[in]  conditions conditions to search for, as a record may exist and should be updated instead (WHERE)
	/// @param[in]  columns    columns to create or update (optional)
	/// @return                True on success else false
	///
	bool createRecord(const VectorPair& conditions, const QVariantMap& columns = QVariantMap()) const;

	///
	/// @brief Update a record with conditions and additional key:value pairs in columns
	/// @param[in]  conditions conditions which rows should be updated (WHERE)
	/// @param[in]  columns    columns to update
	/// @return                True on success else false
	///
	bool updateRecord(const VectorPair& conditions, const QVariantMap& columns) const;

	///
	/// @brief Get data of a single record, multiple records are not supported
	/// @param[in]  conditions  condition to search for (WHERE)
	/// @param[out] results     results of query
	/// @param[in]  tColumns    target columns to search in (optional) if not provided returns all columns
	/// @param[in]  tOrder      target order columns with order by ASC/DESC (optional)
	/// @return                 True on success else false
	///
	bool getRecord(const VectorPair& conditions, QVariantMap& results, const QStringList& tColumns = QStringList(), const QStringList& tOrder = QStringList()) const;

	///
	/// @brief Get data of multiple records, you need to specify the columns. This search is without conditions. Good to grab all data from db
	/// @param[in]  conditions  condition to search for (WHERE)
	/// @param[out] results     results of query
	/// @param[in]  tColumns    target columns to search in (optional) if not provided returns all columns
	/// @param[in]  tOrder      target order columns with order by ASC/DESC (optional)
	/// @return                 True on success else false
	///
	bool getRecords(QVector<QVariantMap>& results, const QStringList& tColumns = QStringList(), const QStringList& tOrder = QStringList()) const;

	///
	/// @brief Delete a record determined by conditions
	/// @param[in]  conditions conditions of the row to delete it (WHERE)
	/// @return                True on success; on error or not found false
	///
	bool deleteRecord(const VectorPair& conditions) const;

	///
	/// @brief Check if table exists in current database
	/// @param[in]  table   The name of the table
	/// @return             True on success else false
	///
	bool tableExists(const QString& table) const;

	///
	/// @brief Delete a table, fails silent (return true) if table is not found
	/// @param[in]  table   The name of the table
	/// @return             True on success else false
	///
	bool deleteTable(const QString& table) const;

	///
	/// @brief Sets a table in read-only mode.
	/// Updates will not written to the table
	/// @param[in]  readOnly True read-only, false - read/write
	///
	void setReadonlyMode(bool readOnly) { _readonlyMode = readOnly; };

private:

	Logger* _log;
	/// databse connection & file name, defaults to hyperion
	QString _dbn = "hyperion";
	/// table in database
	QString _table;

	bool _readonlyMode;

	/// addBindValue to query given by QVariantList
	void doAddBindValue(QSqlQuery& query, const QVariantList& variants) const;
};


<|start_filename|>libsrc/leddevice/dev_spi/LedDeviceLpd8806.h<|end_filename|>
#ifndef LEDEVICELPD8806_H
#define LEDEVICELPD8806_H

// Local hyperion includes
#include "ProviderSpi.h"

///
/// Implementation of the LedDevice interface for writing to LPD8806 led device.
///
/// The following description is copied from 'adafruit' (github.com/adafruit/LPD8806)
///
/// Clearing up some misconceptions about how the LPD8806 drivers work:
///
/// The LPD8806 is not a FIFO shift register.  The first data out controls the
/// LED *closest* to the processor (unlike a typical shift register, where the
/// first data out winds up at the *furthest* LED).  Each LED driver 'fills up'
/// with data and then passes through all subsequent bytes until a latch
/// condition takes place.  This is actually pretty common among LED drivers.
///
/// All color data bytes have the high bit (128) set, with the remaining
/// seven bits containing a brightness value (0-127).  A byte with the high
/// bit clear has special meaning (explained later).
///
/// The rest gets bizarre...
///
/// The LPD8806 does not perform an in-unison latch (which would display the
/// newly-transmitted data all at once).  Rather, each individual byte (even
/// the separate G, R, B components of each LED) is latched AS IT ARRIVES...
/// or more accurately, as the first bit of the subsequent byte arrives and
/// is passed through.  So the strip actually refreshes at the speed the data
/// is issued, not instantaneously (this can be observed by greatly reducing
/// the data rate).  This has implications for POV displays and light painting
/// applications.  The 'subsequent' rule also means that at least one extra
/// byte must follow the last pixel, in order for the final blue LED to latch.
///
/// To reset the pass-through behaviour and begin sending new data to the start
/// of the strip, a number of zero bytes must be issued (remember, all color
/// data bytes have the high bit set, thus are in the range 128 to 255, so the
/// zero is 'special').  This should be done before each full payload of color
/// values to the strip.  Curiously, zero bytes can only travel one meter (32
/// LEDs) down the line before needing backup; the next meter requires an
/// extra zero byte, and so forth.  Longer strips will require progressively
/// more zeros.  *(see note below)
///
/// In the interest of efficiency, it's possible to combine the former EOD
/// extra latch byte and the latter zero reset...the same data can do double
/// duty, latching the last blue LED while also resetting the strip for the
/// next payload.
///
/// So: reset byte(s) of suitable length are issued once at startup to 'prime'
/// the strip to a known ready state.  After each subsequent LED color payload,
/// these reset byte(s) are then issued at the END of each payload, both to
/// latch the last LED and to prep the strip for the start of the next payload
/// (even if that data does not arrive immediately).  This avoids a tiny bit
/// of latency as the new color payload can begin issuing immediately on some
/// signal, such as a timer or GPIO trigger.
///
/// Technically these zero byte(s) are not a latch, as the color data (save
/// for the last byte) is already latched.  It's a start-of-data marker, or
/// an indicator to clear the thing-that's-not-a-shift-register.  But for
/// conversational consistency with other LED drivers, we'll refer to it as
/// a 'latch' anyway.
///
/// This has been validated independently with multiple customers'
/// hardware.  Please do not report as a bug or issue pull requests for
/// this.  Fewer zeros sometimes gives the *illusion* of working, the first
/// payload will correctly load and latch, but subsequent frames will drop
/// data at the end.  The data shortfall won't always be visually apparent
/// depending on the color data loaded on the prior and subsequent frames.
/// Tested.  Confirmed.  Fact.
///
///
/// The summary of the story is that the following needs to be written on the spi-device:
/// 1RRRRRRR 1GGGGGGG 1BBBBBBB 1RRRRRRR 1GGGGGGG ... ... 1GGGGGGG 1BBBBBBB 00000000 00000000 ...
/// |---------led_1----------| |---------led_2--         -led_n----------| |----clear data--
///
/// The number of zeroes in the 'clear data' is (#led/32 + 1)bytes (or *8 for bits)
///
class LedDeviceLpd8806 : public ProviderSpi
{
public:

	///
	/// @brief Constructs a LDP8806 LED-device
	///
	/// @param deviceConfig Device's configuration as JSON-Object
	///
	explicit LedDeviceLpd8806(const QJsonObject &deviceConfig);

	///
	/// @brief Constructs the LED-device
	///
	/// @param[in] deviceConfig Device's configuration as JSON-Object
	/// @return LedDevice constructed
	///
	static LedDevice* construct(const QJsonObject &deviceConfig);

private:

	///
	/// @brief Initialise the device's configuration
	///
	/// @param[in] deviceConfig the JSON device configuration
	/// @return True, if success
	///
	bool init(const QJsonObject &deviceConfig) override;

	///
	/// @brief Writes the RGB-Color values to the LEDs.
	///
	/// @param[in] ledValues The RGB-color per LED
	/// @return Zero on success, else negative
	///
	int write(const std::vector<ColorRgb> & ledValues) override;
};

#endif // LEDEVICELPD8806_H


<|start_filename|>libsrc/webserver/CgiHandler.h<|end_filename|>
#ifndef CGIHANDLER_H
#define CGIHANDLER_H

#include <QObject>
#include <QString>
#include <QStringList>

#include <utils/Logger.h>

#include "QtHttpReply.h"
#include "QtHttpRequest.h"

class CgiHandler : public QObject
{
	Q_OBJECT

public:
	CgiHandler(QObject * parent = nullptr);

	void setBaseUrl(const QString& url);
	void exec(const QStringList & args, QtHttpRequest * request, QtHttpReply * reply);

private:
	// CGI commands
	void cmd_cfg_jsonserver();
	void cmd_runscript();

	QtHttpReply *       _reply;
	QtHttpRequest *     _request;
	QStringList         _args;
	QString             _baseUrl;
	Logger *            _log;
};

#endif // CGIHANDLER_H


<|start_filename|>libsrc/leddevice/dev_hid/deactivated/LedDeviceLightpack-hidapi.cpp<|end_filename|>
// code currently disabled. must be ported to new structure
#if 0
// stl includes
#include <exception>
#include <cstring>
#include <wchar.h>

// Local Hyperion includes
#include "LedDeviceLightpack-hidapi.h"

// from USB_ID.h (http://code.google.com/p/light-pack/source/browse/CommonHeaders/USB_ID.h)
#define USB_OLD_VENDOR_ID  0x03EB
#define USB_OLD_PRODUCT_ID 0x204F
#define USB_VENDOR_ID      0x1D50
#define USB_PRODUCT_ID     0x6022

#define LIGHTPACK_INTERFACE 0

// from commands.h (http://code.google.com/p/light-pack/source/browse/CommonHeaders/commands.h)
// Commands to device, sends it in first byte of data[]
enum COMMANDS {
	CMD_UPDATE_LEDS = 1,
	CMD_OFF_ALL,
	CMD_SET_TIMER_OPTIONS,
	CMD_SET_PWM_LEVEL_MAX_VALUE, /* deprecated */
	CMD_SET_SMOOTH_SLOWDOWN,
	CMD_SET_BRIGHTNESS,

	CMD_NOP = 0x0F
};

// from commands.h (http://code.google.com/p/light-pack/source/browse/CommonHeaders/commands.h)
enum DATA_VERSION_INDEXES {
	INDEX_FW_VER_MAJOR = 1,
	INDEX_FW_VER_MINOR
};

LedDeviceLightpackHidapi::LedDeviceLightpackHidapi()
	: LedDevice()
	, _deviceHandle(nullptr)
	, _serialNumber("")
	, _firmwareVersion({-1,-1})
	, _bitsPerChannel(-1)
	, _hwLedCount(-1)
{
}

LedDeviceLightpackHidapi::~LedDeviceLightpackHidapi()
{
	if (_deviceHandle != nullptr)
	{
		hid_close(_deviceHandle);
		_deviceHandle = nullptr;
	}

	// TODO: Should be called to avoid memory leak, but only at the end of the application
	//hid_exit();
}

int LedDeviceLightpackHidapi::open(const std::string & serialNumber)
{
	// initialize the usb context
	int error = hid_init();
	if (error != 0)
	{
		Error(_log, "Error while initializing the hidapi context");
		return -1;
	}
	Info("Hidapi initialized");

	// retrieve the list of usb devices
	hid_device_info * deviceList = hid_enumerate(0x0, 0x0);

	// iterate the list of devices
	for (hid_device_info * deviceInfo = deviceList; deviceInfo != nullptr; deviceInfo = deviceInfo->next)
	{
		// try to open and initialize the device
		error = testAndOpen(deviceInfo, serialNumber);

		if (error == 0)
		{
			// a device was sucessfully opened. break from list
			break;
		}
	}

	// free the device list
	hid_free_enumeration(deviceList);

	if (_deviceHandle == nullptr)
	{
		if (_serialNumber.empty())
		{
			Error(_log, "No Lightpack device has been found");
		}
		else
		{
			Error(_log, "No Lightpack device has been found with serial %s", _serialNumber);
		}
	}

	return _deviceHandle == nullptr ? -1 : 0;
}

int LedDeviceLightpackHidapi::testAndOpen(hid_device_info *device, const std::string & requestedSerialNumber)
{
	if ((device->vendor_id == USB_VENDOR_ID && device->product_id == USB_PRODUCT_ID) ||
		(device->vendor_id == USB_OLD_VENDOR_ID && device->product_id == USB_OLD_PRODUCT_ID))
	{
		Debug(_log, "Found a lightpack device. Retrieving more information...");

		// get the serial number
		std::string serialNumber = "";
		if (device->serial_number != nullptr)
		{
			// the serial number needs to be converted to a char array instead of wchar
			size_t size = wcslen(device->serial_number);
			serialNumber.resize(size, '.');
			for (size_t i = 0; i < size; ++i)
			{
				int c = wctob(device->serial_number[i]);
				if (c != EOF)
				{
					serialNumber[i] = c;
				}
			}
		}
		else
		{
			Error(_log, "No serial number for Lightpack device");
		}

		Debug(_log, "Lightpack device found: path=%s serial=%s", device->path.c_str(), serialNumber.c_str());

		// check if this is the device we are looking for
		if (requestedSerialNumber.empty() || requestedSerialNumber == serialNumber)
		{
			// This is it!
			_deviceHandle = hid_open_path(device->path);

			if (_deviceHandle != nullptr)
			{
				_serialNumber = serialNumber;

				Info(_log, "Lightpack device successfully opened");

				// get the firmware version
				uint8_t buffer[256];
				buffer[0] = 0; // report id
				int error = hid_get_feature_report(_deviceHandle, buffer, sizeof(buffer));
				if (error < 4)
				{
					Error(_log, "Unable to retrieve firmware version number from Lightpack device");
				}
				else
				{
					_firmwareVersion.majorVersion = buffer[INDEX_FW_VER_MAJOR+1];
					_firmwareVersion.minorVersion = buffer[INDEX_FW_VER_MINOR+1];
				}

				// FOR TESTING PURPOSE: FORCE MAJOR VERSION TO 6
				_firmwareVersion.majorVersion = 6;

				// disable smoothing of the chosen device
				disableSmoothing();

				// determine the number of leds
				if (_firmwareVersion.majorVersion == 4)
				{
					_hwLedCount = 8;
				}
				else
				{
					_hwLedCount = 10;
				}

				// determine the bits per channel
				if (_firmwareVersion.majorVersion == 6)
				{
					// maybe also or version 7? The firmware suggest this is only for 6... (2013-11-13)
					_bitsPerChannel = 12;
				}
				else
				{
					_bitsPerChannel = 8;
				}

				// set the led buffer size (repport id + command + 6 bytes per led)
				_ledBuffer = std::vector<uint8_t>(2 + _hwLedCount * 6, 0);
				_ledBuffer[0] = 0x0; // report id
				_ledBuffer[1] = CMD_UPDATE_LEDS;

				// return success
				Debug(_log,"Lightpack device opened: path=%s serial=%s version=%s.%s.%s", device->path.c_str(), _serialNumber.c_str(), _firmwareVersion.majorVersion.c_str(),  _firmwareVersion.minorVersion.c_str());
				return 0;
			}
			else
			{
				Warning(_log, "Unable to open Lightpack device. Searching for other device");
			}
		}
	}

	return -1;
}

int LedDeviceLightpack::write(const std::vector<ColorRgb> &ledValues)
{
	return write(ledValues.data(), _ledCount);
}

int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
{
	int count = qMin(_hwLedCount,size);
	for (int i=0; i<count; i++)
	{
		const ColorRgb & color = ledValues[i];

		// copy the most significant bits of the rgb values to the first three bytes
		// offset 1 to accomodate for the report id and command byte
		_ledBuffer[6*i+2] = color.red;
		_ledBuffer[6*i+3] = color.green;
		_ledBuffer[6*i+4] = color.blue;

		// leave the next three bytes on zero...
		// 12-bit values having zeros in the lowest 4 bits which is almost correct, but it saves extra
		// switches to determine what to do and some bit shuffling
	}

	int error = writeBytes(_ledBuffer.data(), _ledBuffer.size());
	return error >= 0 ? 0 : error;
}

int LedDeviceLightpackHidapi::switchOff()
{
	unsigned char buf[2] = {0x0, CMD_OFF_ALL};
	return writeBytes(buf, sizeof(buf)) == sizeof(buf);
}

const std::string &LedDeviceLightpackHidapi::getSerialNumber() const
{
	return _serialNumber;
}

int LedDeviceLightpackHidapi::writeBytes(uint8_t *data, int size)
{
//	std::cout << "Writing " << size << " bytes: ";
//	for (int i = 0; i < size ; ++i) printf("%02x ", data[i]);
//	std::cout << std::endl;

	int error = hid_send_feature_report(_deviceHandle, data, size);
	if (error == size)
	{
		return 0;
	}

	Error(_log, "Unable to write %d bytes to Lightpack device(%d)", size, error);
	return error;
}

int LedDeviceLightpackHidapi::disableSmoothing()
{
	unsigned char buf[2] = {CMD_SET_SMOOTH_SLOWDOWN, 0};
	return writeBytes(buf, sizeof(buf)) == sizeof(buf);
}
#endif


<|start_filename|>libsrc/leddevice/dev_hid/LedDevicePaintpack.h<|end_filename|>
#ifndef LEDEVICEPAINTTPACK_H
#define LEDEVICEPAINTTPACK_H

// Hyperion includes
#include "ProviderHID.h"

///
/// LedDevice implementation for a paintpack LED-device
///
class LedDevicePaintpack : public ProviderHID
{
public:

	///
	/// @brief Constructs a Paintpack LED-device
	///
	/// @param deviceConfig Device's configuration as JSON-Object
	///
	explicit LedDevicePaintpack(const QJsonObject &deviceConfig);

	///
	/// @brief Constructs the LED-device
	///
	/// @param[in] deviceConfig Device's configuration as JSON-Object
	/// @return LedDevice constructed
	///
	static LedDevice* construct(const QJsonObject &deviceConfig);

private:

	///
	/// @brief Initialise the device's configuration
	///
	/// @param[in] deviceConfig the JSON device configuration
	/// @return True, if success
	///
	bool init(const QJsonObject &deviceConfig) override;

	///
	/// @brief Writes the RGB-Color values to the LEDs.
	///
	/// @param[in] ledValues The RGB-color per LED
	/// @return Zero on success, else negative
	///
	int write(const std::vector<ColorRgb> & ledValues) override;
};

#endif // LEDEVICEPAINTTPACK_H


<|start_filename|>include/utils/ColorRgba.h<|end_filename|>
#pragma once

// STL includes
#include <cstdint>
#include <ostream>

struct ColorRgba
{
	/// The red color channel
	uint8_t red;
	/// The green color channel
	uint8_t green;
	/// The blue color channel
	uint8_t blue;

	/// The alpha mask channel
	uint8_t alpha;

	/// 'Black' RgbColor (0, 0, 0, 255)
	static const ColorRgba BLACK;
	/// 'Red' RgbColor (255, 0, 0, 255)
	static const ColorRgba RED;
	/// 'Green' RgbColor (0, 255, 0, 255)
	static const ColorRgba GREEN;
	/// 'Blue' RgbColor (0, 0, 255, 255)
	static const ColorRgba BLUE;
	/// 'Yellow' RgbColor (255, 255, 0, 255)
	static const ColorRgba YELLOW;
	/// 'White' RgbColor (255, 255, 255, 255
	static const ColorRgba WHITE;
};

/// Assert to ensure that the size of the structure is 'only' 3 bytes
static_assert(sizeof(ColorRgba) == 4, "Incorrect size of ColorARGB");

///
/// Stream operator to write ColorRgb to an outputstream (format "'{'[alpha]', '[red]','[green]','[blue]'}'")
///
/// @param os The output stream
/// @param color The color to write
/// @return The output stream (with the color written to it)
///
inline std::ostream& operator<<(std::ostream& os, const ColorRgba& color)
{
	os << "{"
		<< color.alpha << ","
		<< color.red   << ","
		<< color.green << ","
		<< color.blue
	<< "}";

	return os;
}


<|start_filename|>libsrc/leddevice/LedDeviceTemplate.cpp<|end_filename|>
#include "LedDeviceTemplate.h"

LedDeviceTemplate::LedDeviceTemplate(const QJsonObject & /*deviceConfig*/)
{
}

LedDevice* LedDeviceTemplate::construct(const QJsonObject &deviceConfig)
{
	return new LedDeviceTemplate(deviceConfig);
}

bool LedDeviceTemplate::init(const QJsonObject &deviceConfig)
{
	bool isInitOK = false;

	// Initialise sub-class
	if ( LedDevice::init(deviceConfig) )
	{
		// Initialise LedDevice configuration and execution environment
		// ...
		if ( false /*Error during init*/)
		{
			//Build an errortext, illustrative
			QString errortext = QString ("Error message: %1").arg("errno/text");
			this->setInError(errortext);
			isInitOK = false;
		}
		else
		{
			isInitOK = true;
		}
	}
	return isInitOK;
}

int LedDeviceTemplate::open()
{
	int retval = -1;
	QString errortext;
	_isDeviceReady = false;

	// Try to open the LedDevice
	//...

	if ( false /*If opening failed*/ )
	{
		//Build an errortext, illustrative
		errortext = QString ("Failed to xxx. Error message: %1").arg("errno/text");
	}
	else
	{
		// Everything is OK, device is ready
		_isDeviceReady = true;
		retval = 0;
	}

	// On error/exceptions, set LedDevice in error
	if ( false /* retval < 0*/ )
	{
		this->setInError( errortext );
	}
	return retval;
}

int LedDeviceTemplate::close()
{
	// LedDevice specific closing activities
	//...
	int retval = 0;
	_isDeviceReady = false;

	// Test, if device requires closing
	if ( true /*If device is still open*/ )
	{
		// Close device
		// Everything is OK -> device is closed
	}
	return retval;
}

int LedDeviceTemplate::write(const std::vector<ColorRgb> & ledValues)
{
	int retval = -1;

	//...

	return retval;
}


<|start_filename|>libsrc/leddevice/dev_spi/LedDeviceWs2801.cpp<|end_filename|>
#include "LedDeviceWs2801.h"

LedDeviceWs2801::LedDeviceWs2801(const QJsonObject &deviceConfig)
	: ProviderSpi(deviceConfig)
{
}

LedDevice* LedDeviceWs2801::construct(const QJsonObject &deviceConfig)
{
	return new LedDeviceWs2801(deviceConfig);
}

bool LedDeviceWs2801::init(const QJsonObject &deviceConfig)
{
	bool isInitOK = ProviderSpi::init(deviceConfig);
	return isInitOK;
}

int LedDeviceWs2801::write(const std::vector<ColorRgb> &ledValues)
{
	const unsigned dataLen = _ledCount * sizeof(ColorRgb);
	const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());

	return writeBytes(dataLen, dataPtr);
}


<|start_filename|>libsrc/cec/CECHandler.cpp<|end_filename|>
#include <cec/CECHandler.h>
#include <utils/Logger.h>

#include <algorithm>

#include <libcec/cecloader.h>

#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>

/* Enable to turn on detailed CEC logs */
// #define VERBOSE_CEC

CECHandler::CECHandler()
{
	qRegisterMetaType<CECEvent>("CECEvent");

	 _logger = Logger::getInstance("CEC");

	_cecCallbacks            = getCallbacks();
	_cecConfig               = getConfig();
	_cecConfig.callbacks     = &_cecCallbacks;
	_cecConfig.callbackParam = this;
}

CECHandler::~CECHandler()
{
	stop();
}

bool CECHandler::start()
{
	if (_cecAdapter)
		return true;

	Info(_logger, "Starting CEC handler");

	_cecAdapter = LibCecInitialise(&_cecConfig);
	if(!_cecAdapter)
	{
		Error(_logger, "Failed loading libcec.so");
		return false;
	}

	auto adapters = getAdapters();
	if (adapters.isEmpty())
	{
		Error(_logger, "Failed to find CEC adapter");
		UnloadLibCec(_cecAdapter);
		_cecAdapter = nullptr;

		return false;
	}

	Info(_logger, "Auto detecting CEC adapter");
	bool opened = false;
	for (const auto & adapter : adapters)
	{
		printAdapter(adapter);

		if (!opened && openAdapter(adapter))
		{
			Info(_logger, "CEC Handler initialized with adapter : %s", adapter.strComName);

			opened = true;
		}
	}

	if (!opened)
	{
		UnloadLibCec(_cecAdapter);
		_cecAdapter = nullptr;
	}

	return opened;
}

void CECHandler::stop()
{
	if (_cecAdapter)
	{
		Info(_logger, "Stopping CEC handler");

		_cecAdapter->Close();
		UnloadLibCec(_cecAdapter);
		_cecAdapter = nullptr;
	}
}

CECConfig CECHandler::getConfig() const
{
	CECConfig configuration;

	const std::string name("HyperionCEC");
	name.copy(configuration.strDeviceName, std::min(name.size(), sizeof(configuration.strDeviceName)));

	configuration.deviceTypes.Add(CEC::CEC_DEVICE_TYPE_RECORDING_DEVICE);
	configuration.clientVersion = CEC::LIBCEC_VERSION_CURRENT;

	return configuration;
}

CECCallbacks CECHandler::getCallbacks() const
{
	CECCallbacks callbacks;

	callbacks.sourceActivated      = onCecSourceActivated;
	callbacks.commandReceived      = onCecCommandReceived;
	callbacks.alert                = onCecAlert;
	callbacks.logMessage           = onCecLogMessage;
	callbacks.keyPress             = onCecKeyPress;
	callbacks.configurationChanged = onCecConfigurationChanged;
	callbacks.menuStateChanged     = onCecMenuStateChanged;

	return callbacks;
}

QVector<CECAdapterDescriptor> CECHandler::getAdapters() const
{
	if (!_cecAdapter)
		return {};

	QVector<CECAdapterDescriptor> descriptors(16);
	int8_t size = _cecAdapter->DetectAdapters(descriptors.data(), descriptors.size(), nullptr, true /*quickscan*/);
	descriptors.resize(size);

	return descriptors;
}

bool CECHandler::openAdapter(const CECAdapterDescriptor & descriptor)
{
	if (!_cecAdapter)
		return false;

	if(!_cecAdapter->Open(descriptor.strComName))
	{
		Error(_logger, QString("Failed to open the CEC adaper on port %1")
			.arg(descriptor.strComName)
				.toLocal8Bit());

		return false;
	}
	return true;
}

void CECHandler::printAdapter(const CECAdapterDescriptor & descriptor) const
{
	Info(_logger, QString("CEC Adapter:").toLocal8Bit());
	Info(_logger, QString("\tName   : %1").arg(descriptor.strComName).toLocal8Bit());
	Info(_logger, QString("\tPath   : %1").arg(descriptor.strComPath).toLocal8Bit());
}

QString CECHandler::scan() const
{
	if (!_cecAdapter)
		return {};

	Info(_logger, "Starting CEC scan");

	QJsonArray devices;
	CECLogicalAddresses addresses = _cecAdapter->GetActiveDevices();
	for (int address = CEC::CECDEVICE_TV; address <= CEC::CECDEVICE_BROADCAST; ++address)
	{
		if (addresses[address])
		{
			CECLogicalAddress logicalAddress = (CECLogicalAddress)address;

			QJsonObject device;
			CECVendorId vendor = (CECVendorId)_cecAdapter->GetDeviceVendorId(logicalAddress);
			CECPowerStatus power = _cecAdapter->GetDevicePowerStatus(logicalAddress);

			device["name"    ] = _cecAdapter->GetDeviceOSDName(logicalAddress).c_str();
			device["vendor"  ] = _cecAdapter->ToString(vendor);
			device["address" ] = _cecAdapter->ToString(logicalAddress);
			device["power"   ] = _cecAdapter->ToString(power);

			devices << device;

			Info(_logger, QString("\tCECDevice: %1 / %2 / %3 / %4")
				.arg(device["name"].toString())
				.arg(device["vendor"].toString())
				.arg(device["address"].toString())
				.arg(device["power"].toString())
				.toLocal8Bit());
		}
	}

	return QJsonDocument(devices).toJson(QJsonDocument::Compact);
}

void CECHandler::onCecLogMessage(void * context, const CECLogMessage * message)
{
#ifdef VERBOSE_CEC
	CECHandler * handler = qobject_cast<CECHandler*>(static_cast<QObject*>(context));
	if (!handler)
		return;

	switch (message->level)
	{
	case CEC::CEC_LOG_ERROR:
		Error(handler->_logger, QString("%1")
			.arg(message->message)
				.toLocal8Bit());
		break;
	case CEC::CEC_LOG_WARNING:
		Warning(handler->_logger, QString("%1")
			.arg(message->message)
				.toLocal8Bit());
		break;
	case CEC::CEC_LOG_TRAFFIC:
	case CEC::CEC_LOG_NOTICE:
		Info(handler->_logger, QString("%1")
			.arg(message->message)
				.toLocal8Bit());
		break;
	case CEC::CEC_LOG_DEBUG:
		Debug(handler->_logger, QString("%1")
			.arg(message->message)
				.toLocal8Bit());
		break;
	default:
		break;
	}
#endif
}

void CECHandler::onCecKeyPress(void * context, const CECKeyPress * key)
{
#ifdef VERBOSE_CEC
	CECHandler * handler = qobject_cast<CECHandler*>(static_cast<QObject*>(context));
	if (!handler)
		return;

	CECAdapter * adapter = handler->_cecAdapter;

	Debug(handler->_logger, QString("CECHandler::onCecKeyPress: %1")
		.arg(adapter->ToString(key->keycode))
			.toLocal8Bit());
#endif
}

void CECHandler::onCecAlert(void * context, const CECAlert alert, const CECParameter data)
{
#ifdef VERBOSE_CEC
	CECHandler * handler = qobject_cast<CECHandler*>(static_cast<QObject*>(context));
	if (!handler)
		return;

	Error(handler->_logger, QString("CECHandler::onCecAlert: %1")
		.arg(alert)
			.toLocal8Bit());
#endif
}

void CECHandler::onCecConfigurationChanged(void * context, const CECConfig * configuration)
{
#ifdef VERBOSE_CEC
	CECHandler * handler = qobject_cast<CECHandler*>(static_cast<QObject*>(context));
	if (!handler)
		return;

	Debug(handler->_logger, QString("CECHandler::onCecConfigurationChanged: %1")
		.arg(configuration->strDeviceName)
			.toLocal8Bit());
#endif
}

int CECHandler::onCecMenuStateChanged(void * context, const CECMenuState state)
{
#ifdef VERBOSE_CEC
	CECHandler * handler = qobject_cast<CECHandler*>(static_cast<QObject*>(context));
	if (!handler)
		return 0;

	CECAdapter * adapter = handler->_cecAdapter;

	Debug(handler->_logger, QString("CECHandler::onCecMenuStateChanged: %1")
		.arg(adapter->ToString(state))
			.toLocal8Bit());
#endif
	return 0;
}

void CECHandler::onCecCommandReceived(void * context, const CECCommand * command)
{
	CECHandler * handler = qobject_cast<CECHandler*>(static_cast<QObject*>(context));
	if (!handler)
		return;

	CECAdapter * adapter = handler->_cecAdapter;

#ifdef VERBOSE_CEC
	Debug(handler->_logger, QString("CECHandler::onCecCommandReceived: %1 (%2 > %3)")
		.arg(adapter->ToString(command->opcode))
		.arg(adapter->ToString(command->initiator))
		.arg(adapter->ToString(command->destination))
			.toLocal8Bit());
#endif
	/* We do NOT check sender */
	// if (address == CEC::CECDEVICE_TV)
	{
		if (command->opcode == CEC::CEC_OPCODE_SET_STREAM_PATH)
		{
			Info(handler->_logger, QString("CEC source activated: %1")
				.arg(adapter->ToString(command->initiator))
					.toLocal8Bit());
			emit handler->cecEvent(CECEvent::On);
		}
		if (command->opcode == CEC::CEC_OPCODE_STANDBY)
		{
			Info(handler->_logger, QString("CEC source deactivated: %1")
				.arg(adapter->ToString(command->initiator))
					.toLocal8Bit());
			emit handler->cecEvent(CECEvent::Off);
		}
	}
}

void CECHandler::onCecSourceActivated(void * context, const CECLogicalAddress address, const uint8_t activated)
{
	/* We use CECHandler::onCecCommandReceived for
	 * source activated/deactivated notifications. */

#ifdef VERBOSE_CEC
	CECHandler * handler = qobject_cast<CECHandler*>(static_cast<QObject*>(context));
	if (!handler)
		return;

	CECAdapter * adapter = handler->_cecAdapter;

	Debug(handler->_logger, QString("CEC source %1 : %2")
		.arg(activated ? "activated" : "deactivated")
		.arg(adapter->ToString(address))
			.toLocal8Bit());
#endif
}




<|start_filename|>libsrc/leddevice/dev_spi/LedDeviceWs2812SPI.cpp<|end_filename|>
#include "LedDeviceWs2812SPI.h"

	/*
From the data sheet:

(TH+TL=1.25μs±600ns)

T0H,	 0 code, high level time,	 0.40µs ±0.150ns
T0L,	 0 code, low level time,	 0.85µs ±0.150ns
T1H,	 1 code, high level time,	 0.80µs ±0.150ns
T1L,	 1 code, low level time,	 0.45µs ±0.150ns
WT,	 Wait for the processing time,	 NA
Trst,	 Reset code,low level time,	 50µs (not anymore... need 300uS for latest revision)

To normalise the pulse times so they fit in 4 SPI bits:

On the assumption that the "low" time doesnt matter much

A SPI bit time of 0.40uS = 2.5 Mbit/sec
T0 is sent as 1000
T1 is sent as 1100

With a bit of excel testing, we can work out the maximum and minimum speeds:
2106000 MIN
2590500 AVG
3075000 MAX

Wait time:
Not Applicable for WS2812

Reset time:
using the max of 3075000, the bit time is 0.325
Reset time is 300uS = 923 bits = 116 bytes

*/

LedDeviceWs2812SPI::LedDeviceWs2812SPI(const QJsonObject &deviceConfig)
	: ProviderSpi(deviceConfig)
	  , SPI_BYTES_PER_COLOUR(4)
	  , SPI_FRAME_END_LATCH_BYTES(116)
	  , bitpair_to_byte {
		  0b10001000,
		  0b10001100,
		  0b11001000,
		  0b11001100,
		  }
{
}

LedDevice* LedDeviceWs2812SPI::construct(const QJsonObject &deviceConfig)
{
	return new LedDeviceWs2812SPI(deviceConfig);
}

bool LedDeviceWs2812SPI::init(const QJsonObject &deviceConfig)
{
	_baudRate_Hz = 2600000;

	bool isInitOK = false;

	// Initialise sub-class
	if ( ProviderSpi::init(deviceConfig) )
	{
		WarningIf(( _baudRate_Hz < 2106000 || _baudRate_Hz > 3075000 ), _log, "SPI rate %d outside recommended range (2106000 -> 3075000)", _baudRate_Hz);

		_ledBuffer.resize(_ledRGBCount * SPI_BYTES_PER_COLOUR + SPI_FRAME_END_LATCH_BYTES, 0x00);

		isInitOK = true;
	}

	return isInitOK;
}

int LedDeviceWs2812SPI::write(const std::vector<ColorRgb> &ledValues)
{
	unsigned spi_ptr = 0;
	const int SPI_BYTES_PER_LED = sizeof(ColorRgb) * SPI_BYTES_PER_COLOUR;

	for (const ColorRgb& color : ledValues)
	{
		uint32_t colorBits = ((unsigned int)color.red << 16)
							 | ((unsigned int)color.green << 8)
							 | color.blue;

		for (int j=SPI_BYTES_PER_LED - 1; j>=0; j--)
		{
			_ledBuffer[spi_ptr+j] = bitpair_to_byte[ colorBits & 0x3 ];
			colorBits >>= 2;
		}
		spi_ptr += SPI_BYTES_PER_LED;
	}

	for (int j=0; j < SPI_FRAME_END_LATCH_BYTES; j++)
	{
		_ledBuffer[spi_ptr++] = 0;
	}

	return writeBytes(_ledBuffer.size(), _ledBuffer.data());
}


<|start_filename|>src/hyperion-v4l2/ScreenshotHandler.cpp<|end_filename|>
// Qt includes
#include <QImage>
#include <QCoreApplication>
#include <QVector>
#include <algorithm>

// hyperion-v4l2 includes
#include "ScreenshotHandler.h"

ScreenshotHandler::ScreenshotHandler(const QString & filename, const QRectF & signalDetectionOffset)
	: _filename(filename)
	, _signalDetectionOffset(signalDetectionOffset)
{
}

ScreenshotHandler::~ScreenshotHandler()
{
}

void ScreenshotHandler::receiveImage(const Image<ColorRgb> & image)
{
	findNoSignalSettings(image);
	// store as PNG
	QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888);
	pngImage.save(_filename);

	// Quit the application after the first image
	QCoreApplication::quit();
}

bool ScreenshotHandler::findNoSignalSettings(const Image<ColorRgb> & image)
{
	double x_frac_min = _signalDetectionOffset.x();
	double y_frac_min = _signalDetectionOffset.y();
	double x_frac_max = _signalDetectionOffset.width();
	double y_frac_max = _signalDetectionOffset.height();

	unsigned xOffset  = image.width()  * x_frac_min;
	unsigned yOffset  = image.height() * y_frac_min;
	unsigned xMax     = image.width()  * x_frac_max;
	unsigned yMax     = image.height() * y_frac_max;

	ColorRgb noSignalThresholdColor = {0,0,0};

	unsigned yMid = (yMax+yOffset) / 2;
	ColorRgb redThresoldColor   = {255,75,75};
	ColorRgb greenThresoldColor = {75,255,75};
	ColorRgb blueThresoldColor  = {75,75,255};

	QVector<unsigned> redOffsets;
	QVector<unsigned> redCounts;
	QVector<unsigned> greenOffsets;
	QVector<unsigned> greenCounts;
	QVector<unsigned> blueOffsets;
	QVector<unsigned> blueCounts;

	unsigned currentColor = 255;
	for (unsigned x = xOffset; x < xMax; ++x)
	{
		ColorRgb rgb = image(x, yMid);
		if (rgb <= redThresoldColor)
		{
			if ( currentColor != 0)
			{
				redOffsets.append(x);
				redCounts.append(1);
			}
			else
			{
				redCounts[redCounts.size()-1]++;
			}
			currentColor = 0;
		}
		if (rgb <= greenThresoldColor){
			if ( currentColor != 1)
			{
				greenOffsets.append(x);
				greenCounts.append(1);
			}
			else
			{
				greenCounts[greenCounts.size()-1]++;
			}
			currentColor = 1;
		}
		if (rgb <= blueThresoldColor)
		{
			if ( currentColor != 2)
			{
				blueOffsets.append(x);
				blueCounts.append(1);
			}
			else
			{
				blueCounts[blueCounts.size()-1]++;
			}
			currentColor = 2;
		}
	}

	auto itR = std::max_element(std::begin(redCounts), std::end(redCounts));
	auto itG = std::max_element(std::begin(greenCounts), std::end(greenCounts));
	auto itB = std::max_element(std::begin(blueCounts), std::end(blueCounts));

	//std::cout << *itR << " " << *itG << " " << *itB << std::endl;
	double xOffsetSuggested = xOffset;
	double yOffsetSuggested = yOffset;
	double xMaxSuggested    = xMax;
	double yMaxSuggested    = yMax;
	bool   noSignalBlack    = false;

	noSignalThresholdColor = {0,0,0};
	if (*itR >= *itG && *itR >=  *itB && *itR > 1)
	{
		xOffsetSuggested       = redOffsets[redCounts.indexOf(*itR)];
		xMaxSuggested          = xOffsetSuggested + *itR;
		noSignalThresholdColor = redThresoldColor;
	}
	else if (*itG >= *itR && *itG >=  *itB && *itG > 1 )
	{
		xOffsetSuggested       = greenOffsets[greenCounts.indexOf(*itG)];
		xMaxSuggested          = xOffsetSuggested + *itG;
		noSignalThresholdColor = greenThresoldColor;
	}
	else if ( *itB > 1 )
	{
		xOffsetSuggested       = blueOffsets[blueCounts.indexOf(*itB)];
		xMaxSuggested          = xOffsetSuggested + *itB;
		noSignalThresholdColor = blueThresoldColor;
	}
	else
	{
		noSignalThresholdColor = {75,75,75};
		noSignalBlack = true;
	}

	// serach vertical max
	if (!noSignalBlack)
	{
		unsigned xMid = (xMaxSuggested + xOffsetSuggested) / 2;
		for (unsigned y = yMid; y >= yOffset && yOffsetSuggested != y; --y)
		{
			ColorRgb rgb = image(xMid, y);
			if (rgb <= noSignalThresholdColor)
			{
				yOffsetSuggested = y;
			}
		}

		for (unsigned y = yMid; y <= yMax && yMaxSuggested != y; ++y)
		{
			ColorRgb rgb = image(xMid, y);
			if (rgb <= noSignalThresholdColor)
			{
				yMaxSuggested = y;
			}
		}
	}

	// optimize thresold color
	noSignalThresholdColor = {0,0,0};
	for (unsigned x = xOffsetSuggested; x < xMaxSuggested; ++x)
	{
		for (unsigned y = yOffsetSuggested; y < yMaxSuggested; ++y)
		{
			ColorRgb rgb = image(x, y);
			if (rgb >= noSignalThresholdColor)
			{
				noSignalThresholdColor = rgb;
			}
		}
	}

	// calculate fractional values
	xOffsetSuggested = (int)(((float)xOffsetSuggested/image.width())*100+0.5)/100.0;
	xMaxSuggested    = (int)(((float)xMaxSuggested/image.width())*100)/100.0;
	yOffsetSuggested = (int)(((float)yOffsetSuggested/image.height())*100+0.5)/100.0;
	yMaxSuggested    = (int)(((float)yMaxSuggested/image.height())*100)/100.0;
	double thresholdRed   = (int)(((float)noSignalThresholdColor.red/255.0f)*100+0.5)/100.0;
	double thresholdGreen = (int)(((float)noSignalThresholdColor.green/255.0f)*100+0.5)/100.0;
	double thresholdBlue  = (int)(((float)noSignalThresholdColor.blue/255.0f)*100+0.5)/100.0;
	thresholdRed   = (thresholdRed<0.1f)  ?0.1f : thresholdRed;
	thresholdGreen = (thresholdGreen<0.1f)?0.1f : thresholdGreen;
	thresholdBlue  = (thresholdBlue<0.1f) ?0.1f : thresholdBlue;

	std::cout << std::endl << "Signal detection informations"
	          << std::endl << "============================="
	          << std::endl << "dimension after decimation: " << image.width() << " x " << image.height()
	          << std::endl << "signal detection area  : " << xOffset << "," << yOffset << " x "  << xMax << "," << yMax  << std::endl << std::endl;

	// check if values make sense
	if (thresholdRed < 0.5 && thresholdGreen < 0.5 && thresholdBlue < 0.5 && thresholdRed > 0.15 && thresholdGreen > 0.15 && thresholdBlue > 0.15)
	{
		std::cout << "WARNING \"no signal image\" is to dark, signal detection is not relaiable." << std::endl;
	}

	if (thresholdRed > 0.5 && thresholdGreen > 0.5 && thresholdBlue > 0.5)
	{
		std::cout << "WARNING \"no signal image\" is to bright, signal detection is not relaiable." << std::endl;
	}

	if (thresholdRed > thresholdGreen && thresholdRed > thresholdBlue && ((thresholdRed-thresholdGreen) <= 0.5 || (thresholdRed-thresholdBlue) <= 0.5))
	{
		std::cout << "WARNING difference between threshold color and the other color components is to small, signal detection might have problems." << std::endl;
	}

	if (thresholdGreen > thresholdRed && thresholdGreen > thresholdBlue && ((thresholdGreen-thresholdRed) <= 0.5 || (thresholdGreen-thresholdBlue) <= 0.5))
	{
		std::cout << "WARNING difference between threshold color and the other color components is to small, signal detection might have problems." << std::endl;
	}

	if (thresholdBlue > thresholdGreen && thresholdBlue > thresholdRed && ((thresholdBlue-thresholdGreen) <= 0.5 || (thresholdBlue-thresholdRed) <= 0.5))
	{
		std::cout << "WARNING difference between threshold color and the other color components is to small, signal detection might have problems." << std::endl;
	}

	if (noSignalBlack)
	{
		std::cout << "WARNING no red, green or blue \"no signal area\" detected, signal detection might have problems." << std::endl;
	}

	if (xOffsetSuggested >= xMaxSuggested || (xMaxSuggested - xOffsetSuggested) < 0.029 )
	{
		std::cout << "WARNING horizontal values of signal detection are invalid or detection area is to small, signal detection is not relaiable." << std::endl;
	}

	if (yOffsetSuggested >= yMaxSuggested || (yMaxSuggested - yOffsetSuggested) < 0.029 )
	{
		std::cout << "WARNING horizontal values of signal detection are invalid or detection area is to small, signal detection is not relaiable." << std::endl;
	}

	std::cout << std::endl
	          << "suggested config values for signal detection:" << std::endl
	          << "\t\"redSignalThreshold\"   : "               << thresholdRed     << "," << std::endl
	          << "\t\"greenSignalThreshold\" : "               << thresholdGreen   << "," << std::endl
	          << "\t\"blueSignalThreshold\"  : "               << thresholdBlue    << "," << std::endl
	          << "\t\"signalDetectionHorizontalOffsetMin\" : " << xOffsetSuggested << "," << std::endl
	          << "\t\"signalDetectionVerticalOffsetMin\"   : " << yOffsetSuggested << "," << std::endl
	          << "\t\"signalDetectionHorizontalOffsetMax\" : " << xMaxSuggested    << "," << std::endl
	          << "\t\"signalDetectionVerticalOffsetMax\"   : " << yMaxSuggested    << std::endl;

	return true;
}





<|start_filename|>src/hyperiond/console.h<|end_filename|>
#include <Windows.h>

// https://stackoverflow.com/a/57241985
void CreateConsole()
{
    if (!AllocConsole()) {
        // Add some error handling here.
        // You can call GetLastError() to get more info about the error.
        return;
    }

    // std::cout, std::clog, std::cerr, std::cin
    FILE* fDummy;
    freopen_s(&fDummy, "CONOUT$", "w", stdout);
    freopen_s(&fDummy, "CONOUT$", "w", stderr);
    freopen_s(&fDummy, "CONIN$", "r", stdin);
	SetConsoleTitle(TEXT("Hyperion"));
}


<|start_filename|>libsrc/leddevice/dev_net/LedDeviceUdpRaw.cpp<|end_filename|>
#include "LedDeviceUdpRaw.h"

const ushort RAW_DEFAULT_PORT=5568;

LedDeviceUdpRaw::LedDeviceUdpRaw(const QJsonObject &deviceConfig)
	: ProviderUdp(deviceConfig)
{
}

LedDevice* LedDeviceUdpRaw::construct(const QJsonObject &deviceConfig)
{
	return new LedDeviceUdpRaw(deviceConfig);
}

bool LedDeviceUdpRaw::init(const QJsonObject &deviceConfig)
{
	_port = RAW_DEFAULT_PORT;

	// Initialise sub-class
	bool isInitOK = ProviderUdp::init(deviceConfig);
	return isInitOK;
}

int LedDeviceUdpRaw::write(const std::vector<ColorRgb> &ledValues)
{
	const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());

	return writeBytes(_ledRGBCount, dataPtr);
}


<|start_filename|>include/utils/DefaultSignalHandler.h<|end_filename|>
#pragma once

namespace DefaultSignalHandler
{
	void install();
}


<|start_filename|>libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.cpp<|end_filename|>
// stl includes
#include <exception>
#include <cstring>

// Local Hyperion includes
#include "LedDeviceHyperionUsbasp.h"

// Constants which define the Hyperion USBasp device
namespace {
uint16_t _usbVendorId = 0x16c0;
uint16_t _usbProductId = 0x05dc;
QString  _usbProductDescription = "Hyperion led controller";
}

LedDeviceHyperionUsbasp::LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig)
	: LedDevice(deviceConfig)
	, _libusbContext(nullptr)
	, _deviceHandle(nullptr)
{
}

LedDeviceHyperionUsbasp::~LedDeviceHyperionUsbasp()
{
	if (_libusbContext != nullptr)
	{
		libusb_exit(_libusbContext);
	}
}

LedDevice* LedDeviceHyperionUsbasp::construct(const QJsonObject &deviceConfig)
{
	return new LedDeviceHyperionUsbasp(deviceConfig);
}

bool LedDeviceHyperionUsbasp::init(const QJsonObject &deviceConfig)
{
	bool isInitOK = false;

	// Initialise sub-class
	if ( LedDevice::init(deviceConfig) )
	{
		QString ledType = deviceConfig["ledType"].toString("ws2801");
		if (ledType != "ws2801" && ledType != "ws2812")
		{
			QString errortext = QString ("Invalid ledType; must be 'ws2801' or 'ws2812'.");
			this->setInError(errortext);
			isInitOK = false;
		}
		else
		{
			_writeLedsCommand = (ledType == "ws2801") ? CMD_WRITE_WS2801 : CMD_WRITE_WS2812;

			int error;
			// initialize the USB context
			if ( (error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS )
			{
				_libusbContext = nullptr;

				QString errortext = QString ("Error while initializing USB context(%1):%2").arg(error).arg(libusb_error_name(error));
				this->setInError(errortext);
				isInitOK = false;
			}
			else
			{
				Debug(_log, "USB context initialized");
				//libusb_set_debug(_libusbContext, 3);

				// retrieve the list of USB devices
				libusb_device ** deviceList;
				ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);

				// iterate the list of devices
				for (ssize_t i = 0 ; i < deviceCount; ++i)
				{
					// try to open and initialize the device
					if ( testAndOpen(deviceList[i]) == 0 )
					{
						_device = deviceList[i];
						// a device was successfully opened. break from list
						break;
					}
				}

				// free the device list
				libusb_free_device_list(deviceList, 1);

				if (_deviceHandle == nullptr)
				{
					QString errortext;
					errortext = QString ("No %1 has been found").arg( _usbProductDescription);
					this->setInError( errortext );
				}
				else
				{
					isInitOK = true;
				}
			}
		}
	}

	return isInitOK;
}

int LedDeviceHyperionUsbasp::open()
{
	int retval = -1;
	_isDeviceReady = false;

	if ( libusb_open(_device, &_deviceHandle) != LIBUSB_SUCCESS )
	{
		QString errortext = QString ("Failed to open [%1]").arg(_usbProductDescription);
		this->setInError(errortext);
	}
	else
	{
		// Everything is OK -> enable device
		_isDeviceReady = true;
		retval = 0;
	}

	return retval;
}

int LedDeviceHyperionUsbasp::close()
{
	int retval = 0;
	_isDeviceReady = false;

	// LedDevice specific closing activities
	if (_deviceHandle != nullptr)
	{
		libusb_release_interface(_deviceHandle, 0);
		libusb_attach_kernel_driver(_deviceHandle, 0);
		libusb_close(_deviceHandle);

		_deviceHandle = nullptr;
	}
	return retval;
}

int LedDeviceHyperionUsbasp::testAndOpen(libusb_device * device)
{
	libusb_device_descriptor deviceDescriptor;
	int error = libusb_get_device_descriptor(device, &deviceDescriptor);
	if (error != LIBUSB_SUCCESS)
	{
		Error(_log, "Error while retrieving device descriptor(%d): %s", error, libusb_error_name(error));
		return -1;
	}

	if (deviceDescriptor.idVendor == _usbVendorId &&
			deviceDescriptor.idProduct == _usbProductId &&
			deviceDescriptor.iProduct != 0 &&
			getString(device, deviceDescriptor.iProduct) == _usbProductDescription)
	{
		// get the hardware address
		int busNumber = libusb_get_bus_number(device);
		int addressNumber = libusb_get_device_address(device);

		Info(_log, "%s found: bus=%d address=%d", QSTRING_CSTR(_usbProductDescription), busNumber, addressNumber);

		// TODO: Check, if exceptions via try/catch need to be replaced in Qt environment
		try
		{
			_deviceHandle = openDevice(device);
			Info(_log, "%s successfully opened", QSTRING_CSTR(_usbProductDescription) );
			return 0;
		}
		catch(int e)
		{
			_deviceHandle = nullptr;
			Error(_log, "Unable to open %s. Searching for other device(%d): %s", QSTRING_CSTR(_usbProductDescription), e, libusb_error_name(e));
		}
	}

	return -1;
}

int LedDeviceHyperionUsbasp::write(const std::vector<ColorRgb> &ledValues)
{
	int nbytes = libusb_control_transfer(
				_deviceHandle, // device handle
				static_cast<uint8_t>( LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT ), // request type
				_writeLedsCommand, // request
				0, // value
				0, // index
				(uint8_t *) ledValues.data(), // data
				(3*_ledCount) & 0xffff, // length
				5000); // timeout

	// Disabling interrupts for a little while on the device results in a PIPE error. All seems to keep functioning though...
	if(nbytes < 0 && nbytes != LIBUSB_ERROR_PIPE)
	{
		Error(_log, "Error while writing data to %s (%s)",  QSTRING_CSTR(_usbProductDescription), libusb_error_name(nbytes));
		return -1;
	}

	return 0;
}

libusb_device_handle * LedDeviceHyperionUsbasp::openDevice(libusb_device *device)
{
	Logger * log = Logger::getInstance("LedDevice");
	libusb_device_handle * handle = nullptr;

	int error = libusb_open(device, &handle);
	if (error != LIBUSB_SUCCESS)
	{
		Error(log, "unable to open device(%d): %s",error,libusb_error_name(error));
		throw error;
	}

	// detach kernel driver if it is active
	if (libusb_kernel_driver_active(handle, 0) == 1)
	{
		error = libusb_detach_kernel_driver(handle, 0);
		if (error != LIBUSB_SUCCESS)
		{
			Error(log, "unable to detach kernel driver(%d): %s",error,libusb_error_name(error));
			libusb_close(handle);
			throw error;
		}
	}

	error = libusb_claim_interface(handle, 0);
	if (error != LIBUSB_SUCCESS)
	{
		Error(log, "unable to claim interface(%d): %s", error, libusb_error_name(error));
		libusb_attach_kernel_driver(handle, 0);
		libusb_close(handle);
		throw error;
	}

	return handle;
}

QString LedDeviceHyperionUsbasp::getString(libusb_device * device, int stringDescriptorIndex)
{
	libusb_device_handle * handle = nullptr;

	int error = libusb_open(device, &handle);
	if (error != LIBUSB_SUCCESS)
	{
		throw error;
	}

	char buffer[256];
	error = libusb_get_string_descriptor_ascii(handle, stringDescriptorIndex, reinterpret_cast<unsigned char *>(buffer), sizeof(buffer));
	if (error <= 0)
	{
		libusb_close(handle);
		throw error;
	}

	libusb_close(handle);
	return QString(QByteArray(buffer, error));
}


<|start_filename|>include/cec/CECEvent.h<|end_filename|>
#pragma once

enum class CECEvent
{
        On,
        Off
};



<|start_filename|>libsrc/utils/RgbToRgbw.cpp<|end_filename|>
#include <utils/ColorRgb.h>
#include <utils/ColorRgbw.h>
#include <utils/RgbToRgbw.h>
#include <utils/Logger.h>

namespace RGBW {

WhiteAlgorithm stringToWhiteAlgorithm(const QString& str)
{
	if (str == "subtract_minimum")
	{
		return WhiteAlgorithm::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;
	}
	if (str.isEmpty() || str == "white_off")
	{
		return WhiteAlgorithm::WHITE_OFF;
	}
	return WhiteAlgorithm::INVALID;
}

void Rgb_to_Rgbw(ColorRgb input, ColorRgbw * output, WhiteAlgorithm algorithm)
{
	switch (algorithm)
	{
		case WhiteAlgorithm::SUBTRACT_MINIMUM:
		{
			output->white = static_cast<uint8_t>(qMin(qMin(input.red, input.green), input.blue));
			output->red   = input.red   - output->white;
			output->green = input.green - output->white;
			output->blue  = input.blue  - output->white;
			break;
		}

		case WhiteAlgorithm::SUB_MIN_WARM_ADJUST:
		{
			// http://forum.garagecube.com/viewtopic.php?t=10178
			// warm white
			const double F1(0.274);
			const double F2(0.454);
			const double F3(2.333);

			output->white = static_cast<uint8_t>(qMin(input.red*F1,qMin(input.green*F2,input.blue*F3)));
			output->red   = input.red   - static_cast<uint8_t>(output->white/F1);
			output->green = input.green - static_cast<uint8_t>(output->white/F2);
			output->blue  = input.blue  - static_cast<uint8_t>(output->white/F3);
			break;
		}

		case WhiteAlgorithm::SUB_MIN_COOL_ADJUST:
		{
			// http://forum.garagecube.com/viewtopic.php?t=10178
			// cold white
			const double F1(0.299);
			const double F2(0.587);
			const double F3(0.114);

			output->white = static_cast<uint8_t>(qMin(input.red*F1,qMin(input.green*F2,input.blue*F3)));
			output->red   = input.red   - static_cast<uint8_t>(output->white/F1);
			output->green = input.green - static_cast<uint8_t>(output->white/F2);
			output->blue  = input.blue  - static_cast<uint8_t>(output->white/F3);
			break;
		}

		case WhiteAlgorithm::WHITE_OFF:
		{
			output->red = input.red;
			output->green = input.green;
			output->blue = input.blue;
			output->white = 0;
			break;
		}
		default:
			break;
	}
}

};


<|start_filename|>include/python/PythonProgram.h<|end_filename|>
#pragma once

#include <QByteArray>
#include <QString>

// Python includes
// collide of qt slots macro
#undef slots
#include "Python.h"
#define slots

class Logger;

class PythonProgram
{
public:
	PythonProgram(const QString & name, Logger * log);
	~PythonProgram();

	void execute(const QByteArray &python_code);

private:
	QString _name;
	Logger* _log;
	PyThreadState* _tstate;
};


<|start_filename|>libsrc/api/JSONRPC_schema/schema-leddevice.json<|end_filename|>
{
	"type":"object",
	"required":true,
	"properties":{
		"command": {
			"type" : "string",
			"required" : true,
			"enum" : ["leddevice"]
		},
		"tan" : {
			"type" : "integer"
		},
		"subcommand": {
			"type" : "string",
			"required" : true,
			"enum" : ["discover","getProperties","identify"]
		},
		"ledDeviceType": {
			"type" : "string",
			"required" : true
		},
		"params": {
			"type" : "object",
			"required" : false
		}
	},
	"additionalProperties": false
}


<|start_filename|>libsrc/flatbufserver/FlatBufferClient.h<|end_filename|>
#pragma once

// util
#include <utils/Logger.h>
#include <utils/Image.h>
#include <utils/ColorRgb.h>
#include <utils/Components.h>

// flatbuffer FBS
#include "hyperion_reply_generated.h"
#include "hyperion_request_generated.h"

class QTcpSocket;
class QTimer;

namespace flatbuf {
	class HyperionRequest;
}

///
/// @brief Socket (client) of FlatBufferServer
///
class FlatBufferClient : public QObject
{
    Q_OBJECT
public:
	///
	/// @brief Construct the client
	/// @param socket   The socket
	/// @param timeout  The timeout when a client is automatically disconnected and the priority unregistered
	/// @param parent   The parent
	///
	explicit FlatBufferClient(QTcpSocket* socket, int timeout, QObject *parent = nullptr);

signals:
	///
	/// @brief forward register data to HyperionDaemon
	///
	void registerGlobalInput(int priority, hyperion::Components component, const QString& origin = "FlatBuffer", const QString& owner = "", unsigned smooth_cfg = 0);

	///
	/// @brief Forward clear command to HyperionDaemon
	///
	void clearGlobalInput(int priority, bool forceClearAll=false);

	///
	/// @brief forward prepared image to HyperionDaemon
	///
	bool setGlobalInputImage(int priority, const Image<ColorRgb>& image, int timeout_ms, bool clearEffect = false);

	///
	/// @brief Forward requested color
	///
	void setGlobalInputColor(int priority, const std::vector<ColorRgb> &ledColor, int timeout_ms, const QString& origin = "FlatBuffer" ,bool clearEffects = true);

	///
	/// @brief Emits whenever the client disconnected
	///
	void clientDisconnected();

public slots:
	///
	/// @brief Requests a registration from the client
	///
	void registationRequired(int priority);

	///
	/// @brief close the socket and call disconnected()
	///
	void forceClose();

private slots:
	///
	/// @brief Is called whenever the socket got new data to read
	///
	void readyRead();

	///
	/// @brief Is called when the socket closed the connection, also requests thread exit
	///
	void disconnected();

private:
	///
	/// @brief Handle the received message
	///
	void handleMessage(const hyperionnet::Request * req);

	///
	/// Register new priority
	///
	void handleRegisterCommand(const hyperionnet::Register *regReq);

	///
	/// @brief Hande Color message
	///
	void handleColorCommand(const hyperionnet::Color *colorReq);

	///
	/// Handle an incoming Image message
	///
	/// @param image the incoming image
	///
	void handleImageCommand(const hyperionnet::Image *image);

	///
	/// @brief Handle clear command
	///
	/// @param clear the incoming clear request
	///
	void handleClearCommand(const hyperionnet::Clear *clear);

	///
	/// Send handle not implemented
	///
	void handleNotImplemented();

	///
	/// Send a message to the connected client
	///
	void sendMessage();

	///
	/// Send a standard reply indicating success
	///
	void sendSuccessReply();

	///
	/// Send an error message back to the client
	///
	/// @param error String describing the error
	///
	void sendErrorReply(const std::string & error);

private:
	Logger *_log;
	QTcpSocket *_socket;
	const QString _clientAddress;
	QTimer *_timeoutTimer;
	int _timeout;
	int _priority;

	QByteArray _receiveBuffer;

	// Flatbuffers builder
	flatbuffers::FlatBufferBuilder _builder;
};


<|start_filename|>include/python/PythonInit.h<|end_filename|>
#pragma once

///
/// @brief Handle the PythonInit, module registers and DeInit
///
class PythonInit
{
private:
	friend class HyperionDaemon;

	PythonInit();
	~PythonInit();
};


<|start_filename|>include/commandline/ImageOption.h<|end_filename|>
#ifndef HYPERION_IMAGEOPTION_H
#define HYPERION_IMAGEOPTION_H

#include "Option.h"
#include <QImage>
#include <QCommandLineParser>

namespace commandline
{

class ImageOption: public Option
{
protected:
    QImage _image;

public:
    ImageOption(const QString &name,
                const QString &description = QString(),
                const QString &valueName = QString(),
                const QString &defaultValue = QString()
    )
        : Option(name, description, valueName, defaultValue)
    {}

    ImageOption(const QStringList &names,
                const QString &description = QString(),
                const QString &valueName = QString(),
                const QString &defaultValue = QString()
    )
        : Option(names, description, valueName, defaultValue)
    {}

    ImageOption(const QCommandLineOption &other)
        : Option(other)
    {}

    bool validate(Parser & parser, QString & value) override;
    QImage& getImage(Parser &parser) { return _image; }
};

}

#endif //HYPERION_IMAGEOPTION_H


<|start_filename|>cmake/FindCoreFoundation.cmake<|end_filename|>
# -----------------------------------------------------------------------------
# Find IOKit framework (Mac OS X).
#
# Define:
# CoreFoundation_FOUND
# CoreFoundation_INCLUDE_DIR
# CoreFoundation_LIBRARY

set(CoreFoundation_FOUND false)
set(CoreFoundation_INCLUDE_DIR)
set(CoreFoundation_LIBRARY)

if(APPLE)
# The only platform it makes sense to check for CoreFoundation
	find_library(CoreFoundation CoreFoundation)
	if(CoreFoundation)
		set(CoreFoundation_FOUND true)
		set(CoreFoundation_INCLUDE_DIR ${CoreFoundation})
		set(CoreFoundation_LIBRARY ${CoreFoundation})
	endif()
endif()


<|start_filename|>libsrc/leddevice/dev_net/LedDeviceNanoleaf.h<|end_filename|>
#ifndef LEDEVICENANOLEAF_H
#define LEDEVICENANOLEAF_H

// LedDevice includes
#include <leddevice/LedDevice.h>
#include "ProviderRestApi.h"
#include "ProviderUdp.h"

// Qt includes
#include <QString>
#include <QNetworkAccessManager>

///
/// Implementation of the LedDevice interface for sending to
/// Nanoleaf devices via network by using the 'external control' protocol.
///
class LedDeviceNanoleaf : public ProviderUdp
{
public:
	///
	/// @brief Constructs LED-device for Nanoleaf LightPanels (aka Aurora) or Canvas
	///
	/// following code shows all configuration options
	/// @code
	/// "device" :
	/// {
	///     "type" : "nanoleaf"
	///     "host" : "hostname or IP",
	///     "token": "<PASSWORD> Token",
	/// },
	///@endcode
	///
	/// @param deviceConfig Device's configuration as JSON-Object
	///
	explicit LedDeviceNanoleaf(const QJsonObject& deviceConfig);

	///
	/// @brief Destructor of the LED-device
	///
	~LedDeviceNanoleaf() override;

	///
	/// @brief Constructs the LED-device
	///
	/// @param[in] deviceConfig Device's configuration as JSON-Object
	/// @return LedDevice constructed
	static LedDevice* construct(const QJsonObject& deviceConfig);

	///
	/// @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
	///
	QJsonObject discover(const QJsonObject& params) override;

	///
	/// @brief Get the Nanoleaf device's resource properties
	///
	/// Following parameters are required
	/// @code
	/// {
	///     "host"  : "hostname or IP [:port]",
	///     "token" : "<PASSWORD> token",
	///     "filter": "resource to query", root "/" is used, if empty
	/// }
	///@endcode
	///
	/// @param[in] params Parameters to query device
	/// @return A JSON structure holding the device's properties
	///
	QJsonObject getProperties(const QJsonObject& params) override;

	///
	/// @brief Send an update to the Nanoleaf device to identify it.
	///
	/// Following parameters are required
	/// @code
	/// {
	///     "host"  : "hostname or IP [:port]",
	///     "token" : "<PASSWORD>",
	/// }
	///@endcode
	///
	/// @param[in] params Parameters to address device
	///
	void identify(const QJsonObject& params) override;

protected:

	///
	/// @brief Initialise the Nanoleaf device's configuration and network address details
	///
	/// @param[in] deviceConfig the JSON device configuration
	/// @return True, if success
	///
	bool init(const QJsonObject& deviceConfig) override;

	///
	/// @brief Opens the output device.
	///
	/// @return Zero on success (i.e. device is ready), else negative
	///
	int open() override;

	///
	/// @brief Writes the RGB-Color values to the LEDs.
	///
	/// @param[in] ledValues The RGB-color per LED
	/// @return Zero on success, else negative
	//////
	int write(const std::vector<ColorRgb>& ledValues) override;

	///
	/// @brief Power-/turn on the Nanoleaf device.
	///
	/// @brief Store the device's original state.
	///
	bool powerOn() override;

	///
	/// @brief Power-/turn off the Nanoleaf device.
	///
	/// @return True if success
	///
	bool powerOff() override;

private:

	///
	/// @brief Initialise the access to the REST-API wrapper
	///
	/// @param[in] host
	/// @param[in] port
	/// @param[in] authentication token
	///
	/// @return True, if success
	///
	bool initRestAPI(const QString& hostname, int port, const QString& token);

	///
	/// @brief Get Nanoleaf device details and configuration
	///
	/// @return True, if Nanoleaf device capabilities fit configuration
	///
	bool initLedsConfiguration();

	///
	/// @brief Change Nanoleaf device to External Control (UDP) mode
	///
	/// @return Response from device
	///@brief
	QJsonDocument changeToExternalControlMode();

	///
	/// @brief Get command to power Nanoleaf device on or off
	///
	/// @param isOn True, if to switch on device
	/// @return Command to switch device on/off
	///
	QString getOnOffRequest(bool isOn) const;

	///REST-API wrapper
	ProviderRestApi* _restApi;

	QString _hostname;
	int  _apiPort;
	QString _authToken;

	bool _topDown;
	bool _leftRight;
	int _startPos;
	int _endPos;

	//Nanoleaf device details
	QString _deviceModel;
	QString _deviceFirmwareVersion;
	ushort _extControlVersion;

	/// The number of panels with LEDs
	int _panelLedCount;

	/// Array of the panel ids.
	QVector<int> _panelIds;
};

#endif // LEDEVICENANOLEAF_H


<|start_filename|>libsrc/utils/ColorRgbw.cpp<|end_filename|>
// Local includes
#include <utils/ColorRgbw.h>

const ColorRgbw ColorRgbw::BLACK  = {   0,   0,   0,   0 };
const ColorRgbw ColorRgbw::RED    = { 255,   0,   0,   0 };
const ColorRgbw ColorRgbw::GREEN  = {   0, 255,   0,   0 };
const ColorRgbw ColorRgbw::BLUE   = {   0,   0, 255,   0 };
const ColorRgbw ColorRgbw::YELLOW = { 255, 255,   0,   0 };
const ColorRgbw ColorRgbw::WHITE  = {   0,   0,   0, 255 };


<|start_filename|>include/utils/settings.h<|end_filename|>
#pragma once
#include <QString>
#include <QJsonDocument>

///
/// @brief Provide util methods to work with SettingsManager class
///
namespace settings {
	// all available settings sections
	enum type  {
		BGEFFECT,
		FGEFFECT,
		BLACKBORDER,
		BOBLSERVER,
		COLOR,
		DEVICE,
		EFFECTS,
		NETFORWARD,
		SYSTEMCAPTURE,
		GENERAL,
		V4L2,
		JSONSERVER,
		LEDCONFIG,
		LEDS,
		LOGGER,
		SMOOTHING,
		WEBSERVER,
		INSTCAPTURE,
		NETWORK,
		FLATBUFSERVER,
		PROTOSERVER,
		INVALID
	};

	///
	/// @brief Convert settings::type to string representation
	/// @param  type  The settings::type from enum
	/// @return       The settings type as string
	///
	inline QString typeToString(type type)
	{
		switch (type)
		{
			case BGEFFECT:      return "backgroundEffect";
			case FGEFFECT:      return "foregroundEffect";
			case BLACKBORDER:   return "blackborderdetector";
			case BOBLSERVER:    return "boblightServer";
			case COLOR:         return "color";
			case DEVICE:        return "device";
			case EFFECTS:       return "effects";
			case NETFORWARD:    return "forwarder";
			case SYSTEMCAPTURE: return "framegrabber";
			case GENERAL:       return "general";
			case V4L2:          return "grabberV4L2";
			case JSONSERVER:    return "jsonServer";
			case LEDCONFIG:     return "ledConfig";
			case LEDS:          return "leds";
			case LOGGER:        return "logger";
			case SMOOTHING:     return "smoothing";
			case WEBSERVER:     return "webConfig";
			case INSTCAPTURE:   return "instCapture";
			case NETWORK:       return "network";
			case FLATBUFSERVER: return "flatbufServer";
			case PROTOSERVER:   return "protoServer";
			default:            return "invalid";
		}
	}

	///
	/// @brief Convert string to settings::type representation
	/// @param  type  The string to convert
	/// @return       The settings type from enum
	///
	inline type stringToType(const QString& type)
	{
		if      (type == "backgroundEffect")     return BGEFFECT;
		else if (type == "foregroundEffect")     return FGEFFECT;
		else if (type == "blackborderdetector")  return BLACKBORDER;
		else if (type == "boblightServer")       return BOBLSERVER;
		else if (type == "color")                return COLOR;
		else if (type == "device")               return DEVICE;
		else if (type == "effects")              return EFFECTS;
		else if (type == "forwarder")            return NETFORWARD;
		else if (type == "framegrabber")         return SYSTEMCAPTURE;
		else if (type == "general")              return GENERAL;
		else if (type == "grabberV4L2")          return V4L2;
		else if (type == "jsonServer")           return JSONSERVER;
		else if (type == "ledConfig")            return LEDCONFIG;
		else if (type == "leds")                 return LEDS;
		else if (type == "logger")               return LOGGER;
		else if (type == "smoothing")            return SMOOTHING;
		else if (type == "webConfig")            return WEBSERVER;
		else if (type == "instCapture")          return INSTCAPTURE;
		else if (type == "network")              return NETWORK;
		else if (type == "flatbufServer")        return FLATBUFSERVER;
		else if (type == "protoServer")          return PROTOSERVER;
		else                                     return INVALID;
	}
}


<|start_filename|>include/bonjour/bonjourserviceregister.h<|end_filename|>
/*
Copyright (c) 2007, <NAME>

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 1. Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

 2. Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

 3. The name of the author may not be used to endorse or promote products
    derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef BONJOURSERVICEREGISTER_H
#define BONJOURSERVICEREGISTER_H

#include <QtCore/QObject>

#include "bonjourrecord.h"
class QSocketNotifier;

#ifndef PLATFORM_AMLOGIC
#include <dns_sd.h>
#else
#include <avahi-compat-libdns_sd/dns_sd.h>
#endif

class BonjourServiceRegister : public QObject
{
    Q_OBJECT
public:
    BonjourServiceRegister(QObject *parent = 0);
    ~BonjourServiceRegister() override;

    void registerService(const QString& service, int port);
    void registerService(const BonjourRecord &record, quint16 servicePort, const std::vector<std::pair<std::string, std::string>>& txt = {});
    inline BonjourRecord registeredRecord() const { return finalRecord; }

    quint16 getPort() const { return _port; }

signals:
    void error(DNSServiceErrorType error);
    void serviceRegistered(const BonjourRecord &record);

private slots:
    void bonjourSocketReadyRead();

private:
    static void DNSSD_API bonjourRegisterService(DNSServiceRef sdRef, DNSServiceFlags,
                                       DNSServiceErrorType errorCode, const char *name,
                                       const char *regtype, const char *domain,
                                       void *context);
    DNSServiceRef dnssref;
    QSocketNotifier *bonjourSocket;
    BonjourRecord finalRecord;

    // current port
    quint16 _port = 0;
};

#endif // BONJOURSERVICEREGISTER_H


<|start_filename|>libsrc/webserver/WebJsonRpc.h<|end_filename|>
#pragma once

#include <utils/Logger.h>

#include <QJsonObject>

class QtHttpServer;
class QtHttpRequest;
class QtHttpClientWrapper;
class JsonAPI;

class WebJsonRpc : public QObject {
	Q_OBJECT
public:
	WebJsonRpc(QtHttpRequest* request, QtHttpServer* server, bool localConnection, QtHttpClientWrapper* parent);

	void handleMessage(QtHttpRequest* request);

private:
	QtHttpServer* _server;
	QtHttpClientWrapper* _wrapper;
	Logger* _log;
	JsonAPI* _jsonAPI;

	bool _stopHandle = false;
	bool _unlocked = false;

private slots:
	void handleCallback(QJsonObject obj);
};


<|start_filename|>cmake/ECMFindModuleHelpers.cmake<|end_filename|>
#.rst:
# ECMFindModuleHelpers
# --------------------
#
# Helper macros for find modules: ecm_find_package_version_check(),
# ecm_find_package_parse_components() and
# ecm_find_package_handle_library_components().
#
# ::
#
#   ecm_find_package_version_check(<name>)
#
# Prints warnings if the CMake version or the project's required CMake version
# is older than that required by extra-cmake-modules.
#
# ::
#
#   ecm_find_package_parse_components(<name>
#       RESULT_VAR <variable>
#       KNOWN_COMPONENTS <component1> [<component2> [...]]
#       [SKIP_DEPENDENCY_HANDLING])
#
# This macro will populate <variable> with a list of components found in
# <name>_FIND_COMPONENTS, after checking that all those components are in the
# list of KNOWN_COMPONENTS; if there are any unknown components, it will print
# an error or warning (depending on the value of <name>_FIND_REQUIRED) and call
# return().
#
# The order of components in <variable> is guaranteed to match the order they
# are listed in the KNOWN_COMPONENTS argument.
#
# If SKIP_DEPENDENCY_HANDLING is not set, for each component the variable
# <name>_<component>_component_deps will be checked for dependent components.
# If <component> is listed in <name>_FIND_COMPONENTS, then all its (transitive)
# dependencies will also be added to <variable>.
#
# ::
#
#   ecm_find_package_handle_library_components(<name>
#       COMPONENTS <component> [<component> [...]]
#       [SKIP_DEPENDENCY_HANDLING])
#       [SKIP_PKG_CONFIG])
#
# Creates an imported library target for each component.  The operation of this
# macro depends on the presence of a number of CMake variables.
#
# The <name>_<component>_lib variable should contain the name of this library,
# and <name>_<component>_header variable should contain the name of a header
# file associated with it (whatever relative path is normally passed to
# '#include'). <name>_<component>_header_subdir variable can be used to specify
# which subdirectory of the include path the headers will be found in.
# ecm_find_package_components() will then search for the library
# and include directory (creating appropriate cache variables) and create an
# imported library target named <name>::<component>.
#
# Additional variables can be used to provide additional information:
#
# If SKIP_PKG_CONFIG, the <name>_<component>_pkg_config variable is set, and
# pkg-config is found, the pkg-config module given by
# <name>_<component>_pkg_config will be searched for and used to help locate the
# library and header file.  It will also be used to set
# <name>_<component>_VERSION.
#
# Note that if version information is found via pkg-config,
# <name>_<component>_FIND_VERSION can be set to require a particular version
# for each component.
#
# If SKIP_DEPENDENCY_HANDLING is not set, the INTERFACE_LINK_LIBRARIES property
# of the imported target for <component> will be set to contain the imported
# targets for the components listed in <name>_<component>_component_deps.
# <component>_FOUND will also be set to false if any of the compoments in
# <name>_<component>_component_deps are not found.  This requires the components
# in <name>_<component>_component_deps to be listed before <component> in the
# COMPONENTS argument.
#
# The following variables will be set:
#
# ``<name>_TARGETS``
#   the imported targets
# ``<name>_LIBRARIES``
#   the found libraries
# ``<name>_INCLUDE_DIRS``
#   the combined required include directories for the components
# ``<name>_DEFINITIONS``
#   the "other" CFLAGS provided by pkg-config, if any
# ``<name>_VERSION``
#   the value of ``<name>_<component>_VERSION`` for the first component that
#   has this variable set (note that components are searched for in the order
#   they are passed to the macro), although if it is already set, it will not
#   be altered
#
# Note that these variables are never cleared, so if
# ecm_find_package_handle_library_components() is called multiple times with
# different components (typically because of multiple find_package() calls) then
# ``<name>_TARGETS``, for example, will contain all the targets found in any
# call (although no duplicates).
#
# Since pre-1.0.0.

#=============================================================================
# SPDX-FileCopyrightText: 2014 <NAME> <<EMAIL>>
#
# SPDX-License-Identifier: BSD-3-Clause

include(CMakeParseArguments)

macro(ecm_find_package_version_check module_name)
    if(CMAKE_VERSION VERSION_LESS 2.8.12)
        message(FATAL_ERROR "CMake 2.8.12 is required by Find${module_name}.cmake")
    endif()
    if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12)
        message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use Find${module_name}.cmake")
    endif()
endmacro()

macro(ecm_find_package_parse_components module_name)
    set(ecm_fppc_options SKIP_DEPENDENCY_HANDLING)
    set(ecm_fppc_oneValueArgs RESULT_VAR)
    set(ecm_fppc_multiValueArgs KNOWN_COMPONENTS DEFAULT_COMPONENTS)
    cmake_parse_arguments(ECM_FPPC "${ecm_fppc_options}" "${ecm_fppc_oneValueArgs}" "${ecm_fppc_multiValueArgs}" ${ARGN})

    if(ECM_FPPC_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unexpected arguments to ecm_find_package_parse_components: ${ECM_FPPC_UNPARSED_ARGUMENTS}")
    endif()
    if(NOT ECM_FPPC_RESULT_VAR)
        message(FATAL_ERROR "Missing RESULT_VAR argument to ecm_find_package_parse_components")
    endif()
    if(NOT ECM_FPPC_KNOWN_COMPONENTS)
        message(FATAL_ERROR "Missing KNOWN_COMPONENTS argument to ecm_find_package_parse_components")
    endif()
    if(NOT ECM_FPPC_DEFAULT_COMPONENTS)
        set(ECM_FPPC_DEFAULT_COMPONENTS ${ECM_FPPC_KNOWN_COMPONENTS})
    endif()

    if(${module_name}_FIND_COMPONENTS)
        set(ecm_fppc_requestedComps ${${module_name}_FIND_COMPONENTS})

        if(NOT ECM_FPPC_SKIP_DEPENDENCY_HANDLING)
            # Make sure deps are included
            foreach(ecm_fppc_comp ${ecm_fppc_requestedComps})
                foreach(ecm_fppc_dep_comp ${${module_name}_${ecm_fppc_comp}_component_deps})
                    list(FIND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}" ecm_fppc_index)
                    if("${ecm_fppc_index}" STREQUAL "-1")
                        if(NOT ${module_name}_FIND_QUIETLY)
                            message(STATUS "${module_name}: ${ecm_fppc_comp} requires ${${module_name}_${ecm_fppc_comp}_component_deps}")
                        endif()
                        list(APPEND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}")
                    endif()
                endforeach()
            endforeach()
        else()
            message(STATUS "Skipping dependency handling for ${module_name}")
        endif()
        list(REMOVE_DUPLICATES ecm_fppc_requestedComps)

        # This makes sure components are listed in the same order as
        # KNOWN_COMPONENTS (potentially important for inter-dependencies)
        set(${ECM_FPPC_RESULT_VAR})
        foreach(ecm_fppc_comp ${ECM_FPPC_KNOWN_COMPONENTS})
            list(FIND ecm_fppc_requestedComps "${ecm_fppc_comp}" ecm_fppc_index)
            if(NOT "${ecm_fppc_index}" STREQUAL "-1")
                list(APPEND ${ECM_FPPC_RESULT_VAR} "${ecm_fppc_comp}")
                list(REMOVE_AT ecm_fppc_requestedComps ${ecm_fppc_index})
            endif()
        endforeach()
        # if there are any left, they are unknown components
        if(ecm_fppc_requestedComps)
            set(ecm_fppc_msgType STATUS)
            if(${module_name}_FIND_REQUIRED)
                set(ecm_fppc_msgType FATAL_ERROR)
            endif()
            if(NOT ${module_name}_FIND_QUIETLY)
                message(${ecm_fppc_msgType} "${module_name}: requested unknown components ${ecm_fppc_requestedComps}")
            endif()
            return()
        endif()
    else()
        set(${ECM_FPPC_RESULT_VAR} ${ECM_FPPC_DEFAULT_COMPONENTS})
    endif()
endmacro()

macro(ecm_find_package_handle_library_components module_name)
    set(ecm_fpwc_options SKIP_PKG_CONFIG SKIP_DEPENDENCY_HANDLING)
    set(ecm_fpwc_oneValueArgs)
    set(ecm_fpwc_multiValueArgs COMPONENTS)
    cmake_parse_arguments(ECM_FPWC "${ecm_fpwc_options}" "${ecm_fpwc_oneValueArgs}" "${ecm_fpwc_multiValueArgs}" ${ARGN})

    if(ECM_FPWC_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unexpected arguments to ecm_find_package_handle_components: ${ECM_FPWC_UNPARSED_ARGUMENTS}")
    endif()
    if(NOT ECM_FPWC_COMPONENTS)
        message(FATAL_ERROR "Missing COMPONENTS argument to ecm_find_package_handle_components")
    endif()

    include(FindPackageHandleStandardArgs)
    find_package(PkgConfig)
    foreach(ecm_fpwc_comp ${ECM_FPWC_COMPONENTS})
        set(ecm_fpwc_dep_vars)
        set(ecm_fpwc_dep_targets)
        if(NOT SKIP_DEPENDENCY_HANDLING)
            foreach(ecm_fpwc_dep ${${module_name}_${ecm_fpwc_comp}_component_deps})
                list(APPEND ecm_fpwc_dep_vars "${module_name}_${ecm_fpwc_dep}_FOUND")
                list(APPEND ecm_fpwc_dep_targets "${module_name}::${ecm_fpwc_dep}")
            endforeach()
        endif()

        if(NOT ECM_FPWC_SKIP_PKG_CONFIG AND ${module_name}_${ecm_fpwc_comp}_pkg_config)
            pkg_check_modules(PKG_${module_name}_${ecm_fpwc_comp} QUIET
                              ${${module_name}_${ecm_fpwc_comp}_pkg_config})
        endif()

        find_path(${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
            NAMES ${${module_name}_${ecm_fpwc_comp}_header}
            HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_INCLUDE_DIRS}
            PATH_SUFFIXES ${${module_name}_${ecm_fpwc_comp}_header_subdir}
        )
        find_library(${module_name}_${ecm_fpwc_comp}_LIBRARY
            NAMES ${${module_name}_${ecm_fpwc_comp}_lib}
            HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_LIBRARY_DIRS}
        )

        set(${module_name}_${ecm_fpwc_comp}_VERSION "${PKG_${module_name}_${ecm_fpwc_comp}_VERSION}")
        if(NOT ${module_name}_VERSION)
            set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION})
        endif()

        set(FPHSA_NAME_MISMATCHED 1)
        find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp}
            FOUND_VAR
                ${module_name}_${ecm_fpwc_comp}_FOUND
            REQUIRED_VARS
                ${module_name}_${ecm_fpwc_comp}_LIBRARY
                ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
                ${ecm_fpwc_dep_vars}
            VERSION_VAR
                ${module_name}_${ecm_fpwc_comp}_VERSION
            )
        unset(FPHSA_NAME_MISMATCHED)

        mark_as_advanced(
            ${module_name}_${ecm_fpwc_comp}_LIBRARY
            ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
        )

        if(${module_name}_${ecm_fpwc_comp}_FOUND)
            list(APPEND ${module_name}_LIBRARIES
                        "${${module_name}_${ecm_fpwc_comp}_LIBRARY}")
            list(APPEND ${module_name}_INCLUDE_DIRS
                        "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}")
            set(${module_name}_DEFINITIONS
                    ${${module_name}_DEFINITIONS}
                    ${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS})
            if(NOT TARGET ${module_name}::${ecm_fpwc_comp})
                add_library(${module_name}::${ecm_fpwc_comp} UNKNOWN IMPORTED)
                set_target_properties(${module_name}::${ecm_fpwc_comp} PROPERTIES
                    IMPORTED_LOCATION "${${module_name}_${ecm_fpwc_comp}_LIBRARY}"
                    INTERFACE_COMPILE_OPTIONS "${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}"
                    INTERFACE_INCLUDE_DIRECTORIES "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}"
                    INTERFACE_LINK_LIBRARIES "${ecm_fpwc_dep_targets}"
                )
            endif()
            list(APPEND ${module_name}_TARGETS
                        "${module_name}::${ecm_fpwc_comp}")
        endif()
    endforeach()
    if(${module_name}_LIBRARIES)
        list(REMOVE_DUPLICATES ${module_name}_LIBRARIES)
    endif()
    if(${module_name}_INCLUDE_DIRS)
        list(REMOVE_DUPLICATES ${module_name}_INCLUDE_DIRS)
    endif()
    if(${module_name}_DEFINITIONS)
        list(REMOVE_DUPLICATES ${module_name}_DEFINITIONS)
    endif()
    if(${module_name}_TARGETS)
        list(REMOVE_DUPLICATES ${module_name}_TARGETS)
    endif()
endmacro()


<|start_filename|>libsrc/utils/DefaultSignalHandler.cpp<|end_filename|>
#ifndef _WIN32

#include <utils/DefaultSignalHandler.h>
#include <utils/Logger.h>

#include <ctype.h>
#include <cxxabi.h>
#include <execinfo.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include <QCoreApplication>

namespace DefaultSignalHandler
{
struct Signal
{
	int          number;
	const char * name;
};

const Signal ALL_SIGNALS[] = {
	{ SIGABRT, "SIGABRT" },
	{ SIGBUS,  "SIGBUS"  },
	{ SIGFPE,  "SIGFPE"  },
	{ SIGILL,  "SIGILL"  },
	{ SIGSEGV, "SIGSEGV" },
	{ SIGTERM, "SIGTERM" },
	{ SIGHUP,  "SIGHUP"  },
	{ SIGINT,  "SIGINT"  },
	{ SIGPIPE, "SIGPIPE" },
};

void write_to_stderr(const char* data, size_t size)
{
	int res = write(STDERR_FILENO, data, size);

	Q_UNUSED(res);
}

void write_to_stderr(const char* data)
{
	write_to_stderr(data, strlen(data));
}

std::string decipher_trace(const std::string &trace)
{
	std::string result;

	if(trace.empty())
	{
		result += "??\n";
		return result;
	}

	auto* begin = strchr(trace.c_str(), '(') + 1;
	auto* end = strchr(begin, '+');

	if(!end)
		end = strchr(begin, ')');

	std::string mangled_name(begin, end);

	int status;
	char * realname = abi::__cxa_demangle(mangled_name.c_str(), 0, 0, &status);
	result.insert(result.end(), trace.c_str(), begin);

	if(realname)
		result += realname;
	else
		result.insert(result.end(), begin, end);

	free(realname);
	result.insert(result.size(), end);

	return result;
}

void print_trace()
{
	const int MAX_SIZE = 50;
	void * addresses[MAX_SIZE];
	int size = backtrace(addresses, MAX_SIZE);

	if (!size)
		return;

	Logger* log = Logger::getInstance("CORE");
	char ** symbols = backtrace_symbols(addresses, size);

	/* Skip first 2 frames as they are signal
	 * handler and print_trace functions. */
	for (int i = 2; i < size; ++i)
	{
		std::string line = "\t" + decipher_trace(symbols[i]);
		Error(log, line.c_str());
	}

	free(symbols);
}

void install_default_handler(int signum)
{
	struct sigaction action{};
	sigemptyset(&action.sa_mask);
	action.sa_handler = SIG_DFL;
	(void)sigaction(signum, &action, nullptr);
}

/* Note that this signal handler is not async signal safe !
 * Ideally a signal handler should only flip a bit and defer
 * heavy work to some kind of bottom-half processing. */
void signal_handler(int signum, siginfo_t * /*info*/, void * /*context*/)
{
	const char * name = "UNKNOWN SIGNAL";

	for (const auto& s : ALL_SIGNALS) {
		if (s.number == signum) {
			name = s.name;
			break;
		}
	}

	write_to_stderr("\n");
	write_to_stderr("Hyperion caught signal :");
	write_to_stderr(name);
	write_to_stderr("\n");

	/* Anything below here is unsafe ! */

	switch(signum)
	{
	case SIGBUS:
	case SIGSEGV:
	case SIGABRT:
	case SIGFPE :
		print_trace();

		/* Don't catch our own signal */
		install_default_handler(signum);

		kill(getpid(), signum);
		return;
	case SIGINT :
	case SIGTERM:
	case SIGPIPE:
	default:
		/* If the signal_handler is hit before the event loop is started,
		 * following call will do nothing. So we queue the call. */

		// QCoreApplication::quit();
		QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection);

		// Reset signal handler to default (in case this handler is not capable of stopping)
		install_default_handler(signum);
	}
}

} // namespace DefaultSignalHandler
#endif // _WIN32

namespace DefaultSignalHandler
{
void install()
{
#ifndef _WIN32
	Logger* log = Logger::getInstance("CORE");

	struct sigaction action{};
	sigemptyset(&action.sa_mask);
	action.sa_sigaction = signal_handler;
	action.sa_flags |= SA_SIGINFO;

	for (const auto& s : ALL_SIGNALS)
	{
		if (sigaction(s.number, &action, nullptr)!= 0)
		{
			Error(log, "Failed to install handler for %s]\n", s.name);
		}
	}
#endif // _WIN32
}
} // namespace DefaultSignalHandler


<|start_filename|>.vscode/tasks.json<|end_filename|>
{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "cmake:conf Release",
      "detail": "Configure Build Env. Release/Debug switch not required for multi generators (msvc)",
      "type": "shell",
      "command": "cmake -B ${workspaceFolder}/build -DCMAKE_BUILD_TYPE=Release",
      "windows": {
        "command": "cmake -G \"Visual Studio 16 2019\" -A x64 -B ${workspaceFolder}/build"
      },
      "group": "build"
    },
    {
      "label": "cmake:conf Debug",
      "detail": "Configure Build Env. Release/Debug switch not required with msvc",
      "type": "shell",
      "command": "cmake -B ${workspaceFolder}/build -DCMAKE_BUILD_TYPE=Debug",
      "windows": {
        "command": "cmake -G \"Visual Studio 16 2019\" -A x64 -B ${workspaceFolder}/build"
      },
      "group": "build"
    },
    {
      "label": "build:debug hyperiond",
      "type": "shell",
      "command": "cmake --build ${workspaceFolder}/build --target hyperiond -- -j $(nproc)",
      "windows": {
        "command": "cmake --build ${workspaceFolder}/build --target hyperiond --config Debug -- -maxcpucount"
      },
      "osx": {
        "command": "cmake --build ${workspaceFolder}/build --target hyperiond -- -j $(sysctl -n hw.ncpu)"
      },
      "group": {
        "kind": "build",
        "isDefault": true
      }
    },
    {
      "label": "build:debug all",
      "type": "shell",
      "command": "cmake --build ${workspaceFolder}/build -- -j $(nproc)",
      "windows": {
        "command": "cmake --build ${workspaceFolder}/build --config Debug -- -maxcpucount"
      },
      "osx": {
        "command": "cmake --build ${workspaceFolder}/build -- -j $(sysctl -n hw.ncpu)"
      },
      "group": "build"
    },
    {
      "label": "build:debug package",
      "type": "shell",
      "command": "cmake --build ${workspaceFolder}/build --target package -- -j $(nproc)",
      "windows": {
        "command": "cmake --build ${workspaceFolder}/build --target package --config Debug -- -maxcpucount"
      },
      "osx": {
        "command": "cmake --build ${workspaceFolder}/build --target package -- -j $(sysctl -n hw.ncpu)"
      },
      "group": "build"
    },
    {
      "label": "build:release hyperiond",
      "type": "shell",
      "command": "cmake --build ${workspaceFolder}/build --target hyperiond -- -j $(nproc)",
      "windows": {
        "command": "cmake --build ${workspaceFolder}/build --target hyperiond --config Release -- -maxcpucount"
      },
      "osx": {
        "command": "cmake --build ${workspaceFolder}/build --target hyperiond -- -j $(sysctl -n hw.ncpu)"
      },
      "group": {
        "kind": "build",
        "isDefault": true
      }
    },
    {
      "label": "build:release all",
      "type": "shell",
      "command": "cmake --build ${workspaceFolder}/build -- -j $(nproc)",
      "windows": {
        "command": "cmake --build ${workspaceFolder}/build --config Release -- -maxcpucount"
      },
      "osx": {
        "command": "cmake --build ${workspaceFolder}/build -- -j $(sysctl -n hw.ncpu)"
      },
      "group": "build"
    },
    {
      "label": "build:release package",
      "type": "shell",
      "command": "cmake --build ${workspaceFolder}/build --target package -- -j $(nproc)",
      "windows": {
        "command": "cmake --build ${workspaceFolder}/build --target package --config Release -- -maxcpucount"
      },
      "osx": {
        "command": "cmake --build ${workspaceFolder}/build --target package -- -j $(sysctl -n hw.ncpu)"
      },
      "group": "build"
    },
    {
      "label": "run:hyperiond (Debug)",
      "type": "shell",
      "command": "${workspaceFolder}/build/bin/hyperiond -d",
      "windows": {
        "command": "${workspaceFolder}/build/bin/Debug/hyperiond -d -c"
      },
      "group": "build"
    },
    {
      "label": "run:hyperiond (Release)",
      "type": "shell",
      "command": "${workspaceFolder}/build/bin/hyperiond -d",
      "windows": {
        "command": "${workspaceFolder}/build/bin/Release/hyperiond -d -c"
      },
      "group": "build"
    }
  ]
}


<|start_filename|>include/bonjour/bonjourservicebrowser.h<|end_filename|>
/*
Copyright (c) 2007, <NAME>

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 1. Redistributions of source code must retain the above copyright notice,
	this list of conditions and the following disclaimer.

 2. Redistributions in binary form must reproduce the above copyright notice,
	this list of conditions and the following disclaimer in the documentation
	and/or other materials provided with the distribution.

 3. The name of the author may not be used to endorse or promote products
	derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef BONJOURSERVICEBROWSER_H
#define BONJOURSERVICEBROWSER_H

#include <QtCore/QObject>
#ifndef PLATFORM_AMLOGIC
#include <dns_sd.h>
#else
#include <avahi-compat-libdns_sd/dns_sd.h>
#endif
#include "bonjour/bonjourrecord.h"


class QSocketNotifier;
class BonjourServiceBrowser : public QObject
{
	Q_OBJECT
public:
	BonjourServiceBrowser(QObject *parent = 0);
	~BonjourServiceBrowser() override;
	void browseForServiceType(const QString &serviceType);
	inline QList<BonjourRecord> currentRecords() const { return bonjourRecords; }
	inline QString serviceType() const { return browsingType; }

signals:
	void currentBonjourRecordsChanged(const QList<BonjourRecord> &list);
	void error(DNSServiceErrorType err);

private slots:
	void bonjourSocketReadyRead();

private:
	static void DNSSD_API bonjourBrowseReply(DNSServiceRef , DNSServiceFlags flags, quint32,
								   DNSServiceErrorType errorCode, const char *serviceName,
								   const char *regType, const char *replyDomain, void *context);
	DNSServiceRef dnssref;
	QSocketNotifier *bonjourSocket;
	QList<BonjourRecord> bonjourRecords;
	QString browsingType;
};

#endif // BONJOURSERVICEBROWSER_H


<|start_filename|>include/utils/JsonUtils.h<|end_filename|>
#pragma once

#include <utils/FileUtils.h>

#include <QJsonObject>
#include <utils/Logger.h>

namespace JsonUtils {
	///
	/// @brief read a json file and get the parsed result on success
	/// @param[in]  path     The file path to read
	/// @param[out] obj      Returns the parsed QJsonObject
	/// @param[in]  log      The logger of the caller to print errors
	/// @param[in]  ignError Ignore errors during file read (no log output)
	/// @return              true on success else false
	///
	bool readFile(const QString& path, QJsonObject& obj, Logger* log, bool ignError=false);

	///
	/// @brief read a schema file and resolve $refs
	/// @param[in]  path     The file path to read
	/// @param[out] obj      Returns the parsed QJsonObject
	/// @param[in]  log      The logger of the caller to print errors
	/// @return              true on success else false
	///
	bool readSchema(const QString& path, QJsonObject& obj, Logger* log);

	///
	/// @brief parse a json QString and get a QJsonObject. Overloaded funtion
	/// @param[in]  path     The file path/name just used for log messages
	/// @param[in]  data     Data to parse
	/// @param[out] obj      Retuns the parsed QJsonObject
	/// @param[in]  log      The logger of the caller to print errors
	/// @return              true on success else false
	///
	bool parse(const QString& path, const QString& data, QJsonObject& obj, Logger* log);

	///
	/// @brief parse a json QString and get a QJsonArray. Overloaded function
	/// @param[in]  path     The file path/name just used for log messages
	/// @param[in]  data     Data to parse
	/// @param[out] arr      Retuns the parsed QJsonArray
	/// @param[in]  log      The logger of the caller to print errors
	/// @return              true on success else false
	///
	bool parse(const QString& path, const QString& data, QJsonArray& arr, Logger* log);

	///
	/// @brief parse a json QString and get a QJsonDocument
	/// @param[in]  path     The file path/name just used for log messages
	/// @param[in]  data     Data to parse
	/// @param[out] doc      Retuns the parsed QJsonDocument
	/// @param[in]  log      The logger of the caller to print errors
	/// @return              true on success else false
	///
	bool parse(const QString& path, const QString& data, QJsonDocument& doc, Logger* log);

	///
	/// @brief Validate json data against a schema
	/// @param[in]   file     The path/name of json file just used for log messages
	/// @param[in]   json     The json data
	/// @param[in]   schemaP  The schema path
	/// @param[in]   log      The logger of the caller to print errors
	/// @return               true on success else false
	///
	bool validate(const QString& file, const QJsonObject& json, const QString& schemaPath, Logger* log);

	///
	/// @brief Validate json data against a schema
	/// @param[in]   file     The path/name of json file just used for log messages
	/// @param[in]   json     The json data
	/// @param[in]   schema   The schema object
	/// @param[in]   log      The logger of the caller to print errors
	/// @return               true on success else false
	///
	bool validate(const QString& file, const QJsonObject& json, const QJsonObject& schema, Logger* log);

	///
	/// @brief Write json data to file
	/// @param[in]   filenameThe file path to write
	/// @param[in]   json    The json data to write
	/// @param[in]   log     The logger of the caller to print errors
	/// @return              true on success else false
	///
	bool write(const QString& filename, const QJsonObject& json, Logger* log);

	///
	/// @brief resolve schema $ref attribute
	/// @param[in]   schema  the schema to iterate
	/// @param[out]  obj     the resolved object
	/// @param[in]   log     The logger of the caller to print errors
	/// @return              true on success else false
	///
	bool resolveRefs(const QJsonObject& schema, QJsonObject& obj, Logger* log);
}


<|start_filename|>libsrc/leddevice/schemas/schema-nanoleaf.json<|end_filename|>
{
	"type":"object",
	"required":true,
	"properties":{
		"host": {
			"type": "string",
			"title":"edt_dev_spec_targetIpHost_title",
			"propertyOrder" : 1
		},
		"token": {
			"type": "string",
			"title":"edt_dev_auth_key_title",
			"propertyOrder" : 2
		},
		"title": {
		"type" : "object",
		"title":"edt_dev_spec_panelorganisation_title",
		"access" : "advanced",
		"propertyOrder" : 3
		},
		"panelOrderTopDown": {
			"type": "integer",
			"title":"edt_dev_spec_order_top_down_title",
			"enum" : [0, 1],
			"default" : 0,
			"options" : {
				"enum_titles" : ["edt_conf_enum_top_down", "edt_conf_enum_bottom_up"]
			},
			"minimum" : 0,
			"maximum" : 1,
			"access" : "advanced",
			"propertyOrder" : 4
		},
		"panelOrderLeftRight": {
			"type": "integer",
			"title":"edt_dev_spec_order_left_right_title",
			"enum" : [0, 1],
			"default" : 0,
			"options" : {
				"enum_titles" : ["edt_conf_enum_left_right", "edt_conf_enum_right_left"]
			},
			"minimum" : 0,
			"maximum" : 1,
			"access" : "advanced",
			"propertyOrder" : 5
		},
		"panelStartPos": {
			"type": "integer",
			"title":"edt_dev_spec_panel_start_position",
			"step": 1,
			"minimum" : 0,
			"default": 0,
			"access" : "advanced",
			"propertyOrder" : 6
		}
	},
	"additionalProperties": true
}
