Merge remote-tracking branch 'refs/remotes/origin/Beta'

Former-commit-id: 55e158c5ccd60cff7d5fbd3fd4267e620792fd35
This commit is contained in:
brindosch 2016-06-11 10:43:19 +02:00
commit d2f47251f5
182 changed files with 8866 additions and 6977 deletions

3
.gitmodules vendored
View File

@ -3,4 +3,5 @@
url = https://github.com/tvdzwan/protobuf.git url = https://github.com/tvdzwan/protobuf.git
[submodule "dependencies/external/rpi_ws281x"] [submodule "dependencies/external/rpi_ws281x"]
path = dependencies/external/rpi_ws281x path = dependencies/external/rpi_ws281x
url = https://github.com/jgarff/rpi_ws281x url = https://github.com/penfold42/rpi_ws281x.git
branch = sk6812

View File

@ -1,28 +1,63 @@
# Define the main-project name # Define the main-project name
project(Hyperion) project(hyperion)
# define the minimum cmake version (as required by cmake) # define the minimum cmake version (as required by cmake)
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
#set(CMAKE_TOOLCHAIN_FILE /opt/raspberrypi/Toolchain-RaspberryPi.cmake) IF ( POLICY CMP0026 )
CMAKE_POLICY( SET CMP0026 OLD )
ENDIF()
SET ( DEFAULT_AMLOGIC OFF )
SET ( DEFAULT_DISPMANX OFF )
SET ( DEFAULT_FB OFF )
SET ( DEFAULT_OSX OFF )
SET ( DEFAULT_X11 OFF )
SET ( DEFAULT_SPIDEV OFF )
SET ( DEFAULT_WS2812BPWM OFF )
SET ( DEFAULT_WS281XPWM OFF )
SET ( DEFAULT_ZEROCONF OFF )
if (APPLE)
SET ( DEFAULT_OSX ON )
else ()
if ( "${PLATFORM}" STREQUAL "rpi" )
SET ( DEFAULT_DISPMANX ON )
SET ( DEFAULT_SPIDEV ON )
elseif ( "${PLATFORM}" STREQUAL "rpi-pwm" )
SET ( DEFAULT_DISPMANX ON )
SET ( DEFAULT_WS2812BPWM ON )
SET ( DEFAULT_WS281XPWM ON )
SET ( DEFAULT_SPIDEV ON )
elseif ( "${PLATFORM}" STREQUAL "wetek" )
SET ( DEFAULT_AMLOGIC ON )
SET ( DEFAULT_FB ON )
elseif ( "${PLATFORM}" STREQUAL "x86" )
SET ( DEFAULT_X11 ON )
SET ( DEFAULT_FB ON )
elseif ( "${PLATFORM}" STREQUAL "imx6" )
SET ( DEFAULT_FB ON )
endif()
endif ()
# set the build options # set the build options
option(ENABLE_AMLOGIC "Enable the AMLOGIC video grabber" OFF) option(ENABLE_ZEROCONF "Enable the avahi/zeroconf announce" ${DEFAULT_ZEROCONF} )
message(STATUS "ENABLE_ZEROCONF = " ${ENABLE_ZEROCONF})
option(ENABLE_AMLOGIC "Enable the AMLOGIC video grabber" ${DEFAULT_AMLOGIC} )
message(STATUS "ENABLE_AMLOGIC = " ${ENABLE_AMLOGIC}) message(STATUS "ENABLE_AMLOGIC = " ${ENABLE_AMLOGIC})
option(ENABLE_DISPMANX "Enable the RPi dispmanx grabber" ON) option(ENABLE_DISPMANX "Enable the RPi dispmanx grabber" ${DEFAULT_DISPMANX} )
message(STATUS "ENABLE_DISPMANX = " ${ENABLE_DISPMANX}) message(STATUS "ENABLE_DISPMANX = " ${ENABLE_DISPMANX})
option(ENABLE_FB "Enable the framebuffer grabber" OFF) option(ENABLE_FB "Enable the framebuffer grabber" ${DEFAULT_FB} )
message(STATUS "ENABLE_FB = " ${ENABLE_FB}) message(STATUS "ENABLE_FB = " ${ENABLE_FB})
option(ENABLE_OSX "Enable the osx grabber" OFF) option(ENABLE_OSX "Enable the osx grabber" ${DEFAULT_OSX} )
message(STATUS "ENABLE_OSX = " ${ENABLE_OSX}) message(STATUS "ENABLE_OSX = " ${ENABLE_OSX})
option(ENABLE_PROTOBUF "Enable PROTOBUF server" ON) option(ENABLE_SPIDEV "Enable the SPIDEV device" ${DEFAULT_SPIDEV} )
message(STATUS "ENABLE_PROTOBUF = " ${ENABLE_PROTOBUF})
option(ENABLE_SPIDEV "Enable the SPIDEV device" ON)
message(STATUS "ENABLE_SPIDEV = " ${ENABLE_SPIDEV}) message(STATUS "ENABLE_SPIDEV = " ${ENABLE_SPIDEV})
option(ENABLE_TINKERFORGE "Enable the TINKERFORGE device" ON) option(ENABLE_TINKERFORGE "Enable the TINKERFORGE device" ON)
@ -31,13 +66,13 @@ message(STATUS "ENABLE_TINKERFORGE = " ${ENABLE_TINKERFORGE})
option(ENABLE_V4L2 "Enable the V4L2 grabber" ON) option(ENABLE_V4L2 "Enable the V4L2 grabber" ON)
message(STATUS "ENABLE_V4L2 = " ${ENABLE_V4L2}) message(STATUS "ENABLE_V4L2 = " ${ENABLE_V4L2})
option(ENABLE_WS2812BPWM "Enable the WS2812b-PWM device" OFF) option(ENABLE_WS2812BPWM "Enable the WS2812b-PWM device" ${DEFAULT_WS2812BPWM} )
message(STATUS "ENABLE_WS2812BPWM = " ${ENABLE_WS2812BPWM}) message(STATUS "ENABLE_WS2812BPWM = " ${ENABLE_WS2812BPWM})
option(ENABLE_WS281XPWM "Enable the WS281x-PWM device" OFF) option(ENABLE_WS281XPWM "Enable the WS281x-PWM device" ${DEFAULT_WS281XPWM} )
message(STATUS "ENABLE_WS281XPWM = " ${ENABLE_WS281XPWM}) message(STATUS "ENABLE_WS281XPWM = " ${ENABLE_WS281XPWM})
option(ENABLE_X11 "Enable the X11 grabber" OFF) option(ENABLE_X11 "Enable the X11 grabber" ${DEFAULT_X11})
message(STATUS "ENABLE_X11 = " ${ENABLE_X11}) message(STATUS "ENABLE_X11 = " ${ENABLE_X11})
option(ENABLE_QT5 "Enable QT5" OFF) option(ENABLE_QT5 "Enable QT5" OFF)
@ -46,22 +81,21 @@ message(STATUS "ENABLE_QT5 = " ${ENABLE_QT5})
option(ENABLE_TESTS "Compile additional test applications" OFF) option(ENABLE_TESTS "Compile additional test applications" OFF)
message(STATUS "ENABLE_TESTS = " ${ENABLE_TESTS}) message(STATUS "ENABLE_TESTS = " ${ENABLE_TESTS})
if(ENABLE_V4L2 AND NOT ENABLE_PROTOBUF) option(ENABLE_PROFILER "enable profiler capabilities - not for release code" OFF)
message(FATAL_ERROR "V4L2 grabber requires PROTOBUF. Disable V4L2 or enable PROTOBUF") message(STATUS "ENABLE_PROFILER = " ${ENABLE_PROFILER})
endif(ENABLE_V4L2 AND NOT ENABLE_PROTOBUF)
if(ENABLE_FB AND ENABLE_DISPMANX) if(ENABLE_FB AND ENABLE_DISPMANX)
message(FATAL_ERROR "dispmanx grabber and framebuffer grabber cannot be used at the same time") message(FATAL_ERROR "dispmanx grabber and framebuffer grabber cannot be used at the same time")
endif(ENABLE_FB AND ENABLE_DISPMANX) endif()
if(ENABLE_FB AND ENABLE_OSX) if(ENABLE_FB AND ENABLE_OSX)
message(FATAL_ERROR "osx grabber and framebuffer grabber cannot be used at the same time") message(FATAL_ERROR "osx grabber and framebuffer grabber cannot be used at the same time")
endif(ENABLE_FB AND ENABLE_OSX) endif()
if(ENABLE_OSX AND ENABLE_DISPMANX) if(ENABLE_OSX AND ENABLE_DISPMANX)
message(FATAL_ERROR "dispmanx grabber and osx grabber cannot be used at the same time") message(FATAL_ERROR "dispmanx grabber and osx grabber cannot be used at the same time")
endif(ENABLE_OSX AND ENABLE_DISPMANX) endif()
SET ( PROTOBUF_INSTALL_BIN_DIR ${CMAKE_BINARY_DIR}/proto ) SET ( PROTOBUF_INSTALL_BIN_DIR ${CMAKE_BINARY_DIR}/proto )
SET ( PROTOBUF_INSTALL_LIB_DIR ${CMAKE_BINARY_DIR}/proto ) SET ( PROTOBUF_INSTALL_LIB_DIR ${CMAKE_BINARY_DIR}/proto )
@ -85,10 +119,10 @@ include_directories("${PROJECT_BINARY_DIR}")
if(ENABLE_QT5) if(ENABLE_QT5)
ADD_DEFINITIONS ( -DENABLE_QT5 ) ADD_DEFINITIONS ( -DENABLE_QT5 )
#find_package(Qt5Widgets) #find_package(Qt5Widgets)
else(ENABLE_QT5) else()
# Add specific cmake modules to find qt4 (default version finds first available QT which might not be qt4) # Add specific cmake modules to find qt4 (default version finds first available QT which might not be qt4)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/qt4) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/qt4)
endif(ENABLE_QT5) endif()
# Define the global output path of binaries # Define the global output path of binaries
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
@ -113,10 +147,10 @@ if(ENABLE_QT5)
find_package(Qt5 COMPONENTS Core Gui Widgets Network REQUIRED) find_package(Qt5 COMPONENTS Core Gui Widgets Network REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
# set(CMAKE_CXX_FLAGS "-fPIC") # set(CMAKE_CXX_FLAGS "-fPIC")
else(ENABLE_QT5) else()
# Configure the use of QT4 # Configure the use of QT4
find_package(Qt4 COMPONENTS QtCore QtNetwork QtGui REQUIRED QUIET) find_package(Qt4 COMPONENTS QtCore QtNetwork QtGui REQUIRED QUIET)
endif(ENABLE_QT5) endif()
#add libusb and pthreads #add libusb and pthreads
find_package(libusb-1.0 REQUIRED) find_package(libusb-1.0 REQUIRED)
@ -124,10 +158,10 @@ find_package(Threads REQUIRED)
if(ENABLE_QT5) if(ENABLE_QT5)
#include(${QT_USE_FILE}) #include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS}) add_definitions(${QT_DEFINITIONS})
else(ENABLE_QT5) else()
include(${QT_USE_FILE}) include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS}) add_definitions(${QT_DEFINITIONS})
endif(ENABLE_QT5) endif()
# TODO[TvdZ]: This linking directory should only be added if we are cross compiling # TODO[TvdZ]: This linking directory should only be added if we are cross compiling
if(NOT APPLE) if(NOT APPLE)
@ -138,18 +172,21 @@ if(ENABLE_OSX)
set(CMAKE_EXE_LINKER_FLAGS "-framework CoreGraphics") set(CMAKE_EXE_LINKER_FLAGS "-framework CoreGraphics")
endif() endif()
configure_file(bin/install_hyperion.sh ${LIBRARY_OUTPUT_PATH} @ONLY)
configure_file(config/hyperion.config.json ${LIBRARY_OUTPUT_PATH} @ONLY)
configure_file(config/hyperion_x86.config.json ${LIBRARY_OUTPUT_PATH} @ONLY)
# Add the source/lib directories # Add the source/lib directories
add_subdirectory(dependencies) add_subdirectory(dependencies)
add_subdirectory(libsrc) add_subdirectory(libsrc)
add_subdirectory(src) add_subdirectory(src)
if (ENABLE_TESTS) if (ENABLE_TESTS)
add_subdirectory(test) add_subdirectory(test)
endif (ENABLE_TESTS) endif ()
# Add the doxygen generation directory # Add the doxygen generation directory
add_subdirectory(doc) add_subdirectory(doc)
# uninstall target
configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
# enable make package - no code after this line !
include (${CMAKE_CURRENT_SOURCE_DIR}/cmake/packages.cmake)

19
CODING_STYLE.md Normal file
View File

@ -0,0 +1,19 @@
### Please use the following code style/guidelines
- use QT wherever it's possible (except there is a good reason)
- use unix line endings (not windows)
- indent your code with TABs instead of spaces
- follow this rule for curly brackets
```
bad:
if (conditon) {
code
}
good:
if (condition)
{
code
}
```

View File

@ -18,9 +18,6 @@
// Define to enable the spi-device // Define to enable the spi-device
#cmakedefine ENABLE_TINKERFORGE #cmakedefine ENABLE_TINKERFORGE
// Define to enable PROTOBUF server
#cmakedefine ENABLE_PROTOBUF
// Define to enable the framebuffer grabber // Define to enable the framebuffer grabber
#cmakedefine ENABLE_FB #cmakedefine ENABLE_FB
@ -30,4 +27,11 @@
// Define to enable the osx grabber // Define to enable the osx grabber
#cmakedefine ENABLE_OSX #cmakedefine ENABLE_OSX
// Define to enable the bonjour/zeroconf publishing
#cmakedefine ENABLE_ZEROCONF
// Define to enable profiler for development purpose
#cmakedefine ENABLE_PROFILER
// the hyperion build id string
#define HYPERION_VERSION_ID "${HYPERION_VERSION_ID}" #define HYPERION_VERSION_ID "${HYPERION_VERSION_ID}"

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2014 hyperion team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,43 +1,34 @@
#!/bin/sh #!/bin/sh
# create all directly for release with -DCMAKE_BUILD_TYPE=Release -Wno-dev
# Create the x64 build
mkdir build-x86x64
cd build-x86x64
cmake -DENABLE_DISPMANX=OFF -DENABLE_X11=ON -DCMAKE_BUILD_TYPE=Release -Wno-dev ..
make -j 4
cd ..
# Create the x32 build # make_release <release name> <platform> [<cmake args ...>]
#mkdir build-x32 make_release()
#cd build-x32 {
#cmake -DIMPORT_PROTOC=../build-x64/protoc_export.cmake -DENABLE_DISPMANX=OFF -DENABLE_X11=ON -DCMAKE_BUILD_TYPE=Release -Wno-dev .. echo
#make -j 4 echo "--- build release for $1 ---"
#cd .. echo
RELEASE=$1
PLATFORM=$2
shift 2
# Create the RPI build mkdir -p build-${RELEASE}
mkdir build-rpi mkdir -p deploy/${RELEASE}
cd build-rpi cd build-${RELEASE}
cmake -DCMAKE_TOOLCHAIN_FILE="../Toolchain-rpi.cmake" -DIMPORT_PROTOC=../build-x86x64/protoc_export.cmake -DENABLE_WS2812BPWM=ON -DENABLE_WS281XPWM=ON -DCMAKE_BUILD_TYPE=Release -Wno-dev .. cmake -DCMAKE_INSTALL_PREFIX=/usr -DPLATFORM=${PLATFORM} $@ -DCMAKE_BUILD_TYPE=Release -Wno-dev .. || exit 1
make -j 4 make -j $(nproc) || exit 1
cd .. #strip bin/*
make package -j $(nproc)
mv hyperion-*-ambilight.* ../deploy/${RELEASE}
cd ..
bin/create_release.sh . ${RELEASE}
}
# Create the WETEK build export PATH="$PATH:$HOME/raspberrypi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin"
mkdir build-wetek CMAKE_PROTOC_FLAG="-DIMPORT_PROTOC=../build-x86x64/protoc_export.cmake"
cd build-wetek
cmake -DCMAKE_TOOLCHAIN_FILE="../Toolchain-rpi.cmake" -DIMPORT_PROTOC=../build-x86x64/protoc_export.cmake -DENABLE_DISPMANX=OFF -DENABLE_FB=ON -DENABLE_AMLOGIC=ON -DCMAKE_BUILD_TYPE=Release -Wno-dev ..
make -j 4
cd ..
# Create the IMX6 build make_release x86x64 x86
#mkdir build-imx6 #make_release x32 x86 ${CMAKE_PROTOC_FLAG}
#cd build-imx6 make_release rpi rpi-pwm -DCMAKE_TOOLCHAIN_FILE="../cmake/Toolchain-rpi.cmake" ${CMAKE_PROTOC_FLAG}
#cmake -DCMAKE_TOOLCHAIN_FILE="../Toolchain-imx6.cmake" -DIMPORT_PROTOC=../build-x32x64/protoc_export.cmake -DENABLE_DISPMANX=OFF -DENABLE_FB=ON -DCMAKE_BUILD_TYPE=Release -Wno-dev .. make_release wetek wetek -DCMAKE_TOOLCHAIN_FILE="../cmake/Toolchain-rpi.cmake" ${CMAKE_PROTOC_FLAG}
#make -j 4 #make_release imx6 imx6 -DCMAKE_TOOLCHAIN_FILE="../cmake/Toolchain-imx6.cmake" ${CMAKE_PROTOC_FLAG}
#cd ..
bin/create_release.sh . x86x64
#bin/create_release.sh . x32
bin/create_release.sh . rpi
bin/create_release.sh . wetek
#bin/create_release.sh . imx6

View File

@ -23,18 +23,14 @@ tar --create --gzip --absolute-names --show-transformed-names --ignore-failed-re
--transform "s:$builddir/bin/:hyperion/bin/:" \ --transform "s:$builddir/bin/:hyperion/bin/:" \
--transform "s:$repodir/effects/:hyperion/effects/:" \ --transform "s:$repodir/effects/:hyperion/effects/:" \
--transform "s:$repodir/config/:hyperion/config/:" \ --transform "s:$repodir/config/:hyperion/config/:" \
--transform "s:$repodir/bin/service/hyperion.init.sh:hyperion/init.d/hyperion.init.sh:" \ --transform "s:$repodir/bin/service/hyperion.init.sh:hyperion/services/hyperion.init.sh:" \
--transform "s:$repodir/bin/service/hyperion.systemd.sh:hyperion/init.d/hyperion.systemd.sh:" \ --transform "s:$repodir/bin/service/hyperion.systemd.sh:hyperion/services/hyperion.systemd.sh:" \
--transform "s:$repodir/bin/service/hyperion.initctl.sh:hyperion/init.d/hyperion.initctl.sh:" \ --transform "s:$repodir/bin/service/hyperion.initctl.sh:hyperion/services/hyperion.initctl.sh:" \
--transform "s://:/:g" \ --transform "s://:/:g" \
"$builddir/bin/hyperiond" \ "$builddir/bin/hyperion"* \
"$builddir/bin/hyperion-remote" \
"$builddir/bin/hyperion-v4l2" \
"$builddir/bin/hyperion-x11" \
"$builddir/bin/hyperion-dispmanx" \
"$repodir/effects/"* \ "$repodir/effects/"* \
"$repodir/bin/service/hyperion.init.sh" \ "$repodir/bin/service/hyperion.init.sh" \
"$repodir/bin/service/hyperion.systemd.sh" \ "$repodir/bin/service/hyperion.systemd.sh" \
"$repodir/bin/service/hyperion.initctl.sh" \ "$repodir/bin/service/hyperion.initctl.sh" \
"$repodir/config/hyperion.config.json" "$repodir/config/hyperion.config.json.example"

View File

