Conflicts:
	bin/install_hyperion.sh
	deploy/hyperion.conf

Former-commit-id: 3a51538a8d50f7f3198a044c29200ec6dba4e931
This commit is contained in:
T. van der Zwan 2013-10-16 19:20:36 +00:00
commit e24420c6d4
40 changed files with 1645 additions and 504 deletions

View File

@ -32,6 +32,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall")
# Configure the use of QT4
find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED QUIET)
# add protocol buffers
find_package(Protobuf REQUIRED)
#SET(QT_DONT_USE_QTGUI TRUE)
#SET(QT_USE_QTCONSOLE TRUE)
include(${QT_USE_FILE})

View File

@ -1,10 +1,14 @@
HYPERION
========
An opensource 'AmbiLight' implementation controlled using the RaspBerry Pi running Raspbmc.
The intention is to replace BobLight. The replacement includes several 'improvements':
* Frame capture of screen included in deamon. This reduces the processor usages for image based led control to less than 2%.
* Priority channel can specificy a timeout on their 'command'. This allows a client or remote control to specify a fixed color and then close the connection.
* Json IP-control interface. Easy to use interface based on json format for control over TCP/IP.
Hyperion is an opensource 'AmbiLight' implementation controlled using the RaspBerry Pi running [Raspbmc](http://www.raspbmc.com). The main features of Hyperion are:
* Low CPU load. For a led string of 50 leds the CPU usage will typically be below 1.5% on a non-overclocked Pi.
* Json interface which allows easy integration into scripts.
* A command line utility allows easy testing and configuration of the color transforms (Transformation settings are not preserved over a restart at the moment...).
* Priority channels are not coupled to a specific led data provider which means that a provider can post led data and leave without the need to maintain a connection to Hyperion. This is ideal for a remote application (like our Android app).
* HyperCon. A tool which helps generate a Hyperion configuration file.
* Generic software architecture to support new devices and new algorithms easily.
More information can be found on the [wiki](https://github.com/tvdzwan/hyperion/wiki).
The source is released under MIT-License (see http://opensource.org/licenses/MIT).

16
bin/copy_binaries_to_deploy.sh Executable file
View File

@ -0,0 +1,16 @@
#!/bin/sh
if [ "$#" -ne 2 ] || ! [ -d "$1" ] || ! [ -d "$2" ]; then
echo "Usage: $0 <BUILD-DIR> <REPO-DIR>" >&2
exit 1
fi
builddir="$1"
repodir="$2"
echo build directory = $builddir
echo repository root dirrectory = $repodir
echo Copying binaries
cp -v "$builddir"/bin/hyperiond "$repodir"/deploy
cp -v "$builddir"/bin/hyperion-remote "$repodir"/deploy
cp -v "$builddir"/bin/gpio2spi "$repodir"/deploy

View File

@ -13,15 +13,22 @@ fi
# Stop hyperion daemon if it is running
initctl stop hyperion
# Copy the hyperion-binaries to the /usr/bin
wget raw.github.com/tvdzwan/hyperion/master/deploy/hyperiond -P /usr/bin/
wget raw.github.com/tvdzwan/hyperion/master/deploy/hyperion-remote -P /usr/bin/
wget -N github.com/tvdzwan/hyperion/raw/master/deploy/hyperiond -P /usr/bin/
wget -N github.com/tvdzwan/hyperion/raw/master/deploy/hyperion-remote -P /usr/bin/
# Copy the gpio changer (gpio->spi) to the /usr/bin
wget -N github.com/tvdzwan/hyperion/raw/master/deploy/gpio2spi -P /usr/bin/
# Copy the hyperion configuration file to /etc
wget raw.github.com/tvdzwan/hyperion/master/config/hyperion.config.json -P /etc/
wget -N github.com/tvdzwan/hyperion/raw/master/config/hyperion.config.json -P /etc/
# Copy the service control configuration to /etc/int
wget raw.github.com/tvdzwan/hyperion/master/bin/hyperion.conf -P /etc/init/
wget -N github.com/tvdzwan/hyperion/raw/master/deploy/hyperion.conf -P /etc/init/
# Set permissions
chmod +x /usr/bin/hyperiond
chmod +x /usr/bin/hyperion-remote
chmod +x /usr/bin/gpio2spi
# Start the hyperion daemon
initctl start hyperion

View File

@ -1,333 +1,372 @@
// Hyperion configuration
// Automatically generated configuration file for 'Hyperion daemon'
// Generated by: HyperCon (The Hyperion deamon configuration file builder
{
"device" :
{
"name" : "MyPi",
"type" : "ws2801",
"output" : "/dev/spidev0.0",
"interval" : 20000,
"rate" : 48000
},
"color" :
{
"hsv" : {
"saturationGain" : 1.0,
"valueGain" : 1.0
},
"red" :
{
"threshold" : 0.0,
"gamma" : 1.0,
"blacklevel" : 0.0,
"whitelevel" : 1.0
},
"green" :
{
"threshold" : 0.0,
"gamma" : 1.0,
"blacklevel" : 0.0,
"whitelevel" : 1.0
},
"blue" :
{
"threshold" : 0.0,
"gamma" : 1.0,
"blacklevel" : 0.0,
"whitelevel" : 1.0
}
},
"leds" :
[
{
"index" : 0,
"hscan" : { "minimum" : 47.0588, "maximum" : 52.9412 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 1,
"hscan" : { "minimum" : 41.1765, "maximum" : 47.0588 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 2,
"hscan" : { "minimum" : 35.2941, "maximum" : 41.1765 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 3,
"hscan" : { "minimum" : 29.4118, "maximum" : 35.2941 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 4,
"hscan" : { "minimum" : 23.5294, "maximum" : 29.4118 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 5,
"hscan" : { "minimum" : 17.6471, "maximum" : 23.5294 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 6,
"hscan" : { "minimum" : 11.7647, "maximum" : 17.6471 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 7,
"hscan" : { "minimum" : 5.88235, "maximum" : 11.7647 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
// TOP-LEFT Corner
{
"index" : 8,
"hscan" : { "minimum" : 0, "maximum" : 5.88235 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 9,
"hscan" : { "minimum" : 0, "maximum" : 10 },
"vscan" : { "minimum" : 10, "maximum" : 20 }
},
{
"index" : 10,
"hscan" : { "minimum" : 0, "maximum" : 10 },
"vscan" : { "minimum" : 20, "maximum" : 30 }
},
{
"index" : 11,
"hscan" : { "minimum" : 0, "maximum" : 10 },
"vscan" : { "minimum" : 30, "maximum" : 40 }
},
{
"index" : 12,
"hscan" : { "minimum" : 0, "maximum" : 10 },
"vscan" : { "minimum" : 40, "maximum" : 50 }
},
{
"index" : 13,
"hscan" : { "minimum" : 0, "maximum" : 10 },
"vscan" : { "minimum" : 50, "maximum" : 60 }
},
{
"index" : 14,
"hscan" : { "minimum" : 0, "maximum" : 10 },
"vscan" : { "minimum" : 60, "maximum" : 70 }
},
{
"index" : 15,
"hscan" : { "minimum" : 0, "maximum" : 10 },
"vscan" : { "minimum" : 70, "maximum" : 80 }
},
{
"index" : 16,
"hscan" : { "minimum" : 0, "maximum" : 10 },
"vscan" : { "minimum" : 80, "maximum" : 90 }
},
// BOTTOM-LEFT Corner
{
"index" : 17,
"hscan" : { "minimum" : 0, "maximum" : 5.88235 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 18,
"hscan" : { "minimum" : 5.88235, "maximum" : 11.7647 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 19,
"hscan" : { "minimum" : 11.7647, "maximum" : 17.6471 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 20,
"hscan" : { "minimum" : 17.6471, "maximum" : 23.5294 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 21,
"hscan" : { "minimum" : 23.5294, "maximum" : 29.4118 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 22,
"hscan" : { "minimum" : 29.4118, "maximum" : 35.2941 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 23,
"hscan" : { "minimum" : 35.2941, "maximum" : 41.1765 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 24,
"hscan" : { "minimum" : 41.1765, "maximum" : 47.0588 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 25,
"hscan" : { "minimum" : 47.0588, "maximum" : 52.9412 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 26,
"hscan" : { "minimum" : 52.9412, "maximum" : 58.8235 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 27,
"hscan" : { "minimum" : 58.8235, "maximum" : 64.7059 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 28,
"hscan" : { "minimum" : 64.7059, "maximum" : 70.5882 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 29,
"hscan" : { "minimum" : 70.5882, "maximum" : 76.4706 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 30,
"hscan" : { "minimum" : 76.4706, "maximum" : 82.3529 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 31,
"hscan" : { "minimum" : 82.3529, "maximum" : 88.2353 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 32,
"hscan" : { "minimum" : 88.2353, "maximum" : 94.1176 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
// BOTTOM-RIGHT Corner
{
"index" : 33,
"hscan" : { "minimum" : 94.1176, "maximum" : 100 },
"vscan" : { "minimum" : 90, "maximum" : 100 }
},
{
"index" : 34,
"hscan" : { "minimum" : 90, "maximum" : 100 },
"vscan" : { "minimum" : 80, "maximum" : 90 }
},
{
"index" : 35,
"hscan" : { "minimum" : 90, "maximum" : 100 },
"vscan" : { "minimum" : 70, "maximum" : 80 }
},
{
"index" : 36,
"hscan" : { "minimum" : 90, "maximum" : 100 },
"vscan" : { "minimum" : 60, "maximum" : 70 }
},
{
"index" : 37,
"hscan" : { "minimum" : 90, "maximum" : 100 },
"vscan" : { "minimum" : 50, "maximum" : 60 }
},
{
"index" : 38,
"hscan" : { "minimum" : 90, "maximum" : 100 },
"vscan" : { "minimum" : 40, "maximum" : 50 }
},
{
"index" : 39,
"hscan" : { "minimum" : 90, "maximum" : 100 },
"vscan" : { "minimum" : 30, "maximum" : 40 }
},
{
"index" : 40,
"hscan" : { "minimum" : 90, "maximum" : 100 },
"vscan" : { "minimum" : 20, "maximum" : 30 }
},
{
"index" : 41,
"hscan" : { "minimum" : 90, "maximum" : 100 },
"vscan" : { "minimum" : 10, "maximum" : 20 }
},
// TOP-RIGHT Corner
{
"index" : 42,
"hscan" : { "minimum" : 94.1176, "maximum" : 100 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 43,
"hscan" : { "minimum" : 88.2353, "maximum" : 94.1176 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 44,
"hscan" : { "minimum" : 82.3529, "maximum" : 88.2353 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 45,
"hscan" : { "minimum" : 76.4706, "maximum" : 82.3529 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 46,
"hscan" : { "minimum" : 70.5882, "maximum" : 76.4706 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 47,
"hscan" : { "minimum" : 64.7059, "maximum" : 70.5882 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 48,
"hscan" : { "minimum" : 58.8235, "maximum" : 64.7059 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
},
{
"index" : 49,
"hscan" : { "minimum" : 52.9412, "maximum" : 58.8235 },
"vscan" : { "minimum" : 0, "maximum" : 10 }
}
],
/// 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', 'test' and 'none')
/// * 'output' : The output specification depends on selected device
/// - 'ws2801' this is the device (eg '/dev/spidev0.0')
/// - 'test' this is the file used to write test output (eg '/home/pi/hyperion.out')
/// * 'rate' : The baudrate of the output to the device (only applicable for 'ws2801')
"device" :
{
"name" : "MyPi",
"type" : "ws2801",
"output" : "/dev/spidev0.0",
"rate" : 1000000
},
// The XBMC video checker will connect to XBMC to check its player state and adjust the grabbing on it
"xbmcVideoChecker" : {
// Enable the use of the XBMC checker
"enable" : true,
/// Color manipulation configuration used to tune the output colors to specific surroundings. Contains the following fields:
/// * '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)
"color" :
{
"hsv" :
{
"saturationGain" : 1.0000,
"valuGain" : 1.5000
},
"red" :
{
"threshold" : 0.1000,
"gamma" : 2.0000,
"blacklevel" : 0.0000,
"whitelevel" : 0.8000
},
"green" :
{
"threshold" : 0.1000,
"gamma" : 2.0000,
"blacklevel" : 0.0000,
"whitelevel" : 1.0000
},
"blue" :
{
"threshold" : 0.1000,
"gamma" : 2.0000,
"blacklevel" : 0.0000,
"whitelevel" : 1.0000
}
},
// Address of the hoxt running XBMC
"xbmcAddress" : "127.0.0.1",
/// 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 }
}
],
// Port used by XBMC for the TCP json service (Default disabled by XBMC for non-local clients)
"xbmcTcpPort" : 9090,
/// The boot-sequence configuration, contains the following items:
/// * type : The type of the boot-sequence ('rainbow', 'knight_rider', 'none')
/// * duration_ms : The length of the boot-sequence [ms]
"bootsequence" :
{
"type" : "Rainbow",
"duration_ms" : 3000
},
// Grab screen when XBMC is playing video
"grabVideo" : true,
/// 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
},
// Grab screen when XBMC is playing pictures
"grabPictures" : true,
/// 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
"xbmcVideoChecker" :
{
"xbmcAddress" : "127.0.0.1",
"xbmcTcpPort" : 9090,
"grabVideo" : true,
"grabPictures" : true,
"grabAudio" : true,
"grabMenu" : false
},
// Grab screen when XBMC is playing audio
"grabAudio" : 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
},
// Grab screen when XBMC is not playing anything (in menu)
"grabMenu" : true
},
"bootsequence" :
{
"type" : "rainbow",
"duration_ms" : 3000
},
"framegrabber" :
{
"width" : 64,
"height" : 64,
"frequency_Hz" : 10
}
/// The configuration of the Proto server which enables the protobuffer remote interface
/// * port : Port at which the protobuffer server is started
"protoServer" :
{
"port" : 19445
}
}

View File

@ -1 +1 @@
76f29d2a8a10e60629d08889f183d318dfee9f3f
58c9b56f08a3ea76161730b0f8b8f102e8d70143

BIN
deploy/gpio2spi Executable file

Binary file not shown.

Binary file not shown.

17
deploy/hyperion.conf Normal file
View File

@ -0,0 +1,17 @@
## Hyperion daemon
description "hyperion"
author "poljvd & tvdzwan"
start on (runlevel [2345])
stop on (runlevel [!2345])
respawn
pre-start script
modprobe spidev
/usr/bin/gpio2spi
end script
exec /usr/bin/hyperiond /etc/hyperion.config.json

Binary file not shown.

View File

@ -0,0 +1 @@
cf974e6aa1ff2a7194ce2b82fd5da5fa2373676a

View File

@ -0,0 +1,59 @@
#pragma once
// system includes
#include <cstdint>
// Qt includes
#include <QTcpServer>
#include <QSet>
// Hyperion includes
#include <hyperion/Hyperion.h>
class ProtoClientConnection;
///
/// This class creates a TCP server which accepts connections wich can then send
/// in Protocol Buffer encoded commands. This interface to Hyperion is used by
/// hyperion-remote to control the leds
///
class ProtoServer : public QObject
{
Q_OBJECT
public:
///
/// ProtoServer constructor
/// @param hyperion Hyperion instance
/// @param port port number on which to start listening for connections
///
ProtoServer(Hyperion * hyperion, uint16_t port = 19445);
~ProtoServer();
///
/// @return the port number on which this TCP listens for incoming connections
///
uint16_t getPort() const;
private slots:
///
/// Slot which is called when a client tries to create a new connection
///
void newConnection();
///
/// Slot which is called when a client closes a connection
/// @param connection The Connection object which is being closed
///
void closedConnection(ProtoClientConnection * connection);
private:
/// Hyperion instance
Hyperion * _hyperion;
/// The TCP server object
QTcpServer _server;
/// List with open connections
QSet<ProtoClientConnection *> _openConnections;
};

View File

@ -7,5 +7,6 @@ add_subdirectory(bootsequence)
add_subdirectory(dispmanx-grabber)
add_subdirectory(hyperion)
add_subdirectory(jsonserver)
add_subdirectory(protoserver)
add_subdirectory(utils)
add_subdirectory(xbmcvideochecker)

View File

@ -1,3 +1,6 @@
// stl includes
#include <cctype>
#include <algorithm>
// Bootsequence includes
#include <bootsequence/BootSequenceFactory.h>
@ -8,7 +11,8 @@
BootSequence * BootSequenceFactory::createBootSequence(Hyperion * hyperion, const Json::Value & jsonConfig)
{
const std::string type = jsonConfig["type"].asString();
std::string type = jsonConfig["type"].asString();
std::transform(type.begin(), type.end(), type.begin(), ::tolower);
if (type == "none")
{
@ -19,7 +23,7 @@ BootSequence * BootSequenceFactory::createBootSequence(Hyperion * hyperion, cons
const unsigned duration_ms = jsonConfig["duration_ms"].asUInt();
return new RainbowBootSequence(hyperion, duration_ms);
}
else if (type == "knightrider")
else if (type == "knightrider" || type == "knight rider")
{
const unsigned duration_ms = jsonConfig["duration_ms"].asUInt();
return new KittBootSequence(hyperion, duration_ms);

View File

@ -1,18 +1,6 @@
#include "DispmanxFrameGrabber.h"
// Because the shapshot function is incompatible between versions (use of different enum as
// third argument) and no proper version number is available as preprocessor define we cast the
// function to the same function with the third argument as 'int'.
// This way we can call the function in both versions of the VideoCore library without
// switching.
static int my_vc_dispmanx_snapshot(DISPMANX_DISPLAY_HANDLE_T display, DISPMANX_RESOURCE_HANDLE_T snapshot_resource, int transform)
{
typedef int (*SnapshotFunctionPtr)(DISPMANX_DISPLAY_HANDLE_T, DISPMANX_RESOURCE_HANDLE_T, int);
SnapshotFunctionPtr snapshot = (SnapshotFunctionPtr) &vc_dispmanx_snapshot;
return (*snapshot)(display, snapshot_resource, transform);
}
DispmanxFrameGrabber::DispmanxFrameGrabber(const unsigned width, const unsigned height) :
_vc_display(0),
_vc_resource(0),
@ -77,7 +65,7 @@ void DispmanxFrameGrabber::grabFrame(RgbImage& image)
_vc_display = vc_dispmanx_display_open(0);
// Create the snapshot (incl down-scaling)
my_vc_dispmanx_snapshot(_vc_display, _vc_resource, _vc_flags);
vc_dispmanx_snapshot(_vc_display, _vc_resource, (DISPMANX_TRANSFORM_T) _vc_flags);
// Read the snapshot into the memory
void* image_ptr = image.memptr();

View File

@ -66,10 +66,10 @@ LedString Hyperion::createLedString(const Json::Value& ledsConfig)
led.index = ledConfig["index"].asInt();
const Json::Value& hscanConfig = ledConfig["hscan"];
const Json::Value& vscanConfig = ledConfig["vscan"];
led.minX_frac = std::max(0.0, std::min(100.0, hscanConfig["minimum"].asDouble()))/100.0;
led.maxX_frac = std::max(0.0, std::min(100.0, hscanConfig["maximum"].asDouble()))/100.0;
led.minY_frac = 1.0 - std::max(0.0, std::min(100.0, vscanConfig["maximum"].asDouble()))/100.0;
led.maxY_frac = 1.0 - std::max(0.0, std::min(100.0, vscanConfig["minimum"].asDouble()))/100.0;
led.minX_frac = std::max(0.0, std::min(1.0, hscanConfig["minimum"].asDouble()));
led.maxX_frac = std::max(0.0, std::min(1.0, hscanConfig["maximum"].asDouble()));
led.minY_frac = std::max(0.0, std::min(1.0, vscanConfig["maximum"].asDouble()));
led.maxY_frac = std::max(0.0, std::min(1.0, vscanConfig["minimum"].asDouble()));
ledString.leds().push_back(led);
}

View File

@ -1,50 +1,47 @@
{
"type":"object",
"required":true,
"properties":{
"device": {
"type":"object",
"required":true,
"properties":{
"name": {
"type":"string",
"required":true
"type" : "object",
"required" : true,
"properties" : {
"device" : {
"type" : "object",
"required" : true,
"properties" : {
"name" : {
"type" : "string",
"required" : true
},
"type": {
"type":"string",
"required":true
"type" : {
"type" : "string",
"required" : true
},
"output": {
"type":"string",
"required":true
"output" : {
"type" : "string",
"required" : true
},
"interval": {
"type":"integer",
"required":true
},
"rate": {
"type":"integer",
"required":true
"rate" : {
"type" : "integer",
"required" : true,
"minimum" : 0
}
},
"additionalProperties": false
"additionalProperties" : false
},
"color": {
"type":"object",
"required":true,
"required":false,
"properties": {
"hsv" : {
"type" : "object",
"required" : true,
"required" : false,
"properties" : {
"saturationGain" : {
"type" : "number",
"required" : true,
"required" : false,
"minimum" : 0.0
},
"valueGain" : {
"type" : "number",
"required" : true,
"required" : false,
"minimum" : 0.0
}
},
@ -52,77 +49,81 @@
},
"red": {
"type":"object",
"required":true,
"required":false,
"properties":{
"gamma": {
"type":"number",
"required":true
"required":false
},
"blacklevel": {
"type":"number",
"required":true
"required":false
},
"whitelevel": {
"type":"number",
"required":true
"required":false
},
"threshold": {
"type":"number",
"required":true,
"required":false,
"minimum" : 0.0,
"maximum" : 1.0
}
}
},
"additionalProperties" : false
},
"green": {
"type":"object",
"required":true,
"required":false,
"properties":{
"gamma": {
"type":"number",
"required":true
"required":false
},
"blacklevel": {
"type":"number",
"required":true
"required":false
},
"whitelevel": {
"type":"number",
"required":true
"required":false
},
"threshold": {
"type":"number",
"required":true,
"required":false,
"minimum" : 0.0,
"maximum" : 1.0
}
}
},
"additionalProperties" : false
},
"blue": {
"type":"object",
"required":true,
"required":false,
"properties":{
"gamma": {
"type":"number",
"required":true
"required":false
},
"whitelevel": {
"type":"number",
"required":true
"required":false
},
"blacklevel": {
"type":"number",
"required":true
"required":false
},
"threshold": {
"type":"number",
"required":true,
"required":false,
"minimum" : 0.0,
"maximum" : 1.0
}
}
},
"additionalProperties" : false
}
}
},
"additionalProperties" : false
},
"leds": {
"type":"array",
@ -146,7 +147,8 @@
"type":"number",
"required":true
}
}
},
"additionalProperties" : false
},
"vscan": {
"type":"object",
@ -160,20 +162,18 @@
"type":"number",
"required":true
}
}
},
"additionalProperties" : false
}
}
},
"additionalProperties" : false
}
},
"xbmcVideoChecker" :
{
"type" : "object",
"required" : true,
"required" : false,
"properties" : {
"enable" : {
"type" : "boolean",
"required" : true
},
"xbmcAddress" : {
"type" : "string",
"required" : true
@ -204,7 +204,7 @@
"bootsequence" :
{
"type" : "object",
"required" : true,
"required" : false,
"properties" : {
"type" : {
"type" : "string",
@ -220,7 +220,7 @@
"framegrabber" :
{
"type" : "object",
"required" : true,
"required" : false,
"properties" : {
"width" : {
"type" : "integer",
@ -236,6 +236,34 @@
}
},
"additionalProperties" : false
},
"jsonServer" :
{
"type" : "object",
"required" : false,
"properties" : {
"port" : {
"type" : "integer",
"required" : true,
"minimum" : 0,
"maximum" : 65535
}
},
"additionalProperties" : false
},
"protoServer" :
{
"type" : "object",
"required" : false,
"properties" : {
"port" : {
"type" : "integer",
"required" : true,
"minimum" : 0,
"maximum" : 65535
}
},
"additionalProperties" : false
}
},
"additionalProperties" : false

View File

@ -0,0 +1,52 @@
# Define the current source locations
set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/protoserver)
set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/protoserver)
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${PROTOBUF_INCLUDE_DIRS})
# Group the headers that go through the MOC compiler
set(ProtoServer_QT_HEADERS
${CURRENT_HEADER_DIR}/ProtoServer.h
${CURRENT_SOURCE_DIR}/ProtoClientConnection.h
)
set(ProtoServer_HEADERS
)
set(ProtoServer_SOURCES
${CURRENT_SOURCE_DIR}/ProtoServer.cpp
${CURRENT_SOURCE_DIR}/ProtoClientConnection.cpp
)
set(ProtoServer_PROTOS
${CURRENT_SOURCE_DIR}/message.proto
)
protobuf_generate_cpp(ProtoServer_PROTO_SRCS ProtoServer_PROTO_HDRS
${ProtoServer_PROTOS}
)
qt4_wrap_cpp(ProtoServer_HEADERS_MOC ${ProtoServer_QT_HEADERS})
add_library(protoserver
${ProtoServer_HEADERS}
${ProtoServer_QT_HEADERS}
${ProtoServer_SOURCES}
${ProtoServer_HEADERS_MOC}
${ProtoServer_PROTOS}
${ProtoServer_PROTO_SRCS}
${ProtoServer_PROTO_HDRS}
)
target_link_libraries(protoserver
hyperion
hyperion-utils
${PROTOBUF_LIBRARIES})
qt4_use_modules(protoserver
Core
Gui
Network)

View File

@ -0,0 +1,223 @@
// system includes
#include <stdexcept>
#include <cassert>
// stl includes
#include <iostream>
#include <sstream>
#include <iterator>
// Qt includes
#include <QRgb>
#include <QResource>
#include <QDateTime>
// hyperion util includes
#include "hyperion/ImageProcessorFactory.h"
#include "hyperion/ImageProcessor.h"
#include "utils/RgbColor.h"
// project includes
#include "ProtoClientConnection.h"
ProtoClientConnection::ProtoClientConnection(QTcpSocket *socket, Hyperion * hyperion) :
QObject(),
_socket(socket),
_imageProcessor(ImageProcessorFactory::getInstance().newImageProcessor()),
_hyperion(hyperion),
_receiveBuffer()
{
// connect internal signals and slots
connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
connect(_socket, SIGNAL(readyRead()), this, SLOT(readData()));
}
ProtoClientConnection::~ProtoClientConnection()
{
delete _socket;
}
void ProtoClientConnection::readData()
{
_receiveBuffer += _socket->readAll();
// check if we can read a message size
if (_receiveBuffer.size() <= 4)
{
return;
}
// read the message size
uint32_t messageSize =
((_receiveBuffer[0]<<24) & 0xFF000000) |
((_receiveBuffer[1]<<16) & 0x00FF0000) |
((_receiveBuffer[2]<< 8) & 0x0000FF00) |
((_receiveBuffer[3] ) & 0x000000FF);
// check if we can read a complete message
if ((uint32_t) _receiveBuffer.size() < messageSize + 4)
{
return;
}
// read a message
proto::HyperionRequest message;
if (!message.ParseFromArray(_receiveBuffer.data() + 4, messageSize))
{
sendErrorReply("Unable to parse message");
}
// handle the message
handleMessage(message);
// remove message data from buffer
_receiveBuffer = _receiveBuffer.mid(messageSize + 4);
}
void ProtoClientConnection::socketClosed()
{
emit connectionClosed(this);
}
void ProtoClientConnection::handleMessage(const proto::HyperionRequest & message)
{
switch (message.command())
{
case proto::HyperionRequest::COLOR:
if (!message.HasExtension(proto::ColorRequest::colorRequest))
{
sendErrorReply("Received COLOR command without ColorRequest");
break;
}
handleColorCommand(message.GetExtension(proto::ColorRequest::colorRequest));
break;
case proto::HyperionRequest::IMAGE:
if (!message.HasExtension(proto::ImageRequest::imageRequest))
{
sendErrorReply("Received IMAGE command without ImageRequest");
break;
}
handleImageCommand(message.GetExtension(proto::ImageRequest::imageRequest));
break;
case proto::HyperionRequest::CLEAR:
if (!message.HasExtension(proto::ClearRequest::clearRequest))
{
sendErrorReply("Received CLEAR command without ClearRequest");
break;
}
handleClearCommand(message.GetExtension(proto::ClearRequest::clearRequest));
break;
case proto::HyperionRequest::CLEARALL:
handleClearallCommand();
break;
default:
handleNotImplemented();
}
}
void ProtoClientConnection::handleColorCommand(const proto::ColorRequest &message)
{
// extract parameters
int priority = message.priority();
int duration = message.has_duration() ? message.duration() : -1;
RgbColor color;
color.red = qRed(message.rgbcolor());
color.green = qGreen(message.rgbcolor());
color.blue = qBlue(message.rgbcolor());
// set output
_hyperion->setColor(priority, color, duration);
// send reply
sendSuccessReply();
}
void ProtoClientConnection::handleImageCommand(const proto::ImageRequest &message)
{
// extract parameters
int priority = message.priority();
int duration = message.has_duration() ? message.duration() : -1;
int width = message.imagewidth();
int height = message.imageheight();
const std::string & imageData = message.imagedata();
// check consistency of the size of the received data
if ((int) imageData.size() != width*height*3)
{
sendErrorReply("Size of image data does not match with the width and height");
return;
}
// set width and height of the image processor
_imageProcessor->setSize(width, height);
// create RgbImage
RgbImage image(width, height);
memcpy(image.memptr(), imageData.c_str(), imageData.size());
// process the image
std::vector<RgbColor> ledColors = _imageProcessor->process(image);
_hyperion->setColors(priority, ledColors, duration);
// send reply
sendSuccessReply();
}
void ProtoClientConnection::handleClearCommand(const proto::ClearRequest &message)
{
// extract parameters
int priority = message.priority();
// clear priority
_hyperion->clear(priority);
// send reply
sendSuccessReply();
}
void ProtoClientConnection::handleClearallCommand()
{
// clear priority
_hyperion->clearall();
// send reply
sendSuccessReply();
}
void ProtoClientConnection::handleNotImplemented()
{
sendErrorReply("Command not implemented");
}
void ProtoClientConnection::sendMessage(const google::protobuf::Message &message)
{
std::string serializedReply = message.SerializeAsString();
uint32_t size = serializedReply.size();
uint8_t sizeData[] = {uint8_t(size >> 24), uint8_t(size >> 16), uint8_t(size >> 8), uint8_t(size)};
_socket->write((const char *) sizeData, sizeof(sizeData));
_socket->write(serializedReply.data(), serializedReply.length());
_socket->flush();
}
void ProtoClientConnection::sendSuccessReply()
{
// create reply
proto::HyperionReply reply;
reply.set_success(true);
// send reply
sendMessage(reply);
}
void ProtoClientConnection::sendErrorReply(const std::string &error)
{
// create reply
proto::HyperionReply reply;
reply.set_success(false);
reply.set_error(error);
// send reply
sendMessage(reply);
}

View File

@ -0,0 +1,126 @@
#pragma once
// stl includes
#include <string>
// Qt includes
#include <QByteArray>
#include <QTcpSocket>
// Hyperion includes
#include <hyperion/Hyperion.h>
// proto includes
#include "message.pb.h"
class ImageProcessor;
///
/// The Connection object created by \a ProtoServer when a new connection is establshed
///
class ProtoClientConnection : public QObject
{
Q_OBJECT
public:
///
/// Constructor
/// @param socket The Socket object for this connection
/// @param hyperion The Hyperion server
///
ProtoClientConnection(QTcpSocket * socket, Hyperion * hyperion);
///
/// Destructor
///
~ProtoClientConnection();
signals:
///
/// Signal which is emitted when the connection is being closed
/// @param connection This connection object
///
void connectionClosed(ProtoClientConnection * connection);
private slots:
///
/// Slot called when new data has arrived
///
void readData();
///
/// Slot called when this connection is being closed
///
void socketClosed();
private:
///
/// Handle an incoming Proto message
///
/// @param message the incoming message as string
///
void handleMessage(const proto::HyperionRequest &message);
///
/// Handle an incoming Proto Color message
///
/// @param message the incoming message
///
void handleColorCommand(const proto::ColorRequest & message);
///
/// Handle an incoming Proto Image message
///
/// @param message the incoming message
///
void handleImageCommand(const proto::ImageRequest & message);
///
/// Handle an incoming Proto Clear message
///
/// @param message the incoming message
///
void handleClearCommand(const proto::ClearRequest & message);
///
/// Handle an incoming Proto Clearall message
///
void handleClearallCommand();
///
/// Handle an incoming Proto message of unknown type
///
void handleNotImplemented();
///
/// Send a message to the connected client
///
/// @param message The Proto message to send
///
void sendMessage(const google::protobuf::Message &message);
///
/// Send a standard reply indicating success
///
void sendSuccessReply();
///
/// Send an error message back to the client
///
/// @param error String describing the error
///
void sendErrorReply(const std::string & error);
private:
/// The TCP-Socket that is connected tot the Proto-client
QTcpSocket * _socket;
/// The processor for translating images to led-values
ImageProcessor * _imageProcessor;
/// Link to Hyperion for writing led-values to a priority channel
Hyperion * _hyperion;
/// The buffer used for reading data from the socket
QByteArray _receiveBuffer;
};

View File

@ -0,0 +1,57 @@
// system includes
#include <stdexcept>
// project includes
#include <protoserver/ProtoServer.h>
#include "ProtoClientConnection.h"
ProtoServer::ProtoServer(Hyperion *hyperion, uint16_t port) :
QObject(),
_hyperion(hyperion),
_server(),
_openConnections()
{
if (!_server.listen(QHostAddress::Any, port))
{
throw std::runtime_error("Proto server could not bind to port");
}
// Set trigger for incoming connections
connect(&_server, SIGNAL(newConnection()), this, SLOT(newConnection()));
}
ProtoServer::~ProtoServer()
{
foreach (ProtoClientConnection * connection, _openConnections) {
delete connection;
}
}
uint16_t ProtoServer::getPort() const
{
return _server.serverPort();
}
void ProtoServer::newConnection()
{
QTcpSocket * socket = _server.nextPendingConnection();
if (socket != nullptr)
{
std::cout << "New proto connection" << std::endl;
ProtoClientConnection * connection = new ProtoClientConnection(socket, _hyperion);
_openConnections.insert(connection);
// register slot for cleaning up after the connection closed
connect(connection, SIGNAL(connectionClosed(ProtoClientConnection*)), this, SLOT(closedConnection(ProtoClientConnection*)));
}
}
void ProtoServer::closedConnection(ProtoClientConnection *connection)
{
std::cout << "Proto connection closed" << std::endl;
_openConnections.remove(connection);
// schedule to delete the connection object
connection->deleteLater();
}

View File

@ -0,0 +1,69 @@
package proto;
message HyperionRequest {
enum Command {
COLOR = 1;
IMAGE = 2;
CLEAR = 3;
CLEARALL = 4;
}
// command specification
required Command command = 1;
// extensions to define all specific requests
extensions 10 to 100;
}
message ColorRequest {
extend HyperionRequest {
required ColorRequest colorRequest = 10;
}
// priority to use when setting the color
required int32 priority = 1;
// integer value containing the rgb color (0x00RRGGBB)
required int32 rgbColor = 2;
// duration of the request (negative results in infinite)
optional int32 duration = 3;
}
message ImageRequest {
extend HyperionRequest {
required ImageRequest imageRequest = 11;
}
// priority to use when setting the image
required int32 priority = 1;
// width of the image
required int32 imagewidth = 2;
// height of the image
required int32 imageheight = 3;
// image data
required bytes imagedata = 4;
// duration of the request (negative results in infinite)
optional int32 duration = 5;
}
message ClearRequest {
extend HyperionRequest {
required ClearRequest clearRequest = 12;
}
// priority which need to be cleared
required int32 priority = 1;
}
message HyperionReply {
// flag indication success or failure
required bool success = 1;
// string indicating the reason for failure (if applicable)
optional string error = 2;
}

View File

@ -45,8 +45,6 @@ void HsvTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue) con
uint8_t saturation, value;
rgb2hsv(red, green, blue, hue, saturation, value);
std::cout << int(hue) << " " << int(saturation) << " " << int(value) << std::endl;
int s = saturation * _saturationGain;
if (s > 255)
saturation = 255;

View File

@ -7,7 +7,7 @@ XBMCVideoChecker::XBMCVideoChecker(const std::string & address, uint16_t port, u
QObject(),
_address(QString::fromStdString(address)),
_port(port),
_request("{\"jsonrpc\":\"2.0\",\"method\":\"Player.GetActivePlayers\",\"id\":666}"),
_request(R"({"jsonrpc":"2.0","method":"Player.GetActivePlayers","id":666})"),
_timer(),
_socket(),
_grabVideo(grabVideo),

View File

@ -44,16 +44,16 @@ public class MiscConfigPanel extends JPanel {
add(mMenuLabel);
mMenuCombo = new JComboBox<>(new String[] {"On", "Off"});
mMenuCombo.setSelectedItem("Off");
mMenuCombo.setSelectedItem(mMiscConfig.mMenuOn? "On": "Off");
mMenuCombo.setToolTipText("Enables('On') or disbales('Off') the ambi-light in the XBMC Menu");
mMenuCombo.addActionListener(mActionListener);
add(mMenuCombo);
mVideoLabel = new JLabel("Video");
add(mVideoLabel);
mVideoCombo = new JComboBox<>(new String[] {"On", "Off"});
mVideoCombo.setSelectedItem("On");
mVideoCombo.setSelectedItem(mMiscConfig.mVideoOn? "On": "Off");
mVideoCombo.setToolTipText("Enables('On') or disbales('Off') the ambi-light during video playback");
mVideoCombo.addActionListener(mActionListener);
add(mVideoCombo);
@ -62,7 +62,7 @@ public class MiscConfigPanel extends JPanel {
add(mPictureLabel);
mPictureCombo = new JComboBox<>(new String[] {"On", "Off"});
mPictureCombo.setSelectedItem("Off");
mPictureCombo.setSelectedItem(mMiscConfig.mPictureOn? "On": "Off");
mPictureCombo.setToolTipText("Enables('On') or disbales('Off') the ambi-light when viewing pictures");
mPictureCombo.addActionListener(mActionListener);
add(mPictureCombo);
@ -71,7 +71,7 @@ public class MiscConfigPanel extends JPanel {
add(mAudioLabel);
mAudioCombo = new JComboBox<>(new String[] {"On", "Off"});
mAudioCombo.setSelectedItem("Off");
mAudioCombo.setSelectedItem(mMiscConfig.mAudioOn? "On": "Off");
mAudioCombo.setToolTipText("Enables('On') or disbales('Off') the ambi-light when listing to audio");
mAudioCombo.addActionListener(mActionListener);
add(mAudioCombo);

View File

@ -1 +1 @@
176f5c8e4a406929620764b19e77c5120570325c
d37be0ef34a74fb15c9ec81e9ebadb57de62d294

View File

@ -1 +1 @@
048b062d931b7754a533734a1dec21692bce2dc6
1df18121f930623884da3de93f146f93d11f621c

View File

@ -1 +1 @@
bd23dc9ed11283d527effc78e437e8ef18903123
97019f8cd170a7792bb81ae09efd690669eef567

View File

@ -1 +1 @@
427d6ffe9935a3011f05b13bcf44a47796e99a80
b607e73b98996bfa40d19d508be01919552552d0

View File

@ -1 +1 @@
0dd04b5ec932aa251136740c6ea87f71847eb537
0d3aafb4a85649e53888a660b87de98f59f0ec32

View File

@ -1 +1 @@
10fa576b5a494b9e0377e8b944904bfa7ac97cb6
7962c1194cb2a2b7af6c3b34151701e113f00087

View File

@ -1 +1 @@
620cf4f8a4c8dc62cabe9045c1ad04c38cecb942
ad1aba652ea186845d0c340cbeca7efb9d662e10

View File

@ -10,30 +10,30 @@ public class ColorConfig {
/** The saturation gain (in HSV space) */
double mSaturationGain = 1.0;
/** The value gain (in HSV space) */
double mValueGain = 1.0;
double mValueGain = 1.5;
/** The minimum required RED-value (in RGB space) */
double mRedThreshold = 0.0;
double mRedThreshold = 0.1;
/** The gamma-curve correct for the RED-value (in RGB space) */
double mRedGamma = 1.0;
double mRedGamma = 2.0;
/** The black-level of the RED-value (in RGB space) */
double mRedBlacklevel = 0.0;
/** The white-level of the RED-value (in RGB space) */
double mRedWhitelevel = 1.0;
double mRedWhitelevel = 0.8;
/** The minimum required GREEN-value (in RGB space) */
double mGreenThreshold = 0.0;
double mGreenThreshold = 0.1;
/** The gamma-curve correct for the GREEN-value (in RGB space) */
double mGreenGamma = 1.0;
double mGreenGamma = 2.0;
/** The black-level of the GREEN-value (in RGB space) */
double mGreenBlacklevel = 0.0;
/** The white-level of the GREEN-value (in RGB space) */
double mGreenWhitelevel = 1.0;
/** The minimum required BLUE-value (in RGB space) */
double mBlueThreshold = 0.0;
double mBlueThreshold = 0.1;
/** The gamma-curve correct for the BLUE-value (in RGB space) */
double mBlueGamma = 1.0;
double mBlueGamma = 2.0;
/** The black-level of the BLUE-value (in RGB space) */
double mBlueBlacklevel = 0.0;
/** The white-level of the BLUE-value (in RGB space) */
@ -75,8 +75,8 @@ public class ColorConfig {
StringBuffer strBuf = new StringBuffer();
strBuf.append("\t\t\"hsv\" :\n");
strBuf.append("\t\t{\n");
strBuf.append(String.format(Locale.ROOT, "\t\t\tsaturationGain : %.4f,\n", mSaturationGain));
strBuf.append(String.format(Locale.ROOT, "\t\t\tvaluGain : %.4f\n", mValueGain));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"saturationGain\" : %.4f,\n", mSaturationGain));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"valuGain\" : %.4f\n", mValueGain));
strBuf.append("\t\t}");
return strBuf.toString();
@ -92,26 +92,26 @@ public class ColorConfig {
strBuf.append("\t\t\"red\" :\n");
strBuf.append("\t\t{\n");
strBuf.append(String.format(Locale.ROOT, "\t\t\tthreshold : %.4f,\n", mRedThreshold));
strBuf.append(String.format(Locale.ROOT, "\t\t\tgamma : %.4f,\n", mRedGamma));
strBuf.append(String.format(Locale.ROOT, "\t\t\tblacklevel : %.4f,\n", mRedBlacklevel));
strBuf.append(String.format(Locale.ROOT, "\t\t\twhitelevel : %.4f\n", mRedWhitelevel));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"threshold\" : %.4f,\n", mRedThreshold));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"gamma\" : %.4f,\n", mRedGamma));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"blacklevel\" : %.4f,\n", mRedBlacklevel));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"whitelevel\" : %.4f\n", mRedWhitelevel));
strBuf.append("\t\t},\n");
strBuf.append("\t\t\"green\" :\n");
strBuf.append("\t\t{\n");
strBuf.append(String.format(Locale.ROOT, "\t\t\tthreshold : %.4f,\n", mGreenThreshold));
strBuf.append(String.format(Locale.ROOT, "\t\t\tgamma : %.4f,\n", mGreenGamma));
strBuf.append(String.format(Locale.ROOT, "\t\t\tblacklevel : %.4f,\n", mGreenBlacklevel));
strBuf.append(String.format(Locale.ROOT, "\t\t\twhitelevel : %.4f\n", mGreenWhitelevel));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"threshold\" : %.4f,\n", mGreenThreshold));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"gamma\" : %.4f,\n", mGreenGamma));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"blacklevel\" : %.4f,\n", mGreenBlacklevel));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"whitelevel\" : %.4f\n", mGreenWhitelevel));
strBuf.append("\t\t},\n");
strBuf.append("\t\t\"blue\" :\n");
strBuf.append("\t\t{\n");
strBuf.append(String.format(Locale.ROOT, "\t\t\tthreshold : %.4f,\n", mBlueThreshold));
strBuf.append(String.format(Locale.ROOT, "\t\t\tgamma : %.4f,\n", mBlueGamma));
strBuf.append(String.format(Locale.ROOT, "\t\t\tblacklevel : %.4f,\n", mBlueBlacklevel));
strBuf.append(String.format(Locale.ROOT, "\t\t\twhitelevel : %.4f\n", mBlueWhitelevel));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"threshold\" : %.4f,\n", mBlueThreshold));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"gamma\" : %.4f,\n", mBlueGamma));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"blacklevel\" : %.4f,\n", mBlueBlacklevel));
strBuf.append(String.format(Locale.ROOT, "\t\t\t\"whitelevel\" : %.4f\n", mBlueWhitelevel));
strBuf.append("\t\t}");
return strBuf.toString();

View File

@ -12,7 +12,7 @@ public class DeviceConfig {
/** The device 'file' name */
String mOutput = "/dev/spidev0.0";
/** The baudrate of the device */
int mBaudrate = 48000;
int mBaudrate = 1000000;
/**
* Creates the JSON string of the configuration as used in the Hyperion daemon configfile

View File

@ -18,8 +18,6 @@ public class MiscConfig {
/** The interval of frame grabs (screen shots) [ms] */
public int mFrameGrabberInterval_ms = 100;
/** Flag enabling/disabling XBMC communication */
public boolean mXbmcChecker = true;
/** The IP-address of XBMC */
public String mXbmcAddress = "127.0.0.1";
/** The TCP JSON-Port of XBMC */
@ -29,9 +27,15 @@ public class MiscConfig {
/** Flag indicating that the frame-grabber is on during XBMC menu */
public boolean mMenuOn = false;
/** Flag indicating that the frame-grabber is on during picture slideshow */
public boolean mPictureOn = false;
public boolean mPictureOn = true;
/** Flag indicating that the frame-grabber is on during audio playback */
public boolean mAudioOn = false;
public boolean mAudioOn = true;
/** The TCP port at which the JSON server is listening for incoming connections */
public int mJsonPort = 19444;
/** The TCP port at which the Protobuf server is listening for incoming connections */
public int mProtoPort = 19445;
/**
* Creates the JSON string of the configuration as used in the Hyperion daemon configfile
@ -41,26 +45,6 @@ public class MiscConfig {
public String toJsonString() {
StringBuffer strBuf = new StringBuffer();
strBuf.append("\t/// The configuration of the XBMC connection used to enable and disable the frame-grabber. Contains the following fields: \n");
strBuf.append("\t/// * enable : Flag for enabling or disabling the XBMC-based frame grabbing\n");
strBuf.append("\t/// * xbmcAddress : The IP address of the XBMC-host\n");
strBuf.append("\t/// * xbmcTcpPort : The TCP-port of the XBMC-server\n");
strBuf.append("\t/// * grabVideo : Flag indicating that the frame-grabber is on(true) during video playback\n");
strBuf.append("\t/// * grabPictures : Flag indicating that the frame-grabber is on(true) during picture show\n");
strBuf.append("\t/// * grabAudio : Flag indicating that the frame-grabber is on(true) during audio playback\n");
strBuf.append("\t/// * grabMenu : Flag indicating that the frame-grabber is on(true) in the XBMC menu\n");
strBuf.append("\t\"xbmcVideoChecker\" :\n");
strBuf.append("\t{\n");
strBuf.append(String.format(Locale.ROOT, "\t\t\"enable\" : %s,\n", mXbmcChecker));
strBuf.append(String.format(Locale.ROOT, "\t\t\"xbmcAddress\" : \"%s\",\n", mXbmcAddress));
strBuf.append(String.format(Locale.ROOT, "\t\t\"xbmcTcpPort\" : %d,\n", mXbmcTcpPort));
strBuf.append(String.format(Locale.ROOT, "\t\t\"grabVideo\" : %s,\n", mVideoOn));
strBuf.append(String.format(Locale.ROOT, "\t\t\"grabPictures\" : %s,\n", mPictureOn));
strBuf.append(String.format(Locale.ROOT, "\t\t\"grabAudio\" : %s,\n", mAudioOn));
strBuf.append(String.format(Locale.ROOT, "\t\t\"grabMenu\" : %s\n", mMenuOn));
strBuf.append("\t},\n");
strBuf.append("\t/// The boot-sequence configuration, contains the following items: \n");
strBuf.append("\t/// * type : The type of the boot-sequence ('rainbow', 'knight_rider', 'none') \n");
strBuf.append("\t/// * duration_ms : The length of the boot-sequence [ms]\n");
@ -69,8 +53,8 @@ public class MiscConfig {
strBuf.append("\t{\n");
strBuf.append(String.format(Locale.ROOT, "\t\t\"type\" : \"%s\",\n", mBootSequence));
strBuf.append(String.format(Locale.ROOT, "\t\t\"duration_ms\" : %d\n", mBootSequenceLength_ms));
strBuf.append("\t},\n");
strBuf.append("\t},\n\n");
strBuf.append("\t/// The configuration for the frame-grabber, contains the following items: \n");
strBuf.append("\t/// * width : The width of the grabbed frames [pixels]\n");
@ -82,10 +66,44 @@ public class MiscConfig {
strBuf.append(String.format(Locale.ROOT, "\t\t\"width\" : %d,\n", mFrameGrabberWidth));
strBuf.append(String.format(Locale.ROOT, "\t\t\"height\" : %d,\n", mFrameGrabberHeight));
strBuf.append(String.format(Locale.ROOT, "\t\t\"frequency_Hz\" : %.1f\n", 1000.0/mFrameGrabberInterval_ms));
strBuf.append("\t}");
strBuf.append("\t},\n\n");
strBuf.append("\t/// The configuration of the XBMC connection used to enable and disable the frame-grabber. Contains the following fields: \n");
strBuf.append("\t/// * xbmcAddress : The IP address of the XBMC-host\n");
strBuf.append("\t/// * xbmcTcpPort : The TCP-port of the XBMC-server\n");
strBuf.append("\t/// * grabVideo : Flag indicating that the frame-grabber is on(true) during video playback\n");
strBuf.append("\t/// * grabPictures : Flag indicating that the frame-grabber is on(true) during picture show\n");
strBuf.append("\t/// * grabAudio : Flag indicating that the frame-grabber is on(true) during audio playback\n");
strBuf.append("\t/// * grabMenu : Flag indicating that the frame-grabber is on(true) in the XBMC menu\n");
strBuf.append("\t\"xbmcVideoChecker\" :\n");
strBuf.append("\t{\n");
strBuf.append(String.format(Locale.ROOT, "\t\t\"xbmcAddress\" : \"%s\",\n", mXbmcAddress));
strBuf.append(String.format(Locale.ROOT, "\t\t\"xbmcTcpPort\" : %d,\n", mXbmcTcpPort));
strBuf.append(String.format(Locale.ROOT, "\t\t\"grabVideo\" : %s,\n", mVideoOn));
strBuf.append(String.format(Locale.ROOT, "\t\t\"grabPictures\" : %s,\n", mPictureOn));
strBuf.append(String.format(Locale.ROOT, "\t\t\"grabAudio\" : %s,\n", mAudioOn));
strBuf.append(String.format(Locale.ROOT, "\t\t\"grabMenu\" : %s\n", mMenuOn));
strBuf.append("\t},\n\n");
strBuf.append("\t/// The configuration of the Json server which enables the json remote interface\n");
strBuf.append("\t/// * port : Port at which the json server is started\n");
strBuf.append("\t\"jsonServer\" :\n");
strBuf.append("\t{\n");
strBuf.append(String.format(Locale.ROOT, "\t\t\"port\" : %d\n", mJsonPort));
strBuf.append("\t},\n\n");
strBuf.append("\t/// The configuration of the Proto server which enables the protobuffer remote interface\n");
strBuf.append("\t/// * port : Port at which the protobuffer server is started\n");
strBuf.append("\t\"protoServer\" :\n");
strBuf.append("\t{\n");
strBuf.append(String.format(Locale.ROOT, "\t\t\"port\" : %d\n", mProtoPort));
strBuf.append("\t}");
return strBuf.toString();
}
}

View File

@ -7,4 +7,5 @@ target_link_libraries(hyperiond
hyperion
dispmanx-grabber
xbmcvideochecker
jsonserver)
jsonserver
protoserver)

View File

@ -1,4 +1,3 @@
// C++ includes
#include <csignal>
@ -24,6 +23,9 @@
// JsonServer includes
#include <jsonserver/JsonServer.h>
// ProtoServer includes
#include <protoserver/ProtoServer.h>
void signal_handler(const int signum)
{
QCoreApplication::quit();
@ -66,7 +68,7 @@ int main(int argc, char** argv)
{
std::cout << "Missing required configuration file. Usage:" << std::endl;
std::cout << "hyperiond [config.file]" << std::endl;
return 0;
return 1;
}
const std::string configFile = argv[1];
@ -76,14 +78,24 @@ int main(int argc, char** argv)
Hyperion hyperion(config);
std::cout << "Hyperion created and initialised" << std::endl;
BootSequence * bootSequence = BootSequenceFactory::createBootSequence(&hyperion, config["bootsequence"]);
if (bootSequence)
// create boot sequence if the configuration is present
BootSequence * bootSequence = nullptr;
if (config.isMember("bootsequence"))
{
bootSequence->start();
bootSequence = BootSequenceFactory::createBootSequence(&hyperion, config["bootsequence"]);
if (bootSequence != nullptr)
{
bootSequence->start();
}
}
const Json::Value & videoCheckerConfig = config["xbmcVideoChecker"];
XBMCVideoChecker xbmcVideoChecker(
// create XBMC video checker if the configuration is present
XBMCVideoChecker * xbmcVideoChecker = nullptr;
if (config.isMember("xbmcVideoChecker"))
{
const Json::Value & videoCheckerConfig = config["xbmcVideoChecker"];
xbmcVideoChecker = new XBMCVideoChecker(
videoCheckerConfig["xbmcAddress"].asString(),
videoCheckerConfig["xbmcTcpPort"].asUInt(),
1000,
@ -91,38 +103,67 @@ int main(int argc, char** argv)
videoCheckerConfig["grabPictures"].asBool(),
videoCheckerConfig["grabAudio"].asBool(),
videoCheckerConfig["grabMenu"].asBool());
if (videoCheckerConfig["enable"].asBool())
{
xbmcVideoChecker.start();
xbmcVideoChecker->start();
std::cout << "XBMC video checker created and started" << std::endl;
}
// Construct and start the frame-grabber
const Json::Value & frameGrabberConfig = config["framegrabber"];
DispmanxWrapper dispmanx(
// Construct and start the frame-grabber if the configuration is present
DispmanxWrapper * dispmanx = nullptr;
if (config.isMember("framegrabber"))
{
const Json::Value & frameGrabberConfig = config["framegrabber"];
dispmanx = new DispmanxWrapper(
frameGrabberConfig["width"].asUInt(),
frameGrabberConfig["height"].asUInt(),
frameGrabberConfig["frequency_Hz"].asUInt(),
&hyperion);
QObject::connect(&xbmcVideoChecker, SIGNAL(grabbingMode(GrabbingMode)), &dispmanx, SLOT(setGrabbingMode(GrabbingMode)));
dispmanx.start();
std::cout << "Frame grabber created and started" << std::endl;
JsonServer jsonServer(&hyperion);
std::cout << "Json server created and started on port " << jsonServer.getPort() << std::endl;
if (xbmcVideoChecker != nullptr)
{
QObject::connect(xbmcVideoChecker, SIGNAL(grabbingMode(GrabbingMode)), dispmanx, SLOT(setGrabbingMode(GrabbingMode)));
}
else
{
dispmanx->setGrabbingMode(GRABBINGMODE_VIDEO);
}
dispmanx->start();
std::cout << "Frame grabber created and started" << std::endl;
}
// Create Json server if configuration is present
JsonServer * jsonServer = nullptr;
if (config.isMember("jsonServer"))
{
const Json::Value & jsonServerConfig = config["jsonServer"];
jsonServer = new JsonServer(&hyperion, jsonServerConfig["port"].asUInt());
std::cout << "Json server created and started on port " << jsonServer->getPort() << std::endl;
}
// Create Proto server if configuration is present
ProtoServer * protoServer = nullptr;
if (config.isMember("protoServer"))
{
const Json::Value & protoServerConfig = config["protoServer"];
protoServer = new ProtoServer(&hyperion, protoServerConfig["port"].asUInt());
std::cout << "Proto server created and started on port " << protoServer->getPort() << std::endl;
}
// run the application
int rc = app.exec();
std::cout << "Application closed" << std::endl;
// Stop the frame grabber
dispmanx.stop();
// Delete the boot sequence
delete bootSequence;
// Clear all colors (switchting off all leds)
hyperion.clearall();
// Delete all component
delete bootSequence;
delete dispmanx;
delete xbmcVideoChecker;
delete jsonServer;
delete protoServer;
// leave application
return rc;
}

View File

@ -7,7 +7,6 @@ add_executable(test_spi
target_link_libraries(test_spi
hyperion)
add_executable(test_configfile
TestConfigFile.cpp)
target_link_libraries(test_configfile
@ -39,3 +38,6 @@ add_executable(test_blackborderprocessor
TestBlackBorderProcessor.cpp)
target_link_libraries(test_blackborderprocessor
hyperion)
add_executable(spidev_test spidev_test.c)
add_executable(gpio2spi switchPinCtrl.c)

210
test/spidev_test.c Normal file
View File

@ -0,0 +1,210 @@
/*
* SPI testing utility (using spidev driver)
*
* Copyright (c) 2007 MontaVista Software, Inc.
* Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* Cross-compile with cross-gcc -I/path/to/cross-kernel/include
*/
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static void pabort(const char *s)
{
perror(s);
abort();
}
static const char *device = "/dev/spidev0.0";
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
static void transfer(int fd)
{
int ret;
uint8_t tx[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
0xF0, 0x0D,
};
uint8_t rx[ARRAY_SIZE(tx)] = {0, };
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
if (!(ret % 6))
puts("");
printf("%.2X ", rx[ret]);
}
puts("");
}
static void print_usage(const char *prog)
{
printf("Usage: %s [-DsbdlHOLC3]\n", prog);
puts(" -D --device device to use (default /dev/spidev0.0)\n"
" -s --speed max speed (Hz)\n"
" -d --delay delay (usec)\n"
" -b --bpw bits per word \n"
" -l --loop loopback\n"
" -H --cpha clock phase\n"
" -O --cpol clock polarity\n"
" -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n"
" -3 --3wire SI/SO signals shared\n");
exit(1);
}
static void parse_opts(int argc, char *argv[])
{
while (1) {
static const struct option lopts[] = {
{ "device", 1, 0, 'D' },
{ "speed", 1, 0, 's' },
{ "delay", 1, 0, 'd' },
{ "bpw", 1, 0, 'b' },
{ "loop", 0, 0, 'l' },
{ "cpha", 0, 0, 'H' },
{ "cpol", 0, 0, 'O' },
{ "lsb", 0, 0, 'L' },
{ "cs-high", 0, 0, 'C' },
{ "3wire", 0, 0, '3' },
{ "no-cs", 0, 0, 'N' },
{ "ready", 0, 0, 'R' },
{ NULL, 0, 0, 0 },
};
int c;
c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);
if (c == -1)
break;
switch (c) {
case 'D':
device = optarg;
break;
case 's':
speed = atoi(optarg);
break;
case 'd':
delay = atoi(optarg);
break;
case 'b':
bits = atoi(optarg);
break;
case 'l':
mode |= SPI_LOOP;
break;
case 'H':
mode |= SPI_CPHA;
break;
case 'O':
mode |= SPI_CPOL;
break;
case 'L':
mode |= SPI_LSB_FIRST;
break;
case 'C':
mode |= SPI_CS_HIGH;
break;
case '3':
mode |= SPI_3WIRE;
break;
case 'N':
mode |= SPI_NO_CS;
break;
case 'R':
mode |= SPI_READY;
break;
default:
print_usage(argv[0]);
break;
}
}
}
int main(int argc, char *argv[])
{
int ret = 0;
int fd;
parse_opts(argc, argv);
fd = open(device, O_RDWR);
if (fd < 0)
pabort("can't open device");
/*
* spi mode
*/
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1)
pabort("can't set spi mode");
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1)
pabort("can't get spi mode");
/*
* bits per word
*/
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't get bits per word");
/*
* max speed hz
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't get max speed hz");
printf("spi mode: %d\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
transfer(fd);
close(fd);
return ret;
}

177
test/switchPinCtrl.c Normal file
View File

@ -0,0 +1,177 @@
//
// Simple byte wise SPI driver
// Demo how to set up memmap and access SPI registers.
// Code seems to be working but has not been much tested.
// G.J. van Loo 15-Jan-2012
//
// Access from ARM Running Linux
#define BCM2708_PERI_BASE 0x20000000
#define UART0_BASE (BCM2708_PERI_BASE + 0x201000) /* Uart 0 */
#define UART1_BASE (BCM2708_PERI_BASE + 0x215000) /* Uart 1 */
#define MCORE_BASE (BCM2708_PERI_BASE + 0x0000) /* Fake frame buffer device */
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
#define SPI0_BASE (BCM2708_PERI_BASE + 0x204000) /* SPI0 controller */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
int mem_fd;
char *gpio_mem, *gpio_map;
char *spi0_mem, *spi0_map;
// I/O access
volatile unsigned *gpio;
volatile unsigned *spi0;
// SPI operation
// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
//
#define SPI0_CNTLSTAT *(spi0 + 0)
#define SPI0_FIFO *(spi0 + 1)
#define SPI0_CLKSPEED *(spi0 + 2)
// SPI0_CNTLSTAT register bits
#define SPI0_CS_CS2ACTHIGH 0x00800000 // CS2 active high
#define SPI0_CS_CS1ACTHIGH 0x00400000 // CS1 active high
#define SPI0_CS_CS0ACTHIGH 0x00200000 // CS0 active high
#define SPI0_CS_RXFIFOFULL 0x00100000 // Receive FIFO full
#define SPI0_CS_RXFIFO3_4 0x00080000 // Receive FIFO 3/4 full
#define SPI0_CS_TXFIFOSPCE 0x00040000 // Transmit FIFO has space
#define SPI0_CS_RXFIFODATA 0x00020000 // Receive FIFO has data
#define SPI0_CS_DONE 0x00010000 // SPI transfer done. WRT to CLR!
#define SPI0_CS_MOSI_INPUT 0x00001000 // MOSI is input, read from MOSI (BI-dir mode)
#define SPI0_CS_DEASRT_CS 0x00000800 // De-assert CS at end
#define SPI0_CS_RX_IRQ 0x00000400 // Receive irq enable
#define SPI0_CS_DONE_IRQ 0x00000200 // irq when done
#define SPI0_CS_DMA_ENABLE 0x00000100 // Run in DMA mode
#define SPI0_CS_ACTIVATE 0x00000080 // Activate: be high before starting
#define SPI0_CS_CS_POLARIT 0x00000040 // Chip selects active high
#define SPI0_CS_CLRTXFIFO 0x00000020 // Clear TX FIFO (auto clear bit)
#define SPI0_CS_CLRRXFIFO 0x00000010 // Clear RX FIFO (auto clear bit)
#define SPI0_CS_CLRFIFOS 0x00000030 // Clear BOTH FIFOs (auto clear bit)
#define SPI0_CS_CLK_IDLHI 0x00000008 // Clock pin is high when idle
#define SPI0_CS_CLKTRANS 0x00000004 // 0=first clock in middle of data bit
// 1=first clock at begin of data bit
#define SPI0_CS_CHIPSEL0 0x00000000 // Use chip select 0
#define SPI0_CS_CHIPSEL1 0x00000001 // Use chip select 1
#define SPI0_CS_CHIPSEL2 0x00000002 // Use chip select 2
#define SPI0_CS_CHIPSELN 0x00000003 // No chip select (e.g. use GPIO pin)
#define SPI0_CS_CLRALL (SPI0_CS_CLRFIFOS|SPI0_CS_DONE)
#define ISASC(x) ((x)>=0x20 && (x)<=0x7F)
void setup_io();
int main(int argc, char **argv)
{ int g;
setup_io(); // Set up direct access to I/O for GPIO and SPI
// Switch GPIO 7..11 to SPI mode (ALT function 0)
/************************************************************************\
* You are about to change the GPIO settings of your computer. *
* Mess this up and it will stop working! *
* It might be a good idea to 'sync' before running this program *
* so at least you still have your code changes written to the SD-card! *
\************************************************************************/
for (g=7; g<=11; g++)
{
INP_GPIO(g); // clear bits (= input)
SET_GPIO_ALT(g,0); // set function 0
}
return 0;
} // main
//
// Set up a memory regions to access GPIO and SPI0
//
void setup_io()
{
/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("can't open /dev/mem \n");
exit (-1);
}
/* mmap GPIO */
if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
printf("allocation error \n");
exit (-1);
}
if ((unsigned long)gpio_mem % PAGE_SIZE)
gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE);
gpio_map = (unsigned char *)mmap(
(caddr_t)gpio_mem,
BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
GPIO_BASE
);
if ((long)gpio_map < 0) {
printf("mmap error %d\n", (int)gpio_map);
exit (-1);
}
gpio = (volatile unsigned *)gpio_map;
/* mmap SPI0 */
if ((spi0_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
printf("allocation error \n");
exit (-1);
}
if ((unsigned long)spi0_mem % PAGE_SIZE)
spi0_mem += PAGE_SIZE - ((unsigned long)spi0_mem % PAGE_SIZE);
spi0_map = (unsigned char *)mmap(
(caddr_t)spi0_mem,
BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
SPI0_BASE
);
printf("SPI mapped from 0x%p to 0x%p\n",SPI0_BASE,spi0_map);
if ((long)spi0_map < 0) {
printf("mmap error %d\n", (int)spi0_map);
exit (-1);
}
spi0 = (volatile unsigned *)spi0_map;
} // setup_io