diff --git a/CMakeLists.txt b/CMakeLists.txt index d2f14ab4..a82810e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,8 +51,7 @@ message(STATUS "ENABLE_FB = " ${ENABLE_FB}) option(ENABLE_OSX "Enable the osx grabber" ${DEFAULT_OSX} ) message(STATUS "ENABLE_OSX = " ${ENABLE_OSX}) -option(ENABLE_PROTOBUF "Enable PROTOBUF server" ON) -message(STATUS "ENABLE_PROTOBUF = " ${ENABLE_PROTOBUF}) +set(ENABLE_PROTOBUF ON) option(ENABLE_SPIDEV "Enable the SPIDEV device" ${DEFAULT_SPIDEV} ) message(STATUS "ENABLE_SPIDEV = " ${ENABLE_SPIDEV}) @@ -78,9 +77,6 @@ message(STATUS "ENABLE_QT5 = " ${ENABLE_QT5}) option(ENABLE_TESTS "Compile additional test applications" OFF) message(STATUS "ENABLE_TESTS = " ${ENABLE_TESTS}) -if(ENABLE_V4L2 AND NOT ENABLE_PROTOBUF) - message(FATAL_ERROR "V4L2 grabber requires PROTOBUF. Disable V4L2 or enable PROTOBUF") -endif() if(ENABLE_FB AND ENABLE_DISPMANX) message(FATAL_ERROR "dispmanx grabber and framebuffer grabber cannot be used at the same time") diff --git a/bin/copy_binaries_to_deploy.sh b/bin/copy_binaries_to_deploy.sh index 5ce8be74..82dc5032 100755 --- a/bin/copy_binaries_to_deploy.sh +++ b/bin/copy_binaries_to_deploy.sh @@ -1,8 +1,8 @@ #!/bin/sh if [ "$#" -ne 2 ] || ! [ -d "$1" ] || ! [ -d "$2" ]; then - echo "Usage: $0 " >&2 - exit 1 + echo "Usage: $0 " >&2 + exit 1 fi builddir="$1" diff --git a/bin/remove_hyperion.sh b/bin/remove_hyperion.sh index c3034032..b6bf9d1b 100644 --- a/bin/remove_hyperion.sh +++ b/bin/remove_hyperion.sh @@ -6,15 +6,15 @@ PATH="/sbin:$PATH" #Check if HyperCon is logged in as root if [ $(id -u) != 0 ] && [ "$1" = "HyperConRemove" ]; then - echo '---> Critical Error: Please connect as user "root" through HyperCon' - echo '---> We need admin privileges to remove your Hyperion! -> abort' - exit 1 + echo '---> Critical Error: Please connect as user "root" through HyperCon' + echo '---> We need admin privileges to remove your Hyperion! -> abort' + exit 1 fi #Check, if script is running as root if [ $(id -u) != 0 ]; then - echo '---> Critical Error: Please run the script as root (sudo sh ./remove_hyperion.sh)' - exit 1 + echo '---> Critical Error: Please run the script as root (sudo sh ./remove_hyperion.sh)' + exit 1 fi #Welcome message @@ -26,21 +26,22 @@ echo '************************************************************************** #Skip the prompt if HyperCon Remove if [ "$1" = "" ]; then -#Prompt for confirmation to proceed -while true -do -echo -n "---> Do you really want to remove Hyperion and itīs services? (y or n) :" -read CONFIRM -case $CONFIRM in -y|Y|YES|yes|Yes) break ;; -n|N|no|NO|No) -echo "---> Aborting - you entered \"$CONFIRM\"" -exit -;; -*) echo "-> Please enter only y or n" -esac -done -echo "---> You entered \"$CONFIRM\". Remove Hyperion!" + #Prompt for confirmation to proceed + while true + do + echo -n "---> Do you really want to remove Hyperion and itīs services? (y or n) :" + read CONFIRM + case $CONFIRM in + y|Y|YES|yes|Yes) break ;; + n|N|no|NO|No) + echo "---> Aborting - you entered \"$CONFIRM\"" + exit + ;; + *) echo "-> Please enter only y or n" + esac + done + + echo "---> You entered \"$CONFIRM\". Remove Hyperion!" fi # Find out if we are on OpenElec or RasPlex OS_OPENELEC=`grep -m1 -c 'OpenELEC\|RasPlex\|LibreELEC' /etc/issue` @@ -124,4 +125,3 @@ echo '************************************************************************** echo 'Hyperion successful removed!' echo '*******************************************************************************' exit 0 - \ No newline at end of file diff --git a/cmake/FindBCM.cmake b/cmake/FindBCM.cmake index 5e9ce645..f64c540e 100644 --- a/cmake/FindBCM.cmake +++ b/cmake/FindBCM.cmake @@ -8,16 +8,16 @@ # FIND_PATH(BCM_INCLUDE_DIR - bcm_host.h - /usr/include - /usr/local/include - /opt/vc/include) + bcm_host.h + /usr/include + /usr/local/include + /opt/vc/include) SET(BCM_INCLUDE_DIRS - ${BCM_INCLUDE_DIR} - ${BCM_INCLUDE_DIR}/interface/vcos/pthreads - ${BCM_INCLUDE_DIR}/interface/vmcs_host/linux) + ${BCM_INCLUDE_DIR} + ${BCM_INCLUDE_DIR}/interface/vcos/pthreads + ${BCM_INCLUDE_DIR}/interface/vmcs_host/linux) FIND_LIBRARY(BCM_LIBRARIES - NAMES bcm_host - PATHS /usr/lib /usr/local/lib /opt/vc/lib) + NAMES bcm_host + PATHS /usr/lib /usr/local/lib /opt/vc/lib) diff --git a/cmake/FindCoreFoundation.cmake b/cmake/FindCoreFoundation.cmake index aaf1502c..195fe551 100644 --- a/cmake/FindCoreFoundation.cmake +++ b/cmake/FindCoreFoundation.cmake @@ -17,5 +17,5 @@ if(APPLE) set(CoreFoundation_FOUND true) set(CoreFoundation_INCLUDE_DIR ${CoreFoundation}) set(CoreFoundation_LIBRARY ${CoreFoundation}) - endif(CoreFoundation) -endif(APPLE) + endif() +endif() diff --git a/cmake/FindIOKit.cmake b/cmake/FindIOKit.cmake index 7a532a5d..7c17be9e 100644 --- a/cmake/FindIOKit.cmake +++ b/cmake/FindIOKit.cmake @@ -13,9 +13,9 @@ set(IOKit_LIBRARY) if(APPLE) # The only platform it makes sense to check for IOKit find_library(IOKit IOKit) - if(IOKit) - set(IOKit_FOUND true) + if(IOKit) + set(IOKit_FOUND true) set(IOKit_INCLUDE_DIR ${IOKit}) - set(IOKit_LIBRARY ${IOKit}) - endif(IOKit) + set(IOKit_LIBRARY ${IOKit}) + endif(IOKit) endif(APPLE) diff --git a/cmake/FindUDev.cmake b/cmake/FindUDev.cmake index 866608dc..12a429d9 100644 --- a/cmake/FindUDev.cmake +++ b/cmake/FindUDev.cmake @@ -10,44 +10,44 @@ # FIND_PATH( - UDEV_INCLUDE_DIR - libudev.h - /usr/include - /usr/local/include - ${UDEV_PATH_INCLUDES} + UDEV_INCLUDE_DIR + libudev.h + /usr/include + /usr/local/include + ${UDEV_PATH_INCLUDES} ) FIND_LIBRARY( - UDEV_LIBRARIES - NAMES udev libudev - PATHS - /usr/lib${LIB_SUFFIX} - /usr/local/lib${LIB_SUFFIX} - ${UDEV_PATH_LIB} + UDEV_LIBRARIES + NAMES udev libudev + PATHS + /usr/lib${LIB_SUFFIX} + /usr/local/lib${LIB_SUFFIX} + ${UDEV_PATH_LIB} ) IF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR) - SET(UDEV_FOUND "YES") - execute_process(COMMAND pkg-config --atleast-version=143 libudev RESULT_VARIABLE UDEV_STABLE) - # retvale is 0 of the condition is "true" so we need to negate the value... - if (UDEV_STABLE) - set(UDEV_STABLE 0) - else (UDEV_STABLE) - set(UDEV_STABLE 1) - endif (UDEV_STABLE) - message(STATUS "libudev stable: ${UDEV_STABLE}") -ENDIF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR) + SET(UDEV_FOUND "YES") + execute_process(COMMAND pkg-config --atleast-version=143 libudev RESULT_VARIABLE UDEV_STABLE) + # retvale is 0 of the condition is "true" so we need to negate the value... + if (UDEV_STABLE) + set(UDEV_STABLE 0) + else () + set(UDEV_STABLE 1) + endif () + message(STATUS "libudev stable: ${UDEV_STABLE}") +ENDIF () IF (UDEV_FOUND) - MESSAGE(STATUS "Found UDev: ${UDEV_LIBRARIES}") - MESSAGE(STATUS " include: ${UDEV_INCLUDE_DIR}") -ELSE (UDEV_FOUND) - MESSAGE(STATUS "UDev not found.") - MESSAGE(STATUS "UDev: You can specify includes: -DUDEV_PATH_INCLUDES=/opt/udev/include") - MESSAGE(STATUS " currently found includes: ${UDEV_INCLUDE_DIR}") - MESSAGE(STATUS "UDev: You can specify libs: -DUDEV_PATH_LIB=/opt/udev/lib") - MESSAGE(STATUS " currently found libs: ${UDEV_LIBRARIES}") - IF (UDev_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find UDev library") - ENDIF (UDev_FIND_REQUIRED) -ENDIF (UDEV_FOUND) + MESSAGE(STATUS "Found UDev: ${UDEV_LIBRARIES}") + MESSAGE(STATUS " include: ${UDEV_INCLUDE_DIR}") +ELSE () + MESSAGE(STATUS "UDev not found.") + MESSAGE(STATUS "UDev: You can specify includes: -DUDEV_PATH_INCLUDES=/opt/udev/include") + MESSAGE(STATUS " currently found includes: ${UDEV_INCLUDE_DIR}") + MESSAGE(STATUS "UDev: You can specify libs: -DUDEV_PATH_LIB=/opt/udev/lib") + MESSAGE(STATUS " currently found libs: ${UDEV_LIBRARIES}") + IF (UDev_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find UDev library") + ENDIF () +ENDIF () diff --git a/cmake/Findlibusb-1.0.cmake b/cmake/Findlibusb-1.0.cmake index 77474e9a..79269e88 100644 --- a/cmake/Findlibusb-1.0.cmake +++ b/cmake/Findlibusb-1.0.cmake @@ -44,56 +44,52 @@ if (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) - # in cache already - set(LIBUSB_FOUND TRUE) + # in cache already + set(LIBUSB_FOUND TRUE) else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) - find_path(LIBUSB_1_INCLUDE_DIR + find_path(LIBUSB_1_INCLUDE_DIR + NAMES + libusb.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + PATH_SUFFIXES + libusb-1.0 + ) + + find_library(LIBUSB_1_LIBRARY NAMES - libusb.h + usb-1.0 usb PATHS - /usr/include - /usr/local/include - /opt/local/include - /sw/include - PATH_SUFFIXES - libusb-1.0 - ) + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ) - find_library(LIBUSB_1_LIBRARY - NAMES - usb-1.0 usb - PATHS - /usr/lib - /usr/local/lib - /opt/local/lib - /sw/lib - ) + set(LIBUSB_1_INCLUDE_DIRS ${LIBUSB_1_INCLUDE_DIR} ) + set(LIBUSB_1_LIBRARIES ${LIBUSB_1_LIBRARY} ) - set(LIBUSB_1_INCLUDE_DIRS - ${LIBUSB_1_INCLUDE_DIR} - ) - set(LIBUSB_1_LIBRARIES - ${LIBUSB_1_LIBRARY} -) + if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) + set(LIBUSB_1_FOUND TRUE) + endif (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) - if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) - set(LIBUSB_1_FOUND TRUE) - endif (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) + if (LIBUSB_1_FOUND) + if (NOT libusb_1_FIND_QUIETLY) + message(STATUS "Found libusb-1.0:") + message(STATUS " - Includes: ${LIBUSB_1_INCLUDE_DIRS}") + message(STATUS " - Libraries: ${LIBUSB_1_LIBRARIES}") + endif (NOT libusb_1_FIND_QUIETLY) + else (LIBUSB_1_FOUND) + unset(LIBUSB_1_LIBRARY CACHE) + if (libusb_1_FIND_REQUIRED) + message(FATAL_ERROR "Could not find libusb") + endif (libusb_1_FIND_REQUIRED) + endif (LIBUSB_1_FOUND) - if (LIBUSB_1_FOUND) - if (NOT libusb_1_FIND_QUIETLY) - message(STATUS "Found libusb-1.0:") - message(STATUS " - Includes: ${LIBUSB_1_INCLUDE_DIRS}") - message(STATUS " - Libraries: ${LIBUSB_1_LIBRARIES}") - endif (NOT libusb_1_FIND_QUIETLY) - else (LIBUSB_1_FOUND) - unset(LIBUSB_1_LIBRARY CACHE) - if (libusb_1_FIND_REQUIRED) - message(FATAL_ERROR "Could not find libusb") - endif (libusb_1_FIND_REQUIRED) - endif (LIBUSB_1_FOUND) - - # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view - mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES) + # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view + mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES) endif (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in index 27ed4ace..75771c04 100644 --- a/cmake/cmake_uninstall.cmake.in +++ b/cmake/cmake_uninstall.cmake.in @@ -1,22 +1,22 @@ if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) - message(STATUS "Uninstalling $ENV{DESTDIR}${file}") - if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") - exec_program( - "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" - OUTPUT_VARIABLE rm_out - RETURN_VALUE rm_retval - ) - if(NOT "${rm_retval}" STREQUAL 0) - message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") - endif(NOT "${rm_retval}" STREQUAL 0) - else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") - message(STATUS "File $ENV{DESTDIR}${file} does not exist.") - endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + exec_program( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif(NOT "${rm_retval}" STREQUAL 0) + else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File $ENV{DESTDIR}${file} does not exist.") + endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") endforeach(file) diff --git a/effects/knight-rider.json b/effects/knight-rider.json index b4644387..9801d491 100644 --- a/effects/knight-rider.json +++ b/effects/knight-rider.json @@ -1,10 +1,10 @@ -{ - "name" : "Knight rider", - "script" : "knight-rider.py", - "args" : - { - "speed" : 1.0, - "fadeFactor" : 0.7, - "color" : [255,0,0] - } -} +{ + "name" : "Knight rider", + "script" : "knight-rider.py", + "args" : + { + "speed" : 1.0, + "fadeFactor" : 0.7, + "color" : [255,0,0] + } +} diff --git a/effects/mood-blobs-blue.json b/effects/mood-blobs-blue.json index 1aa188ab..32280b46 100644 --- a/effects/mood-blobs-blue.json +++ b/effects/mood-blobs-blue.json @@ -1,12 +1,12 @@ -{ - "name" : "Blue mood blobs", - "script" : "mood-blobs.py", - "args" : - { - "rotationTime" : 60.0, - "color" : [0,0,255], - "hueChange" : 60.0, - "blobs" : 5, - "reverse" : false - } -} +{ + "name" : "Blue mood blobs", + "script" : "mood-blobs.py", + "args" : + { + "rotationTime" : 60.0, + "color" : [0,0,255], + "hueChange" : 60.0, + "blobs" : 5, + "reverse" : false + } +} diff --git a/effects/mood-blobs-green.json b/effects/mood-blobs-green.json index c0c104fe..aabd536c 100644 --- a/effects/mood-blobs-green.json +++ b/effects/mood-blobs-green.json @@ -1,12 +1,12 @@ -{ - "name" : "Green mood blobs", - "script" : "mood-blobs.py", - "args" : - { - "rotationTime" : 60.0, - "color" : [0,255,0], - "hueChange" : 60.0, - "blobs" : 5, - "reverse" : false - } -} +{ + "name" : "Green mood blobs", + "script" : "mood-blobs.py", + "args" : + { + "rotationTime" : 60.0, + "color" : [0,255,0], + "hueChange" : 60.0, + "blobs" : 5, + "reverse" : false + } +} diff --git a/effects/mood-blobs-red.json b/effects/mood-blobs-red.json index 3272dded..ac47af53 100644 --- a/effects/mood-blobs-red.json +++ b/effects/mood-blobs-red.json @@ -1,12 +1,12 @@ -{ - "name" : "Red mood blobs", - "script" : "mood-blobs.py", - "args" : - { - "rotationTime" : 60.0, - "color" : [255,0,0], - "hueChange" : 60.0, - "blobs" : 5, - "reverse" : false - } -} +{ + "name" : "Red mood blobs", + "script" : "mood-blobs.py", + "args" : + { + "rotationTime" : 60.0, + "color" : [255,0,0], + "hueChange" : 60.0, + "blobs" : 5, + "reverse" : false + } +} diff --git a/effects/rainbow-mood.json b/effects/rainbow-mood.json index fe754287..c9208b60 100644 --- a/effects/rainbow-mood.json +++ b/effects/rainbow-mood.json @@ -1,10 +1,10 @@ -{ - "name" : "Rainbow mood", - "script" : "rainbow-mood.py", - "args" : - { - "rotation-time" : 60.0, - "brightness" : 1.0, - "reverse" : false - } -} +{ + "name" : "Rainbow mood", + "script" : "rainbow-mood.py", + "args" : + { + "rotation-time" : 60.0, + "brightness" : 1.0, + "reverse" : false + } +} diff --git a/effects/rainbow-swirl-fast.json b/effects/rainbow-swirl-fast.json index 19fec89c..88e8d79d 100644 --- a/effects/rainbow-swirl-fast.json +++ b/effects/rainbow-swirl-fast.json @@ -1,10 +1,10 @@ -{ - "name" : "Rainbow swirl fast", - "script" : "rainbow-swirl.py", - "args" : - { - "rotation-time" : 3.0, - "brightness" : 1.0, - "reverse" : false - } -} +{ + "name" : "Rainbow swirl fast", + "script" : "rainbow-swirl.py", + "args" : + { + "rotation-time" : 3.0, + "brightness" : 1.0, + "reverse" : false + } +} diff --git a/effects/rainbow-swirl.json b/effects/rainbow-swirl.json index 3f7b7243..43a80a8d 100644 --- a/effects/rainbow-swirl.json +++ b/effects/rainbow-swirl.json @@ -1,10 +1,10 @@ -{ - "name" : "Rainbow swirl", - "script" : "rainbow-swirl.py", - "args" : - { - "rotation-time" : 20.0, - "brightness" : 1.0, - "reverse" : false - } -} +{ + "name" : "Rainbow swirl", + "script" : "rainbow-swirl.py", + "args" : + { + "rotation-time" : 20.0, + "brightness" : 1.0, + "reverse" : false + } +} diff --git a/effects/snake.json b/effects/snake.json index 18f2b17c..d5a7674f 100644 --- a/effects/snake.json +++ b/effects/snake.json @@ -1,10 +1,10 @@ -{ - "name" : "Snake", - "script" : "snake.py", - "args" : - { - "rotation-time" : 12.0, - "color" : [255, 0, 0], - "percentage" : 10 - } -} +{ + "name" : "Snake", + "script" : "snake.py", + "args" : + { + "rotation-time" : 12.0, + "color" : [255, 0, 0], + "percentage" : 10 + } +} diff --git a/include/grabber/V4L2Grabber.h b/include/grabber/V4L2Grabber.h index c4fc5a27..b87deb29 100644 --- a/include/grabber/V4L2Grabber.h +++ b/include/grabber/V4L2Grabber.h @@ -23,103 +23,103 @@ /// @see http://linuxtv.org/downloads/v4l-dvb-apis/capture-example.html class V4L2Grabber : public QObject { - Q_OBJECT + Q_OBJECT public: - V4L2Grabber(const std::string & device, - int input, - VideoStandard videoStandard, PixelFormat pixelFormat, - int width, - int height, - int frameDecimation, - int horizontalPixelDecimation, - int verticalPixelDecimation); - virtual ~V4L2Grabber(); + V4L2Grabber(const std::string & device, + int input, + VideoStandard videoStandard, PixelFormat pixelFormat, + int width, + int height, + int frameDecimation, + int horizontalPixelDecimation, + int verticalPixelDecimation); + virtual ~V4L2Grabber(); public slots: - void setCropping(int cropLeft, - int cropRight, - int cropTop, - int cropBottom); + void setCropping(int cropLeft, + int cropRight, + int cropTop, + int cropBottom); - void set3D(VideoMode mode); + void set3D(VideoMode mode); - void setSignalThreshold(double redSignalThreshold, - double greenSignalThreshold, - double blueSignalThreshold, - int noSignalCounterThreshold); + void setSignalThreshold(double redSignalThreshold, + double greenSignalThreshold, + double blueSignalThreshold, + int noSignalCounterThreshold); - void start(); + void start(); - void stop(); + void stop(); signals: - void newFrame(const Image & image); + void newFrame(const Image & image); private slots: - int read_frame(); + int read_frame(); private: - void open_device(); + void open_device(); - void close_device(); + void close_device(); - void init_read(unsigned int buffer_size); + void init_read(unsigned int buffer_size); - void init_mmap(); + void init_mmap(); - void init_userp(unsigned int buffer_size); + void init_userp(unsigned int buffer_size); - void init_device(VideoStandard videoStandard, int input); + void init_device(VideoStandard videoStandard, int input); - void uninit_device(); + void uninit_device(); - void start_capturing(); + void start_capturing(); - void stop_capturing(); + void stop_capturing(); - bool process_image(const void *p, int size); + bool process_image(const void *p, int size); - void process_image(const uint8_t *p); + void process_image(const uint8_t *p); - int xioctl(int request, void *arg); + int xioctl(int request, void *arg); - void throw_exception(const std::string &error); + void throw_exception(const std::string &error); - void throw_errno_exception(const std::string &error); + void throw_errno_exception(const std::string &error); private: - enum io_method { - IO_METHOD_READ, - IO_METHOD_MMAP, - IO_METHOD_USERPTR - }; + enum io_method { + IO_METHOD_READ, + IO_METHOD_MMAP, + IO_METHOD_USERPTR + }; - struct buffer { - void *start; - size_t length; - }; + struct buffer { + void *start; + size_t length; + }; private: - const std::string _deviceName; - const io_method _ioMethod; - int _fileDescriptor; - std::vector _buffers; + const std::string _deviceName; + const io_method _ioMethod; + int _fileDescriptor; + std::vector _buffers; - PixelFormat _pixelFormat; - int _width; - int _height; - int _lineLength; - int _frameByteSize; - int _frameDecimation; - int _noSignalCounterThreshold; + PixelFormat _pixelFormat; + int _width; + int _height; + int _lineLength; + int _frameByteSize; + int _frameDecimation; + int _noSignalCounterThreshold; - ColorRgb _noSignalThresholdColor; + ColorRgb _noSignalThresholdColor; - int _currentFrame; - int _noSignalCounter; + int _currentFrame; + int _noSignalCounter; - QSocketNotifier * _streamNotifier; + QSocketNotifier * _streamNotifier; - ImageResampler _imageResampler; + ImageResampler _imageResampler; }; diff --git a/include/grabber/X11Grabber.h b/include/grabber/X11Grabber.h index d8e4783c..5c2dd3b2 100644 --- a/include/grabber/X11Grabber.h +++ b/include/grabber/X11Grabber.h @@ -15,7 +15,7 @@ class X11Grabber { public: - X11Grabber(bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation); + X11Grabber(bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation); virtual ~X11Grabber(); @@ -26,16 +26,16 @@ public: Image & grab(); private: - ImageResampler _imageResampler; - - bool _useXGetImage, _XShmAvailable, _XShmPixmapAvailable, _XRenderAvailable; - int _cropLeft; - int _cropRight; - int _cropTop; - int _cropBottom; - - XImage* _xImage; - XShmSegmentInfo _shminfo; + ImageResampler _imageResampler; + + bool _useXGetImage, _XShmAvailable, _XShmPixmapAvailable, _XRenderAvailable; + int _cropLeft; + int _cropRight; + int _cropTop; + int _cropBottom; + + XImage* _xImage; + XShmSegmentInfo _shminfo; /// Reference to the X11 display (nullptr if not opened) Display* _x11Display; diff --git a/include/protoserver/ProtoConnection.h b/include/protoserver/ProtoConnection.h index 7ecd8f36..a6480eb6 100644 --- a/include/protoserver/ProtoConnection.h +++ b/include/protoserver/ProtoConnection.h @@ -23,90 +23,90 @@ class ProtoConnection : public QObject { -Q_OBJECT + Q_OBJECT public: - /// - /// Constructor - /// - /// @param address The address of the Hyperion server (for example "192.168.0.32:19444) - /// - ProtoConnection(const std::string & address); + /// + /// Constructor + /// + /// @param address The address of the Hyperion server (for example "192.168.0.32:19444) + /// + ProtoConnection(const std::string & address); - /// - /// Destructor - /// - ~ProtoConnection(); + /// + /// Destructor + /// + ~ProtoConnection(); - /// Do not read reply messages from Hyperion if set to true - void setSkipReply(bool skip); + /// Do not read reply messages from Hyperion if set to true + void setSkipReply(bool skip); - /// - /// Set all leds to the specified color - /// - /// @param color The color - /// @param priority The priority - /// @param duration The duration in milliseconds - /// - void setColor(const ColorRgb & color, int priority, int duration = 1); + /// + /// Set all leds to the specified color + /// + /// @param color The color + /// @param priority The priority + /// @param duration The duration in milliseconds + /// + void setColor(const ColorRgb & color, int priority, int duration = 1); - /// - /// Set the leds according to the given image (assume the image is stretched to the display size) - /// - /// @param image The image - /// @param priority The priority - /// @param duration The duration in milliseconds - /// - void setImage(const Image & image, int priority, int duration = -1); + /// + /// Set the leds according to the given image (assume the image is stretched to the display size) + /// + /// @param image The image + /// @param priority The priority + /// @param duration The duration in milliseconds + /// + void setImage(const Image & image, int priority, int duration = -1); - /// - /// Clear the given priority channel - /// - /// @param priority The priority - /// - void clear(int priority); + /// + /// Clear the given priority channel + /// + /// @param priority The priority + /// + void clear(int priority); - /// - /// Clear all priority channels - /// - void clearAll(); + /// + /// Clear all priority channels + /// + void clearAll(); - /// - /// Send a command message and receive its reply - /// - /// @param message The message to send - /// - void sendMessage(const proto::HyperionRequest & message); + /// + /// Send a command message and receive its reply + /// + /// @param message The message to send + /// + void sendMessage(const proto::HyperionRequest & message); private slots: - /// Try to connect to the Hyperion host - void connectToHost(); + /// Try to connect to the Hyperion host + void connectToHost(); private: - /// - /// Parse a reply message - /// - /// @param reply The received reply - /// - /// @return true if the reply indicates success - /// - bool parseReply(const proto::HyperionReply & reply); + /// + /// Parse a reply message + /// + /// @param reply The received reply + /// + /// @return true if the reply indicates success + /// + bool parseReply(const proto::HyperionReply & reply); private: - /// The TCP-Socket with the connection to the server - QTcpSocket _socket; + /// The TCP-Socket with the connection to the server + QTcpSocket _socket; - /// Host address - QString _host; + /// Host address + QString _host; - /// Host port - uint16_t _port; + /// Host port + uint16_t _port; - /// Skip receiving reply messages from Hyperion if set - bool _skipReply; + /// Skip receiving reply messages from Hyperion if set + bool _skipReply; - QTimer _timer; - QAbstractSocket::SocketState _prevSocketState; + QTimer _timer; + QAbstractSocket::SocketState _prevSocketState; }; diff --git a/include/protoserver/ProtoConnectionWrapper.h b/include/protoserver/ProtoConnectionWrapper.h index f5b072ea..7d2f3f6c 100644 --- a/include/protoserver/ProtoConnectionWrapper.h +++ b/include/protoserver/ProtoConnectionWrapper.h @@ -11,24 +11,24 @@ /// This class handles callbacks from the V4L2 grabber class ProtoConnectionWrapper : public QObject { - Q_OBJECT + Q_OBJECT public: - ProtoConnectionWrapper(const std::string & address, int priority, int duration_ms, bool skipProtoReply); - virtual ~ProtoConnectionWrapper(); + ProtoConnectionWrapper(const std::string & address, int priority, int duration_ms, bool skipProtoReply); + virtual ~ProtoConnectionWrapper(); public slots: - /// Handle a single image - /// @param image The image to process - void receiveImage(const Image & image); + /// Handle a single image + /// @param image The image to process + void receiveImage(const Image & image); private: - /// Priority for calls to Hyperion - const int _priority; + /// Priority for calls to Hyperion + const int _priority; - /// Duration for color calls to Hyperion - const int _duration_ms; + /// Duration for color calls to Hyperion + const int _duration_ms; - /// Hyperion proto connection object - ProtoConnection _connection; + /// Hyperion proto connection object + ProtoConnection _connection; }; diff --git a/include/utils/Image.h b/include/utils/Image.h index ece6155a..e8c82e48 100644 --- a/include/utils/Image.h +++ b/include/utils/Image.h @@ -13,221 +13,221 @@ class Image { public: - typedef Pixel_T pixel_type; + typedef Pixel_T pixel_type; - /// - /// Default constructor for an image - /// - Image() : - _width(1), - _height(1), - _pixels(new Pixel_T[2]), - _endOfPixels(_pixels + 1) - { - memset(_pixels, 0, 2*sizeof(Pixel_T)); - } + /// + /// Default constructor for an image + /// + Image() : + _width(1), + _height(1), + _pixels(new Pixel_T[2]), + _endOfPixels(_pixels + 1) + { + memset(_pixels, 0, 2*sizeof(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 - /// - Image(const unsigned width, const unsigned height) : - _width(width), - _height(height), - _pixels(new Pixel_T[width * height + 1]), - _endOfPixels(_pixels + width * height) - { - memset(_pixels, 0, (_width*_height+1)*sizeof(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 + /// + Image(const unsigned width, const unsigned height) : + _width(width), + _height(height), + _pixels(new Pixel_T[width * height + 1]), + _endOfPixels(_pixels + width * height) + { + memset(_pixels, 0, (_width*_height+1)*sizeof(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(const unsigned width, const unsigned height, const Pixel_T background) : - _width(width), - _height(height), - _pixels(new Pixel_T[width * height + 1]), - _endOfPixels(_pixels + width * height) - { - std::fill(_pixels, _endOfPixels, background); - } + /// + /// 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(const unsigned width, const unsigned height, const Pixel_T background) : + _width(width), + _height(height), + _pixels(new Pixel_T[width * height + 1]), + _endOfPixels(_pixels + width * height) + { + std::fill(_pixels, _endOfPixels, background); + } - /// - /// Copy constructor for an image - /// - Image(const Image & other) : - _width(other._width), - _height(other._height), - _pixels(new Pixel_T[other._width * other._height + 1]), - _endOfPixels(_pixels + other._width * other._height) - { - memcpy(_pixels, other._pixels, other._width * other._height * sizeof(Pixel_T)); - } + /// + /// Copy constructor for an image + /// + Image(const Image & other) : + _width(other._width), + _height(other._height), + _pixels(new Pixel_T[other._width * other._height + 1]), + _endOfPixels(_pixels + other._width * other._height) + { + memcpy(_pixels, other._pixels, other._width * other._height * sizeof(Pixel_T)); + } - /// - /// Destructor - /// - ~Image() - { - delete[] _pixels; - } + /// + /// Destructor + /// + ~Image() + { + delete[] _pixels; + } - /// - /// Returns the width of the image - /// - /// @return The width of the image - /// - inline unsigned width() const - { - return _width; - } + /// + /// Returns the width of the image + /// + /// @return The width of the image + /// + inline unsigned width() const + { + return _width; + } - /// - /// Returns the height of the image - /// - /// @return The height of the image - /// - inline unsigned height() const - { - return _height; - } + /// + /// Returns the height of the image + /// + /// @return The height of the image + /// + inline unsigned height() const + { + return _height; + } - uint8_t red(const unsigned pixel) const - { - return (_pixels + pixel)->red; - } + uint8_t red(const unsigned pixel) const + { + return (_pixels + pixel)->red; + } - uint8_t green(const unsigned pixel) const - { - return (_pixels + pixel)->green; - } + uint8_t green(const unsigned pixel) const + { + return (_pixels + pixel)->green; + } - uint8_t blue(const unsigned pixel) const - { - return (_pixels + pixel)->blue; - } + uint8_t blue(const unsigned pixel) const + { + return (_pixels + pixel)->blue; + } - /// - /// 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 - /// - const Pixel_T& operator()(const unsigned x, const unsigned y) const - { - return _pixels[toIndex(x,y)]; - } + /// + /// 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 + /// + const Pixel_T& operator()(const unsigned x, const unsigned y) const + { + return _pixels[toIndex(x,y)]; + } - /// - /// Returns a reference to a specified pixel in the image - /// - /// @param x The x index - /// @param y The y index - /// - /// @return reference to specified pixel - /// - Pixel_T& operator()(const unsigned x, const unsigned y) - { - return _pixels[toIndex(x,y)]; - } + /// + /// Returns a reference to a specified pixel in the image + /// + /// @param x The x index + /// @param y The y index + /// + /// @return reference to specified pixel + /// + Pixel_T& operator()(const unsigned x, const unsigned y) + { + return _pixels[toIndex(x,y)]; + } - /// Resize the image - /// @param width The width of the image - /// @param height The height of the image - void resize(const unsigned width, const unsigned height) - { - if ((width*height) > unsigned((_endOfPixels-_pixels))) - { - delete[] _pixels; - _pixels = new Pixel_T[width*height + 1]; - _endOfPixels = _pixels + width*height; - } + /// Resize the image + /// @param width The width of the image + /// @param height The height of the image + void resize(const unsigned width, const unsigned height) + { + if ((width*height) > unsigned((_endOfPixels-_pixels))) + { + delete[] _pixels; + _pixels = new Pixel_T[width*height + 1]; + _endOfPixels = _pixels + width*height; + } - _width = width; - _height = height; - } + _width = width; + _height = height; + } - /// - /// Copies another image into this image. The images should have exactly the same size. - /// - /// @param other The image to copy into this - /// - void copy(const Image& other) - { - assert(other._width == _width); - assert(other._height == _height); + /// + /// Copies another image into this image. The images should have exactly the same size. + /// + /// @param other The image to copy into this + /// + void copy(const Image& other) + { + assert(other._width == _width); + assert(other._height == _height); - memcpy(_pixels, other._pixels, _width*_height*sizeof(Pixel_T)); - } + memcpy(_pixels, other._pixels, _width*_height*sizeof(Pixel_T)); + } - /// - /// Returns a memory pointer to the first pixel in the image - /// @return The memory pointer to the first pixel - /// - Pixel_T* memptr() - { - return _pixels; - } + /// + /// Returns a memory pointer to the first pixel in the image + /// @return The memory pointer to the first pixel + /// + Pixel_T* memptr() + { + return _pixels; + } - /// - /// 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 _pixels; - } - - - /// - /// Convert image of any color order to a RGB image. - /// - /// @param[out] image The image that buffers the output - /// - void toRgb(Image& image) - { - image.resize(_width, _height); - const unsigned imageSize = _width * _height; + /// + /// 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 _pixels; + } - for (unsigned idx=0; idx& image) + { + image.resize(_width, _height); + const unsigned imageSize = _width * _height; + + for (unsigned idx=0; idx & outputImage) const; + void processImage(const uint8_t * data, int width, int height, int lineLength, PixelFormat pixelFormat, Image & outputImage) const; private: static inline uint8_t clamp(int x); diff --git a/include/utils/PixelFormat.h b/include/utils/PixelFormat.h index 3b56bdad..472b18f2 100644 --- a/include/utils/PixelFormat.h +++ b/include/utils/PixelFormat.h @@ -11,9 +11,9 @@ enum PixelFormat { PIXELFORMAT_UYVY, PIXELFORMAT_BGR16, PIXELFORMAT_BGR24, - PIXELFORMAT_RGB32, - PIXELFORMAT_BGR32, - PIXELFORMAT_NO_CHANGE + PIXELFORMAT_RGB32, + PIXELFORMAT_BGR32, + PIXELFORMAT_NO_CHANGE }; inline PixelFormat parsePixelFormat(std::string pixelFormat) @@ -29,22 +29,22 @@ inline PixelFormat parsePixelFormat(std::string pixelFormat) { return PIXELFORMAT_UYVY; } - else if (pixelFormat == "bgr16") - { - return PIXELFORMAT_BGR16; - } - else if (pixelFormat == "bgr24") - { - return PIXELFORMAT_BGR24; - } - else if (pixelFormat == "rgb32") - { - return PIXELFORMAT_RGB32; - } - else if (pixelFormat == "bgr32") - { - return PIXELFORMAT_BGR32; - } + else if (pixelFormat == "bgr16") + { + return PIXELFORMAT_BGR16; + } + else if (pixelFormat == "bgr24") + { + return PIXELFORMAT_BGR24; + } + else if (pixelFormat == "rgb32") + { + return PIXELFORMAT_RGB32; + } + else if (pixelFormat == "bgr32") + { + return PIXELFORMAT_BGR32; + } // return the default NO_CHANGE return PIXELFORMAT_NO_CHANGE; diff --git a/include/utils/Sleep.h b/include/utils/Sleep.h index a2c55815..95d2aa68 100644 --- a/include/utils/Sleep.h +++ b/include/utils/Sleep.h @@ -4,7 +4,7 @@ class Sleep : protected QThread { public: - static inline void msleep(unsigned long msecs) { - QThread::msleep(msecs); - } + static inline void msleep(unsigned long msecs) { + QThread::msleep(msecs); + } }; diff --git a/include/utils/jsonschema/JsonSchemaChecker.h b/include/utils/jsonschema/JsonSchemaChecker.h index 768b57db..d03a11e5 100644 --- a/include/utils/jsonschema/JsonSchemaChecker.h +++ b/include/utils/jsonschema/JsonSchemaChecker.h @@ -1,192 +1,192 @@ -#pragma once - -// stl includes -#include -#include - -// jsoncpp includes -#include - - -/// JsonSchemaChecker is a very basic implementation of json schema. -/// The json schema definition draft can be found at -/// http://tools.ietf.org/html/draft-zyp-json-schema-03 -/// -/// The following keywords are supported: -/// - type -/// - required -/// - properties -/// - items -/// - enum -/// - minimum -/// - maximum -/// - addtionalProperties -/// - minItems -/// - maxItems -/// -/// And the non-standard: -/// - dependencies -class JsonSchemaChecker -{ -public: - JsonSchemaChecker(); - virtual ~JsonSchemaChecker(); - - /// - /// @param schema The schema to use - /// @return true upon succes - /// - bool setSchema(const Json::Value & schema); - - /// - /// @brief Validate a JSON structure - /// @param value The JSON value to check - /// @return true when the arguments is valid according to the schema - /// - bool validate(const Json::Value & value); - - /// - /// @return A list of error messages - /// - const std::list & getMessages() const; - -private: - /// - /// Validates a json-value against a given schema. Results are stored in the members of this - /// class (_error & _messages) - /// - /// @param[in] value The value to validate - /// @param[in] schema The schema against which the value is validated - /// - void validate(const Json::Value &value, const Json::Value & schema); - - /// - /// Adds the given message to the message-queue (with reference to current line-number) - /// - /// @param[in] message The message to add to the queue - /// - void setMessage(const std::string & message); - - /// - /// Retrieves all references from the json-value as specified by the schema - /// - /// @param[in] value The json-value - /// @param[in] schema The schema - /// - void collectDependencies(const Json::Value & value, const Json::Value &schema); - -private: - // attribute check functions - /// - /// Checks if the given value is of the specified type. If the type does not match _error is set - /// to true and an error-message is added to the message-queue - /// - /// @param[in] value The given value - /// @param[in] schema The specified type (as json-value) - /// - void checkType(const Json::Value & value, const Json::Value & schema); - /// - /// Checks is required properties of an json-object exist and if all properties are of the - /// correct format. If this is not the case _error is set to true and an error-message is added - /// to the message-queue. - /// - /// @param[in] value The given json-object - /// @param[in] schema The schema of the json-object - /// - void checkProperties(const Json::Value & value, const Json::Value & schema); - - /// - /// Verifies the additional configured properties of an json-object. If this is not the case - /// _error is set to true and an error-message is added to the message-queue. - /// - /// @param value The given json-object - /// @param schema The schema for the json-object - /// @param ignoredProperties The properties that were ignored - /// - void checkAdditionalProperties(const Json::Value & value, const Json::Value & schema, const Json::Value::Members & ignoredProperties); - - /// - /// Checks if references are configued and used correctly. If this is not the case _error is set - /// to true and an error-message is added to the message-queue. - /// - /// @param value The given json-object - /// @param schemaLink The schema of the json-object - /// - void checkDependencies(const Json::Value & value, const Json::Value & schemaLink); - - /// - /// Checks if the given value is larger or equal to the specified value. If this is not the case - /// _error is set to true and an error-message is added to the message-queue. - /// - /// @param[in] value The given value - /// @param[in] schema The minimum value (as json-value) - /// - void checkMinimum(const Json::Value & value, const Json::Value & schema); - - /// - /// Checks if the given value is smaller or equal to the specified value. If this is not the - /// case _error is set to true and an error-message is added to the message-queue. - /// - /// @param[in] value The given value - /// @param[in] schema The maximum value (as json-value) - /// - void checkMaximum(const Json::Value & value, const Json::Value & schema); - - /// - /// Validates all the items of an array. - /// - /// @param value The json-array - /// @param schema The schema for the items in the array - /// - void checkItems(const Json::Value & value, const Json::Value & schema); - - /// - /// Checks if a given array has at least a minimum number of items. If this is not the case - /// _error is set to true and an error-message is added to the message-queue. - /// - /// @param value The json-array - /// @param schema The minimum size specification (as json-value) - /// - void checkMinItems(const Json::Value & value, const Json::Value & schema); - - /// - /// Checks if a given array has at most a maximum number of items. If this is not the case - /// _error is set to true and an error-message is added to the message-queue. - /// - /// @param value The json-array - /// @param schema The maximum size specification (as json-value) - /// - void checkMaxItems(const Json::Value & value, const Json::Value & schema); - - /// - /// Checks if a given array contains only unique items. If this is not the case - /// _error is set to true and an error-message is added to the message-queue. - /// - /// @param value The json-array - /// @param schema Bool to enable the check (as json-value) - /// - void checkUniqueItems(const Json::Value & value, const Json::Value & schema); - - /// - /// Checks if an enum value is actually a valid value for that enum. If this is not the case - /// _error is set to true and an error-message is added to the message-queue. - /// - /// @param value The enum value - /// @param schema The enum schema definition - /// - void checkEnum(const Json::Value & value, const Json::Value & schema); - -private: - /// The schema of the entire json-configuration - Json::Value _schema; - - /// The current location into a json-configuration structure being checked - std::list _currentPath; - /// The result messages collected during the schema verification - std::list _messages; - /// Flag indicating an error occured during validation - bool _error; - - /// A list with references (string => json-value) - std::map _references; // ref 2 value -}; +#pragma once + +// stl includes +#include +#include + +// jsoncpp includes +#include + + +/// JsonSchemaChecker is a very basic implementation of json schema. +/// The json schema definition draft can be found at +/// http://tools.ietf.org/html/draft-zyp-json-schema-03 +/// +/// The following keywords are supported: +/// - type +/// - required +/// - properties +/// - items +/// - enum +/// - minimum +/// - maximum +/// - addtionalProperties +/// - minItems +/// - maxItems +/// +/// And the non-standard: +/// - dependencies +class JsonSchemaChecker +{ +public: + JsonSchemaChecker(); + virtual ~JsonSchemaChecker(); + + /// + /// @param schema The schema to use + /// @return true upon succes + /// + bool setSchema(const Json::Value & schema); + + /// + /// @brief Validate a JSON structure + /// @param value The JSON value to check + /// @return true when the arguments is valid according to the schema + /// + bool validate(const Json::Value & value); + + /// + /// @return A list of error messages + /// + const std::list & getMessages() const; + +private: + /// + /// Validates a json-value against a given schema. Results are stored in the members of this + /// class (_error & _messages) + /// + /// @param[in] value The value to validate + /// @param[in] schema The schema against which the value is validated + /// + void validate(const Json::Value &value, const Json::Value & schema); + + /// + /// Adds the given message to the message-queue (with reference to current line-number) + /// + /// @param[in] message The message to add to the queue + /// + void setMessage(const std::string & message); + + /// + /// Retrieves all references from the json-value as specified by the schema + /// + /// @param[in] value The json-value + /// @param[in] schema The schema + /// + void collectDependencies(const Json::Value & value, const Json::Value &schema); + +private: + // attribute check functions + /// + /// Checks if the given value is of the specified type. If the type does not match _error is set + /// to true and an error-message is added to the message-queue + /// + /// @param[in] value The given value + /// @param[in] schema The specified type (as json-value) + /// + void checkType(const Json::Value & value, const Json::Value & schema); + /// + /// Checks is required properties of an json-object exist and if all properties are of the + /// correct format. If this is not the case _error is set to true and an error-message is added + /// to the message-queue. + /// + /// @param[in] value The given json-object + /// @param[in] schema The schema of the json-object + /// + void checkProperties(const Json::Value & value, const Json::Value & schema); + + /// + /// Verifies the additional configured properties of an json-object. If this is not the case + /// _error is set to true and an error-message is added to the message-queue. + /// + /// @param value The given json-object + /// @param schema The schema for the json-object + /// @param ignoredProperties The properties that were ignored + /// + void checkAdditionalProperties(const Json::Value & value, const Json::Value & schema, const Json::Value::Members & ignoredProperties); + + /// + /// Checks if references are configued and used correctly. If this is not the case _error is set + /// to true and an error-message is added to the message-queue. + /// + /// @param value The given json-object + /// @param schemaLink The schema of the json-object + /// + void checkDependencies(const Json::Value & value, const Json::Value & schemaLink); + + /// + /// Checks if the given value is larger or equal to the specified value. If this is not the case + /// _error is set to true and an error-message is added to the message-queue. + /// + /// @param[in] value The given value + /// @param[in] schema The minimum value (as json-value) + /// + void checkMinimum(const Json::Value & value, const Json::Value & schema); + + /// + /// Checks if the given value is smaller or equal to the specified value. If this is not the + /// case _error is set to true and an error-message is added to the message-queue. + /// + /// @param[in] value The given value + /// @param[in] schema The maximum value (as json-value) + /// + void checkMaximum(const Json::Value & value, const Json::Value & schema); + + /// + /// Validates all the items of an array. + /// + /// @param value The json-array + /// @param schema The schema for the items in the array + /// + void checkItems(const Json::Value & value, const Json::Value & schema); + + /// + /// Checks if a given array has at least a minimum number of items. If this is not the case + /// _error is set to true and an error-message is added to the message-queue. + /// + /// @param value The json-array + /// @param schema The minimum size specification (as json-value) + /// + void checkMinItems(const Json::Value & value, const Json::Value & schema); + + /// + /// Checks if a given array has at most a maximum number of items. If this is not the case + /// _error is set to true and an error-message is added to the message-queue. + /// + /// @param value The json-array + /// @param schema The maximum size specification (as json-value) + /// + void checkMaxItems(const Json::Value & value, const Json::Value & schema); + + /// + /// Checks if a given array contains only unique items. If this is not the case + /// _error is set to true and an error-message is added to the message-queue. + /// + /// @param value The json-array + /// @param schema Bool to enable the check (as json-value) + /// + void checkUniqueItems(const Json::Value & value, const Json::Value & schema); + + /// + /// Checks if an enum value is actually a valid value for that enum. If this is not the case + /// _error is set to true and an error-message is added to the message-queue. + /// + /// @param value The enum value + /// @param schema The enum schema definition + /// + void checkEnum(const Json::Value & value, const Json::Value & schema); + +private: + /// The schema of the entire json-configuration + Json::Value _schema; + + /// The current location into a json-configuration structure being checked + std::list _currentPath; + /// The result messages collected during the schema verification + std::list _messages; + /// Flag indicating an error occured during validation + bool _error; + + /// A list with references (string => json-value) + std::map _references; // ref 2 value +}; diff --git a/libsrc/CMakeLists.txt b/libsrc/CMakeLists.txt index 680e7a53..38ced39a 100644 --- a/libsrc/CMakeLists.txt +++ b/libsrc/CMakeLists.txt @@ -9,7 +9,7 @@ add_subdirectory(jsonserver) if (ENABLE_PROTOBUF) add_subdirectory(protoserver) -endif (ENABLE_PROTOBUF) +endif () add_subdirectory(boblightserver) add_subdirectory(leddevice) diff --git a/libsrc/blackborder/CMakeLists.txt b/libsrc/blackborder/CMakeLists.txt index 0d693c89..97d62739 100644 --- a/libsrc/blackborder/CMakeLists.txt +++ b/libsrc/blackborder/CMakeLists.txt @@ -1,23 +1,23 @@ - -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/blackborder) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/blackborder) - -SET(Blackborder_HEADERS - ${CURRENT_HEADER_DIR}/BlackBorderDetector.h - ${CURRENT_HEADER_DIR}/BlackBorderProcessor.h -) - -SET(Blackborder_SOURCES - ${CURRENT_SOURCE_DIR}/BlackBorderDetector.cpp - ${CURRENT_SOURCE_DIR}/BlackBorderProcessor.cpp -) - -add_library(blackborder - ${Blackborder_HEADERS} - ${Blackborder_SOURCES} -) - -target_link_libraries(blackborder - hyperion-utils -) + +# Define the current source locations +SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/blackborder) +SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/blackborder) + +SET(Blackborder_HEADERS + ${CURRENT_HEADER_DIR}/BlackBorderDetector.h + ${CURRENT_HEADER_DIR}/BlackBorderProcessor.h +) + +SET(Blackborder_SOURCES + ${CURRENT_SOURCE_DIR}/BlackBorderDetector.cpp + ${CURRENT_SOURCE_DIR}/BlackBorderProcessor.cpp +) + +add_library(blackborder + ${Blackborder_HEADERS} + ${Blackborder_SOURCES} +) + +target_link_libraries(blackborder + hyperion-utils +) diff --git a/libsrc/boblightserver/CMakeLists.txt b/libsrc/boblightserver/CMakeLists.txt index 33be4d17..c7a0e12d 100644 --- a/libsrc/boblightserver/CMakeLists.txt +++ b/libsrc/boblightserver/CMakeLists.txt @@ -1,40 +1,40 @@ - -# Define the current source locations -set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/boblightserver) -set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/boblightserver) - -# Group the headers that go through the MOC compiler -set(BoblightServer_QT_HEADERS - ${CURRENT_HEADER_DIR}/BoblightServer.h - ${CURRENT_SOURCE_DIR}/BoblightClientConnection.h -) - -set(BoblightServer_HEADERS -) - -set(BoblightServer_SOURCES - ${CURRENT_SOURCE_DIR}/BoblightServer.cpp - ${CURRENT_SOURCE_DIR}/BoblightClientConnection.cpp -) - -if(ENABLE_QT5) -qt5_wrap_cpp(BoblightServer_HEADERS_MOC ${BoblightServer_QT_HEADERS}) -else(ENABLE_QT5) -qt4_wrap_cpp(BoblightServer_HEADERS_MOC ${BoblightServer_QT_HEADERS}) -endif(ENABLE_QT5) - -add_library(boblightserver - ${BoblightServer_HEADERS} - ${BoblightServer_QT_HEADERS} - ${BoblightServer_SOURCES} - ${BoblightServer_HEADERS_MOC} -) - -if(ENABLE_QT5) -qt5_use_modules(boblightserver Widgets) -endif(ENABLE_QT5) - -target_link_libraries(boblightserver - hyperion - hyperion-utils - ${QT_LIBRARIES}) + +# Define the current source locations +set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/boblightserver) +set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/boblightserver) + +# Group the headers that go through the MOC compiler +set(BoblightServer_QT_HEADERS + ${CURRENT_HEADER_DIR}/BoblightServer.h + ${CURRENT_SOURCE_DIR}/BoblightClientConnection.h +) + +set(BoblightServer_HEADERS +) + +set(BoblightServer_SOURCES + ${CURRENT_SOURCE_DIR}/BoblightServer.cpp + ${CURRENT_SOURCE_DIR}/BoblightClientConnection.cpp +) + +if(ENABLE_QT5) + qt5_wrap_cpp(BoblightServer_HEADERS_MOC ${BoblightServer_QT_HEADERS}) +else() + qt4_wrap_cpp(BoblightServer_HEADERS_MOC ${BoblightServer_QT_HEADERS}) +endif() + +add_library(boblightserver + ${BoblightServer_HEADERS} + ${BoblightServer_QT_HEADERS} + ${BoblightServer_SOURCES} + ${BoblightServer_HEADERS_MOC} +) + +if(ENABLE_QT5) + qt5_use_modules(boblightserver Widgets) +endif() + +target_link_libraries(boblightserver + hyperion + hyperion-utils + ${QT_LIBRARIES}) diff --git a/libsrc/effectengine/CMakeLists.txt b/libsrc/effectengine/CMakeLists.txt index adb430e0..e3133213 100644 --- a/libsrc/effectengine/CMakeLists.txt +++ b/libsrc/effectengine/CMakeLists.txt @@ -13,8 +13,8 @@ SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/effectengine) # Group the headers that go through the MOC compiler SET(EffectEngineQT_HEADERS - ${CURRENT_HEADER_DIR}/EffectEngine.h - ${CURRENT_SOURCE_DIR}/Effect.h + ${CURRENT_HEADER_DIR}/EffectEngine.h + ${CURRENT_SOURCE_DIR}/Effect.h ) SET(EffectEngineHEADERS @@ -22,35 +22,34 @@ SET(EffectEngineHEADERS ) SET(EffectEngineSOURCES - ${CURRENT_SOURCE_DIR}/EffectEngine.cpp - ${CURRENT_SOURCE_DIR}/Effect.cpp + ${CURRENT_SOURCE_DIR}/EffectEngine.cpp + ${CURRENT_SOURCE_DIR}/Effect.cpp ) - set(EffectEngine_RESOURCES ${CURRENT_SOURCE_DIR}/EffectEngine.qrc) if(ENABLE_QT5) -QT5_WRAP_CPP(EffectEngineHEADERS_MOC ${EffectEngineQT_HEADERS}) -qt5_add_resources(EffectEngine_RESOURCES_RCC ${EffectEngine_RESOURCES} OPTIONS "-no-compress") -else(ENABLE_QT5) -QT4_WRAP_CPP(EffectEngineHEADERS_MOC ${EffectEngineQT_HEADERS}) -qt4_add_resources(EffectEngine_RESOURCES_RCC ${EffectEngine_RESOURCES} OPTIONS "-no-compress") -endif(ENABLE_QT5) + QT5_WRAP_CPP(EffectEngineHEADERS_MOC ${EffectEngineQT_HEADERS}) + qt5_add_resources(EffectEngine_RESOURCES_RCC ${EffectEngine_RESOURCES} OPTIONS "-no-compress") +else() + QT4_WRAP_CPP(EffectEngineHEADERS_MOC ${EffectEngineQT_HEADERS}) + qt4_add_resources(EffectEngine_RESOURCES_RCC ${EffectEngine_RESOURCES} OPTIONS "-no-compress") +endif() add_library(effectengine - ${EffectEngineHEADERS} - ${EffectEngineQT_HEADERS} - ${EffectEngineHEADERS_MOC} - ${EffectEngine_RESOURCES_RCC} - ${EffectEngineSOURCES} + ${EffectEngineHEADERS} + ${EffectEngineQT_HEADERS} + ${EffectEngineHEADERS_MOC} + ${EffectEngine_RESOURCES_RCC} + ${EffectEngineSOURCES} ) if(ENABLE_QT5) -qt5_use_modules(effectengine Widgets) -endif(ENABLE_QT5) + qt5_use_modules(effectengine Widgets) +endif() target_link_libraries(effectengine - hyperion - jsoncpp - ${QT_LIBRARIES} - ${PYTHON_LIBRARIES}) + hyperion + jsoncpp + ${QT_LIBRARIES} + ${PYTHON_LIBRARIES}) diff --git a/libsrc/effectengine/EffectDefinition.schema.json b/libsrc/effectengine/EffectDefinition.schema.json index 44733252..aa9c106a 100644 --- a/libsrc/effectengine/EffectDefinition.schema.json +++ b/libsrc/effectengine/EffectDefinition.schema.json @@ -1,342 +1,342 @@ -{ - "type" : "object", - "required" : true, - "properties" : { - "device" : { - "type" : "object", - "required" : true, - "properties" : { - "name" : { - "type" : "string", - "required" : true - }, - "type" : { - "type" : "string", - "required" : true - }, - "output" : { - "type" : "string", - "required" : true - }, - "rate" : { - "type" : "integer", - "required" : true, - "minimum" : 0 - }, - "colorOrder" : { - "type" : "string", - "required" : false - }, - "bgr-output" : { // deprecated - "type" : "boolean", - "required" : false - } - }, - "additionalProperties" : false - }, - "color": { - "type":"object", - "required":false, - "properties": { - "hsv" : { - "type" : "object", - "required" : false, - "properties" : { - "saturationGain" : { - "type" : "number", - "required" : false, - "minimum" : 0.0 - }, - "valueGain" : { - "type" : "number", - "required" : false, - "minimum" : 0.0 - } - }, - "additionalProperties" : false - }, - "red": { - "type":"object", - "required":false, - "properties":{ - "gamma": { - "type":"number", - "required":false - }, - "blacklevel": { - "type":"number", - "required":false - }, - "whitelevel": { - "type":"number", - "required":false - }, - "threshold": { - "type":"number", - "required":false, - "minimum" : 0.0, - "maximum" : 1.0 - } - }, - "additionalProperties" : false - }, - "green": { - "type":"object", - "required":false, - "properties":{ - "gamma": { - "type":"number", - "required":false - }, - "blacklevel": { - "type":"number", - "required":false - }, - "whitelevel": { - "type":"number", - "required":false - }, - "threshold": { - "type":"number", - "required":false, - "minimum" : 0.0, - "maximum" : 1.0 - } - }, - "additionalProperties" : false - }, - "blue": { - "type":"object", - "required":false, - "properties":{ - "gamma": { - "type":"number", - "required":false - }, - "whitelevel": { - "type":"number", - "required":false - }, - "blacklevel": { - "type":"number", - "required":false - }, - "threshold": { - "type":"number", - "required":false, - "minimum" : 0.0, - "maximum" : 1.0 - } - }, - "additionalProperties" : false - }, - "smoothing" : { - "type" : "object", - "required" : false, - "properties" : { - "type" : { - "type" : "enum", - "required" : true, - "values" : ["none", "linear"] - }, - "time_ms" : { - "type" : "integer", - "required" : false, - "minimum" : 10 - }, - "updateFrequency" : { - "type" : "number", - "required" : false, - "minimum" : 0.001 - } - }, - "additionalProperties" : false - } - - }, - "additionalProperties" : false - }, - "leds": { - "type":"array", - "required":true, - "items": { - "type":"object", - "properties": { - "index": { - "type":"integer", - "required":true - }, - "hscan": { - "type":"object", - "required":true, - "properties": { - "minimum": { - "type":"number", - "required":true - }, - "maximum": { - "type":"number", - "required":true - } - }, - "additionalProperties" : false - }, - "vscan": { - "type":"object", - "required":true, - "properties": { - "minimum": { - "type":"number", - "required":true - }, - "maximum": { - "type":"number", - "required":true - } - }, - "additionalProperties" : false - } - }, - "additionalProperties" : false - } - }, - "effects" : - { - "type" : "object", - "required" : false, - "properties" : { - "paths" : { - "type" : "array", - "required" : false, - "items" : { - "type" : "string" - } - } - }, - "additionalProperties" : false - }, - "blackborderdetector" : - { - "type" : "object", - "required" : false, - "properties" : { - "enable" : { - "type" : "boolean", - "required" : true - } - }, - "additionalProperties" : false - }, - "xbmcVideoChecker" : - { - "type" : "object", - "required" : false, - "properties" : { - "xbmcAddress" : { - "type" : "string", - "required" : true - }, - "xbmcTcpPort" : { - "type" : "integer", - "required" : true - }, - "grabVideo" : { - "type" : "boolean", - "required" : true - }, - "grabPictures" : { - "type" : "boolean", - "required" : true - }, - "grabAudio" : { - "type" : "boolean", - "required" : true - }, - "grabMenu" : { - "type" : "boolean", - "required" : true - } - }, - "additionalProperties" : false - }, - "bootsequence" : - { - "type" : "object", - "required" : false, - "properties" : { - "path" : { - "type" : "string", - "required" : true - }, - "effect" : { - "type" : "string", - "required" : true - } - }, - "additionalProperties" : false - }, - "framegrabber" : - { - "type" : "object", - "required" : false, - "properties" : { - "width" : { - "type" : "integer", - "required" : true - }, - "height" : { - "type" : "integer", - "required" : true - }, - "frequency_Hz" : { - "type" : "integer", - "required" : true - } - }, - "additionalProperties" : false - }, - "jsonServer" : - { - "type" : "object", - "required" : false, - "properties" : { - "port" : { - "type" : "integer", - "required" : true, - "minimum" : 0, - "maximum" : 65535 - } - }, - "additionalProperties" : false - }, - "protoServer" : - { - "type" : "object", - "required" : false, - "properties" : { - "port" : { - "type" : "integer", - "required" : true, - "minimum" : 0, - "maximum" : 65535 - } - }, - "additionalProperties" : false - }, - "boblightServer" : - { - "type" : "object", - "required" : false, - "properties" : { - "port" : { - "type" : "integer", - "required" : true, - "minimum" : 0, - "maximum" : 65535 - } - }, - "additionalProperties" : false - } - }, - "additionalProperties" : false -} +{ + "type" : "object", + "required" : true, + "properties" : { + "device" : { + "type" : "object", + "required" : true, + "properties" : { + "name" : { + "type" : "string", + "required" : true + }, + "type" : { + "type" : "string", + "required" : true + }, + "output" : { + "type" : "string", + "required" : true + }, + "rate" : { + "type" : "integer", + "required" : true, + "minimum" : 0 + }, + "colorOrder" : { + "type" : "string", + "required" : false + }, + "bgr-output" : { // deprecated + "type" : "boolean", + "required" : false + } + }, + "additionalProperties" : false + }, + "color": { + "type":"object", + "required":false, + "properties": { + "hsv" : { + "type" : "object", + "required" : false, + "properties" : { + "saturationGain" : { + "type" : "number", + "required" : false, + "minimum" : 0.0 + }, + "valueGain" : { + "type" : "number", + "required" : false, + "minimum" : 0.0 + } + }, + "additionalProperties" : false + }, + "red": { + "type":"object", + "required":false, + "properties":{ + "gamma": { + "type":"number", + "required":false + }, + "blacklevel": { + "type":"number", + "required":false + }, + "whitelevel": { + "type":"number", + "required":false + }, + "threshold": { + "type":"number", + "required":false, + "minimum" : 0.0, + "maximum" : 1.0 + } + }, + "additionalProperties" : false + }, + "green": { + "type":"object", + "required":false, + "properties":{ + "gamma": { + "type":"number", + "required":false + }, + "blacklevel": { + "type":"number", + "required":false + }, + "whitelevel": { + "type":"number", + "required":false + }, + "threshold": { + "type":"number", + "required":false, + "minimum" : 0.0, + "maximum" : 1.0 + } + }, + "additionalProperties" : false + }, + "blue": { + "type":"object", + "required":false, + "properties":{ + "gamma": { + "type":"number", + "required":false + }, + "whitelevel": { + "type":"number", + "required":false + }, + "blacklevel": { + "type":"number", + "required":false + }, + "threshold": { + "type":"number", + "required":false, + "minimum" : 0.0, + "maximum" : 1.0 + } + }, + "additionalProperties" : false + }, + "smoothing" : { + "type" : "object", + "required" : false, + "properties" : { + "type" : { + "type" : "enum", + "required" : true, + "values" : ["none", "linear"] + }, + "time_ms" : { + "type" : "integer", + "required" : false, + "minimum" : 10 + }, + "updateFrequency" : { + "type" : "number", + "required" : false, + "minimum" : 0.001 + } + }, + "additionalProperties" : false + } + + }, + "additionalProperties" : false + }, + "leds": { + "type":"array", + "required":true, + "items": { + "type":"object", + "properties": { + "index": { + "type":"integer", + "required":true + }, + "hscan": { + "type":"object", + "required":true, + "properties": { + "minimum": { + "type":"number", + "required":true + }, + "maximum": { + "type":"number", + "required":true + } + }, + "additionalProperties" : false + }, + "vscan": { + "type":"object", + "required":true, + "properties": { + "minimum": { + "type":"number", + "required":true + }, + "maximum": { + "type":"number", + "required":true + } + }, + "additionalProperties" : false + } + }, + "additionalProperties" : false + } + }, + "effects" : + { + "type" : "object", + "required" : false, + "properties" : { + "paths" : { + "type" : "array", + "required" : false, + "items" : { + "type" : "string" + } + } + }, + "additionalProperties" : false + }, + "blackborderdetector" : + { + "type" : "object", + "required" : false, + "properties" : { + "enable" : { + "type" : "boolean", + "required" : true + } + }, + "additionalProperties" : false + }, + "xbmcVideoChecker" : + { + "type" : "object", + "required" : false, + "properties" : { + "xbmcAddress" : { + "type" : "string", + "required" : true + }, + "xbmcTcpPort" : { + "type" : "integer", + "required" : true + }, + "grabVideo" : { + "type" : "boolean", + "required" : true + }, + "grabPictures" : { + "type" : "boolean", + "required" : true + }, + "grabAudio" : { + "type" : "boolean", + "required" : true + }, + "grabMenu" : { + "type" : "boolean", + "required" : true + } + }, + "additionalProperties" : false + }, + "bootsequence" : + { + "type" : "object", + "required" : false, + "properties" : { + "path" : { + "type" : "string", + "required" : true + }, + "effect" : { + "type" : "string", + "required" : true + } + }, + "additionalProperties" : false + }, + "framegrabber" : + { + "type" : "object", + "required" : false, + "properties" : { + "width" : { + "type" : "integer", + "required" : true + }, + "height" : { + "type" : "integer", + "required" : true + }, + "frequency_Hz" : { + "type" : "integer", + "required" : true + } + }, + "additionalProperties" : false + }, + "jsonServer" : + { + "type" : "object", + "required" : false, + "properties" : { + "port" : { + "type" : "integer", + "required" : true, + "minimum" : 0, + "maximum" : 65535 + } + }, + "additionalProperties" : false + }, + "protoServer" : + { + "type" : "object", + "required" : false, + "properties" : { + "port" : { + "type" : "integer", + "required" : true, + "minimum" : 0, + "maximum" : 65535 + } + }, + "additionalProperties" : false + }, + "boblightServer" : + { + "type" : "object", + "required" : false, + "properties" : { + "port" : { + "type" : "integer", + "required" : true, + "minimum" : 0, + "maximum" : 65535 + } + }, + "additionalProperties" : false + } + }, + "additionalProperties" : false +} diff --git a/libsrc/grabber/CMakeLists.txt b/libsrc/grabber/CMakeLists.txt index bb35f046..a075e79d 100644 --- a/libsrc/grabber/CMakeLists.txt +++ b/libsrc/grabber/CMakeLists.txt @@ -1,23 +1,23 @@ -if (ENABLE_AMLOGIC) - add_subdirectory(amlogic) -endif (ENABLE_AMLOGIC) - -if (ENABLE_DISPMANX) - add_subdirectory(dispmanx) -endif (ENABLE_DISPMANX) - -if (ENABLE_FB) - add_subdirectory(framebuffer) -endif (ENABLE_FB) - -if (ENABLE_OSX) - add_subdirectory(osx) -endif() - -if (ENABLE_V4L2) - add_subdirectory(v4l2) -endif (ENABLE_V4L2) - -if (ENABLE_X11) - add_subdirectory(x11) -endif() +if (ENABLE_AMLOGIC) + add_subdirectory(amlogic) +endif (ENABLE_AMLOGIC) + +if (ENABLE_DISPMANX) + add_subdirectory(dispmanx) +endif (ENABLE_DISPMANX) + +if (ENABLE_FB) + add_subdirectory(framebuffer) +endif (ENABLE_FB) + +if (ENABLE_OSX) + add_subdirectory(osx) +endif() + +if (ENABLE_V4L2) + add_subdirectory(v4l2) +endif (ENABLE_V4L2) + +if (ENABLE_X11) + add_subdirectory(x11) +endif() diff --git a/libsrc/grabber/amlogic/CMakeLists.txt b/libsrc/grabber/amlogic/CMakeLists.txt index 9ec98bfe..cf8844b9 100644 --- a/libsrc/grabber/amlogic/CMakeLists.txt +++ b/libsrc/grabber/amlogic/CMakeLists.txt @@ -1,33 +1,33 @@ - -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/amlogic) - -# Group the headers that go through the MOC compiler -SET(AmlogicQT_HEADERS ${CURRENT_HEADER_DIR}/AmlogicWrapper.h) - -SET(AmlogicHEADERS - ${CURRENT_HEADER_DIR}/AmlogicGrabber.h -) - -SET(AmlogicSOURCES - ${CURRENT_SOURCE_DIR}/AmlogicWrapper.cpp - ${CURRENT_SOURCE_DIR}/AmlogicGrabber.cpp -) - -if(ENABLE_QT5) -QT5_WRAP_CPP(AmlogicHEADERS_MOC ${AmlogicQT_HEADERS}) -else(ENABLE_QT5) -QT4_WRAP_CPP(AmlogicHEADERS_MOC ${AmlogicQT_HEADERS}) -endif(ENABLE_QT5) - -add_library(amlogic-grabber - ${AmlogicHEADERS} - ${AmlogicQT_HEADERS} - ${AmlogicHEADERS_MOC} - ${AmlogicSOURCES} -) - -target_link_libraries(amlogic-grabber - hyperion - ${QT_LIBRARIES}) + +# Define the current source locations +SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) +SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/amlogic) + +# Group the headers that go through the MOC compiler +SET(AmlogicQT_HEADERS ${CURRENT_HEADER_DIR}/AmlogicWrapper.h) + +SET(AmlogicHEADERS + ${CURRENT_HEADER_DIR}/AmlogicGrabber.h +) + +SET(AmlogicSOURCES + ${CURRENT_SOURCE_DIR}/AmlogicWrapper.cpp + ${CURRENT_SOURCE_DIR}/AmlogicGrabber.cpp +) + +if(ENABLE_QT5) +QT5_WRAP_CPP(AmlogicHEADERS_MOC ${AmlogicQT_HEADERS}) +else(ENABLE_QT5) +QT4_WRAP_CPP(AmlogicHEADERS_MOC ${AmlogicQT_HEADERS}) +endif(ENABLE_QT5) + +add_library(amlogic-grabber + ${AmlogicHEADERS} + ${AmlogicQT_HEADERS} + ${AmlogicHEADERS_MOC} + ${AmlogicSOURCES} +) + +target_link_libraries(amlogic-grabber + hyperion + ${QT_LIBRARIES}) diff --git a/libsrc/grabber/dispmanx/CMakeLists.txt b/libsrc/grabber/dispmanx/CMakeLists.txt index 4eb59e64..b453e3ab 100644 --- a/libsrc/grabber/dispmanx/CMakeLists.txt +++ b/libsrc/grabber/dispmanx/CMakeLists.txt @@ -1,41 +1,41 @@ - -# Find the BCM-package (VC control) -find_package(BCM REQUIRED) -include_directories(${BCM_INCLUDE_DIRS}) - -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/dispmanx) - -# Group the headers that go through the MOC compiler -SET(DispmanxGrabberQT_HEADERS - ${CURRENT_HEADER_DIR}/DispmanxWrapper.h -) - -SET(DispmanxGrabberHEADERS - ${CURRENT_HEADER_DIR}/DispmanxFrameGrabber.h -) - -SET(DispmanxGrabberSOURCES - ${CURRENT_SOURCE_DIR}/DispmanxWrapper.cpp - ${CURRENT_SOURCE_DIR}/DispmanxFrameGrabber.cpp -) - -if(ENABLE_QT5) - QT5_WRAP_CPP(DispmanxGrabberHEADERS_MOC ${DispmanxGrabberQT_HEADERS}) -else(ENABLE_QT5) - QT4_WRAP_CPP(DispmanxGrabberHEADERS_MOC ${DispmanxGrabberQT_HEADERS}) -endif(ENABLE_QT5) - -add_library(dispmanx-grabber - ${DispmanxGrabberHEADERS} - ${DispmanxGrabberQT_HEADERS} - ${DispmanxGrabberHEADERS_MOC} - ${DispmanxGrabberSOURCES} -) - -target_link_libraries(dispmanx-grabber - hyperion - ${QT_LIBRARIES} - ${BCM_LIBRARIES} -) + +# Find the BCM-package (VC control) +find_package(BCM REQUIRED) +include_directories(${BCM_INCLUDE_DIRS}) + +# Define the current source locations +SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) +SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/dispmanx) + +# Group the headers that go through the MOC compiler +SET(DispmanxGrabberQT_HEADERS + ${CURRENT_HEADER_DIR}/DispmanxWrapper.h +) + +SET(DispmanxGrabberHEADERS + ${CURRENT_HEADER_DIR}/DispmanxFrameGrabber.h +) + +SET(DispmanxGrabberSOURCES + ${CURRENT_SOURCE_DIR}/DispmanxWrapper.cpp + ${CURRENT_SOURCE_DIR}/DispmanxFrameGrabber.cpp +) + +if(ENABLE_QT5) + QT5_WRAP_CPP(DispmanxGrabberHEADERS_MOC ${DispmanxGrabberQT_HEADERS}) +else() + QT4_WRAP_CPP(DispmanxGrabberHEADERS_MOC ${DispmanxGrabberQT_HEADERS}) +endif() + +add_library(dispmanx-grabber + ${DispmanxGrabberHEADERS} + ${DispmanxGrabberQT_HEADERS} + ${DispmanxGrabberHEADERS_MOC} + ${DispmanxGrabberSOURCES} +) + +target_link_libraries(dispmanx-grabber + hyperion + ${QT_LIBRARIES} + ${BCM_LIBRARIES} +) diff --git a/libsrc/grabber/framebuffer/CMakeLists.txt b/libsrc/grabber/framebuffer/CMakeLists.txt index 0dec11f4..c001155c 100644 --- a/libsrc/grabber/framebuffer/CMakeLists.txt +++ b/libsrc/grabber/framebuffer/CMakeLists.txt @@ -9,31 +9,31 @@ SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/framebuffer) # Group the headers that go through the MOC compiler SET(FramebufferGrabberQT_HEADERS - ${CURRENT_HEADER_DIR}/FramebufferWrapper.h + ${CURRENT_HEADER_DIR}/FramebufferWrapper.h ) SET(FramebufferGrabberHEADERS - ${CURRENT_HEADER_DIR}/FramebufferFrameGrabber.h + ${CURRENT_HEADER_DIR}/FramebufferFrameGrabber.h ) SET(FramebufferGrabberSOURCES - ${CURRENT_SOURCE_DIR}/FramebufferWrapper.cpp - ${CURRENT_SOURCE_DIR}/FramebufferFrameGrabber.cpp + ${CURRENT_SOURCE_DIR}/FramebufferWrapper.cpp + ${CURRENT_SOURCE_DIR}/FramebufferFrameGrabber.cpp ) if(ENABLE_QT5) QT5_WRAP_CPP(FramebufferGrabberHEADERS_MOC ${FramebufferGrabberQT_HEADERS}) -else(ENABLE_QT5) +else() QT4_WRAP_CPP(FramebufferGrabberHEADERS_MOC ${FramebufferGrabberQT_HEADERS}) -endif(ENABLE_QT5) +endif() add_library(framebuffer-grabber - ${FramebufferGrabberHEADERS} - ${FramebufferGrabberQT_HEADERS} - ${FramebufferGrabberHEADERS_MOC} - ${FramebufferGrabberSOURCES} + ${FramebufferGrabberHEADERS} + ${FramebufferGrabberQT_HEADERS} + ${FramebufferGrabberHEADERS_MOC} + ${FramebufferGrabberSOURCES} ) target_link_libraries(framebuffer-grabber - hyperion - ${QT_LIBRARIES}) + hyperion + ${QT_LIBRARIES}) diff --git a/libsrc/grabber/osx/CMakeLists.txt b/libsrc/grabber/osx/CMakeLists.txt index ca72df4c..63bdfaa4 100644 --- a/libsrc/grabber/osx/CMakeLists.txt +++ b/libsrc/grabber/osx/CMakeLists.txt @@ -4,31 +4,31 @@ SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/osx) # Group the headers that go through the MOC compiler SET(OsxGrabberQT_HEADERS - ${CURRENT_HEADER_DIR}/OsxWrapper.h + ${CURRENT_HEADER_DIR}/OsxWrapper.h ) SET(OsxGrabberHEADERS - ${CURRENT_HEADER_DIR}/OsxFrameGrabber.h + ${CURRENT_HEADER_DIR}/OsxFrameGrabber.h ) SET(OsxGrabberSOURCES - ${CURRENT_SOURCE_DIR}/OsxWrapper.cpp - ${CURRENT_SOURCE_DIR}/OsxFrameGrabber.cpp + ${CURRENT_SOURCE_DIR}/OsxWrapper.cpp + ${CURRENT_SOURCE_DIR}/OsxFrameGrabber.cpp ) if(ENABLE_QT5) QT5_WRAP_CPP(OsxGrabberHEADERS_MOC ${OsxGrabberQT_HEADERS}) -else(ENABLE_QT5) +else() QT4_WRAP_CPP(OsxGrabberHEADERS_MOC ${OsxGrabberQT_HEADERS}) -endif(ENABLE_QT5) +endif() add_library(osx-grabber - ${OsxGrabberHEADERS} - ${OsxGrabberQT_HEADERS} - ${OsxGrabberHEADERS_MOC} - ${OsxGrabberSOURCES} + ${OsxGrabberHEADERS} + ${OsxGrabberQT_HEADERS} + ${OsxGrabberHEADERS_MOC} + ${OsxGrabberSOURCES} ) target_link_libraries(osx-grabber - hyperion - ${QT_LIBRARIES}) + hyperion + ${QT_LIBRARIES}) diff --git a/libsrc/grabber/v4l2/CMakeLists.txt b/libsrc/grabber/v4l2/CMakeLists.txt index 71de7806..56f81814 100644 --- a/libsrc/grabber/v4l2/CMakeLists.txt +++ b/libsrc/grabber/v4l2/CMakeLists.txt @@ -1,39 +1,39 @@ -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/v4l2) - -SET(V4L2_QT_HEADERS - ${CURRENT_HEADER_DIR}/V4L2Grabber.h - ${CURRENT_HEADER_DIR}/V4L2Wrapper.h -) - -SET(V4L2_HEADERS - ${CURRENT_HEADER_DIR}/VideoStandard.h -) - -SET(V4L2_SOURCES - ${CURRENT_SOURCE_DIR}/V4L2Grabber.cpp - ${CURRENT_SOURCE_DIR}/V4L2Wrapper.cpp -) - -if(ENABLE_QT5) -QT5_WRAP_CPP(V4L2_HEADERS_MOC ${V4L2_QT_HEADERS}) -else(ENABLE_QT5) -QT4_WRAP_CPP(V4L2_HEADERS_MOC ${V4L2_QT_HEADERS}) -endif(ENABLE_QT5) - -add_library(v4l2-grabber - ${V4L2_HEADERS} - ${V4L2_SOURCES} - ${V4L2_QT_HEADERS} - ${V4L2_HEADERS_MOC} -) - -if(ENABLE_QT5) -qt5_use_modules(v4l2-grabber Widgets) -endif(ENABLE_QT5) - -target_link_libraries(v4l2-grabber - hyperion - ${QT_LIBRARIES} -) +# Define the current source locations +SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) +SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/v4l2) + +SET(V4L2_QT_HEADERS + ${CURRENT_HEADER_DIR}/V4L2Grabber.h + ${CURRENT_HEADER_DIR}/V4L2Wrapper.h +) + +SET(V4L2_HEADERS + ${CURRENT_HEADER_DIR}/VideoStandard.h +) + +SET(V4L2_SOURCES + ${CURRENT_SOURCE_DIR}/V4L2Grabber.cpp + ${CURRENT_SOURCE_DIR}/V4L2Wrapper.cpp +) + +if(ENABLE_QT5) + QT5_WRAP_CPP(V4L2_HEADERS_MOC ${V4L2_QT_HEADERS}) +else() + QT4_WRAP_CPP(V4L2_HEADERS_MOC ${V4L2_QT_HEADERS}) +endif() + +add_library(v4l2-grabber + ${V4L2_HEADERS} + ${V4L2_SOURCES} + ${V4L2_QT_HEADERS} + ${V4L2_HEADERS_MOC} +) + +if(ENABLE_QT5) +qt5_use_modules(v4l2-grabber Widgets) +endif(ENABLE_QT5) + +target_link_libraries(v4l2-grabber + hyperion + ${QT_LIBRARIES} +) diff --git a/libsrc/grabber/v4l2/V4L2Grabber.cpp b/libsrc/grabber/v4l2/V4L2Grabber.cpp index 4bce3a57..1f65395f 100644 --- a/libsrc/grabber/v4l2/V4L2Grabber.cpp +++ b/libsrc/grabber/v4l2/V4L2Grabber.cpp @@ -19,720 +19,720 @@ #define CLEAR(x) memset(&(x), 0, sizeof(x)) V4L2Grabber::V4L2Grabber(const std::string & device, - int input, - VideoStandard videoStandard, - PixelFormat pixelFormat, - int width, - int height, - int frameDecimation, - int horizontalPixelDecimation, - int verticalPixelDecimation) : - _deviceName(device), - _ioMethod(IO_METHOD_MMAP), - _fileDescriptor(-1), - _buffers(), - _pixelFormat(pixelFormat), - _width(width), - _height(height), - _lineLength(-1), - _frameByteSize(-1), - _frameDecimation(std::max(1, frameDecimation)), - _noSignalCounterThreshold(50), - _noSignalThresholdColor(ColorRgb{0,0,0}), - _currentFrame(0), - _noSignalCounter(0), - _streamNotifier(nullptr), - _imageResampler() + int input, + VideoStandard videoStandard, + PixelFormat pixelFormat, + int width, + int height, + int frameDecimation, + int horizontalPixelDecimation, + int verticalPixelDecimation) : + _deviceName(device), + _ioMethod(IO_METHOD_MMAP), + _fileDescriptor(-1), + _buffers(), + _pixelFormat(pixelFormat), + _width(width), + _height(height), + _lineLength(-1), + _frameByteSize(-1), + _frameDecimation(std::max(1, frameDecimation)), + _noSignalCounterThreshold(50), + _noSignalThresholdColor(ColorRgb{0,0,0}), + _currentFrame(0), + _noSignalCounter(0), + _streamNotifier(nullptr), + _imageResampler() { - _imageResampler.setHorizontalPixelDecimation(std::max(1, horizontalPixelDecimation)); - _imageResampler.setVerticalPixelDecimation(std::max(1, verticalPixelDecimation)); + _imageResampler.setHorizontalPixelDecimation(std::max(1, horizontalPixelDecimation)); + _imageResampler.setVerticalPixelDecimation(std::max(1, verticalPixelDecimation)); - open_device(); - init_device(videoStandard, input); + open_device(); + init_device(videoStandard, input); } V4L2Grabber::~V4L2Grabber() { - // stop if the grabber was not stopped - stop(); - uninit_device(); - close_device(); + // stop if the grabber was not stopped + stop(); + uninit_device(); + close_device(); } void V4L2Grabber::setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom) { - _imageResampler.setCropping(cropLeft, cropRight, cropTop, cropBottom); + _imageResampler.setCropping(cropLeft, cropRight, cropTop, cropBottom); } void V4L2Grabber::set3D(VideoMode mode) { - _imageResampler.set3D(mode); + _imageResampler.set3D(mode); } void V4L2Grabber::setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold, int noSignalCounterThreshold) { - _noSignalThresholdColor.red = uint8_t(255*redSignalThreshold); - _noSignalThresholdColor.green = uint8_t(255*greenSignalThreshold); - _noSignalThresholdColor.blue = uint8_t(255*blueSignalThreshold); - _noSignalCounterThreshold = std::max(1, noSignalCounterThreshold); + _noSignalThresholdColor.red = uint8_t(255*redSignalThreshold); + _noSignalThresholdColor.green = uint8_t(255*greenSignalThreshold); + _noSignalThresholdColor.blue = uint8_t(255*blueSignalThreshold); + _noSignalCounterThreshold = std::max(1, noSignalCounterThreshold); - std::cout << "V4L2GRABBER INFO: signal threshold set to: " << _noSignalThresholdColor << std::endl; + std::cout << "V4L2GRABBER INFO: signal threshold set to: " << _noSignalThresholdColor << std::endl; } void V4L2Grabber::start() { - if (_streamNotifier != nullptr && !_streamNotifier->isEnabled()) - { - _streamNotifier->setEnabled(true); - start_capturing(); - std::cout << "V4L2GRABBER INFO: started" << std::endl; - } + if (_streamNotifier != nullptr && !_streamNotifier->isEnabled()) + { + _streamNotifier->setEnabled(true); + start_capturing(); + std::cout << "V4L2GRABBER INFO: started" << std::endl; + } } void V4L2Grabber::stop() { - if (_streamNotifier != nullptr && _streamNotifier->isEnabled()) - { - stop_capturing(); - _streamNotifier->setEnabled(false); - std::cout << "V4L2GRABBER INFO: stopped" << std::endl; - } + if (_streamNotifier != nullptr && _streamNotifier->isEnabled()) + { + stop_capturing(); + _streamNotifier->setEnabled(false); + std::cout << "V4L2GRABBER INFO: stopped" << std::endl; + } } void V4L2Grabber::open_device() { - struct stat st; + struct stat st; - if (-1 == stat(_deviceName.c_str(), &st)) - { - std::ostringstream oss; - oss << "V4L2GRABBER ERROR: Cannot identify '" << _deviceName << "'"; - throw_errno_exception(oss.str()); - } + if (-1 == stat(_deviceName.c_str(), &st)) + { + std::ostringstream oss; + oss << "V4L2GRABBER ERROR: Cannot identify '" << _deviceName << "'"; + throw_errno_exception(oss.str()); + } - if (!S_ISCHR(st.st_mode)) - { - std::ostringstream oss; - oss << "'" << _deviceName << "' is no device"; - throw_exception(oss.str()); - } + if (!S_ISCHR(st.st_mode)) + { + std::ostringstream oss; + oss << "'" << _deviceName << "' is no device"; + throw_exception(oss.str()); + } - _fileDescriptor = open(_deviceName.c_str(), O_RDWR /* required */ | O_NONBLOCK, 0); + _fileDescriptor = open(_deviceName.c_str(), O_RDWR /* required */ | O_NONBLOCK, 0); - if (-1 == _fileDescriptor) - { - std::ostringstream oss; - oss << "V4L2GRABBER ERROR: Cannot open '" << _deviceName << "'"; - throw_errno_exception(oss.str()); - } + if (-1 == _fileDescriptor) + { + std::ostringstream oss; + oss << "V4L2GRABBER ERROR: Cannot open '" << _deviceName << "'"; + throw_errno_exception(oss.str()); + } - // create the notifier for when a new frame is available - _streamNotifier = new QSocketNotifier(_fileDescriptor, QSocketNotifier::Read); - _streamNotifier->setEnabled(false); - connect(_streamNotifier, SIGNAL(activated(int)), this, SLOT(read_frame())); + // create the notifier for when a new frame is available + _streamNotifier = new QSocketNotifier(_fileDescriptor, QSocketNotifier::Read); + _streamNotifier->setEnabled(false); + connect(_streamNotifier, SIGNAL(activated(int)), this, SLOT(read_frame())); } void V4L2Grabber::close_device() { - if (-1 == close(_fileDescriptor)) - throw_errno_exception("close"); + if (-1 == close(_fileDescriptor)) + throw_errno_exception("close"); - _fileDescriptor = -1; + _fileDescriptor = -1; - if (_streamNotifier != nullptr) - { - delete _streamNotifier; - _streamNotifier = nullptr; - } + if (_streamNotifier != nullptr) + { + delete _streamNotifier; + _streamNotifier = nullptr; + } } void V4L2Grabber::init_read(unsigned int buffer_size) { - _buffers.resize(1); + _buffers.resize(1); - _buffers[0].length = buffer_size; - _buffers[0].start = malloc(buffer_size); + _buffers[0].length = buffer_size; + _buffers[0].start = malloc(buffer_size); - if (!_buffers[0].start) { - throw_exception("V4L2GRABBER ERROR: Out of memory"); - } + if (!_buffers[0].start) { + throw_exception("V4L2GRABBER ERROR: Out of memory"); + } } void V4L2Grabber::init_mmap() { - struct v4l2_requestbuffers req; + struct v4l2_requestbuffers req; - CLEAR(req); + CLEAR(req); - req.count = 4; - req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - req.memory = V4L2_MEMORY_MMAP; + req.count = 4; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_MMAP; - if (-1 == xioctl(VIDIOC_REQBUFS, &req)) { - if (EINVAL == errno) { - std::ostringstream oss; - oss << "'" << _deviceName << "' does not support memory mapping"; - throw_exception(oss.str()); - } else { - throw_errno_exception("VIDIOC_REQBUFS"); - } - } + if (-1 == xioctl(VIDIOC_REQBUFS, &req)) { + if (EINVAL == errno) { + std::ostringstream oss; + oss << "'" << _deviceName << "' does not support memory mapping"; + throw_exception(oss.str()); + } else { + throw_errno_exception("VIDIOC_REQBUFS"); + } + } - if (req.count < 2) { - std::ostringstream oss; - oss << "Insufficient buffer memory on " << _deviceName; - throw_exception(oss.str()); - } + if (req.count < 2) { + std::ostringstream oss; + oss << "Insufficient buffer memory on " << _deviceName; + throw_exception(oss.str()); + } - _buffers.resize(req.count); + _buffers.resize(req.count); - for (size_t n_buffers = 0; n_buffers < req.count; ++n_buffers) { - struct v4l2_buffer buf; + for (size_t n_buffers = 0; n_buffers < req.count; ++n_buffers) { + struct v4l2_buffer buf; - CLEAR(buf); + CLEAR(buf); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - buf.index = n_buffers; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = n_buffers; - if (-1 == xioctl(VIDIOC_QUERYBUF, &buf)) - throw_errno_exception("VIDIOC_QUERYBUF"); + if (-1 == xioctl(VIDIOC_QUERYBUF, &buf)) + throw_errno_exception("VIDIOC_QUERYBUF"); - _buffers[n_buffers].length = buf.length; - _buffers[n_buffers].start = - mmap(NULL /* start anywhere */, - buf.length, - PROT_READ | PROT_WRITE /* required */, - MAP_SHARED /* recommended */, - _fileDescriptor, buf.m.offset); + _buffers[n_buffers].length = buf.length; + _buffers[n_buffers].start = + mmap(NULL /* start anywhere */, + buf.length, + PROT_READ | PROT_WRITE /* required */, + MAP_SHARED /* recommended */, + _fileDescriptor, buf.m.offset); - if (MAP_FAILED == _buffers[n_buffers].start) - throw_errno_exception("mmap"); - } + if (MAP_FAILED == _buffers[n_buffers].start) + throw_errno_exception("mmap"); + } } void V4L2Grabber::init_userp(unsigned int buffer_size) { - struct v4l2_requestbuffers req; + struct v4l2_requestbuffers req; - CLEAR(req); + CLEAR(req); - req.count = 4; - req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - req.memory = V4L2_MEMORY_USERPTR; + req.count = 4; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_USERPTR; - if (-1 == xioctl(VIDIOC_REQBUFS, &req)) { - if (EINVAL == errno) - { - std::ostringstream oss; - oss << "'" << _deviceName << "' does not support user pointer"; - throw_exception(oss.str()); - } else { - throw_errno_exception("VIDIOC_REQBUFS"); - } - } + if (-1 == xioctl(VIDIOC_REQBUFS, &req)) { + if (EINVAL == errno) + { + std::ostringstream oss; + oss << "'" << _deviceName << "' does not support user pointer"; + throw_exception(oss.str()); + } else { + throw_errno_exception("VIDIOC_REQBUFS"); + } + } - _buffers.resize(4); + _buffers.resize(4); - for (size_t n_buffers = 0; n_buffers < 4; ++n_buffers) { - _buffers[n_buffers].length = buffer_size; - _buffers[n_buffers].start = malloc(buffer_size); + for (size_t n_buffers = 0; n_buffers < 4; ++n_buffers) { + _buffers[n_buffers].length = buffer_size; + _buffers[n_buffers].start = malloc(buffer_size); - if (!_buffers[n_buffers].start) { - throw_exception("V4L2GRABBER ERROR: Out of memory"); - } - } + if (!_buffers[n_buffers].start) { + throw_exception("V4L2GRABBER ERROR: Out of memory"); + } + } } void V4L2Grabber::init_device(VideoStandard videoStandard, int input) { - struct v4l2_capability cap; - if (-1 == xioctl(VIDIOC_QUERYCAP, &cap)) - { - if (EINVAL == errno) { - std::ostringstream oss; - oss << "'" << _deviceName << "' is no V4L2 device"; - throw_exception(oss.str()); - } else { - throw_errno_exception("VIDIOC_QUERYCAP"); - } - } + struct v4l2_capability cap; + if (-1 == xioctl(VIDIOC_QUERYCAP, &cap)) + { + if (EINVAL == errno) { + std::ostringstream oss; + oss << "'" << _deviceName << "' is no V4L2 device"; + throw_exception(oss.str()); + } else { + throw_errno_exception("VIDIOC_QUERYCAP"); + } + } - if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) - { - std::ostringstream oss; - oss << "'" << _deviceName << "' is no video capture device"; - throw_exception(oss.str()); - } + if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) + { + std::ostringstream oss; + oss << "'" << _deviceName << "' is no video capture device"; + throw_exception(oss.str()); + } - switch (_ioMethod) { - case IO_METHOD_READ: - if (!(cap.capabilities & V4L2_CAP_READWRITE)) - { - std::ostringstream oss; - oss << "'" << _deviceName << "' does not support read i/o"; - throw_exception(oss.str()); - } - break; + switch (_ioMethod) { + case IO_METHOD_READ: + if (!(cap.capabilities & V4L2_CAP_READWRITE)) + { + std::ostringstream oss; + oss << "'" << _deviceName << "' does not support read i/o"; + throw_exception(oss.str()); + } + break; - case IO_METHOD_MMAP: - case IO_METHOD_USERPTR: - if (!(cap.capabilities & V4L2_CAP_STREAMING)) - { - std::ostringstream oss; - oss << "'" << _deviceName << "' does not support streaming i/o"; - throw_exception(oss.str()); - } - break; - } + case IO_METHOD_MMAP: + case IO_METHOD_USERPTR: + if (!(cap.capabilities & V4L2_CAP_STREAMING)) + { + std::ostringstream oss; + oss << "'" << _deviceName << "' does not support streaming i/o"; + throw_exception(oss.str()); + } + break; + } - /* Select video input, video standard and tune here. */ + /* Select video input, video standard and tune here. */ - struct v4l2_cropcap cropcap; - CLEAR(cropcap); + struct v4l2_cropcap cropcap; + CLEAR(cropcap); - cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (0 == xioctl(VIDIOC_CROPCAP, &cropcap)) { - struct v4l2_crop crop; - crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - crop.c = cropcap.defrect; /* reset to default */ + if (0 == xioctl(VIDIOC_CROPCAP, &cropcap)) { + struct v4l2_crop crop; + crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + crop.c = cropcap.defrect; /* reset to default */ - if (-1 == xioctl(VIDIOC_S_CROP, &crop)) { - switch (errno) { - case EINVAL: - /* Cropping not supported. */ - break; - default: - /* Errors ignored. */ - break; - } - } - } else { - /* Errors ignored. */ - } + if (-1 == xioctl(VIDIOC_S_CROP, &crop)) { + switch (errno) { + case EINVAL: + /* Cropping not supported. */ + break; + default: + /* Errors ignored. */ + break; + } + } + } else { + /* Errors ignored. */ + } - // set input if needed - if (input >= 0) - { - if (-1 == xioctl(VIDIOC_S_INPUT, &input)) - { - throw_errno_exception("VIDIOC_S_INPUT"); - } - } + // set input if needed + if (input >= 0) + { + if (-1 == xioctl(VIDIOC_S_INPUT, &input)) + { + throw_errno_exception("VIDIOC_S_INPUT"); + } + } - // set the video standard if needed - switch (videoStandard) - { - case VIDEOSTANDARD_PAL: - { - v4l2_std_id std_id = V4L2_STD_PAL; - if (-1 == xioctl(VIDIOC_S_STD, &std_id)) - { - throw_errno_exception("VIDIOC_S_STD"); - } - } - break; - case VIDEOSTANDARD_NTSC: - { - v4l2_std_id std_id = V4L2_STD_NTSC; - if (-1 == xioctl(VIDIOC_S_STD, &std_id)) - { - throw_errno_exception("VIDIOC_S_STD"); - } - } - break; - case VIDEOSTANDARD_NO_CHANGE: - default: - // No change to device settings - break; - } + // set the video standard if needed + switch (videoStandard) + { + case VIDEOSTANDARD_PAL: + { + v4l2_std_id std_id = V4L2_STD_PAL; + if (-1 == xioctl(VIDIOC_S_STD, &std_id)) + { + throw_errno_exception("VIDIOC_S_STD"); + } + } + break; + case VIDEOSTANDARD_NTSC: + { + v4l2_std_id std_id = V4L2_STD_NTSC; + if (-1 == xioctl(VIDIOC_S_STD, &std_id)) + { + throw_errno_exception("VIDIOC_S_STD"); + } + } + break; + case VIDEOSTANDARD_NO_CHANGE: + default: + // No change to device settings + break; + } - // get the current settings - struct v4l2_format fmt; - CLEAR(fmt); - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (-1 == xioctl(VIDIOC_G_FMT, &fmt)) - { - throw_errno_exception("VIDIOC_G_FMT"); - } + // get the current settings + struct v4l2_format fmt; + CLEAR(fmt); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl(VIDIOC_G_FMT, &fmt)) + { + throw_errno_exception("VIDIOC_G_FMT"); + } - // set the requested pixel format - switch (_pixelFormat) - { - case PIXELFORMAT_UYVY: - fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; - break; - case PIXELFORMAT_YUYV: - fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - break; - case PIXELFORMAT_RGB32: - fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; - break; - case PIXELFORMAT_NO_CHANGE: - default: - // No change to device settings - break; - } + // set the requested pixel format + switch (_pixelFormat) + { + case PIXELFORMAT_UYVY: + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; + break; + case PIXELFORMAT_YUYV: + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + break; + case PIXELFORMAT_RGB32: + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; + break; + case PIXELFORMAT_NO_CHANGE: + default: + // No change to device settings + break; + } - // set the requested withd and height - if (_width > 0 || _height > 0) - { - if (_width > 0) - { - fmt.fmt.pix.width = _width; - } + // set the requested withd and height + if (_width > 0 || _height > 0) + { + if (_width > 0) + { + fmt.fmt.pix.width = _width; + } - if (fmt.fmt.pix.height > 0) - { - fmt.fmt.pix.height = _height; - } - } + if (fmt.fmt.pix.height > 0) + { + fmt.fmt.pix.height = _height; + } + } - // set the line length - _lineLength = fmt.fmt.pix.bytesperline; + // set the line length + _lineLength = fmt.fmt.pix.bytesperline; - // set the settings - if (-1 == xioctl(VIDIOC_S_FMT, &fmt)) - { - throw_errno_exception("VIDIOC_S_FMT"); - } + // set the settings + if (-1 == xioctl(VIDIOC_S_FMT, &fmt)) + { + throw_errno_exception("VIDIOC_S_FMT"); + } - // get the format settings again - // (the size may not have been accepted without an error) - if (-1 == xioctl(VIDIOC_G_FMT, &fmt)) - { - throw_errno_exception("VIDIOC_G_FMT"); - } + // get the format settings again + // (the size may not have been accepted without an error) + if (-1 == xioctl(VIDIOC_G_FMT, &fmt)) + { + throw_errno_exception("VIDIOC_G_FMT"); + } - // store width & height - _width = fmt.fmt.pix.width; - _height = fmt.fmt.pix.height; + // store width & height + _width = fmt.fmt.pix.width; + _height = fmt.fmt.pix.height; - // print the eventually used width and height - std::cout << "V4L2GRABBER INFO: width=" << _width << " height=" << _height << std::endl; + // print the eventually used width and height + std::cout << "V4L2GRABBER INFO: width=" << _width << " height=" << _height << std::endl; - // check pixel format and frame size - switch (fmt.fmt.pix.pixelformat) - { - case V4L2_PIX_FMT_UYVY: - _pixelFormat = PIXELFORMAT_UYVY; - _frameByteSize = _width * _height * 2; - std::cout << "V4L2GRABBER INFO: pixel format=UYVY" << std::endl; - break; - case V4L2_PIX_FMT_YUYV: - _pixelFormat = PIXELFORMAT_YUYV; - _frameByteSize = _width * _height * 2; - std::cout << "V4L2GRABBER INFO: pixel format=YUYV" << std::endl; - break; - case V4L2_PIX_FMT_RGB32: - _pixelFormat = PIXELFORMAT_RGB32; - _frameByteSize = _width * _height * 4; - std::cout << "V4L2GRABBER INFO: pixel format=RGB32" << std::endl; - break; - default: - throw_exception("V4L2GRABBER ERROR: Only pixel formats UYVY, YUYV, and RGB32 are supported"); - } + // check pixel format and frame size + switch (fmt.fmt.pix.pixelformat) + { + case V4L2_PIX_FMT_UYVY: + _pixelFormat = PIXELFORMAT_UYVY; + _frameByteSize = _width * _height * 2; + std::cout << "V4L2GRABBER INFO: pixel format=UYVY" << std::endl; + break; + case V4L2_PIX_FMT_YUYV: + _pixelFormat = PIXELFORMAT_YUYV; + _frameByteSize = _width * _height * 2; + std::cout << "V4L2GRABBER INFO: pixel format=YUYV" << std::endl; + break; + case V4L2_PIX_FMT_RGB32: + _pixelFormat = PIXELFORMAT_RGB32; + _frameByteSize = _width * _height * 4; + std::cout << "V4L2GRABBER INFO: pixel format=RGB32" << std::endl; + break; + default: + throw_exception("V4L2GRABBER ERROR: Only pixel formats UYVY, YUYV, and RGB32 are supported"); + } - switch (_ioMethod) { - case IO_METHOD_READ: - init_read(fmt.fmt.pix.sizeimage); - break; + switch (_ioMethod) { + case IO_METHOD_READ: + init_read(fmt.fmt.pix.sizeimage); + break; - case IO_METHOD_MMAP: - init_mmap(); - break; + case IO_METHOD_MMAP: + init_mmap(); + break; - case IO_METHOD_USERPTR: - init_userp(fmt.fmt.pix.sizeimage); - break; - } + case IO_METHOD_USERPTR: + init_userp(fmt.fmt.pix.sizeimage); + break; + } } void V4L2Grabber::uninit_device() { - switch (_ioMethod) { - case IO_METHOD_READ: - free(_buffers[0].start); - break; + switch (_ioMethod) { + case IO_METHOD_READ: + free(_buffers[0].start); + break; - case IO_METHOD_MMAP: - for (size_t i = 0; i < _buffers.size(); ++i) - if (-1 == munmap(_buffers[i].start, _buffers[i].length)) - throw_errno_exception("munmap"); - break; + case IO_METHOD_MMAP: + for (size_t i = 0; i < _buffers.size(); ++i) + if (-1 == munmap(_buffers[i].start, _buffers[i].length)) + throw_errno_exception("munmap"); + break; - case IO_METHOD_USERPTR: - for (size_t i = 0; i < _buffers.size(); ++i) - free(_buffers[i].start); - break; - } + case IO_METHOD_USERPTR: + for (size_t i = 0; i < _buffers.size(); ++i) + free(_buffers[i].start); + break; + } - _buffers.resize(0); + _buffers.resize(0); } void V4L2Grabber::start_capturing() { - switch (_ioMethod) { - case IO_METHOD_READ: - /* Nothing to do. */ - break; + switch (_ioMethod) { + case IO_METHOD_READ: + /* Nothing to do. */ + break; - case IO_METHOD_MMAP: - { - for (size_t i = 0; i < _buffers.size(); ++i) { - struct v4l2_buffer buf; + case IO_METHOD_MMAP: + { + for (size_t i = 0; i < _buffers.size(); ++i) { + struct v4l2_buffer buf; - CLEAR(buf); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - buf.index = i; + CLEAR(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; - if (-1 == xioctl(VIDIOC_QBUF, &buf)) - throw_errno_exception("VIDIOC_QBUF"); - } - v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (-1 == xioctl(VIDIOC_STREAMON, &type)) - throw_errno_exception("VIDIOC_STREAMON"); - break; - } - case IO_METHOD_USERPTR: - { - for (size_t i = 0; i < _buffers.size(); ++i) { - struct v4l2_buffer buf; + if (-1 == xioctl(VIDIOC_QBUF, &buf)) + throw_errno_exception("VIDIOC_QBUF"); + } + v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl(VIDIOC_STREAMON, &type)) + throw_errno_exception("VIDIOC_STREAMON"); + break; + } + case IO_METHOD_USERPTR: + { + for (size_t i = 0; i < _buffers.size(); ++i) { + struct v4l2_buffer buf; - CLEAR(buf); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_USERPTR; - buf.index = i; - buf.m.userptr = (unsigned long)_buffers[i].start; - buf.length = _buffers[i].length; + CLEAR(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_USERPTR; + buf.index = i; + buf.m.userptr = (unsigned long)_buffers[i].start; + buf.length = _buffers[i].length; - if (-1 == xioctl(VIDIOC_QBUF, &buf)) - throw_errno_exception("VIDIOC_QBUF"); - } - v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (-1 == xioctl(VIDIOC_STREAMON, &type)) - throw_errno_exception("VIDIOC_STREAMON"); - break; - } - } + if (-1 == xioctl(VIDIOC_QBUF, &buf)) + throw_errno_exception("VIDIOC_QBUF"); + } + v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl(VIDIOC_STREAMON, &type)) + throw_errno_exception("VIDIOC_STREAMON"); + break; + } + } } void V4L2Grabber::stop_capturing() { - enum v4l2_buf_type type; + enum v4l2_buf_type type; - switch (_ioMethod) { - case IO_METHOD_READ: - /* Nothing to do. */ - break; + switch (_ioMethod) { + case IO_METHOD_READ: + /* Nothing to do. */ + break; - case IO_METHOD_MMAP: - case IO_METHOD_USERPTR: - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (-1 == xioctl(VIDIOC_STREAMOFF, &type)) - throw_errno_exception("VIDIOC_STREAMOFF"); - break; - } + case IO_METHOD_MMAP: + case IO_METHOD_USERPTR: + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl(VIDIOC_STREAMOFF, &type)) + throw_errno_exception("VIDIOC_STREAMOFF"); + break; + } } int V4L2Grabber::read_frame() { - bool rc = false; + bool rc = false; - struct v4l2_buffer buf; + struct v4l2_buffer buf; - switch (_ioMethod) { - case IO_METHOD_READ: - int size; - if ((size = read(_fileDescriptor, _buffers[0].start, _buffers[0].length)) == -1) - { - switch (errno) - { - case EAGAIN: - return 0; + switch (_ioMethod) { + case IO_METHOD_READ: + int size; + if ((size = read(_fileDescriptor, _buffers[0].start, _buffers[0].length)) == -1) + { + switch (errno) + { + case EAGAIN: + return 0; - case EIO: - /* Could ignore EIO, see spec. */ + case EIO: + /* Could ignore EIO, see spec. */ - /* fall through */ + /* fall through */ - default: - throw_errno_exception("read"); - } - } + default: + throw_errno_exception("read"); + } + } - rc = process_image(_buffers[0].start, size); - break; + rc = process_image(_buffers[0].start, size); + break; - case IO_METHOD_MMAP: - CLEAR(buf); + case IO_METHOD_MMAP: + CLEAR(buf); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; - if (-1 == xioctl(VIDIOC_DQBUF, &buf)) - { - switch (errno) - { - case EAGAIN: - return 0; + if (-1 == xioctl(VIDIOC_DQBUF, &buf)) + { + switch (errno) + { + case EAGAIN: + return 0; - case EIO: - /* Could ignore EIO, see spec. */ + case EIO: + /* Could ignore EIO, see spec. */ - /* fall through */ + /* fall through */ - default: - throw_errno_exception("VIDIOC_DQBUF"); - } - } + default: + throw_errno_exception("VIDIOC_DQBUF"); + } + } - assert(buf.index < _buffers.size()); + assert(buf.index < _buffers.size()); - rc = process_image(_buffers[buf.index].start, buf.bytesused); + rc = process_image(_buffers[buf.index].start, buf.bytesused); - if (-1 == xioctl(VIDIOC_QBUF, &buf)) - { - throw_errno_exception("VIDIOC_QBUF"); - } + if (-1 == xioctl(VIDIOC_QBUF, &buf)) + { + throw_errno_exception("VIDIOC_QBUF"); + } - break; + break; - case IO_METHOD_USERPTR: - CLEAR(buf); + case IO_METHOD_USERPTR: + CLEAR(buf); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_USERPTR; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_USERPTR; - if (-1 == xioctl(VIDIOC_DQBUF, &buf)) - { - switch (errno) - { - case EAGAIN: - return 0; + if (-1 == xioctl(VIDIOC_DQBUF, &buf)) + { + switch (errno) + { + case EAGAIN: + return 0; - case EIO: - /* Could ignore EIO, see spec. */ + case EIO: + /* Could ignore EIO, see spec. */ - /* fall through */ + /* fall through */ - default: - throw_errno_exception("VIDIOC_DQBUF"); - } - } + default: + throw_errno_exception("VIDIOC_DQBUF"); + } + } - for (size_t i = 0; i < _buffers.size(); ++i) - { - if (buf.m.userptr == (unsigned long)_buffers[i].start && buf.length == _buffers[i].length) - { - break; - } - } + for (size_t i = 0; i < _buffers.size(); ++i) + { + if (buf.m.userptr == (unsigned long)_buffers[i].start && buf.length == _buffers[i].length) + { + break; + } + } - rc = process_image((void *)buf.m.userptr, buf.bytesused); + rc = process_image((void *)buf.m.userptr, buf.bytesused); - if (-1 == xioctl(VIDIOC_QBUF, &buf)) - { - throw_errno_exception("VIDIOC_QBUF"); - } - break; - } + if (-1 == xioctl(VIDIOC_QBUF, &buf)) + { + throw_errno_exception("VIDIOC_QBUF"); + } + break; + } - return rc ? 1 : 0; + return rc ? 1 : 0; } bool V4L2Grabber::process_image(const void *p, int size) { - if (++_currentFrame >= _frameDecimation) - { - // We do want a new frame... + if (++_currentFrame >= _frameDecimation) + { + // We do want a new frame... - if (size != _frameByteSize) - { - std::cout << "V4L2GRABBER ERROR: Frame too small: " << size << " != " << _frameByteSize << std::endl; - } - else - { - process_image(reinterpret_cast(p)); - _currentFrame = 0; // restart counting - return true; - } - } + if (size != _frameByteSize) + { + std::cout << "V4L2GRABBER ERROR: Frame too small: " << size << " != " << _frameByteSize << std::endl; + } + else + { + process_image(reinterpret_cast(p)); + _currentFrame = 0; // restart counting + return true; + } + } - return false; + return false; } void V4L2Grabber::process_image(const uint8_t * data) { - Image image(0, 0); - _imageResampler.processImage(data, _width, _height, _lineLength, _pixelFormat, image); + Image image(0, 0); + _imageResampler.processImage(data, _width, _height, _lineLength, _pixelFormat, image); - // check signal (only in center of the resulting image, because some grabbers have noise values along the borders) - bool noSignal = true; - for (unsigned x = 0; noSignal && x < (image.width()>>1); ++x) - { - int xImage = (image.width()>>2) + x; + // check signal (only in center of the resulting image, because some grabbers have noise values along the borders) + bool noSignal = true; + for (unsigned x = 0; noSignal && x < (image.width()>>1); ++x) + { + int xImage = (image.width()>>2) + x; - for (unsigned y = 0; noSignal && y < (image.height()>>1); ++y) - { - int yImage = (image.height()>>2) + y; + for (unsigned y = 0; noSignal && y < (image.height()>>1); ++y) + { + int yImage = (image.height()>>2) + y; - ColorRgb & rgb = image(xImage, yImage); - noSignal &= rgb <= _noSignalThresholdColor; - } - } + ColorRgb & rgb = image(xImage, yImage); + noSignal &= rgb <= _noSignalThresholdColor; + } + } - if (noSignal) - { - ++_noSignalCounter; - } - else - { - if (_noSignalCounter >= _noSignalCounterThreshold) - { - std::cout << "V4L2GRABBER INFO: " << "Signal detected" << std::endl; - } + if (noSignal) + { + ++_noSignalCounter; + } + else + { + if (_noSignalCounter >= _noSignalCounterThreshold) + { + std::cout << "V4L2GRABBER INFO: " << "Signal detected" << std::endl; + } - _noSignalCounter = 0; - } + _noSignalCounter = 0; + } - if (_noSignalCounter < _noSignalCounterThreshold) - { - emit newFrame(image); - } - else if (_noSignalCounter == _noSignalCounterThreshold) - { - std::cout << "V4L2GRABBER INFO: " << "Signal lost" << std::endl; - } + if (_noSignalCounter < _noSignalCounterThreshold) + { + emit newFrame(image); + } + else if (_noSignalCounter == _noSignalCounterThreshold) + { + std::cout << "V4L2GRABBER INFO: " << "Signal lost" << std::endl; + } } int V4L2Grabber::xioctl(int request, void *arg) { - int r; + int r; - do - { - r = ioctl(_fileDescriptor, request, arg); - } - while (-1 == r && EINTR == errno); + do + { + r = ioctl(_fileDescriptor, request, arg); + } + while (-1 == r && EINTR == errno); - return r; + return r; } void V4L2Grabber::throw_exception(const std::string & error) { - std::ostringstream oss; - oss << error << " ERROR"; - throw std::runtime_error(oss.str()); + std::ostringstream oss; + oss << error << " ERROR"; + throw std::runtime_error(oss.str()); } void V4L2Grabber::throw_errno_exception(const std::string & error) { - std::ostringstream oss; - oss << error << " ERROR " << errno << ", " << strerror(errno); - throw std::runtime_error(oss.str()); + std::ostringstream oss; + oss << error << " ERROR " << errno << ", " << strerror(errno); + throw std::runtime_error(oss.str()); } diff --git a/libsrc/grabber/x11/CMakeLists.txt b/libsrc/grabber/x11/CMakeLists.txt index 4d8ead6d..cd1bb0f0 100644 --- a/libsrc/grabber/x11/CMakeLists.txt +++ b/libsrc/grabber/x11/CMakeLists.txt @@ -19,20 +19,20 @@ SET(X11_HEADERS ) SET(X11_SOURCES - ${CURRENT_SOURCE_DIR}/X11Grabber.cpp + ${CURRENT_SOURCE_DIR}/X11Grabber.cpp ) if(ENABLE_QT5) -QT5_WRAP_CPP(X11_HEADERS_MOC ${X11_QT_HEADERS}) -else(ENABLE_QT5) -QT4_WRAP_CPP(X11_HEADERS_MOC ${X11_QT_HEADERS}) -endif(ENABLE_QT5) + QT5_WRAP_CPP(X11_HEADERS_MOC ${X11_QT_HEADERS}) +else() + QT4_WRAP_CPP(X11_HEADERS_MOC ${X11_QT_HEADERS}) +endif() add_library(x11-grabber - ${X11_HEADERS} - ${X11_SOURCES} - ${X11_QT_HEADERS} - ${X11_HEADERS_MOC} + ${X11_HEADERS} + ${X11_SOURCES} + ${X11_QT_HEADERS} + ${X11_HEADERS_MOC} ) target_link_libraries(x11-grabber diff --git a/libsrc/grabber/x11/X11Grabber.cpp b/libsrc/grabber/x11/X11Grabber.cpp index 4d4d6fa7..5b662288 100644 --- a/libsrc/grabber/x11/X11Grabber.cpp +++ b/libsrc/grabber/x11/X11Grabber.cpp @@ -6,107 +6,108 @@ #include X11Grabber::X11Grabber(bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation) : - _imageResampler(), - _useXGetImage(useXGetImage), - _cropLeft(cropLeft), - _cropRight(cropRight), - _cropTop(cropTop), - _cropBottom(cropBottom), - _x11Display(nullptr), - _pixmap(None), - _srcFormat(nullptr), - _dstFormat(nullptr), - _srcPicture(None), - _dstPicture(None), - _screenWidth(0), - _screenHeight(0), - _croppedWidth(0), - _croppedHeight(0), - _image(0,0) + _imageResampler(), + _useXGetImage(useXGetImage), + _cropLeft(cropLeft), + _cropRight(cropRight), + _cropTop(cropTop), + _cropBottom(cropBottom), + _x11Display(nullptr), + _pixmap(None), + _srcFormat(nullptr), + _dstFormat(nullptr), + _srcPicture(None), + _dstPicture(None), + _screenWidth(0), + _screenHeight(0), + _croppedWidth(0), + _croppedHeight(0), + _image(0,0) { - _imageResampler.setHorizontalPixelDecimation(horizontalPixelDecimation); - _imageResampler.setVerticalPixelDecimation(verticalPixelDecimation); - _imageResampler.setCropping(0, 0, 0, 0); // cropping is performed by XShmGetImage or XGetImage - memset(&_pictAttr, 0, sizeof(_pictAttr)); - _pictAttr.repeat = RepeatNone; + _imageResampler.setHorizontalPixelDecimation(horizontalPixelDecimation); + _imageResampler.setVerticalPixelDecimation(verticalPixelDecimation); + _imageResampler.setCropping(0, 0, 0, 0); // cropping is performed by XShmGetImage or XGetImage + memset(&_pictAttr, 0, sizeof(_pictAttr)); + _pictAttr.repeat = RepeatNone; } X11Grabber::~X11Grabber() { - if (_x11Display != nullptr) - { - freeResources(); - XCloseDisplay(_x11Display); - } + if (_x11Display != nullptr) + { + freeResources(); + XCloseDisplay(_x11Display); + } } void X11Grabber::freeResources() { - // Cleanup allocated resources of the X11 grab - XDestroyImage(_xImage); - if(_XShmAvailable && !_useXGetImage) { - XShmDetach(_x11Display, &_shminfo); - shmdt(_shminfo.shmaddr); - shmctl(_shminfo.shmid, IPC_RMID, 0); - } - if (_XRenderAvailable && !_useXGetImage) { - XRenderFreePicture(_x11Display, _srcPicture); - XRenderFreePicture(_x11Display, _dstPicture); - XFreePixmap(_x11Display, _pixmap); - } + // Cleanup allocated resources of the X11 grab + XDestroyImage(_xImage); + if(_XShmAvailable && !_useXGetImage) { + XShmDetach(_x11Display, &_shminfo); + shmdt(_shminfo.shmaddr); + shmctl(_shminfo.shmid, IPC_RMID, 0); + } + if (_XRenderAvailable && !_useXGetImage) { + XRenderFreePicture(_x11Display, _srcPicture); + XRenderFreePicture(_x11Display, _dstPicture); + XFreePixmap(_x11Display, _pixmap); + } } void X11Grabber::setupResources() { - if(_XShmAvailable && !_useXGetImage) { - _xImage = XShmCreateImage(_x11Display, _windowAttr.visual, - _windowAttr.depth, ZPixmap, NULL, &_shminfo, - _croppedWidth, _croppedHeight); + if(_XShmAvailable && !_useXGetImage) { + _xImage = XShmCreateImage(_x11Display, _windowAttr.visual, + _windowAttr.depth, ZPixmap, NULL, &_shminfo, + _croppedWidth, _croppedHeight); - _shminfo.shmid = shmget(IPC_PRIVATE, _xImage->bytes_per_line * _xImage->height, IPC_CREAT|0777); - _xImage->data = (char*)shmat(_shminfo.shmid,0,0); - _shminfo.shmaddr = _xImage->data; - _shminfo.readOnly = False; - + _shminfo.shmid = shmget(IPC_PRIVATE, _xImage->bytes_per_line * _xImage->height, IPC_CREAT|0777); + _xImage->data = (char*)shmat(_shminfo.shmid,0,0); + _shminfo.shmaddr = _xImage->data; + _shminfo.readOnly = False; + XShmAttach(_x11Display, &_shminfo); - } - if (_XRenderAvailable && !_useXGetImage) { - if(_XShmPixmapAvailable) { - _pixmap = XShmCreatePixmap(_x11Display, _window, _xImage->data, &_shminfo, _croppedWidth, _croppedHeight, _windowAttr.depth); - } else { - _pixmap = XCreatePixmap(_x11Display, _window, _croppedWidth, _croppedHeight, _windowAttr.depth); } - _srcFormat = XRenderFindVisualFormat(_x11Display, _windowAttr.visual); - _dstFormat = XRenderFindVisualFormat(_x11Display, _windowAttr.visual); - _srcPicture = XRenderCreatePicture(_x11Display, _window, _srcFormat, CPRepeat, &_pictAttr); - _dstPicture = XRenderCreatePicture(_x11Display, _pixmap, _dstFormat, CPRepeat, &_pictAttr); - XRenderSetPictureFilter(_x11Display, _srcPicture, "bilinear", NULL, 0); - } + if (_XRenderAvailable && !_useXGetImage) { + if(_XShmPixmapAvailable) { + _pixmap = XShmCreatePixmap(_x11Display, _window, _xImage->data, &_shminfo, _croppedWidth, _croppedHeight, _windowAttr.depth); + } else { + _pixmap = XCreatePixmap(_x11Display, _window, _croppedWidth, _croppedHeight, _windowAttr.depth); + } + _srcFormat = XRenderFindVisualFormat(_x11Display, _windowAttr.visual); + _dstFormat = XRenderFindVisualFormat(_x11Display, _windowAttr.visual); + _srcPicture = XRenderCreatePicture(_x11Display, _window, _srcFormat, CPRepeat, &_pictAttr); + _dstPicture = XRenderCreatePicture(_x11Display, _pixmap, _dstFormat, CPRepeat, &_pictAttr); + XRenderSetPictureFilter(_x11Display, _srcPicture, "bilinear", NULL, 0); + } } bool X11Grabber::Setup() { - _x11Display = XOpenDisplay(NULL); - if (_x11Display == nullptr) - { - std::cerr << "X11GRABBER ERROR: Unable to open display"; - if (getenv("DISPLAY")) - std::cerr << " " << std::string(getenv("DISPLAY")) << std::endl; - else - std::cerr << ". DISPLAY environment variable not set" << std::endl; - return false; - } - - _window = DefaultRootWindow(_x11Display); + _x11Display = XOpenDisplay(NULL); + if (_x11Display == nullptr) + { + std::cerr << "X11GRABBER ERROR: Unable to open display"; + if (getenv("DISPLAY")) { + std::cerr << " " << std::string(getenv("DISPLAY")) << std::endl; + } else { + std::cerr << ". DISPLAY environment variable not set" << std::endl; + } + return false; + } + + _window = DefaultRootWindow(_x11Display); - int dummy, pixmaps_supported; - - _XRenderAvailable = XRenderQueryExtension(_x11Display, &dummy, &dummy); - _XShmAvailable = XShmQueryExtension(_x11Display); - XShmQueryVersion(_x11Display, &dummy, &dummy, &pixmaps_supported); - _XShmPixmapAvailable = pixmaps_supported && XShmPixmapFormat(_x11Display) == ZPixmap; + int dummy, pixmaps_supported; + + _XRenderAvailable = XRenderQueryExtension(_x11Display, &dummy, &dummy); + _XShmAvailable = XShmQueryExtension(_x11Display); + XShmQueryVersion(_x11Display, &dummy, &dummy, &pixmaps_supported); + _XShmPixmapAvailable = pixmaps_supported && XShmPixmapFormat(_x11Display) == ZPixmap; - return true; + return true; } Image & X11Grabber::grab() @@ -129,75 +130,74 @@ Image & X11Grabber::grab() _croppedHeight); // height XSync(_x11Display, False); - - if (_XShmAvailable) { - XShmGetImage(_x11Display, _pixmap, _xImage, 0, 0, AllPlanes); - } else { - _xImage = XGetImage(_x11Display, _pixmap, 0, 0, _croppedWidth, _croppedHeight, AllPlanes, ZPixmap); - } - } else { - if (_XShmAvailable && !_useXGetImage) { - XShmGetImage(_x11Display, _window, _xImage, _cropLeft, _cropTop, AllPlanes); - } else { - _xImage = XGetImage(_x11Display, _window, _cropLeft, _cropTop, _croppedWidth, _croppedHeight, AllPlanes, ZPixmap); - } - } - - if (_xImage == nullptr) - { - std::cerr << "X11GRABBER ERROR: Grab failed" << std::endl; - return _image; - } - _imageResampler.processImage(reinterpret_cast(_xImage->data), _xImage->width, _xImage->height, _xImage->bytes_per_line, PIXELFORMAT_BGR32, _image); + if (_XShmAvailable) { + XShmGetImage(_x11Display, _pixmap, _xImage, 0, 0, AllPlanes); + } else { + _xImage = XGetImage(_x11Display, _pixmap, 0, 0, _croppedWidth, _croppedHeight, AllPlanes, ZPixmap); + } + } else { + if (_XShmAvailable && !_useXGetImage) { + XShmGetImage(_x11Display, _window, _xImage, _cropLeft, _cropTop, AllPlanes); + } else { + _xImage = XGetImage(_x11Display, _window, _cropLeft, _cropTop, _croppedWidth, _croppedHeight, AllPlanes, ZPixmap); + } + } - return _image; + if (_xImage == nullptr) + { + std::cerr << "X11GRABBER ERROR: Grab failed" << std::endl; + return _image; + } + + _imageResampler.processImage(reinterpret_cast(_xImage->data), _xImage->width, _xImage->height, _xImage->bytes_per_line, PIXELFORMAT_BGR32, _image); + + return _image; } int X11Grabber::updateScreenDimensions() { - const Status status = XGetWindowAttributes(_x11Display, _window, &_windowAttr); - if (status == 0) - { - std::cerr << "X11GRABBER ERROR: Failed to obtain window attributes" << std::endl; - return -1; - } + const Status status = XGetWindowAttributes(_x11Display, _window, &_windowAttr); + if (status == 0) + { + std::cerr << "X11GRABBER ERROR: Failed to obtain window attributes" << std::endl; + return -1; + } - if (_screenWidth == unsigned(_windowAttr.width) && _screenHeight == unsigned(_windowAttr.height)) - { - // No update required - return 0; - } - - std::cout << "X11GRABBER INFO: Update of screen resolution: [" << _screenWidth << "x" << _screenHeight <<"] => "; + if (_screenWidth == unsigned(_windowAttr.width) && _screenHeight == unsigned(_windowAttr.height)) + { + // No update required + return 0; + } + + std::cout << "X11GRABBER INFO: Update of screen resolution: [" << _screenWidth << "x" << _screenHeight <<"] => "; - if (_screenWidth || _screenHeight) - freeResources(); - - _screenWidth = _windowAttr.width; - _screenHeight = _windowAttr.height; - - std::cout << "[" << _screenWidth << "x" << _screenHeight <<"]" << std::endl; - - if (_screenWidth > unsigned(_cropLeft + _cropRight)) - _croppedWidth = _screenWidth - _cropLeft - _cropRight; - else - _croppedWidth = _screenWidth; - - if (_screenHeight > unsigned(_cropTop + _cropBottom)) - _croppedHeight = _screenHeight - _cropTop - _cropBottom; - else - _croppedHeight = _screenHeight; - - std::cout << "X11GRABBER INFO: Using "; - - if (_XRenderAvailable && !_useXGetImage) { - std::cout << "XRender for grabbing" << std::endl; - } else { - std::cout << "XGetImage for grabbing" << std::endl; - } - - setupResources(); + if (_screenWidth || _screenHeight) { + freeResources(); + } - return 0; + _screenWidth = _windowAttr.width; + _screenHeight = _windowAttr.height; + + std::cout << "[" << _screenWidth << "x" << _screenHeight <<"]" << std::endl; + + _croppedWidth = (_screenWidth > unsigned(_cropLeft + _cropRight)) + ? (_screenWidth - _cropLeft - _cropRight) + : _screenWidth; + + _croppedHeight = (_screenHeight > unsigned(_cropTop + _cropBottom)) + ? (_screenHeight - _cropTop - _cropBottom) + : (_croppedHeight = _screenHeight); + + std::cout << "X11GRABBER INFO: Using "; + + if (_XRenderAvailable && !_useXGetImage) { + std::cout << "XRender for grabbing" << std::endl; + } else { + std::cout << "XGetImage for grabbing" << std::endl; + } + + setupResources(); + + return 0; } diff --git a/libsrc/hyperion/CMakeLists.txt b/libsrc/hyperion/CMakeLists.txt index b4f53a19..021b4e2d 100644 --- a/libsrc/hyperion/CMakeLists.txt +++ b/libsrc/hyperion/CMakeLists.txt @@ -1,72 +1,72 @@ - -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/hyperion) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperion) - -# Group the headers that go through the MOC compiler -SET(Hyperion_QT_HEADERS - ${CURRENT_HEADER_DIR}/Hyperion.h - - ${CURRENT_SOURCE_DIR}/LinearColorSmoothing.h -) - -SET(Hyperion_HEADERS - ${CURRENT_HEADER_DIR}/ImageProcessor.h - ${CURRENT_HEADER_DIR}/ImageProcessorFactory.h - ${CURRENT_HEADER_DIR}/ImageToLedsMap.h - ${CURRENT_HEADER_DIR}/LedString.h - ${CURRENT_HEADER_DIR}/PriorityMuxer.h - - ${CURRENT_SOURCE_DIR}/MultiColorTransform.h - ${CURRENT_SOURCE_DIR}/MultiColorCorrection.h - ${CURRENT_SOURCE_DIR}/MultiColorAdjustment.h - ${CURRENT_HEADER_DIR}/MessageForwarder.h -) - -SET(Hyperion_SOURCES - ${CURRENT_SOURCE_DIR}/Hyperion.cpp - ${CURRENT_SOURCE_DIR}/ImageProcessor.cpp - ${CURRENT_SOURCE_DIR}/ImageProcessorFactory.cpp - ${CURRENT_SOURCE_DIR}/LedString.cpp - ${CURRENT_SOURCE_DIR}/PriorityMuxer.cpp - - ${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp - ${CURRENT_SOURCE_DIR}/MultiColorTransform.cpp - ${CURRENT_SOURCE_DIR}/MultiColorCorrection.cpp - ${CURRENT_SOURCE_DIR}/MultiColorAdjustment.cpp - ${CURRENT_SOURCE_DIR}/LinearColorSmoothing.cpp - ${CURRENT_SOURCE_DIR}/MessageForwarder.cpp -) - -set(Hyperion_RESOURCES - ${CURRENT_SOURCE_DIR}/resource.qrc -) - -if(ENABLE_QT5) -QT5_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS}) -QT5_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress") -else(ENABLE_QT5) -QT4_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS}) -QT4_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress") -endif(ENABLE_QT5) - -add_library(hyperion - ${Hyperion_HEADERS} - ${Hyperion_QT_HEADERS} - ${Hyperion_HEADERS_MOC} - ${Hyperion_SOURCES} - ${Hyperion_RESOURCES_RCC} -) - -if(ENABLE_QT5) -qt5_use_modules(hyperion Widgets) -endif(ENABLE_QT5) - -target_link_libraries(hyperion - blackborder - hyperion-utils - leddevice - effectengine - serialport - ${QT_LIBRARIES} -) + +# Define the current source locations +SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/hyperion) +SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperion) + +# Group the headers that go through the MOC compiler +SET(Hyperion_QT_HEADERS + ${CURRENT_HEADER_DIR}/Hyperion.h + + ${CURRENT_SOURCE_DIR}/LinearColorSmoothing.h +) + +SET(Hyperion_HEADERS + ${CURRENT_HEADER_DIR}/ImageProcessor.h + ${CURRENT_HEADER_DIR}/ImageProcessorFactory.h + ${CURRENT_HEADER_DIR}/ImageToLedsMap.h + ${CURRENT_HEADER_DIR}/LedString.h + ${CURRENT_HEADER_DIR}/PriorityMuxer.h + + ${CURRENT_SOURCE_DIR}/MultiColorTransform.h + ${CURRENT_SOURCE_DIR}/MultiColorCorrection.h + ${CURRENT_SOURCE_DIR}/MultiColorAdjustment.h + ${CURRENT_HEADER_DIR}/MessageForwarder.h +) + +SET(Hyperion_SOURCES + ${CURRENT_SOURCE_DIR}/Hyperion.cpp + ${CURRENT_SOURCE_DIR}/ImageProcessor.cpp + ${CURRENT_SOURCE_DIR}/ImageProcessorFactory.cpp + ${CURRENT_SOURCE_DIR}/LedString.cpp + ${CURRENT_SOURCE_DIR}/PriorityMuxer.cpp + + ${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp + ${CURRENT_SOURCE_DIR}/MultiColorTransform.cpp + ${CURRENT_SOURCE_DIR}/MultiColorCorrection.cpp + ${CURRENT_SOURCE_DIR}/MultiColorAdjustment.cpp + ${CURRENT_SOURCE_DIR}/LinearColorSmoothing.cpp + ${CURRENT_SOURCE_DIR}/MessageForwarder.cpp +) + +SET(Hyperion_RESOURCES + ${CURRENT_SOURCE_DIR}/resource.qrc +) + +if(ENABLE_QT5) + QT5_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS}) + QT5_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress") +else() + QT4_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS}) + QT4_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress") +endif() + +add_library(hyperion + ${Hyperion_HEADERS} + ${Hyperion_QT_HEADERS} + ${Hyperion_HEADERS_MOC} + ${Hyperion_SOURCES} + ${Hyperion_RESOURCES_RCC} +) + +if(ENABLE_QT5) + qt5_use_modules(hyperion Widgets) +endif() + +target_link_libraries(hyperion + blackborder + hyperion-utils + leddevice + effectengine + serialport + ${QT_LIBRARIES} +) diff --git a/libsrc/hyperion/hyperion.schema.json b/libsrc/hyperion/hyperion.schema.json index aded2acf..f839b7f1 100644 --- a/libsrc/hyperion/hyperion.schema.json +++ b/libsrc/hyperion/hyperion.schema.json @@ -1,382 +1,382 @@ -{ - "type" : "object", - "required" : true, - "properties" : { - "device" : { - "type" : "object", - "required" : true, - "properties" : { - "name" : { - "type" : "string", - "required" : true - }, - "type" : { - "type" : "string", - "required" : true - }, - "output" : { - "type" : "string", - "required" : true - }, - "rate" : { - "type" : "integer", - "required" : true, - "minimum" : 0 - }, - "colorOrder" : { - "type" : "string", - "required" : false - }, - "bgr-output" : { // deprecated - "type" : "boolean", - "required" : false - } - }, - "additionalProperties" : false - }, - "color": { - "type":"object", - "required":false, - "properties": { - "hsv" : { - "type" : "object", - "required" : false, - "properties" : { - "saturationGain" : { - "type" : "number", - "required" : false, - "minimum" : 0.0 - }, - "valueGain" : { - "type" : "number", - "required" : false, - "minimum" : 0.0 - } - }, - "additionalProperties" : false - }, - "hsl" : { - "type" : "object", - "required" : false, - "properties" : { - "saturationGain" : { - "type" : "number", - "required" : false, - "minimum" : 0.0 - }, - "luminanceGain" : { - "type" : "number", - "required" : false, - "minimum" : 0.0 - }, - "luminanceMinimum" : { - "type" : "number", - "required" : false, - "minimum" : 0.0 - } - }, - "additionalProperties" : false - }, - "red": { - "type":"object", - "required":false, - "properties":{ - "gamma": { - "type":"number", - "required":false - }, - "blacklevel": { - "type":"number", - "required":false - }, - "whitelevel": { - "type":"number", - "required":false - }, - "threshold": { - "type":"number", - "required":false, - "minimum" : 0.0, - "maximum" : 1.0 - } - }, - "additionalProperties" : false - }, - "green": { - "type":"object", - "required":false, - "properties":{ - "gamma": { - "type":"number", - "required":false - }, - "blacklevel": { - "type":"number", - "required":false - }, - "whitelevel": { - "type":"number", - "required":false - }, - "threshold": { - "type":"number", - "required":false, - "minimum" : 0.0, - "maximum" : 1.0 - } - }, - "additionalProperties" : false - }, - "blue": { - "type":"object", - "required":false, - "properties":{ - "gamma": { - "type":"number", - "required":false - }, - "whitelevel": { - "type":"number", - "required":false - }, - "blacklevel": { - "type":"number", - "required":false - }, - "threshold": { - "type":"number", - "required":false, - "minimum" : 0.0, - "maximum" : 1.0 - } - }, - "additionalProperties" : false - }, - "smoothing" : { - "type" : "object", - "required" : false, - "properties" : { - "type" : { - "type" : "enum", - "required" : true, - "values" : ["none", "linear"] - }, - "time_ms" : { - "type" : "integer", - "required" : false, - "minimum" : 10 - }, - "updateFrequency" : { - "type" : "number", - "required" : false, - "minimum" : 0.001 - } - }, - "additionalProperties" : false - } - - }, - "additionalProperties" : false - }, - "leds": { - "type":"array", - "required":true, - "items": { - "type":"object", - "properties": { - "index": { - "type":"integer", - "required":true - }, - "hscan": { - "type":"object", - "required":true, - "properties": { - "minimum": { - "type":"number", - "required":true - }, - "maximum": { - "type":"number", - "required":true - } - }, - "additionalProperties" : false - }, - "vscan": { - "type":"object", - "required":true, - "properties": { - "minimum": { - "type":"number", - "required":true - }, - "maximum": { - "type":"number", - "required":true - } - }, - "additionalProperties" : false - }, - "colorOrder" : { - "type" : "string", - "required" : false - } - }, - "additionalProperties" : false - } - }, - "effects" : - { - "type" : "object", - "required" : false, - "properties" : { - "paths" : { - "type" : "array", - "required" : false, - "items" : { - "type" : "string" - } - } - }, - "additionalProperties" : false - }, - "blackborderdetector" : - { - "type" : "object", - "required" : false, - "properties" : { - "enable" : { - "type" : "boolean", - "required" : true - }, - "threshold" : { - "type" : "number", - "required" : false, - "minimum" : 0.0, - "maximum" : 1.0 - } - }, - "additionalProperties" : false - }, - "xbmcVideoChecker" : - { - "type" : "object", - "required" : false, - "properties" : { - "xbmcAddress" : { - "type" : "string", - "required" : true - }, - "xbmcTcpPort" : { - "type" : "integer", - "required" : true - }, - "grabVideo" : { - "type" : "boolean", - "required" : true - }, - "grabPictures" : { - "type" : "boolean", - "required" : true - }, - "grabAudio" : { - "type" : "boolean", - "required" : true - }, - "grabMenu" : { - "type" : "boolean", - "required" : true - }, - "grabScreensaver" : { - "type" : "boolean", - "required" : false - }, - "enable3DDetection" : { - "type" : "boolean", - "required" : false - } - }, - "additionalProperties" : false - }, - "bootsequence" : - { - "type" : "object", - "required" : false, - "properties" : { - "path" : { - "type" : "string", - "required" : true - }, - "effect" : { - "type" : "string", - "required" : true - } - }, - "additionalProperties" : false - }, - "framegrabber" : - { - "type" : "object", - "required" : false, - "properties" : { - "width" : { - "type" : "integer", - "required" : true - }, - "height" : { - "type" : "integer", - "required" : true - }, - "frequency_Hz" : { - "type" : "integer", - "required" : true - } - }, - "additionalProperties" : false - }, - "jsonServer" : - { - "type" : "object", - "required" : false, - "properties" : { - "port" : { - "type" : "integer", - "required" : true, - "minimum" : 0, - "maximum" : 65535 - } - }, - "additionalProperties" : false - }, - "protoServer" : - { - "type" : "object", - "required" : false, - "properties" : { - "port" : { - "type" : "integer", - "required" : true, - "minimum" : 0, - "maximum" : 65535 - } - }, - "additionalProperties" : false - }, - "boblightServer" : - { - "type" : "object", - "required" : false, - "properties" : { - "port" : { - "type" : "integer", - "required" : true, - "minimum" : 0, - "maximum" : 65535 - } - }, - "additionalProperties" : false - } - }, - "additionalProperties" : false -} +{ + "type" : "object", + "required" : true, + "properties" : { + "device" : { + "type" : "object", + "required" : true, + "properties" : { + "name" : { + "type" : "string", + "required" : true + }, + "type" : { + "type" : "string", + "required" : true + }, + "output" : { + "type" : "string", + "required" : true + }, + "rate" : { + "type" : "integer", + "required" : true, + "minimum" : 0 + }, + "colorOrder" : { + "type" : "string", + "required" : false + }, + "bgr-output" : { // deprecated + "type" : "boolean", + "required" : false + } + }, + "additionalProperties" : false + }, + "color": { + "type":"object", + "required":false, + "properties": { + "hsv" : { + "type" : "object", + "required" : false, + "properties" : { + "saturationGain" : { + "type" : "number", + "required" : false, + "minimum" : 0.0 + }, + "valueGain" : { + "type" : "number", + "required" : false, + "minimum" : 0.0 + } + }, + "additionalProperties" : false + }, + "hsl" : { + "type" : "object", + "required" : false, + "properties" : { + "saturationGain" : { + "type" : "number", + "required" : false, + "minimum" : 0.0 + }, + "luminanceGain" : { + "type" : "number", + "required" : false, + "minimum" : 0.0 + }, + "luminanceMinimum" : { + "type" : "number", + "required" : false, + "minimum" : 0.0 + } + }, + "additionalProperties" : false + }, + "red": { + "type":"object", + "required":false, + "properties":{ + "gamma": { + "type":"number", + "required":false + }, + "blacklevel": { + "type":"number", + "required":false + }, + "whitelevel": { + "type":"number", + "required":false + }, + "threshold": { + "type":"number", + "required":false, + "minimum" : 0.0, + "maximum" : 1.0 + } + }, + "additionalProperties" : false + }, + "green": { + "type":"object", + "required":false, + "properties":{ + "gamma": { + "type":"number", + "required":false + }, + "blacklevel": { + "type":"number", + "required":false + }, + "whitelevel": { + "type":"number", + "required":false + }, + "threshold": { + "type":"number", + "required":false, + "minimum" : 0.0, + "maximum" : 1.0 + } + }, + "additionalProperties" : false + }, + "blue": { + "type":"object", + "required":false, + "properties":{ + "gamma": { + "type":"number", + "required":false + }, + "whitelevel": { + "type":"number", + "required":false + }, + "blacklevel": { + "type":"number", + "required":false + }, + "threshold": { + "type":"number", + "required":false, + "minimum" : 0.0, + "maximum" : 1.0 + } + }, + "additionalProperties" : false + }, + "smoothing" : { + "type" : "object", + "required" : false, + "properties" : { + "type" : { + "type" : "enum", + "required" : true, + "values" : ["none", "linear"] + }, + "time_ms" : { + "type" : "integer", + "required" : false, + "minimum" : 10 + }, + "updateFrequency" : { + "type" : "number", + "required" : false, + "minimum" : 0.001 + } + }, + "additionalProperties" : false + } + + }, + "additionalProperties" : false + }, + "leds": { + "type":"array", + "required":true, + "items": { + "type":"object", + "properties": { + "index": { + "type":"integer", + "required":true + }, + "hscan": { + "type":"object", + "required":true, + "properties": { + "minimum": { + "type":"number", + "required":true + }, + "maximum": { + "type":"number", + "required":true + } + }, + "additionalProperties" : false + }, + "vscan": { + "type":"object", + "required":true, + "properties": { + "minimum": { + "type":"number", + "required":true + }, + "maximum": { + "type":"number", + "required":true + } + }, + "additionalProperties" : false + }, + "colorOrder" : { + "type" : "string", + "required" : false + } + }, + "additionalProperties" : false + } + }, + "effects" : + { + "type" : "object", + "required" : false, + "properties" : { + "paths" : { + "type" : "array", + "required" : false, + "items" : { + "type" : "string" + } + } + }, + "additionalProperties" : false + }, + "blackborderdetector" : + { + "type" : "object", + "required" : false, + "properties" : { + "enable" : { + "type" : "boolean", + "required" : true + }, + "threshold" : { + "type" : "number", + "required" : false, + "minimum" : 0.0, + "maximum" : 1.0 + } + }, + "additionalProperties" : false + }, + "xbmcVideoChecker" : + { + "type" : "object", + "required" : false, + "properties" : { + "xbmcAddress" : { + "type" : "string", + "required" : true + }, + "xbmcTcpPort" : { + "type" : "integer", + "required" : true + }, + "grabVideo" : { + "type" : "boolean", + "required" : true + }, + "grabPictures" : { + "type" : "boolean", + "required" : true + }, + "grabAudio" : { + "type" : "boolean", + "required" : true + }, + "grabMenu" : { + "type" : "boolean", + "required" : true + }, + "grabScreensaver" : { + "type" : "boolean", + "required" : false + }, + "enable3DDetection" : { + "type" : "boolean", + "required" : false + } + }, + "additionalProperties" : false + }, + "bootsequence" : + { + "type" : "object", + "required" : false, + "properties" : { + "path" : { + "type" : "string", + "required" : true + }, + "effect" : { + "type" : "string", + "required" : true + } + }, + "additionalProperties" : false + }, + "framegrabber" : + { + "type" : "object", + "required" : false, + "properties" : { + "width" : { + "type" : "integer", + "required" : true + }, + "height" : { + "type" : "integer", + "required" : true + }, + "frequency_Hz" : { + "type" : "integer", + "required" : true + } + }, + "additionalProperties" : false + }, + "jsonServer" : + { + "type" : "object", + "required" : false, + "properties" : { + "port" : { + "type" : "integer", + "required" : true, + "minimum" : 0, + "maximum" : 65535 + } + }, + "additionalProperties" : false + }, + "protoServer" : + { + "type" : "object", + "required" : false, + "properties" : { + "port" : { + "type" : "integer", + "required" : true, + "minimum" : 0, + "maximum" : 65535 + } + }, + "additionalProperties" : false + }, + "boblightServer" : + { + "type" : "object", + "required" : false, + "properties" : { + "port" : { + "type" : "integer", + "required" : true, + "minimum" : 0, + "maximum" : 65535 + } + }, + "additionalProperties" : false + } + }, + "additionalProperties" : false +} diff --git a/libsrc/jsonserver/CMakeLists.txt b/libsrc/jsonserver/CMakeLists.txt index d03ed1ea..9569f076 100644 --- a/libsrc/jsonserver/CMakeLists.txt +++ b/libsrc/jsonserver/CMakeLists.txt @@ -1,48 +1,48 @@ - -# Define the current source locations -set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/jsonserver) -set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/jsonserver) - -# Group the headers that go through the MOC compiler -set(JsonServer_QT_HEADERS - ${CURRENT_HEADER_DIR}/JsonServer.h - ${CURRENT_SOURCE_DIR}/JsonClientConnection.h -) - -set(JsonServer_HEADERS -) - -set(JsonServer_SOURCES - ${CURRENT_SOURCE_DIR}/JsonServer.cpp - ${CURRENT_SOURCE_DIR}/JsonClientConnection.cpp -) - -set(JsonServer_RESOURCES - ${CURRENT_SOURCE_DIR}/JsonSchemas.qrc -) -if(ENABLE_QT5) -qt5_wrap_cpp(JsonServer_HEADERS_MOC ${JsonServer_QT_HEADERS}) -qt5_add_resources(JsonServer_RESOURCES_RCC ${JsonServer_RESOURCES} OPTIONS "-no-compress") -else(ENABLE_QT5) -qt4_wrap_cpp(JsonServer_HEADERS_MOC ${JsonServer_QT_HEADERS}) -qt4_add_resources(JsonServer_RESOURCES_RCC ${JsonServer_RESOURCES} OPTIONS "-no-compress") -endif(ENABLE_QT5) - -add_library(jsonserver - ${JsonServer_HEADERS} - ${JsonServer_QT_HEADERS} - ${JsonServer_SOURCES} - ${JsonServer_RESOURCES} - ${JsonServer_HEADERS_MOC} - ${JsonServer_RESOURCES_RCC} -) - -if(ENABLE_QT5) -qt5_use_modules(jsonserver Widgets Network) -endif(ENABLE_QT5) - -target_link_libraries(jsonserver - hyperion - hyperion-utils - jsoncpp - ${QT_LIBRARIES}) + +# Define the current source locations +set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/jsonserver) +set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/jsonserver) + +# Group the headers that go through the MOC compiler +set(JsonServer_QT_HEADERS + ${CURRENT_HEADER_DIR}/JsonServer.h + ${CURRENT_SOURCE_DIR}/JsonClientConnection.h +) + +set(JsonServer_HEADERS +) + +set(JsonServer_SOURCES + ${CURRENT_SOURCE_DIR}/JsonServer.cpp + ${CURRENT_SOURCE_DIR}/JsonClientConnection.cpp +) + +set(JsonServer_RESOURCES + ${CURRENT_SOURCE_DIR}/JsonSchemas.qrc +) +if(ENABLE_QT5) + qt5_wrap_cpp(JsonServer_HEADERS_MOC ${JsonServer_QT_HEADERS}) + qt5_add_resources(JsonServer_RESOURCES_RCC ${JsonServer_RESOURCES} OPTIONS "-no-compress") +else() + qt4_wrap_cpp(JsonServer_HEADERS_MOC ${JsonServer_QT_HEADERS}) + qt4_add_resources(JsonServer_RESOURCES_RCC ${JsonServer_RESOURCES} OPTIONS "-no-compress") +endif() + +add_library(jsonserver + ${JsonServer_HEADERS} + ${JsonServer_QT_HEADERS} + ${JsonServer_SOURCES} + ${JsonServer_RESOURCES} + ${JsonServer_HEADERS_MOC} + ${JsonServer_RESOURCES_RCC} +) + +if(ENABLE_QT5) + qt5_use_modules(jsonserver Widgets Network) +endif() + +target_link_libraries(jsonserver + hyperion + hyperion-utils + jsoncpp + ${QT_LIBRARIES}) diff --git a/libsrc/leddevice/CMakeLists.txt b/libsrc/leddevice/CMakeLists.txt index 2d2ceba5..efdbffa6 100755 --- a/libsrc/leddevice/CMakeLists.txt +++ b/libsrc/leddevice/CMakeLists.txt @@ -1,165 +1,166 @@ - -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/leddevice) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/leddevice) - -#add libusb and pthreads (required for the Lighpack usb device) -find_package(libusb-1.0 REQUIRED) -find_package(Threads REQUIRED) - -include_directories( - ../../include/hidapi - ${LIBUSB_1_INCLUDE_DIRS}) # for Lightpack device - -# Group the headers that go through the MOC compiler -SET(Leddevice_QT_HEADERS - ${CURRENT_SOURCE_DIR}/LedRs232Device.h - ${CURRENT_SOURCE_DIR}/LedDeviceAdalight.h - ${CURRENT_SOURCE_DIR}/LedDeviceAdalightApa102.h - ${CURRENT_SOURCE_DIR}/LedDeviceAmbiLed.h - ${CURRENT_SOURCE_DIR}/LedDeviceAtmoOrb.h - ${CURRENT_SOURCE_DIR}/LedDevicePhilipsHue.h - ${CURRENT_SOURCE_DIR}/LedHIDDevice.h - ${CURRENT_SOURCE_DIR}/LedDeviceRawHID.h - ${CURRENT_SOURCE_DIR}/LedDeviceFile.h - ${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.h -) - -SET(Leddevice_HEADERS - ${CURRENT_HEADER_DIR}/LedDevice.h - ${CURRENT_HEADER_DIR}/LedDeviceFactory.h - - ${CURRENT_SOURCE_DIR}/LedDeviceLightpack.h - ${CURRENT_SOURCE_DIR}/LedDeviceMultiLightpack.h - ${CURRENT_SOURCE_DIR}/LedDevicePaintpack.h - ${CURRENT_SOURCE_DIR}/LedDevicePiBlaster.h - ${CURRENT_SOURCE_DIR}/LedDeviceSedu.h - ${CURRENT_SOURCE_DIR}/LedDeviceFile.h - ${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.h - ${CURRENT_SOURCE_DIR}/LedDeviceUdp.h - ${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.h - ${CURRENT_SOURCE_DIR}/LedDeviceTpm2.h - ${CURRENT_SOURCE_DIR}/LedDeviceAtmo.h -) - -SET(Leddevice_SOURCES - ${CURRENT_SOURCE_DIR}/LedDeviceFactory.cpp - - ${CURRENT_SOURCE_DIR}/LedRs232Device.cpp - ${CURRENT_SOURCE_DIR}/LedHIDDevice.cpp - - ${CURRENT_SOURCE_DIR}/LedDeviceAdalight.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceAdalightApa102.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceAmbiLed.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceAtmoOrb.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceRawHID.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceLightpack.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceMultiLightpack.cpp - ${CURRENT_SOURCE_DIR}/LedDevicePaintpack.cpp - ${CURRENT_SOURCE_DIR}/LedDevicePiBlaster.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceSedu.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceFile.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceUdp.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.cpp - ${CURRENT_SOURCE_DIR}/LedDevicePhilipsHue.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceTpm2.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceAtmo.cpp -) - -if(ENABLE_SPIDEV) - SET(Leddevice_HEADERS - ${Leddevice_HEADERS} - ${CURRENT_SOURCE_DIR}/LedSpiDevice.h - ${CURRENT_SOURCE_DIR}/LedDeviceLpd6803.h - ${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.h - ${CURRENT_SOURCE_DIR}/LedDeviceP9813.h - ${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h - ${CURRENT_SOURCE_DIR}/LedDeviceWs2812SPI.h - ${CURRENT_SOURCE_DIR}/LedDeviceAPA102.h - ) - SET(Leddevice_SOURCES - ${Leddevice_SOURCES} - ${CURRENT_SOURCE_DIR}/LedSpiDevice.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceLpd6803.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceP9813.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceWs2812SPI.cpp - ${CURRENT_SOURCE_DIR}/LedDeviceAPA102.cpp - ) -endif(ENABLE_SPIDEV) - -if(ENABLE_WS2812BPWM) -SET(Leddevice_HEADERS - ${Leddevice_HEADERS} - ${CURRENT_SOURCE_DIR}/LedDeviceWS2812b.h - ) -SET(Leddevice_SOURCES - ${Leddevice_SOURCES} - ${CURRENT_SOURCE_DIR}/LedDeviceWS2812b.cpp -) -endif(ENABLE_WS2812BPWM) - -if(ENABLE_WS281XPWM) -include_directories(../../dependencies/external/rpi_ws281x) -SET(Leddevice_HEADERS - ${Leddevice_HEADERS} - ${CURRENT_SOURCE_DIR}/LedDeviceWS281x.h - ) -SET(Leddevice_SOURCES - ${Leddevice_SOURCES} - ${CURRENT_SOURCE_DIR}/LedDeviceWS281x.cpp -) -endif(ENABLE_WS281XPWM) - -if(ENABLE_TINKERFORGE) - SET(Leddevice_HEADERS - ${Leddevice_HEADERS} - ${CURRENT_SOURCE_DIR}/LedDeviceTinkerforge.h - ) - SET(Leddevice_SOURCES - ${Leddevice_SOURCES} - ${CURRENT_SOURCE_DIR}/LedDeviceTinkerforge.cpp - ) -endif(ENABLE_TINKERFORGE) - -if(ENABLE_QT5) -QT5_WRAP_CPP(Leddevice_HEADERS_MOC ${Leddevice_QT_HEADERS}) -else(ENABLE_QT5) -QT4_WRAP_CPP(Leddevice_HEADERS_MOC ${Leddevice_QT_HEADERS}) -endif(ENABLE_QT5) - - -add_library(leddevice - ${Leddevice_HEADERS} - ${Leddevice_QT_HEADERS} - ${Leddevice_HEADERS_MOC} - ${Leddevice_SOURCES} -) - -if(ENABLE_QT5) -qt5_use_modules(leddevice Widgets Network) -endif(ENABLE_QT5) - -target_link_libraries(leddevice - hyperion-utils - serialport - ${LIBUSB_1_LIBRARIES} #apt-get install libusb-1.0-0-dev - ${CMAKE_THREAD_LIBS_INIT} - ${QT_LIBRARIES} -) - -if(ENABLE_TINKERFORGE) - target_link_libraries(leddevice tinkerforge) -endif() - -if(ENABLE_WS281XPWM) - target_link_libraries(leddevice ws281x) -endif() - -if(APPLE) - target_link_libraries(leddevice hidapi-mac) -else() - target_link_libraries(leddevice hidapi-libusb) -endif() + +# Define the current source locations +SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/leddevice) +SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/leddevice) + +#add libusb and pthreads (required for the Lighpack usb device) +find_package(libusb-1.0 REQUIRED) +find_package(Threads REQUIRED) + +include_directories( + ../../include/hidapi + ${LIBUSB_1_INCLUDE_DIRS} +) # for Lightpack device + +# Group the headers that go through the MOC compiler +SET(Leddevice_QT_HEADERS + ${CURRENT_SOURCE_DIR}/LedRs232Device.h + ${CURRENT_SOURCE_DIR}/LedDeviceAdalight.h + ${CURRENT_SOURCE_DIR}/LedDeviceAdalightApa102.h + ${CURRENT_SOURCE_DIR}/LedDeviceAmbiLed.h + ${CURRENT_SOURCE_DIR}/LedDeviceAtmoOrb.h + ${CURRENT_SOURCE_DIR}/LedDevicePhilipsHue.h + ${CURRENT_SOURCE_DIR}/LedHIDDevice.h + ${CURRENT_SOURCE_DIR}/LedDeviceRawHID.h + ${CURRENT_SOURCE_DIR}/LedDeviceFile.h + ${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.h +) + +SET(Leddevice_HEADERS + ${CURRENT_HEADER_DIR}/LedDevice.h + ${CURRENT_HEADER_DIR}/LedDeviceFactory.h + + ${CURRENT_SOURCE_DIR}/LedDeviceLightpack.h + ${CURRENT_SOURCE_DIR}/LedDeviceMultiLightpack.h + ${CURRENT_SOURCE_DIR}/LedDevicePaintpack.h + ${CURRENT_SOURCE_DIR}/LedDevicePiBlaster.h + ${CURRENT_SOURCE_DIR}/LedDeviceSedu.h + ${CURRENT_SOURCE_DIR}/LedDeviceFile.h + ${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.h + ${CURRENT_SOURCE_DIR}/LedDeviceUdp.h + ${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.h + ${CURRENT_SOURCE_DIR}/LedDeviceTpm2.h + ${CURRENT_SOURCE_DIR}/LedDeviceAtmo.h +) + +SET(Leddevice_SOURCES + ${CURRENT_SOURCE_DIR}/LedDeviceFactory.cpp + + ${CURRENT_SOURCE_DIR}/LedRs232Device.cpp + ${CURRENT_SOURCE_DIR}/LedHIDDevice.cpp + + ${CURRENT_SOURCE_DIR}/LedDeviceAdalight.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceAdalightApa102.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceAmbiLed.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceAtmoOrb.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceRawHID.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceLightpack.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceMultiLightpack.cpp + ${CURRENT_SOURCE_DIR}/LedDevicePaintpack.cpp + ${CURRENT_SOURCE_DIR}/LedDevicePiBlaster.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceSedu.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceFile.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceUdp.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.cpp + ${CURRENT_SOURCE_DIR}/LedDevicePhilipsHue.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceTpm2.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceAtmo.cpp +) + +if(ENABLE_SPIDEV) + SET(Leddevice_HEADERS + ${Leddevice_HEADERS} + ${CURRENT_SOURCE_DIR}/LedSpiDevice.h + ${CURRENT_SOURCE_DIR}/LedDeviceLpd6803.h + ${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.h + ${CURRENT_SOURCE_DIR}/LedDeviceP9813.h + ${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h + ${CURRENT_SOURCE_DIR}/LedDeviceWs2812SPI.h + ${CURRENT_SOURCE_DIR}/LedDeviceAPA102.h + ) + SET(Leddevice_SOURCES + ${Leddevice_SOURCES} + ${CURRENT_SOURCE_DIR}/LedSpiDevice.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceLpd6803.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceP9813.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceWs2812SPI.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceAPA102.cpp + ) +endif() + +if(ENABLE_WS2812BPWM) + SET(Leddevice_HEADERS + ${Leddevice_HEADERS} + ${CURRENT_SOURCE_DIR}/LedDeviceWS2812b.h + ) + SET(Leddevice_SOURCES + ${Leddevice_SOURCES} + ${CURRENT_SOURCE_DIR}/LedDeviceWS2812b.cpp + ) +endif() + +if(ENABLE_WS281XPWM) + include_directories(../../dependencies/external/rpi_ws281x) + SET(Leddevice_HEADERS + ${Leddevice_HEADERS} + ${CURRENT_SOURCE_DIR}/LedDeviceWS281x.h + ) + SET(Leddevice_SOURCES + ${Leddevice_SOURCES} + ${CURRENT_SOURCE_DIR}/LedDeviceWS281x.cpp + ) +endif() + +if(ENABLE_TINKERFORGE) + SET(Leddevice_HEADERS + ${Leddevice_HEADERS} + ${CURRENT_SOURCE_DIR}/LedDeviceTinkerforge.h + ) + SET(Leddevice_SOURCES + ${Leddevice_SOURCES} + ${CURRENT_SOURCE_DIR}/LedDeviceTinkerforge.cpp + ) +endif() + +if(ENABLE_QT5) + QT5_WRAP_CPP(Leddevice_HEADERS_MOC ${Leddevice_QT_HEADERS}) +else() + QT4_WRAP_CPP(Leddevice_HEADERS_MOC ${Leddevice_QT_HEADERS}) +endif() + + +add_library(leddevice + ${Leddevice_HEADERS} + ${Leddevice_QT_HEADERS} + ${Leddevice_HEADERS_MOC} + ${Leddevice_SOURCES} +) + +if(ENABLE_QT5) + qt5_use_modules(leddevice Widgets Network) +endif() + +target_link_libraries(leddevice + hyperion-utils + serialport + ${LIBUSB_1_LIBRARIES} #apt-get install libusb-1.0-0-dev + ${CMAKE_THREAD_LIBS_INIT} + ${QT_LIBRARIES} +) + +if(ENABLE_TINKERFORGE) + target_link_libraries(leddevice tinkerforge) +endif() + +if(ENABLE_WS281XPWM) + target_link_libraries(leddevice ws281x) +endif() + +if(APPLE) + target_link_libraries(leddevice hidapi-mac) +else() + target_link_libraries(leddevice hidapi-libusb) +endif() diff --git a/libsrc/leddevice/LedDeviceAtmoOrb.cpp b/libsrc/leddevice/LedDeviceAtmoOrb.cpp index ae448f33..28532105 100644 --- a/libsrc/leddevice/LedDeviceAtmoOrb.cpp +++ b/libsrc/leddevice/LedDeviceAtmoOrb.cpp @@ -1,152 +1,158 @@ -// Local-Hyperion includes -#include "LedDeviceAtmoOrb.h" - -// qt includes -#include -#include -#include -#include - -#include -#include -#include - -AtmoOrbLight::AtmoOrbLight(unsigned int id) { - // Not implemented -} - -LedDeviceAtmoOrb::LedDeviceAtmoOrb(const std::string &output, bool useOrbSmoothing, - int transitiontime, int skipSmoothingDiff, int port, int numLeds, std::vector orbIds) : - multicastGroup(output.c_str()), useOrbSmoothing(useOrbSmoothing), transitiontime(transitiontime), skipSmoothingDiff(skipSmoothingDiff), - multiCastGroupPort(port), numLeds(numLeds), orbIds(orbIds) { - manager = new QNetworkAccessManager(); - groupAddress = QHostAddress(multicastGroup); - - udpSocket = new QUdpSocket(this); - udpSocket->bind(multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint); - - joinedMulticastgroup = udpSocket->joinMulticastGroup(groupAddress); -} - -int LedDeviceAtmoOrb::write(const std::vector &ledValues) { - - // If not in multicast group return - if (!joinedMulticastgroup) { - return 0; - } - - // Command options: - // - // 1 = force off - // 2 = use lamp smoothing and validate by Orb ID - // 4 = validate by Orb ID - - // When setting useOrbSmoothing = true it's recommended to disable Hyperion's own smoothing as it will conflict (double smoothing) - int commandType = 4; - if(useOrbSmoothing) - { - commandType = 2; - } - - // Iterate through colors and set Orb color - // Start off with idx 1 as 0 is reserved for controlling all orbs at once - unsigned int idx = 1; - - for (const ColorRgb &color : ledValues) { - // Retrieve last send colors - int lastRed = lastColorRedMap[idx]; - int lastGreen = lastColorGreenMap[idx]; - int lastBlue = lastColorBlueMap[idx]; - - // If color difference is higher than skipSmoothingDiff than we skip Orb smoothing (if enabled) and send it right away - if ((skipSmoothingDiff != 0 && useOrbSmoothing) && (abs(color.red - lastRed) >= skipSmoothingDiff || abs(color.blue - lastBlue) >= skipSmoothingDiff || - abs(color.green - lastGreen) >= skipSmoothingDiff)) - { - // Skip Orb smoothing when using (command type 4) - for (unsigned int i = 0; i < orbIds.size(); i++) { - if (orbIds[i] == idx) { - setColor(idx, color, 4); - } - } - } - else { - // Send color - for (unsigned int i = 0; i < orbIds.size(); i++) { - if (orbIds[i] == idx) { - setColor(idx, color, commandType); - } - } - } - - // Store last colors send for light id - lastColorRedMap[idx] = color.red; - lastColorGreenMap[idx] = color.green; - lastColorBlueMap[idx] = color.blue; - - // Next light id. - idx++; - } - - return 0; -} - -void LedDeviceAtmoOrb::setColor(unsigned int orbId, const ColorRgb &color, int commandType) { - QByteArray bytes; - bytes.resize(5 + numLeds * 3); - bytes.fill('\0'); - - // Command identifier: C0FFEE - bytes[0] = 0xC0; - bytes[1] = 0xFF; - bytes[2] = 0xEE; - - // Command type - bytes[3] = commandType; - - // Orb ID - bytes[4] = orbId; - - // RED / GREEN / BLUE - bytes[5] = color.red; - bytes[6] = color.green; - bytes[7] = color.blue; - - sendCommand(bytes); -} - -void LedDeviceAtmoOrb::sendCommand(const QByteArray &bytes) { - QByteArray datagram = bytes; - udpSocket->writeDatagram(datagram.data(), datagram.size(), - groupAddress, multiCastGroupPort); -} - -int LedDeviceAtmoOrb::switchOff() { - for (unsigned int i = 0; i < orbIds.size(); i++) { - QByteArray bytes; - bytes.resize(5 + numLeds * 3); - bytes.fill('\0'); - - // Command identifier: C0FFEE - bytes[0] = 0xC0; - bytes[1] = 0xFF; - bytes[2] = 0xEE; - - // Command type - bytes[3] = 1; - - // Orb ID - bytes[4] = orbIds[i]; - - // RED / GREEN / BLUE - bytes[5] = 0; - bytes[6] = 0; - bytes[7] = 0; - - sendCommand(bytes); - } - return 0; -} - -LedDeviceAtmoOrb::~LedDeviceAtmoOrb() { - delete manager; -} \ No newline at end of file +// Local-Hyperion includes +#include "LedDeviceAtmoOrb.h" + +// qt includes +#include +#include +#include +#include + +#include +#include +#include + +AtmoOrbLight::AtmoOrbLight(unsigned int id) { + // Not implemented +} + +LedDeviceAtmoOrb::LedDeviceAtmoOrb( + const std::string &output, + bool useOrbSmoothing, + int transitiontime, + int skipSmoothingDiff, + int port, + int numLeds, + std::vector orbIds) : + multicastGroup(output.c_str()), useOrbSmoothing(useOrbSmoothing), transitiontime(transitiontime), skipSmoothingDiff(skipSmoothingDiff), + multiCastGroupPort(port), numLeds(numLeds), orbIds(orbIds) +{ + manager = new QNetworkAccessManager(); + groupAddress = QHostAddress(multicastGroup); + + udpSocket = new QUdpSocket(this); + udpSocket->bind(multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint); + + joinedMulticastgroup = udpSocket->joinMulticastGroup(groupAddress); +} + +int LedDeviceAtmoOrb::write(const std::vector &ledValues) { + // If not in multicast group return + if (!joinedMulticastgroup) { + return 0; + } + + // Command options: + // + // 1 = force off + // 2 = use lamp smoothing and validate by Orb ID + // 4 = validate by Orb ID + + // When setting useOrbSmoothing = true it's recommended to disable Hyperion's own smoothing as it will conflict (double smoothing) + int commandType = 4; + if(useOrbSmoothing) + { + commandType = 2; + } + + // Iterate through colors and set Orb color + // Start off with idx 1 as 0 is reserved for controlling all orbs at once + unsigned int idx = 1; + + for (const ColorRgb &color : ledValues) { + // Retrieve last send colors + int lastRed = lastColorRedMap[idx]; + int lastGreen = lastColorGreenMap[idx]; + int lastBlue = lastColorBlueMap[idx]; + + // If color difference is higher than skipSmoothingDiff than we skip Orb smoothing (if enabled) and send it right away + if ((skipSmoothingDiff != 0 && useOrbSmoothing) && (abs(color.red - lastRed) >= skipSmoothingDiff || abs(color.blue - lastBlue) >= skipSmoothingDiff || + abs(color.green - lastGreen) >= skipSmoothingDiff)) + { + // Skip Orb smoothing when using (command type 4) + for (unsigned int i = 0; i < orbIds.size(); i++) { + if (orbIds[i] == idx) { + setColor(idx, color, 4); + } + } + } + else { + // Send color + for (unsigned int i = 0; i < orbIds.size(); i++) { + if (orbIds[i] == idx) { + setColor(idx, color, commandType); + } + } + } + + // Store last colors send for light id + lastColorRedMap[idx] = color.red; + lastColorGreenMap[idx] = color.green; + lastColorBlueMap[idx] = color.blue; + + // Next light id. + idx++; + } + + return 0; +} + +void LedDeviceAtmoOrb::setColor(unsigned int orbId, const ColorRgb &color, int commandType) { + QByteArray bytes; + bytes.resize(5 + numLeds * 3); + bytes.fill('\0'); + + // Command identifier: C0FFEE + bytes[0] = 0xC0; + bytes[1] = 0xFF; + bytes[2] = 0xEE; + + // Command type + bytes[3] = commandType; + + // Orb ID + bytes[4] = orbId; + + // RED / GREEN / BLUE + bytes[5] = color.red; + bytes[6] = color.green; + bytes[7] = color.blue; + + sendCommand(bytes); +} + +void LedDeviceAtmoOrb::sendCommand(const QByteArray &bytes) { + QByteArray datagram = bytes; + udpSocket->writeDatagram(datagram.data(), datagram.size(), + groupAddress, multiCastGroupPort); +} + +int LedDeviceAtmoOrb::switchOff() { + for (unsigned int i = 0; i < orbIds.size(); i++) { + QByteArray bytes; + bytes.resize(5 + numLeds * 3); + bytes.fill('\0'); + + // Command identifier: C0FFEE + bytes[0] = 0xC0; + bytes[1] = 0xFF; + bytes[2] = 0xEE; + + // Command type + bytes[3] = 1; + + // Orb ID + bytes[4] = orbIds[i]; + + // RED / GREEN / BLUE + bytes[5] = 0; + bytes[6] = 0; + bytes[7] = 0; + + sendCommand(bytes); + } + return 0; +} + +LedDeviceAtmoOrb::~LedDeviceAtmoOrb() { + delete manager; +} diff --git a/libsrc/leddevice/LedDeviceAtmoOrb.h b/libsrc/leddevice/LedDeviceAtmoOrb.h index 8c697af2..6b574155 100644 --- a/libsrc/leddevice/LedDeviceAtmoOrb.h +++ b/libsrc/leddevice/LedDeviceAtmoOrb.h @@ -1,132 +1,132 @@ -#pragma once - -// STL includes -#include - -// Qt includes -#include -#include -#include -#include - -// Leddevice includes -#include - -class QUdpSocket; - -class AtmoOrbLight { -public: - unsigned int id; - - /// - /// Constructs the light. - /// - /// @param id the orb id - AtmoOrbLight(unsigned int id); -}; - -/** - * Implementation for the AtmoOrb - * - * To use set the device to "atmoorb". - * - * @author RickDB (github) - */ -class LedDeviceAtmoOrb : public QObject, public LedDevice { - Q_OBJECT -public: - // Last send color map - QMap lastColorRedMap; - QMap lastColorGreenMap; - QMap lastColorBlueMap; - - // Multicast status - bool joinedMulticastgroup; - - /// - /// Constructs the device. - /// - /// @param output is the multicast address of Orbs - /// - /// @param transitiontime is optional and not used at the moment - /// - /// @param useOrbSmoothing use Orbs own (external) smoothing algorithm (default: false) - /// - /// @param skipSmoothingDiff minimal color (0-255) difference to override smoothing so that if current and previously received colors are higher than set dif we override smoothing - /// - /// @param port is the multicast port. - /// - /// @param numLeds is the total amount of leds per Orb - /// - /// @param array containing orb ids - /// - LedDeviceAtmoOrb(const std::string &output, bool useOrbSmoothing = - false, int transitiontime = 0, int skipSmoothingDiff = 0, int port = 49692, int numLeds = 24, - std::vector orbIds = std::vector < unsigned int>()); - - /// - /// Destructor of this device - /// - virtual ~LedDeviceAtmoOrb(); - - /// - /// Sends the given led-color values to the Orbs - /// - /// @param ledValues The color-value per led - /// - /// @return Zero on success else negative - /// - virtual int write(const std::vector &ledValues); - - virtual int switchOff(); - -private: - /// QNetworkAccessManager object for sending requests. - QNetworkAccessManager *manager; - - /// String containing multicast group IP address - QString multicastGroup; - - /// use Orbs own (external) smoothing algorithm - bool useOrbSmoothing; - - /// Transition time between colors (not implemented) - int transitiontime; - - // Maximum allowed color difference, will skip Orb (external) smoothing once reached - int skipSmoothingDiff; - - /// Multicast port to send data to - int multiCastGroupPort; - - /// Number of leds in Orb, used to determine buffer size - int numLeds; - - /// QHostAddress object of multicast group IP address - QHostAddress groupAddress; - - /// QUdpSocket object used to send data over - QUdpSocket *udpSocket; - - /// Array of the orb ids. - std::vector orbIds; - - /// - /// Set Orbcolor - /// - /// @param orbId the orb id - /// - /// @param color which color to set - /// - /// - /// @param commandType which type of command to send (off / smoothing / etc..) - /// - void setColor(unsigned int orbId, const ColorRgb &color, int commandType); - - /// - /// Send Orb command - /// - /// @param bytes the byte array containing command to send over multicast - /// - void sendCommand(const QByteArray &bytes); +#pragma once + +// STL includes +#include + +// Qt includes +#include +#include +#include +#include + +// Leddevice includes +#include + +class QUdpSocket; + +class AtmoOrbLight { +public: + unsigned int id; + + /// + /// Constructs the light. + /// + /// @param id the orb id + AtmoOrbLight(unsigned int id); +}; + +/** + * Implementation for the AtmoOrb + * + * To use set the device to "atmoorb". + * + * @author RickDB (github) + */ +class LedDeviceAtmoOrb : public QObject, public LedDevice { + Q_OBJECT +public: + // Last send color map + QMap lastColorRedMap; + QMap lastColorGreenMap; + QMap lastColorBlueMap; + + // Multicast status + bool joinedMulticastgroup; + + /// + /// Constructs the device. + /// + /// @param output is the multicast address of Orbs + /// + /// @param transitiontime is optional and not used at the moment + /// + /// @param useOrbSmoothing use Orbs own (external) smoothing algorithm (default: false) + /// + /// @param skipSmoothingDiff minimal color (0-255) difference to override smoothing so that if current and previously received colors are higher than set dif we override smoothing + /// + /// @param port is the multicast port. + /// + /// @param numLeds is the total amount of leds per Orb + /// + /// @param array containing orb ids + /// + LedDeviceAtmoOrb(const std::string &output, bool useOrbSmoothing = + false, int transitiontime = 0, int skipSmoothingDiff = 0, int port = 49692, int numLeds = 24, + std::vector orbIds = std::vector < unsigned int>()); + + /// + /// Destructor of this device + /// + virtual ~LedDeviceAtmoOrb(); + + /// + /// Sends the given led-color values to the Orbs + /// + /// @param ledValues The color-value per led + /// + /// @return Zero on success else negative + /// + virtual int write(const std::vector &ledValues); + + virtual int switchOff(); + +private: + /// QNetworkAccessManager object for sending requests. + QNetworkAccessManager *manager; + + /// String containing multicast group IP address + QString multicastGroup; + + /// use Orbs own (external) smoothing algorithm + bool useOrbSmoothing; + + /// Transition time between colors (not implemented) + int transitiontime; + + // Maximum allowed color difference, will skip Orb (external) smoothing once reached + int skipSmoothingDiff; + + /// Multicast port to send data to + int multiCastGroupPort; + + /// Number of leds in Orb, used to determine buffer size + int numLeds; + + /// QHostAddress object of multicast group IP address + QHostAddress groupAddress; + + /// QUdpSocket object used to send data over + QUdpSocket *udpSocket; + + /// Array of the orb ids. + std::vector orbIds; + + /// + /// Set Orbcolor + /// + /// @param orbId the orb id + /// + /// @param color which color to set + /// + /// + /// @param commandType which type of command to send (off / smoothing / etc..) + /// + void setColor(unsigned int orbId, const ColorRgb &color, int commandType); + + /// + /// Send Orb command + /// + /// @param bytes the byte array containing command to send over multicast + /// + void sendCommand(const QByteArray &bytes); }; \ No newline at end of file diff --git a/libsrc/leddevice/LedDeviceLpd6803.cpp b/libsrc/leddevice/LedDeviceLpd6803.cpp index 09d5f838..2a3aeb6b 100644 --- a/libsrc/leddevice/LedDeviceLpd6803.cpp +++ b/libsrc/leddevice/LedDeviceLpd6803.cpp @@ -1,50 +1,50 @@ -// STL includes -#include -#include -#include - -// Linux includes -#include -#include - -// hyperion local includes -#include "LedDeviceLpd6803.h" - -LedDeviceLpd6803::LedDeviceLpd6803(const std::string& outputDevice, const unsigned baudrate) : - LedSpiDevice(outputDevice, baudrate), - _ledBuffer(0) -{ - // empty -} - -int LedDeviceLpd6803::write(const std::vector &ledValues) -{ - unsigned messageLength = 4 + 2*ledValues.size() + ledValues.size()/8 + 1; - // Reconfigure if the current connfiguration does not match the required configuration - if (messageLength != _ledBuffer.size()) - { - // Initialise the buffer - _ledBuffer.resize(messageLength, 0x00); - } - - // Copy the colors from the ColorRgb vector to the Ldp6803 data vector - for (unsigned iLed=0; iLed> 1) | (rgb.green >> 6); - _ledBuffer[5 + 2 * iLed] = ((rgb.green & 0x38) << 2) | (rgb.blue >> 3); - } - - // Write the data - if (writeBytes(_ledBuffer.size(), _ledBuffer.data()) < 0) - { - return -1; - } - return 0; -} - -int LedDeviceLpd6803::switchOff() -{ - return write(std::vector(_ledBuffer.size(), ColorRgb{0,0,0})); -} +// STL includes +#include +#include +#include + +// Linux includes +#include +#include + +// hyperion local includes +#include "LedDeviceLpd6803.h" + +LedDeviceLpd6803::LedDeviceLpd6803(const std::string& outputDevice, const unsigned baudrate) : + LedSpiDevice(outputDevice, baudrate), + _ledBuffer(0) +{ + // empty +} + +int LedDeviceLpd6803::write(const std::vector &ledValues) +{ + unsigned messageLength = 4 + 2*ledValues.size() + ledValues.size()/8 + 1; + // Reconfigure if the current connfiguration does not match the required configuration + if (messageLength != _ledBuffer.size()) + { + // Initialise the buffer + _ledBuffer.resize(messageLength, 0x00); + } + + // Copy the colors from the ColorRgb vector to the Ldp6803 data vector + for (unsigned iLed=0; iLed> 1) | (rgb.green >> 6); + _ledBuffer[5 + 2 * iLed] = ((rgb.green & 0x38) << 2) | (rgb.blue >> 3); + } + + // Write the data + if (writeBytes(_ledBuffer.size(), _ledBuffer.data()) < 0) + { + return -1; + } + return 0; +} + +int LedDeviceLpd6803::switchOff() +{ + return write(std::vector(_ledBuffer.size(), ColorRgb{0,0,0})); +} diff --git a/libsrc/leddevice/LedDeviceLpd6803.h b/libsrc/leddevice/LedDeviceLpd6803.h index c53919b2..f3d08978 100644 --- a/libsrc/leddevice/LedDeviceLpd6803.h +++ b/libsrc/leddevice/LedDeviceLpd6803.h @@ -1,42 +1,42 @@ -#pragma once - -// Local hyperion incluse -#include "LedSpiDevice.h" - -/// -/// Implementation of the LedDevice interface for writing to LDP6803 led device. -/// -/// 00000000 00000000 00000000 00000000 1RRRRRGG GGGBBBBB 1RRRRRGG GGGBBBBB ... -/// |---------------------------------| |---------------| |---------------| -/// 32 zeros to start the frame Led1 Led2 ... -/// -/// For each led, the first bit is always 1, and then you have 5 bits each for red, green and blue -/// (R, G and B in the above illustration) making 16 bits per led. Total bytes = 4 + (2 x number of -/// leds) -/// -class LedDeviceLpd6803 : public LedSpiDevice -{ -public: - /// - /// Constructs the LedDevice for a string containing leds of the type LDP6803 - /// - /// @param[in] outputDevice The name of the output device (eg '/dev/spidev0.0') - /// @param[in] baudrate The used baudrate for writing to the output device - /// - LedDeviceLpd6803(const std::string& outputDevice, const unsigned baudrate); - - /// - /// Writes the led color values to the led-device - /// - /// @param ledValues The color-value per led - /// @return Zero on succes else negative - /// - virtual int write(const std::vector &ledValues); - - /// Switch the leds off - virtual int switchOff(); - -private: - /// The buffer containing the packed RGB values - std::vector _ledBuffer; -}; +#pragma once + +// Local hyperion incluse +#include "LedSpiDevice.h" + +/// +/// Implementation of the LedDevice interface for writing to LDP6803 led device. +/// +/// 00000000 00000000 00000000 00000000 1RRRRRGG GGGBBBBB 1RRRRRGG GGGBBBBB ... +/// |---------------------------------| |---------------| |---------------| +/// 32 zeros to start the frame Led1 Led2 ... +/// +/// For each led, the first bit is always 1, and then you have 5 bits each for red, green and blue +/// (R, G and B in the above illustration) making 16 bits per led. Total bytes = 4 + (2 x number of +/// leds) +/// +class LedDeviceLpd6803 : public LedSpiDevice +{ +public: + /// + /// Constructs the LedDevice for a string containing leds of the type LDP6803 + /// + /// @param[in] outputDevice The name of the output device (eg '/dev/spidev0.0') + /// @param[in] baudrate The used baudrate for writing to the output device + /// + LedDeviceLpd6803(const std::string& outputDevice, const unsigned baudrate); + + /// + /// Writes the led color values to the led-device + /// + /// @param ledValues The color-value per led + /// @return Zero on succes else negative + /// + virtual int write(const std::vector &ledValues); + + /// Switch the leds off + virtual int switchOff(); + +private: + /// The buffer containing the packed RGB values + std::vector _ledBuffer; +}; diff --git a/libsrc/leddevice/LedDeviceLpd8806.cpp b/libsrc/leddevice/LedDeviceLpd8806.cpp index 3e8cc1da..f9dfb53c 100644 --- a/libsrc/leddevice/LedDeviceLpd8806.cpp +++ b/libsrc/leddevice/LedDeviceLpd8806.cpp @@ -1,54 +1,54 @@ -// STL includes -#include -#include -#include - -// Linux includes -#include -#include - -// hyperion local includes -#include "LedDeviceLpd8806.h" - -LedDeviceLpd8806::LedDeviceLpd8806(const std::string& outputDevice, const unsigned baudrate) : - LedSpiDevice(outputDevice, baudrate), - _ledBuffer(0) -{ - // empty -} - -int LedDeviceLpd8806::write(const std::vector &ledValues) -{ - const unsigned clearSize = ledValues.size()/32+1; - // Reconfigure if the current connfiguration does not match the required configuration - if (3*ledValues.size() + clearSize != _ledBuffer.size()) - { - // Initialise the buffer - _ledBuffer.resize(3*ledValues.size() + clearSize, 0x00); - - // Perform an initial reset to start accepting data on the first led - writeBytes(clearSize, _ledBuffer.data()); - } - - // Copy the colors from the ColorRgb vector to the Ldp8806 data vector - for (unsigned iLed=0; iLed> 1); - _ledBuffer[iLed*3+1] = 0x80 | (rgb.green >> 1); - _ledBuffer[iLed*3+2] = 0x80 | (rgb.blue >> 1); - } - - // Write the data - if (writeBytes(_ledBuffer.size(), _ledBuffer.data()) < 0) - { - return -1; - } - return 0; -} - -int LedDeviceLpd8806::switchOff() -{ - return write(std::vector(_ledBuffer.size(), ColorRgb{0,0,0})); -} +// STL includes +#include +#include +#include + +// Linux includes +#include +#include + +// hyperion local includes +#include "LedDeviceLpd8806.h" + +LedDeviceLpd8806::LedDeviceLpd8806(const std::string& outputDevice, const unsigned baudrate) : + LedSpiDevice(outputDevice, baudrate), + _ledBuffer(0) +{ + // empty +} + +int LedDeviceLpd8806::write(const std::vector &ledValues) +{ + const unsigned clearSize = ledValues.size()/32+1; + // Reconfigure if the current connfiguration does not match the required configuration + if (3*ledValues.size() + clearSize != _ledBuffer.size()) + { + // Initialise the buffer + _ledBuffer.resize(3*ledValues.size() + clearSize, 0x00); + + // Perform an initial reset to start accepting data on the first led + writeBytes(clearSize, _ledBuffer.data()); + } + + // Copy the colors from the ColorRgb vector to the Ldp8806 data vector + for (unsigned iLed=0; iLed> 1); + _ledBuffer[iLed*3+1] = 0x80 | (rgb.green >> 1); + _ledBuffer[iLed*3+2] = 0x80 | (rgb.blue >> 1); + } + + // Write the data + if (writeBytes(_ledBuffer.size(), _ledBuffer.data()) < 0) + { + return -1; + } + return 0; +} + +int LedDeviceLpd8806::switchOff() +{ + return write(std::vector(_ledBuffer.size(), ColorRgb{0,0,0})); +} diff --git a/libsrc/leddevice/LedDeviceLpd8806.h b/libsrc/leddevice/LedDeviceLpd8806.h index bf85b177..8d4bed3a 100644 --- a/libsrc/leddevice/LedDeviceLpd8806.h +++ b/libsrc/leddevice/LedDeviceLpd8806.h @@ -1,103 +1,103 @@ -#pragma once - -// Local hyperion incluse -#include "LedSpiDevice.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 behavior 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 writen 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 LedSpiDevice -{ -public: - /// - /// Constructs the LedDevice for a string containing leds of the type LPD8806 - /// - /// @param[in] outputDevice The name of the output device (eg '/dev/spidev0.0') - /// @param[in] baudrate The used baudrate for writing to the output device - /// - LedDeviceLpd8806(const std::string& outputDevice, const unsigned baudrate); - - /// - /// Writes the led color values to the led-device - /// - /// @param ledValues The color-value per led - /// @return Zero on succes else negative - /// - virtual int write(const std::vector &ledValues); - - /// Switch the leds off - virtual int switchOff(); - -private: - /// The buffer containing the packed RGB values - std::vector _ledBuffer; -}; +#pragma once + +// Local hyperion incluse +#include "LedSpiDevice.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 behavior 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 writen 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 LedSpiDevice +{ +public: + /// + /// Constructs the LedDevice for a string containing leds of the type LPD8806 + /// + /// @param[in] outputDevice The name of the output device (eg '/dev/spidev0.0') + /// @param[in] baudrate The used baudrate for writing to the output device + /// + LedDeviceLpd8806(const std::string& outputDevice, const unsigned baudrate); + + /// + /// Writes the led color values to the led-device + /// + /// @param ledValues The color-value per led + /// @return Zero on succes else negative + /// + virtual int write(const std::vector &ledValues); + + /// Switch the leds off + virtual int switchOff(); + +private: + /// The buffer containing the packed RGB values + std::vector _ledBuffer; +}; diff --git a/libsrc/leddevice/LedDevicePhilipsHue.cpp b/libsrc/leddevice/LedDevicePhilipsHue.cpp index eec1c824..464820bb 100755 --- a/libsrc/leddevice/LedDevicePhilipsHue.cpp +++ b/libsrc/leddevice/LedDevicePhilipsHue.cpp @@ -1,342 +1,342 @@ -// Local-Hyperion includes -#include "LedDevicePhilipsHue.h" - -// jsoncpp includes -#include - -// qt includes -#include -#include -#include - -#include -#include - -bool operator ==(CiColor p1, CiColor p2) { - return (p1.x == p2.x) && (p1.y == p2.y) && (p1.bri == p2.bri); -} - -bool operator !=(CiColor p1, CiColor p2) { - return !(p1 == p2); -} - -PhilipsHueLight::PhilipsHueLight(unsigned int id, QString originalState, QString modelId) : - id(id), originalState(originalState) { - // Hue system model ids (http://www.developers.meethue.com/documentation/supported-lights). - // Light strips, color iris, ... - const std::set GAMUT_A_MODEL_IDS = { "LLC001", "LLC005", "LLC006", "LLC007", "LLC010", "LLC011", "LLC012", - "LLC013", "LLC014", "LST001" }; - // Hue bulbs, spots, ... - const std::set GAMUT_B_MODEL_IDS = { "LCT001", "LCT002", "LCT003", "LCT007", "LLM001" }; - // Hue Lightstrip plus, go ... - const std::set GAMUT_C_MODEL_IDS = { "LLC020", "LST002" }; - // Find id in the sets and set the appropiate color space. - if (GAMUT_A_MODEL_IDS.find(modelId) != GAMUT_A_MODEL_IDS.end()) { - colorSpace.red = {0.703f, 0.296f}; - colorSpace.green = {0.2151f, 0.7106f}; - colorSpace.blue = {0.138f, 0.08f}; - } else if (GAMUT_B_MODEL_IDS.find(modelId) != GAMUT_B_MODEL_IDS.end()) { - colorSpace.red = {0.675f, 0.322f}; - colorSpace.green = {0.4091f, 0.518f}; - colorSpace.blue = {0.167f, 0.04f}; - } else if (GAMUT_C_MODEL_IDS.find(modelId) != GAMUT_B_MODEL_IDS.end()) { - colorSpace.red = {0.675f, 0.322f}; - colorSpace.green = {0.2151f, 0.7106f}; - colorSpace.blue = {0.167f, 0.04f}; - } else { - colorSpace.red = {1.0f, 0.0f}; - colorSpace.green = {0.0f, 1.0f}; - colorSpace.blue = {0.0f, 0.0f}; - } - // Initialize black color. - black = rgbToCiColor(0.0f, 0.0f, 0.0f); - // Initialize color with black - color = {black.x, black.y, black.bri}; -} - -float PhilipsHueLight::crossProduct(CiColor p1, CiColor p2) { - return p1.x * p2.y - p1.y * p2.x; -} - -bool PhilipsHueLight::isPointInLampsReach(CiColor p) { - CiColor v1 = { colorSpace.green.x - colorSpace.red.x, colorSpace.green.y - colorSpace.red.y }; - CiColor v2 = { colorSpace.blue.x - colorSpace.red.x, colorSpace.blue.y - colorSpace.red.y }; - CiColor q = { p.x - colorSpace.red.x, p.y - colorSpace.red.y }; - float s = crossProduct(q, v2) / crossProduct(v1, v2); - float t = crossProduct(v1, q) / crossProduct(v1, v2); - if ((s >= 0.0f) && (t >= 0.0f) && (s + t <= 1.0f)) { - return true; - } - return false; -} - -CiColor PhilipsHueLight::getClosestPointToPoint(CiColor a, CiColor b, CiColor p) { - CiColor AP = { p.x - a.x, p.y - a.y }; - CiColor AB = { b.x - a.x, b.y - a.y }; - float ab2 = AB.x * AB.x + AB.y * AB.y; - float ap_ab = AP.x * AB.x + AP.y * AB.y; - float t = ap_ab / ab2; - if (t < 0.0f) { - t = 0.0f; - } else if (t > 1.0f) { - t = 1.0f; - } - return {a.x + AB.x * t, a.y + AB.y * t}; -} - -float PhilipsHueLight::getDistanceBetweenTwoPoints(CiColor p1, CiColor p2) { - // Horizontal difference. - float dx = p1.x - p2.x; - // Vertical difference. - float dy = p1.y - p2.y; - // Absolute value. - return sqrt(dx * dx + dy * dy); -} - -CiColor PhilipsHueLight::rgbToCiColor(float red, float green, float blue) { - // Apply gamma correction. - float r = (red > 0.04045f) ? powf((red + 0.055f) / (1.0f + 0.055f), 2.4f) : (red / 12.92f); - float g = (green > 0.04045f) ? powf((green + 0.055f) / (1.0f + 0.055f), 2.4f) : (green / 12.92f); - float b = (blue > 0.04045f) ? powf((blue + 0.055f) / (1.0f + 0.055f), 2.4f) : (blue / 12.92f); - // Convert to XYZ space. - float X = r * 0.649926f + g * 0.103455f + b * 0.197109f; - float Y = r * 0.234327f + g * 0.743075f + b * 0.022598f; - float Z = r * 0.0000000f + g * 0.053077f + b * 1.035763f; - // Convert to x,y space. - float cx = X / (X + Y + Z); - float cy = Y / (X + Y + Z); - if (isnan(cx)) { - cx = 0.0f; - } - if (isnan(cy)) { - cy = 0.0f; - } - // Brightness is simply Y in the XYZ space. - CiColor xy = { cx, cy, Y }; - // Check if the given XY value is within the color reach of our lamps. - if (!isPointInLampsReach(xy)) { - // It seems the color is out of reach let's find the closes color we can produce with our lamp and send this XY value out. - CiColor pAB = getClosestPointToPoint(colorSpace.red, colorSpace.green, xy); - CiColor pAC = getClosestPointToPoint(colorSpace.blue, colorSpace.red, xy); - CiColor pBC = getClosestPointToPoint(colorSpace.green, colorSpace.blue, xy); - // Get the distances per point and see which point is closer to our Point. - float dAB = getDistanceBetweenTwoPoints(xy, pAB); - float dAC = getDistanceBetweenTwoPoints(xy, pAC); - float dBC = getDistanceBetweenTwoPoints(xy, pBC); - float lowest = dAB; - CiColor closestPoint = pAB; - if (dAC < lowest) { - lowest = dAC; - closestPoint = pAC; - } - if (dBC < lowest) { - lowest = dBC; - closestPoint = pBC; - } - // Change the xy value to a value which is within the reach of the lamp. - xy.x = closestPoint.x; - xy.y = closestPoint.y; - } - return xy; -} - -LedDevicePhilipsHue::LedDevicePhilipsHue(const std::string& output, const std::string& username, bool switchOffOnBlack, - int transitiontime, std::vector lightIds) : - host(output.c_str()), username(username.c_str()), switchOffOnBlack(switchOffOnBlack), transitiontime( - transitiontime), lightIds(lightIds) { - manager = new QNetworkAccessManager(); - timer.setInterval(3000); - timer.setSingleShot(true); - connect(&timer, SIGNAL(timeout()), this, SLOT(restoreStates())); -} - -LedDevicePhilipsHue::~LedDevicePhilipsHue() { - delete manager; -} - -int LedDevicePhilipsHue::write(const std::vector & ledValues) { - // Save light states if not done before. - if (!areStatesSaved()) { - saveStates((unsigned int) ledValues.size()); - switchOn((unsigned int) ledValues.size()); - } - // If there are less states saved than colors given, then maybe something went wrong before. - if (lights.size() != ledValues.size()) { - restoreStates(); - return 0; - } - // Iterate through colors and set light states. - unsigned int idx = 0; - for (const ColorRgb& color : ledValues) { - // Get lamp. - PhilipsHueLight& lamp = lights.at(idx); - // Scale colors from [0, 255] to [0, 1] and convert to xy space. - CiColor xy = lamp.rgbToCiColor(color.red / 255.0f, color.green / 255.0f, color.blue / 255.0f); - // Write color if color has been changed. - if (xy != lamp.color) { - // Switch on if the lamp has been previously switched off. - if (switchOffOnBlack && lamp.color == lamp.black) { - put(getStateRoute(lamp.id), QString("{\"on\": true}")); - } - // Send adjust color and brightness command in JSON format. - // We have to set the transition time each time. - put(getStateRoute(lamp.id), - QString("{\"xy\": [%1, %2], \"bri\": %3, \"transitiontime\": %4}").arg(xy.x).arg(xy.y).arg( - qRound(xy.bri * 255.0f)).arg(transitiontime)); - - } - // Switch lamp off if switchOffOnBlack is enabled and the lamp is currently on. - if (switchOffOnBlack) { - // From black to a color. - if (lamp.color == lamp.black && xy != lamp.black) { - put(getStateRoute(lamp.id), QString("{\"on\": true}")); - } - // From a color to black. - else if (lamp.color != lamp.black && xy == lamp.black) { - put(getStateRoute(lamp.id), QString("{\"on\": false}")); - } - } - // Remember last color. - lamp.color = xy; - // Next light id. - idx++; - } - timer.start(); - return 0; -} - -int LedDevicePhilipsHue::switchOff() { - timer.stop(); - // If light states have been saved before, ... - if (areStatesSaved()) { - // ... restore them. - restoreStates(); - } - return 0; -} - -void LedDevicePhilipsHue::put(QString route, QString content) { - QString url = getUrl(route); - // Perfrom request - QNetworkRequest request(url); - QNetworkReply* reply = manager->put(request, content.toLatin1()); - // Connect finished signal to quit slot of the loop. - QEventLoop loop; - loop.connect(reply, SIGNAL(finished()), SLOT(quit())); - // Go into the loop until the request is finished. - loop.exec(); - // Free space. - reply->deleteLater(); -} - -QByteArray LedDevicePhilipsHue::get(QString route) { - QString url = getUrl(route); - // Perfrom request - QNetworkRequest request(url); - QNetworkReply* reply = manager->get(request); - // Connect requestFinished signal to quit slot of the loop. - QEventLoop loop; - loop.connect(reply, SIGNAL(finished()), SLOT(quit())); - // Go into the loop until the request is finished. - loop.exec(); - // Read all data of the response. - QByteArray response = reply->readAll(); - // Free space. - reply->deleteLater(); - // Return response - return response; -} - -QString LedDevicePhilipsHue::getStateRoute(unsigned int lightId) { - return QString("lights/%1/state").arg(lightId); -} - -QString LedDevicePhilipsHue::getRoute(unsigned int lightId) { - return QString("lights/%1").arg(lightId); -} - -QString LedDevicePhilipsHue::getUrl(QString route) { - return QString("http://%1/api/%2/%3").arg(host).arg(username).arg(route); -} - -void LedDevicePhilipsHue::saveStates(unsigned int nLights) { - // Clear saved lamps. - lights.clear(); - // Use json parser to parse reponse. - Json::Reader reader; - Json::FastWriter writer; - // Read light ids if none have been supplied by the user. - if (lightIds.size() != nLights) { - lightIds.clear(); - // - QByteArray response = get("lights"); - Json::Value json; - if (!reader.parse(QString(response).toStdString(), json)) { - throw std::runtime_error(("No lights found at " + getUrl("lights")).toStdString()); - } - // Loop over all children. - for (Json::ValueIterator it = json.begin(); it != json.end() && lightIds.size() < nLights; it++) { - int lightId = atoi(it.key().asCString()); - lightIds.push_back(lightId); - std::cout << "LedDevicePhilipsHue::saveStates(nLights=" << nLights << "): found light with id " << lightId - << "." << std::endl; - } - // Check if we found enough lights. - if (lightIds.size() != nLights) { - throw std::runtime_error(("Not enough lights found at " + getUrl("lights")).toStdString()); - } - } - // Iterate lights. - for (unsigned int i = 0; i < nLights; i++) { - // Read the response. - QByteArray response = get(getRoute(lightIds.at(i))); - // Parse JSON. - Json::Value json; - if (!reader.parse(QString(response).toStdString(), json)) { - // Error occured, break loop. - std::cerr << "LedDevicePhilipsHue::saveStates(nLights=" << nLights << "): got invalid response from light " - << getUrl(getRoute(lightIds.at(i))).toStdString() << "." << std::endl; - break; - } - // Get state object values which are subject to change. - Json::Value state(Json::objectValue); - if (!json.isMember("state")) { - std::cerr << "LedDevicePhilipsHue::saveStates(nLights=" << nLights << "): got no state for light from " - << getUrl(getRoute(lightIds.at(i))).toStdString() << std::endl; - break; - } - if (!json["state"].isMember("on")) { - std::cerr << "LedDevicePhilipsHue::saveStates(nLights=" << nLights << "): got no valid state from light " - << getUrl(getRoute(lightIds.at(i))).toStdString() << std::endl; - break; - } - state["on"] = json["state"]["on"]; - if (json["state"]["on"] == true) { - state["xy"] = json["state"]["xy"]; - state["bri"] = json["state"]["bri"]; - } - // Determine the model id. - QString modelId = QString(writer.write(json["modelid"]).c_str()).trimmed().replace("\"", ""); - QString originalState = QString(writer.write(state).c_str()).trimmed(); - // Save state object. - lights.push_back(PhilipsHueLight(lightIds.at(i), originalState, modelId)); - } -} - -void LedDevicePhilipsHue::switchOn(unsigned int nLights) { - for (PhilipsHueLight light : lights) { - put(getStateRoute(light.id), "{\"on\": true}"); - } -} - -void LedDevicePhilipsHue::restoreStates() { - for (PhilipsHueLight light : lights) { - put(getStateRoute(light.id), light.originalState); - } - // Clear saved light states. - lights.clear(); -} - -bool LedDevicePhilipsHue::areStatesSaved() { - return !lights.empty(); -} +// Local-Hyperion includes +#include "LedDevicePhilipsHue.h" + +// jsoncpp includes +#include + +// qt includes +#include +#include +#include + +#include +#include + +bool operator ==(CiColor p1, CiColor p2) { + return (p1.x == p2.x) && (p1.y == p2.y) && (p1.bri == p2.bri); +} + +bool operator !=(CiColor p1, CiColor p2) { + return !(p1 == p2); +} + +PhilipsHueLight::PhilipsHueLight(unsigned int id, QString originalState, QString modelId) : + id(id), originalState(originalState) { + // Hue system model ids (http://www.developers.meethue.com/documentation/supported-lights). + // Light strips, color iris, ... + const std::set GAMUT_A_MODEL_IDS = { "LLC001", "LLC005", "LLC006", "LLC007", "LLC010", "LLC011", "LLC012", + "LLC013", "LLC014", "LST001" }; + // Hue bulbs, spots, ... + const std::set GAMUT_B_MODEL_IDS = { "LCT001", "LCT002", "LCT003", "LCT007", "LLM001" }; + // Hue Lightstrip plus, go ... + const std::set GAMUT_C_MODEL_IDS = { "LLC020", "LST002" }; + // Find id in the sets and set the appropiate color space. + if (GAMUT_A_MODEL_IDS.find(modelId) != GAMUT_A_MODEL_IDS.end()) { + colorSpace.red = {0.703f, 0.296f}; + colorSpace.green = {0.2151f, 0.7106f}; + colorSpace.blue = {0.138f, 0.08f}; + } else if (GAMUT_B_MODEL_IDS.find(modelId) != GAMUT_B_MODEL_IDS.end()) { + colorSpace.red = {0.675f, 0.322f}; + colorSpace.green = {0.4091f, 0.518f}; + colorSpace.blue = {0.167f, 0.04f}; + } else if (GAMUT_C_MODEL_IDS.find(modelId) != GAMUT_B_MODEL_IDS.end()) { + colorSpace.red = {0.675f, 0.322f}; + colorSpace.green = {0.2151f, 0.7106f}; + colorSpace.blue = {0.167f, 0.04f}; + } else { + colorSpace.red = {1.0f, 0.0f}; + colorSpace.green = {0.0f, 1.0f}; + colorSpace.blue = {0.0f, 0.0f}; + } + // Initialize black color. + black = rgbToCiColor(0.0f, 0.0f, 0.0f); + // Initialize color with black + color = {black.x, black.y, black.bri}; +} + +float PhilipsHueLight::crossProduct(CiColor p1, CiColor p2) { + return p1.x * p2.y - p1.y * p2.x; +} + +bool PhilipsHueLight::isPointInLampsReach(CiColor p) { + CiColor v1 = { colorSpace.green.x - colorSpace.red.x, colorSpace.green.y - colorSpace.red.y }; + CiColor v2 = { colorSpace.blue.x - colorSpace.red.x, colorSpace.blue.y - colorSpace.red.y }; + CiColor q = { p.x - colorSpace.red.x, p.y - colorSpace.red.y }; + float s = crossProduct(q, v2) / crossProduct(v1, v2); + float t = crossProduct(v1, q) / crossProduct(v1, v2); + if ((s >= 0.0f) && (t >= 0.0f) && (s + t <= 1.0f)) { + return true; + } + return false; +} + +CiColor PhilipsHueLight::getClosestPointToPoint(CiColor a, CiColor b, CiColor p) { + CiColor AP = { p.x - a.x, p.y - a.y }; + CiColor AB = { b.x - a.x, b.y - a.y }; + float ab2 = AB.x * AB.x + AB.y * AB.y; + float ap_ab = AP.x * AB.x + AP.y * AB.y; + float t = ap_ab / ab2; + if (t < 0.0f) { + t = 0.0f; + } else if (t > 1.0f) { + t = 1.0f; + } + return {a.x + AB.x * t, a.y + AB.y * t}; +} + +float PhilipsHueLight::getDistanceBetweenTwoPoints(CiColor p1, CiColor p2) { + // Horizontal difference. + float dx = p1.x - p2.x; + // Vertical difference. + float dy = p1.y - p2.y; + // Absolute value. + return sqrt(dx * dx + dy * dy); +} + +CiColor PhilipsHueLight::rgbToCiColor(float red, float green, float blue) { + // Apply gamma correction. + float r = (red > 0.04045f) ? powf((red + 0.055f) / (1.0f + 0.055f), 2.4f) : (red / 12.92f); + float g = (green > 0.04045f) ? powf((green + 0.055f) / (1.0f + 0.055f), 2.4f) : (green / 12.92f); + float b = (blue > 0.04045f) ? powf((blue + 0.055f) / (1.0f + 0.055f), 2.4f) : (blue / 12.92f); + // Convert to XYZ space. + float X = r * 0.649926f + g * 0.103455f + b * 0.197109f; + float Y = r * 0.234327f + g * 0.743075f + b * 0.022598f; + float Z = r * 0.0000000f + g * 0.053077f + b * 1.035763f; + // Convert to x,y space. + float cx = X / (X + Y + Z); + float cy = Y / (X + Y + Z); + if (isnan(cx)) { + cx = 0.0f; + } + if (isnan(cy)) { + cy = 0.0f; + } + // Brightness is simply Y in the XYZ space. + CiColor xy = { cx, cy, Y }; + // Check if the given XY value is within the color reach of our lamps. + if (!isPointInLampsReach(xy)) { + // It seems the color is out of reach let's find the closes color we can produce with our lamp and send this XY value out. + CiColor pAB = getClosestPointToPoint(colorSpace.red, colorSpace.green, xy); + CiColor pAC = getClosestPointToPoint(colorSpace.blue, colorSpace.red, xy); + CiColor pBC = getClosestPointToPoint(colorSpace.green, colorSpace.blue, xy); + // Get the distances per point and see which point is closer to our Point. + float dAB = getDistanceBetweenTwoPoints(xy, pAB); + float dAC = getDistanceBetweenTwoPoints(xy, pAC); + float dBC = getDistanceBetweenTwoPoints(xy, pBC); + float lowest = dAB; + CiColor closestPoint = pAB; + if (dAC < lowest) { + lowest = dAC; + closestPoint = pAC; + } + if (dBC < lowest) { + lowest = dBC; + closestPoint = pBC; + } + // Change the xy value to a value which is within the reach of the lamp. + xy.x = closestPoint.x; + xy.y = closestPoint.y; + } + return xy; +} + +LedDevicePhilipsHue::LedDevicePhilipsHue(const std::string& output, const std::string& username, bool switchOffOnBlack, + int transitiontime, std::vector lightIds) : + host(output.c_str()), username(username.c_str()), switchOffOnBlack(switchOffOnBlack), transitiontime( + transitiontime), lightIds(lightIds) { + manager = new QNetworkAccessManager(); + timer.setInterval(3000); + timer.setSingleShot(true); + connect(&timer, SIGNAL(timeout()), this, SLOT(restoreStates())); +} + +LedDevicePhilipsHue::~LedDevicePhilipsHue() { + delete manager; +} + +int LedDevicePhilipsHue::write(const std::vector & ledValues) { + // Save light states if not done before. + if (!areStatesSaved()) { + saveStates((unsigned int) ledValues.size()); + switchOn((unsigned int) ledValues.size()); + } + // If there are less states saved than colors given, then maybe something went wrong before. + if (lights.size() != ledValues.size()) { + restoreStates(); + return 0; + } + // Iterate through colors and set light states. + unsigned int idx = 0; + for (const ColorRgb& color : ledValues) { + // Get lamp. + PhilipsHueLight& lamp = lights.at(idx); + // Scale colors from [0, 255] to [0, 1] and convert to xy space. + CiColor xy = lamp.rgbToCiColor(color.red / 255.0f, color.green / 255.0f, color.blue / 255.0f); + // Write color if color has been changed. + if (xy != lamp.color) { + // Switch on if the lamp has been previously switched off. + if (switchOffOnBlack && lamp.color == lamp.black) { + put(getStateRoute(lamp.id), QString("{\"on\": true}")); + } + // Send adjust color and brightness command in JSON format. + // We have to set the transition time each time. + put(getStateRoute(lamp.id), + QString("{\"xy\": [%1, %2], \"bri\": %3, \"transitiontime\": %4}").arg(xy.x).arg(xy.y).arg( + qRound(xy.bri * 255.0f)).arg(transitiontime)); + + } + // Switch lamp off if switchOffOnBlack is enabled and the lamp is currently on. + if (switchOffOnBlack) { + // From black to a color. + if (lamp.color == lamp.black && xy != lamp.black) { + put(getStateRoute(lamp.id), QString("{\"on\": true}")); + } + // From a color to black. + else if (lamp.color != lamp.black && xy == lamp.black) { + put(getStateRoute(lamp.id), QString("{\"on\": false}")); + } + } + // Remember last color. + lamp.color = xy; + // Next light id. + idx++; + } + timer.start(); + return 0; +} + +int LedDevicePhilipsHue::switchOff() { + timer.stop(); + // If light states have been saved before, ... + if (areStatesSaved()) { + // ... restore them. + restoreStates(); + } + return 0; +} + +void LedDevicePhilipsHue::put(QString route, QString content) { + QString url = getUrl(route); + // Perfrom request + QNetworkRequest request(url); + QNetworkReply* reply = manager->put(request, content.toLatin1()); + // Connect finished signal to quit slot of the loop. + QEventLoop loop; + loop.connect(reply, SIGNAL(finished()), SLOT(quit())); + // Go into the loop until the request is finished. + loop.exec(); + // Free space. + reply->deleteLater(); +} + +QByteArray LedDevicePhilipsHue::get(QString route) { + QString url = getUrl(route); + // Perfrom request + QNetworkRequest request(url); + QNetworkReply* reply = manager->get(request); + // Connect requestFinished signal to quit slot of the loop. + QEventLoop loop; + loop.connect(reply, SIGNAL(finished()), SLOT(quit())); + // Go into the loop until the request is finished. + loop.exec(); + // Read all data of the response. + QByteArray response = reply->readAll(); + // Free space. + reply->deleteLater(); + // Return response + return response; +} + +QString LedDevicePhilipsHue::getStateRoute(unsigned int lightId) { + return QString("lights/%1/state").arg(lightId); +} + +QString LedDevicePhilipsHue::getRoute(unsigned int lightId) { + return QString("lights/%1").arg(lightId); +} + +QString LedDevicePhilipsHue::getUrl(QString route) { + return QString("http://%1/api/%2/%3").arg(host).arg(username).arg(route); +} + +void LedDevicePhilipsHue::saveStates(unsigned int nLights) { + // Clear saved lamps. + lights.clear(); + // Use json parser to parse reponse. + Json::Reader reader; + Json::FastWriter writer; + // Read light ids if none have been supplied by the user. + if (lightIds.size() != nLights) { + lightIds.clear(); + // + QByteArray response = get("lights"); + Json::Value json; + if (!reader.parse(QString(response).toStdString(), json)) { + throw std::runtime_error(("No lights found at " + getUrl("lights")).toStdString()); + } + // Loop over all children. + for (Json::ValueIterator it = json.begin(); it != json.end() && lightIds.size() < nLights; it++) { + int lightId = atoi(it.key().asCString()); + lightIds.push_back(lightId); + std::cout << "LedDevicePhilipsHue::saveStates(nLights=" << nLights << "): found light with id " << lightId + << "." << std::endl; + } + // Check if we found enough lights. + if (lightIds.size() != nLights) { + throw std::runtime_error(("Not enough lights found at " + getUrl("lights")).toStdString()); + } + } + // Iterate lights. + for (unsigned int i = 0; i < nLights; i++) { + // Read the response. + QByteArray response = get(getRoute(lightIds.at(i))); + // Parse JSON. + Json::Value json; + if (!reader.parse(QString(response).toStdString(), json)) { + // Error occured, break loop. + std::cerr << "LedDevicePhilipsHue::saveStates(nLights=" << nLights << "): got invalid response from light " + << getUrl(getRoute(lightIds.at(i))).toStdString() << "." << std::endl; + break; + } + // Get state object values which are subject to change. + Json::Value state(Json::objectValue); + if (!json.isMember("state")) { + std::cerr << "LedDevicePhilipsHue::saveStates(nLights=" << nLights << "): got no state for light from " + << getUrl(getRoute(lightIds.at(i))).toStdString() << std::endl; + break; + } + if (!json["state"].isMember("on")) { + std::cerr << "LedDevicePhilipsHue::saveStates(nLights=" << nLights << "): got no valid state from light " + << getUrl(getRoute(lightIds.at(i))).toStdString() << std::endl; + break; + } + state["on"] = json["state"]["on"]; + if (json["state"]["on"] == true) { + state["xy"] = json["state"]["xy"]; + state["bri"] = json["state"]["bri"]; + } + // Determine the model id. + QString modelId = QString(writer.write(json["modelid"]).c_str()).trimmed().replace("\"", ""); + QString originalState = QString(writer.write(state).c_str()).trimmed(); + // Save state object. + lights.push_back(PhilipsHueLight(lightIds.at(i), originalState, modelId)); + } +} + +void LedDevicePhilipsHue::switchOn(unsigned int nLights) { + for (PhilipsHueLight light : lights) { + put(getStateRoute(light.id), "{\"on\": true}"); + } +} + +void LedDevicePhilipsHue::restoreStates() { + for (PhilipsHueLight light : lights) { + put(getStateRoute(light.id), light.originalState); + } + // Clear saved light states. + lights.clear(); +} + +bool LedDevicePhilipsHue::areStatesSaved() { + return !lights.empty(); +} diff --git a/libsrc/leddevice/LedDevicePhilipsHue.h b/libsrc/leddevice/LedDevicePhilipsHue.h index 5e5409b6..9f48a661 100755 --- a/libsrc/leddevice/LedDevicePhilipsHue.h +++ b/libsrc/leddevice/LedDevicePhilipsHue.h @@ -1,236 +1,236 @@ -#pragma once - -// STL includes -#include - -// Qt includes -#include -#include -#include -#include -// Leddevice includes -#include - -/** - * A color point in the color space of the hue system. - */ -struct CiColor { - /// X component. - float x; - /// Y component. - float y; - /// The brightness. - float bri; -}; - -bool operator==(CiColor p1, CiColor p2); -bool operator!=(CiColor p1, CiColor p2); - -/** - * Color triangle to define an available color space for the hue lamps. - */ -struct CiColorTriangle { - CiColor red, green, blue; -}; - -/** - * Simple class to hold the id, the latest color, the color space and the original state. - */ -class PhilipsHueLight { -public: - unsigned int id; - CiColor black; - CiColor color; - CiColorTriangle colorSpace; - QString originalState; - - /// - /// Constructs the light. - /// - /// @param id the light id - /// - /// @param originalState the json string of the original state - /// - /// @param modelId the model id of the hue lamp which is used to determine the color space - /// - PhilipsHueLight(unsigned int id, QString originalState, QString modelId); - - /// - /// Converts an RGB color to the Hue xy color space and brightness. - /// https://github.com/PhilipsHue/PhilipsHueSDK-iOS-OSX/blob/master/ApplicationDesignNotes/RGB%20to%20xy%20Color%20conversion.md - /// - /// @param red the red component in [0, 1] - /// - /// @param green the green component in [0, 1] - /// - /// @param blue the blue component in [0, 1] - /// - /// @return color point - /// - CiColor rgbToCiColor(float red, float green, float blue); - - /// - /// @param p the color point to check - /// - /// @return true if the color point is covered by the lamp color space - /// - bool isPointInLampsReach(CiColor p); - - /// - /// @param p1 point one - /// - /// @param p2 point tow - /// - /// @return the cross product between p1 and p2 - /// - float crossProduct(CiColor p1, CiColor p2); - - /// - /// @param a reference point one - /// - /// @param b reference point two - /// - /// @param p the point to which the closest point is to be found - /// - /// @return the closest color point of p to a and b - /// - CiColor getClosestPointToPoint(CiColor a, CiColor b, CiColor p); - - /// - /// @param p1 point one - /// - /// @param p2 point tow - /// - /// @return the distance between the two points - /// - float getDistanceBetweenTwoPoints(CiColor p1, CiColor p2); -}; - -/** - * Implementation for the Philips Hue system. - * - * To use set the device to "philipshue". - * Uses the official Philips Hue API (http://developers.meethue.com). - * Framegrabber must be limited to 10 Hz / numer of lights to avoid rate limitation by the hue bridge. - * Create a new API user name "newdeveloper" on the bridge (http://developers.meethue.com/gettingstarted.html) - * - * @author ntim (github), bimsarck (github) - */ -class LedDevicePhilipsHue: public QObject, public LedDevice { -Q_OBJECT -public: - /// - /// Constructs the device. - /// - /// @param output the ip address of the bridge - /// - /// @param username username of the hue bridge (default: newdeveloper) - /// - /// @param switchOffOnBlack kill lights for black (default: false) - /// - /// @param transitiontime the time duration a light change takes in multiples of 100 ms (default: 400 ms). - /// - /// @param lightIds light ids of the lights to control if not starting at one in ascending order. - /// - LedDevicePhilipsHue(const std::string& output, const std::string& username = "newdeveloper", bool switchOffOnBlack = - false, int transitiontime = 1, std::vector lightIds = std::vector()); - - /// - /// Destructor of this device - /// - virtual ~LedDevicePhilipsHue(); - - /// - /// Sends the given led-color values via put request to the hue system - /// - /// @param ledValues The color-value per led - /// - /// @return Zero on success else negative - /// - virtual int write(const std::vector & ledValues); - - /// Restores the original state of the leds. - virtual int switchOff(); - -private slots: - /// Restores the status of all lights. - void restoreStates(); - -private: - /// Array to save the lamps. - std::vector lights; - /// Ip address of the bridge - QString host; - /// User name for the API ("newdeveloper") - QString username; - /// QNetworkAccessManager object for sending requests. +#pragma once + +// STL includes +#include + +// Qt includes +#include +#include +#include +#include +// Leddevice includes +#include + +/** + * A color point in the color space of the hue system. + */ +struct CiColor { + /// X component. + float x; + /// Y component. + float y; + /// The brightness. + float bri; +}; + +bool operator==(CiColor p1, CiColor p2); +bool operator!=(CiColor p1, CiColor p2); + +/** + * Color triangle to define an available color space for the hue lamps. + */ +struct CiColorTriangle { + CiColor red, green, blue; +}; + +/** + * Simple class to hold the id, the latest color, the color space and the original state. + */ +class PhilipsHueLight { +public: + unsigned int id; + CiColor black; + CiColor color; + CiColorTriangle colorSpace; + QString originalState; + + /// + /// Constructs the light. + /// + /// @param id the light id + /// + /// @param originalState the json string of the original state + /// + /// @param modelId the model id of the hue lamp which is used to determine the color space + /// + PhilipsHueLight(unsigned int id, QString originalState, QString modelId); + + /// + /// Converts an RGB color to the Hue xy color space and brightness. + /// https://github.com/PhilipsHue/PhilipsHueSDK-iOS-OSX/blob/master/ApplicationDesignNotes/RGB%20to%20xy%20Color%20conversion.md + /// + /// @param red the red component in [0, 1] + /// + /// @param green the green component in [0, 1] + /// + /// @param blue the blue component in [0, 1] + /// + /// @return color point + /// + CiColor rgbToCiColor(float red, float green, float blue); + + /// + /// @param p the color point to check + /// + /// @return true if the color point is covered by the lamp color space + /// + bool isPointInLampsReach(CiColor p); + + /// + /// @param p1 point one + /// + /// @param p2 point tow + /// + /// @return the cross product between p1 and p2 + /// + float crossProduct(CiColor p1, CiColor p2); + + /// + /// @param a reference point one + /// + /// @param b reference point two + /// + /// @param p the point to which the closest point is to be found + /// + /// @return the closest color point of p to a and b + /// + CiColor getClosestPointToPoint(CiColor a, CiColor b, CiColor p); + + /// + /// @param p1 point one + /// + /// @param p2 point tow + /// + /// @return the distance between the two points + /// + float getDistanceBetweenTwoPoints(CiColor p1, CiColor p2); +}; + +/** + * Implementation for the Philips Hue system. + * + * To use set the device to "philipshue". + * Uses the official Philips Hue API (http://developers.meethue.com). + * Framegrabber must be limited to 10 Hz / numer of lights to avoid rate limitation by the hue bridge. + * Create a new API user name "newdeveloper" on the bridge (http://developers.meethue.com/gettingstarted.html) + * + * @author ntim (github), bimsarck (github) + */ +class LedDevicePhilipsHue: public QObject, public LedDevice { +Q_OBJECT +public: + /// + /// Constructs the device. + /// + /// @param output the ip address of the bridge + /// + /// @param username username of the hue bridge (default: newdeveloper) + /// + /// @param switchOffOnBlack kill lights for black (default: false) + /// + /// @param transitiontime the time duration a light change takes in multiples of 100 ms (default: 400 ms). + /// + /// @param lightIds light ids of the lights to control if not starting at one in ascending order. + /// + LedDevicePhilipsHue(const std::string& output, const std::string& username = "newdeveloper", bool switchOffOnBlack = + false, int transitiontime = 1, std::vector lightIds = std::vector()); + + /// + /// Destructor of this device + /// + virtual ~LedDevicePhilipsHue(); + + /// + /// Sends the given led-color values via put request to the hue system + /// + /// @param ledValues The color-value per led + /// + /// @return Zero on success else negative + /// + virtual int write(const std::vector & ledValues); + + /// Restores the original state of the leds. + virtual int switchOff(); + +private slots: + /// Restores the status of all lights. + void restoreStates(); + +private: + /// Array to save the lamps. + std::vector lights; + /// Ip address of the bridge + QString host; + /// User name for the API ("newdeveloper") + QString username; + /// QNetworkAccessManager object for sending requests. QNetworkAccessManager* manager; - /// Use timer to reset lights when we got into "GRABBINGMODE_OFF". - QTimer timer; - /// - bool switchOffOnBlack; - /// Transition time in multiples of 100 ms. - /// The default of the Hue lights will be 400 ms, but we want to have it snapier - int transitiontime; - /// Array of the light ids. - std::vector lightIds; - - /// - /// Sends a HTTP GET request (blocking). - /// - /// @param route the URI of the request - /// - /// @return response of the request - /// - QByteArray get(QString route); - - /// - /// Sends a HTTP PUT request (non-blocking). - /// - /// @param route the URI of the request - /// - /// @param content content of the request - /// - void put(QString route, QString content); - - /// - /// @param lightId the id of the hue light (starting from 1) - /// - /// @return the URI of the light state for PUT requests. - /// - QString getStateRoute(unsigned int lightId); - - /// - /// @param lightId the id of the hue light (starting from 1) - /// - /// @return the URI of the light for GET requests. - /// - QString getRoute(unsigned int lightId); - - /// - /// @param route - /// - /// @return the full URL of the request. - /// - QString getUrl(QString route); - - /// - /// Queries the status of all lights and saves it. - /// - /// @param nLights the number of lights - /// - void saveStates(unsigned int nLights); - - /// - /// Switches the leds on. - /// - /// @param nLights the number of lights - /// - void switchOn(unsigned int nLights); - - /// - /// @return true if light states have been saved. - /// - bool areStatesSaved(); - -}; + /// Use timer to reset lights when we got into "GRABBINGMODE_OFF". + QTimer timer; + /// + bool switchOffOnBlack; + /// Transition time in multiples of 100 ms. + /// The default of the Hue lights will be 400 ms, but we want to have it snapier + int transitiontime; + /// Array of the light ids. + std::vector lightIds; + + /// + /// Sends a HTTP GET request (blocking). + /// + /// @param route the URI of the request + /// + /// @return response of the request + /// + QByteArray get(QString route); + + /// + /// Sends a HTTP PUT request (non-blocking). + /// + /// @param route the URI of the request + /// + /// @param content content of the request + /// + void put(QString route, QString content); + + /// + /// @param lightId the id of the hue light (starting from 1) + /// + /// @return the URI of the light state for PUT requests. + /// + QString getStateRoute(unsigned int lightId); + + /// + /// @param lightId the id of the hue light (starting from 1) + /// + /// @return the URI of the light for GET requests. + /// + QString getRoute(unsigned int lightId); + + /// + /// @param route + /// + /// @return the full URL of the request. + /// + QString getUrl(QString route); + + /// + /// Queries the status of all lights and saves it. + /// + /// @param nLights the number of lights + /// + void saveStates(unsigned int nLights); + + /// + /// Switches the leds on. + /// + /// @param nLights the number of lights + /// + void switchOn(unsigned int nLights); + + /// + /// @return true if light states have been saved. + /// + bool areStatesSaved(); + +}; diff --git a/libsrc/leddevice/LedDeviceTpm2.cpp b/libsrc/leddevice/LedDeviceTpm2.cpp index c865ef96..c6054038 100644 --- a/libsrc/leddevice/LedDeviceTpm2.cpp +++ b/libsrc/leddevice/LedDeviceTpm2.cpp @@ -16,18 +16,18 @@ LedDeviceTpm2::LedDeviceTpm2(const std::string& outputDevice, const unsigned bau int LedDeviceTpm2::write(const std::vector &ledValues) { - if (_ledBuffer.size() == 0) - { - _ledBuffer.resize(5 + 3*ledValues.size()); - _ledBuffer[0] = 0xC9; // block-start byte - _ledBuffer[1] = 0xDA; // DATA frame - _ledBuffer[2] = ((3 * ledValues.size()) >> 8) & 0xFF; // frame size high byte - _ledBuffer[3] = (3 * ledValues.size()) & 0xFF; // frame size low byte - _ledBuffer.back() = 0x36; // block-end byte - } + if (_ledBuffer.size() == 0) + { + _ledBuffer.resize(5 + 3*ledValues.size()); + _ledBuffer[0] = 0xC9; // block-start byte + _ledBuffer[1] = 0xDA; // DATA frame + _ledBuffer[2] = ((3 * ledValues.size()) >> 8) & 0xFF; // frame size high byte + _ledBuffer[3] = (3 * ledValues.size()) & 0xFF; // frame size low byte + _ledBuffer.back() = 0x36; // block-end byte + } - // write data - memcpy(4 + _ledBuffer.data(), ledValues.data(), ledValues.size() * 3); + // write data + memcpy(4 + _ledBuffer.data(), ledValues.data(), ledValues.size() * 3); return writeBytes(_ledBuffer.size(), _ledBuffer.data()); } diff --git a/libsrc/leddevice/LedDeviceUdp.cpp b/libsrc/leddevice/LedDeviceUdp.cpp index 48c2a8d7..71078ed0 100644 --- a/libsrc/leddevice/LedDeviceUdp.cpp +++ b/libsrc/leddevice/LedDeviceUdp.cpp @@ -25,55 +25,54 @@ LedDeviceUdp::LedDeviceUdp(const std::string& output, const unsigned baudrate, c //LedDeviceUdp::LedDeviceUdp(const std::string& output, const unsigned baudrate) : // _ofs(output.empty()?"/home/pi/LedDevice.out":output.c_str()) { - - std::string hostname; - std::string port; - ledprotocol = protocol; - leds_per_pkt = ((maxPacket-4)/3); - if (leds_per_pkt <= 0) { - leds_per_pkt = 200; - } + std::string hostname; + std::string port; + ledprotocol = protocol; + leds_per_pkt = ((maxPacket-4)/3); + if (leds_per_pkt <= 0) { + leds_per_pkt = 200; + } //printf ("leds_per_pkt is %d\n", leds_per_pkt); - int got_colon=0; - for (unsigned int i=0; iai_next) { - if ((sockfd = socket(p->ai_family, p->ai_socktype, - p->ai_protocol)) == -1) { - perror("talker: socket"); - continue; - } + // loop through all the results and make a socket + for(p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + perror("talker: socket"); + continue; + } - break; - } + break; + } - if (p == NULL) { - fprintf(stderr, "talker: failed to create socket\n"); - assert(p!=NULL); - } + if (p == NULL) { + fprintf(stderr, "talker: failed to create socket\n"); + assert(p!=NULL); + } } LedDeviceUdp::~LedDeviceUdp() @@ -99,7 +98,7 @@ int LedDeviceUdp::write(const std::vector & ledValues) udpbuffer[i++] = color.green; udpbuffer[i++] = color.blue; } - //printf ("c.red %d sz c.red %d\n", color.red, sizeof(color.red)); + //printf ("c.red %d sz c.red %d\n", color.red, sizeof(color.red)); } sendto(sockfd, udpbuffer, i, 0, p->ai_addr, p->ai_addrlen); } @@ -153,7 +152,6 @@ int LedDeviceUdp::write(const std::vector & ledValues) udpbuffer[udpPtr++] = ledCtr%256; // low byte } } - } if (ledprotocol == 3) { @@ -172,7 +170,6 @@ int LedDeviceUdp::write(const std::vector & ledValues) udpbuffer[udpPtr++] = fragment_number++; udpbuffer[udpPtr++] = fragments; - for (const ColorRgb& color : ledValues) { if (udpPtr<4090) { @@ -201,6 +198,6 @@ int LedDeviceUdp::write(const std::vector & ledValues) int LedDeviceUdp::switchOff() { -// return write(std::vector(mLedCount, ColorRgb{0,0,0})); +// return write(std::vector(mLedCount, ColorRgb{0,0,0})); return 0; } diff --git a/libsrc/leddevice/LedDeviceWS2812b.h b/libsrc/leddevice/LedDeviceWS2812b.h index d945e20d..1e19cf73 100644 --- a/libsrc/leddevice/LedDeviceWS2812b.h +++ b/libsrc/leddevice/LedDeviceWS2812b.h @@ -86,17 +86,17 @@ // Raspberry Pi low-level peripherals: // http://elinux.org/RPi_Low-level_peripherals // -// Richard Hirst's nice, clean code: -// https://github.com/richardghirst/PiBits/blob/master/PiFmDma/PiFmDma.c +// Richard Hirst's nice, clean code: +// https://github.com/richardghirst/PiBits/blob/master/PiFmDma/PiFmDma.c // // PWM clock register: // http://www.raspberrypi.org/forums/viewtopic.php?t=8467&p=124620 // -// Simple (because it's in assembly) PWM+DMA setup: -// https://github.com/mikedurso/rpi-projects/blob/master/asm-nyancat/rpi-nyancat.s +// Simple (because it's in assembly) PWM+DMA setup: +// https://github.com/mikedurso/rpi-projects/blob/master/asm-nyancat/rpi-nyancat.s // -// Adafruit's NeoPixel driver: -// https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp +// Adafruit's NeoPixel driver: +// https://github.com/adafruit/Adafruit_NeoPixel/blob/master/Adafruit_NeoPixel.cpp // Hyperion includes #include diff --git a/libsrc/protoserver/CMakeLists.txt b/libsrc/protoserver/CMakeLists.txt index 769cc807..5d8737d7 100644 --- a/libsrc/protoserver/CMakeLists.txt +++ b/libsrc/protoserver/CMakeLists.txt @@ -1,61 +1,61 @@ - -# Define the current source locations -set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/protoserver) -set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/protoserver) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ${PROTOBUF_INCLUDE_DIRS} -) - -# Group the headers that go through the MOC compiler -set(ProtoServer_QT_HEADERS - ${CURRENT_HEADER_DIR}/ProtoServer.h - ${CURRENT_HEADER_DIR}/ProtoConnection.h - ${CURRENT_SOURCE_DIR}/ProtoClientConnection.h - ${CURRENT_HEADER_DIR}/ProtoConnectionWrapper.h -) - -set(ProtoServer_HEADERS -) - -set(ProtoServer_SOURCES - ${CURRENT_SOURCE_DIR}/ProtoServer.cpp - ${CURRENT_SOURCE_DIR}/ProtoClientConnection.cpp - ${CURRENT_SOURCE_DIR}/ProtoConnection.cpp - ${CURRENT_SOURCE_DIR}/ProtoConnectionWrapper.cpp -) - -set(ProtoServer_PROTOS - ${CURRENT_SOURCE_DIR}/message.proto -) - -protobuf_generate_cpp(ProtoServer_PROTO_SRCS ProtoServer_PROTO_HDRS - ${ProtoServer_PROTOS} -) - -if(ENABLE_QT5) -qt5_wrap_cpp(ProtoServer_HEADERS_MOC ${ProtoServer_QT_HEADERS}) -else(ENABLE_QT5) -qt4_wrap_cpp(ProtoServer_HEADERS_MOC ${ProtoServer_QT_HEADERS}) -endif(ENABLE_QT5) - -add_library(protoserver - ${ProtoServer_HEADERS} - ${ProtoServer_QT_HEADERS} - ${ProtoServer_SOURCES} - ${ProtoServer_HEADERS_MOC} - ${ProtoServer_PROTOS} - ${ProtoServer_PROTO_SRCS} - ${ProtoServer_PROTO_HDRS} -) -if(ENABLE_QT5) -qt5_use_modules(protoserver Widgets) -endif(ENABLE_QT5) - -target_link_libraries(protoserver - hyperion - hyperion-utils - protobuf - ${QT_LIBRARIES} -) + +# Define the current source locations +set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/protoserver) +set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/protoserver) + +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${PROTOBUF_INCLUDE_DIRS} +) + +# Group the headers that go through the MOC compiler +set(ProtoServer_QT_HEADERS + ${CURRENT_HEADER_DIR}/ProtoServer.h + ${CURRENT_HEADER_DIR}/ProtoConnection.h + ${CURRENT_SOURCE_DIR}/ProtoClientConnection.h + ${CURRENT_HEADER_DIR}/ProtoConnectionWrapper.h +) + +set(ProtoServer_HEADERS +) + +set(ProtoServer_SOURCES + ${CURRENT_SOURCE_DIR}/ProtoServer.cpp + ${CURRENT_SOURCE_DIR}/ProtoClientConnection.cpp + ${CURRENT_SOURCE_DIR}/ProtoConnection.cpp + ${CURRENT_SOURCE_DIR}/ProtoConnectionWrapper.cpp +) + +set(ProtoServer_PROTOS + ${CURRENT_SOURCE_DIR}/message.proto +) + +protobuf_generate_cpp(ProtoServer_PROTO_SRCS ProtoServer_PROTO_HDRS + ${ProtoServer_PROTOS} +) + +if(ENABLE_QT5) + qt5_wrap_cpp(ProtoServer_HEADERS_MOC ${ProtoServer_QT_HEADERS}) +else() + qt4_wrap_cpp(ProtoServer_HEADERS_MOC ${ProtoServer_QT_HEADERS}) +endif() + +add_library(protoserver + ${ProtoServer_HEADERS} + ${ProtoServer_QT_HEADERS} + ${ProtoServer_SOURCES} + ${ProtoServer_HEADERS_MOC} + ${ProtoServer_PROTOS} + ${ProtoServer_PROTO_SRCS} + ${ProtoServer_PROTO_HDRS} +) +if(ENABLE_QT5) + qt5_use_modules(protoserver Widgets) +endif() + +target_link_libraries(protoserver + hyperion + hyperion-utils + protobuf + ${QT_LIBRARIES} +) diff --git a/libsrc/protoserver/ProtoConnection.cpp b/libsrc/protoserver/ProtoConnection.cpp index b48c3466..d4850d48 100644 --- a/libsrc/protoserver/ProtoConnection.cpp +++ b/libsrc/protoserver/ProtoConnection.cpp @@ -8,207 +8,207 @@ #include "protoserver/ProtoConnection.h" ProtoConnection::ProtoConnection(const std::string & a) : - _socket(), - _skipReply(false), - _prevSocketState(QAbstractSocket::UnconnectedState) + _socket(), + _skipReply(false), + _prevSocketState(QAbstractSocket::UnconnectedState) { - QString address(a.c_str()); - QStringList parts = address.split(":"); - if (parts.size() != 2) - { - throw std::runtime_error(QString("PROTOCONNECTION ERROR: Wrong address: Unable to parse address (%1)").arg(address).toStdString()); - } - _host = parts[0]; + QString address(a.c_str()); + QStringList parts = address.split(":"); + if (parts.size() != 2) + { + throw std::runtime_error(QString("PROTOCONNECTION ERROR: Wrong address: Unable to parse address (%1)").arg(address).toStdString()); + } + _host = parts[0]; - bool ok; - _port = parts[1].toUShort(&ok); - if (!ok) - { - throw std::runtime_error(QString("PROTOCONNECTION ERROR: Wrong port: Unable to parse the port number (%1)").arg(parts[1]).toStdString()); - } + bool ok; + _port = parts[1].toUShort(&ok); + if (!ok) + { + throw std::runtime_error(QString("PROTOCONNECTION ERROR: Wrong port: Unable to parse the port number (%1)").arg(parts[1]).toStdString()); + } - // try to connect to host - std::cout << "PROTOCONNECTION INFO: Connecting to Hyperion: " << _host.toStdString() << ":" << _port << std::endl; - connectToHost(); + // try to connect to host + std::cout << "PROTOCONNECTION INFO: Connecting to Hyperion: " << _host.toStdString() << ":" << _port << std::endl; + connectToHost(); - // start the connection timer - _timer.setInterval(5000); - _timer.setSingleShot(false); + // start the connection timer + _timer.setInterval(5000); + _timer.setSingleShot(false); - connect(&_timer,SIGNAL(timeout()), this, SLOT(connectToHost()) ); - _timer.start(); + connect(&_timer,SIGNAL(timeout()), this, SLOT(connectToHost()) ); + _timer.start(); } ProtoConnection::~ProtoConnection() { - _timer.stop(); - _socket.close(); + _timer.stop(); + _socket.close(); } void ProtoConnection::setSkipReply(bool skip) { - _skipReply = skip; + _skipReply = skip; } void ProtoConnection::setColor(const ColorRgb & color, int priority, int duration) { - proto::HyperionRequest request; - request.set_command(proto::HyperionRequest::COLOR); - proto::ColorRequest * colorRequest = request.MutableExtension(proto::ColorRequest::colorRequest); - colorRequest->set_rgbcolor((color.red << 16) | (color.green << 8) | color.blue); - colorRequest->set_priority(priority); - colorRequest->set_duration(duration); + proto::HyperionRequest request; + request.set_command(proto::HyperionRequest::COLOR); + proto::ColorRequest * colorRequest = request.MutableExtension(proto::ColorRequest::colorRequest); + colorRequest->set_rgbcolor((color.red << 16) | (color.green << 8) | color.blue); + colorRequest->set_priority(priority); + colorRequest->set_duration(duration); - // send command message - sendMessage(request); + // send command message + sendMessage(request); } void ProtoConnection::setImage(const Image &image, int priority, int duration) { - proto::HyperionRequest request; - request.set_command(proto::HyperionRequest::IMAGE); - proto::ImageRequest * imageRequest = request.MutableExtension(proto::ImageRequest::imageRequest); - imageRequest->set_imagedata(image.memptr(), image.width() * image.height() * 3); - imageRequest->set_imagewidth(image.width()); - imageRequest->set_imageheight(image.height()); - imageRequest->set_priority(priority); - imageRequest->set_duration(duration); + proto::HyperionRequest request; + request.set_command(proto::HyperionRequest::IMAGE); + proto::ImageRequest * imageRequest = request.MutableExtension(proto::ImageRequest::imageRequest); + imageRequest->set_imagedata(image.memptr(), image.width() * image.height() * 3); + imageRequest->set_imagewidth(image.width()); + imageRequest->set_imageheight(image.height()); + imageRequest->set_priority(priority); + imageRequest->set_duration(duration); - // send command message - sendMessage(request); + // send command message + sendMessage(request); } void ProtoConnection::clear(int priority) { - proto::HyperionRequest request; - request.set_command(proto::HyperionRequest::CLEAR); - proto::ClearRequest * clearRequest = request.MutableExtension(proto::ClearRequest::clearRequest); - clearRequest->set_priority(priority); + proto::HyperionRequest request; + request.set_command(proto::HyperionRequest::CLEAR); + proto::ClearRequest * clearRequest = request.MutableExtension(proto::ClearRequest::clearRequest); + clearRequest->set_priority(priority); - // send command message - sendMessage(request); + // send command message + sendMessage(request); } void ProtoConnection::clearAll() { - proto::HyperionRequest request; - request.set_command(proto::HyperionRequest::CLEARALL); + proto::HyperionRequest request; + request.set_command(proto::HyperionRequest::CLEARALL); - // send command message - sendMessage(request); + // send command message + sendMessage(request); } void ProtoConnection::connectToHost() { - // try connection only when - if (_socket.state() == QAbstractSocket::UnconnectedState) - { - _socket.connectToHost(_host, _port); - //_socket.waitForConnected(1000); - } + // try connection only when + if (_socket.state() == QAbstractSocket::UnconnectedState) + { + _socket.connectToHost(_host, _port); + //_socket.waitForConnected(1000); + } } void ProtoConnection::sendMessage(const proto::HyperionRequest &message) { - // print out connection message only when state is changed - if (_socket.state() != _prevSocketState ) - { - switch (_socket.state() ) - { - case QAbstractSocket::UnconnectedState: - std::cout << "PROTOCONNECTION INFO: No connection to Hyperion: " << _host.toStdString() << ":" << _port << std::endl; - break; + // print out connection message only when state is changed + if (_socket.state() != _prevSocketState ) + { + switch (_socket.state() ) + { + case QAbstractSocket::UnconnectedState: + std::cout << "PROTOCONNECTION INFO: No connection to Hyperion: " << _host.toStdString() << ":" << _port << std::endl; + break; - case QAbstractSocket::ConnectedState: - std::cout << "PROTOCONNECTION INFO: Connected to Hyperion: " << _host.toStdString() << ":" << _port << std::endl; - break; + case QAbstractSocket::ConnectedState: + std::cout << "PROTOCONNECTION INFO: Connected to Hyperion: " << _host.toStdString() << ":" << _port << std::endl; + break; - default: - //std::cout << "Connecting to Hyperion: " << _host.toStdString() << ":" << _port << std::endl; - break; - } - _prevSocketState = _socket.state(); - } + default: + //std::cout << "Connecting to Hyperion: " << _host.toStdString() << ":" << _port << std::endl; + break; + } + _prevSocketState = _socket.state(); + } - if (_socket.state() != QAbstractSocket::ConnectedState) - { - return; - } + if (_socket.state() != QAbstractSocket::ConnectedState) + { + return; + } - // We only get here if we are connected + // We only get here if we are connected - // serialize message (FastWriter already appends a newline) - std::string serializedMessage = message.SerializeAsString(); + // serialize message (FastWriter already appends a newline) + std::string serializedMessage = message.SerializeAsString(); - int length = serializedMessage.size(); - const uint8_t header[] = { - uint8_t((length >> 24) & 0xFF), - uint8_t((length >> 16) & 0xFF), - uint8_t((length >> 8) & 0xFF), - uint8_t((length ) & 0xFF)}; + int length = serializedMessage.size(); + const uint8_t header[] = { + uint8_t((length >> 24) & 0xFF), + uint8_t((length >> 16) & 0xFF), + uint8_t((length >> 8) & 0xFF), + uint8_t((length ) & 0xFF)}; - // write message - int count = 0; - count += _socket.write(reinterpret_cast(header), 4); - count += _socket.write(reinterpret_cast(serializedMessage.data()), length); - if (!_socket.waitForBytesWritten()) - { - std::cerr << "PROTOCONNECTION ERROR: Error while writing data to host" << std::endl; - return; - } + // write message + int count = 0; + count += _socket.write(reinterpret_cast(header), 4); + count += _socket.write(reinterpret_cast(serializedMessage.data()), length); + if (!_socket.waitForBytesWritten()) + { + std::cerr << "PROTOCONNECTION ERROR: Error while writing data to host" << std::endl; + return; + } - if (!_skipReply) - { - // read reply data - QByteArray serializedReply; - length = -1; - while (length < 0 && serializedReply.size() < length+4) - { - // receive reply - if (!_socket.waitForReadyRead()) - { - std::cerr << "PROTOCONNECTION ERROR: Error while reading data from host" << std::endl; - return; - } + if (!_skipReply) + { + // read reply data + QByteArray serializedReply; + length = -1; + while (length < 0 && serializedReply.size() < length+4) + { + // receive reply + if (!_socket.waitForReadyRead()) + { + std::cerr << "PROTOCONNECTION ERROR: Error while reading data from host" << std::endl; + return; + } - serializedReply += _socket.readAll(); + serializedReply += _socket.readAll(); - if (length < 0 && serializedReply.size() >= 4) - { - // read the message size - length = - ((serializedReply[0]<<24) & 0xFF000000) | - ((serializedReply[1]<<16) & 0x00FF0000) | - ((serializedReply[2]<< 8) & 0x0000FF00) | - ((serializedReply[3] ) & 0x000000FF); - } - } + if (length < 0 && serializedReply.size() >= 4) + { + // read the message size + length = + ((serializedReply[0]<<24) & 0xFF000000) | + ((serializedReply[1]<<16) & 0x00FF0000) | + ((serializedReply[2]<< 8) & 0x0000FF00) | + ((serializedReply[3] ) & 0x000000FF); + } + } - // parse reply data - proto::HyperionReply reply; - reply.ParseFromArray(serializedReply.constData()+4, length); + // parse reply data + proto::HyperionReply reply; + reply.ParseFromArray(serializedReply.constData()+4, length); - // parse reply message - parseReply(reply); - } + // parse reply message + parseReply(reply); + } } bool ProtoConnection::parseReply(const proto::HyperionReply &reply) { - bool success = false; + bool success = false; - if (!reply.success()) - { - if (reply.has_error()) - { - throw std::runtime_error("PROTOCONNECTION ERROR: " + reply.error()); - } - else - { - throw std::runtime_error("PROTOCONNECTION ERROR: No error info"); - } - } + if (!reply.success()) + { + if (reply.has_error()) + { + throw std::runtime_error("PROTOCONNECTION ERROR: " + reply.error()); + } + else + { + throw std::runtime_error("PROTOCONNECTION ERROR: No error info"); + } + } - return success; + return success; } diff --git a/libsrc/protoserver/ProtoConnectionWrapper.cpp b/libsrc/protoserver/ProtoConnectionWrapper.cpp index 7cf88f43..e1c5b8d4 100644 --- a/libsrc/protoserver/ProtoConnectionWrapper.cpp +++ b/libsrc/protoserver/ProtoConnectionWrapper.cpp @@ -2,11 +2,11 @@ #include "protoserver/ProtoConnectionWrapper.h" ProtoConnectionWrapper::ProtoConnectionWrapper(const std::string & address, int priority, int duration_ms, bool skipProtoReply) : - _priority(priority), - _duration_ms(duration_ms), - _connection(address) + _priority(priority), + _duration_ms(duration_ms), + _connection(address) { - _connection.setSkipReply(skipProtoReply); + _connection.setSkipReply(skipProtoReply); } ProtoConnectionWrapper::~ProtoConnectionWrapper() @@ -15,5 +15,5 @@ ProtoConnectionWrapper::~ProtoConnectionWrapper() void ProtoConnectionWrapper::receiveImage(const Image & image) { - _connection.setImage(image, _priority, _duration_ms); + _connection.setImage(image, _priority, _duration_ms); } diff --git a/libsrc/utils/CMakeLists.txt b/libsrc/utils/CMakeLists.txt index 5978c2c1..1b9e2982 100644 --- a/libsrc/utils/CMakeLists.txt +++ b/libsrc/utils/CMakeLists.txt @@ -1,41 +1,41 @@ - -# Define the current source locations -SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/utils) -SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/utils) - -add_library(hyperion-utils - ${CURRENT_HEADER_DIR}/ColorArgb.h - ${CURRENT_SOURCE_DIR}/ColorArgb.cpp - ${CURRENT_HEADER_DIR}/ColorBgr.h - ${CURRENT_SOURCE_DIR}/ColorBgr.cpp - ${CURRENT_HEADER_DIR}/ColorRgb.h - ${CURRENT_SOURCE_DIR}/ColorRgb.cpp - ${CURRENT_HEADER_DIR}/ColorRgba.h - ${CURRENT_SOURCE_DIR}/ColorRgba.cpp - ${CURRENT_HEADER_DIR}/Image.h - ${CURRENT_HEADER_DIR}/Sleep.h - - ${CURRENT_HEADER_DIR}/PixelFormat.h - ${CURRENT_HEADER_DIR}/VideoMode.h - - ${CURRENT_HEADER_DIR}/ImageResampler.h - ${CURRENT_SOURCE_DIR}/ImageResampler.cpp - - ${CURRENT_HEADER_DIR}/HsvTransform.h - ${CURRENT_SOURCE_DIR}/HsvTransform.cpp - ${CURRENT_HEADER_DIR}/HslTransform.h - ${CURRENT_SOURCE_DIR}/HslTransform.cpp - ${CURRENT_HEADER_DIR}/RgbChannelTransform.h - ${CURRENT_SOURCE_DIR}/RgbChannelTransform.cpp - ${CURRENT_HEADER_DIR}/RgbChannelCorrection.h - ${CURRENT_SOURCE_DIR}/RgbChannelCorrection.cpp - ${CURRENT_HEADER_DIR}/RgbChannelAdjustment.h - ${CURRENT_SOURCE_DIR}/RgbChannelAdjustment.cpp - - ${CURRENT_HEADER_DIR}/jsonschema/JsonFactory.h - ${CURRENT_HEADER_DIR}/jsonschema/JsonSchemaChecker.h - ${CURRENT_SOURCE_DIR}/jsonschema/JsonSchemaChecker.cpp -) - -target_link_libraries(hyperion-utils - jsoncpp) + +# Define the current source locations +SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/utils) +SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/utils) + +add_library(hyperion-utils + ${CURRENT_HEADER_DIR}/ColorArgb.h + ${CURRENT_SOURCE_DIR}/ColorArgb.cpp + ${CURRENT_HEADER_DIR}/ColorBgr.h + ${CURRENT_SOURCE_DIR}/ColorBgr.cpp + ${CURRENT_HEADER_DIR}/ColorRgb.h + ${CURRENT_SOURCE_DIR}/ColorRgb.cpp + ${CURRENT_HEADER_DIR}/ColorRgba.h + ${CURRENT_SOURCE_DIR}/ColorRgba.cpp + ${CURRENT_HEADER_DIR}/Image.h + ${CURRENT_HEADER_DIR}/Sleep.h + + ${CURRENT_HEADER_DIR}/PixelFormat.h + ${CURRENT_HEADER_DIR}/VideoMode.h + + ${CURRENT_HEADER_DIR}/ImageResampler.h + ${CURRENT_SOURCE_DIR}/ImageResampler.cpp + + ${CURRENT_HEADER_DIR}/HsvTransform.h + ${CURRENT_SOURCE_DIR}/HsvTransform.cpp + ${CURRENT_HEADER_DIR}/HslTransform.h + ${CURRENT_SOURCE_DIR}/HslTransform.cpp + ${CURRENT_HEADER_DIR}/RgbChannelTransform.h + ${CURRENT_SOURCE_DIR}/RgbChannelTransform.cpp + ${CURRENT_HEADER_DIR}/RgbChannelCorrection.h + ${CURRENT_SOURCE_DIR}/RgbChannelCorrection.cpp + ${CURRENT_HEADER_DIR}/RgbChannelAdjustment.h + ${CURRENT_SOURCE_DIR}/RgbChannelAdjustment.cpp + + ${CURRENT_HEADER_DIR}/jsonschema/JsonFactory.h + ${CURRENT_HEADER_DIR}/jsonschema/JsonSchemaChecker.h + ${CURRENT_SOURCE_DIR}/jsonschema/JsonSchemaChecker.cpp +) + +target_link_libraries(hyperion-utils + jsoncpp) diff --git a/libsrc/utils/jsonschema/JsonSchemaChecker.cpp b/libsrc/utils/jsonschema/JsonSchemaChecker.cpp index 3411d84d..9a6a6116 100644 --- a/libsrc/utils/jsonschema/JsonSchemaChecker.cpp +++ b/libsrc/utils/jsonschema/JsonSchemaChecker.cpp @@ -1,464 +1,464 @@ -// stdlib includes -#include -#include -#include -#include - -// Utils-Jsonschema includes -#include - -JsonSchemaChecker::JsonSchemaChecker() -{ - // empty -} - -JsonSchemaChecker::~JsonSchemaChecker() -{ - // empty -} - -bool JsonSchemaChecker::setSchema(const Json::Value & schema) -{ - _schema = schema; - - // TODO: check the schema - - return true; -} - -bool JsonSchemaChecker::validate(const Json::Value & value) -{ - // initialize state - _error = false; - _messages.clear(); - _currentPath.clear(); - _currentPath.push_back("[root]"); - _references.clear(); - - // collect dependencies - collectDependencies(value, _schema); - - // validate - validate(value, _schema); - - return !_error; -} - -void JsonSchemaChecker::collectDependencies(const Json::Value & value, const Json::Value &schema) -{ - assert (schema.isObject()); - - // check if id is present - if (schema.isMember("id")) - { - // strore reference - assert (schema["id"].isString()); - std::ostringstream ref; - ref << "$(" << schema["id"].asString() << ")"; - _references[ref.str()] = &value; - } - - // check the current json value - if (schema.isMember("properties")) - { - const Json::Value & properties = schema["properties"]; - assert(properties.isObject()); - - for (Json::Value::const_iterator j = properties.begin(); j != properties.end(); ++j) - { - std::string property = j.memberName(); - if (value.isMember(property)) - { - collectDependencies(value[property], properties[property]); - } - } - } -} - -void JsonSchemaChecker::validate(const Json::Value & value, const Json::Value &schema) -{ - assert (schema.isObject()); - - // check the current json value - for (Json::Value::const_iterator i = schema.begin(); i != schema.end(); ++i) - { - std::string attribute = i.memberName(); - const Json::Value & attributeValue = *i; - - if (attribute == "type") - checkType(value, attributeValue); - else if (attribute == "properties") - checkProperties(value, attributeValue); - else if (attribute == "additionalProperties") - { - // ignore the properties which are handled by the properties attribute (if present) - Json::Value::Members ignoredProperties; - if (schema.isMember("properties")) { - const Json::Value & props = schema["properties"]; - ignoredProperties = props.getMemberNames(); - } - - checkAdditionalProperties(value, attributeValue, ignoredProperties); - } - else if (attribute == "dependencies") - checkDependencies(value, attributeValue); - else if (attribute == "minimum") - checkMinimum(value, attributeValue); - else if (attribute == "maximum") - checkMaximum(value, attributeValue); - else if (attribute == "items") - checkItems(value, attributeValue); - else if (attribute == "minItems") - checkMinItems(value, attributeValue); - else if (attribute == "maxItems") - checkMaxItems(value, attributeValue); - else if (attribute == "uniqueItems") - checkUniqueItems(value, attributeValue); - else if (attribute == "enum") - checkEnum(value, attributeValue); - else if (attribute == "required") - ; // nothing to do. value is present so always oke - else if (attribute == "id") - ; // references have already been collected - else - { - // no check function defined for this attribute - setMessage(std::string("No check function defined for attribute ") + attribute); - continue; - } - } -} - -void JsonSchemaChecker::setMessage(const std::string & message) -{ - std::ostringstream oss; - std::copy(_currentPath.begin(), _currentPath.end(), std::ostream_iterator(oss, "")); - oss << ": " << message; - _messages.push_back(oss.str()); -} - -const std::list & JsonSchemaChecker::getMessages() const -{ - return _messages; -} - -void JsonSchemaChecker::checkType(const Json::Value & value, const Json::Value & schema) -{ - assert(schema.isString()); - - std::string type = schema.asString(); - bool wrongType = false; - if (type == "string") - wrongType = !value.isString(); - else if (type == "number") - wrongType = !value.isNumeric(); - else if (type == "integer") - wrongType = !value.isIntegral(); - else if (type == "double") - wrongType = !value.isDouble(); - else if (type == "boolean") - wrongType = !value.isBool(); - else if (type == "object") - wrongType = !value.isObject(); - else if (type == "array") - wrongType = !value.isArray(); - else if (type == "null") - wrongType = !value.isNull(); - else if (type == "enum") - wrongType = !value.isString(); - else if (type == "any") - wrongType = false; -// else -// assert(false); - - if (wrongType) - { - _error = true; - setMessage(type + " expected"); - } -} - -void JsonSchemaChecker::checkProperties(const Json::Value & value, const Json::Value & schema) -{ - assert(schema.isObject()); - - if (!value.isObject()) - { - _error = true; - setMessage("properies attribute is only valid for objects"); - return; - } - - for (Json::Value::const_iterator i = schema.begin(); i != schema.end(); ++i) - { - std::string property = i.memberName(); - const Json::Value & propertyValue = *i; - - assert(propertyValue.isObject()); - - _currentPath.push_back(std::string(".") + property); - if (value.isMember(property)) - { - validate(value[property], propertyValue); - } - else if (propertyValue.get("required", false).asBool()) - { - _error = true; - setMessage("missing member"); - } - _currentPath.pop_back(); - } -} - -void JsonSchemaChecker::checkAdditionalProperties(const Json::Value & value, const Json::Value & schema, const Json::Value::Members & ignoredProperties) -{ - if (!value.isObject()) - { - _error = true; - setMessage("additional properies attribute is only valid for objects"); - return; - } - - for (Json::Value::const_iterator i = value.begin(); i != value.end(); ++i) - { - std::string property = i.memberName(); - if (std::find(ignoredProperties.begin(), ignoredProperties.end(), property) == ignoredProperties.end()) - { - // property has no property definition. check against the definition for additional properties - _currentPath.push_back(std::string(".") + property); - if (schema.isBool()) - { - if (schema.asBool() == false) - { - _error = true; - setMessage("no schema definition"); - } - } - else - { - validate(value[property], schema); - } - _currentPath.pop_back(); - } - } -} - -void JsonSchemaChecker::checkDependencies(const Json::Value & value, const Json::Value & schemaLink) -{ - if (!value.isObject()) - { - _error = true; - setMessage("dependencies attribute is only valid for objects"); - return; - } - - assert(schemaLink.isString()); - std::map::iterator iter = _references.find(schemaLink.asString()); - if (iter == _references.end()) - { - _error = true; - std::ostringstream oss; - oss << "reference " << schemaLink.asString() << " could not be resolved"; - setMessage(oss.str()); - return; - } - const Json::Value & schema = *(iter->second); - - std::list requiredProperties; - if (schema.isString()) - { - requiredProperties.push_back(schema.asString()); - } - else if (schema.isArray()) - { - for (Json::UInt i = 0; i < schema.size(); ++i) - { - assert(schema[i].isString()); - requiredProperties.push_back(schema[i].asString()); - } - } - else - { - _error = true; - std::ostringstream oss; - oss << "Exepected reference " << schemaLink.asString() << " to resolve to a string or array"; - setMessage(oss.str()); - return; - } - - for (std::list::const_iterator i = requiredProperties.begin(); i != requiredProperties.end(); ++i) - { - if (!value.isMember(*i)) - { - _error = true; - std::ostringstream oss; - oss << "missing member " << *i; - setMessage(oss.str()); - } - } -} - -void JsonSchemaChecker::checkMinimum(const Json::Value & value, const Json::Value & schema) -{ - assert(schema.isNumeric()); - - if (!value.isNumeric()) - { - // only for numeric - _error = true; - setMessage("minimum check only for numeric fields"); - return; - } - - if (value.asDouble() < schema.asDouble()) - { - _error = true; - std::ostringstream oss; - oss << "value is too small (minimum=" << schema.asDouble() << ")"; - setMessage(oss.str()); - } -} - -void JsonSchemaChecker::checkMaximum(const Json::Value & value, const Json::Value & schema) -{ - assert(schema.isNumeric()); - - if (!value.isNumeric()) - { - // only for numeric - _error = true; - setMessage("maximum check only for numeric fields"); - return; - } - - if (value.asDouble() > schema.asDouble()) - { - _error = true; - std::ostringstream oss; - oss << "value is too large (maximum=" << schema.asDouble() << ")"; - setMessage(oss.str()); - } -} - -void JsonSchemaChecker::checkItems(const Json::Value & value, const Json::Value & schema) -{ - assert(schema.isObject()); - - if (!value.isArray()) - { - // only for arrays - _error = true; - setMessage("items only valid for arrays"); - return; - } - - for(Json::ArrayIndex i = 0; i < value.size(); ++i) - { - // validate each item - std::ostringstream oss; - oss << "[" << i << "]"; - _currentPath.push_back(oss.str()); - validate(value[i], schema); - _currentPath.pop_back(); - } -} - -void JsonSchemaChecker::checkMinItems(const Json::Value & value, const Json::Value & schema) -{ - assert(schema.isIntegral()); - - if (!value.isArray()) - { - // only for arrays - _error = true; - setMessage("minItems only valid for arrays"); - return; - } - - int minimum = schema.asInt(); - - if (static_cast(value.size()) < minimum) - { - _error = true; - std::ostringstream oss; - oss << "array is too small (minimum=" << minimum << ")"; - setMessage(oss.str()); - } -} - -void JsonSchemaChecker::checkMaxItems(const Json::Value & value, const Json::Value & schema) -{ - assert(schema.isIntegral()); - - if (!value.isArray()) - { - // only for arrays - _error = true; - setMessage("maxItems only valid for arrays"); - return; - } - - int maximum = schema.asInt(); - - if (static_cast(value.size()) > maximum) - { - _error = true; - std::ostringstream oss; - oss << "array is too large (maximum=" << maximum << ")"; - setMessage(oss.str()); - } -} - -void JsonSchemaChecker::checkUniqueItems(const Json::Value & value, const Json::Value & schema) -{ - assert(schema.isBool()); - - if (!value.isArray()) - { - // only for arrays - _error = true; - setMessage("uniqueItems only valid for arrays"); - return; - } - - if (schema.asBool() == true) - { - // make sure no two items are identical - - for(Json::UInt i = 0; i < value.size(); ++i) - { - for (Json::UInt j = i+1; j < value.size(); ++j) - { - if (value[i] == value[j]) - { - // found a value twice - _error = true; - setMessage("array must have unique values"); - } - } - } - } -} - -void JsonSchemaChecker::checkEnum(const Json::Value & value, const Json::Value & schema) -{ - assert(schema.isArray()); - - for(Json::ArrayIndex i = 0; i < schema.size(); ++i) - { - if (schema[i] == value) - { - // found enum value. done. - return; - } - } - - // nothing found - _error = true; - std::ostringstream oss; - oss << "Unknown enum value (allowed values are: "; - std::string values = Json::FastWriter().write(schema); - oss << values.substr(0, values.size()-1); // The writer append a new line which we don't want - oss << ")"; - setMessage(oss.str()); -} +// stdlib includes +#include +#include +#include +#include + +// Utils-Jsonschema includes +#include + +JsonSchemaChecker::JsonSchemaChecker() +{ + // empty +} + +JsonSchemaChecker::~JsonSchemaChecker() +{ + // empty +} + +bool JsonSchemaChecker::setSchema(const Json::Value & schema) +{ + _schema = schema; + + // TODO: check the schema + + return true; +} + +bool JsonSchemaChecker::validate(const Json::Value & value) +{ + // initialize state + _error = false; + _messages.clear(); + _currentPath.clear(); + _currentPath.push_back("[root]"); + _references.clear(); + + // collect dependencies + collectDependencies(value, _schema); + + // validate + validate(value, _schema); + + return !_error; +} + +void JsonSchemaChecker::collectDependencies(const Json::Value & value, const Json::Value &schema) +{ + assert (schema.isObject()); + + // check if id is present + if (schema.isMember("id")) + { + // strore reference + assert (schema["id"].isString()); + std::ostringstream ref; + ref << "$(" << schema["id"].asString() << ")"; + _references[ref.str()] = &value; + } + + // check the current json value + if (schema.isMember("properties")) + { + const Json::Value & properties = schema["properties"]; + assert(properties.isObject()); + + for (Json::Value::const_iterator j = properties.begin(); j != properties.end(); ++j) + { + std::string property = j.memberName(); + if (value.isMember(property)) + { + collectDependencies(value[property], properties[property]); + } + } + } +} + +void JsonSchemaChecker::validate(const Json::Value & value, const Json::Value &schema) +{ + assert (schema.isObject()); + + // check the current json value + for (Json::Value::const_iterator i = schema.begin(); i != schema.end(); ++i) + { + std::string attribute = i.memberName(); + const Json::Value & attributeValue = *i; + + if (attribute == "type") + checkType(value, attributeValue); + else if (attribute == "properties") + checkProperties(value, attributeValue); + else if (attribute == "additionalProperties") + { + // ignore the properties which are handled by the properties attribute (if present) + Json::Value::Members ignoredProperties; + if (schema.isMember("properties")) { + const Json::Value & props = schema["properties"]; + ignoredProperties = props.getMemberNames(); + } + + checkAdditionalProperties(value, attributeValue, ignoredProperties); + } + else if (attribute == "dependencies") + checkDependencies(value, attributeValue); + else if (attribute == "minimum") + checkMinimum(value, attributeValue); + else if (attribute == "maximum") + checkMaximum(value, attributeValue); + else if (attribute == "items") + checkItems(value, attributeValue); + else if (attribute == "minItems") + checkMinItems(value, attributeValue); + else if (attribute == "maxItems") + checkMaxItems(value, attributeValue); + else if (attribute == "uniqueItems") + checkUniqueItems(value, attributeValue); + else if (attribute == "enum") + checkEnum(value, attributeValue); + else if (attribute == "required") + ; // nothing to do. value is present so always oke + else if (attribute == "id") + ; // references have already been collected + else + { + // no check function defined for this attribute + setMessage(std::string("No check function defined for attribute ") + attribute); + continue; + } + } +} + +void JsonSchemaChecker::setMessage(const std::string & message) +{ + std::ostringstream oss; + std::copy(_currentPath.begin(), _currentPath.end(), std::ostream_iterator(oss, "")); + oss << ": " << message; + _messages.push_back(oss.str()); +} + +const std::list & JsonSchemaChecker::getMessages() const +{ + return _messages; +} + +void JsonSchemaChecker::checkType(const Json::Value & value, const Json::Value & schema) +{ + assert(schema.isString()); + + std::string type = schema.asString(); + bool wrongType = false; + if (type == "string") + wrongType = !value.isString(); + else if (type == "number") + wrongType = !value.isNumeric(); + else if (type == "integer") + wrongType = !value.isIntegral(); + else if (type == "double") + wrongType = !value.isDouble(); + else if (type == "boolean") + wrongType = !value.isBool(); + else if (type == "object") + wrongType = !value.isObject(); + else if (type == "array") + wrongType = !value.isArray(); + else if (type == "null") + wrongType = !value.isNull(); + else if (type == "enum") + wrongType = !value.isString(); + else if (type == "any") + wrongType = false; +// else +// assert(false); + + if (wrongType) + { + _error = true; + setMessage(type + " expected"); + } +} + +void JsonSchemaChecker::checkProperties(const Json::Value & value, const Json::Value & schema) +{ + assert(schema.isObject()); + + if (!value.isObject()) + { + _error = true; + setMessage("properies attribute is only valid for objects"); + return; + } + + for (Json::Value::const_iterator i = schema.begin(); i != schema.end(); ++i) + { + std::string property = i.memberName(); + const Json::Value & propertyValue = *i; + + assert(propertyValue.isObject()); + + _currentPath.push_back(std::string(".") + property); + if (value.isMember(property)) + { + validate(value[property], propertyValue); + } + else if (propertyValue.get("required", false).asBool()) + { + _error = true; + setMessage("missing member"); + } + _currentPath.pop_back(); + } +} + +void JsonSchemaChecker::checkAdditionalProperties(const Json::Value & value, const Json::Value & schema, const Json::Value::Members & ignoredProperties) +{ + if (!value.isObject()) + { + _error = true; + setMessage("additional properies attribute is only valid for objects"); + return; + } + + for (Json::Value::const_iterator i = value.begin(); i != value.end(); ++i) + { + std::string property = i.memberName(); + if (std::find(ignoredProperties.begin(), ignoredProperties.end(), property) == ignoredProperties.end()) + { + // property has no property definition. check against the definition for additional properties + _currentPath.push_back(std::string(".") + property); + if (schema.isBool()) + { + if (schema.asBool() == false) + { + _error = true; + setMessage("no schema definition"); + } + } + else + { + validate(value[property], schema); + } + _currentPath.pop_back(); + } + } +} + +void JsonSchemaChecker::checkDependencies(const Json::Value & value, const Json::Value & schemaLink) +{ + if (!value.isObject()) + { + _error = true; + setMessage("dependencies attribute is only valid for objects"); + return; + } + + assert(schemaLink.isString()); + std::map::iterator iter = _references.find(schemaLink.asString()); + if (iter == _references.end()) + { + _error = true; + std::ostringstream oss; + oss << "reference " << schemaLink.asString() << " could not be resolved"; + setMessage(oss.str()); + return; + } + const Json::Value & schema = *(iter->second); + + std::list requiredProperties; + if (schema.isString()) + { + requiredProperties.push_back(schema.asString()); + } + else if (schema.isArray()) + { + for (Json::UInt i = 0; i < schema.size(); ++i) + { + assert(schema[i].isString()); + requiredProperties.push_back(schema[i].asString()); + } + } + else + { + _error = true; + std::ostringstream oss; + oss << "Exepected reference " << schemaLink.asString() << " to resolve to a string or array"; + setMessage(oss.str()); + return; + } + + for (std::list::const_iterator i = requiredProperties.begin(); i != requiredProperties.end(); ++i) + { + if (!value.isMember(*i)) + { + _error = true; + std::ostringstream oss; + oss << "missing member " << *i; + setMessage(oss.str()); + } + } +} + +void JsonSchemaChecker::checkMinimum(const Json::Value & value, const Json::Value & schema) +{ + assert(schema.isNumeric()); + + if (!value.isNumeric()) + { + // only for numeric + _error = true; + setMessage("minimum check only for numeric fields"); + return; + } + + if (value.asDouble() < schema.asDouble()) + { + _error = true; + std::ostringstream oss; + oss << "value is too small (minimum=" << schema.asDouble() << ")"; + setMessage(oss.str()); + } +} + +void JsonSchemaChecker::checkMaximum(const Json::Value & value, const Json::Value & schema) +{ + assert(schema.isNumeric()); + + if (!value.isNumeric()) + { + // only for numeric + _error = true; + setMessage("maximum check only for numeric fields"); + return; + } + + if (value.asDouble() > schema.asDouble()) + { + _error = true; + std::ostringstream oss; + oss << "value is too large (maximum=" << schema.asDouble() << ")"; + setMessage(oss.str()); + } +} + +void JsonSchemaChecker::checkItems(const Json::Value & value, const Json::Value & schema) +{ + assert(schema.isObject()); + + if (!value.isArray()) + { + // only for arrays + _error = true; + setMessage("items only valid for arrays"); + return; + } + + for(Json::ArrayIndex i = 0; i < value.size(); ++i) + { + // validate each item + std::ostringstream oss; + oss << "[" << i << "]"; + _currentPath.push_back(oss.str()); + validate(value[i], schema); + _currentPath.pop_back(); + } +} + +void JsonSchemaChecker::checkMinItems(const Json::Value & value, const Json::Value & schema) +{ + assert(schema.isIntegral()); + + if (!value.isArray()) + { + // only for arrays + _error = true; + setMessage("minItems only valid for arrays"); + return; + } + + int minimum = schema.asInt(); + + if (static_cast(value.size()) < minimum) + { + _error = true; + std::ostringstream oss; + oss << "array is too small (minimum=" << minimum << ")"; + setMessage(oss.str()); + } +} + +void JsonSchemaChecker::checkMaxItems(const Json::Value & value, const Json::Value & schema) +{ + assert(schema.isIntegral()); + + if (!value.isArray()) + { + // only for arrays + _error = true; + setMessage("maxItems only valid for arrays"); + return; + } + + int maximum = schema.asInt(); + + if (static_cast(value.size()) > maximum) + { + _error = true; + std::ostringstream oss; + oss << "array is too large (maximum=" << maximum << ")"; + setMessage(oss.str()); + } +} + +void JsonSchemaChecker::checkUniqueItems(const Json::Value & value, const Json::Value & schema) +{ + assert(schema.isBool()); + + if (!value.isArray()) + { + // only for arrays + _error = true; + setMessage("uniqueItems only valid for arrays"); + return; + } + + if (schema.asBool() == true) + { + // make sure no two items are identical + + for(Json::UInt i = 0; i < value.size(); ++i) + { + for (Json::UInt j = i+1; j < value.size(); ++j) + { + if (value[i] == value[j]) + { + // found a value twice + _error = true; + setMessage("array must have unique values"); + } + } + } + } +} + +void JsonSchemaChecker::checkEnum(const Json::Value & value, const Json::Value & schema) +{ + assert(schema.isArray()); + + for(Json::ArrayIndex i = 0; i < schema.size(); ++i) + { + if (schema[i] == value) + { + // found enum value. done. + return; + } + } + + // nothing found + _error = true; + std::ostringstream oss; + oss << "Unknown enum value (allowed values are: "; + std::string values = Json::FastWriter().write(schema); + oss << values.substr(0, values.size()-1); // The writer append a new line which we don't want + oss << ")"; + setMessage(oss.str()); +} diff --git a/libsrc/xbmcvideochecker/CMakeLists.txt b/libsrc/xbmcvideochecker/CMakeLists.txt index f6e71b00..bb13fb21 100644 --- a/libsrc/xbmcvideochecker/CMakeLists.txt +++ b/libsrc/xbmcvideochecker/CMakeLists.txt @@ -5,33 +5,33 @@ SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/xbmcvideochecker) # Group the headers that go through the MOC compiler SET(XBMCVideoChecker_QT_HEADERS - ${CURRENT_HEADER_DIR}/XBMCVideoChecker.h + ${CURRENT_HEADER_DIR}/XBMCVideoChecker.h ) SET(XBMCVideoChecker_HEADERS ) SET(XBMCVideoChecker_SOURCES - ${CURRENT_SOURCE_DIR}/XBMCVideoChecker.cpp + ${CURRENT_SOURCE_DIR}/XBMCVideoChecker.cpp ) if(ENABLE_QT5) -QT5_WRAP_CPP(XBMCVideoChecker_HEADERS_MOC ${XBMCVideoChecker_QT_HEADERS}) -else(ENABLE_QT5) -QT4_WRAP_CPP(XBMCVideoChecker_HEADERS_MOC ${XBMCVideoChecker_QT_HEADERS}) -endif(ENABLE_QT5) + QT5_WRAP_CPP(XBMCVideoChecker_HEADERS_MOC ${XBMCVideoChecker_QT_HEADERS}) +else() + QT4_WRAP_CPP(XBMCVideoChecker_HEADERS_MOC ${XBMCVideoChecker_QT_HEADERS}) +endif() add_library(xbmcvideochecker - ${XBMCVideoChecker_HEADERS} - ${XBMCVideoChecker_QT_HEADERS} - ${XBMCVideoChecker_HEADERS_MOC} - ${XBMCVideoChecker_SOURCES} + ${XBMCVideoChecker_HEADERS} + ${XBMCVideoChecker_QT_HEADERS} + ${XBMCVideoChecker_HEADERS_MOC} + ${XBMCVideoChecker_SOURCES} ) if(ENABLE_QT5) -qt5_use_modules(xbmcvideochecker Widgets) -endif(ENABLE_QT5) + qt5_use_modules(xbmcvideochecker Widgets) +endif() target_link_libraries(xbmcvideochecker - hyperion - ${QT_LIBRARIES}) + hyperion + ${QT_LIBRARIES}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2626ba9b..89a91802 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,30 +2,27 @@ add_subdirectory(hyperiond) add_subdirectory(hyperion-remote) # The following clients depend on the protobuf library -if(ENABLE_PROTOBUF) - - if (ENABLE_AMLOGIC) - add_subdirectory(hyperion-aml) - endif() - - if(ENABLE_V4L2) - add_subdirectory(hyperion-v4l2) - endif() - - if(ENABLE_X11) - add_subdirectory(hyperion-x11) - endif() - - if(ENABLE_DISPMANX) - add_subdirectory(hyperion-dispmanx) - endif() - - if(ENABLE_FB) - add_subdirectory(hyperion-framebuffer) - endif() - - if(ENABLE_OSX) - add_subdirectory(hyperion-osx) - endif() - +if (ENABLE_AMLOGIC) + add_subdirectory(hyperion-aml) endif() + +if(ENABLE_V4L2) + add_subdirectory(hyperion-v4l2) +endif() + +if(ENABLE_X11) + add_subdirectory(hyperion-x11) +endif() + +if(ENABLE_DISPMANX) + add_subdirectory(hyperion-dispmanx) +endif() + +if(ENABLE_FB) + add_subdirectory(hyperion-framebuffer) +endif() + +if(ENABLE_OSX) + add_subdirectory(hyperion-osx) +endif() + diff --git a/src/hyperion-aml/AmlogicWrapper.cpp b/src/hyperion-aml/AmlogicWrapper.cpp index e4c1f7f1..cf9c2ea2 100644 --- a/src/hyperion-aml/AmlogicWrapper.cpp +++ b/src/hyperion-aml/AmlogicWrapper.cpp @@ -3,14 +3,14 @@ #include "AmlogicWrapper.h" AmlogicWrapper::AmlogicWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz) : - _timer(this), - _grabber(grabWidth, grabHeight) + _timer(this), + _grabber(grabWidth, grabHeight) { - _timer.setSingleShot(false); - _timer.setInterval(updateRate_Hz); + _timer.setSingleShot(false); + _timer.setInterval(updateRate_Hz); - // Connect capturing to the timeout signal of the timer - connect(&_timer, SIGNAL(timeout()), this, SLOT(capture())); + // Connect capturing to the timeout signal of the timer + connect(&_timer, SIGNAL(timeout()), this, SLOT(capture())); } const Image & AmlogicWrapper::getScreenshot() @@ -21,12 +21,12 @@ const Image & AmlogicWrapper::getScreenshot() void AmlogicWrapper::start() { - _timer.start(); + _timer.start(); } void AmlogicWrapper::stop() { - _timer.stop(); + _timer.stop(); } void AmlogicWrapper::capture() diff --git a/src/hyperion-dispmanx/DispmanxWrapper.cpp b/src/hyperion-dispmanx/DispmanxWrapper.cpp index ff88fc77..78f10f02 100644 --- a/src/hyperion-dispmanx/DispmanxWrapper.cpp +++ b/src/hyperion-dispmanx/DispmanxWrapper.cpp @@ -7,16 +7,16 @@ DispmanxWrapper::DispmanxWrapper(const unsigned grabWidth, const unsigned grabHe const unsigned cropLeft, const unsigned cropRight, const unsigned cropTop, const unsigned cropBottom, const unsigned updateRate_Hz) : - _timer(this), - _grabber(grabWidth, grabHeight) + _timer(this), + _grabber(grabWidth, grabHeight) { - _grabber.setVideoMode(videoMode); - _grabber.setCropping(cropLeft, cropRight, cropTop, cropBottom); - _timer.setSingleShot(false); - _timer.setInterval(updateRate_Hz); + _grabber.setVideoMode(videoMode); + _grabber.setCropping(cropLeft, cropRight, cropTop, cropBottom); + _timer.setSingleShot(false); + _timer.setInterval(updateRate_Hz); - // Connect capturing to the timeout signal of the timer - connect(&_timer, SIGNAL(timeout()), this, SLOT(capture())); + // Connect capturing to the timeout signal of the timer + connect(&_timer, SIGNAL(timeout()), this, SLOT(capture())); } const Image & DispmanxWrapper::getScreenshot() @@ -27,12 +27,12 @@ const Image & DispmanxWrapper::getScreenshot() void DispmanxWrapper::start() { - _timer.start(); + _timer.start(); } void DispmanxWrapper::stop() { - _timer.stop(); + _timer.stop(); } void DispmanxWrapper::capture() diff --git a/src/hyperion-framebuffer/FramebufferWrapper.cpp b/src/hyperion-framebuffer/FramebufferWrapper.cpp index b7d7c7b7..48ef4ec7 100644 --- a/src/hyperion-framebuffer/FramebufferWrapper.cpp +++ b/src/hyperion-framebuffer/FramebufferWrapper.cpp @@ -3,14 +3,14 @@ #include "FramebufferWrapper.h" FramebufferWrapper::FramebufferWrapper(const std::string & device, const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz) : - _timer(this), - _grabber(device,grabWidth, grabHeight) + _timer(this), + _grabber(device,grabWidth, grabHeight) { - _timer.setSingleShot(false); - _timer.setInterval(updateRate_Hz); + _timer.setSingleShot(false); + _timer.setInterval(updateRate_Hz); - // Connect capturing to the timeout signal of the timer - connect(&_timer, SIGNAL(timeout()), this, SLOT(capture())); + // Connect capturing to the timeout signal of the timer + connect(&_timer, SIGNAL(timeout()), this, SLOT(capture())); } const Image & FramebufferWrapper::getScreenshot() @@ -21,12 +21,12 @@ const Image & FramebufferWrapper::getScreenshot() void FramebufferWrapper::start() { - _timer.start(); + _timer.start(); } void FramebufferWrapper::stop() { - _timer.stop(); + _timer.stop(); } void FramebufferWrapper::capture() diff --git a/src/hyperion-osx/OsxWrapper.cpp b/src/hyperion-osx/OsxWrapper.cpp index eb9256c2..26544153 100644 --- a/src/hyperion-osx/OsxWrapper.cpp +++ b/src/hyperion-osx/OsxWrapper.cpp @@ -3,14 +3,14 @@ #include "OsxWrapper.h" OsxWrapper::OsxWrapper(const unsigned display, const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz) : - _timer(this), - _grabber(display,grabWidth, grabHeight) + _timer(this), + _grabber(display,grabWidth, grabHeight) { - _timer.setSingleShot(false); - _timer.setInterval(updateRate_Hz); + _timer.setSingleShot(false); + _timer.setInterval(updateRate_Hz); - // Connect capturing to the timeout signal of the timer - connect(&_timer, SIGNAL(timeout()), this, SLOT(capture())); + // Connect capturing to the timeout signal of the timer + connect(&_timer, SIGNAL(timeout()), this, SLOT(capture())); } const Image & OsxWrapper::getScreenshot() diff --git a/src/hyperion-v4l2/PixelFormatParameter.h b/src/hyperion-v4l2/PixelFormatParameter.h index 3ebccfc7..e789f96c 100644 --- a/src/hyperion-v4l2/PixelFormatParameter.h +++ b/src/hyperion-v4l2/PixelFormatParameter.h @@ -10,34 +10,34 @@ using namespace vlofgren; typedef vlofgren::PODParameter PixelFormatParameter; namespace vlofgren { - /// Translates a string (as passed on the commandline) to a pixel format - /// - /// @param[in] s The string (as passed on the commandline) - /// @return The pixel format - /// @throws Parameter::ParameterRejected If the string did not result in a pixel format - template<> - PixelFormat PixelFormatParameter::validate(const std::string& s) throw (Parameter::ParameterRejected) - { - QString input = QString::fromStdString(s).toLower(); + /// Translates a string (as passed on the commandline) to a pixel format + /// + /// @param[in] s The string (as passed on the commandline) + /// @return The pixel format + /// @throws Parameter::ParameterRejected If the string did not result in a pixel format + template<> + PixelFormat PixelFormatParameter::validate(const std::string& s) throw (Parameter::ParameterRejected) + { + QString input = QString::fromStdString(s).toLower(); - if (input == "yuyv") - { - return PIXELFORMAT_YUYV; - } - else if (input == "uyvy") - { - return PIXELFORMAT_UYVY; - } - else if (input == "rgb32") - { - return PIXELFORMAT_RGB32; - } - else if (input == "no-change") - { - return PIXELFORMAT_NO_CHANGE; - } + if (input == "yuyv") + { + return PIXELFORMAT_YUYV; + } + else if (input == "uyvy") + { + return PIXELFORMAT_UYVY; + } + else if (input == "rgb32") + { + return PIXELFORMAT_RGB32; + } + else if (input == "no-change") + { + return PIXELFORMAT_NO_CHANGE; + } - throw Parameter::ParameterRejected("Invalid value for pixel format. Valid values are: YUYV, UYVY, RGB32, and NO-CHANGE"); - return PIXELFORMAT_NO_CHANGE; - } + throw Parameter::ParameterRejected("Invalid value for pixel format. Valid values are: YUYV, UYVY, RGB32, and NO-CHANGE"); + return PIXELFORMAT_NO_CHANGE; + } } diff --git a/src/hyperion-v4l2/ScreenshotHandler.cpp b/src/hyperion-v4l2/ScreenshotHandler.cpp index 0f9daaef..6acd6cc3 100644 --- a/src/hyperion-v4l2/ScreenshotHandler.cpp +++ b/src/hyperion-v4l2/ScreenshotHandler.cpp @@ -6,7 +6,7 @@ #include "ScreenshotHandler.h" ScreenshotHandler::ScreenshotHandler(const std::string & filename) : - _filename(filename) + _filename(filename) { } diff --git a/src/hyperion-v4l2/hyperion-v4l2.cpp b/src/hyperion-v4l2/hyperion-v4l2.cpp index 22add6c7..747bd4a5 100644 --- a/src/hyperion-v4l2/hyperion-v4l2.cpp +++ b/src/hyperion-v4l2/hyperion-v4l2.cpp @@ -31,150 +31,150 @@ using namespace vlofgren; // save the image as screenshot void saveScreenshot(void *, const Image & image) { - // store as PNG - QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888); - pngImage.save("screenshot.png"); + // store as PNG + QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888); + pngImage.save("screenshot.png"); } int main(int argc, char** argv) { std::cout - << "hyperion-v4l2:" << std::endl - << "\tversion : " << HYPERION_VERSION_ID << std::endl - << "\tbuild time: " << __DATE__ << " " << __TIME__ << std::endl; + << "hyperion-v4l2:" << std::endl + << "\tversion : " << HYPERION_VERSION_ID << std::endl + << "\tbuild time: " << __DATE__ << " " << __TIME__ << std::endl; - QCoreApplication app(argc, argv); + QCoreApplication app(argc, argv); - // force the locale - setlocale(LC_ALL, "C"); - QLocale::setDefault(QLocale::c()); + // force the locale + setlocale(LC_ALL, "C"); + QLocale::setDefault(QLocale::c()); - // register the image type to use in signals - qRegisterMetaType>("Image"); + // register the image type to use in signals + qRegisterMetaType>("Image"); - try - { - // create the option parser and initialize all parameters - OptionsParser optionParser("V4L capture application for Hyperion"); - ParameterSet & parameters = optionParser.getParameters(); + try + { + // create the option parser and initialize all parameters + OptionsParser optionParser("V4L capture application for Hyperion"); + ParameterSet & parameters = optionParser.getParameters(); - StringParameter & argDevice = parameters.add ('d', "device", "The device to use [default: /dev/video0]"); - VideoStandardParameter & argVideoStandard = parameters.add('v', "video-standard", "The used video standard. Valid values are PAL or NTSC (optional)"); - PixelFormatParameter & argPixelFormat = parameters.add (0x0, "pixel-format", "The use pixel format. Valid values are YUYV, UYVY, and RGB32 (optional)"); - IntParameter & argInput = parameters.add (0x0, "input", "Input channel (optional)"); - IntParameter & argWidth = parameters.add (0x0, "width", "Try to set the width of the video input (optional)"); - IntParameter & argHeight = parameters.add (0x0, "height", "Try to set the height of the video input (optional)"); - IntParameter & argCropWidth = parameters.add (0x0, "crop-width", "Number of pixels to crop from the left and right sides of the picture before decimation [default: 0]"); - IntParameter & argCropHeight = parameters.add (0x0, "crop-height", "Number of pixels to crop from the top and the bottom of the picture before decimation [default: 0]"); - IntParameter & argCropLeft = parameters.add (0x0, "crop-left", "Number of pixels to crop from the left of the picture before decimation (overrides --crop-width)"); - IntParameter & argCropRight = parameters.add (0x0, "crop-right", "Number of pixels to crop from the right of the picture before decimation (overrides --crop-width)"); - IntParameter & argCropTop = parameters.add (0x0, "crop-top", "Number of pixels to crop from the top of the picture before decimation (overrides --crop-height)"); - IntParameter & argCropBottom = parameters.add (0x0, "crop-bottom", "Number of pixels to crop from the bottom of the picture before decimation (overrides --crop-height)"); - IntParameter & argSizeDecimation = parameters.add ('s', "size-decimator", "Decimation factor for the output size [default=1]"); - IntParameter & argFrameDecimation = parameters.add ('f', "frame-decimator", "Decimation factor for the video frames [default=1]"); - SwitchParameter<> & argScreenshot = parameters.add> (0x0, "screenshot", "Take a single screenshot, save it to file and quit"); - DoubleParameter & argSignalThreshold = parameters.add ('t', "signal-threshold", "The signal threshold for detecting the presence of a signal. Value should be between 0.0 and 1.0."); - DoubleParameter & argRedSignalThreshold = parameters.add (0x0, "red-threshold", "The red signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)"); - DoubleParameter & argGreenSignalThreshold = parameters.add (0x0, "green-threshold", "The green signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)"); - DoubleParameter & argBlueSignalThreshold = parameters.add (0x0, "blue-threshold", "The blue signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)"); - SwitchParameter<> & arg3DSBS = parameters.add> (0x0, "3DSBS", "Interpret the incoming video stream as 3D side-by-side"); - SwitchParameter<> & arg3DTAB = parameters.add> (0x0, "3DTAB", "Interpret the incoming video stream as 3D top-and-bottom"); - StringParameter & argAddress = parameters.add ('a', "address", "Set the address of the hyperion server [default: 127.0.0.1:19445]"); - IntParameter & argPriority = parameters.add ('p', "priority", "Use the provided priority channel (the lower the number, the higher the priority) [default: 800]"); - SwitchParameter<> & argSkipReply = parameters.add> (0x0, "skip-reply", "Do not receive and check reply messages from Hyperion"); - SwitchParameter<> & argHelp = parameters.add> ('h', "help", "Show this help message and exit"); + StringParameter & argDevice = parameters.add ('d', "device", "The device to use [default: /dev/video0]"); + VideoStandardParameter & argVideoStandard = parameters.add('v', "video-standard", "The used video standard. Valid values are PAL or NTSC (optional)"); + PixelFormatParameter & argPixelFormat = parameters.add (0x0, "pixel-format", "The use pixel format. Valid values are YUYV, UYVY, and RGB32 (optional)"); + IntParameter & argInput = parameters.add (0x0, "input", "Input channel (optional)"); + IntParameter & argWidth = parameters.add (0x0, "width", "Try to set the width of the video input (optional)"); + IntParameter & argHeight = parameters.add (0x0, "height", "Try to set the height of the video input (optional)"); + IntParameter & argCropWidth = parameters.add (0x0, "crop-width", "Number of pixels to crop from the left and right sides of the picture before decimation [default: 0]"); + IntParameter & argCropHeight = parameters.add (0x0, "crop-height", "Number of pixels to crop from the top and the bottom of the picture before decimation [default: 0]"); + IntParameter & argCropLeft = parameters.add (0x0, "crop-left", "Number of pixels to crop from the left of the picture before decimation (overrides --crop-width)"); + IntParameter & argCropRight = parameters.add (0x0, "crop-right", "Number of pixels to crop from the right of the picture before decimation (overrides --crop-width)"); + IntParameter & argCropTop = parameters.add (0x0, "crop-top", "Number of pixels to crop from the top of the picture before decimation (overrides --crop-height)"); + IntParameter & argCropBottom = parameters.add (0x0, "crop-bottom", "Number of pixels to crop from the bottom of the picture before decimation (overrides --crop-height)"); + IntParameter & argSizeDecimation = parameters.add ('s', "size-decimator", "Decimation factor for the output size [default=1]"); + IntParameter & argFrameDecimation = parameters.add ('f', "frame-decimator", "Decimation factor for the video frames [default=1]"); + SwitchParameter<> & argScreenshot = parameters.add> (0x0, "screenshot", "Take a single screenshot, save it to file and quit"); + DoubleParameter & argSignalThreshold = parameters.add ('t', "signal-threshold", "The signal threshold for detecting the presence of a signal. Value should be between 0.0 and 1.0."); + DoubleParameter & argRedSignalThreshold = parameters.add (0x0, "red-threshold", "The red signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)"); + DoubleParameter & argGreenSignalThreshold = parameters.add (0x0, "green-threshold", "The green signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)"); + DoubleParameter & argBlueSignalThreshold = parameters.add (0x0, "blue-threshold", "The blue signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)"); + SwitchParameter<> & arg3DSBS = parameters.add> (0x0, "3DSBS", "Interpret the incoming video stream as 3D side-by-side"); + SwitchParameter<> & arg3DTAB = parameters.add> (0x0, "3DTAB", "Interpret the incoming video stream as 3D top-and-bottom"); + StringParameter & argAddress = parameters.add ('a', "address", "Set the address of the hyperion server [default: 127.0.0.1:19445]"); + IntParameter & argPriority = parameters.add ('p', "priority", "Use the provided priority channel (the lower the number, the higher the priority) [default: 800]"); + SwitchParameter<> & argSkipReply = parameters.add> (0x0, "skip-reply", "Do not receive and check reply messages from Hyperion"); + SwitchParameter<> & argHelp = parameters.add> ('h', "help", "Show this help message and exit"); - // set defaults - argDevice.setDefault("/dev/video0"); - argVideoStandard.setDefault(VIDEOSTANDARD_NO_CHANGE); - argPixelFormat.setDefault(PIXELFORMAT_NO_CHANGE); - argInput.setDefault(-1); - argWidth.setDefault(-1); - argHeight.setDefault(-1); - argCropWidth.setDefault(0); - argCropHeight.setDefault(0); - argSizeDecimation.setDefault(1); - argFrameDecimation.setDefault(1); - argAddress.setDefault("127.0.0.1:19445"); - argPriority.setDefault(800); - argSignalThreshold.setDefault(-1); + // set defaults + argDevice.setDefault("/dev/video0"); + argVideoStandard.setDefault(VIDEOSTANDARD_NO_CHANGE); + argPixelFormat.setDefault(PIXELFORMAT_NO_CHANGE); + argInput.setDefault(-1); + argWidth.setDefault(-1); + argHeight.setDefault(-1); + argCropWidth.setDefault(0); + argCropHeight.setDefault(0); + argSizeDecimation.setDefault(1); + argFrameDecimation.setDefault(1); + argAddress.setDefault("127.0.0.1:19445"); + argPriority.setDefault(800); + argSignalThreshold.setDefault(-1); - // parse all options - optionParser.parse(argc, const_cast(argv)); + // parse all options + optionParser.parse(argc, const_cast(argv)); - // check if we need to display the usage. exit if we do. - if (argHelp.isSet()) - { - optionParser.usage(); - return 0; - } + // check if we need to display the usage. exit if we do. + if (argHelp.isSet()) + { + optionParser.usage(); + return 0; + } - // cropping values if not defined - if (!argCropLeft.isSet()) argCropLeft.setDefault(argCropWidth.getValue()); - if (!argCropRight.isSet()) argCropRight.setDefault(argCropWidth.getValue()); - if (!argCropTop.isSet()) argCropTop.setDefault(argCropHeight.getValue()); - if (!argCropBottom.isSet()) argCropBottom.setDefault(argCropHeight.getValue()); + // cropping values if not defined + if (!argCropLeft.isSet()) argCropLeft.setDefault(argCropWidth.getValue()); + if (!argCropRight.isSet()) argCropRight.setDefault(argCropWidth.getValue()); + if (!argCropTop.isSet()) argCropTop.setDefault(argCropHeight.getValue()); + if (!argCropBottom.isSet()) argCropBottom.setDefault(argCropHeight.getValue()); - // initialize the grabber - V4L2Grabber grabber( - argDevice.getValue(), - argInput.getValue(), - argVideoStandard.getValue(), - argPixelFormat.getValue(), - argWidth.getValue(), - argHeight.getValue(), - std::max(1, argFrameDecimation.getValue()), - std::max(1, argSizeDecimation.getValue()), - std::max(1, argSizeDecimation.getValue())); + // initialize the grabber + V4L2Grabber grabber( + argDevice.getValue(), + argInput.getValue(), + argVideoStandard.getValue(), + argPixelFormat.getValue(), + argWidth.getValue(), + argHeight.getValue(), + std::max(1, argFrameDecimation.getValue()), + std::max(1, argSizeDecimation.getValue()), + std::max(1, argSizeDecimation.getValue())); - // set signal detection - grabber.setSignalThreshold( - std::min(1.0, std::max(0.0, argRedSignalThreshold.isSet() ? argRedSignalThreshold.getValue() : argSignalThreshold.getValue())), - std::min(1.0, std::max(0.0, argGreenSignalThreshold.isSet() ? argGreenSignalThreshold.getValue() : argSignalThreshold.getValue())), - std::min(1.0, std::max(0.0, argBlueSignalThreshold.isSet() ? argBlueSignalThreshold.getValue() : argSignalThreshold.getValue())), - 50); + // set signal detection + grabber.setSignalThreshold( + std::min(1.0, std::max(0.0, argRedSignalThreshold.isSet() ? argRedSignalThreshold.getValue() : argSignalThreshold.getValue())), + std::min(1.0, std::max(0.0, argGreenSignalThreshold.isSet() ? argGreenSignalThreshold.getValue() : argSignalThreshold.getValue())), + std::min(1.0, std::max(0.0, argBlueSignalThreshold.isSet() ? argBlueSignalThreshold.getValue() : argSignalThreshold.getValue())), + 50); - // set cropping values - grabber.setCropping( - std::max(0, argCropLeft.getValue()), - std::max(0, argCropRight.getValue()), - std::max(0, argCropTop.getValue()), - std::max(0, argCropBottom.getValue())); + // set cropping values + grabber.setCropping( + std::max(0, argCropLeft.getValue()), + std::max(0, argCropRight.getValue()), + std::max(0, argCropTop.getValue()), + std::max(0, argCropBottom.getValue())); - // set 3D mode if applicable - if (arg3DSBS.isSet()) - { - grabber.set3D(VIDEO_3DSBS); - } - else if (arg3DTAB.isSet()) - { - grabber.set3D(VIDEO_3DTAB); - } + // set 3D mode if applicable + if (arg3DSBS.isSet()) + { + grabber.set3D(VIDEO_3DSBS); + } + else if (arg3DTAB.isSet()) + { + grabber.set3D(VIDEO_3DTAB); + } - // run the grabber - if (argScreenshot.isSet()) - { - ScreenshotHandler handler("screenshot.png"); - QObject::connect(&grabber, SIGNAL(newFrame(Image)), &handler, SLOT(receiveImage(Image))); - grabber.start(); - QCoreApplication::exec(); - grabber.stop(); - } - else - { - ProtoConnectionWrapper handler(argAddress.getValue(), argPriority.getValue(), 1000, argSkipReply.isSet()); - QObject::connect(&grabber, SIGNAL(newFrame(Image)), &handler, SLOT(receiveImage(Image))); - grabber.start(); - QCoreApplication::exec(); - grabber.stop(); - } - } - catch (const std::runtime_error & e) - { - // An error occured. Display error and quit - std::cerr << e.what() << std::endl; - return 1; - } + // run the grabber + if (argScreenshot.isSet()) + { + ScreenshotHandler handler("screenshot.png"); + QObject::connect(&grabber, SIGNAL(newFrame(Image)), &handler, SLOT(receiveImage(Image))); + grabber.start(); + QCoreApplication::exec(); + grabber.stop(); + } + else + { + ProtoConnectionWrapper handler(argAddress.getValue(), argPriority.getValue(), 1000, argSkipReply.isSet()); + QObject::connect(&grabber, SIGNAL(newFrame(Image)), &handler, SLOT(receiveImage(Image))); + grabber.start(); + QCoreApplication::exec(); + grabber.stop(); + } + } + catch (const std::runtime_error & e) + { + // An error occured. Display error and quit + std::cerr << e.what() << std::endl; + return 1; + } - return 0; + return 0; } diff --git a/src/hyperion-x11/X11Wrapper.cpp b/src/hyperion-x11/X11Wrapper.cpp index 8aa8fb49..e417a07b 100644 --- a/src/hyperion-x11/X11Wrapper.cpp +++ b/src/hyperion-x11/X11Wrapper.cpp @@ -3,39 +3,39 @@ #include "X11Wrapper.h" X11Wrapper::X11Wrapper(int grabInterval, bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation) : - _timer(this), - _grabber(useXGetImage, cropLeft, cropRight, cropTop, cropBottom, horizontalPixelDecimation, verticalPixelDecimation) + _timer(this), + _grabber(useXGetImage, cropLeft, cropRight, cropTop, cropBottom, horizontalPixelDecimation, verticalPixelDecimation) { - _timer.setSingleShot(false); - _timer.setInterval(grabInterval); + _timer.setSingleShot(false); + _timer.setInterval(grabInterval); - // Connect capturing to the timeout signal of the timer - connect(&_timer, SIGNAL(timeout()), this, SLOT(capture())); + // Connect capturing to the timeout signal of the timer + connect(&_timer, SIGNAL(timeout()), this, SLOT(capture())); } const Image & X11Wrapper::getScreenshot() { - const Image & screenshot = _grabber.grab(); - return screenshot; + const Image & screenshot = _grabber.grab(); + return screenshot; } void X11Wrapper::start() { - _timer.start(); + _timer.start(); } void X11Wrapper::stop() { - _timer.stop(); + _timer.stop(); } bool X11Wrapper::displayInit() { - return _grabber.Setup(); + return _grabber.Setup(); } void X11Wrapper::capture() { - const Image & screenshot = _grabber.grab(); - emit sig_screenshot(screenshot); + const Image & screenshot = _grabber.grab(); + emit sig_screenshot(screenshot); } diff --git a/src/hyperion-x11/X11Wrapper.h b/src/hyperion-x11/X11Wrapper.h index 26ccc796..b672c3a0 100644 --- a/src/hyperion-x11/X11Wrapper.h +++ b/src/hyperion-x11/X11Wrapper.h @@ -7,35 +7,35 @@ class X11Wrapper : public QObject { - Q_OBJECT + Q_OBJECT public: - X11Wrapper(int grabInterval, bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation); + X11Wrapper(int grabInterval, bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation); - const Image & getScreenshot(); + const Image & getScreenshot(); - /// - /// Starts the timed capturing of screenshots - /// - void start(); + /// + /// Starts the timed capturing of screenshots + /// + void start(); - void stop(); - - bool displayInit(); + void stop(); + + bool displayInit(); signals: - void sig_screenshot(const Image & screenshot); + void sig_screenshot(const Image & screenshot); private slots: - /// - /// Performs a single screenshot capture and publishes the capture screenshot on the screenshot - /// signal. - /// - void capture(); + /// + /// Performs a single screenshot capture and publishes the capture screenshot on the screenshot + /// signal. + /// + void capture(); private: - /// The QT timer to generate capture-publish events - QTimer _timer; + /// The QT timer to generate capture-publish events + QTimer _timer; - /// The grabber for creating screenshots - X11Grabber _grabber; + /// The grabber for creating screenshots + X11Grabber _grabber; }; diff --git a/src/hyperion-x11/hyperion-x11.cpp b/src/hyperion-x11/hyperion-x11.cpp index b7be000d..1c9f4d65 100644 --- a/src/hyperion-x11/hyperion-x11.cpp +++ b/src/hyperion-x11/hyperion-x11.cpp @@ -15,108 +15,108 @@ using namespace vlofgren; // save the image as screenshot void saveScreenshot(const char * filename, const Image & image) { - // store as PNG - QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888); - pngImage.save(filename); + // store as PNG + QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888); + pngImage.save(filename); } int main(int argc, char ** argv) { std::cout - << "hyperion-x11:" << std::endl - << "\tversion : " << HYPERION_VERSION_ID << std::endl - << "\tbuild time: " << __DATE__ << " " << __TIME__ << std::endl; + << "hyperion-x11:" << std::endl + << "\tversion : " << HYPERION_VERSION_ID << std::endl + << "\tbuild time: " << __DATE__ << " " << __TIME__ << std::endl; - QCoreApplication app(argc, argv); + QCoreApplication app(argc, argv); - try - { - // create the option parser and initialize all parameters - OptionsParser optionParser("X11 capture application for Hyperion"); - ParameterSet & parameters = optionParser.getParameters(); + try + { + // create the option parser and initialize all parameters + OptionsParser optionParser("X11 capture application for Hyperion"); + ParameterSet & parameters = optionParser.getParameters(); - IntParameter & argFps = parameters.add ('f', "framerate", "Capture frame rate [default: 10]"); - SwitchParameter<> & argXGetImage = parameters.add> ('x', "xgetimage", "Use XGetImage instead of XRender"); - IntParameter & argCropWidth = parameters.add (0x0, "crop-width", "Number of pixels to crop from the left and right sides of the picture before decimation [default: 0]"); - IntParameter & argCropHeight = parameters.add (0x0, "crop-height", "Number of pixels to crop from the top and the bottom of the picture before decimation [default: 0]"); - IntParameter & argCropLeft = parameters.add (0x0, "crop-left", "Number of pixels to crop from the left of the picture before decimation (overrides --crop-width)"); - IntParameter & argCropRight = parameters.add (0x0, "crop-right", "Number of pixels to crop from the right of the picture before decimation (overrides --crop-width)"); - IntParameter & argCropTop = parameters.add (0x0, "crop-top", "Number of pixels to crop from the top of the picture before decimation (overrides --crop-height)"); - IntParameter & argCropBottom = parameters.add (0x0, "crop-bottom", "Number of pixels to crop from the bottom of the picture before decimation (overrides --crop-height)"); - IntParameter & argSizeDecimation = parameters.add ('s', "size-decimator", "Decimation factor for the output size [default=8]"); - SwitchParameter<> & argScreenshot = parameters.add> (0x0, "screenshot", "Take a single screenshot, save it to file and quit"); - StringParameter & argAddress = parameters.add ('a', "address", "Set the address of the hyperion server [default: 127.0.0.1:19445]"); - IntParameter & argPriority = parameters.add ('p', "priority", "Use the provided priority channel (the lower the number, the higher the priority) [default: 800]"); - SwitchParameter<> & argSkipReply = parameters.add> (0x0, "skip-reply", "Do not receive and check reply messages from Hyperion"); - SwitchParameter<> & argHelp = parameters.add> ('h', "help", "Show this help message and exit"); + IntParameter & argFps = parameters.add ('f', "framerate", "Capture frame rate [default: 10]"); + SwitchParameter<> & argXGetImage = parameters.add> ('x', "xgetimage", "Use XGetImage instead of XRender"); + IntParameter & argCropWidth = parameters.add (0x0, "crop-width", "Number of pixels to crop from the left and right sides of the picture before decimation [default: 0]"); + IntParameter & argCropHeight = parameters.add (0x0, "crop-height", "Number of pixels to crop from the top and the bottom of the picture before decimation [default: 0]"); + IntParameter & argCropLeft = parameters.add (0x0, "crop-left", "Number of pixels to crop from the left of the picture before decimation (overrides --crop-width)"); + IntParameter & argCropRight = parameters.add (0x0, "crop-right", "Number of pixels to crop from the right of the picture before decimation (overrides --crop-width)"); + IntParameter & argCropTop = parameters.add (0x0, "crop-top", "Number of pixels to crop from the top of the picture before decimation (overrides --crop-height)"); + IntParameter & argCropBottom = parameters.add (0x0, "crop-bottom", "Number of pixels to crop from the bottom of the picture before decimation (overrides --crop-height)"); + IntParameter & argSizeDecimation = parameters.add ('s', "size-decimator", "Decimation factor for the output size [default=8]"); + SwitchParameter<> & argScreenshot = parameters.add> (0x0, "screenshot", "Take a single screenshot, save it to file and quit"); + StringParameter & argAddress = parameters.add ('a', "address", "Set the address of the hyperion server [default: 127.0.0.1:19445]"); + IntParameter & argPriority = parameters.add ('p', "priority", "Use the provided priority channel (the lower the number, the higher the priority) [default: 800]"); + SwitchParameter<> & argSkipReply = parameters.add> (0x0, "skip-reply", "Do not receive and check reply messages from Hyperion"); + SwitchParameter<> & argHelp = parameters.add> ('h', "help", "Show this help message and exit"); - // set defaults - argFps.setDefault(10); - argCropWidth.setDefault(0); - argCropHeight.setDefault(0); - argSizeDecimation.setDefault(8); - argAddress.setDefault("127.0.0.1:19445"); - argPriority.setDefault(800); + // set defaults + argFps.setDefault(10); + argCropWidth.setDefault(0); + argCropHeight.setDefault(0); + argSizeDecimation.setDefault(8); + argAddress.setDefault("127.0.0.1:19445"); + argPriority.setDefault(800); - // parse all options - optionParser.parse(argc, const_cast(argv)); + // parse all options + optionParser.parse(argc, const_cast(argv)); - // check if we need to display the usage. exit if we do. - if (argHelp.isSet()) - { - optionParser.usage(); - return 0; - } + // check if we need to display the usage. exit if we do. + if (argHelp.isSet()) + { + optionParser.usage(); + return 0; + } - // cropping values if not defined - if (!argCropLeft.isSet()) argCropLeft.setDefault(argCropWidth.getValue()); - if (!argCropRight.isSet()) argCropRight.setDefault(argCropWidth.getValue()); - if (!argCropTop.isSet()) argCropTop.setDefault(argCropHeight.getValue()); - if (!argCropBottom.isSet()) argCropBottom.setDefault(argCropHeight.getValue()); + // cropping values if not defined + if (!argCropLeft.isSet()) argCropLeft.setDefault(argCropWidth.getValue()); + if (!argCropRight.isSet()) argCropRight.setDefault(argCropWidth.getValue()); + if (!argCropTop.isSet()) argCropTop.setDefault(argCropHeight.getValue()); + if (!argCropBottom.isSet()) argCropBottom.setDefault(argCropHeight.getValue()); - // Create the X11 grabbing stuff - int grabInterval = 1000 / argFps.getValue(); - bool useXGetImage = argXGetImage.isSet(); - X11Wrapper x11Wrapper( - grabInterval, - useXGetImage, - argCropLeft.getValue(), - argCropRight.getValue(), - argCropTop.getValue(), - argCropBottom.getValue(), - argSizeDecimation.getValue(), // horizontal decimation - argSizeDecimation.getValue()); // vertical decimation + // Create the X11 grabbing stuff + int grabInterval = 1000 / argFps.getValue(); + bool useXGetImage = argXGetImage.isSet(); + X11Wrapper x11Wrapper( + grabInterval, + useXGetImage, + argCropLeft.getValue(), + argCropRight.getValue(), + argCropTop.getValue(), + argCropBottom.getValue(), + argSizeDecimation.getValue(), // horizontal decimation + argSizeDecimation.getValue()); // vertical decimation if (!x11Wrapper.displayInit()) return -1; - if (argScreenshot.isSet()) - { - // Capture a single screenshot and finish - const Image & screenshot = x11Wrapper.getScreenshot(); - saveScreenshot("screenshot.png", screenshot); - } - else - { - // Create the Proto-connection with hyperiond - ProtoConnectionWrapper protoWrapper(argAddress.getValue(), argPriority.getValue(), 1000, argSkipReply.isSet()); + if (argScreenshot.isSet()) + { + // Capture a single screenshot and finish + const Image & screenshot = x11Wrapper.getScreenshot(); + saveScreenshot("screenshot.png", screenshot); + } + else + { + // Create the Proto-connection with hyperiond + ProtoConnectionWrapper protoWrapper(argAddress.getValue(), argPriority.getValue(), 1000, argSkipReply.isSet()); - // Connect the screen capturing to the proto processing - QObject::connect(&x11Wrapper, SIGNAL(sig_screenshot(const Image &)), &protoWrapper, SLOT(receiveImage(Image))); + // Connect the screen capturing to the proto processing + QObject::connect(&x11Wrapper, SIGNAL(sig_screenshot(const Image &)), &protoWrapper, SLOT(receiveImage(Image))); - // Start the capturing - x11Wrapper.start(); + // Start the capturing + x11Wrapper.start(); - // Start the application - app.exec(); - } - } - catch (const std::runtime_error & e) - { - // An error occured. Display error and quit - std::cerr << e.what() << std::endl; - return -1; - } + // Start the application + app.exec(); + } + } + catch (const std::runtime_error & e) + { + // An error occured. Display error and quit + std::cerr << e.what() << std::endl; + return -1; + } - return 0; + return 0; } diff --git a/src/hyperiond/hyperiond.cpp b/src/hyperiond/hyperiond.cpp index 00ab7a3f..c52e82ee 100644 --- a/src/hyperiond/hyperiond.cpp +++ b/src/hyperiond/hyperiond.cpp @@ -51,10 +51,8 @@ // JsonServer includes #include -#ifdef ENABLE_PROTOBUF // ProtoServer includes #include -#endif // BoblightServer includes #include @@ -208,7 +206,6 @@ int main(int argc, char** argv) std::cout << "INFO: Json server created and started on port " << jsonServer->getPort() << std::endl; } -#ifdef ENABLE_PROTOBUF // Create Proto server if configuration is present ProtoServer * protoServer = nullptr; if (config.isMember("protoServer")) @@ -217,7 +214,6 @@ int main(int argc, char** argv) protoServer = new ProtoServer(&hyperion, protoServerConfig["port"].asUInt() ); std::cout << "INFO: Proto server created and started on port " << protoServer->getPort() << std::endl; } -#endif // Create Boblight server if configuration is present BoblightServer * boblightServer = nullptr; @@ -254,9 +250,7 @@ int main(int argc, char** argv) QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), dispmanx, SLOT(setVideoMode(VideoMode))); } - #ifdef ENABLE_PROTOBUF QObject::connect(dispmanx, SIGNAL(emitImage(int, const Image&, const int)), protoServer, SLOT(sendImageToProtoSlaves(int, const Image&, const int)) ); - #endif dispmanx->start(); std::cout << "INFO: Frame grabber created and started" << std::endl; @@ -297,9 +291,7 @@ int main(int argc, char** argv) grabberConfig.get("cropTop", 0).asInt(), grabberConfig.get("cropBottom", 0).asInt()); - #ifdef ENABLE_PROTOBUF QObject::connect(v4l2Grabber, SIGNAL(emitImage(int, const Image&, const int)), protoServer, SLOT(sendImageToProtoSlaves(int, const Image&, const int)) ); - #endif v4l2Grabber->start(); std::cout << "INFO: V4L2 grabber created and started" << std::endl; @@ -331,9 +323,7 @@ int main(int argc, char** argv) QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), amlGrabber, SLOT(setVideoMode(VideoMode))); } - #ifdef ENABLE_PROTOBUF QObject::connect(amlGrabber, SIGNAL(emitImage(int, const Image&, const int)), protoServer, SLOT(sendImageToProtoSlaves(int, const Image&, const int)) ); - #endif amlGrabber->start(); std::cout << "INFO: AMLOGIC grabber created and started" << std::endl; @@ -365,9 +355,7 @@ int main(int argc, char** argv) QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), fbGrabber, SLOT(setVideoMode(VideoMode))); } - #ifdef ENABLE_PROTOBUF QObject::connect(fbGrabber, SIGNAL(emitImage(int, const Image&, const int)), protoServer, SLOT(sendImageToProtoSlaves(int, const Image&, const int)) ); - #endif fbGrabber->start(); std::cout << "INFO: Framebuffer grabber created and started" << std::endl; @@ -405,9 +393,7 @@ int main(int argc, char** argv) QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), osxGrabber, SLOT(setVideoMode(VideoMode))); } - #ifdef ENABLE_PROTOBUF QObject::connect(osxGrabber, SIGNAL(emitImage(int, const Image&, const int)), protoServer, SLOT(sendImageToProtoSlaves(int, const Image&, const int)) ); - #endif osxGrabber->start(); std::cout << "INFO: OSX grabber created and started" << std::endl; @@ -445,9 +431,7 @@ int main(int argc, char** argv) #endif delete xbmcVideoChecker; delete jsonServer; -#ifdef ENABLE_PROTOBUF delete protoServer; -#endif delete boblightServer; // leave application