@ -23,7 +23,7 @@ fi
#Set welcome message #Set welcome message
if [ $BETA -eq 1 ]; then if [ $BETA -eq 1 ]; then
WMESSAGE="echo This script will update Hyperion to the latest BETA" WMESSAGE="echo This script will update Hyperion to the latest BETA"
else WMESSAGE="echo This script will install/update Hyperion Ambilight" else WMESSAGE="echo This script will install/update Hyperion Ambient Light"
fi fi
#Welcome message #Welcome message
@ -74,24 +74,34 @@ if [ $BOBLIGHT_PROCNR -eq 1 ]; then
exit 1 exit 1
fi fi
# Stop hyperion daemon if it is running #set service script path
SERVICEL="/usr/share/hyperion/services"
# Stop hyperion daemon if it is running and set service path
echo '---> Stop Hyperion, if necessary' echo '---> Stop Hyperion, if necessary'
if [ $OS_OPENELEC -eq 1 ]; then if [ $OS_OPENELEC -eq 1 ]; then
killall hyperiond 2>/dev/null killall hyperiond 2>/dev/null
elif [ $USE_INITCTL -eq 1 ]; then elif [ $USE_INITCTL -eq 1 ]; then
/sbin/initctl stop hyperion 2>/dev/null /sbin/initctl stop hyperion 2>/dev/null
elif [ $USE_SERVICE -eq 1 ]; then SERVICEP="/etc/init"
/usr/sbin/service hyperion stop 2>/dev/null
elif [ $USE_SYSTEMD -eq 1 ]; then elif [ $USE_SYSTEMD -eq 1 ]; then
service hyperion stop 2>/dev/null service hyperion stop 2>/dev/null
SERVICEP="/etc/systemd/system"
#many people installed with the official script and this just uses service, if both registered -> dead #many people installed with the official script and this just uses service, if both registered -> dead
/usr/sbin/service hyperion stop 2>/dev/null /usr/sbin/service hyperion stop 2>/dev/null
#Bad workaround for Jessie (systemd) users that used the old official script for install
update-rc.d -f hyperion remove 2>/dev/null
rm /etc/init.d/hyperion 2>/dev/null
elif [ $USE_SERVICE -eq 1 ]; then
/usr/sbin/service hyperion stop 2>/dev/null
SERVICEP="/etc/init.d"
fi fi
#Install dependencies for Hyperion #Install dependencies for Hyperion and setup preperation
if [ $OS_OPENELEC -ne 1 ]; then if [ $OS_OPENELEC -ne 1 ]; then
echo '---> Install/Update Hyperion dependencies (This may take a while)' echo '---> Install/Update Hyperion dependencies (This may take a while)'
apt-get -qq update && apt-get -qq --yes install libqtcore4 libqtgui4 libqt4-network libusb-1.0-0 ca-certificates apt-get -qq update && apt-get -qq --yes install libqtcore4 libqtgui4 libqt4-network libusb-1.0-0 ca-certificates
mkdir /etc/hyperion 2>/dev/null
fi fi
#Check, if dtparam=spi=on is in place (not for OPENELEC) #Check, if dtparam=spi=on is in place (not for OPENELEC)
@ -120,12 +130,34 @@ if [ $CPU_RPI -eq 1 ] && [ $OS_OPENELEC -eq 1 ]; then
fi fi
fi fi
#Backup the .conf files, if present # compatibility layer to move old configs to new config dir
echo '---> Backup Hyperion configuration(s), if present' if [ -f "/opt/hyperion/bin/hyperiond" ]; then
rm -f /tmp/*.json 2>/dev/null echo '---> Old installation found, move configs to /etc/hyperion/ and move hyperion to /usr/share/hyperion/'
if [ $OS_OPENELEC -eq 1 ]; then mv /opt/hyperion/config/*.json /etc/hyperion 2>/dev/null
cp -v /storage/.config/*.json /tmp 2>/dev/null sed -i "s|/opt/hyperion/effects|/usr/share/hyperion/effects|g" /etc/hyperion/*.json
else cp -v /opt/hyperion/config/*.json /tmp 2>/dev/null CPO1=/etc/hyperion.config.json
CPO2=/opt/hyperion/config/hyperion.config.json
CPN=/etc/hyperion/hyperion.config.json
BPO=/opt/hyperion/bin/hyperiond
BPN=/usr/bin/hyperiond
if [ $USE_INITCTL -eq 1 ]; then
sed -i "s|$BPO|$BPN|g" $SERVICEP/hyperion.conf
sed -i "s|$CPO1|$CPN|g" $SERVICEP/hyperion.conf
sed -i "s|$CPO2|$CPN|g" $SERVICEP/hyperion.conf
initctl reload-configuration
elif [ $OS_OPENELEC -eq 1 ]; then
sleep 0
elif [ $USE_SYSTEMD -eq 1 ]; then
sed -i "s|$BPO|$BPN|g" $SERVICEP/hyperion.service
sed -i "s|$CPO1|$CPN|g" $SERVICEP/hyperion.service
sed -i "s|$CPO2|$CPN|g" $SERVICEP/hyperion.service
systemctl -q daemon-reload
elif [ $USE_SERVICE -eq 1 ]; then
sed -i "s|$BPO|$BPN|g" $SERVICEP/hyperion
sed -i "s|$CPO1|$CPN|g" $SERVICEP/hyperion
sed -i "s|$CPO2|$CPN|g" $SERVICEP/hyperion
update-rc.d hyperion defaults 98 02
fi
fi fi
# Select the appropriate download path # Select the appropriate download path
@ -191,34 +223,25 @@ if [ $OS_OPENELEC -eq 1 ]; then
curl -# -L --get $OE_DEPENDECIES | tar -C /storage/hyperion/bin -xz curl -# -L --get $OE_DEPENDECIES | tar -C /storage/hyperion/bin -xz
#set the executen bit (failsave) #set the executen bit (failsave)
chmod +x -R /storage/hyperion/bin chmod +x -R /storage/hyperion/bin
# modify the default config to have a correct effect path
sed -i 's:/opt:/storage:g' /storage/hyperion/config/hyperion.config.json
# /storage/.config is available as samba share. A symbolic link would not be working
false | cp -i /storage/hyperion/config/hyperion.config.json /storage/.config/hyperion.config.json 2>/dev/null
else else
wget -nv $HYPERION_RELEASE -O - | tar -C /opt -xz BINSP=/usr/share/hyperion/bin
#set the executen bit (failsave) BINTP=/usr/bin
chmod +x -R /opt/hyperion/bin wget -nv $HYPERION_RELEASE -O - | tar -C /usr/share -xz
#set the executen bit (failsave) and move config to /etc/hyperion
chmod +x -R $BINSP
# create links to the binaries # create links to the binaries
ln -fs /opt/hyperion/bin/hyperiond /usr/bin/hyperiond ln -fs $BINSP/hyperiond $BINTP/hyperiond
ln -fs /opt/hyperion/bin/hyperion-remote /usr/bin/hyperion-remote ln -fs $BINSP/hyperion-remote $BINTP/hyperion-remote
ln -fs /opt/hyperion/bin/hyperion-v4l2 /usr/bin/hyperion-v4l2 ln -fs $BINSP/hyperion-v4l2 $BINTP/hyperion-v4l2
ln -fs /opt/hyperion/bin/hyperion-dispmanx /usr/bin/hyperion-dispmanx 2>/dev/null ln -fs $BINSP/hyperion-dispmanx $BINTP/hyperion-dispmanx 2>/dev/null
ln -fs /opt/hyperion/bin/hyperion-x11 /usr/bin/hyperion-x11 2>/dev/null ln -fs $BINSP/hyperion-x11 $BINTP/hyperion-x11 2>/dev/null
ln -fs $BINSP/hyperion-aml $BINTP/hyperion-aml 2>/dev/null
fi fi
# Restore backup of .conf files, if present # Copy the service control configuration to /etc/init (-n to respect user modified scripts)
echo '---> Restore Hyperion configuration(s), if present'
if [ $OS_OPENELEC -eq 1 ]; then
mv -v /tmp/*.json /storage/.config/ 2>/dev/null
else mv -v /tmp/*.json /opt/hyperion/config/ 2>/dev/null
fi
# Copy the service control configuration to /etc/int (-n to respect user modified scripts)
if [ $USE_INITCTL -eq 1 ]; then if [ $USE_INITCTL -eq 1 ]; then
echo '---> Installing initctl script' echo '---> Installing initctl script'
cp -n /opt/hyperion/init.d/hyperion.initctl.sh /etc/init/hyperion.conf 2>/dev/null cp -n $SERVICEL/hyperion.initctl.sh $SERVICEP/hyperion.conf 2>/dev/null
initctl reload-configuration initctl reload-configuration
elif [ $OS_OPENELEC -eq 1 ]; then elif [ $OS_OPENELEC -eq 1 ]; then
#modify all old installs with a logfile output #modify all old installs with a logfile output
@ -239,34 +262,35 @@ elif [ $OS_OPENELEC -eq 1 ]; then
elif [ $USE_SYSTEMD -eq 1 ]; then elif [ $USE_SYSTEMD -eq 1 ]; then
echo '---> Installing systemd script' echo '---> Installing systemd script'
#place startup script for systemd and activate #place startup script for systemd and activate
#Problem with systemd to enable symlinks - Bug? Workaround cp -n (overwrite never) cp -n $SERVICEL/hyperion.systemd.sh $SERVICEP/hyperion.service
#Bad workaround for Jessie (systemd) users that used the official script for install
update-rc.d -f hyperion remove 2>/dev/null
rm /etc/init.d/hyperion 2>/dev/null
cp -n /opt/hyperion/init.d/hyperion.systemd.sh /etc/systemd/system/hyperion.service
systemctl -q enable hyperion.service systemctl -q enable hyperion.service
if [ $OS_OSMC -eq 1 ]; then if [ $OS_OSMC -eq 1 ]; then
echo '---> Modify systemd script for OSMC usage' echo '---> Modify systemd script for OSMC usage'
# Wait until kodi is sarted (for kodi checker) # Wait until kodi is sarted
sed -i '/After = mediacenter.service/d' /etc/systemd/system/hyperion.service sed -i '/After = mediacenter.service/d' $SERVICEP/hyperion.service
sed -i '/Unit/a After = mediacenter.service' /etc/systemd/system/hyperion.service sed -i '/Unit/a After = mediacenter.service' $SERVICEP/hyperion.service
sed -i 's/User=osmc/User=root/g' /etc/systemd/system/hyperion.service
sed -i 's/Group=osmc/Group=root/g' /etc/systemd/system/hyperion.service
systemctl -q daemon-reload systemctl -q daemon-reload
fi fi
elif [ $USE_SERVICE -eq 1 ]; then elif [ $USE_SERVICE -eq 1 ]; then
echo '---> Installing startup script in init.d' echo '---> Installing startup script in init.d'
# place startup script in init.d and add it to upstart (-s to respect user modified scripts) # place startup script in init.d and add it to upstart (-s to respect user modified scripts)
ln -s /opt/hyperion/init.d/hyperion.init.sh /etc/init.d/hyperion 2>/dev/null ln -s $SERVICEL/hyperion.init.sh $SERVICEP/hyperion 2>/dev/null && chmod +x $SERVICEP/hyperion
chmod +x /etc/init.d/hyperion
update-rc.d hyperion defaults 98 02 update-rc.d hyperion defaults 98 02
fi fi
#remove unwanted files/dirs
if [ $OS_OPENELEC -eq 1 ]; then
rm -r /storage/hyperion/services
else
rm -r /usr/share/hyperion/services
rm -r /opt/hyperion 2>/dev/null
fi
#chown the /config/ dir and all configs inside for hypercon config upload for non-root logins #chown the /config/ dir and all configs inside for hypercon config upload for non-root logins
if [ $OS_OSMC -eq 1 ]; then if [ $OS_OSMC -eq 1 ]; then
chown -R osmc:osmc /opt/hyperion/config chown -R osmc:osmc /etc/hyperion
elif [ $OS_RASPBIAN -eq 1 ]; then elif [ $OS_RASPBIAN -eq 1 ]; then
chown -R pi:pi /opt/hyperion/config chown -R pi:pi /etc/hyperion
fi fi
# Start the hyperion daemon # Start the hyperion daemon

View File

@ -26,22 +26,23 @@ echo '**************************************************************************
#Skip the prompt if HyperCon Remove #Skip the prompt if HyperCon Remove
if [ "$1" = "" ]; then if [ "$1" = "" ]; then
#Prompt for confirmation to proceed #Prompt for confirmation to proceed
while true while true
do do
echo -n "---> Do you really want to remove Hyperion and it´s services? (y or n) :" echo -n "---> Do you really want to remove Hyperion and it´s services? (y or n) :"
read CONFIRM read CONFIRM
case $CONFIRM in case $CONFIRM in
y|Y|YES|yes|Yes) break ;; y|Y|YES|yes|Yes) break ;;
n|N|no|NO|No) n|N|no|NO|No)
echo "---> Aborting - you entered \"$CONFIRM\"" echo "---> Aborting - you entered \"$CONFIRM\""
exit exit
;; ;;
*) echo "-> Please enter only y or n" *) echo "-> Please enter only y or n"
esac esac
done done
echo "---> You entered \"$CONFIRM\". Remove Hyperion!" echo "---> You entered \"$CONFIRM\". Remove Hyperion!"
fi fi
# Find out if we are on OpenElec or RasPlex # Find out if we are on OpenElec or RasPlex
OS_OPENELEC=`grep -m1 -c 'OpenELEC\|RasPlex\|LibreELEC' /etc/issue` OS_OPENELEC=`grep -m1 -c 'OpenELEC\|RasPlex\|LibreELEC' /etc/issue`
@ -63,10 +64,6 @@ elif [ $USE_SERVICE -eq 1 ]; then
/usr/sbin/service hyperion stop 2>/dev/null /usr/sbin/service hyperion stop 2>/dev/null
elif [ $USE_SYSTEMD -eq 1 ]; then elif [ $USE_SYSTEMD -eq 1 ]; then
service hyperion stop 2>/dev/null service hyperion stop 2>/dev/null
# while [ $SERVICEC -le 20 ]; do
# service hyperion_fw$SERVICEC stop 2>/dev/null
# ((SERVICEC++))
# done
fi fi
#reset count #reset count
@ -86,19 +83,11 @@ elif [ $USE_SYSTEMD -eq 1 ]; then
# Delete and disable Hyperion systemd script # Delete and disable Hyperion systemd script
echo '---> Delete and disable Hyperion systemd script' echo '---> Delete and disable Hyperion systemd script'
systemctl disable hyperion.service systemctl disable hyperion.service
# while [ $SERVICEC -le 20 ]; do
# systemctl -q disable hyperion_fw$SERVICEC.service 2>/dev/null
# ((SERVICEC++))
# done
rm -v /etc/systemd/system/hyperion* 2>/dev/null rm -v /etc/systemd/system/hyperion* 2>/dev/null
elif [ $USE_SERVICE -eq 1 ]; then elif [ $USE_SERVICE -eq 1 ]; then
# Delete and disable Hyperion init.d script # Delete and disable Hyperion init.d script
echo '---> Delete and disable Hyperion init.d script' echo '---> Delete and disable Hyperion init.d script'
update-rc.d -f hyperion remove update-rc.d -f hyperion remove
# while [ $SERVICEC -le 20 ]; do
# update-rc.d -f hyperion_fw$SERVICEC remove 2>/dev/null
# ((SERVICEC++))
# done
rm /etc/init.d/hyperion* 2>/dev/null rm /etc/init.d/hyperion* 2>/dev/null
fi fi
@ -116,9 +105,12 @@ else
rm -v /usr/bin/hyperion-v4l2 2>/dev/null rm -v /usr/bin/hyperion-v4l2 2>/dev/null
rm -v /usr/bin/hyperion-dispmanx 2>/dev/null rm -v /usr/bin/hyperion-dispmanx 2>/dev/null
rm -v /usr/bin/hyperion-x11 2>/dev/null rm -v /usr/bin/hyperion-x11 2>/dev/null
rm -v /usr/bin/hyperion-aml 2>/dev/null
rm -v /etc/hyperion.config.json 2>/dev/null rm -v /etc/hyperion.config.json 2>/dev/null
echo "---> Remove binaries" echo "---> Remove binaries"
rm -rv /opt/hyperion 2>/dev/null rm -rv /opt/hyperion 2>/dev/null
rm -rv /etc/hyperion 2>/dev/null
rm -rv /usr/share/hyperion 2>/dev/null
fi fi
echo '*******************************************************************************' echo '*******************************************************************************'
echo 'Hyperion successful removed!' echo 'Hyperion successful removed!'

View File

@ -0,0 +1,165 @@
#!/bin/bash
# Script to add a second or more hyperion instance(s) to the corresponding system service
# Make sure /sbin is on the path (for service to find sub scripts)
PATH="/sbin:$PATH"
#Check, if script is running as root
if [ $(id -u) != 0 ]; then
echo '---> Critical Error: Please run the script as root (sudo sh ./setup_hyperion_forward.sh) -> abort'
exit 1
fi
#Welcome message
echo '*******************************************************************************'
echo 'This setup script will duplicate the hyperion service'
echo 'Choose the name(s) for one or more config files - one service for each config'
echo 'Created by brindosch - hyperion-project.org - the official Hyperion source.'
echo '*******************************************************************************'
#Prompt for confirmation to proceed
while true
do
echo -n "---> Do you really want to proceed? (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\". We will proceed!"
echo ""
#Check which system we are on
OS_OPENELEC=`grep -m1 -c 'OpenELEC\|RasPlex\|LibreELEC' /etc/issue`
USE_SYSTEMD=`grep -m1 -c systemd /proc/1/comm`
USE_INITCTL=`which /sbin/initctl | wc -l`
USE_SERVICE=`which /usr/sbin/service | wc -l`
#Setting up the paths to service files
if [ $USE_INITCTL -eq 1 ]; then
SERVICEPATH=/etc/init
elif [ $OS_OPENELEC -eq 1 ]; then
SERVICEPATH=/storage/.config
elif [ $USE_SYSTEMD -eq 1 ]; then
SERVICEPATH=/etc/systemd/system
elif [ $USE_SERVICE -eq 1 ]; then
SERVICEPATH/etc/init.d
fi
#Setting up the default PROTO/JSON ports
JSONPORT=19444
PROTOPORT=19445
# and service count
SERVICEC=1
#Setting up the paths to config files
if [ $OS_OPENELEC -eq 1 ]; then
CONFIGPATH=/storage/.config
else CONFIGPATH=/opt/hyperion/config
fi
#Ask the user for some informations regarding the setup
echo "---> Please enter the config name(s) you want to create"
echo "---> Information: One name creates one service and two names two services etc"
echo '---> Please enter them seperated with a space in a one line row!'
echo '---> example: hyperion.philipshue_1.json hyperion.AtmoOrb_2.json hypthreeconf.json'
echo '---> In any case, add ".json" at the end of each file name'
read -p 'Config file name(s): ' FILENAMES
echo '---> Thank you, we will modify your Hyperion installation now'
sleep 2
#Processing input
set $FILENAMES
FWCOUNT=${#}
#Convert all old config file paths to make sure this script is working (default for new installs with 1.02.0 and higher)
if [ $USE_INITCTL -eq 1 ]; then
sed -i "s|/etc/hyperion.config.json|/etc/hyperion/hyperion.config.json|g" $SERVICEPATH/hyperion.conf
elif [ $OS_OPENELEC -eq 1 ]; then
sleep 0
elif [ $USE_SYSTEMD -eq 1 ]; then
sed -i "s|/etc/hyperion.config.json|/etc/hyperion/hyperion.config.json|g" $SERVICEPATH/hyperion.service
elif [ $USE_SERVICE -eq 1 ]; then
sed -i "s|/etc/hyperion.config.json|/etc/hyperion/hyperion.config.json|g" $SERVICEPATH/hyperion
fi
#Processing service files
if [ $USE_INITCTL -eq 1 ]; then
echo "---> Initctl detected, processing service files"
while [ $SERVICEC -le $FWCOUNT ]; do
echo "Processing service ${SERVICEC}: \"hyperion_fw${SERVICEC}.conf\""
if [ -e "${SERVICEPATH}/hyperion_fw${SERVICEC}.conf" ]; then
echo "Service was already created - skipped"
echo "Input \"${1}\" was skipped"
else
echo "Create ${SERVICEPATH}/hyperion_fw${SERVICEC}.conf"
cp -s $SERVICEPATH/hyperion.conf $SERVICEPATH/hyperion_fw$SERVICEC.conf
echo "Config name changed to \"${1}\" inside \"hyperion_fw${SERVICEC}.conf\""
sed -i "s/hyperion.config.json/$1/g" $SERVICEPATH/hyperion_fw$SERVICEC.conf
initctl reload-configuration
fi
shift
SERVICEC=$((SERVICEC + 1))
done
elif [ $OS_OPENELEC -eq 1 ]; then
echo "---> OE/LE detected, processing autostart.sh"
while [ $SERVICEC -le $FWCOUNT ]; do
echo "${SERVICEC}. processing OE autostart.sh entry \"${1}\""
OE=`grep -m1 -c ${1} $SERVICEPATH/autostart.sh`
if [ $OE -eq 0 ]; then
echo "Add config name \"${1}\" to \"autostart.sh\""
echo "/storage/hyperion/bin/hyperiond.sh /storage/.config/${1} > /storage/logfiles/hyperion_fw${SERVICEC}.log 2>&1 &" >> /storage/.config/autostart.sh
else
echo "\"${1}\" was already added - skipped"
fi
shift
SERVICEC=$((SERVICEC + 1))
done
elif [ $USE_SYSTEMD -eq 1 ]; then
echo "---> Systemd detected, processing service files"
while [ $SERVICEC -le $FWCOUNT ]; do
echo "Processing service ${SERVICEC}: \"hyperion_fw${SERVICEC}.service\""
if [ -e "${SERVICEPATH}/hyperion_fw${SERVICEC}.service" ]; then
echo "Service was already created - skipped"
echo "Input \"${1}\" was skipped"
else
echo "Create ${SERVICEPATH}/hyperion_fw${SERVICEC}.service"
cp -s $SERVICEPATH/hyperion.service $SERVICEPATH/hyperion_fw$SERVICEC.service
echo "Config name changed to \"${1}\" inside \"hyperion_fw${SERVICEC}.service\""
sed -i "s/hyperion.config.json/$1/g" $SERVICEPATH/hyperion_fw$SERVICEC.service
systemctl -q enable hyperion_fw$SERVICEC.service
fi
shift
SERVICEC=$((SERVICEC + 1))
done
elif [ $USE_SERVICE -eq 1 ]; then
echo "---> Init.d detected, processing service files"
while [ $SERVICEC -le $FWCOUNT ]; do
echo "Processing service ${SERVICEC}: \"hyperion_fw${SERVICEC}\""
if [ -e "${SERVICEPATH}/hyperion_fw${SERVICEC}" ]; then
echo "Service was already created - skipped"
echo "Input \"${1}\" was skipped"
else
echo "Create ${SERVICEPATH}/hyperion_fw${SERVICEC}"
cp -s $SERVICEPATH/hyperion $SERVICEPATH/hyperion_fw$SERVICEC
echo "Config name changed to \"${1}\" inside \"hyperion_fw${SERVICEC}\""
sed -i "s/hyperion.config.json/$1/g" $SERVICEPATH/hyperion_fw$SERVICEC
update-rc.d hyperion_fw$SERVICEC defaults 98 02
fi
shift
SERVICEC=$((SERVICEC + 1))
done
fi
#Service creation done
echo '*******************************************************************************'
echo 'Script done all actions - all input processed'
echo 'Now upload your configuration(s) with HyperCon at the SSH Tab'
echo 'All created Hyperion services will start with your chosen confignames'
echo 'Wiki: wiki.hyperion-project.org Webpage: www.hyperion-project.org'
echo '*******************************************************************************'

View File

@ -13,7 +13,7 @@
### END INIT INFO ### END INIT INFO
DAEMON=hyperiond DAEMON=hyperiond
DAEMONOPTS="/opt/hyperion/config/hyperion.config.json" DAEMONOPTS="/etc/hyperion/hyperion.config.json"
DAEMON_PATH="/usr/bin" DAEMON_PATH="/usr/bin"
NAME=$DAEMON NAME=$DAEMON

View File

@ -8,4 +8,4 @@ stop on (runlevel [!2345])
respawn respawn
exec /usr/bin/hyperiond /opt/hyperion/config/hyperion.config.json exec /usr/bin/hyperiond /etc/hyperion/hyperion.config.json

View File

@ -6,7 +6,7 @@ Type=simple
User=root User=root
Group=root Group=root
UMask=007 UMask=007
ExecStart=/opt/hyperion/bin/hyperiond /opt/hyperion/config/hyperion.config.json ExecStart=/usr/bin/hyperiond /etc/hyperion/hyperion.config.json
ExecReload=/bin/kill -HUP $MAINPID ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure Restart=on-failure
TimeoutStopSec=10 TimeoutStopSec=10

View File

@ -17,5 +17,5 @@ if(APPLE)
set(CoreFoundation_FOUND true) set(CoreFoundation_FOUND true)
set(CoreFoundation_INCLUDE_DIR ${CoreFoundation}) set(CoreFoundation_INCLUDE_DIR ${CoreFoundation})
set(CoreFoundation_LIBRARY ${CoreFoundation}) set(CoreFoundation_LIBRARY ${CoreFoundation})
endif(CoreFoundation) endif()
endif(APPLE) endif()

View File

@ -32,16 +32,16 @@ IF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR)
# retvale is 0 of the condition is "true" so we need to negate the value... # retvale is 0 of the condition is "true" so we need to negate the value...
if (UDEV_STABLE) if (UDEV_STABLE)
set(UDEV_STABLE 0) set(UDEV_STABLE 0)
else (UDEV_STABLE) else ()
set(UDEV_STABLE 1) set(UDEV_STABLE 1)
endif (UDEV_STABLE) endif ()
message(STATUS "libudev stable: ${UDEV_STABLE}") message(STATUS "libudev stable: ${UDEV_STABLE}")
ENDIF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR) ENDIF ()
IF (UDEV_FOUND) IF (UDEV_FOUND)
MESSAGE(STATUS "Found UDev: ${UDEV_LIBRARIES}") MESSAGE(STATUS "Found UDev: ${UDEV_LIBRARIES}")
MESSAGE(STATUS " include: ${UDEV_INCLUDE_DIR}") MESSAGE(STATUS " include: ${UDEV_INCLUDE_DIR}")
ELSE (UDEV_FOUND) ELSE ()
MESSAGE(STATUS "UDev not found.") MESSAGE(STATUS "UDev not found.")
MESSAGE(STATUS "UDev: You can specify includes: -DUDEV_PATH_INCLUDES=/opt/udev/include") MESSAGE(STATUS "UDev: You can specify includes: -DUDEV_PATH_INCLUDES=/opt/udev/include")
MESSAGE(STATUS " currently found includes: ${UDEV_INCLUDE_DIR}") MESSAGE(STATUS " currently found includes: ${UDEV_INCLUDE_DIR}")
@ -49,5 +49,5 @@ ELSE (UDEV_FOUND)
MESSAGE(STATUS " currently found libs: ${UDEV_LIBRARIES}") MESSAGE(STATUS " currently found libs: ${UDEV_LIBRARIES}")
IF (UDev_FIND_REQUIRED) IF (UDev_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find UDev library") MESSAGE(FATAL_ERROR "Could not find UDev library")
ENDIF (UDev_FIND_REQUIRED) ENDIF ()
ENDIF (UDEV_FOUND) ENDIF ()

View File

@ -69,12 +69,8 @@ else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS)
/sw/lib /sw/lib
) )
set(LIBUSB_1_INCLUDE_DIRS set(LIBUSB_1_INCLUDE_DIRS ${LIBUSB_1_INCLUDE_DIR} )
${LIBUSB_1_INCLUDE_DIR} set(LIBUSB_1_LIBRARIES ${LIBUSB_1_LIBRARY} )
)
set(LIBUSB_1_LIBRARIES
${LIBUSB_1_LIBRARY}
)
if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES)
set(LIBUSB_1_FOUND TRUE) set(LIBUSB_1_FOUND TRUE)

View File

@ -0,0 +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")
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}")
endforeach(file)

87
cmake/debian/postinst Normal file
View File

@ -0,0 +1,87 @@
#!/bin/sh
install_file()
{
src="$1"
dest="$2"
if [ -e "$dest" ] && ! cmp --quiet "$src" "$dest"
then
echo "INFO: $dest exists, new version copied to ${dest}.new"
cp "$src" "${dest}.new"
return 1
fi
cp "$src" "${dest}"
return 0
}
echo "--- hyperion ambilight postinstall ---"
echo "- install configuration template"
mkdir -p /etc/hyperion
install_file /usr/share/hyperion/config/hyperion.config.json /etc/hyperion/hyperion.config.json
HYPERION_RUNNING=false
pgrep hyperiond > /dev/null 2>&1 && HYPERION_RUNNING=true
start_msg=""
restart_msg=""
SERVICE_POSTFIX=""
if [ -e /sbin/initctl ]
then
echo "- init deamon: upstart"
# upstart
$HYPERION_RUNNING && initctl stop hyperion
install_file /usr/share/hyperion/service/hyperion.initctl.sh /etc/init/hyperion.conf || SERVICE_POSTFIX=".new"
initctl reload-configuration
start_msg="initctl start hyperion"
$HYPERION_RUNNING && initctl start hyperion
elif grep -m1 systemd /proc/1/comm > /dev/null
then
echo "- init deamon: systemd"
# systemd
$HYPERION_RUNNING && systemctl stop hyperion 2> /dev/null
install_file /usr/share/hyperion/service/hyperion.systemd.sh /etc/systemd/system/hyperion.service || SERVICE_POSTFIX=".new"
systemctl -q enable hyperion.service
start_msg="systemctl start hyperion"
$HYPERION_RUNNING && systemctl start hyperion
# if [ $OS_OSMC -eq 1 ]; then
# echo '---> Modify systemd script for OSMC usage'
# # Wait until kodi is sarted (for kodi checker)
# sed -i '/After = mediacenter.service/d' /etc/systemd/system/hyperion.service
# sed -i '/Unit/a After = mediacenter.service' /etc/systemd/system/hyperion.service
# sed -i 's/User=osmc/User=root/g' /etc/systemd/system/hyperion.service
# sed -i 's/Group=osmc/Group=root/g' /etc/systemd/system/hyperion.service
# systemctl -q daemon-reload
# fi
# systemctl start hyperion
else
echo "- init deamon: sysV"
# sysV
$HYPERION_RUNNING && service hyperion stop 2>/dev/null
install_file /usr/share/hyperion/service/hyperion.init.sh /etc/init.d/hyperion || SERVICE_POSTFIX=".new"
chmod +x /etc/init.d/hyperion
update-rc.d hyperion defaults 98 02
start_msg="service hyperion start"
$HYPERION_RUNNING && service hyperion start
fi
echo "-----------------------------------------------------------------------------"
echo "- hyperion is installed, please check your configuration in /etc/hyperion/ -"
echo "-----------------------------------------------------------------------------"
if [ -e /opt/hyperion/ ]
then
echo
echo "---------------------------------------------------------------------------------"
echo "- It seemd that you have an older version of hyperion installed in /opt/hyerion -"
echo "- please remove it and check your config to avoid problems -"
echo "---------------------------------------------------------------------------------"
fi

32
cmake/packages.cmake Normal file
View File

@ -0,0 +1,32 @@
# cmake file for generating distribution packages
SET ( CPACK_GENERATOR "DEB" "TGZ" "STGZ" ) # "RPM"
SET ( CPACK_PACKAGE_NAME "hyperion" )
SET ( CPACK_PACKAGE_DESCRIPTION_SUMMARY "Hyperion is an opensource 'AmbiLight' implementation" )
SET ( CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md" )
SET ( CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" )
SET ( CPACK_DEBIAN_PACKAGE_MAINTAINER "hyperion team")
SET ( CPACK_DEBIAN_PACKAGE_NAME "hyperion" )
SET ( CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/cmake/debian/postinst" )
SET ( CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/hyperion-project/hyperion" )
SET ( CPACK_DEBIAN_PACKAGE_DEPENDS "libqtcore4 (>= 4:4.8.0), libqt4-network (>= 4:4.8.0), libusb-1.0-0, libpython2.7, libc6" )
SET ( CPACK_DEBIAN_PACKAGE_SECTION "Miscellaneous" )
SET ( CPACK_RPM_PACKAGE_NAME "hyperion" )
SET ( CPACK_RPM_PACKAGE_URL "https://github.com/hyperion-project/hyperion" )
SET ( CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/rpm/postinst" )
SET(CPACK_PACKAGE_VERSION_MAJOR "1")
SET(CPACK_PACKAGE_VERSION_MINOR "3")
SET(CPACK_PACKAGE_VERSION_PATCH "0")
SET ( CPACK_COMPONENTS_ALL ambilight )
SET ( CPACK_ARCHIVE_COMPONENT_INSTALL ON )
SET ( CPACK_DEB_COMPONENT_INSTALL ON )
SET ( CPACK_RPM_COMPONENT_INSTALL ON )
SET ( CPACK_STRIP_FILES ON )
# no code after following line!
INCLUDE ( CPack )

View File

@ -202,7 +202,7 @@ macro (QT4_ADD_RESOURCES outfiles )
# let's make a configured file and add it as a dependency so cmake is run # let's make a configured file and add it as a dependency so cmake is run
# again when dependencies need to be recomputed. # again when dependencies need to be recomputed.
QT4_MAKE_OUTPUT_FILE("${infile}" "" "qrc.depends" out_depends) QT4_MAKE_OUTPUT_FILE("${infile}" "" "qrc.depends" out_depends)
configure_file("${infile}" "${out_depends}" COPY_ONLY) configure_file("${infile}" "${out_depends}" COPYONLY)
else() else()
# The .qrc file does not exist (yet). Let's add a dependency and hope # The .qrc file does not exist (yet). Let's add a dependency and hope
# that it will be generated later # that it will be generated later

57
cmake/rpm/postinst Normal file
View File

@ -0,0 +1,57 @@
#!/bin/sh
install_file()
{
src="$1"
dest="$2"
if [ -e "$dest" ] && ! cmp --quiet "$src" "$dest"
then
cp "$src" "${dest}.new"
else
cp "$src" "${dest}"
fi
}
echo "--- hyperion ambilight postinstall ---"
echo "- install configuration template"
mkdir -p /etc/hyperion
install_file /usr/share/hyperion/config/hyperion.config.json /etc/hyperion/hyperion.config.json
if grep -m1 systemd /proc/1/comm > /dev/null
then
# systemd
echo
systemctl stop hyperion 2> /dev/null
install_file /usr/share/hyperion/service/hyperion.systemd.sh /etc/systemd/system/hyperion.service
systemctl -q enable hyperion.service
# if [ $OS_OSMC -eq 1 ]; then
# echo '---> Modify systemd script for OSMC usage'
# # Wait until kodi is sarted (for kodi checker)
# sed -i '/After = mediacenter.service/d' /etc/systemd/system/hyperion.service
# sed -i '/Unit/a After = mediacenter.service' /etc/systemd/system/hyperion.service
# sed -i 's/User=osmc/User=root/g' /etc/systemd/system/hyperion.service
# sed -i 's/Group=osmc/Group=root/g' /etc/systemd/system/hyperion.service
# systemctl -q daemon-reload
# fi
systemctl start hyperion
elif [ -e /sbin/initctl ]
then
# upstart
install_file /usr/share/hyperion/service/hyperion.initctl.sh /etc/init/hyperion.conf
initctl reload-configuration
initctl start hyperion
else
# sysV
service hyperion stop 2>/dev/null
install_file /usr/share/hyperion/service/hyperion.init.sh /etc/init.d/hyperion
chmod +x /etc/init.d/hyperion
update-rc.d hyperion defaults 98 02
service hyperion start
fi
echo "- done"

View File

@ -1,12 +1,13 @@
// Automatically generated configuration file for 'Hyperion daemon' // This is a example config (hyperion.config.json) with comments, in any case you need to create your own one with HyperCon!
// Generated by: HyperCon (The Hyperion deamon configuration file builder) // location of all configs: /etc/hyperion
// Created with HyperCon V1.02.0 (30.04.2016) // Webpage: https://www.hyperion-project.org
{ {
/// Device configuration contains the following fields: /// Device configuration contains the following fields:
/// * 'name' : The user friendly name of the device (only used for display purposes) /// * 'name' : The user friendly name of the device (only used for display purposes)
/// * 'type' : The type of the device or leds (known types for now are /// * 'type' : The type of the device or leds (known types for now are
/// ---------SPI---------, APA102, WS2801, P9813, LPD6803, LPD8806, ---------PWM---------, WS2812b (just RPi1), WS281X (RPi1, RPi2, RPi3), --------OTHER--------, PhilipsHUE, AtmoOrb, PiBlaster, Tinkerforge, FadeCandy, RawHID (USB), UDP, SEDU, TPM2, USBASP-WS2801, USBASP-WS2812, ------3rd PARTY------, Adalight, AdalightAPA102, AmbiLed, Atmo, Lightpack, Multi-Lightpack, Paintpack, Test (file), None) /// APA102, WS2801, P9813, LPD6803, LPD8806, ---------PWM---------, WS2812b (just RPi1), WS281X (RPi1, RPi2, RPi3), --------OTHER--------, PhilipsHUE, AtmoOrb, PiBlaster, Tinkerforge, FadeCandy, RawHID (USB), UDP, SEDU, TPM2, USBASP-WS2801, USBASP-WS2812, ------3rd PARTY------, Adalight, AdalightAPA102, AmbiLed, Atmo, Lightpack, Multi-Lightpack, Paintpack, Test (file), None)
/// * [device type specific configuration] /// * [device type specific configuration]
/// * 'colorOrder' : The order of the color bytes ('rgb', 'rbg', 'bgr', etc.). /// * 'colorOrder' : The order of the color bytes ('rgb', 'rbg', 'bgr', etc.).
"device" : "device" :
@ -41,6 +42,7 @@
/// tuning parameters: /// tuning parameters:
/// - 'saturationGain' The gain adjustement of the saturation /// - 'saturationGain' The gain adjustement of the saturation
/// - 'luminanceGain' The gain adjustement of the luminance /// - 'luminanceGain' The gain adjustement of the luminance
/// - 'luminanceMinimum' The minimum luminance (backlight)
/// * 'red'/'green'/'blue' : The manipulation in the Red-Green-Blue color domain with the /// * 'red'/'green'/'blue' : The manipulation in the Red-Green-Blue color domain with the
/// following tuning parameters for each channel: /// following tuning parameters for each channel:
/// - 'threshold' The minimum required input value for the channel to be on /// - 'threshold' The minimum required input value for the channel to be on
@ -102,7 +104,8 @@
"hsl" : "hsl" :
{ {
"saturationGain" : 1.0000, "saturationGain" : 1.0000,
"luminanceGain" : 1.0000 "luminanceGain" : 1.0000,
"luminanceMinimum" : 0.0000
}, },
"red" : "red" :
{ {
@ -178,11 +181,11 @@
/// * json : Json server adress and port of your target. Syntax:[IP:PORT] -> ["127.0.0.1:19446"] or more instances to forward ["127.0.0.1:19446","192.168.0.24:19448"] /// * json : Json server adress and port of your target. Syntax:[IP:PORT] -> ["127.0.0.1:19446"] or more instances to forward ["127.0.0.1:19446","192.168.0.24:19448"]
/// HINT: If you redirect to "127.0.0.1" (localhost) you could start a second hyperion with another device/led config! /// HINT: If you redirect to "127.0.0.1" (localhost) you could start a second hyperion with another device/led config!
/// Be sure your client(s) is/are listening on the configured ports. The second Hyperion (if used) also needs to be configured! (HyperCon -> External -> Json Server/Proto Server) /// Be sure your client(s) is/are listening on the configured ports. The second Hyperion (if used) also needs to be configured! (HyperCon -> External -> Json Server/Proto Server)
// "forwarder" : "forwarder" :
// { {
// "proto" : ["127.0.0.1:19447"], "proto" : ["127.0.0.1:19447"],
// "json" : ["127.0.0.1:19446"] "json" : ["127.0.0.1:19446"]
// }, },
/// The configuration for the frame-grabber, contains the following items: /// The configuration for the frame-grabber, contains the following items:
/// * width : The width of the grabbed frames [pixels] /// * width : The width of the grabbed frames [pixels]
@ -205,19 +208,21 @@
/// * grabPictures : Flag indicating that the frame-grabber is on(true) during picture show /// * grabPictures : Flag indicating that the frame-grabber is on(true) during picture show
/// * grabAudio : Flag indicating that the frame-grabber is on(true) during audio playback /// * grabAudio : Flag indicating that the frame-grabber is on(true) during audio playback
/// * grabMenu : Flag indicating that the frame-grabber is on(true) at the Kodi menu /// * grabMenu : Flag indicating that the frame-grabber is on(true) at the Kodi menu
/// * grabPause : Flag indicating that the frame-grabber is on(true) at player state "pause"
/// * grabScreensaver : Flag indicating that the frame-grabber is on(true) when Kodi is on screensaver /// * grabScreensaver : Flag indicating that the frame-grabber is on(true) when Kodi is on screensaver
/// * enable3DDetection : Flag indicating that the frame-grabber should switch to a 3D compatible modus if a 3D video is playing /// * enable3DDetection : Flag indicating that the frame-grabber should switch to a 3D compatible modus if a 3D video is playing
// "xbmcVideoChecker" : "xbmcVideoChecker" :
// { {
// "xbmcAddress" : "127.0.0.1", "xbmcAddress" : "127.0.0.1",
// "xbmcTcpPort" : 9090, "xbmcTcpPort" : 9090,
// "grabVideo" : true, "grabVideo" : true,
// "grabPictures" : true, "grabPictures" : true,
// "grabAudio" : true, "grabAudio" : true,
// "grabMenu" : false, "grabMenu" : false,
// "grabScreensaver" : true, "grabPause" : false,
// "enable3DDetection" : true "grabScreensaver" : true,
// }, "enable3DDetection" : true
},
/// The configuration of the Json server which enables the json remote interface /// The configuration of the Json server which enables the json remote interface
/// * port : Port at which the json server is started /// * port : Port at which the json server is started
@ -236,11 +241,11 @@
/// The configuration of the boblight server which enables the boblight remote interface /// The configuration of the boblight server which enables the boblight remote interface
/// * port : Port at which the boblight server is started /// * port : Port at which the boblight server is started
/// * priority: Priority of the boblight server (Default=900) HINT: lower value result in HIGHER priority! /// * priority: Priority of the boblight server (Default=900) HINT: lower value result in HIGHER priority!
// "boblightServer" : "boblightServer" :
// { {
// "port" : 19333, "port" : 19333,
// "priority" : 900 "priority" : 900
// }, },
/// Configuration for the embedded V4L2 grabber /// Configuration for the embedded V4L2 grabber
/// * device : V4L2 Device to use [default="/dev/video0"] /// * device : V4L2 Device to use [default="/dev/video0"]
@ -259,25 +264,25 @@
/// * redSignalThreshold : Signal threshold for the red channel between 0.0 and 1.0 [default=0.0] /// * redSignalThreshold : Signal threshold for the red channel between 0.0 and 1.0 [default=0.0]
/// * greenSignalThreshold : Signal threshold for the green channel between 0.0 and 1.0 [default=0.0] /// * greenSignalThreshold : Signal threshold for the green channel between 0.0 and 1.0 [default=0.0]
/// * blueSignalThreshold : Signal threshold for the blue channel between 0.0 and 1.0 [default=0.0] /// * blueSignalThreshold : Signal threshold for the blue channel between 0.0 and 1.0 [default=0.0]
// "grabber-v4l2" : "grabber-v4l2" :
// { {
// "device" : "/dev/video0", "device" : "/dev/video0",
// "input" : 0, "input" : 0,
// "standard" : "no-change", "standard" : "no-change",
// "width" : -1, "width" : -1,
// "height" : -1, "height" : -1,
// "frameDecimation" : 2, "frameDecimation" : 2,
// "sizeDecimation" : 8, "sizeDecimation" : 8,
// "priority" : 900, "priority" : 900,
// "mode" : "2D", "mode" : "2D",
// "cropLeft" : 0, "cropLeft" : 0,
// "cropRight" : 0, "cropRight" : 0,
// "cropTop" : 0, "cropTop" : 0,
// "cropBottom" : 0, "cropBottom" : 0,
// "redSignalThreshold" : 0.0, "redSignalThreshold" : 0.0,
// "greenSignalThreshold" : 0.0, "greenSignalThreshold" : 0.0,
// "blueSignalThreshold" : 0.0 "blueSignalThreshold" : 0.0
// }, },
/// The configuration for each individual led. This contains the specification of the area /// The configuration for each individual led. This contains the specification of the area
/// averaged of an input image for each led to determine its color. Each item in the list /// averaged of an input image for each led to determine its color. Each item in the list

View File

@ -1,430 +0,0 @@
// Automatically generated configuration file for 'Hyperion daemon'
// Generated by: HyperCon (The Hyperion deamon configuration file builder
{
/// Device configuration contains the following fields:
/// * 'name' : The user friendly name of the device (only used for display purposes)
/// * 'type' : The type of the device or leds (known types for now are 'ws2801', 'ldp8806',
/// 'lpd6803', 'sedu', 'adalight', 'lightpack', 'test' and 'none')
/// * 'output' : The output specification depends on selected device. This can for example be the
/// device specifier, device serial number, or the output file name
/// * 'rate' : The baudrate of the output to the device
/// * 'colorOrder' : The order of the color bytes ('rgb', 'rbg', 'bgr', etc.).
"device" :
{
"name" : "MyPi",
"type" : "adalight",
"output" : "/dev/ttyUSB0",
"rate" : 115200,
"colorOrder" : "rgb"
},
/// Color manipulation configuration used to tune the output colors to specific surroundings.
/// The configuration contains a list of color-transforms. Each transform contains the
/// following fields:
/// * 'id' : The unique identifier of the color transformation (eg 'device_1') /// * 'leds' : The indices (or index ranges) of the leds to which this color transform applies
/// (eg '0-5, 9, 11, 12-17'). The indices are zero based. /// * 'hsv' : The manipulation in the Hue-Saturation-Value color domain with the following
/// tuning parameters:
/// - 'saturationGain' The gain adjustement of the saturation
/// - 'valueGain' The gain adjustement of the value
/// * 'red'/'green'/'blue' : The manipulation in the Red-Green-Blue color domain with the
/// following tuning parameters for each channel:
/// - 'threshold' The minimum required input value for the channel to be on
/// (else zero)
/// - 'gamma' The gamma-curve correction factor
/// - 'blacklevel' The lowest possible value (when the channel is black)
/// - 'whitelevel' The highest possible value (when the channel is white)
///
/// Next to the list with color transforms there is also a smoothing option.
/// * 'smoothing' : Smoothing of the colors in the time-domain with the following tuning
/// parameters:
/// - 'type' The type of smoothing algorithm ('linear' or 'none')
/// - 'time_ms' The time constant for smoothing algorithm in milliseconds
/// - 'updateFrequency' The update frequency of the leds in Hz
"color" :
{
"transform" :
[
{
"id" : "default",
"leds" : "*",
"hsv" :
{
"saturationGain" : 1.0000,
"valueGain" : 1.0000
},
"red" :
{
"threshold" : 0.0000,
"gamma" : 1.0000,
"blacklevel" : 0.0000,
"whitelevel" : 1.0000
},
"green" :
{
"threshold" : 0.0000,
"gamma" : 1.0000,
"blacklevel" : 0.0000,
"whitelevel" : 1.0000
},
"blue" :
{
"threshold" : 0.0000,
"gamma" : 1.0000,
"blacklevel" : 0.0000,
"whitelevel" : 1.0000
}
}
],
"smoothing" :
{
"type" : "none",
"time_ms" : 200,
"updateFrequency" : 20.0000
}
},
/// The configuration for each individual led. This contains the specification of the area
/// averaged of an input image for each led to determine its color. Each item in the list
/// contains the following fields:
/// * index: The index of the led. This determines its location in the string of leds; zero
/// being the first led.
/// * hscan: The fractional part of the image along the horizontal used for the averaging
/// (minimum and maximum inclusive)
/// * vscan: The fractional part of the image along the vertical used for the averaging
/// (minimum and maximum inclusive)
"leds" :
[
{
"index" : 0,
"hscan" : { "minimum" : 0.4375, "maximum" : 0.5000 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 1,
"hscan" : { "minimum" : 0.3750, "maximum" : 0.4375 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 2,
"hscan" : { "minimum" : 0.3125, "maximum" : 0.3750 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 3,
"hscan" : { "minimum" : 0.2500, "maximum" : 0.3125 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 4,
"hscan" : { "minimum" : 0.1875, "maximum" : 0.2500 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 5,
"hscan" : { "minimum" : 0.1250, "maximum" : 0.1875 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 6,
"hscan" : { "minimum" : 0.0625, "maximum" : 0.1250 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 7,
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0625 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 8,
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 9,
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 },
"vscan" : { "minimum" : 0.8571, "maximum" : 1.0000 }
},
{
"index" : 10,
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 },
"vscan" : { "minimum" : 0.7143, "maximum" : 0.8571 }
},
{
"index" : 11,
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 },
"vscan" : { "minimum" : 0.5714, "maximum" : 0.7143 }
},
{
"index" : 12,
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 },
"vscan" : { "minimum" : 0.4286, "maximum" : 0.5714 }
},
{
"index" : 13,
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 },
"vscan" : { "minimum" : 0.2857, "maximum" : 0.4286 }
},
{
"index" : 14,
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 },
"vscan" : { "minimum" : 0.1429, "maximum" : 0.2857 }
},
{
"index" : 15,
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.1429 }
},
{
"index" : 16,
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0500 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 17,
"hscan" : { "minimum" : 0.0000, "maximum" : 0.0625 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 18,
"hscan" : { "minimum" : 0.0625, "maximum" : 0.1250 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 19,
"hscan" : { "minimum" : 0.1250, "maximum" : 0.1875 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 20,
"hscan" : { "minimum" : 0.1875, "maximum" : 0.2500 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 21,
"hscan" : { "minimum" : 0.2500, "maximum" : 0.3125 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 22,
"hscan" : { "minimum" : 0.3125, "maximum" : 0.3750 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 23,
"hscan" : { "minimum" : 0.3750, "maximum" : 0.4375 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 24,
"hscan" : { "minimum" : 0.4375, "maximum" : 0.5000 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 25,
"hscan" : { "minimum" : 0.5000, "maximum" : 0.5625 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 26,
"hscan" : { "minimum" : 0.5625, "maximum" : 0.6250 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 27,
"hscan" : { "minimum" : 0.6250, "maximum" : 0.6875 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 28,
"hscan" : { "minimum" : 0.6875, "maximum" : 0.7500 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 29,
"hscan" : { "minimum" : 0.7500, "maximum" : 0.8125 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 30,
"hscan" : { "minimum" : 0.8125, "maximum" : 0.8750 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 31,
"hscan" : { "minimum" : 0.8750, "maximum" : 0.9375 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 32,
"hscan" : { "minimum" : 0.9375, "maximum" : 1.0000 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 33,
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.0800 }
},
{
"index" : 34,
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
"vscan" : { "minimum" : 0.0000, "maximum" : 0.1429 }
},
{
"index" : 35,
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
"vscan" : { "minimum" : 0.1429, "maximum" : 0.2857 }
},
{
"index" : 36,
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
"vscan" : { "minimum" : 0.2857, "maximum" : 0.4286 }
},
{
"index" : 37,
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
"vscan" : { "minimum" : 0.4286, "maximum" : 0.5714 }
},
{
"index" : 38,
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
"vscan" : { "minimum" : 0.5714, "maximum" : 0.7143 }
},
{
"index" : 39,
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
"vscan" : { "minimum" : 0.7143, "maximum" : 0.8571 }
},
{
"index" : 40,
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
"vscan" : { "minimum" : 0.8571, "maximum" : 1.0000 }
},
{
"index" : 41,
"hscan" : { "minimum" : 0.9500, "maximum" : 1.0000 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 42,
"hscan" : { "minimum" : 0.9375, "maximum" : 1.0000 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 43,
"hscan" : { "minimum" : 0.8750, "maximum" : 0.9375 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 44,
"hscan" : { "minimum" : 0.8125, "maximum" : 0.8750 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 45,
"hscan" : { "minimum" : 0.7500, "maximum" : 0.8125 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 46,
"hscan" : { "minimum" : 0.6875, "maximum" : 0.7500 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 47,
"hscan" : { "minimum" : 0.6250, "maximum" : 0.6875 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 48,
"hscan" : { "minimum" : 0.5625, "maximum" : 0.6250 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
},
{
"index" : 49,
"hscan" : { "minimum" : 0.5000, "maximum" : 0.5625 },
"vscan" : { "minimum" : 0.9200, "maximum" : 1.0000 }
}
],
/// The black border configuration, contains the following items:
/// * enable : true if the detector should be activated
/// * threshold : Value below which a pixel is regarded as black (value between 0.0 and 1.0)
"blackborderdetector" :
{
"enable" : true,
"threshold" : 0.01
},
/// The configuration of the effect engine, contains the following items:
/// * paths : An array with absolute location(s) of directories with effects
/// * bootsequence : The effect selected as 'boot sequence'
"effects" :
{
"paths" :
[
"/home/dincs/projects/hyperion/effects"
]
},
"bootsequence" :
{
"effect" : "Rainbow swirl fast",
"duration_ms" : 3000
},
/// The configuration for the frame-grabber, contains the following items:
/// * width : The width of the grabbed frames [pixels]
/// * height : The height of the grabbed frames [pixels]
/// * frequency_Hz : The frequency of the frame grab [Hz]
// "framegrabber" :
// {
// "width" : 64,
// "height" : 64,
// "frequency_Hz" : 10.0
// },
/// The configuration of the XBMC connection used to enable and disable the frame-grabber. Contains the following fields:
/// * xbmcAddress : The IP address of the XBMC-host
/// * xbmcTcpPort : The TCP-port of the XBMC-server
/// * grabVideo : Flag indicating that the frame-grabber is on(true) during video playback
/// * grabPictures : Flag indicating that the frame-grabber is on(true) during picture show
/// * grabAudio : Flag indicating that the frame-grabber is on(true) during audio playback
/// * grabMenu : Flag indicating that the frame-grabber is on(true) in the XBMC menu
/// * grabScreensaver : Flag indicating that the frame-grabber is on(true) when XBMC is on screensaver
/// * enable3DDetection : Flag indicating that the frame-grabber should switch to a 3D compatible modus if a 3D video is playing
// "xbmcVideoChecker" :
// {
// "xbmcAddress" : "127.0.0.1",
// "xbmcTcpPort" : 9090,
// "grabVideo" : true,
// "grabPictures" : true,
// "grabAudio" : true,
// "grabMenu" : false,
// "grabScreensaver" : true,
// "enable3DDetection" : true
// },
/// The configuration of the Json server which enables the json remote interface
/// * port : Port at which the json server is started
"jsonServer" :
{
"port" : 19444
},
/// The configuration of the Proto server which enables the protobuffer remote interface
/// * port : Port at which the protobuffer server is started
"protoServer" :
{
"port" : 19445
},
/// The configuration of the boblight server which enables the boblight remote interface
/// * port : Port at which the boblight server is started
// "boblightServer" :
// {
// "port" : 19333
// },
"endOfJson" : "endOfJson"
}

View File

@ -11,43 +11,42 @@ if(ENABLE_WS281XPWM)
external/rpi_ws281x/rpihw.c) external/rpi_ws281x/rpihw.c)
endif(ENABLE_WS281XPWM) endif(ENABLE_WS281XPWM)
if(ENABLE_PROTOBUF) set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared protobuf library")
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared protobuf library") add_subdirectory(external/protobuf)
add_subdirectory(external/protobuf)
if(CMAKE_CROSSCOMPILING) if(CMAKE_CROSSCOMPILING)
# when crosscompiling import the protoc executable targets from a file generated by a native build # when crosscompiling import the protoc executable targets from a file generated by a native build
option(IMPORT_PROTOC "Protoc export file (protoc_export.cmake) from a native build" "IMPORT_PROTOC-FILE_NOT_FOUND") option(IMPORT_PROTOC "Protoc export file (protoc_export.cmake) from a native build" "IMPORT_PROTOC-FILE_NOT_FOUND")
include(${IMPORT_PROTOC}) include(${IMPORT_PROTOC})
else() else()
# export the protoc compiler so it can be used when cross compiling # export the protoc compiler so it can be used when cross compiling
export(TARGETS protoc_compiler FILE "${CMAKE_BINARY_DIR}/protoc_export.cmake") export(TARGETS protoc_compiler FILE "${CMAKE_BINARY_DIR}/protoc_export.cmake")
endif() endif()
# define the include for the protobuf library at the parent scope # define the include for the protobuf library at the parent scope
set(PROTOBUF_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/external/protobuf/src") set(PROTOBUF_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/external/protobuf/src")
set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIRS} PARENT_SCOPE) set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIRS} PARENT_SCOPE)
# define the protoc executable at the parent scope # define the protoc executable at the parent scope
get_property(PROTOBUF_PROTOC_EXECUTABLE TARGET protoc_compiler PROPERTY LOCATION) get_property(PROTOBUF_PROTOC_EXECUTABLE TARGET protoc_compiler PROPERTY LOCATION)
set(PROTOBUF_PROTOC_EXECUTABLE ${PROTOBUF_PROTOC_EXECUTABLE} PARENT_SCOPE) set(PROTOBUF_PROTOC_EXECUTABLE ${PROTOBUF_PROTOC_EXECUTABLE} PARENT_SCOPE)
message(STATUS "Using protobuf compiler: " ${PROTOBUF_PROTOC_EXECUTABLE}) message(STATUS "Using protobuf compiler: " ${PROTOBUF_PROTOC_EXECUTABLE})
#============================================================================= #=============================================================================
# Copyright 2009 Kitware, Inc. # Copyright 2009 Kitware, Inc.
# Copyright 2009-2011 Philip Lowman <philip@yhbt.com> # Copyright 2009-2011 Philip Lowman <philip@yhbt.com>
# Copyright 2008 Esben Mose Hansen, Ange Optimization ApS # Copyright 2008 Esben Mose Hansen, Ange Optimization ApS
# #
# Distributed under the OSI-approved BSD License (the "License"); # Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details. # see accompanying file Copyright.txt for details.
# #
# This software is distributed WITHOUT ANY WARRANTY; without even the # This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information. # See the License for more information.
#============================================================================= #=============================================================================
# (To distribute this file outside of CMake, substitute the full # (To distribute this file outside of CMake, substitute the full
# License text for the above reference.) # License text for the above reference.)
function(PROTOBUF_GENERATE_CPP SRCS HDRS) function(PROTOBUF_GENERATE_CPP SRCS HDRS)
if(NOT ARGN) if(NOT ARGN)
message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() called without any proto files") message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() called without any proto files")
return() return()
@ -106,5 +105,4 @@ if(ENABLE_PROTOBUF)
set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE) set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE)
set(${SRCS} ${${SRCS}} PARENT_SCOPE) set(${SRCS} ${${SRCS}} PARENT_SCOPE)
set(${HDRS} ${${HDRS}} PARENT_SCOPE) set(${HDRS} ${${HDRS}} PARENT_SCOPE)
endfunction() endfunction()
endif()

@ -1 +1 @@
Subproject commit e053bc9be127d1f4f0cffd10e7892cd32657ecf7 Subproject commit dfcf740848898b432fe3a3170417de60f81521ee

View File

@ -1,57 +0,0 @@
BACKGROUND
---------------------------------------------------------
The UDP led device type can be used to send LED data over UDP packets.
It was originally designed to support an ESP8266 Wifi module based WS2812
LED strip controller.
I've used this to support :
- A string of 600 LEDs as xmas decorations
The effects development kit is great for these scenarios
- a 61 LED collection of concentric circles
This has been used as a "night light" and a super lo-res
TV
In each of these cases, the hyperion-remote iOS app is a great way to
control the effects.
CONFIG
---------------------------------------------------------
Simple example for devices that support a raw binary protocol.
"device" :
{
"name" : "MyPi",
"type" : "udp",
"output" : "esp201-0.home:2391", "protocol" : 0,
"rate" : 1000000,
"colorOrder" : "grb"
},
If you are using an ESP8266/Arduino device with a long LED strip, you chould use this alternate protocol.
The ESP8266/Arduino doesnt support datagram re-assembly so will never see any udp packets greater than 1450.
"device" :
{
"name" : "MyPi",
"type" : "udp",
// "output" : "esp201-0.home:2392", "protocol" : 2, "maxpacket" : 1450,
"rate" : 1000000,
"colorOrder" : "rgb"
},
PROTOCOL
---------------------------------------------------------
Simple UDP packets are sent.
Packet Format protocol 0:
3 bytes per LED as R, G, B
Packet Format protocol 2:
0: update number & 0xf;
1: fragment of this update
2: 1st led# of this update - high byte
3: 1st led# of this update - low byte
4..n 3 bytes per LED as R, G, B

Binary file not shown.

View File

@ -1,165 +0,0 @@
// Automatically generated configuration file for 'Hyperion daemon'
// Generated by: HyperCon (The Hyperion deamon configuration file builder)
// Created with HyperCon V1.00.0 (11.03.2016)
{
/// Device configuration contains the following fields:
/// * 'name' : The user friendly name of the device (only used for display purposes)
/// * 'type' : The type of the device or leds (known types for now are
/// APA102, Adalight, AdalightAPA102, AmbiLed, Atmo, Hyperion-USBASP-WS2801, Hyperion-USBASP-WS2812, Lightberry, Lightpack, LPD6803, LPD8806, Multi-Lightpack, P9813, Paintpack, PhilipsHUE, PiBlaster, SEDU, Test, ThinkerForge, TPM2, WS2801, WS2812b, None)
/// * [device type specific configuration]
/// * 'colorOrder' : The order of the color bytes ('rgb', 'rbg', 'bgr', etc.).
///
/// * 'Specific for AtmoOrb:
/// * 'transitiontime' : Set the time of transition between color of Orb (not implemented)
/// * 'port' : Multicast UDP port
/// * 'numLeds' : Number of leds in Orb
/// * 'orbIds' : The Orb ids to use
/// * 'switchOffOnBlack': Define if Orb is to switch off when black is detected
"device" :
{
"name" : "MyPi",
"type" : "atmoorb",
"output" : "239.15.18.2",
"transitiontime" : 0,
"port" : 49692,
"numLeds" : 24,
"orbIds" : "1",
"switchOffOnBlack" : true,
"colorOrder" : "rgb"
},
/// Color manipulation configuration used to tune the output colors to specific surroundings.
/// The configuration contains a list of color-transforms. Each transform contains the
/// following fields:
/// * 'id' : The unique identifier of the color transformation (eg 'device_1') /// * 'leds' : The indices (or index ranges) of the leds to which this color transform applies
/// (eg '0-5, 9, 11, 12-17'). The indices are zero based. /// * 'hsv' : The manipulation in the Hue-Saturation-Value color domain with the following
/// tuning parameters:
/// - 'saturationGain' The gain adjustement of the saturation
/// - 'valueGain' The gain adjustement of the value
/// * 'red'/'green'/'blue' : The manipulation in the Red-Green-Blue color domain with the
/// following tuning parameters for each channel:
/// - 'threshold' The minimum required input value for the channel to be on
/// (else zero)
/// - 'gamma' The gamma-curve correction factor
/// - 'blacklevel' The lowest possible value (when the channel is black)
/// - 'whitelevel' The highest possible value (when the channel is white)
///
/// Next to the list with color transforms there is also a smoothing option.
/// * 'smoothing' : Smoothing of the colors in the time-domain with the following tuning
/// parameters:
/// - 'type' The type of smoothing algorithm ('linear' or 'none')
/// - 'time_ms' The time constant for smoothing algorithm in milliseconds
/// - 'updateFrequency' The update frequency of the leds in Hz
/// - 'updateDelay' The delay of the output to leds (in periods of smoothing)
"color" :
{
"transform" :
[
{
"id" : "default",
"leds" : "*",
"hsv" :
{
"saturationGain" : 1.0000,
"valueGain" : 1.0000
},
"red" :
{
"threshold" : 0.0000,
"gamma" : 2.2000,
"blacklevel" : 0.0000,
"whitelevel" : 1.0000
},
"green" :
{
"threshold" : 0.0000,
"gamma" : 2.2000,
"blacklevel" : 0.0000,
"whitelevel" : 1.0000
},
"blue" :
{
"threshold" : 0.0000,
"gamma" : 2.2000,
"blacklevel" : 0.0000,
"whitelevel" : 1.0000
}
}
],
"smoothing" :
{
"type" : "linear",
"time_ms" : 100,
"updateFrequency" : 60.0000,
"updateDelay" : 0
}
},
/// The black border configuration, contains the following items:
/// * enable : true if the detector should be activated
/// * threshold : Value below which a pixel is regarded as black (value between 0.0 and 1.0)
/// * unknownFrameCnt : Number of frames without any detection before the border is set to 0 (default 600)
/// * borderFrameCnt : Number of frames before a consistent detected border gets set (default 50)
/// * maxInconsistentCnt : Number of inconsistent frames that are ignored before a new border gets a chance to proof consistency
/// * blurRemoveCnt : Number of pixels that get removed from the detected border to cut away blur (default 1)
/// * mode : Border detection mode (values=default,classic,osd)
"blackborderdetector" :
{
"enable" : false,
"threshold" : 0.01,
"unknownFrameCnt" : 600,
"borderFrameCnt" : 50,
"maxInconsistentCnt" : 10,
"blurRemoveCnt" : 1,
"mode" : "default"
},
/// The configuration of the effect engine, contains the following items:
/// * paths : An array with absolute location(s) of directories with effects
/// * color : Set static color after boot -> set effect to "" (empty) and input the values [R,G,B] and set duration_ms NOT to 0 (use 1) instead
/// * effect : The effect selected as 'boot sequence'
/// * duration_ms : The duration of the selected effect (0=endless)
/// * priority : The priority of the selected effect/static color (default=990) HINT: lower value result in HIGHER priority!
"effects" :
{
"paths" :
[
"/opt/hyperion/effects"
]
},
/// The configuration of the Json server which enables the json remote interface
/// * port : Port at which the json server is started
"jsonServer" :
{
"port" : 19446
},
/// The configuration of the Proto server which enables the protobuffer remote interface
/// * port : Port at which the protobuffer server is started
"protoServer" :
{
"port" : 19447
},
/// The configuration for each individual led. This contains the specification of the area
/// averaged of an input image for each led to determine its color. Each item in the list
/// contains the following fields:
/// * index: The index of the led. This determines its location in the string of leds; zero
/// being the first led.
/// * hscan: The fractional part of the image along the horizontal used for the averaging
/// (minimum and maximum inclusive)
/// * vscan: The fractional part of the image along the vertical used for the averaging
/// (minimum and maximum inclusive)
"leds" :
[
{
"index" : 0,
"hscan" : { "minimum" : 0.0000, "maximum" : 1.0000 },
"vscan" : { "minimum" : 0.0000, "maximum" : 1.0000 }
}
],
"endOfJson" : "endOfJson"
}

Binary file not shown.

Binary file not shown.

View File

@ -1,79 +0,0 @@
Fadecandy: Open Pixel Control Protocol
======================================
The Fadecandy Server (`fcserver`) operates as a bridge between LED controllers attached over USB, and visual effects that communicate via a TCP socket.
The primary protocol supported by `fcserver` is [Open Pixel Control](http://openpixelcontrol.org), a super simple way to send RGB values over a socket. We support the standard Open Pixel Control commands, as well as some Fadecandy extensions.
Socket
------
Open Pixel Control uses a TCP socket, by default on port 7890. For the best performance, remember to set TCP_NODELAY socket option.
Command Format
--------------
All OPC commands follow the same general format. All multi-byte values in Open Pixel Control are in network byte order, high byte followed by low byte.
Channel | Command | Length (N) | Data
---------- | --------- | ---------- | --------------------------
1 byte | 1 byte | 2 bytes | N bytes of message data
Set Pixel Colors
----------------
Video data arrives in a **Set Pixel Colors** command:
Byte | **Set Pixel Colors** command
------ | --------------------------------
0 | Channel Number
1 | Command (0x00)
2 - 3 | Data length
4 | Pixel #0, Red
5 | Pixel #0, Green
6 | Pixel #0, Blue
7 | Pixel #1, Red
8 | Pixel #1, Green
9 | Pixel #1, Blue
… | …
As soon as a complete Set Pixel Colors command is received, a new frame of video will be broadcast simultaneously to all attached Fadecandy devices.
Set Global Color Correction
---------------------------
The color correction data (from the 'color' configuration key) can also be changed at runtime, by sending a new blob of JSON text in a Fadecandy-specific command. Fadecandy's 16-bit System ID for Open Pixel Control's System Exclusive (0xFF) command is **0x0001**.
Byte | **Set Global Color Correction** command
------ | ------------------------------------------
0 | Channel Number (0x00, reserved)
1 | Command (0xFF, System Exclusive)
2 - 3 | Data length (JSON Length + 4)
4 - 5 | System ID (0x0001, Fadecandy)
6 - 7 | SysEx ID (0x0001, Set Global Color Correction)
8 - … | JSON Text
Set Firmware Configuration
--------------------------
The firmware supports some runtime configuration options. Any OPC client can send a new firmware configuration packet using this command. If the supplied data is shorter than the firmware's configuration buffer, only the provided bytes will be changed.
Byte | **Set Firmware Configuration** command
------ | ------------------------------------------
0 | Channel Number (0x00, reserved)
1 | Command (0xFF, System Exclusive)
2 - 3 | Data length (Configuration Length + 4)
4 - 5 | System ID (0x0001, Fadecandy)
6 - 7 | SysEx ID (0x0002, Set Firmware Configuration)
8 - … | Configuration Data
Current firmwares support the following configuration options:
Byte Offset | Bits | Description
----------- | ------ | ------------
0 | 7 … 4 | (reserved)
0 | 3 | Manual LED control bit
0 | 2 | 0 = LED shows USB activity, 1 = LED under manual control
0 | 1 | Disable keyframe interpolation
0 | 0 | Disable dithering
1 … 62 | 7 … 0 | (reserved)

View File

@ -4,7 +4,7 @@
"args" : "args" :
{ {
"rotationTime" : 60.0, "rotationTime" : 60.0,
"color" : [0,0,255], "colorRandom" : true,
"hueChange" : 30.0, "hueChange" : 30.0,
"blobs" : 5, "blobs" : 5,
"reverse" : false, "reverse" : false,

View File

@ -2,10 +2,12 @@ import hyperion
import time import time
import colorsys import colorsys
import math import math
from random import random
# Get the parameters # Get the parameters
rotationTime = float(hyperion.args.get('rotationTime', 20.0)) rotationTime = float(hyperion.args.get('rotationTime', 20.0))
color = hyperion.args.get('color', (0,0,255)) color = hyperion.args.get('color', (0,0,255))
colorRandom = bool(hyperion.args.get('colorRandom', False))
hueChange = float(hyperion.args.get('hueChange', 60.0)) hueChange = float(hyperion.args.get('hueChange', 60.0))
blobs = int(hyperion.args.get('blobs', 5)) blobs = int(hyperion.args.get('blobs', 5))
reverse = bool(hyperion.args.get('reverse', False)) reverse = bool(hyperion.args.get('reverse', False))
@ -34,6 +36,9 @@ baseColorChangeRate = max(0, baseColorChangeRate) # > 0
# Calculate the color data # Calculate the color data
baseHsv = colorsys.rgb_to_hsv(color[0]/255.0, color[1]/255.0, color[2]/255.0) baseHsv = colorsys.rgb_to_hsv(color[0]/255.0, color[1]/255.0, color[2]/255.0)
if colorRandom:
baseHsv = (random(), baseHsv[1], baseHsv[2])
colorData = bytearray() colorData = bytearray()
for i in range(hyperion.ledCount): for i in range(hyperion.ledCount):
hue = (baseHsv[0] + hueChange * math.sin(2*math.pi * i / hyperion.ledCount)) % 1.0 hue = (baseHsv[0] + hueChange * math.sin(2*math.pi * i / hyperion.ledCount)) % 1.0

9
effects/udp-mcast.json Normal file
View File

@ -0,0 +1,9 @@
{
"name" : "UDP multicast listener",
"script" : "udp.py",
"args" :
{
"ListenPort" : 2801,
"ListenIP" : "239.255.28.01"
}
}

View File

@ -3,6 +3,6 @@
"script" : "udp.py", "script" : "udp.py",
"args" : "args" :
{ {
"udpPort" : 2391 "ListenPort" : 2391
} }
} }

View File

@ -3,17 +3,33 @@ import time
import colorsys import colorsys
import socket import socket
import errno import errno
import struct
# Get the parameters # Get the parameters
udpPort = int(hyperion.args.get('udpPort', 2812)) ListenPort = int(hyperion.args.get('ListenPort', 2801))
ListenIP = hyperion.args.get('ListenIP', "")
octets = ListenIP.split('.');
UDPSock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) UDPSock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM, socket.IPPROTO_UDP)
UDPSock.setblocking(False) UDPSock.setblocking(False)
listen_addr = ("",udpPort) listen_addr = (ListenIP,ListenPort)
print "udp.py: bind socket port:",udpPort
UDPSock.bind(listen_addr) UDPSock.bind(listen_addr)
if ListenIP == "":
print "udp.py: Listening on *.*.*.*:"+str(ListenPort)
else:
print "udp.py: Listening on "+ListenIP+":"+str(ListenPort)
if len(octets) == 4 and int(octets[0]) >= 224 and int(octets[0]) < 240:
print "ListenIP is a multicast address\n"
# Multicast handling
try:
mreq = struct.pack("4sl", socket.inet_aton(ListenIP), socket.INADDR_ANY)
UDPSock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
except socket.error:
print "ERROR enabling multicast\n"
hyperion.setColor(hyperion.ledCount * bytearray((int(0), int(0), int(0))) ) hyperion.setColor(hyperion.ledCount * bytearray((int(0), int(0), int(0))) )
# Start the write data loop # Start the write data loop

60
include/bonjour/bonjourrecord.h Executable file
View File

@ -0,0 +1,60 @@
/*
Copyright (c) 2007, Trenton Schulz
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef BONJOURRECORD_H
#define BONJOURRECORD_H
#include <QtCore/QMetaType>
#include <QtCore/QString>
class BonjourRecord
{
public:
BonjourRecord() {}
BonjourRecord(const QString &name, const QString &regType, const QString &domain)
: serviceName(name), registeredType(regType), replyDomain(domain)
{}
BonjourRecord(const char *name, const char *regType, const char *domain)
{
serviceName = QString::fromUtf8(name);
registeredType = QString::fromUtf8(regType);
replyDomain = QString::fromUtf8(domain);
}
QString serviceName;
QString registeredType;
QString replyDomain;
bool operator==(const BonjourRecord &other) const {
return serviceName == other.serviceName
&& registeredType == other.registeredType
&& replyDomain == other.replyDomain;
}
};
Q_DECLARE_METATYPE(BonjourRecord)
#endif // BONJOURRECORD_H

View File

@ -0,0 +1,66 @@
/*
Copyright (c) 2007, Trenton Schulz
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef BONJOURSERVICEREGISTER_H
#define BONJOURSERVICEREGISTER_H
#include <QtCore/QObject>
#include "bonjourrecord.h"
class QSocketNotifier;
#include <dns_sd.h>
class BonjourServiceRegister : public QObject
{
Q_OBJECT
public:
BonjourServiceRegister(QObject *parent = 0);
~BonjourServiceRegister();
void registerService(const BonjourRecord &record, quint16 servicePort);
inline BonjourRecord registeredRecord() const {return finalRecord; }
signals:
void error(DNSServiceErrorType error);
void serviceRegistered(const BonjourRecord &record);
private slots:
void bonjourSocketReadyRead();
private:
static void DNSSD_API bonjourRegisterService(DNSServiceRef sdRef, DNSServiceFlags,
DNSServiceErrorType errorCode, const char *name,
const char *regtype, const char *domain,
void *context);
DNSServiceRef dnssref;
QSocketNotifier *bonjourSocket;
BonjourRecord finalRecord;
};
#endif // BONJOURSERVICEREGISTER_H

View File

@ -41,6 +41,9 @@ public:
/// ///
void setVideoMode(const VideoMode videoMode); void setVideoMode(const VideoMode videoMode);
void setCropping(const unsigned cropLeft, const unsigned cropRight,
const unsigned cropTop, const unsigned cropBottom);
/// ///
/// Captures a single snapshot of the display and writes the data to the given image. The /// Captures a single snapshot of the display and writes the data to the given image. The
/// provided image should have the same dimensions as the configured values (_width and /// provided image should have the same dimensions as the configured values (_width and
@ -68,4 +71,17 @@ private:
const unsigned _width; const unsigned _width;
/// Height of the captured snapshot [pixels] /// Height of the captured snapshot [pixels]
const unsigned _height; const unsigned _height;
// the selected VideoMode
VideoMode _videoMode;
// number of pixels to crop after capturing
unsigned _cropLeft, _cropRight, _cropTop, _cropBottom;
// temp buffer when capturing with unsupported pitch size or
// when we need to crop the image
ColorRgba* _captureBuffer;
// size of the capture buffer in Pixels
unsigned _captureBufferSize;
}; };

View File

@ -56,6 +56,9 @@ public slots:
/// ///
void stop(); void stop();
void setCropping(const unsigned cropLeft, const unsigned cropRight,
const unsigned cropTop, const unsigned cropBottom);
/// ///
/// Set the grabbing mode /// Set the grabbing mode
/// @param[in] mode The new grabbing mode /// @param[in] mode The new grabbing mode

View File

@ -6,7 +6,6 @@
// X11 includes // X11 includes
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/extensions/Xrender.h> #include <X11/extensions/Xrender.h>
#include <X11/extensions/XShm.h> #include <X11/extensions/XShm.h>
#include <sys/ipc.h> #include <sys/ipc.h>
@ -16,11 +15,15 @@ class X11Grabber
{ {
public: public:
X11Grabber(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(); virtual ~X11Grabber();
int open(); ///
/// Set the video mode (2D/3D)
/// @param[in] mode The new video mode
///
void setVideoMode(const VideoMode videoMode);
bool Setup(); bool Setup();
@ -29,6 +32,7 @@ public:
private: private:
ImageResampler _imageResampler; ImageResampler _imageResampler;
bool _useXGetImage, _XShmAvailable, _XShmPixmapAvailable, _XRenderAvailable;
int _cropLeft; int _cropLeft;
int _cropRight; int _cropRight;
int _cropTop; int _cropTop;
@ -42,6 +46,13 @@ private:
Window _window; Window _window;
XWindowAttributes _windowAttr; XWindowAttributes _windowAttr;
Pixmap _pixmap;
XRenderPictFormat* _srcFormat;
XRenderPictFormat* _dstFormat;
XRenderPictureAttributes _pictAttr;
Picture _srcPicture;
Picture _dstPicture;
unsigned _screenWidth; unsigned _screenWidth;
unsigned _screenHeight; unsigned _screenHeight;
unsigned _croppedWidth; unsigned _croppedWidth;

View File

@ -79,6 +79,12 @@ public:
/// ///
unsigned getLedCount() const; unsigned getLedCount() const;
///
/// Returns the current priority
///
/// @return The current priority
///
int getCurrentPriority() const;
/// ///
/// Returns a list of active priorities /// Returns a list of active priorities
/// ///

View File

@ -5,6 +5,8 @@
// Utility includes // Utility includes
#include <utils/ColorRgb.h> #include <utils/ColorRgb.h>
#include <utils/ColorRgbw.h>
#include <utils/RgbToRgbw.h>
/// ///
/// Interface (pure virtual base class) for LedDevices. /// Interface (pure virtual base class) for LedDevices.

View File

@ -13,6 +13,8 @@
// hyperion util // hyperion util
#include <utils/Image.h> #include <utils/Image.h>
#include <utils/ColorRgb.h> #include <utils/ColorRgb.h>
#include <utils/GrabbingMode.h>
#include <utils/VideoMode.h>
// jsoncpp includes // jsoncpp includes
#include <message.pb.h> #include <message.pb.h>
@ -23,7 +25,7 @@
class ProtoConnection : public QObject class ProtoConnection : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
/// ///
@ -82,6 +84,18 @@ private slots:
/// Try to connect to the Hyperion host /// Try to connect to the Hyperion host
void connectToHost(); void connectToHost();
///
/// Slot called when new data has arrived
///
void readData();
signals:
///
/// XBMC Video Checker Message
///
void setGrabbingMode(const GrabbingMode mode);
void setVideoMode(const VideoMode videoMode);
private: private:
@ -109,4 +123,7 @@ private:
QTimer _timer; QTimer _timer;
QAbstractSocket::SocketState _prevSocketState; QAbstractSocket::SocketState _prevSocketState;
/// The buffer used for reading data from the socket
QByteArray _receiveBuffer;
}; };

View File

@ -4,11 +4,13 @@
// hyperion includes // hyperion includes
#include <utils/Image.h> #include <utils/Image.h>
#include <utils/ColorRgb.h> #include <utils/ColorRgb.h>
#include <utils/GrabbingMode.h>
#include <utils/VideoMode.h>
// hyperion proto includes // hyperion proto includes
#include "protoserver/ProtoConnection.h" #include "protoserver/ProtoConnection.h"
/// This class handles callbacks from the V4L2 grabber /// This class handles callbacks from the V4L2 and X11 grabber
class ProtoConnectionWrapper : public QObject class ProtoConnectionWrapper : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -17,6 +19,13 @@ public:
ProtoConnectionWrapper(const std::string & address, int priority, int duration_ms, bool skipProtoReply); ProtoConnectionWrapper(const std::string & address, int priority, int duration_ms, bool skipProtoReply);
virtual ~ProtoConnectionWrapper(); virtual ~ProtoConnectionWrapper();
signals:
///
/// Forwarding XBMC Video Checker Message
///
void setGrabbingMode(const GrabbingMode mode);
void setVideoMode(const VideoMode videoMode);
public slots: public slots:
/// Handle a single image /// Handle a single image
/// @param image The image to process /// @param image The image to process

View File

@ -15,6 +15,8 @@
// hyperion includes // hyperion includes
#include <utils/Image.h> #include <utils/Image.h>
#include <utils/ColorRgb.h> #include <utils/ColorRgb.h>
#include <utils/GrabbingMode.h>
#include <utils/VideoMode.h>
// forward decl // forward decl
class ProtoClientConnection; class ProtoClientConnection;
@ -50,6 +52,13 @@ public:
public slots: public slots:
void sendImageToProtoSlaves(int priority, const Image<ColorRgb> & image, int duration_ms); void sendImageToProtoSlaves(int priority, const Image<ColorRgb> & image, int duration_ms);
signals:
///
/// Forwarding XBMC Checker
///
void grabbingMode(const GrabbingMode mode);
void videoMode(const VideoMode VideoMode);
private slots: private slots:
/// ///
/// Slot which is called when a client tries to create a new connection /// Slot which is called when a client tries to create a new connection

65
include/utils/ColorRgbw.h Normal file
View File

@ -0,0 +1,65 @@
#pragma once
// STL includes
#include <cstdint>
#include <iostream>
struct ColorRgbw;
///
/// Plain-Old-Data structure containing the red-green-blue color specification. Size of the
/// structure is exactly 3-bytes for easy writing to led-device
///
struct ColorRgbw
{
/// The red color channel
uint8_t red;
/// The green color channel
uint8_t green;
/// The blue color channel
uint8_t blue;
/// The white color channel
uint8_t white;
/// 'Black' RgbColor (0, 0, 0, 0)
static ColorRgbw BLACK;
/// 'Red' RgbColor (255, 0, 0, 0)
static ColorRgbw RED;
/// 'Green' RgbColor (0, 255, 0, 0)
static ColorRgbw GREEN;
/// 'Blue' RgbColor (0, 0, 255, 0)
static ColorRgbw BLUE;
/// 'Yellow' RgbColor (255, 255, 0, 0)
static ColorRgbw YELLOW;
/// 'White' RgbColor (0, 0, 0, 255)
static ColorRgbw WHITE;
};
/// Assert to ensure that the size of the structure is 'only' 4 bytes
static_assert(sizeof(ColorRgbw) == 4, "Incorrect size of ColorRgbw");
///
/// Stream operator to write ColorRgb to an outputstream (format "'{'[red]','[green]','[blue]'}'")
///
/// @param os The output stream
/// @param color The color to write
/// @return The output stream (with the color written to it)
///
inline std::ostream& operator<<(std::ostream& os, const ColorRgbw& color)
{
os << "{" << unsigned(color.red) << "," << unsigned(color.green) << "," << unsigned(color.blue) << "," << unsigned(color.white) << "}";
return os;
}
/// Compare operator to check if a color is 'smaller' than another color
inline bool operator<(const ColorRgbw & lhs, const ColorRgbw & rhs)
{
return (lhs.red < rhs.red) && (lhs.green < rhs.green) && (lhs.blue < rhs.blue) && (lhs.white < rhs.white);
}
/// Compare operator to check if a color is 'smaller' than or 'equal' to another color
inline bool operator<=(const ColorRgbw & lhs, const ColorRgbw & rhs)
{
return (lhs.red <= rhs.red) && (lhs.green <= rhs.green) && (lhs.blue <= rhs.blue) && (lhs.white < rhs.white);
}

View File

@ -9,6 +9,7 @@ enum GrabbingMode
GRABBINGMODE_OFF, GRABBINGMODE_OFF,
/** Frame grabbing during video */ /** Frame grabbing during video */
GRABBINGMODE_VIDEO, GRABBINGMODE_VIDEO,
GRABBINGMODE_PAUSE,
GRABBINGMODE_PHOTO, GRABBINGMODE_PHOTO,
GRABBINGMODE_AUDIO, GRABBINGMODE_AUDIO,
GRABBINGMODE_MENU, GRABBINGMODE_MENU,

