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
[submodule "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
project(Hyperion)
project(hyperion)
# define the minimum cmake version (as required by cmake)
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
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})
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})
option(ENABLE_FB "Enable the framebuffer grabber" OFF)
option(ENABLE_FB "Enable the framebuffer grabber" ${DEFAULT_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})
option(ENABLE_PROTOBUF "Enable PROTOBUF server" ON)
message(STATUS "ENABLE_PROTOBUF = " ${ENABLE_PROTOBUF})
option(ENABLE_SPIDEV "Enable the SPIDEV device" ON)
option(ENABLE_SPIDEV "Enable the SPIDEV device" ${DEFAULT_SPIDEV} )
message(STATUS "ENABLE_SPIDEV = " ${ENABLE_SPIDEV})
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)
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})
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})
option(ENABLE_X11 "Enable the X11 grabber" OFF)
option(ENABLE_X11 "Enable the X11 grabber" ${DEFAULT_X11})
message(STATUS "ENABLE_X11 = " ${ENABLE_X11})
option(ENABLE_QT5 "Enable QT5" OFF)
@ -46,22 +81,21 @@ message(STATUS "ENABLE_QT5 = " ${ENABLE_QT5})
option(ENABLE_TESTS "Compile additional test applications" OFF)
message(STATUS "ENABLE_TESTS = " ${ENABLE_TESTS})
if(ENABLE_V4L2 AND NOT ENABLE_PROTOBUF)
message(FATAL_ERROR "V4L2 grabber requires PROTOBUF. Disable V4L2 or enable PROTOBUF")
endif(ENABLE_V4L2 AND NOT ENABLE_PROTOBUF)
option(ENABLE_PROFILER "enable profiler capabilities - not for release code" OFF)
message(STATUS "ENABLE_PROFILER = " ${ENABLE_PROFILER})
if(ENABLE_FB AND ENABLE_DISPMANX)
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)
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)
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_LIB_DIR ${CMAKE_BINARY_DIR}/proto )
@ -85,10 +119,10 @@ include_directories("${PROJECT_BINARY_DIR}")
if(ENABLE_QT5)
ADD_DEFINITIONS ( -DENABLE_QT5 )
#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)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/qt4)
endif(ENABLE_QT5)
endif()
# Define the global output path of binaries
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
@ -113,10 +147,10 @@ if(ENABLE_QT5)
find_package(Qt5 COMPONENTS Core Gui Widgets Network REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
# set(CMAKE_CXX_FLAGS "-fPIC")
else(ENABLE_QT5)
else()
# Configure the use of QT4
find_package(Qt4 COMPONENTS QtCore QtNetwork QtGui REQUIRED QUIET)
endif(ENABLE_QT5)
endif()
#add libusb and pthreads
find_package(libusb-1.0 REQUIRED)
@ -124,10 +158,10 @@ find_package(Threads REQUIRED)
if(ENABLE_QT5)
#include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS})
else(ENABLE_QT5)
else()
include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS})
endif(ENABLE_QT5)
endif()
# TODO[TvdZ]: This linking directory should only be added if we are cross compiling
if(NOT APPLE)
@ -138,18 +172,21 @@ if(ENABLE_OSX)
set(CMAKE_EXE_LINKER_FLAGS "-framework CoreGraphics")
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_subdirectory(dependencies)
add_subdirectory(libsrc)
add_subdirectory(src)
if (ENABLE_TESTS)
add_subdirectory(test)
endif (ENABLE_TESTS)
endif ()
# Add the doxygen generation directory
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
#cmakedefine ENABLE_TINKERFORGE
// Define to enable PROTOBUF server
#cmakedefine ENABLE_PROTOBUF
// Define to enable the framebuffer grabber
#cmakedefine ENABLE_FB
@ -30,4 +27,11 @@
// Define to enable the osx grabber
#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}"

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
# 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
# make_release <release name> <platform> [<cmake args ...>]
make_release()
{
echo
echo "--- build release for $1 ---"
echo
RELEASE=$1
PLATFORM=$2
shift 2
mkdir -p build-${RELEASE}
mkdir -p deploy/${RELEASE}
cd build-${RELEASE}
cmake -DCMAKE_INSTALL_PREFIX=/usr -DPLATFORM=${PLATFORM} $@ -DCMAKE_BUILD_TYPE=Release -Wno-dev .. || exit 1
make -j $(nproc) || exit 1
#strip bin/*
make package -j $(nproc)
mv hyperion-*-ambilight.* ../deploy/${RELEASE}
cd ..
bin/create_release.sh . ${RELEASE}
}
# Create the x32 build
#mkdir build-x32
#cd build-x32
#cmake -DIMPORT_PROTOC=../build-x64/protoc_export.cmake -DENABLE_DISPMANX=OFF -DENABLE_X11=ON -DCMAKE_BUILD_TYPE=Release -Wno-dev ..
#make -j 4
#cd ..
export PATH="$PATH:$HOME/raspberrypi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin"
CMAKE_PROTOC_FLAG="-DIMPORT_PROTOC=../build-x86x64/protoc_export.cmake"
# Create the RPI build
mkdir build-rpi
cd build-rpi
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 ..
make -j 4
cd ..
make_release x86x64 x86
#make_release x32 x86 ${CMAKE_PROTOC_FLAG}
make_release rpi rpi-pwm -DCMAKE_TOOLCHAIN_FILE="../cmake/Toolchain-rpi.cmake" ${CMAKE_PROTOC_FLAG}
make_release wetek wetek -DCMAKE_TOOLCHAIN_FILE="../cmake/Toolchain-rpi.cmake" ${CMAKE_PROTOC_FLAG}
#make_release imx6 imx6 -DCMAKE_TOOLCHAIN_FILE="../cmake/Toolchain-imx6.cmake" ${CMAKE_PROTOC_FLAG}
# Create the WETEK build
mkdir build-wetek
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
#mkdir build-imx6
#cd build-imx6
#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 -j 4
#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:$repodir/effects/:hyperion/effects/:" \
--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.systemd.sh:hyperion/init.d/hyperion.systemd.sh:" \
--transform "s:$repodir/bin/service/hyperion.initctl.sh:hyperion/init.d/hyperion.initctl.sh:" \
--transform "s:$repodir/bin/service/hyperion.init.sh:hyperion/services/hyperion.init.sh:" \
--transform "s:$repodir/bin/service/hyperion.systemd.sh:hyperion/services/hyperion.systemd.sh:" \
--transform "s:$repodir/bin/service/hyperion.initctl.sh:hyperion/services/hyperion.initctl.sh:" \
--transform "s://:/:g" \
"$builddir/bin/hyperiond" \
"$builddir/bin/hyperion-remote" \
"$builddir/bin/hyperion-v4l2" \
"$builddir/bin/hyperion-x11" \
"$builddir/bin/hyperion-dispmanx" \
"$builddir/bin/hyperion"* \
"$repodir/effects/"* \
"$repodir/bin/service/hyperion.init.sh" \
"$repodir/bin/service/hyperion.systemd.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
if [ $BETA -eq 1 ]; then
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
#Welcome message
@ -74,24 +74,34 @@ if [ $BOBLIGHT_PROCNR -eq 1 ]; then
exit 1
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'
if [ $OS_OPENELEC -eq 1 ]; then
killall hyperiond 2>/dev/null
elif [ $USE_INITCTL -eq 1 ]; then
/sbin/initctl stop hyperion 2>/dev/null
elif [ $USE_SERVICE -eq 1 ]; then
/usr/sbin/service hyperion stop 2>/dev/null
SERVICEP="/etc/init"
elif [ $USE_SYSTEMD -eq 1 ]; then
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
/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
#Install dependencies for Hyperion
#Install dependencies for Hyperion and setup preperation
if [ $OS_OPENELEC -ne 1 ]; then
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
mkdir /etc/hyperion 2>/dev/null
fi
#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
#Backup the .conf files, if present
echo '---> Backup Hyperion configuration(s), if present'
rm -f /tmp/*.json 2>/dev/null
if [ $OS_OPENELEC -eq 1 ]; then
cp -v /storage/.config/*.json /tmp 2>/dev/null
else cp -v /opt/hyperion/config/*.json /tmp 2>/dev/null
# compatibility layer to move old configs to new config dir
if [ -f "/opt/hyperion/bin/hyperiond" ]; then
echo '---> Old installation found, move configs to /etc/hyperion/ and move hyperion to /usr/share/hyperion/'
mv /opt/hyperion/config/*.json /etc/hyperion 2>/dev/null
sed -i "s|/opt/hyperion/effects|/usr/share/hyperion/effects|g" /etc/hyperion/*.json
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
# 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
#set the executen bit (failsave)
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
wget -nv $HYPERION_RELEASE -O - | tar -C /opt -xz
#set the executen bit (failsave)
chmod +x -R /opt/hyperion/bin
BINSP=/usr/share/hyperion/bin
BINTP=/usr/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
ln -fs /opt/hyperion/bin/hyperiond /usr/bin/hyperiond
ln -fs /opt/hyperion/bin/hyperion-remote /usr/bin/hyperion-remote
ln -fs /opt/hyperion/bin/hyperion-v4l2 /usr/bin/hyperion-v4l2
ln -fs /opt/hyperion/bin/hyperion-dispmanx /usr/bin/hyperion-dispmanx 2>/dev/null
ln -fs /opt/hyperion/bin/hyperion-x11 /usr/bin/hyperion-x11 2>/dev/null
ln -fs $BINSP/hyperiond $BINTP/hyperiond
ln -fs $BINSP/hyperion-remote $BINTP/hyperion-remote
ln -fs $BINSP/hyperion-v4l2 $BINTP/hyperion-v4l2
ln -fs $BINSP/hyperion-dispmanx $BINTP/hyperion-dispmanx 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
# Restore backup of .conf files, if present
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)
# Copy the service control configuration to /etc/init (-n to respect user modified scripts)
if [ $USE_INITCTL -eq 1 ]; then
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
elif [ $OS_OPENELEC -eq 1 ]; then
#modify all old installs with a logfile output
@ -239,34 +262,35 @@ elif [ $OS_OPENELEC -eq 1 ]; then
elif [ $USE_SYSTEMD -eq 1 ]; then
echo '---> Installing systemd script'
#place startup script for systemd and activate
#Problem with systemd to enable symlinks - Bug? Workaround cp -n (overwrite never)
#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
cp -n $SERVICEL/hyperion.systemd.sh $SERVICEP/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
# Wait until kodi is sarted
sed -i '/After = mediacenter.service/d' $SERVICEP/hyperion.service
sed -i '/Unit/a After = mediacenter.service' $SERVICEP/hyperion.service
systemctl -q daemon-reload
fi
elif [ $USE_SERVICE -eq 1 ]; then
echo '---> Installing startup script in init.d'
# 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
chmod +x /etc/init.d/hyperion
ln -s $SERVICEL/hyperion.init.sh $SERVICEP/hyperion 2>/dev/null && chmod +x $SERVICEP/hyperion
update-rc.d hyperion defaults 98 02
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
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
chown -R pi:pi /opt/hyperion/config
chown -R pi:pi /etc/hyperion
fi
# Start the hyperion daemon

View File

@ -42,6 +42,7 @@ esac
done
echo "---> You entered \"$CONFIRM\". Remove Hyperion!"
fi
# Find out if we are on OpenElec or RasPlex
OS_OPENELEC=`grep -m1 -c 'OpenELEC\|RasPlex\|LibreELEC' /etc/issue`
@ -63,10 +64,6 @@ elif [ $USE_SERVICE -eq 1 ]; then
/usr/sbin/service hyperion stop 2>/dev/null
elif [ $USE_SYSTEMD -eq 1 ]; then
service hyperion stop 2>/dev/null
# while [ $SERVICEC -le 20 ]; do
# service hyperion_fw$SERVICEC stop 2>/dev/null
# ((SERVICEC++))
# done
fi
#reset count
@ -86,19 +83,11 @@ elif [ $USE_SYSTEMD -eq 1 ]; then
# Delete and disable Hyperion systemd script
echo '---> Delete and disable Hyperion systemd script'
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
elif [ $USE_SERVICE -eq 1 ]; then
# Delete and disable Hyperion init.d script
echo '---> Delete and disable Hyperion init.d script'
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
fi
@ -116,9 +105,12 @@ else
rm -v /usr/bin/hyperion-v4l2 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-aml 2>/dev/null
rm -v /etc/hyperion.config.json 2>/dev/null
echo "---> Remove binaries"
rm -rv /opt/hyperion 2>/dev/null
rm -rv /etc/hyperion 2>/dev/null
rm -rv /usr/share/hyperion 2>/dev/null
fi
echo '*******************************************************************************'
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
DAEMON=hyperiond
DAEMONOPTS="/opt/hyperion/config/hyperion.config.json"
DAEMONOPTS="/etc/hyperion/hyperion.config.json"
DAEMON_PATH="/usr/bin"
NAME=$DAEMON

View File

@ -8,4 +8,4 @@ stop on (runlevel [!2345])
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
Group=root
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
Restart=on-failure
TimeoutStopSec=10

View File

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

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...
if (UDEV_STABLE)
set(UDEV_STABLE 0)
else (UDEV_STABLE)
else ()
set(UDEV_STABLE 1)
endif (UDEV_STABLE)
endif ()
message(STATUS "libudev stable: ${UDEV_STABLE}")
ENDIF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR)
ENDIF ()
IF (UDEV_FOUND)
MESSAGE(STATUS "Found UDev: ${UDEV_LIBRARIES}")
MESSAGE(STATUS " include: ${UDEV_INCLUDE_DIR}")
ELSE (UDEV_FOUND)
ELSE ()
MESSAGE(STATUS "UDev not found.")
MESSAGE(STATUS "UDev: You can specify includes: -DUDEV_PATH_INCLUDES=/opt/udev/include")
MESSAGE(STATUS " currently found includes: ${UDEV_INCLUDE_DIR}")
@ -49,5 +49,5 @@ ELSE (UDEV_FOUND)
MESSAGE(STATUS " currently found libs: ${UDEV_LIBRARIES}")
IF (UDev_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find UDev library")
ENDIF (UDev_FIND_REQUIRED)
ENDIF (UDEV_FOUND)
ENDIF ()
ENDIF ()

View File

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

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
# again when dependencies need to be recomputed.
QT4_MAKE_OUTPUT_FILE("${infile}" "" "qrc.depends" out_depends)
configure_file("${infile}" "${out_depends}" COPY_ONLY)
configure_file("${infile}" "${out_depends}" COPYONLY)
else()
# The .qrc file does not exist (yet). Let's add a dependency and hope
# 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'
// Generated by: HyperCon (The Hyperion deamon configuration file builder)
// Created with HyperCon V1.02.0 (30.04.2016)
// This is a example config (hyperion.config.json) with comments, in any case you need to create your own one with HyperCon!
// location of all configs: /etc/hyperion
// Webpage: https://www.hyperion-project.org
{
/// 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
/// ---------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]
/// * 'colorOrder' : The order of the color bytes ('rgb', 'rbg', 'bgr', etc.).
"device" :
@ -41,6 +42,7 @@
/// tuning parameters:
/// - 'saturationGain' The gain adjustement of the saturation
/// - '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
/// following tuning parameters for each channel:
/// - 'threshold' The minimum required input value for the channel to be on
@ -102,7 +104,8 @@
"hsl" :
{
"saturationGain" : 1.0000,
"luminanceGain" : 1.0000
"luminanceGain" : 1.0000,
"luminanceMinimum" : 0.0000
},
"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"]
/// 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)
// "forwarder" :
// {
// "proto" : ["127.0.0.1:19447"],
// "json" : ["127.0.0.1:19446"]
// },
"forwarder" :
{
"proto" : ["127.0.0.1:19447"],
"json" : ["127.0.0.1:19446"]
},
/// The configuration for the frame-grabber, contains the following items:
/// * 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
/// * 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
/// * 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
/// * 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
// },
"xbmcVideoChecker" :
{
"xbmcAddress" : "127.0.0.1",
"xbmcTcpPort" : 9090,
"grabVideo" : true,
"grabPictures" : true,
"grabAudio" : true,
"grabMenu" : false,
"grabPause" : 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
@ -236,11 +241,11 @@
/// The configuration of the boblight server which enables the boblight remote interface
/// * port : Port at which the boblight server is started
/// * priority: Priority of the boblight server (Default=900) HINT: lower value result in HIGHER priority!
// "boblightServer" :
// {
// "port" : 19333,
// "priority" : 900
// },
"boblightServer" :
{
"port" : 19333,
"priority" : 900
},
/// Configuration for the embedded V4L2 grabber
/// * 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]
/// * 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]
// "grabber-v4l2" :
// {
// "device" : "/dev/video0",
// "input" : 0,
// "standard" : "no-change",
// "width" : -1,
// "height" : -1,
// "frameDecimation" : 2,
// "sizeDecimation" : 8,
// "priority" : 900,
// "mode" : "2D",
// "cropLeft" : 0,
// "cropRight" : 0,
// "cropTop" : 0,
// "cropBottom" : 0,
// "redSignalThreshold" : 0.0,
// "greenSignalThreshold" : 0.0,
// "blueSignalThreshold" : 0.0
// },
"grabber-v4l2" :
{
"device" : "/dev/video0",
"input" : 0,
"standard" : "no-change",
"width" : -1,
"height" : -1,
"frameDecimation" : 2,
"sizeDecimation" : 8,
"priority" : 900,
"mode" : "2D",
"cropLeft" : 0,
"cropRight" : 0,
"cropTop" : 0,
"cropBottom" : 0,
"redSignalThreshold" : 0.0,
"greenSignalThreshold" : 0.0,
"blueSignalThreshold" : 0.0
},
/// 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

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,7 +11,6 @@ if(ENABLE_WS281XPWM)
external/rpi_ws281x/rpihw.c)
endif(ENABLE_WS281XPWM)
if(ENABLE_PROTOBUF)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared protobuf library")
add_subdirectory(external/protobuf)
@ -107,4 +106,3 @@ if(ENABLE_PROTOBUF)
set(${SRCS} ${${SRCS}} PARENT_SCOPE)
set(${HDRS} ${${HDRS}} PARENT_SCOPE)
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" :
{
"rotationTime" : 60.0,
"color" : [0,0,255],
"colorRandom" : true,
"hueChange" : 30.0,
"blobs" : 5,
"reverse" : false,

View File

@ -2,10 +2,12 @@ import hyperion
import time
import colorsys
import math
from random import random
# Get the parameters
rotationTime = float(hyperion.args.get('rotationTime', 20.0))
color = hyperion.args.get('color', (0,0,255))
colorRandom = bool(hyperion.args.get('colorRandom', False))
hueChange = float(hyperion.args.get('hueChange', 60.0))
blobs = int(hyperion.args.get('blobs', 5))
reverse = bool(hyperion.args.get('reverse', False))
@ -34,6 +36,9 @@ baseColorChangeRate = max(0, baseColorChangeRate) # > 0
# Calculate the color data
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()
for i in range(hyperion.ledCount):
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",
"args" :
{
"udpPort" : 2391
"ListenPort" : 2391
}
}

View File

@ -3,17 +3,33 @@ import time
import colorsys
import socket
import errno
import struct
# 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)
listen_addr = ("",udpPort)
print "udp.py: bind socket port:",udpPort
listen_addr = (ListenIP,ListenPort)
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))) )
# 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 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
/// provided image should have the same dimensions as the configured values (_width and
@ -68,4 +71,17 @@ private:
const unsigned _width;
/// Height of the captured snapshot [pixels]
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 setCropping(const unsigned cropLeft, const unsigned cropRight,
const unsigned cropTop, const unsigned cropBottom);
///
/// Set the grabbing mode
/// @param[in] mode The new grabbing mode

View File

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

View File

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

View File

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

View File

@ -13,6 +13,8 @@
// hyperion util
#include <utils/Image.h>
#include <utils/ColorRgb.h>
#include <utils/GrabbingMode.h>
#include <utils/VideoMode.h>
// jsoncpp includes
#include <message.pb.h>
@ -82,6 +84,18 @@ private slots:
/// Try to connect to the Hyperion host
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:
@ -109,4 +123,7 @@ private:
QTimer _timer;
QAbstractSocket::SocketState _prevSocketState;
/// The buffer used for reading data from the socket
QByteArray _receiveBuffer;
};

View File

@ -4,11 +4,13 @@
// hyperion includes
#include <utils/Image.h>
#include <utils/ColorRgb.h>
#include <utils/GrabbingMode.h>
#include <utils/VideoMode.h>
// hyperion proto includes
#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
{
Q_OBJECT
@ -17,6 +19,13 @@ public:
ProtoConnectionWrapper(const std::string & address, int priority, int duration_ms, bool skipProtoReply);
virtual ~ProtoConnectionWrapper();
signals:
///
/// Forwarding XBMC Video Checker Message
///
void setGrabbingMode(const GrabbingMode mode);
void setVideoMode(const VideoMode videoMode);
public slots:
/// Handle a single image
/// @param image The image to process

View File

@ -15,6 +15,8 @@
// hyperion includes
#include <utils/Image.h>
#include <utils/ColorRgb.h>
#include <utils/GrabbingMode.h>
#include <utils/VideoMode.h>
// forward decl
class ProtoClientConnection;
@ -50,6 +52,13 @@ public:
public slots:
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:
///
/// 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,
/** Frame grabbing during video */
GRABBINGMODE_VIDEO,
GRABBINGMODE_PAUSE,
GRABBINGMODE_PHOTO,
GRABBINGMODE_AUDIO,
GRABBINGMODE_MENU,