View File

@ -20,7 +20,7 @@ public:
/// @param saturationGain The used saturation gain /// @param saturationGain The used saturation gain
/// @param luminanceGain The used luminance gain /// @param luminanceGain The used luminance gain
/// ///
HslTransform(double saturationGain, double luminanceGain); HslTransform(double saturationGain, double luminanceGain, double luminanceMinimum);
/// ///
/// Destructor /// Destructor
@ -55,6 +55,20 @@ public:
/// ///
double getLuminanceGain() const; double getLuminanceGain() const;
///
/// Updates the luminance minimum
///
/// @param luminanceMinimum New luminance minimum
///
void setLuminanceMinimum(double luminanceMinimum);
///
/// Returns the luminance minimum
///
/// @return The current luminance minimum
///
double getLuminanceMinimum() const;
/// ///
/// Apply the transform the the given RGB values. /// Apply the transform the the given RGB values.
/// ///
@ -97,4 +111,6 @@ private:
double _saturationGain; double _saturationGain;
/// The luminance gain /// The luminance gain
double _luminanceGain; double _luminanceGain;
/// The luminance minimum
double _luminanceMinimum;
}; };

View File

@ -22,8 +22,7 @@ public:
void set3D(VideoMode mode); void set3D(VideoMode mode);
void processImage(const uint8_t * data, int width, int height, int lineLength, PixelFormat pixelFormat, void processImage(const uint8_t * data, int width, int height, int lineLength, PixelFormat pixelFormat, Image<ColorRgb> & outputImage) const;
Image<ColorRgb> & outputImage) const;
private: private:
static inline uint8_t clamp(int x); static inline uint8_t clamp(int x);

48
include/utils/Logger.h Normal file
View File

@ -0,0 +1,48 @@
#pragma once
#include <string>
#include <stdio.h>
#include <stdarg.h>
#include <map>
// standard log messages
//#define _FUNCNAME_ __PRETTY_FUNCTION__
#define _FUNCNAME_ __FUNCTION__
#define Debug(logger, ...) { (logger)->Message(Logger::DEBUG , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__); }
#define Info(logger, ...) { (logger)->Message(Logger::INFO , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__); }
#define Warning(logger, ...) { (logger)->Message(Logger::WARNING, __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__); }
#define Error(logger, ...) { (logger)->Message(Logger::ERROR , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__); }
// conditional log messages
#define DebugIf(condition, logger, ...) { if (condition) {(logger)->Message(Logger::DEBUG , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__);} }
#define InfoIf(condition, logger, ...) { if (condition) {(logger)->Message(Logger::INFO , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__);} }
#define WarningIf(condition, logger, ...) { if (condition) {(logger)->Message(Logger::WARNING , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__);} }
#define ErrorIf(condition, logger, ...) { if (condition) {(logger)->Message(Logger::ERROR , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__);} }
// ================================================================
class Logger
{
public:
enum LogLevel { DEBUG=0, INFO=1,WARNING=2,ERROR=3 };
static Logger* getInstance(std::string name="", LogLevel minLevel=Logger::INFO);
void Message(LogLevel level, const char* sourceFile, const char* func, unsigned int line, const char* fmt, ...);
void setMinLevel(LogLevel level) { _minLevel = level; };
protected:
Logger( std::string name="", LogLevel minLevel=INFO);
~Logger();
private:
static std::map<std::string,Logger*> *LoggerMap;
std::string _name;
std::string _appname;
LogLevel _minLevel;
bool _syslogEnabled;
unsigned int _loggerId;
};