View File

@ -20,7 +20,7 @@ public:
/// @param saturationGain The used saturation gain
/// @param luminanceGain The used luminance gain
///
HslTransform(double saturationGain, double luminanceGain);
HslTransform(double saturationGain, double luminanceGain, double luminanceMinimum);
///
/// Destructor
@ -55,6 +55,20 @@ public:
///
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.
///
@ -97,4 +111,6 @@ private:
double _saturationGain;
/// The luminance gain
double _luminanceGain;
/// The luminance minimum
double _luminanceMinimum;
};

View File

@ -22,8 +22,7 @@ public:
void set3D(VideoMode mode);
void processImage(const uint8_t * data, int width, int height, int lineLength, PixelFormat pixelFormat,
Image<ColorRgb> & outputImage) const;
void processImage(const uint8_t * data, int width, int height, int lineLength, PixelFormat pixelFormat, Image<ColorRgb> & outputImage) const;
private:
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 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
@ -117,6 +117,9 @@ private:
/// Flag indicating whether or not to grab when XBMC is playing nothing (in menu)
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
const bool _grabScreensaver;

View File

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

View File

@ -19,9 +19,9 @@ set(BoblightServer_SOURCES
if(ENABLE_QT5)
qt5_wrap_cpp(BoblightServer_HEADERS_MOC ${BoblightServer_QT_HEADERS})
else(ENABLE_QT5)
else()
qt4_wrap_cpp(BoblightServer_HEADERS_MOC ${BoblightServer_QT_HEADERS})
endif(ENABLE_QT5)
endif()
add_library(boblightserver
${BoblightServer_HEADERS}
@ -32,7 +32,7 @@ add_library(boblightserver
if(ENABLE_QT5)
qt5_use_modules(boblightserver Widgets)
endif(ENABLE_QT5)
endif()
target_link_libraries(boblightserver
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
)
set(EffectEngine_RESOURCES ${CURRENT_SOURCE_DIR}/EffectEngine.qrc)
if(ENABLE_QT5)
QT5_WRAP_CPP(EffectEngineHEADERS_MOC ${EffectEngineQT_HEADERS})
qt5_add_resources(EffectEngine_RESOURCES_RCC ${EffectEngine_RESOURCES} OPTIONS "-no-compress")
else(ENABLE_QT5)
else()
QT4_WRAP_CPP(EffectEngineHEADERS_MOC ${EffectEngineQT_HEADERS})
qt4_add_resources(EffectEngine_RESOURCES_RCC ${EffectEngine_RESOURCES} OPTIONS "-no-compress")
endif(ENABLE_QT5)
endif()
add_library(effectengine
${EffectEngineHEADERS}
@ -47,7 +46,7 @@ add_library(effectengine
if(ENABLE_QT5)
qt5_use_modules(effectengine Widgets)
endif(ENABLE_QT5)
endif()
target_link_libraries(effectengine
hyperion

View File

@ -35,12 +35,9 @@ EffectEngine::EffectEngine(Hyperion * hyperion, const Json::Value & jsonEffectCo
{
const std::string & path = paths[i].asString();
QDir directory(QString::fromStdString(path));
if (!directory.exists())
if (directory.exists())
{
std::cerr << "EFFECTENGINE ERROR: Effect directory can not be loaded: " << path << std::endl;
continue;
}
int efxCount = 0;
QStringList filenames = directory.entryList(QStringList() << "*.json", QDir::Files, QDir::Name | QDir::IgnoreCase);
foreach (const QString & filename, filenames)
{
@ -48,8 +45,16 @@ EffectEngine::EffectEngine(Hyperion * hyperion, const Json::Value & jsonEffectCo
if (loadEffectDefinition(path, filename.toStdString(), 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

View File

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

View File

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

View File

@ -11,7 +11,14 @@ DispmanxFrameGrabber::DispmanxFrameGrabber(const unsigned width, const unsigned
_vc_resource(0),
_vc_flags(0),
_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
bcm_host_init();
@ -49,6 +56,8 @@ DispmanxFrameGrabber::DispmanxFrameGrabber(const unsigned width, const unsigned
DispmanxFrameGrabber::~DispmanxFrameGrabber()
{
delete[] _captureBuffer;
// Clean up resources
vc_dispmanx_resource_delete(_vc_resource);
@ -63,38 +72,147 @@ void DispmanxFrameGrabber::setFlags(const int vc_flags)
void DispmanxFrameGrabber::setVideoMode(const VideoMode videoMode)
{
switch (videoMode) {
case VIDEO_3DSBS:
vc_dispmanx_rect_set(&_rectangle, 0, 0, _width/2, _height);
break;
case VIDEO_3DTAB:
vc_dispmanx_rect_set(&_rectangle, 0, 0, _width, _height/2);
break;
case VIDEO_2D:
default:
vc_dispmanx_rect_set(&_rectangle, 0, 0, _width, _height);
break;
_videoMode = videoMode;
}
void DispmanxFrameGrabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom)
{
if (cropLeft + cropRight >= _width || cropTop + cropBottom >= _height)
{
std::cout
<< "DISPMANXGRABBER ERROR: Rejecting invalid crop values"
<< " left: " << cropLeft
<< " 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)
{
// resize the given image if needed
if (image.width() != unsigned(_rectangle.width) || image.height() != unsigned(_rectangle.height))
int ret;
// 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
_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)
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
void* image_ptr = image.memptr();
const unsigned destPitch = _rectangle.width * sizeof(ColorRgba);
vc_dispmanx_resource_read_data(_vc_resource, &_rectangle, image_ptr, destPitch);
void* imagePtr = image.memptr();
void* capturePtr = imagePtr;
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
vc_dispmanx_display_close(_vc_display);

View File

@ -74,6 +74,7 @@ void DispmanxWrapper::setGrabbingMode(const GrabbingMode mode)
switch (mode)
{
case GRABBINGMODE_VIDEO:
case GRABBINGMODE_PAUSE:
_frameGrabber->setFlags(DISPMANX_SNAPSHOT_NO_RGB|DISPMANX_SNAPSHOT_FILL);
start();
break;
@ -94,3 +95,9 @@ void DispmanxWrapper::setVideoMode(const VideoMode 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)
QT5_WRAP_CPP(FramebufferGrabberHEADERS_MOC ${FramebufferGrabberQT_HEADERS})
else(ENABLE_QT5)
else()
QT4_WRAP_CPP(FramebufferGrabberHEADERS_MOC ${FramebufferGrabberQT_HEADERS})
endif(ENABLE_QT5)
endif()
add_library(framebuffer-grabber
${FramebufferGrabberHEADERS}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,19 +2,22 @@
#include <iostream>
#include <cstdint>
// X11 includes
#include <X11/Xutil.h>
// X11Grabber includes
#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(),
_useXGetImage(useXGetImage),
_cropLeft(cropLeft),
_cropRight(cropRight),
_cropTop(cropTop),
_cropBottom(cropBottom),
_x11Display(nullptr),
_pixmap(None),
_srcFormat(nullptr),
_dstFormat(nullptr),
_srcPicture(None),
_dstPicture(None),
_screenWidth(0),
_screenHeight(0),
_croppedWidth(0),
@ -23,7 +26,9 @@ X11Grabber::X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom,
{
_imageResampler.setHorizontalPixelDecimation(horizontalPixelDecimation);
_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()
@ -35,27 +40,54 @@ X11Grabber::~X11Grabber()
}
}
void X11Grabber::setVideoMode(const VideoMode videoMode)
{
_imageResampler.set3D(videoMode);
}
void X11Grabber::freeResources()
{
// Cleanup allocated resources of the X11 grab
XShmDetach(_x11Display, &_shminfo);
XDestroyImage(_xImage);
if(_XShmAvailable && !_useXGetImage) {
XShmDetach(_x11Display, &_shminfo);
shmdt(_shminfo.shmaddr);
shmctl(_shminfo.shmid, IPC_RMID, 0);
}
if (_XRenderAvailable && !_useXGetImage) {
XRenderFreePicture(_x11Display, _srcPicture);
XRenderFreePicture(_x11Display, _dstPicture);
XFreePixmap(_x11Display, _pixmap);
}
}
void X11Grabber::setupResources()
{
if(_XShmAvailable && !_useXGetImage) {
_xImage = XShmCreateImage(_x11Display, _windowAttr.visual,
_windowAttr.depth, ZPixmap, NULL, &_shminfo,
_croppedWidth, _croppedHeight);
_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;
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()
{
@ -63,15 +95,23 @@ bool X11Grabber::Setup()
if (_x11Display == nullptr)
{
std::cerr << "X11GRABBER ERROR: Unable to open display";
if (getenv("DISPLAY"))
if (getenv("DISPLAY")) {
std::cerr << " " << std::string(getenv("DISPLAY")) << std::endl;
else
} else {
std::cerr << ". DISPLAY environment variable not set" << std::endl;
}
return false;
}
_window = DefaultRootWindow(_x11Display);
int dummy, pixmaps_supported;
_XRenderAvailable = XRenderQueryExtension(_x11Display, &dummy, &dummy);
_XShmAvailable = XShmQueryExtension(_x11Display);
XShmQueryVersion(_x11Display, &dummy, &dummy, &pixmaps_supported);
_XShmPixmapAvailable = pixmaps_supported && XShmPixmapFormat(_x11Display) == ZPixmap;
return true;
}
@ -79,7 +119,36 @@ Image<ColorRgb> & X11Grabber::grab()
{
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)
{
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 <<"] => ";
if (_screenWidth || _screenHeight)
if (_screenWidth || _screenHeight) {
freeResources();
}
_screenWidth = _windowAttr.width;
_screenHeight = _windowAttr.height;
std::cout << "[" << _screenWidth << "x" << _screenHeight <<"]" << std::endl;
if (_screenWidth > unsigned(_cropLeft + _cropRight))
_croppedWidth = _screenWidth - _cropLeft - _cropRight;
else
_croppedWidth = _screenWidth;
_croppedWidth = (_screenWidth > unsigned(_cropLeft + _cropRight))
? (_screenWidth - _cropLeft - _cropRight)
: _screenWidth;
if (_screenHeight > unsigned(_cropTop + _cropBottom))
_croppedHeight = _screenHeight - _cropTop - _cropBottom;
else
_croppedHeight = _screenHeight;
_croppedHeight = (_screenHeight > unsigned(_cropTop + _cropBottom))
? (_screenHeight - _cropTop - _cropBottom)
: _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();

View File

@ -38,17 +38,17 @@ SET(Hyperion_SOURCES
${CURRENT_SOURCE_DIR}/MessageForwarder.cpp
)
set(Hyperion_RESOURCES
SET(Hyperion_RESOURCES
${CURRENT_SOURCE_DIR}/resource.qrc
)
if(ENABLE_QT5)
QT5_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS})
QT5_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress")
else(ENABLE_QT5)
else()
QT4_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS})
QT4_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress")
endif(ENABLE_QT5)
endif()
add_library(hyperion
${Hyperion_HEADERS}
@ -60,7 +60,7 @@ add_library(hyperion
if(ENABLE_QT5)
qt5_use_modules(hyperion Widgets)
endif(ENABLE_QT5)
endif()
target_link_libraries(hyperion
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 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)
@ -479,7 +480,7 @@ RgbChannelCorrection* Hyperion::createRgbChannelCorrection(const Json::Value& co
RgbChannelAdjustment* Hyperion::createRgbChannelAdjustment(const Json::Value& colorConfig, const RgbChannel color)
{
int varR, varG, varB;
int varR=0, varG=0, varB=0;
if (color == RED)
{
varR = colorConfig.get("redChannel", 255).asInt();
@ -617,10 +618,10 @@ MessageForwarder * Hyperion::getForwarder()
Hyperion::Hyperion(const Json::Value &jsonConfig) :
_ledString(createLedString(jsonConfig["leds"], createColorOrder(jsonConfig["device"]))),
_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"])),
_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"])),
_effectEngine(nullptr),
_messageForwarder(createMessageForwarder(jsonConfig["forwarder"])),
@ -818,6 +819,11 @@ void Hyperion::clearall()
_effectEngine->allChannelsCleared();
}
int Hyperion::getCurrentPriority() const
{
return _muxer.getCurrentPriority();
}
QList<int> Hyperion::getActivePriorities() const
{
return _muxer.getPriorities();
@ -860,9 +866,9 @@ void Hyperion::update()
// Apply the correction and the transform to each led and color-channel
// Avoid applying correction, the same task is performed by adjustment
// std::vector<ColorRgb> correctedColors = _raw2ledCorrection->applyCorrection(priorityInfo.ledColors);
std::vector<ColorRgb> adjustedColors = _raw2ledAdjustment->applyAdjustment(priorityInfo.ledColors);
std::vector<ColorRgb> transformColors =_raw2ledTransform->applyTransform(adjustedColors);
std::vector<ColorRgb> ledColors = _raw2ledTemperature->applyCorrection(transformColors);
std::vector<ColorRgb> transformColors =_raw2ledTransform->applyTransform(priorityInfo.ledColors);
std::vector<ColorRgb> adjustedColors = _raw2ledAdjustment->applyAdjustment(transformColors);
std::vector<ColorRgb> ledColors = _raw2ledTemperature->applyCorrection(adjustedColors);
const std::vector<Led>& leds = _ledString.leds();
int i = 0;
for (ColorRgb& color : ledColors)
@ -885,18 +891,14 @@ void Hyperion::update()
break;
case ORDER_GBR:
{
uint8_t temp = color.red;
color.red = color.green;
color.green = color.blue;
color.blue = temp;
std::swap(color.red, color.green);
std::swap(color.green, color.blue);
break;
}
case ORDER_BRG:
{
uint8_t temp = color.red;
color.red = color.blue;
color.blue = color.green;
color.green = temp;
std::swap(color.red, color.blue);
std::swap(color.green, color.blue);
break;
}
}

View File

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

View File

@ -80,4 +80,6 @@ private:
/** The output queue */
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];
int RR = adjustment->_rgbRedAdjustment.adjustmentR(color.red);
int RG = adjustment->_rgbRedAdjustment.adjustmentG(color.red);
int RB = adjustment->_rgbRedAdjustment.adjustmentB(color.red);
int GR = adjustment->_rgbGreenAdjustment.adjustmentR(color.green);
int RG = color.red > color.green ? adjustment->_rgbRedAdjustment.adjustmentG(color.red-color.green) : 0;
int RB = color.red > color.blue ? adjustment->_rgbRedAdjustment.adjustmentB(color.red-color.blue) : 0;
int GR = color.green > color.red ? adjustment->_rgbGreenAdjustment.adjustmentR(color.green-color.red) : 0;
int GG = adjustment->_rgbGreenAdjustment.adjustmentG(color.green);
int GB = adjustment->_rgbGreenAdjustment.adjustmentB(color.green);
int BR = adjustment->_rgbBlueAdjustment.adjustmentR(color.blue);
int BG = adjustment->_rgbBlueAdjustment.adjustmentG(color.blue);
int GB = color.green > color.blue ? adjustment->_rgbGreenAdjustment.adjustmentB(color.green-color.blue) : 0;
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 ledR = RR + GR + BR;

View File

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

View File

@ -23,10 +23,10 @@ set(JsonServer_RESOURCES
if(ENABLE_QT5)
qt5_wrap_cpp(JsonServer_HEADERS_MOC ${JsonServer_QT_HEADERS})
qt5_add_resources(JsonServer_RESOURCES_RCC ${JsonServer_RESOURCES} OPTIONS "-no-compress")
else(ENABLE_QT5)
else()
qt4_wrap_cpp(JsonServer_HEADERS_MOC ${JsonServer_QT_HEADERS})
qt4_add_resources(JsonServer_RESOURCES_RCC ${JsonServer_RESOURCES} OPTIONS "-no-compress")
endif(ENABLE_QT5)
endif()
add_library(jsonserver
${JsonServer_HEADERS}
@ -39,7 +39,7 @@ add_library(jsonserver
if(ENABLE_QT5)
qt5_use_modules(jsonserver Widgets Network)
endif(ENABLE_QT5)
endif()
target_link_libraries(jsonserver
hyperion

View File

@ -1,6 +1,7 @@
// system includes
#include <stdexcept>
#include <cassert>
#include <iomanip>
// stl includes
#include <iostream>
@ -21,6 +22,7 @@
#include <hyperion/ColorCorrection.h>
#include <hyperion/ColorAdjustment.h>
#include <utils/ColorRgb.h>
#include <HyperionConfig.h>
// project includes
#include "JsonClientConnection.h"
@ -455,6 +457,7 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &)
transform["valueGain"] = colorTransform->_hsvTransform.getValueGain();
transform["saturationLGain"] = colorTransform->_hslTransform.getSaturationGain();
transform["luminanceGain"] = colorTransform->_hslTransform.getLuminanceGain();
transform["luminanceMinimum"] = colorTransform->_hslTransform.getLuminanceMinimum();
Json::Value & threshold = transform["threshold"];
threshold.append(colorTransform->_rgbRedTransform.getThreshold());
@ -529,6 +532,74 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &)
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
sendMessage(result);
}
@ -590,6 +661,11 @@ void JsonClientConnection::handleTransformCommand(const Json::Value &message)
colorTransform->_hslTransform.setLuminanceGain(transform["luminanceGain"].asDouble());
}
if (transform.isMember("luminanceMinimum"))
{
colorTransform->_hslTransform.setLuminanceMinimum(transform["luminanceMinimum"].asDouble());
}
if (transform.isMember("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
Q_INIT_RESOURCE(JsonSchemas);
}
JsonServer::~JsonServer()

View File

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

View File

@ -9,7 +9,8 @@ find_package(Threads REQUIRED)
include_directories(
../../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
SET(Leddevice_QT_HEADERS
@ -37,6 +38,8 @@ SET(Leddevice_HEADERS
${CURRENT_SOURCE_DIR}/LedDeviceFile.h
${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.h
${CURRENT_SOURCE_DIR}/LedDeviceUdp.h
${CURRENT_SOURCE_DIR}/LedDeviceUdpRaw.h
${CURRENT_SOURCE_DIR}/LedUdpDevice.h
${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.h
${CURRENT_SOURCE_DIR}/LedDeviceTpm2.h
${CURRENT_SOURCE_DIR}/LedDeviceAtmo.h
@ -61,6 +64,8 @@ SET(Leddevice_SOURCES
${CURRENT_SOURCE_DIR}/LedDeviceFile.cpp
${CURRENT_SOURCE_DIR}/LedDeviceFadeCandy.cpp
${CURRENT_SOURCE_DIR}/LedDeviceUdp.cpp
${CURRENT_SOURCE_DIR}/LedDeviceUdpRaw.cpp
${CURRENT_SOURCE_DIR}/LedUdpDevice.cpp
${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.cpp
${CURRENT_SOURCE_DIR}/LedDevicePhilipsHue.cpp
${CURRENT_SOURCE_DIR}/LedDeviceTpm2.cpp
@ -75,6 +80,7 @@ if(ENABLE_SPIDEV)
${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.h
${CURRENT_SOURCE_DIR}/LedDeviceP9813.h
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h
${CURRENT_SOURCE_DIR}/LedDeviceWs2812SPI.h
${CURRENT_SOURCE_DIR}/LedDeviceAPA102.h
)
SET(Leddevice_SOURCES
@ -84,9 +90,10 @@ if(ENABLE_SPIDEV)
${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.cpp
${CURRENT_SOURCE_DIR}/LedDeviceP9813.cpp
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp
${CURRENT_SOURCE_DIR}/LedDeviceWs2812SPI.cpp
${CURRENT_SOURCE_DIR}/LedDeviceAPA102.cpp
)
endif(ENABLE_SPIDEV)
endif()
if(ENABLE_WS2812BPWM)
SET(Leddevice_HEADERS
@ -97,7 +104,7 @@ SET(Leddevice_SOURCES
${Leddevice_SOURCES}
${CURRENT_SOURCE_DIR}/LedDeviceWS2812b.cpp
)
endif(ENABLE_WS2812BPWM)
endif()
if(ENABLE_WS281XPWM)
include_directories(../../dependencies/external/rpi_ws281x)
@ -109,7 +116,7 @@ SET(Leddevice_SOURCES
${Leddevice_SOURCES}
${CURRENT_SOURCE_DIR}/LedDeviceWS281x.cpp
)
endif(ENABLE_WS281XPWM)
endif()
if(ENABLE_TINKERFORGE)
SET(Leddevice_HEADERS
@ -120,13 +127,13 @@ if(ENABLE_TINKERFORGE)
${Leddevice_SOURCES}
${CURRENT_SOURCE_DIR}/LedDeviceTinkerforge.cpp
)
endif(ENABLE_TINKERFORGE)
endif()
if(ENABLE_QT5)
QT5_WRAP_CPP(Leddevice_HEADERS_MOC ${Leddevice_QT_HEADERS})
else(ENABLE_QT5)
else()
QT4_WRAP_CPP(Leddevice_HEADERS_MOC ${Leddevice_QT_HEADERS})
endif(ENABLE_QT5)
endif()
add_library(leddevice
@ -138,7 +145,7 @@ add_library(leddevice
if(ENABLE_QT5)
qt5_use_modules(leddevice Widgets Network)
endif(ENABLE_QT5)
endif()
target_link_libraries(leddevice
hyperion-utils

View File

@ -12,38 +12,61 @@
// hyperion local includes
#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),
_ledBuffer(0)
{
// empty
_HW_ledcount = ledcount;
}
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 endFrameSize = std::max<unsigned int>(((ledValues.size() + 15) / 16), 4);
const unsigned int mLedCount = (ledValues.size() * 4) + startFrameSize + endFrameSize;
if(_ledBuffer.size() != mLedCount){
_ledBuffer.resize(mLedCount, 0xFF);
const unsigned int endFrameSize = std::max<unsigned int>(((max_leds + 15) / 16), 4);
const unsigned int APAbufferSize = (max_leds * 4) + startFrameSize + endFrameSize;
//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[1] = 0x00;
_ledBuffer[2] = 0x00;
_ledBuffer[3] = 0x00;
}
for (unsigned iLed=1; iLed<=ledValues.size(); ++iLed) {
const ColorRgb& rgb = ledValues[iLed-1];
_ledBuffer[iLed*4] = 0xFF;
_ledBuffer[iLed*4+1] = rgb.red;
_ledBuffer[iLed*4+2] = rgb.green;
_ledBuffer[iLed*4+3] = rgb.blue;
unsigned iLed=0;
for (iLed=0; iLed < _mLedCount; ++iLed) {
const ColorRgb& rgb = ledValues[iLed];
_ledBuffer[4+iLed*4] = 0xFF;
_ledBuffer[4+iLed*4+1] = rgb.red;
_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());
}
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
///
LedDeviceAPA102(const std::string& outputDevice,
const unsigned baudrate);
const unsigned baudrate, const unsigned ledcount );
///
/// Writes the led color values to the led-device
@ -38,5 +39,7 @@ private:
/// The buffer containing the packed RGB values
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
}
LedDeviceAtmoOrb::LedDeviceAtmoOrb(const std::string &output, bool useOrbSmoothing,
int transitiontime, int skipSmoothingDiff, int port, int numLeds, std::vector<unsigned int> orbIds) :
LedDeviceAtmoOrb::LedDeviceAtmoOrb(
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),
multiCastGroupPort(port), numLeds(numLeds), orbIds(orbIds) {
multiCastGroupPort(port), numLeds(numLeds), orbIds(orbIds)
{
manager = new QNetworkAccessManager();
groupAddress = QHostAddress(multicastGroup);
udpSocket = new QUdpSocket(this);
udpSocket->bind(multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
udpSocket->bind(QHostAddress::Any, multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
joinedMulticastgroup = udpSocket->joinMulticastGroup(groupAddress);
}
int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues) {
// If not in multicast group return
if (!joinedMulticastgroup) {
return 0;

View File

@ -14,6 +14,7 @@
#include "LedDeviceLpd8806.h"
#include "LedDeviceP9813.h"
#include "LedDeviceWs2801.h"
#include "LedDeviceWs2812SPI.h"
#include "LedDeviceAPA102.h"
#endif
@ -32,6 +33,7 @@
#include "LedDeviceFile.h"
#include "LedDeviceFadeCandy.h"
#include "LedDeviceUdp.h"
#include "LedDeviceUdpRaw.h"
#include "LedDeviceHyperionUsbasp.h"
#include "LedDevicePhilipsHue.h"
#include "LedDeviceTpm2.h"
@ -124,8 +126,9 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
{
const std::string output = deviceConfig["output"].asString();
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();
device = deviceAPA102;
@ -141,6 +144,16 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
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
#ifdef ENABLE_TINKERFORGE
else if (type=="tinkerforge")
@ -306,6 +319,16 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
const unsigned maxPacket = deviceConfig["maxpacket"].asInt();
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")
{
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 pwmchannel = deviceConfig.get("pwmchannel", 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;
}
#endif
@ -349,6 +375,7 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
{
std::cout << "LEDDEVICE ERROR: Unknown/Unimplemented device " << type << std::endl;
// Unknown / Unimplemented device
exit(1);
}
return device;
}

View File

@ -105,10 +105,10 @@ CiColor PhilipsHueLight::rgbToCiColor(float red, float green, float blue) {
// Convert to x,y space.
float cx = X / (X + Y + Z);
float cy = Y / (X + Y + Z);
if (isnan(cx)) {
if (std::isnan(cx)) {
cx = 0.0f;
}
if (isnan(cy)) {
if (std::isnan(cy)) {
cy = 0.0f;
}
// 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);
// Write color if color has been changed.
if (xy != lamp.color) {
// Switch on if the lamp has been previously switched off.
if (switchOffOnBlack && lamp.color == lamp.black) {
put(getStateRoute(lamp.id), QString("{\"on\": true}"));
// From a color to black.
if (switchOffOnBlack && lamp.color != lamp.black && xy == lamp.black) {
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.
// We have to set the transition time each time.
put(getStateRoute(lamp.id),
QString("{\"xy\": [%1, %2], \"bri\": %3, \"transitiontime\": %4}").arg(xy.x).arg(xy.y).arg(
qRound(xy.bri * 255.0f)).arg(transitiontime));
}
// Switch lamp off if switchOffOnBlack is enabled and the lamp is currently on.
if (switchOffOnBlack) {
// From black to a color.
if (lamp.color == lamp.black && xy != lamp.black) {
put(getStateRoute(lamp.id), QString("{\"on\": true}"));
}
// From a color to black.
else if (lamp.color != lamp.black && xy == lamp.black) {
put(getStateRoute(lamp.id), QString("{\"on\": false}"));
}
}
// Remember last color.

View File

@ -27,7 +27,7 @@ LedDevicePiBlaster::LedDevicePiBlaster(const std::string & deviceName, const Jso
// { "gpio" : 4, "ledindex" : 0, "ledcolor" : "r" },
#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_color[i] = 'z';
@ -41,7 +41,7 @@ LedDevicePiBlaster::LedDevicePiBlaster(const std::string & deviceName, const Jso
const std::string ledcolor = gpioMap.get("ledcolor","z").asString();
// printf ("got gpio %d ledindex %d color %c\n", gpio,ledindex, ledcolor[0]);
// 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_color[gpio] = ledcolor[0]; // 1st char of string
} else {

View File

@ -17,7 +17,7 @@ struct addrinfo hints, *servinfo, *p;
//char udpbuffer[1024];
int sockfd;
int ledprotocol;
int leds_per_pkt;
unsigned leds_per_pkt;
int update_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) :
// _ofs(output.empty()?"/home/pi/LedDevice.out":output.c_str())
{
std::string hostname;
std::string port;
ledprotocol = protocol;
@ -153,8 +152,47 @@ int LedDeviceUdp::write(const std::vector<ColorRgb> & ledValues)
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;
}

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"
// 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;
led_string.freq = freq;
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].count = leds;
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].gpionum = 0;
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)
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)
led_string.channel[chan].leds[idx++] = 0;

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