37
include/utils/Profiler.h Normal file
View File

@ -0,0 +1,37 @@
#include "utils/Logger.h"
#include <string>
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include <map>
#ifndef ENABLE_PROFILER
#error "Profiler is not for productive code, enable it via cmake or remove header include"
#endif
// profiler
#define PROFILER_BLOCK_EXECUTION_TIME Profiler DEBUG_PROFILE__BLOCK__EXECUTION__TIME_messure_object(__FILE__, _FUNCNAME_, __LINE__ );
#define PROFILER_TIMER_START(stopWatchName) Profiler::TimerStart(stopWatchName, __FILE__, _FUNCNAME_, __LINE__);
#define PROFILER_TIMER_GET(stopWatchName) Profiler::TimerGetTime(stopWatchName, __FILE__, _FUNCNAME_, __LINE__);
#define PROFILER_TIMER_GET_IF(condition, stopWatchName) { if (condition) {Profiler::TimerGetTime(stopWatchName, __FILE__, _FUNCNAME_, __LINE__);} }
class Profiler
{
public:
Profiler(const char* sourceFile, const char* func, unsigned int line);
~Profiler();
static void TimerStart(const std::string stopWatchName, const char* sourceFile, const char* func, unsigned int line);
static void TimerGetTime(const std::string stopWatchName, const char* sourceFile, const char* func, unsigned int line);
private:
static void initLogger();
static Logger* _logger;
const char* _file;
const char* _func;
unsigned int _line;
unsigned int _blockId;
clock_t _startTime;
};

View File

@ -0,0 +1,4 @@
#include <utils/ColorRgb.h>
#include <utils/ColorRgbw.h>
void Rgb_to_Rgbw(ColorRgb input, ColorRgbw * output, std::string _whiteAlgorithm);

View File

@ -41,7 +41,7 @@ public:
/// @param grabScreensaver Whether or not to grab when the XBMC screensaver is activated /// @param grabScreensaver Whether or not to grab when the XBMC screensaver is activated
/// @param enable3DDetection Wheter or not to enable the detection of 3D movies playing /// @param enable3DDetection Wheter or not to enable the detection of 3D movies playing
/// ///
XBMCVideoChecker(const std::string & address, uint16_t port, bool grabVideo, bool grabPhoto, bool grabAudio, bool grabMenu, bool grabScreensaver, bool enable3DDetection); XBMCVideoChecker(const std::string & address, uint16_t port, bool grabVideo, bool grabPhoto, bool grabAudio, bool grabMenu, bool grabPause, bool grabScreensaver, bool enable3DDetection);
/// ///
/// Start polling XBMC /// Start polling XBMC
@ -117,6 +117,9 @@ private:
/// Flag indicating whether or not to grab when XBMC is playing nothing (in menu) /// Flag indicating whether or not to grab when XBMC is playing nothing (in menu)
const bool _grabMenu; const bool _grabMenu;
/// Flag indicating whether or not to grab when the XBMC videoplayer is at pause state
const bool _grabPause;
/// Flag indicating whether or not to grab when the XBMC screensaver is activated /// Flag indicating whether or not to grab when the XBMC screensaver is activated
const bool _grabScreensaver; const bool _grabScreensaver;

View File

@ -7,9 +7,11 @@ add_subdirectory(hyperion)
add_subdirectory(blackborder) add_subdirectory(blackborder)
add_subdirectory(jsonserver) add_subdirectory(jsonserver)
if (ENABLE_PROTOBUF) add_subdirectory(protoserver)
add_subdirectory(protoserver)
endif (ENABLE_PROTOBUF) if (ENABLE_ZEROCONF)
add_subdirectory(bonjour)
endif (ENABLE_ZEROCONF)
add_subdirectory(boblightserver) add_subdirectory(boblightserver)
add_subdirectory(leddevice) add_subdirectory(leddevice)

View File

@ -18,10 +18,10 @@ set(BoblightServer_SOURCES
) )
if(ENABLE_QT5) if(ENABLE_QT5)
qt5_wrap_cpp(BoblightServer_HEADERS_MOC ${BoblightServer_QT_HEADERS}) qt5_wrap_cpp(BoblightServer_HEADERS_MOC ${BoblightServer_QT_HEADERS})
else(ENABLE_QT5) else()
qt4_wrap_cpp(BoblightServer_HEADERS_MOC ${BoblightServer_QT_HEADERS}) qt4_wrap_cpp(BoblightServer_HEADERS_MOC ${BoblightServer_QT_HEADERS})
endif(ENABLE_QT5) endif()
add_library(boblightserver add_library(boblightserver
${BoblightServer_HEADERS} ${BoblightServer_HEADERS}
@ -31,8 +31,8 @@ add_library(boblightserver
) )
if(ENABLE_QT5) if(ENABLE_QT5)
qt5_use_modules(boblightserver Widgets) qt5_use_modules(boblightserver Widgets)
endif(ENABLE_QT5) endif()
target_link_libraries(boblightserver target_link_libraries(boblightserver
hyperion hyperion

View File

@ -0,0 +1,52 @@
# Define the current source locations
set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/bonjour)
set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/bonjour)
# Group the headers that go through the MOC compiler
set(Bonjour_QT_HEADERS
${CURRENT_HEADER_DIR}/bonjourrecord.h
${CURRENT_HEADER_DIR}/bonjourserviceregister.h
)
set(Bonjour_HEADERS
)
set(Bonjour_SOURCES
${CURRENT_SOURCE_DIR}/bonjourserviceregister.cpp
)
set(Bonjour_RESOURCES
)
if(ENABLE_QT5)
qt5_wrap_cpp(Bonjour_HEADERS_MOC ${Bonjour_QT_HEADERS})
qt5_add_resources(Bonjour_RESOURCES_RCC ${Bonjour_RESOURCES} OPTIONS "-no-compress")
else(ENABLE_QT5)
qt4_wrap_cpp(Bonjour_HEADERS_MOC ${Bonjour_QT_HEADERS})
qt4_add_resources(Bonjour_RESOURCES_RCC ${Bonjour_RESOURCES} OPTIONS "-no-compress")
endif(ENABLE_QT5)
add_library(bonjour
${Bonjour_HEADERS}
${Bonjour_QT_HEADERS}
${Bonjour_SOURCES}
${Bonjour_RESOURCES}
${Bonjour_HEADERS_MOC}
${Bonjour_RESOURCES_RCC}
)
if(ENABLE_QT5)
qt5_use_modules(bonjour Widgets Network)
endif(ENABLE_QT5)
target_link_libraries(bonjour
libdns_sd.a
libavahi-client.a
libavahi-common.a
libavahi-core.a
libavahi-qt4.a
libdbus-1.a
hyperion
hyperion-utils
${QT_LIBRARIES})

View File

@ -0,0 +1,102 @@
/*
Copyright (c) 2007, Trenton Schulz
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//#include "bonjourserviceregister.h"
#include <bonjour/bonjourserviceregister.h>
#include <QtCore/QSocketNotifier>
BonjourServiceRegister::BonjourServiceRegister(QObject *parent)
: QObject(parent), dnssref(0), bonjourSocket(0)
{
}
BonjourServiceRegister::~BonjourServiceRegister()
{
if (dnssref) {
DNSServiceRefDeallocate(dnssref);
dnssref = 0;
}
}
void BonjourServiceRegister::registerService(const BonjourRecord &record, quint16 servicePort)
{
if (dnssref) {
qWarning("Warning: Already registered a service for this object, aborting new register");
return;
}
quint16 bigEndianPort = servicePort;
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
{
bigEndianPort = 0 | ((servicePort & 0x00ff) << 8) | ((servicePort & 0xff00) >> 8);
}
#endif
DNSServiceErrorType err = DNSServiceRegister(&dnssref, 0, 0, record.serviceName.toUtf8().constData(),
record.registeredType.toUtf8().constData(),
record.replyDomain.isEmpty() ? 0
: record.replyDomain.toUtf8().constData(), 0,
bigEndianPort, 0, 0, bonjourRegisterService, this);
if (err != kDNSServiceErr_NoError) {
emit error(err);
} else {
int sockfd = DNSServiceRefSockFD(dnssref);
if (sockfd == -1) {
emit error(kDNSServiceErr_Invalid);
} else {
bonjourSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this);
connect(bonjourSocket, SIGNAL(activated(int)), this, SLOT(bonjourSocketReadyRead()));
}
}
}
void BonjourServiceRegister::bonjourSocketReadyRead()
{
DNSServiceErrorType err = DNSServiceProcessResult(dnssref);
if (err != kDNSServiceErr_NoError)
emit error(err);
}
void BonjourServiceRegister::bonjourRegisterService(DNSServiceRef, DNSServiceFlags,
DNSServiceErrorType errorCode, const char *name,
const char *regtype, const char *domain,
void *data)
{
BonjourServiceRegister *serviceRegister = static_cast<BonjourServiceRegister *>(data);
if (errorCode != kDNSServiceErr_NoError) {
emit serviceRegister->error(errorCode);
} else {
serviceRegister->finalRecord = BonjourRecord(QString::fromUtf8(name),
QString::fromUtf8(regtype),
QString::fromUtf8(domain));
emit serviceRegister->serviceRegistered(serviceRegister->finalRecord);
}
}

View File

@ -0,0 +1,15 @@
HEADERS = server.h \
bonjourserviceregister.h
SOURCES = server.cpp \
main.cpp \
bonjourserviceregister.cpp
QT += network
!mac:x11:LIBS+=-ldns_sd
win32 {
LIBS+=-ldnssd
# Add your path to bonjour here.
LIBPATH=C:/Temp/mDNSResponder-107.6/mDNSWindows/DLL/Debug
INCLUDEPATH += c:/Temp/mDNSResponder-107.6/mDNSShared
}

39
libsrc/bonjour/main.cpp Executable file
View File

@ -0,0 +1,39 @@
/****************************************************************************
**
** Copyright (C) 2004-2007 Trolltech ASA. All rights reserved.
**
** This file is part of the example classes of the Qt Toolkit.
**
** This file may be used under the terms of the GNU General Public
** License version 2.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
** http://www.trolltech.com/products/qt/opensource.html
**
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://www.trolltech.com/products/qt/licensing.html or contact the
** sales department at sales@trolltech.com.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include <QApplication>
#include <QtCore>
#include <stdlib.h>
#include "server.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Server server;
server.show();
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
int x = server.exec();
return x;
}

96
libsrc/bonjour/server.cpp Executable file
View File

@ -0,0 +1,96 @@
/****************************************************************************
**
** Copyright (C) 2004-2007 Trolltech ASA. All rights reserved.
**
** This file is part of the example classes of the Qt Toolkit.
**
** This file may be used under the terms of the GNU General Public
** License version 2.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
** http://www.trolltech.com/products/qt/opensource.html
**
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://www.trolltech.com/products/qt/licensing.html or contact the
** sales department at sales@trolltech.com.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include <QtGui>
#include <QtNetwork>
#include <stdlib.h>
#include "server.h"
#include "bonjourserviceregister.h"
Server::Server(QWidget *parent)
: QDialog(parent)
{
setWindowModality(Qt::ApplicationModal);
statusLabel = new QLabel;
quitButton = new QPushButton(tr("Quit"));
quitButton->setAutoDefault(false);
tcpServer = new QTcpServer(this);
if (!tcpServer->listen()) {
QMessageBox::critical(this, tr("Fortune Server"),
tr("Unable to start the server: %1.")
.arg(tcpServer->errorString()));
close();
return;
}
statusLabel->setText(tr("The server is running on port %1.\n"
"Run the Fortune Client example now.")
.arg(tcpServer->serverPort()));
fortunes << tr("You've been leading a dog's life. Stay off the furniture.")
<< tr("You've got to think about tomorrow.")
<< tr("You will be surprised by a loud noise.")
<< tr("You will feel hungry again in another hour.")
<< tr("You might have mail.")
<< tr("You cannot kill time without injuring eternity.")
<< tr("Computers are not intelligent. They only think they are.");
connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendFortune()));
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch(1);
buttonLayout->addWidget(quitButton);
buttonLayout->addStretch(1);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(statusLabel);
mainLayout->addLayout(buttonLayout);
setLayout(mainLayout);
bonjourRegister = new BonjourServiceRegister(this);
bonjourRegister->registerService(BonjourRecord(tr("Fortune Server on %1").arg(QHostInfo::localHostName()),
QLatin1String("_trollfortune._tcp"), QString()),
tcpServer->serverPort());
setWindowTitle(tr("Fortune Server"));
}
void Server::sendFortune()
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << (quint16)0;
out << fortunes.at(qrand() % fortunes.size());
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));
QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
connect(clientConnection, SIGNAL(disconnected()),
clientConnection, SLOT(deleteLater()));
clientConnection->write(block);
clientConnection->disconnectFromHost();
}

52
libsrc/bonjour/server.h Executable file
View File

@ -0,0 +1,52 @@
/****************************************************************************
**
** Copyright (C) 2004-2007 Trolltech ASA. All rights reserved.
**
** This file is part of the example classes of the Qt Toolkit.
**
** This file may be used under the terms of the GNU General Public
** License version 2.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
** http://www.trolltech.com/products/qt/opensource.html
**
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://www.trolltech.com/products/qt/licensing.html or contact the
** sales department at sales@trolltech.com.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef SERVER_H
#define SERVER_H
#include <QDialog>
class QLabel;
class QPushButton;
class QTcpServer;
class BonjourServiceRegister;
class Server : public QDialog
{
Q_OBJECT
public:
Server(QWidget *parent = 0);
private slots:
void sendFortune();
private:
QLabel *statusLabel;
QPushButton *quitButton;
QTcpServer *tcpServer;
QStringList fortunes;
BonjourServiceRegister *bonjourRegister;
};
#endif

View File

@ -26,16 +26,15 @@ SET(EffectEngineSOURCES
${CURRENT_SOURCE_DIR}/Effect.cpp ${CURRENT_SOURCE_DIR}/Effect.cpp
) )
set(EffectEngine_RESOURCES ${CURRENT_SOURCE_DIR}/EffectEngine.qrc) set(EffectEngine_RESOURCES ${CURRENT_SOURCE_DIR}/EffectEngine.qrc)
if(ENABLE_QT5) if(ENABLE_QT5)
QT5_WRAP_CPP(EffectEngineHEADERS_MOC ${EffectEngineQT_HEADERS}) QT5_WRAP_CPP(EffectEngineHEADERS_MOC ${EffectEngineQT_HEADERS})
qt5_add_resources(EffectEngine_RESOURCES_RCC ${EffectEngine_RESOURCES} OPTIONS "-no-compress") qt5_add_resources(EffectEngine_RESOURCES_RCC ${EffectEngine_RESOURCES} OPTIONS "-no-compress")
else(ENABLE_QT5) else()
QT4_WRAP_CPP(EffectEngineHEADERS_MOC ${EffectEngineQT_HEADERS}) QT4_WRAP_CPP(EffectEngineHEADERS_MOC ${EffectEngineQT_HEADERS})
qt4_add_resources(EffectEngine_RESOURCES_RCC ${EffectEngine_RESOURCES} OPTIONS "-no-compress") qt4_add_resources(EffectEngine_RESOURCES_RCC ${EffectEngine_RESOURCES} OPTIONS "-no-compress")
endif(ENABLE_QT5) endif()
add_library(effectengine add_library(effectengine
${EffectEngineHEADERS} ${EffectEngineHEADERS}
@ -46,8 +45,8 @@ add_library(effectengine
) )
if(ENABLE_QT5) if(ENABLE_QT5)
qt5_use_modules(effectengine Widgets) qt5_use_modules(effectengine Widgets)
endif(ENABLE_QT5) endif()
target_link_libraries(effectengine target_link_libraries(effectengine
hyperion hyperion

View File

@ -35,12 +35,9 @@ EffectEngine::EffectEngine(Hyperion * hyperion, const Json::Value & jsonEffectCo
{ {
const std::string & path = paths[i].asString(); const std::string & path = paths[i].asString();
QDir directory(QString::fromStdString(path)); QDir directory(QString::fromStdString(path));
if (!directory.exists()) if (directory.exists())
{ {
std::cerr << "EFFECTENGINE ERROR: Effect directory can not be loaded: " << path << std::endl; int efxCount = 0;
continue;
}
QStringList filenames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase); QStringList filenames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase);
foreach (const QString & filename, filenames) foreach (const QString & filename, filenames)
{ {
@ -48,8 +45,16 @@ EffectEngine::EffectEngine(Hyperion * hyperion, const Json::Value & jsonEffectCo
if (loadEffectDefinition(path, filename.toStdString(), def)) if (loadEffectDefinition(path, filename.toStdString(), def))
{ {
_availableEffects.push_back(def); _availableEffects.push_back(def);
efxCount++;
} }
} }
std::cerr << "EFFECTENGINE INFO: " << efxCount << " effects loaded from directory " << path << std::endl;
}
}
if (_availableEffects.size() == 0)
{
std::cerr << "EFFECTENGINE ERROR: no effects found, check your effect directories" << std::endl;
} }
// initialize the python interpreter // initialize the python interpreter

View File

@ -78,6 +78,7 @@ void AmlogicWrapper::setGrabbingMode(const GrabbingMode mode)
switch (mode) switch (mode)
{ {
case GRABBINGMODE_VIDEO: case GRABBINGMODE_VIDEO:
case GRABBINGMODE_PAUSE:
// _frameGrabber->setFlags(DISPMANX_SNAPSHOT_NO_RGB|DISPMANX_SNAPSHOT_FILL); // _frameGrabber->setFlags(DISPMANX_SNAPSHOT_NO_RGB|DISPMANX_SNAPSHOT_FILL);
start(); start();
break; break;

View File

@ -23,9 +23,9 @@ SET(DispmanxGrabberSOURCES
if(ENABLE_QT5) if(ENABLE_QT5)
QT5_WRAP_CPP(DispmanxGrabberHEADERS_MOC ${DispmanxGrabberQT_HEADERS}) QT5_WRAP_CPP(DispmanxGrabberHEADERS_MOC ${DispmanxGrabberQT_HEADERS})
else(ENABLE_QT5) else()
QT4_WRAP_CPP(DispmanxGrabberHEADERS_MOC ${DispmanxGrabberQT_HEADERS}) QT4_WRAP_CPP(DispmanxGrabberHEADERS_MOC ${DispmanxGrabberQT_HEADERS})
endif(ENABLE_QT5) endif()
add_library(dispmanx-grabber add_library(dispmanx-grabber
${DispmanxGrabberHEADERS} ${DispmanxGrabberHEADERS}

View File

@ -11,7 +11,14 @@ DispmanxFrameGrabber::DispmanxFrameGrabber(const unsigned width, const unsigned
_vc_resource(0), _vc_resource(0),
_vc_flags(0), _vc_flags(0),
_width(width), _width(width),
_height(height) _height(height),
_videoMode(VIDEO_2D),
_cropLeft(0),
_cropRight(0),
_cropTop(0),
_cropBottom(0),
_captureBuffer(new ColorRgba[0]),
_captureBufferSize(0)
{ {
// Initiase BCM // Initiase BCM
bcm_host_init(); bcm_host_init();
@ -49,6 +56,8 @@ DispmanxFrameGrabber::DispmanxFrameGrabber(const unsigned width, const unsigned
DispmanxFrameGrabber::~DispmanxFrameGrabber() DispmanxFrameGrabber::~DispmanxFrameGrabber()
{ {
delete[] _captureBuffer;
// Clean up resources // Clean up resources
vc_dispmanx_resource_delete(_vc_resource); vc_dispmanx_resource_delete(_vc_resource);
@ -63,38 +72,147 @@ void DispmanxFrameGrabber::setFlags(const int vc_flags)
void DispmanxFrameGrabber::setVideoMode(const VideoMode videoMode) void DispmanxFrameGrabber::setVideoMode(const VideoMode videoMode)
{ {
switch (videoMode) { _videoMode = videoMode;
case VIDEO_3DSBS: }
vc_dispmanx_rect_set(&_rectangle, 0, 0, _width/2, _height);
break; void DispmanxFrameGrabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom)
case VIDEO_3DTAB: {
vc_dispmanx_rect_set(&_rectangle, 0, 0, _width, _height/2); if (cropLeft + cropRight >= _width || cropTop + cropBottom >= _height)
break; {
case VIDEO_2D: std::cout
default: << "DISPMANXGRABBER ERROR: Rejecting invalid crop values"
vc_dispmanx_rect_set(&_rectangle, 0, 0, _width, _height); << " left: " << cropLeft
break; << " right: " << cropRight
<< " top: " << cropTop
<< " bottom: " << cropBottom
<< std::endl;
return;
}
_cropLeft = cropLeft;
_cropRight = cropRight;
_cropTop = cropTop;
_cropBottom = cropBottom;
if (cropLeft > 0 || cropRight > 0 || cropTop > 0 || cropBottom > 0)
{
std::cout
<< "DISPMANXGRABBER INFO: Cropping " << _width << "x" << _height << " image"
<< " left: " << cropLeft
<< " right: " << cropRight
<< " top: " << cropTop
<< " bottom: " << cropBottom
<< std::endl;
} }
} }
void DispmanxFrameGrabber::grabFrame(Image<ColorRgba> & image) void DispmanxFrameGrabber::grabFrame(Image<ColorRgba> & image)
{ {
// resize the given image if needed int ret;
if (image.width() != unsigned(_rectangle.width) || image.height() != unsigned(_rectangle.height))
// vc_dispmanx_resource_read_data doesn't seem to work well
// with arbitrary positions so we have to handle cropping by ourselves
unsigned cropLeft = _cropLeft;
unsigned cropRight = _cropRight;
unsigned cropTop = _cropTop;
unsigned cropBottom = _cropBottom;
if (_vc_flags & DISPMANX_SNAPSHOT_FILL)
{ {
image.resize(_rectangle.width, _rectangle.height); // disable cropping, we are capturing the video overlay window
cropLeft = cropRight = cropTop = cropBottom = 0;
}
unsigned imageWidth = _width - cropLeft - cropRight;
unsigned imageHeight = _height - cropTop - cropBottom;
// calculate final image dimensions and adjust top/left cropping in 3D modes
switch (_videoMode)
{
case VIDEO_3DSBS:
imageWidth = imageWidth / 2;
cropLeft = cropLeft / 2;
break;
case VIDEO_3DTAB:
imageHeight = imageHeight / 2;
cropTop = cropTop / 2;
break;
case VIDEO_2D:
default:
break;
}
// resize the given image if needed
if (image.width() != imageWidth || image.height() != imageHeight)
{
image.resize(imageWidth, imageHeight);
} }
// Open the connection to the display // Open the connection to the display
_vc_display = vc_dispmanx_display_open(0); _vc_display = vc_dispmanx_display_open(0);
if (_vc_display < 0)
{
std::cout << "DISPMANXGRABBER ERROR: Cannot open display: " << _vc_display << std::endl;
return;
}
// Create the snapshot (incl down-scaling) // Create the snapshot (incl down-scaling)
vc_dispmanx_snapshot(_vc_display, _vc_resource, (DISPMANX_TRANSFORM_T) _vc_flags); ret = vc_dispmanx_snapshot(_vc_display, _vc_resource, (DISPMANX_TRANSFORM_T) _vc_flags);
if (ret < 0)
{
std::cout << "DISPMANXGRABBER ERROR: Snapshot failed: " << ret << std::endl;
vc_dispmanx_display_close(_vc_display);
return;
}
// Read the snapshot into the memory // Read the snapshot into the memory
void* image_ptr = image.memptr(); void* imagePtr = image.memptr();
const unsigned destPitch = _rectangle.width * sizeof(ColorRgba); void* capturePtr = imagePtr;
vc_dispmanx_resource_read_data(_vc_resource, &_rectangle, image_ptr, destPitch);
unsigned imagePitch = imageWidth * sizeof(ColorRgba);
// dispmanx seems to require the pitch to be a multiple of 64
unsigned capturePitch = (_rectangle.width * sizeof(ColorRgba) + 63) & (~63);
// grab to temp buffer if image pitch isn't valid or if we are cropping
if (imagePitch != capturePitch
|| (unsigned)_rectangle.width != imageWidth
|| (unsigned)_rectangle.height != imageHeight)
{
// check if we need to resize the capture buffer
unsigned captureSize = capturePitch * _rectangle.height / sizeof(ColorRgba);
if (_captureBufferSize != captureSize)
{
delete[] _captureBuffer;
_captureBuffer = new ColorRgba[captureSize];
_captureBufferSize = captureSize;
}
capturePtr = &_captureBuffer[0];
}
ret = vc_dispmanx_resource_read_data(_vc_resource, &_rectangle, capturePtr, capturePitch);
if (ret < 0)
{
std::cout << "DISPMANXGRABBER ERROR: vc_dispmanx_resource_read_data failed: " << ret << std::endl;
vc_dispmanx_display_close(_vc_display);
return;
}
// copy capture data to image if we captured to temp buffer
if (imagePtr != capturePtr)
{
// adjust source pointer to top/left cropping
uint8_t* src_ptr = (uint8_t*) capturePtr
+ cropLeft * sizeof(ColorRgba)
+ cropTop * capturePitch;
for (unsigned y = 0; y < imageHeight; y++)
{
memcpy((uint8_t*)imagePtr + y * imagePitch,
src_ptr + y * capturePitch,
imagePitch);
}
}
// Close the displaye // Close the displaye
vc_dispmanx_display_close(_vc_display); vc_dispmanx_display_close(_vc_display);

View File

@ -74,6 +74,7 @@ void DispmanxWrapper::setGrabbingMode(const GrabbingMode mode)
switch (mode) switch (mode)
{ {
case GRABBINGMODE_VIDEO: case GRABBINGMODE_VIDEO:
case GRABBINGMODE_PAUSE:
_frameGrabber->setFlags(DISPMANX_SNAPSHOT_NO_RGB|DISPMANX_SNAPSHOT_FILL); _frameGrabber->setFlags(DISPMANX_SNAPSHOT_NO_RGB|DISPMANX_SNAPSHOT_FILL);
start(); start();
break; break;
@ -94,3 +95,9 @@ void DispmanxWrapper::setVideoMode(const VideoMode mode)
{ {
_frameGrabber->setVideoMode(mode); _frameGrabber->setVideoMode(mode);
} }
void DispmanxWrapper::setCropping(const unsigned cropLeft, const unsigned cropRight,
const unsigned cropTop, const unsigned cropBottom)
{
_frameGrabber->setCropping(cropLeft, cropRight, cropTop, cropBottom);
}

View File

@ -23,9 +23,9 @@ SET(FramebufferGrabberSOURCES
if(ENABLE_QT5) if(ENABLE_QT5)
QT5_WRAP_CPP(FramebufferGrabberHEADERS_MOC ${FramebufferGrabberQT_HEADERS}) QT5_WRAP_CPP(FramebufferGrabberHEADERS_MOC ${FramebufferGrabberQT_HEADERS})
else(ENABLE_QT5) else()
QT4_WRAP_CPP(FramebufferGrabberHEADERS_MOC ${FramebufferGrabberQT_HEADERS}) QT4_WRAP_CPP(FramebufferGrabberHEADERS_MOC ${FramebufferGrabberQT_HEADERS})
endif(ENABLE_QT5) endif()
add_library(framebuffer-grabber add_library(framebuffer-grabber
${FramebufferGrabberHEADERS} ${FramebufferGrabberHEADERS}

View File

@ -62,6 +62,7 @@ void FramebufferWrapper::setGrabbingMode(const GrabbingMode mode)
switch (mode) switch (mode)
{ {
case GRABBINGMODE_VIDEO: case GRABBINGMODE_VIDEO:
case GRABBINGMODE_PAUSE:
case GRABBINGMODE_AUDIO: case GRABBINGMODE_AUDIO:
case GRABBINGMODE_PHOTO: case GRABBINGMODE_PHOTO:
case GRABBINGMODE_MENU: case GRABBINGMODE_MENU:

View File

@ -18,9 +18,9 @@ SET(OsxGrabberSOURCES
if(ENABLE_QT5) if(ENABLE_QT5)
QT5_WRAP_CPP(OsxGrabberHEADERS_MOC ${OsxGrabberQT_HEADERS}) QT5_WRAP_CPP(OsxGrabberHEADERS_MOC ${OsxGrabberQT_HEADERS})
else(ENABLE_QT5) else()
QT4_WRAP_CPP(OsxGrabberHEADERS_MOC ${OsxGrabberQT_HEADERS}) QT4_WRAP_CPP(OsxGrabberHEADERS_MOC ${OsxGrabberQT_HEADERS})
endif(ENABLE_QT5) endif()
add_library(osx-grabber add_library(osx-grabber
${OsxGrabberHEADERS} ${OsxGrabberHEADERS}

View File

@ -62,6 +62,7 @@ void OsxWrapper::setGrabbingMode(const GrabbingMode mode)
switch (mode) switch (mode)
{ {
case GRABBINGMODE_VIDEO: case GRABBINGMODE_VIDEO:
case GRABBINGMODE_PAUSE:
case GRABBINGMODE_AUDIO: case GRABBINGMODE_AUDIO:
case GRABBINGMODE_PHOTO: case GRABBINGMODE_PHOTO:
case GRABBINGMODE_MENU: case GRABBINGMODE_MENU:

View File

@ -17,10 +17,10 @@ SET(V4L2_SOURCES
) )
if(ENABLE_QT5) if(ENABLE_QT5)
QT5_WRAP_CPP(V4L2_HEADERS_MOC ${V4L2_QT_HEADERS}) QT5_WRAP_CPP(V4L2_HEADERS_MOC ${V4L2_QT_HEADERS})
else(ENABLE_QT5) else()
QT4_WRAP_CPP(V4L2_HEADERS_MOC ${V4L2_QT_HEADERS}) QT4_WRAP_CPP(V4L2_HEADERS_MOC ${V4L2_QT_HEADERS})
endif(ENABLE_QT5) endif()
add_library(v4l2-grabber add_library(v4l2-grabber
${V4L2_HEADERS} ${V4L2_HEADERS}

View File

@ -23,10 +23,10 @@ SET(X11_SOURCES
) )
if(ENABLE_QT5) if(ENABLE_QT5)
QT5_WRAP_CPP(X11_HEADERS_MOC ${X11_QT_HEADERS}) QT5_WRAP_CPP(X11_HEADERS_MOC ${X11_QT_HEADERS})
else(ENABLE_QT5) else()
QT4_WRAP_CPP(X11_HEADERS_MOC ${X11_QT_HEADERS}) QT4_WRAP_CPP(X11_HEADERS_MOC ${X11_QT_HEADERS})
endif(ENABLE_QT5) endif()
add_library(x11-grabber add_library(x11-grabber
${X11_HEADERS} ${X11_HEADERS}

View File

@ -2,19 +2,22 @@
#include <iostream> #include <iostream>
#include <cstdint> #include <cstdint>
// X11 includes
#include <X11/Xutil.h>
// X11Grabber includes // X11Grabber includes
#include <grabber/X11Grabber.h> #include <grabber/X11Grabber.h>
X11Grabber::X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation) : X11Grabber::X11Grabber(bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation) :
_imageResampler(), _imageResampler(),
_useXGetImage(useXGetImage),
_cropLeft(cropLeft), _cropLeft(cropLeft),
_cropRight(cropRight), _cropRight(cropRight),
_cropTop(cropTop), _cropTop(cropTop),
_cropBottom(cropBottom), _cropBottom(cropBottom),
_x11Display(nullptr), _x11Display(nullptr),
_pixmap(None),
_srcFormat(nullptr),
_dstFormat(nullptr),
_srcPicture(None),
_dstPicture(None),
_screenWidth(0), _screenWidth(0),
_screenHeight(0), _screenHeight(0),
_croppedWidth(0), _croppedWidth(0),
@ -23,7 +26,9 @@ X11Grabber::X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom,
{ {
_imageResampler.setHorizontalPixelDecimation(horizontalPixelDecimation); _imageResampler.setHorizontalPixelDecimation(horizontalPixelDecimation);
_imageResampler.setVerticalPixelDecimation(verticalPixelDecimation); _imageResampler.setVerticalPixelDecimation(verticalPixelDecimation);
_imageResampler.setCropping(0, 0, 0, 0); // cropping is performed by XShmGetImage _imageResampler.setCropping(0, 0, 0, 0); // cropping is performed by XShmGetImage or XGetImage
memset(&_pictAttr, 0, sizeof(_pictAttr));
_pictAttr.repeat = RepeatNone;
} }
X11Grabber::~X11Grabber() X11Grabber::~X11Grabber()
@ -35,26 +40,53 @@ X11Grabber::~X11Grabber()
} }
} }
void X11Grabber::setVideoMode(const VideoMode videoMode)
{
_imageResampler.set3D(videoMode);
}
void X11Grabber::freeResources() void X11Grabber::freeResources()
{ {
// Cleanup allocated resources of the X11 grab // Cleanup allocated resources of the X11 grab
XShmDetach(_x11Display, &_shminfo);
XDestroyImage(_xImage); XDestroyImage(_xImage);
if(_XShmAvailable && !_useXGetImage) {
XShmDetach(_x11Display, &_shminfo);
shmdt(_shminfo.shmaddr); shmdt(_shminfo.shmaddr);
shmctl(_shminfo.shmid, IPC_RMID, 0); shmctl(_shminfo.shmid, IPC_RMID, 0);
}
if (_XRenderAvailable && !_useXGetImage) {
XRenderFreePicture(_x11Display, _srcPicture);
XRenderFreePicture(_x11Display, _dstPicture);
XFreePixmap(_x11Display, _pixmap);
}
} }
void X11Grabber::setupResources() void X11Grabber::setupResources()
{ {
if(_XShmAvailable && !_useXGetImage) {
_xImage = XShmCreateImage(_x11Display, _windowAttr.visual, _xImage = XShmCreateImage(_x11Display, _windowAttr.visual,
_windowAttr.depth, ZPixmap, NULL, &_shminfo, _windowAttr.depth, ZPixmap, NULL, &_shminfo,
_croppedWidth, _croppedHeight); _croppedWidth, _croppedHeight);
_shminfo.shmid = shmget(IPC_PRIVATE, _xImage->bytes_per_line * _xImage->height, IPC_CREAT|0777); _shminfo.shmid = shmget(IPC_PRIVATE, _xImage->bytes_per_line * _xImage->height, IPC_CREAT|0777);
_shminfo.shmaddr = _xImage->data = (char*)shmat(_shminfo.shmid,0,0); _xImage->data = (char*)shmat(_shminfo.shmid,0,0);
_shminfo.shmaddr = _xImage->data;
_shminfo.readOnly = False; _shminfo.readOnly = False;
XShmAttach(_x11Display, &_shminfo); 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);
}
} }
bool X11Grabber::Setup() bool X11Grabber::Setup()
@ -63,23 +95,60 @@ bool X11Grabber::Setup()
if (_x11Display == nullptr) if (_x11Display == nullptr)
{ {
std::cerr << "X11GRABBER ERROR: Unable to open display"; std::cerr << "X11GRABBER ERROR: Unable to open display";
if (getenv("DISPLAY")) if (getenv("DISPLAY")) {
std::cerr << " " << std::string(getenv("DISPLAY")) << std::endl; std::cerr << " " << std::string(getenv("DISPLAY")) << std::endl;
else } else {
std::cerr << ". DISPLAY environment variable not set" << std::endl; std::cerr << ". DISPLAY environment variable not set" << std::endl;
}
return false; return false;
} }
_window = DefaultRootWindow(_x11Display); _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;
return true; return true;
} }
Image<ColorRgb> & X11Grabber::grab() Image<ColorRgb> & X11Grabber::grab()
{ {
updateScreenDimensions(); updateScreenDimensions();
XShmGetImage(_x11Display, _window, _xImage, _cropLeft, _cropTop, 0x00FFFFFF); if (_XRenderAvailable && !_useXGetImage) {
XRenderComposite( _x11Display, // *dpy,
PictOpSrc, // op,
_srcPicture, // src
None, // mask
_dstPicture, // dst
_cropLeft, // src_x
_cropTop, // src_y
0, // mask_x
0, // mask_y
0, // dst_x
0, // dst_y
_croppedWidth, // width
_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) if (_xImage == nullptr)
{ {
std::cerr << "X11GRABBER ERROR: Grab failed" << std::endl; std::cerr << "X11GRABBER ERROR: Grab failed" << std::endl;
@ -108,23 +177,30 @@ int X11Grabber::updateScreenDimensions()
std::cout << "X11GRABBER INFO: Update of screen resolution: [" << _screenWidth << "x" << _screenHeight <<"] => "; std::cout << "X11GRABBER INFO: Update of screen resolution: [" << _screenWidth << "x" << _screenHeight <<"] => ";
if (_screenWidth || _screenHeight) if (_screenWidth || _screenHeight) {
freeResources(); freeResources();
}
_screenWidth = _windowAttr.width; _screenWidth = _windowAttr.width;
_screenHeight = _windowAttr.height; _screenHeight = _windowAttr.height;
std::cout << "[" << _screenWidth << "x" << _screenHeight <<"]" << std::endl; std::cout << "[" << _screenWidth << "x" << _screenHeight <<"]" << std::endl;
if (_screenWidth > unsigned(_cropLeft + _cropRight)) _croppedWidth = (_screenWidth > unsigned(_cropLeft + _cropRight))
_croppedWidth = _screenWidth - _cropLeft - _cropRight; ? (_screenWidth - _cropLeft - _cropRight)
else : _screenWidth;
_croppedWidth = _screenWidth;
if (_screenHeight > unsigned(_cropTop + _cropBottom)) _croppedHeight = (_screenHeight > unsigned(_cropTop + _cropBottom))
_croppedHeight = _screenHeight - _cropTop - _cropBottom; ? (_screenHeight - _cropTop - _cropBottom)
else : _screenHeight;
_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(); setupResources();

View File

@ -38,17 +38,17 @@ SET(Hyperion_SOURCES
${CURRENT_SOURCE_DIR}/MessageForwarder.cpp ${CURRENT_SOURCE_DIR}/MessageForwarder.cpp
) )
set(Hyperion_RESOURCES SET(Hyperion_RESOURCES
${CURRENT_SOURCE_DIR}/resource.qrc ${CURRENT_SOURCE_DIR}/resource.qrc
) )
if(ENABLE_QT5) if(ENABLE_QT5)
QT5_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS}) QT5_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS})
QT5_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress") QT5_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress")
else(ENABLE_QT5) else()
QT4_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS}) QT4_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS})
QT4_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress") QT4_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress")
endif(ENABLE_QT5) endif()
add_library(hyperion add_library(hyperion
${Hyperion_HEADERS} ${Hyperion_HEADERS}
@ -59,8 +59,8 @@ add_library(hyperion
) )
if(ENABLE_QT5) if(ENABLE_QT5)
qt5_use_modules(hyperion Widgets) qt5_use_modules(hyperion Widgets)
endif(ENABLE_QT5) endif()
target_link_libraries(hyperion target_link_libraries(hyperion
blackborder blackborder

View File

@ -452,8 +452,9 @@ HslTransform * Hyperion::createHslTransform(const Json::Value & hslConfig)
{ {
const double saturationGain = hslConfig.get("saturationGain", 1.0).asDouble(); const double saturationGain = hslConfig.get("saturationGain", 1.0).asDouble();
const double luminanceGain = hslConfig.get("luminanceGain", 1.0).asDouble(); const double luminanceGain = hslConfig.get("luminanceGain", 1.0).asDouble();
const double luminanceMinimum = hslConfig.get("luminanceMinimum", 0.0).asDouble();
return new HslTransform(saturationGain, luminanceGain); return new HslTransform(saturationGain, luminanceGain, luminanceMinimum);
} }
RgbChannelTransform* Hyperion::createRgbChannelTransform(const Json::Value& colorConfig) RgbChannelTransform* Hyperion::createRgbChannelTransform(const Json::Value& colorConfig)
@ -479,7 +480,7 @@ RgbChannelCorrection* Hyperion::createRgbChannelCorrection(const Json::Value& co
RgbChannelAdjustment* Hyperion::createRgbChannelAdjustment(const Json::Value& colorConfig, const RgbChannel color) RgbChannelAdjustment* Hyperion::createRgbChannelAdjustment(const Json::Value& colorConfig, const RgbChannel color)
{ {
int varR, varG, varB; int varR=0, varG=0, varB=0;
if (color == RED) if (color == RED)
{ {
varR = colorConfig.get("redChannel", 255).asInt(); varR = colorConfig.get("redChannel", 255).asInt();
@ -617,10 +618,10 @@ MessageForwarder * Hyperion::getForwarder()
Hyperion::Hyperion(const Json::Value &jsonConfig) : Hyperion::Hyperion(const Json::Value &jsonConfig) :
_ledString(createLedString(jsonConfig["leds"], createColorOrder(jsonConfig["device"]))), _ledString(createLedString(jsonConfig["leds"], createColorOrder(jsonConfig["device"]))),
_muxer(_ledString.leds().size()), _muxer(_ledString.leds().size()),
_raw2ledAdjustment(createLedColorsAdjustment(_ledString.leds().size(), jsonConfig["color"])), _raw2ledTransform(createLedColorsTransform(_ledString.leds().size(), jsonConfig["color"])),
_raw2ledCorrection(createLedColorsCorrection(_ledString.leds().size(), jsonConfig["color"])), _raw2ledCorrection(createLedColorsCorrection(_ledString.leds().size(), jsonConfig["color"])),
_raw2ledTemperature(createLedColorsTemperature(_ledString.leds().size(), jsonConfig["color"])), _raw2ledTemperature(createLedColorsTemperature(_ledString.leds().size(), jsonConfig["color"])),
_raw2ledTransform(createLedColorsTransform(_ledString.leds().size(), jsonConfig["color"])), _raw2ledAdjustment(createLedColorsAdjustment(_ledString.leds().size(), jsonConfig["color"])),
_device(LedDeviceFactory::construct(jsonConfig["device"])), _device(LedDeviceFactory::construct(jsonConfig["device"])),
_effectEngine(nullptr), _effectEngine(nullptr),
_messageForwarder(createMessageForwarder(jsonConfig["forwarder"])), _messageForwarder(createMessageForwarder(jsonConfig["forwarder"])),
@ -818,6 +819,11 @@ void Hyperion::clearall()
_effectEngine->allChannelsCleared(); _effectEngine->allChannelsCleared();
} }
int Hyperion::getCurrentPriority() const
{
return _muxer.getCurrentPriority();
}
QList<int> Hyperion::getActivePriorities() const QList<int> Hyperion::getActivePriorities() const
{ {
return _muxer.getPriorities(); return _muxer.getPriorities();
@ -860,9 +866,9 @@ void Hyperion::update()
// Apply the correction and the transform to each led and color-channel // Apply the correction and the transform to each led and color-channel
// Avoid applying correction, the same task is performed by adjustment // Avoid applying correction, the same task is performed by adjustment
// std::vector<ColorRgb> correctedColors = _raw2ledCorrection->applyCorrection(priorityInfo.ledColors); // std::vector<ColorRgb> correctedColors = _raw2ledCorrection->applyCorrection(priorityInfo.ledColors);
std::vector<ColorRgb> adjustedColors = _raw2ledAdjustment->applyAdjustment(priorityInfo.ledColors); std::vector<ColorRgb> transformColors =_raw2ledTransform->applyTransform(priorityInfo.ledColors);
std::vector<ColorRgb> transformColors =_raw2ledTransform->applyTransform(adjustedColors); std::vector<ColorRgb> adjustedColors = _raw2ledAdjustment->applyAdjustment(transformColors);
std::vector<ColorRgb> ledColors = _raw2ledTemperature->applyCorrection(transformColors); std::vector<ColorRgb> ledColors = _raw2ledTemperature->applyCorrection(adjustedColors);
const std::vector<Led>& leds = _ledString.leds(); const std::vector<Led>& leds = _ledString.leds();
int i = 0; int i = 0;
for (ColorRgb& color : ledColors) for (ColorRgb& color : ledColors)
@ -885,18 +891,14 @@ void Hyperion::update()
break; break;
case ORDER_GBR: case ORDER_GBR:
{ {
uint8_t temp = color.red; std::swap(color.red, color.green);
color.red = color.green; std::swap(color.green, color.blue);
color.green = color.blue;
color.blue = temp;
break; break;
} }
case ORDER_BRG: case ORDER_BRG:
{ {
uint8_t temp = color.red; std::swap(color.red, color.blue);
color.red = color.blue; std::swap(color.green, color.blue);
color.blue = color.green;
color.green = temp;
break; break;
} }
} }

View File

@ -14,7 +14,8 @@ LinearColorSmoothing::LinearColorSmoothing(
_updateInterval(1000 / ledUpdateFrequency_hz), _updateInterval(1000 / ledUpdateFrequency_hz),
_settlingTime(settlingTime_ms), _settlingTime(settlingTime_ms),
_timer(), _timer(),
_outputDelay(updateDelay) _outputDelay(updateDelay),
_writeToLedsEnable(true)
{ {
_timer.setSingleShot(false); _timer.setSingleShot(false);
_timer.setInterval(_updateInterval); _timer.setInterval(_updateInterval);
@ -82,9 +83,11 @@ void LinearColorSmoothing::updateLeds()
_previousTime = now; _previousTime = now;
queueColors(_previousValues); queueColors(_previousValues);
_writeToLedsEnable = false;
} }
else else
{ {
_writeToLedsEnable = true;
float k = 1.0f - 1.0f * deltaTime / (_targetTime - _previousTime); float k = 1.0f - 1.0f * deltaTime / (_targetTime - _previousTime);
for (size_t i = 0; i < _previousValues.size(); ++i) for (size_t i = 0; i < _previousValues.size(); ++i)
@ -107,6 +110,7 @@ void LinearColorSmoothing::queueColors(const std::vector<ColorRgb> & ledColors)
if (_outputDelay == 0) if (_outputDelay == 0)
{ {
// No output delay => immediate write // No output delay => immediate write
if ( _writeToLedsEnable )
_ledDevice->write(ledColors); _ledDevice->write(ledColors);
} }
else else
@ -116,6 +120,7 @@ void LinearColorSmoothing::queueColors(const std::vector<ColorRgb> & ledColors)
// If the delay-buffer is filled pop the front and write to device // If the delay-buffer is filled pop the front and write to device
if (_outputQueue.size() > _outputDelay) if (_outputQueue.size() > _outputDelay)
{ {
if ( _writeToLedsEnable )
_ledDevice->write(_outputQueue.front()); _ledDevice->write(_outputQueue.front());
_outputQueue.pop_front(); _outputQueue.pop_front();
} }

View File

@ -80,4 +80,6 @@ private:
/** The output queue */ /** The output queue */
std::list<std::vector<ColorRgb> > _outputQueue; std::list<std::vector<ColorRgb> > _outputQueue;
// prevent sending data to device when no intput data is sent
bool _writeToLedsEnable;
}; };

View File

@ -89,13 +89,15 @@ std::vector<ColorRgb> MultiColorAdjustment::applyAdjustment(const std::vector<Co
ColorRgb& color = ledColors[i]; ColorRgb& color = ledColors[i];
int RR = adjustment->_rgbRedAdjustment.adjustmentR(color.red); int RR = adjustment->_rgbRedAdjustment.adjustmentR(color.red);
int RG = adjustment->_rgbRedAdjustment.adjustmentG(color.red); int RG = color.red > color.green ? adjustment->_rgbRedAdjustment.adjustmentG(color.red-color.green) : 0;
int RB = adjustment->_rgbRedAdjustment.adjustmentB(color.red); int RB = color.red > color.blue ? adjustment->_rgbRedAdjustment.adjustmentB(color.red-color.blue) : 0;
int GR = adjustment->_rgbGreenAdjustment.adjustmentR(color.green);
int GR = color.green > color.red ? adjustment->_rgbGreenAdjustment.adjustmentR(color.green-color.red) : 0;
int GG = adjustment->_rgbGreenAdjustment.adjustmentG(color.green); int GG = adjustment->_rgbGreenAdjustment.adjustmentG(color.green);
int GB = adjustment->_rgbGreenAdjustment.adjustmentB(color.green); int GB = color.green > color.blue ? adjustment->_rgbGreenAdjustment.adjustmentB(color.green-color.blue) : 0;
int BR = adjustment->_rgbBlueAdjustment.adjustmentR(color.blue);
int BG = adjustment->_rgbBlueAdjustment.adjustmentG(color.blue); int BR = color.blue > color.red ? adjustment->_rgbBlueAdjustment.adjustmentR(color.blue-color.red) : 0;
int BG = color.blue > color.green ? adjustment->_rgbBlueAdjustment.adjustmentG(color.blue-color.green) : 0;
int BB = adjustment->_rgbBlueAdjustment.adjustmentB(color.blue); int BB = adjustment->_rgbBlueAdjustment.adjustmentB(color.blue);
int ledR = RR + GR + BR; int ledR = RR + GR + BR;

View File

@ -68,6 +68,11 @@
"type" : "number", "type" : "number",
"required" : false, "required" : false,
"minimum" : 0.0 "minimum" : 0.0
},
"luminanceMinimum" : {
"type" : "number",
"required" : false,
"minimum" : 0.0
} }
}, },
"additionalProperties" : false "additionalProperties" : false
@ -283,6 +288,10 @@
"type" : "boolean", "type" : "boolean",
"required" : true "required" : true
}, },
"grabPause" : {
"type" : "boolean",
"required" : false
},
"grabScreensaver" : { "grabScreensaver" : {
"type" : "boolean", "type" : "boolean",
"required" : false "required" : false

View File

@ -21,12 +21,12 @@ set(JsonServer_RESOURCES
${CURRENT_SOURCE_DIR}/JsonSchemas.qrc ${CURRENT_SOURCE_DIR}/JsonSchemas.qrc
) )
if(ENABLE_QT5) if(ENABLE_QT5)
qt5_wrap_cpp(JsonServer_HEADERS_MOC ${JsonServer_QT_HEADERS}) qt5_wrap_cpp(JsonServer_HEADERS_MOC ${JsonServer_QT_HEADERS})
qt5_add_resources(JsonServer_RESOURCES_RCC ${JsonServer_RESOURCES} OPTIONS "-no-compress") qt5_add_resources(JsonServer_RESOURCES_RCC ${JsonServer_RESOURCES} OPTIONS "-no-compress")
else(ENABLE_QT5) else()
qt4_wrap_cpp(JsonServer_HEADERS_MOC ${JsonServer_QT_HEADERS}) qt4_wrap_cpp(JsonServer_HEADERS_MOC ${JsonServer_QT_HEADERS})
qt4_add_resources(JsonServer_RESOURCES_RCC ${JsonServer_RESOURCES} OPTIONS "-no-compress") qt4_add_resources(JsonServer_RESOURCES_RCC ${JsonServer_RESOURCES} OPTIONS "-no-compress")
endif(ENABLE_QT5) endif()
add_library(jsonserver add_library(jsonserver
${JsonServer_HEADERS} ${JsonServer_HEADERS}
@ -38,8 +38,8 @@ add_library(jsonserver
) )
if(ENABLE_QT5) if(ENABLE_QT5)
qt5_use_modules(jsonserver Widgets Network) qt5_use_modules(jsonserver Widgets Network)
endif(ENABLE_QT5) endif()
target_link_libraries(jsonserver target_link_libraries(jsonserver
hyperion hyperion

View File

@ -1,6 +1,7 @@
// system includes // system includes
#include <stdexcept> #include <stdexcept>
#include <cassert> #include <cassert>
#include <iomanip>
// stl includes // stl includes
#include <iostream> #include <iostream>
@ -21,6 +22,7 @@
#include <hyperion/ColorCorrection.h> #include <hyperion/ColorCorrection.h>
#include <hyperion/ColorAdjustment.h> #include <hyperion/ColorAdjustment.h>
#include <utils/ColorRgb.h> #include <utils/ColorRgb.h>
#include <HyperionConfig.h>
// project includes // project includes
#include "JsonClientConnection.h" #include "JsonClientConnection.h"
@ -455,6 +457,7 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &)
transform["valueGain"] = colorTransform->_hsvTransform.getValueGain(); transform["valueGain"] = colorTransform->_hsvTransform.getValueGain();
transform["saturationLGain"] = colorTransform->_hslTransform.getSaturationGain(); transform["saturationLGain"] = colorTransform->_hslTransform.getSaturationGain();
transform["luminanceGain"] = colorTransform->_hslTransform.getLuminanceGain(); transform["luminanceGain"] = colorTransform->_hslTransform.getLuminanceGain();
transform["luminanceMinimum"] = colorTransform->_hslTransform.getLuminanceMinimum();
Json::Value & threshold = transform["threshold"]; Json::Value & threshold = transform["threshold"];
threshold.append(colorTransform->_rgbRedTransform.getThreshold()); threshold.append(colorTransform->_rgbRedTransform.getThreshold());
@ -529,6 +532,74 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &)
activeEffects.append(activeEffect); activeEffects.append(activeEffect);
} }
////////////////////////////////////
// collect active static led color//
////////////////////////////////////
// create New JSON Array Value "activeLEDColor"
Json::Value & activeLedColors = info["activeLedColor"] = Json::Value(Json::arrayValue);
// get current Priority from Hyperion Muxer
const Hyperion::InputInfo & priorityInfo = _hyperion->getPriorityInfo(_hyperion->getCurrentPriority());
// check if current Priority exist
if (priorityInfo.priority != std::numeric_limits<int>::max())
{
Json::Value LEDcolor;
// check if all LEDs has the same Color
if (std::all_of(priorityInfo.ledColors.begin(), priorityInfo.ledColors.end(), [&](ColorRgb color)
{
return ((color.red == priorityInfo.ledColors.begin()->red) &&
(color.green == priorityInfo.ledColors.begin()->green) &&
(color.blue == priorityInfo.ledColors.begin()->blue));
} ))
{
// check if LED Color not Black (0,0,0)
if ((priorityInfo.ledColors.begin()->red != 0) &&
(priorityInfo.ledColors.begin()->green != 0) &&
(priorityInfo.ledColors.begin()->blue != 0))
{
// add RGB Value to Array
LEDcolor["RGB Value"].append(priorityInfo.ledColors.begin()->red);
LEDcolor["RGB Value"].append(priorityInfo.ledColors.begin()->green);
LEDcolor["RGB Value"].append(priorityInfo.ledColors.begin()->blue);
uint16_t Hue;
float Saturation, Luminace;
// add HSL Value to Array
HslTransform::rgb2hsl(priorityInfo.ledColors.begin()->red,
priorityInfo.ledColors.begin()->green,
priorityInfo.ledColors.begin()->blue,
Hue, Saturation, Luminace);
LEDcolor["HSL Value"].append(Hue);
LEDcolor["HSL Value"].append(Saturation);
LEDcolor["HSL Value"].append(Luminace);
// add HEX Value to Array
std::stringstream hex;
hex << "0x"
<< std::uppercase << std::setw(2) << std::setfill('0')
<< std::hex << unsigned(priorityInfo.ledColors.begin()->red)
<< std::uppercase << std::setw(2) << std::setfill('0')
<< std::hex << unsigned(priorityInfo.ledColors.begin()->green)
<< std::uppercase << std::setw(2) << std::setfill('0')
<< std::hex << unsigned(priorityInfo.ledColors.begin()->blue);
LEDcolor["HEX Value"].append(hex.str());
activeLedColors.append(LEDcolor);
}
}
}
// Add Hyperion Version, build time
Json::Value & version = info["hyperion_build"] = Json::Value(Json::arrayValue);
Json::Value ver;
ver["version"] = HYPERION_VERSION_ID;
ver["time"] = __DATE__ " " __TIME__;
version.append(ver);
// send the result // send the result
sendMessage(result); sendMessage(result);
} }
@ -590,6 +661,11 @@ void JsonClientConnection::handleTransformCommand(const Json::Value &message)
colorTransform->_hslTransform.setLuminanceGain(transform["luminanceGain"].asDouble()); colorTransform->_hslTransform.setLuminanceGain(transform["luminanceGain"].asDouble());
} }
if (transform.isMember("luminanceMinimum"))
{
colorTransform->_hslTransform.setLuminanceMinimum(transform["luminanceMinimum"].asDouble());
}
if (transform.isMember("threshold")) if (transform.isMember("threshold"))
{ {
const Json::Value & values = transform["threshold"]; const Json::Value & values = transform["threshold"];

View File

@ -29,6 +29,7 @@ JsonServer::JsonServer(Hyperion *hyperion, uint16_t port) :
// make sure the resources are loaded (they may be left out after static linking // make sure the resources are loaded (they may be left out after static linking
Q_INIT_RESOURCE(JsonSchemas); Q_INIT_RESOURCE(JsonSchemas);
} }
JsonServer::~JsonServer() JsonServer::~JsonServer()

View File

@ -35,6 +35,11 @@
"required" : false, "required" : false,
"minimum" : 0.0 "minimum" : 0.0
}, },
"luminanceMinimum" : {
"type" : "number",
"required" : false,
"minimum" : 0.0
},
"threshold": { "threshold": {
"type": "array", "type": "array",
"required": false, "required": false,

View File

@ -9,7 +9,8 @@ find_package(Threads REQUIRED)
include_directories( include_directories(
../../include/hidapi ../../include/hidapi
${LIBUSB_1_INCLUDE_DIRS}) # for Lightpack device ${LIBUSB_1_INCLUDE_DIRS}
) # for Lightpack device
# Group the headers that go through the MOC compiler # Group the headers that go through the MOC compiler
SET(Leddevice_QT_HEADERS SET(Leddevice_QT_HEADERS
@ -37,6 +38,8 @@ SET(Leddevice_HEADERS
${CURRENT_SOURCE_DIR}/LedDeviceFile.h ${CURRENT_SOURCE_DIR}/LedDeviceFile.h
${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.h ${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.h
${CURRENT_SOURCE_DIR}/LedDeviceUdp.h ${CURRENT_SOURCE_DIR}/LedDeviceUdp.h
${CURRENT_SOURCE_DIR}/LedDeviceUdpRaw.h
${CURRENT_SOURCE_DIR}/LedUdpDevice.h
${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.h ${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.h
${CURRENT_SOURCE_DIR}/LedDeviceTpm2.h ${CURRENT_SOURCE_DIR}/LedDeviceTpm2.h
${CURRENT_SOURCE_DIR}/LedDeviceAtmo.h ${CURRENT_SOURCE_DIR}/LedDeviceAtmo.h
@ -61,6 +64,8 @@ SET(Leddevice_SOURCES
${CURRENT_SOURCE_DIR}/LedDeviceFile.cpp ${CURRENT_SOURCE_DIR}/LedDeviceFile.cpp
${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.cpp ${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.cpp
${CURRENT_SOURCE_DIR}/LedDeviceUdp.cpp ${CURRENT_SOURCE_DIR}/LedDeviceUdp.cpp
${CURRENT_SOURCE_DIR}/LedDeviceUdpRaw.cpp
${CURRENT_SOURCE_DIR}/LedUdpDevice.cpp
${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.cpp ${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.cpp
${CURRENT_SOURCE_DIR}/LedDevicePhilipsHue.cpp ${CURRENT_SOURCE_DIR}/LedDevicePhilipsHue.cpp
${CURRENT_SOURCE_DIR}/LedDeviceTpm2.cpp ${CURRENT_SOURCE_DIR}/LedDeviceTpm2.cpp
@ -75,6 +80,7 @@ if(ENABLE_SPIDEV)
${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.h ${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.h
${CURRENT_SOURCE_DIR}/LedDeviceP9813.h ${CURRENT_SOURCE_DIR}/LedDeviceP9813.h
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h ${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h
${CURRENT_SOURCE_DIR}/LedDeviceWs2812SPI.h
${CURRENT_SOURCE_DIR}/LedDeviceAPA102.h ${CURRENT_SOURCE_DIR}/LedDeviceAPA102.h
) )
SET(Leddevice_SOURCES SET(Leddevice_SOURCES
@ -84,32 +90,33 @@ if(ENABLE_SPIDEV)
${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.cpp ${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.cpp
${CURRENT_SOURCE_DIR}/LedDeviceP9813.cpp ${CURRENT_SOURCE_DIR}/LedDeviceP9813.cpp
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp ${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp
${CURRENT_SOURCE_DIR}/LedDeviceWs2812SPI.cpp
${CURRENT_SOURCE_DIR}/LedDeviceAPA102.cpp ${CURRENT_SOURCE_DIR}/LedDeviceAPA102.cpp
) )
endif(ENABLE_SPIDEV) endif()
if(ENABLE_WS2812BPWM) if(ENABLE_WS2812BPWM)
SET(Leddevice_HEADERS SET(Leddevice_HEADERS
${Leddevice_HEADERS} ${Leddevice_HEADERS}
${CURRENT_SOURCE_DIR}/LedDeviceWS2812b.h ${CURRENT_SOURCE_DIR}/LedDeviceWS2812b.h
) )
SET(Leddevice_SOURCES SET(Leddevice_SOURCES
${Leddevice_SOURCES} ${Leddevice_SOURCES}
${CURRENT_SOURCE_DIR}/LedDeviceWS2812b.cpp ${CURRENT_SOURCE_DIR}/LedDeviceWS2812b.cpp
) )
endif(ENABLE_WS2812BPWM) endif()
if(ENABLE_WS281XPWM) if(ENABLE_WS281XPWM)
include_directories(../../dependencies/external/rpi_ws281x) include_directories(../../dependencies/external/rpi_ws281x)
SET(Leddevice_HEADERS SET(Leddevice_HEADERS
${Leddevice_HEADERS} ${Leddevice_HEADERS}
${CURRENT_SOURCE_DIR}/LedDeviceWS281x.h ${CURRENT_SOURCE_DIR}/LedDeviceWS281x.h
) )
SET(Leddevice_SOURCES SET(Leddevice_SOURCES
${Leddevice_SOURCES} ${Leddevice_SOURCES}
${CURRENT_SOURCE_DIR}/LedDeviceWS281x.cpp ${CURRENT_SOURCE_DIR}/LedDeviceWS281x.cpp
) )
endif(ENABLE_WS281XPWM) endif()
if(ENABLE_TINKERFORGE) if(ENABLE_TINKERFORGE)
SET(Leddevice_HEADERS SET(Leddevice_HEADERS
@ -120,13 +127,13 @@ if(ENABLE_TINKERFORGE)
${Leddevice_SOURCES} ${Leddevice_SOURCES}
${CURRENT_SOURCE_DIR}/LedDeviceTinkerforge.cpp ${CURRENT_SOURCE_DIR}/LedDeviceTinkerforge.cpp
) )
endif(ENABLE_TINKERFORGE) endif()
if(ENABLE_QT5) if(ENABLE_QT5)
QT5_WRAP_CPP(Leddevice_HEADERS_MOC ${Leddevice_QT_HEADERS}) QT5_WRAP_CPP(Leddevice_HEADERS_MOC ${Leddevice_QT_HEADERS})
else(ENABLE_QT5) else()
QT4_WRAP_CPP(Leddevice_HEADERS_MOC ${Leddevice_QT_HEADERS}) QT4_WRAP_CPP(Leddevice_HEADERS_MOC ${Leddevice_QT_HEADERS})
endif(ENABLE_QT5) endif()
add_library(leddevice add_library(leddevice
@ -137,8 +144,8 @@ add_library(leddevice
) )
if(ENABLE_QT5) if(ENABLE_QT5)
qt5_use_modules(leddevice Widgets Network) qt5_use_modules(leddevice Widgets Network)
endif(ENABLE_QT5) endif()
target_link_libraries(leddevice target_link_libraries(leddevice
hyperion-utils hyperion-utils

View File

@ -12,38 +12,61 @@
// hyperion local includes // hyperion local includes
#include "LedDeviceAPA102.h" #include "LedDeviceAPA102.h"
LedDeviceAPA102::LedDeviceAPA102(const std::string& outputDevice, const unsigned baudrate) : LedDeviceAPA102::LedDeviceAPA102(const std::string& outputDevice, const unsigned baudrate, const unsigned ledcount) :
LedSpiDevice(outputDevice, baudrate, 500000), LedSpiDevice(outputDevice, baudrate, 500000),
_ledBuffer(0) _ledBuffer(0)
{ {
// empty _HW_ledcount = ledcount;
} }
int LedDeviceAPA102::write(const std::vector<ColorRgb> &ledValues) int LedDeviceAPA102::write(const std::vector<ColorRgb> &ledValues)
{ {
_mLedCount = ledValues.size();
const unsigned int max_leds = std::max(_mLedCount, _HW_ledcount);
const unsigned int startFrameSize = 4; const unsigned int startFrameSize = 4;
const unsigned int endFrameSize = std::max<unsigned int>(((ledValues.size() + 15) / 16), 4); const unsigned int endFrameSize = std::max<unsigned int>(((max_leds + 15) / 16), 4);
const unsigned int mLedCount = (ledValues.size() * 4) + startFrameSize + endFrameSize; const unsigned int APAbufferSize = (max_leds * 4) + startFrameSize + endFrameSize;
if(_ledBuffer.size() != mLedCount){
_ledBuffer.resize(mLedCount, 0xFF); //printf ("_mLedCount %d _HW_ledcount %d max_leds %d APAbufferSize %d\n",
// _mLedCount, _HW_ledcount, max_leds, APAbufferSize);
if(_ledBuffer.size() != APAbufferSize){
_ledBuffer.resize(APAbufferSize, 0xFF);
_ledBuffer[0] = 0x00; _ledBuffer[0] = 0x00;
_ledBuffer[1] = 0x00; _ledBuffer[1] = 0x00;
_ledBuffer[2] = 0x00; _ledBuffer[2] = 0x00;
_ledBuffer[3] = 0x00; _ledBuffer[3] = 0x00;
} }
for (unsigned iLed=1; iLed<=ledValues.size(); ++iLed) { unsigned iLed=0;
const ColorRgb& rgb = ledValues[iLed-1]; for (iLed=0; iLed < _mLedCount; ++iLed) {
_ledBuffer[iLed*4] = 0xFF; const ColorRgb& rgb = ledValues[iLed];
_ledBuffer[iLed*4+1] = rgb.red; _ledBuffer[4+iLed*4] = 0xFF;
_ledBuffer[iLed*4+2] = rgb.green; _ledBuffer[4+iLed*4+1] = rgb.red;
_ledBuffer[iLed*4+3] = rgb.blue; _ledBuffer[4+iLed*4+2] = rgb.green;
_ledBuffer[4+iLed*4+3] = rgb.blue;
} }
for ( ; iLed < max_leds; ++iLed) {
_ledBuffer[4+iLed*4] = 0xFF;
_ledBuffer[4+iLed*4+1] = 0x00;
_ledBuffer[4+iLed*4+2] = 0x00;
_ledBuffer[4+iLed*4+3] = 0x00;
}
/*
for (unsigned i=0; i< _ledBuffer.size(); i+=4) {
printf ("i %2d led %2d RGB 0x0%02x%02x%02x%02x\n",i, i/4-1,
_ledBuffer[i+0],
_ledBuffer[i+1],
_ledBuffer[i+2],
_ledBuffer[i+3]);
}
*/
return writeBytes(_ledBuffer.size(), _ledBuffer.data()); return writeBytes(_ledBuffer.size(), _ledBuffer.data());
} }
int LedDeviceAPA102::switchOff() int LedDeviceAPA102::switchOff()
{ {
return write(std::vector<ColorRgb>(_ledBuffer.size(), ColorRgb{0,0,0})); return write(std::vector<ColorRgb>(_mLedCount, ColorRgb{0,0,0}));
} }

View File

@ -21,7 +21,8 @@ public:
/// @param baudrate The used baudrate for writing to the output device /// @param baudrate The used baudrate for writing to the output device
/// ///
LedDeviceAPA102(const std::string& outputDevice, LedDeviceAPA102(const std::string& outputDevice,
const unsigned baudrate); const unsigned baudrate, const unsigned ledcount );
/// ///
/// Writes the led color values to the led-device /// Writes the led color values to the led-device
@ -38,5 +39,7 @@ private:
/// The buffer containing the packed RGB values /// The buffer containing the packed RGB values
std::vector<uint8_t> _ledBuffer; std::vector<uint8_t> _ledBuffer;
unsigned int _HW_ledcount;
unsigned int _mLedCount;
}; };

View File

@ -15,21 +15,27 @@ AtmoOrbLight::AtmoOrbLight(unsigned int id) {
// Not implemented // Not implemented
} }
LedDeviceAtmoOrb::LedDeviceAtmoOrb(const std::string &output, bool useOrbSmoothing, LedDeviceAtmoOrb::LedDeviceAtmoOrb(
int transitiontime, int skipSmoothingDiff, int port, int numLeds, std::vector<unsigned int> orbIds) : const std::string &output,
bool useOrbSmoothing,
int transitiontime,
int skipSmoothingDiff,
int port,
int numLeds,
std::vector<unsigned int> orbIds) :
multicastGroup(output.c_str()), useOrbSmoothing(useOrbSmoothing), transitiontime(transitiontime), skipSmoothingDiff(skipSmoothingDiff), multicastGroup(output.c_str()), useOrbSmoothing(useOrbSmoothing), transitiontime(transitiontime), skipSmoothingDiff(skipSmoothingDiff),
multiCastGroupPort(port), numLeds(numLeds), orbIds(orbIds) { multiCastGroupPort(port), numLeds(numLeds), orbIds(orbIds)
{
manager = new QNetworkAccessManager(); manager = new QNetworkAccessManager();
groupAddress = QHostAddress(multicastGroup); groupAddress = QHostAddress(multicastGroup);
udpSocket = new QUdpSocket(this); udpSocket = new QUdpSocket(this);
udpSocket->bind(multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint); udpSocket->bind(QHostAddress::Any, multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
joinedMulticastgroup = udpSocket->joinMulticastGroup(groupAddress); joinedMulticastgroup = udpSocket->joinMulticastGroup(groupAddress);
} }
int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues) { int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues) {
// If not in multicast group return // If not in multicast group return
if (!joinedMulticastgroup) { if (!joinedMulticastgroup) {
return 0; return 0;

View File

@ -14,6 +14,7 @@
#include "LedDeviceLpd8806.h" #include "LedDeviceLpd8806.h"
#include "LedDeviceP9813.h" #include "LedDeviceP9813.h"
#include "LedDeviceWs2801.h" #include "LedDeviceWs2801.h"
#include "LedDeviceWs2812SPI.h"
#include "LedDeviceAPA102.h" #include "LedDeviceAPA102.h"
#endif #endif
@ -32,6 +33,7 @@
#include "LedDeviceFile.h" #include "LedDeviceFile.h"
#include "LedDeviceFadeCandy.h" #include "LedDeviceFadeCandy.h"
#include "LedDeviceUdp.h" #include "LedDeviceUdp.h"
#include "LedDeviceUdpRaw.h"
#include "LedDeviceHyperionUsbasp.h" #include "LedDeviceHyperionUsbasp.h"
#include "LedDevicePhilipsHue.h" #include "LedDevicePhilipsHue.h"
#include "LedDeviceTpm2.h" #include "LedDeviceTpm2.h"
@ -124,8 +126,9 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
{ {
const std::string output = deviceConfig["output"].asString(); const std::string output = deviceConfig["output"].asString();
const unsigned rate = deviceConfig["rate"].asInt(); const unsigned rate = deviceConfig["rate"].asInt();
const unsigned ledcount = deviceConfig.get("leds",0).asInt();
LedDeviceAPA102* deviceAPA102 = new LedDeviceAPA102(output, rate); LedDeviceAPA102* deviceAPA102 = new LedDeviceAPA102(output, rate, ledcount);
deviceAPA102->open(); deviceAPA102->open();
device = deviceAPA102; device = deviceAPA102;
@ -141,6 +144,16 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
device = deviceWs2801; device = deviceWs2801;
} }
else if (type == "ws2812spi")
{
const std::string output = deviceConfig["output"].asString();
const unsigned rate = deviceConfig.get("rate",2857143).asInt();
LedDeviceWs2812SPI* deviceWs2812SPI = new LedDeviceWs2812SPI(output, rate);
deviceWs2812SPI->open();
device = deviceWs2812SPI;
}
#endif #endif
#ifdef ENABLE_TINKERFORGE #ifdef ENABLE_TINKERFORGE
else if (type=="tinkerforge") else if (type=="tinkerforge")
@ -306,6 +319,16 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
const unsigned maxPacket = deviceConfig["maxpacket"].asInt(); const unsigned maxPacket = deviceConfig["maxpacket"].asInt();
device = new LedDeviceUdp(output, rate, protocol, maxPacket); device = new LedDeviceUdp(output, rate, protocol, maxPacket);
} }
else if (type == "udpraw")
{
const std::string output = deviceConfig["output"].asString();
const unsigned rate = deviceConfig["rate"].asInt();
const unsigned latchtime = deviceConfig.get("latchtime",500000).asInt();
LedDeviceUdpRaw* deviceUdpRaw = new LedDeviceUdpRaw(output, rate, latchtime);
deviceUdpRaw->open();
device = deviceUdpRaw;
}
else if (type == "tpm2") else if (type == "tpm2")
{ {
const std::string output = deviceConfig["output"].asString(); const std::string output = deviceConfig["output"].asString();
@ -340,8 +363,11 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
const int dmanum = deviceConfig.get("dmanum", 5).asInt(); const int dmanum = deviceConfig.get("dmanum", 5).asInt();
const int pwmchannel = deviceConfig.get("pwmchannel", 0).asInt(); const int pwmchannel = deviceConfig.get("pwmchannel", 0).asInt();
const int invert = deviceConfig.get("invert", 0).asInt(); const int invert = deviceConfig.get("invert", 0).asInt();
const int rgbw = deviceConfig.get("rgbw", 0).asInt();
const std::string& whiteAlgorithm = deviceConfig.get("white_algorithm","").asString();
LedDeviceWS281x * ledDeviceWS281x = new LedDeviceWS281x(gpio, leds, freq, dmanum, pwmchannel, invert); LedDeviceWS281x * ledDeviceWS281x = new LedDeviceWS281x(gpio, leds, freq, dmanum, pwmchannel, invert,
rgbw, whiteAlgorithm);
device = ledDeviceWS281x; device = ledDeviceWS281x;
} }
#endif #endif
@ -349,6 +375,7 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
{ {
std::cout << "LEDDEVICE ERROR: Unknown/Unimplemented device " << type << std::endl; std::cout << "LEDDEVICE ERROR: Unknown/Unimplemented device " << type << std::endl;
// Unknown / Unimplemented device // Unknown / Unimplemented device
exit(1);
} }
return device; return device;
} }

View File

@ -105,10 +105,10 @@ CiColor PhilipsHueLight::rgbToCiColor(float red, float green, float blue) {
// Convert to x,y space. // Convert to x,y space.
float cx = X / (X + Y + Z); float cx = X / (X + Y + Z);
float cy = Y / (X + Y + Z); float cy = Y / (X + Y + Z);
if (isnan(cx)) { if (std::isnan(cx)) {
cx = 0.0f; cx = 0.0f;
} }
if (isnan(cy)) { if (std::isnan(cy)) {
cy = 0.0f; cy = 0.0f;
} }
// Brightness is simply Y in the XYZ space. // Brightness is simply Y in the XYZ space.
@ -174,26 +174,26 @@ int LedDevicePhilipsHue::write(const std::vector<ColorRgb> & ledValues) {
CiColor xy = lamp.rgbToCiColor(color.red / 255.0f, color.green / 255.0f, color.blue / 255.0f); CiColor xy = lamp.rgbToCiColor(color.red / 255.0f, color.green / 255.0f, color.blue / 255.0f);
// Write color if color has been changed. // Write color if color has been changed.
if (xy != lamp.color) { if (xy != lamp.color) {
// Switch on if the lamp has been previously switched off. // From a color to black.
if (switchOffOnBlack && lamp.color == lamp.black) { if (switchOffOnBlack && lamp.color != lamp.black && xy == lamp.black) {
put(getStateRoute(lamp.id), QString("{\"on\": true}")); put(getStateRoute(lamp.id), QString("{\"on\": false}"));
} }
// From black to a color
else if (switchOffOnBlack && lamp.color == lamp.black && xy != lamp.black) {
// Send adjust color and brightness command in JSON format.
// We have to set the transition time each time.
// Send also command to switch the lamp on.
put(getStateRoute(lamp.id),
QString("{\"on\": true, \"xy\": [%1, %2], \"bri\": %3, \"transitiontime\": %4}").arg(xy.x).arg(
xy.y).arg(qRound(xy.bri * 255.0f)).arg(transitiontime));
}
// Normal color change.
else {
// Send adjust color and brightness command in JSON format. // Send adjust color and brightness command in JSON format.
// We have to set the transition time each time. // We have to set the transition time each time.
put(getStateRoute(lamp.id), put(getStateRoute(lamp.id),
QString("{\"xy\": [%1, %2], \"bri\": %3, \"transitiontime\": %4}").arg(xy.x).arg(xy.y).arg( QString("{\"xy\": [%1, %2], \"bri\": %3, \"transitiontime\": %4}").arg(xy.x).arg(xy.y).arg(
qRound(xy.bri * 255.0f)).arg(transitiontime)); 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. // Remember last color.

View File

@ -27,7 +27,7 @@ LedDevicePiBlaster::LedDevicePiBlaster(const std::string & deviceName, const Jso
// { "gpio" : 4, "ledindex" : 0, "ledcolor" : "r" }, // { "gpio" : 4, "ledindex" : 0, "ledcolor" : "r" },
#define TABLE_SZ sizeof(_gpio_to_led)/sizeof(_gpio_to_led[0]) #define TABLE_SZ sizeof(_gpio_to_led)/sizeof(_gpio_to_led[0])
for (int i=0; i < TABLE_SZ; i++ ) for (unsigned i=0; i < TABLE_SZ; i++ )
{ {
_gpio_to_led[i] = -1; _gpio_to_led[i] = -1;
_gpio_to_color[i] = 'z'; _gpio_to_color[i] = 'z';
@ -41,7 +41,7 @@ LedDevicePiBlaster::LedDevicePiBlaster(const std::string & deviceName, const Jso
const std::string ledcolor = gpioMap.get("ledcolor","z").asString(); const std::string ledcolor = gpioMap.get("ledcolor","z").asString();
// printf ("got gpio %d ledindex %d color %c\n", gpio,ledindex, ledcolor[0]); // printf ("got gpio %d ledindex %d color %c\n", gpio,ledindex, ledcolor[0]);
// ignore missing/invalid settings // ignore missing/invalid settings
if ( (gpio >= 0) && (gpio < TABLE_SZ) && (ledindex >= 0) ){ if ( (gpio >= 0) && (gpio < signed(TABLE_SZ)) && (ledindex >= 0) ){
_gpio_to_led[gpio] = ledindex; _gpio_to_led[gpio] = ledindex;
_gpio_to_color[gpio] = ledcolor[0]; // 1st char of string _gpio_to_color[gpio] = ledcolor[0]; // 1st char of string
} else { } else {

View File

@ -17,7 +17,7 @@ struct addrinfo hints, *servinfo, *p;
//char udpbuffer[1024]; //char udpbuffer[1024];
int sockfd; int sockfd;
int ledprotocol; int ledprotocol;
int leds_per_pkt; unsigned leds_per_pkt;
int update_number; int update_number;
int fragment_number; int fragment_number;
@ -25,7 +25,6 @@ LedDeviceUdp::LedDeviceUdp(const std::string& output, const unsigned baudrate, c
//LedDeviceUdp::LedDeviceUdp(const std::string& output, const unsigned baudrate) : //LedDeviceUdp::LedDeviceUdp(const std::string& output, const unsigned baudrate) :
// _ofs(output.empty()?"/home/pi/LedDevice.out":output.c_str()) // _ofs(output.empty()?"/home/pi/LedDevice.out":output.c_str())
{ {
std::string hostname; std::string hostname;
std::string port; std::string port;
ledprotocol = protocol; ledprotocol = protocol;
@ -45,7 +44,7 @@ LedDeviceUdp::LedDeviceUdp(const std::string& output, const unsigned baudrate, c
port+=output[i]; port+=output[i];
} }
} }
//std::cout << "output " << output << " hostname " << hostname << " port " << port <<std::endl; //std::cout << "output " << output << " hostname " << hostname << " port " << port <<std::endl;
assert(got_colon==1); assert(got_colon==1);
int rv; int rv;
@ -153,8 +152,47 @@ int LedDeviceUdp::write(const std::vector<ColorRgb> & ledValues)
udpbuffer[udpPtr++] = ledCtr%256; // low byte udpbuffer[udpPtr++] = ledCtr%256; // low byte
} }
} }
} }
if (ledprotocol == 3) {
udpPtr = 0;
unsigned int ledCtr = 0;
unsigned int fragments = 1;
unsigned int datasize = ledValues.size() * 3;
if (ledValues.size() > leds_per_pkt) {
fragments = (ledValues.size() / leds_per_pkt) + 1;
}
fragment_number = 1;
udpbuffer[udpPtr++] = 0x9C;
udpbuffer[udpPtr++] = 0xDA;
udpbuffer[udpPtr++] = datasize/256; // high byte
udpbuffer[udpPtr++] = datasize%256; // low byte
udpbuffer[udpPtr++] = fragment_number++;
udpbuffer[udpPtr++] = fragments;
for (const ColorRgb& color : ledValues)
{
if (udpPtr<4090) {
udpbuffer[udpPtr++] = color.red;
udpbuffer[udpPtr++] = color.green;
udpbuffer[udpPtr++] = color.blue;
}
ledCtr++;
if ( (ledCtr % leds_per_pkt == 0) || (ledCtr == ledValues.size()) ) {
udpbuffer[udpPtr++] = 0x36;
sendto(sockfd, udpbuffer, udpPtr, 0, p->ai_addr, p->ai_addrlen);
memset(udpbuffer, 0, sizeof udpbuffer);
udpPtr = 0;
udpbuffer[udpPtr++] = 0x9C;
udpbuffer[udpPtr++] = 0xDA;
udpbuffer[udpPtr++] = datasize/256; // high byte
udpbuffer[udpPtr++] = datasize%256; // low byte
udpbuffer[udpPtr++] = fragment_number++;
udpbuffer[udpPtr++] = fragments;
}
}
}
return 0; return 0;
} }

View File

@ -0,0 +1,41 @@
// STL includes
#include <cstring>
#include <cstdio>
#include <iostream>
// Linux includes
#include <fcntl.h>
#include <sys/ioctl.h>
// hyperion local includes
#include "LedDeviceUdpRaw.h"
LedDeviceUdpRaw::LedDeviceUdpRaw(const std::string& outputDevice, const unsigned baudrate) :
LedUdpDevice(outputDevice, baudrate, 500000),
mLedCount(0)
{
// empty
}
LedDeviceUdpRaw::LedDeviceUdpRaw(const std::string& outputDevice, const unsigned baudrate, const unsigned latchTime) :
LedUdpDevice(outputDevice, baudrate, latchTime),
mLedCount(0)
{
// empty
}
int LedDeviceUdpRaw::write(const std::vector<ColorRgb> &ledValues)
{
mLedCount = ledValues.size();
const unsigned dataLen = ledValues.size() * sizeof(ColorRgb);
const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());
return writeBytes(dataLen, dataPtr);
}
int LedDeviceUdpRaw::switchOff()
{
return write(std::vector<ColorRgb>(mLedCount, ColorRgb{0,0,0}));
}

View File

@ -0,0 +1,43 @@
#pragma once
// STL includes
#include <string>
// hyperion incluse
#include "LedUdpDevice.h"
///
/// Implementation of the LedDevice interface for writing to Ws2801 led device.
///
class LedDeviceUdpRaw : public LedUdpDevice
{
public:
///
/// Constructs the LedDevice for a string containing leds of the type Ws2801
///
/// @param outputDevice The name of the output device (eg '/etc/SpiDev.0.0')
/// @param baudrate The used baudrate for writing to the output device
///
LedDeviceUdpRaw(const std::string& outputDevice,
const unsigned baudrate);
LedDeviceUdpRaw(const std::string& outputDevice,
const unsigned baudrate,
const unsigned latchTime);
///
/// 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<ColorRgb> &ledValues);
/// Switch the leds off
virtual int switchOff();
private:
/// the number of leds (needed when switching off)
size_t mLedCount;
};

View File

@ -3,8 +3,11 @@
#include "LedDeviceWS281x.h" #include "LedDeviceWS281x.h"
// Constructor // Constructor
LedDeviceWS281x::LedDeviceWS281x(const int gpio, const int leds, const uint32_t freq, const int dmanum, const int pwmchannel, const int invert) LedDeviceWS281x::LedDeviceWS281x(const int gpio, const int leds, const uint32_t freq, const int dmanum, const int pwmchannel, const int invert, const int rgbw, const std::string& whiteAlgorithm)
{ {
_whiteAlgorithm = whiteAlgorithm;
std::cout << "whiteAlgorithm :" << whiteAlgorithm << ":\n";
initialized = false; initialized = false;
led_string.freq = freq; led_string.freq = freq;
led_string.dmanum = dmanum; led_string.dmanum = dmanum;
@ -17,7 +20,11 @@ LedDeviceWS281x::LedDeviceWS281x(const int gpio, const int leds, const uint32_t
led_string.channel[chan].invert = invert; led_string.channel[chan].invert = invert;
led_string.channel[chan].count = leds; led_string.channel[chan].count = leds;
led_string.channel[chan].brightness = 255; led_string.channel[chan].brightness = 255;
if (rgbw == 1) {
led_string.channel[chan].strip_type = SK6812_STRIP_GRBW;
} else {
led_string.channel[chan].strip_type = WS2811_STRIP_RGB; led_string.channel[chan].strip_type = WS2811_STRIP_RGB;
}
led_string.channel[!chan].gpionum = 0; led_string.channel[!chan].gpionum = 0;
led_string.channel[!chan].invert = invert; led_string.channel[!chan].invert = invert;
@ -42,7 +49,19 @@ int LedDeviceWS281x::write(const std::vector<ColorRgb> &ledValues)
{ {
if (idx >= led_string.channel[chan].count) if (idx >= led_string.channel[chan].count)
break; break;
led_string.channel[chan].leds[idx++] = ((uint32_t)color.red << 16) + ((uint32_t)color.green << 8) + color.blue;
_temp_rgbw.red = color.red;
_temp_rgbw.green = color.green;
_temp_rgbw.blue = color.blue;
_temp_rgbw.white = 0;
if (led_string.channel[chan].strip_type == SK6812_STRIP_GRBW) {
Rgb_to_Rgbw(color, &_temp_rgbw, _whiteAlgorithm);
}
led_string.channel[chan].leds[idx++] =
((uint32_t)_temp_rgbw.white << 24) + ((uint32_t)_temp_rgbw.red << 16) + ((uint32_t)_temp_rgbw.green << 8) + _temp_rgbw.blue;
} }
while (idx < led_string.channel[chan].count) while (idx < led_string.channel[chan].count)
led_string.channel[chan].leds[idx++] = 0; led_string.channel[chan].leds[idx++] = 0;

Some files were not shown because too many files have changed in this diff Show More