Merge remote-tracking branch 'remotes/origin/master'

Former-commit-id: e159c4757880a0f77f59c6b23775856e4fd4b8fe
This commit is contained in:
T. van der Zwan 2013-09-24 11:28:33 +02:00
commit b1b6de7ce6
50 changed files with 3337 additions and 215 deletions

View File

@ -46,3 +46,6 @@ add_subdirectory(dependencies)
add_subdirectory(libsrc)
add_subdirectory(src)
add_subdirectory(test)
# Add the doxygen generation directory
add_subdirectory(doc)

32
doc/CMakeLists.txt Normal file
View File

@ -0,0 +1,32 @@
# Find doxygen
find_package(Doxygen QUIET)
# This processes our hyperion-cmake.doxyfile and subsitutes variables to generate a final hyperion.doxyfile
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/hyperion.in.doxygen ${CMAKE_CURRENT_BINARY_DIR}/hyperion.doxygen)
# This processes the shell script that is used to build the documentation and check the result
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/hyperion-build-doc.in.sh ${CMAKE_CURRENT_BINARY_DIR}/hyperion-build-doc.sh)
# Define all static (i.e. not generated) documentation files
set(StaticDocumentationFiles hyperion-header.html hyperion-footer.html hyperion-stylesheet.css)
# Loop over all static documentation files
foreach(StaticDocumentationFile ${StaticDocumentationFiles})
# Copy the file to the bindary documentation directory
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${StaticDocumentationFile} ${CMAKE_CURRENT_BINARY_DIR}/html/${StaticDocumentationFile} COPYONLY)
endforeach()
if(DOXYGEN_FOUND)
option(BuildDocumentationSearchEngine "Enable doxygen's search engine (requires that documentation to be installed on a php enabled web server)" OFF)
if(BuildDocumentationSearchEngine)
set(DOXYGEN_SEARCHENGINE YES)
else(BuildDocumentationSearchEngine)
set(DOXYGEN_SEARCHENGINE NO)
endif(BuildDocumentationSearchEngine)
#Create a custom target to build documentation. It runs doxygen aginast the generated hyperion.doxyfile and checks its return value
add_custom_target(doc sh ${CMAKE_CURRENT_BINARY_DIR}/hyperion-build-doc.sh)
else(DOXYGEN_FOUND)
message(WARNING "Doxygen not found, unable to generate documenation!")
endif(DOXYGEN_FOUND)

View File

@ -0,0 +1,30 @@
#!/bin/sh
# Fail on error.
set -e
# Log file containing documentation errors and warnings (if any).
log_file=${CMAKE_CURRENT_BINARY_DIR}/hyperion-doxygen.log
# Remove the log file before building the documentation.
rm -f $log_file
# Generate the documentation.
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/hyperion.doxygen
# At this point, the log file should have been generated.
# If not, an error is displayed on stderr and 1 is returned to indicate an error.
if [ -f $log_file ] ; then
# So the log file exists. If its size is > 0, show its contents on stderr and exit 1.
if [ -s $log_file ] ; then
cat $log_file 1>&2
exit 1;
else
# The log file exists, but its size is zero, meaning there were no documentation warnings or errors.
# Exit with 0 to indicate success.
exit 0;
fi
else
echo "The doxygen log file ($log_file) does not exist. Ensure that WARN_LOGFILE is set correctly in hyperion-cmake.doxyfile." 1>&2
exit 1;
fi

8
doc/hyperion-footer.html Normal file
View File

@ -0,0 +1,8 @@
<hr>
<table border="0">
<tr>
<td><address style="text-align: right;"><small>Generated at $datetime for $projectname by <a href="http://www.doxygen.org">doxygen</a> $doxygenversion.</small></address></td>
</tr>
</table>
</body>
</html>

9
doc/hyperion-header.html Normal file
View File

@ -0,0 +1,9 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>$title</title>
<link href="$relpath$doxygen.css" rel="stylesheet" type="text/css">
<link href="$relpath$tabs.css" rel="stylesheet" type="text/css">
</head>
<body>

472
doc/hyperion-stylesheet.css Normal file
View File

@ -0,0 +1,472 @@
BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
font-family: Geneva, Arial, Helvetica, sans-serif;
}
BODY,TD {
font-size: 90%;
}
H1 {
text-align: center;
font-size: 160%;
}
H2 {
font-size: 120%;
}
H3 {
font-size: 100%;
}
CAPTION {
font-weight: bold
}
DIV.qindex {
width: 100%;
background-color: #e8eef2;
border: 1px solid #84b0c7;
text-align: center;
margin: 2px;
padding: 2px;
line-height: 140%;
}
DIV.navpath {
width: 100%;
background-color: #e8eef2;
border: 1px solid #84b0c7;
text-align: center;
margin: 2px;
padding: 2px;
line-height: 140%;
}
DIV.navtab {
background-color: #e8eef2;
border: 1px solid #84b0c7;
text-align: center;
margin: 2px;
margin-right: 15px;
padding: 2px;
}
TD.navtab {
font-size: 70%;
}
A.qindex {
text-decoration: none;
font-weight: bold;
color: #1A419D;
}
A.qindex:visited {
text-decoration: none;
font-weight: bold;
color: #1A419D
}
A.qindex:hover {
text-decoration: none;
background-color: #ddddff;
}
A.qindexHL {
text-decoration: none;
font-weight: bold;
background-color: #6666cc;
color: #ffffff;
border: 1px double #9295C2;
}
A.qindexHL:hover {
text-decoration: none;
background-color: #6666cc;
color: #ffffff;
}
A.qindexHL:visited {
text-decoration: none;
background-color: #6666cc;
color: #ffffff
}
A.el {
text-decoration: none;
font-weight: bold
}
A.elRef {
font-weight: bold
}
A.code:link {
text-decoration: none;
font-weight: normal;
color: #0000FF
}
A.code:visited {
text-decoration: none;
font-weight: normal;
color: #0000FF
}
A.codeRef:link {
font-weight: normal;
color: #0000FF
}
A.codeRef:visited {
font-weight: normal;
color: #0000FF
}
A:hover {
text-decoration: none;
background-color: #f2f2ff
}
DL.el {
margin-left: -1cm
}
.fragment {
font-family: monospace, fixed;
font-size: 95%;
}
PRE.fragment {
border: 1px solid #CCCCCC;
background-color: #f5f5f5;
margin-top: 4px;
margin-bottom: 4px;
margin-left: 2px;
margin-right: 8px;
padding-left: 6px;
padding-right: 6px;
padding-top: 4px;
padding-bottom: 4px;
}
DIV.ah {
background-color: black;
font-weight: bold;
color: #ffffff;
margin-bottom: 3px;
margin-top: 3px
}
DIV.groupHeader {
margin-left: 16px;
margin-top: 12px;
margin-bottom: 6px;
font-weight: bold;
}
DIV.groupText {
margin-left: 16px;
font-style: italic;
font-size: 90%
}
BODY {
background: white;
color: black;
margin-right: 20px;
margin-left: 20px;
}
TD.indexkey {
background-color: #e8eef2;
font-weight: bold;
padding-right : 10px;
padding-top : 2px;
padding-left : 10px;
padding-bottom : 2px;
margin-left : 0px;
margin-right : 0px;
margin-top : 2px;
margin-bottom : 2px;
border: 1px solid #CCCCCC;
}
TD.indexvalue {
background-color: #e8eef2;
font-style: italic;
padding-right : 10px;
padding-top : 2px;
padding-left : 10px;
padding-bottom : 2px;
margin-left : 0px;
margin-right : 0px;
margin-top : 2px;
margin-bottom : 2px;
border: 1px solid #CCCCCC;
}
TR.memlist {
background-color: #f0f0f0;
}
P.formulaDsp {
text-align: center;
}
IMG.formulaDsp {
}
IMG.formulaInl {
vertical-align: middle;
}
SPAN.keyword { color: #008000 }
SPAN.keywordtype { color: #604020 }
SPAN.keywordflow { color: #e08000 }
SPAN.comment { color: #800000 }
SPAN.preprocessor { color: #806020 }
SPAN.stringliteral { color: #002080 }
SPAN.charliteral { color: #008080 }
SPAN.vhdldigit { color: #ff00ff }
SPAN.vhdlchar { color: #000000 }
SPAN.vhdlkeyword { color: #700070 }
SPAN.vhdllogic { color: #ff0000 }
.mdescLeft {
padding: 0px 8px 4px 8px;
font-size: 80%;
font-style: italic;
background-color: #FAFAFA;
border-top: 1px none #E0E0E0;
border-right: 1px none #E0E0E0;
border-bottom: 1px none #E0E0E0;
border-left: 1px none #E0E0E0;
margin: 0px;
}
.mdescRight {
padding: 0px 8px 4px 8px;
font-size: 80%;
font-style: italic;
background-color: #FAFAFA;
border-top: 1px none #E0E0E0;
border-right: 1px none #E0E0E0;
border-bottom: 1px none #E0E0E0;
border-left: 1px none #E0E0E0;
margin: 0px;
}
.memItemLeft {
padding: 1px 0px 0px 8px;
margin: 4px;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #E0E0E0;
border-right-color: #E0E0E0;
border-bottom-color: #E0E0E0;
border-left-color: #E0E0E0;
border-top-style: solid;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
background-color: #FAFAFA;
font-size: 80%;
}
.memItemRight {
padding: 1px 8px 0px 8px;
margin: 4px;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #E0E0E0;
border-right-color: #E0E0E0;
border-bottom-color: #E0E0E0;
border-left-color: #E0E0E0;
border-top-style: solid;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
background-color: #FAFAFA;
font-size: 80%;
}
.memTemplItemLeft {
padding: 1px 0px 0px 8px;
margin: 4px;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #E0E0E0;
border-right-color: #E0E0E0;
border-bottom-color: #E0E0E0;
border-left-color: #E0E0E0;
border-top-style: none;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
background-color: #FAFAFA;
font-size: 80%;
}
.memTemplItemRight {
padding: 1px 8px 0px 8px;
margin: 4px;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #E0E0E0;
border-right-color: #E0E0E0;
border-bottom-color: #E0E0E0;
border-left-color: #E0E0E0;
border-top-style: none;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
background-color: #FAFAFA;
font-size: 80%;
}
.memTemplParams {
padding: 1px 0px 0px 8px;
margin: 4px;
border-top-width: 1px;
border-right-width: 1px;
border-bottom-width: 1px;
border-left-width: 1px;
border-top-color: #E0E0E0;
border-right-color: #E0E0E0;
border-bottom-color: #E0E0E0;
border-left-color: #E0E0E0;
border-top-style: solid;
border-right-style: none;
border-bottom-style: none;
border-left-style: none;
color: #606060;
background-color: #FAFAFA;
font-size: 80%;
}
.search {
color: #003399;
font-weight: bold;
}
FORM.search {
margin-bottom: 0px;
margin-top: 0px;
}
INPUT.search {
font-size: 75%;
color: #000080;
font-weight: normal;
background-color: #e8eef2;
}
TD.tiny {
font-size: 75%;
}
a {
color: #1A41A8;
}
a:visited {
color: #2A3798;
}
.dirtab {
padding: 4px;
border-collapse: collapse;
border: 1px solid #84b0c7;
}
TH.dirtab {
background: #e8eef2;
font-weight: bold;
}
HR {
height: 1px;
border: none;
border-top: 1px solid black;
}
/* Style for detailed member documentation */
.memtemplate {
font-size: 80%;
color: #606060;
font-weight: normal;
margin-left: 3px;
}
.memnav {
background-color: #e8eef2;
border: 1px solid #84b0c7;
text-align: center;
margin: 2px;
margin-right: 15px;
padding: 2px;
}
.memitem {
padding: 4px;
background-color: #eef3f5;
border-width: 1px;
border-style: solid;
border-color: #dedeee;
-moz-border-radius: 8px 8px 8px 8px;
}
.memname {
white-space: nowrap;
font-weight: bold;
}
.memdoc {
padding-left: 10px;
}
.memproto {
background-color: #d5e1e8;
width: 100%;
border-width: 1px;
border-style: solid;
border-color: #84b0c7;
font-weight: bold;
-moz-border-radius: 8px 8px 8px 8px;
}
.paramkey {
text-align: right;
}
.paramtype {
white-space: nowrap;
}
.paramname {
color: #602020;
font-style: italic;
white-space: nowrap;
}
/* End Styling for detailed member documentation */
/* for the tree view */
.ftvtree {
font-family: sans-serif;
margin:0.5em;
}
/* these are for tree view when used as main index */
.directory {
font-size: 9pt;
font-weight: bold;
}
.directory h3 {
margin: 0px;
margin-top: 1em;
font-size: 11pt;
}
/* The following two styles can be used to replace the root node title */
/* with an image of your choice. Simply uncomment the next two styles, */
/* specify the name of your image and be sure to set 'height' to the */
/* proper pixel height of your image. */
/* .directory h3.swap { */
/* height: 61px; */
/* background-repeat: no-repeat; */
/* background-image: url("yourimage.gif"); */
/* } */
/* .directory h3.swap span { */
/* display: none; */
/* } */
.directory > h3 {
margin-top: 0;
}
.directory p {
margin: 0px;
white-space: nowrap;
}
.directory div {
display: none;
margin: 0px;
}
.directory img {
vertical-align: -30%;
}
/* these are for tree view when not used as main index */
.directory-alt {
font-size: 100%;
font-weight: bold;
}
.directory-alt h3 {
margin: 0px;
margin-top: 1em;
font-size: 11pt;
}
.directory-alt > h3 {
margin-top: 0;
}
.directory-alt p {
margin: 0px;
white-space: nowrap;
}
.directory-alt div {
display: none;
margin: 0px;
}
.directory-alt img {
vertical-align: -30%;
}

1421
doc/hyperion.in.doxygen Normal file

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@
// Utils includes
#include <utils/RgbColor.h>
#include <utils/RgbImage.h>
#include <utils/GrabbingMode.h>
// Forward class declaration
class DispmanxFrameGrabber;
@ -22,33 +23,64 @@ class DispmanxWrapper: public QObject
{
Q_OBJECT
public:
///
/// Constructs the dispmanx frame grabber with a specified grab size and update rate.
///
/// @param[in] grabWidth The width of the grabbed image [pixels]
/// @param[in] grabHeight The height of the grabbed images [pixels]
/// @param[in] updateRate_Hz The image grab rate [Hz]
/// @param[in] hyperion The instance of Hyperion used to write the led values
///
DispmanxWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, Hyperion * hyperion);
///
/// Destructor of this dispmanx frame grabber. Releases any claimed resources.
///
virtual ~DispmanxWrapper();
signals:
void ledValues(const unsigned priority, const std::vector<RgbColor> ledColors, const unsigned timeout_ms);
public slots:
///
/// Starts the grabber wich produces led values with the specified update rate
///
void start();
///
/// Performs a single frame grab and computes the led-colors
///
void action();
///
/// Stops the grabber
///
void stop();
///
/// \brief Set the grabbing mode
/// \param mode The new grabbing mode
///
void setGrabbingMode(GrabbingMode mode);
private:
/// The update rate [Hz]
const int _updateInterval_ms;
/// The timeout of the led colors [ms]
const int _timeout_ms;
/// The priority of the led colors [ms]
const int _priority;
/// The timer for generating events with the specified update rate
QTimer _timer;
/// The image used for grabbing frames
RgbImage _image;
/// The actual grabber
DispmanxFrameGrabber * _frameGrabber;
/// The processor for transforming images to led colors
ImageProcessor * _processor;
/// The list with computed led colors
std::vector<RgbColor> _ledColors;
/// Pointer to Hyperion for writing led values
Hyperion * _hyperion;
};

View File

@ -19,65 +19,161 @@
class HsvTransform;
class ColorTransform;
///
/// The main class of Hyperion. This gives other 'users' access to the attached LedDevice through
/// the priority muxer.
///
class Hyperion : public QObject
{
Q_OBJECT
public:
/// Type definition of the info structure used by the priority muxer
typedef PriorityMuxer::InputInfo InputInfo;
///
/// RGB-Color channel enumeration
///
enum Color
{
RED, GREEN, BLUE, INVALID
};
///
/// Enumeration of the possible color (color-channel) transforms
///
enum Transform
{
SATURATION_GAIN, VALUE_GAIN, THRESHOLD, GAMMA, BLACKLEVEL, WHITELEVEL
};
///
/// Constructs the Hyperion instance based on the given Json configuration
///
/// @param[in] jsonConfig The Json configuration
///
Hyperion(const Json::Value& jsonConfig);
///
/// Destructor; cleans up resourcess
///
~Hyperion();
///
/// Returns the number of attached leds
///
unsigned getLedCount() const;
void setColor(int priority, RgbColor &ledColor, const int timeout_ms);
///
/// Writes a single color to all the leds for the given time and priority
///
/// @param[in] priority The priority of the written color
/// @param[in] ledColor The color to write to the leds
/// @param[in] timeout_ms The time the leds are set to the given color [ms]
///
void setColor(int priority, const RgbColor &ledColor, const int timeout_ms);
void setColors(int priority, std::vector<RgbColor> &ledColors, const int timeout_ms);
///
/// Writes the given colors to all leds for the given time and priority
///
/// @param[in] priority The priority of the written colors
/// @param[in] ledColors The colors to write to the leds
/// @param[in] timeout_ms The time the leds are set to the given colors [ms]
///
void setColors(int priority, const std::vector<RgbColor> &ledColors, const int timeout_ms);
///
/// Sets/Updates a part of the color transformation.
///
/// @param[in] transform The type of transform to configure
/// @param[in] color The color channel to which the transform applies (only applicable for
/// Transform::THRESHOLD, Transform::GAMMA, Transform::BLACKLEVEL,
/// Transform::WHITELEVEL)
/// @param[in] value The new value for the given transform
///
void setTransform(Transform transform, Color color, double value);
///
/// Clears the given priority channel. This will switch the led-colors to the colors of the next
/// lower priority channel (or off if no more channels are set)
///
/// @param[in] priority The priority channel
///
void clear(int priority);
///
/// Clears all priority channels. This will switch the leds off until a new priority is written.
///
void clearall();
///
/// Returns the value of a specific color transform
///
/// @param[in] transform The type of transform
/// @param[in] color The color channel to which the transform applies (only applicable for
/// Transform::THRESHOLD, Transform::GAMMA, Transform::BLACKLEVEL,
/// Transform::WHITELEVEL)
///
/// @return The value of the specified color transform
///
double getTransform(Transform transform, Color color) const;
///
/// Returns a list of active priorities
///
/// @return The list with priorities
///
QList<int> getActivePriorities() const;
///
/// Returns the information of a specific priorrity channel
///
/// @param[in] priority The priority channel
///
/// @return The information of the given
///
/// @throw std::runtime_error when the priority channel does not exist
///
const InputInfo& getPriorityInfo(const int priority) const;
static LedDevice* constructDevice(const Json::Value & deviceConfig);
static LedDevice * constructDevice(const Json::Value & deviceConfig);
static LedString createLedString(const Json::Value & ledsConfig);
static HsvTransform * createHsvTransform(const Json::Value & hsvConfig);
static ColorTransform* createColorTransform(const Json::Value & colorConfig);
static ColorTransform * createColorTransform(const Json::Value & colorConfig);
private slots:
///
/// Updates the priority muxer with the current time and (re)writes the led color with applied
/// transforms.
///
void update();
private:
///
/// Applies all color transmforms to the given list of colors. The transformation is performed
/// in place.
///
/// @param colors The colors to be transformed
///
void applyTransform(std::vector<RgbColor>& colors) const;
/// The specifiation of the led frame construction and picture integration
LedString _ledString;
/// The priority muxer
PriorityMuxer _muxer;
/// The HSV Transform for applying Saturation and Value transforms
HsvTransform * _hsvTransform;
/// The RED-Channel (RGB) transform
ColorTransform * _redTransform;
/// The GREEN-Channel (RGB) transform
ColorTransform * _greenTransform;
/// The BLUE-Channel (RGB) transform
ColorTransform * _blueTransform;
/// The actual LedDevice
LedDevice* _device;
/// The timer for handling priority channel timeouts
QTimer _timer;
};

View File

@ -14,57 +14,72 @@ namespace hyperion {
class BlackBorderProcessor;
}
/**
* The ImageProcessor translates an RGB-image to RGB-values for the leds. The processing is
* performed in two steps. First the average color per led-region is computed. Second a
* color-tranform is applied based on a gamma-correction.
*/
///
/// The ImageProcessor translates an RGB-image to RGB-values for the leds. The processing is
/// performed in two steps. First the average color per led-region is computed. Second a
/// color-tranform is applied based on a gamma-correction.
///
class ImageProcessor
{
public:
~ImageProcessor();
/**
* Specifies the width and height of 'incomming' images. This will resize the buffer-image to
* match the given size.
* NB All earlier obtained references will be invalid.
*
* @param[in] width The new width of the buffer-image
* @param[in] height The new height of the buffer-image
*/
///
/// Specifies the width and height of 'incomming' images. This will resize the buffer-image to
/// match the given size.
/// NB All earlier obtained references will be invalid.
///
/// @param[in] width The new width of the buffer-image
/// @param[in] height The new height of the buffer-image
///
void setSize(const unsigned width, const unsigned height);
/**
* Processes the image to a list of led colors. This will update the size of the buffer-image
* if required and call the image-to-leds mapping to determine the mean color per led.
*
* @param[in] image The image to translate to led values
*
* @return The color value per led
*/
///
/// Processes the image to a list of led colors. This will update the size of the buffer-image
/// if required and call the image-to-leds mapping to determine the mean color per led.
///
/// @param[in] image The image to translate to led values
///
/// @return The color value per led
///
std::vector<RgbColor> process(const RgbImage& image);
/**
* Determines the led colors of the image in the buffer.
*
* @param[out] ledColors The color value per led
*/
///
/// Determines the led colors of the image in the buffer.
///
/// @param[in] image The image to translate to led values
/// @param[out] ledColors The color value per led
///
void process(const RgbImage& image, std::vector<RgbColor>& ledColors);
private:
/// Friend declaration of the factory for creating ImageProcessor's
friend class ImageProcessorFactory;
///
/// Constructs an image-processor for translating an image to led-color values based on the
/// given led-string specification
///
/// @param[in] ledString The led-string specification
///
ImageProcessor(const LedString &ledString);
///
/// Performs black-border detection (if enabled) on the given image
///
/// @param[in] image The image to perform black-border detection on
///
void verifyBorder(const RgbImage& image);
private:
/// The Led-string specification
const LedString mLedString;
/// Flag the enables(true)/disabled(false) blackborder detector
bool _enableBlackBorderRemoval;
/// The processor for black border detection
hyperion::BlackBorderProcessor* _borderProcessor;
/// The mapping of image-pixels to leds
hyperion::ImageToLedsMap* mImageToLeds;
};

View File

@ -11,16 +11,36 @@
// Forward class declaration
class ImageProcessor;
///
/// The ImageProcessor is a singleton factor for creating ImageProcessors that translate images to
/// led color values.
///
class ImageProcessorFactory
{
public:
///
/// Returns the 'singleton' instance (creates the singleton if it does not exist)
///
/// @return The singleton instance of the ImageProcessorFactory
///
static ImageProcessorFactory& getInstance();
public:
///
/// Initialises this factory with the given led-configuration
///
/// @param[in] ledString The led configuration
///
void init(const LedString& ledString);
///
/// Creates a new ImageProcessor. The onwership of the processor is transferred to the caller.
///
/// @return The newly created ImageProcessor
///
ImageProcessor* newImageProcessor() const;
private:
/// The Led-string specification
LedString _ledString;
};

View File

@ -6,22 +6,27 @@
// Utility includes
#include <utils/RgbColor.h>
///
/// Interface (pure virtual base class) for LedDevices.
///
class LedDevice
{
public:
/**
* Empty virtual destructor for pure virtual base class
*/
///
/// Empty virtual destructor for pure virtual base class
///
virtual ~LedDevice()
{
// empty
}
/**
* Writes the RGB-Color values to the leds.
*
* @param[in] ledValues The RGB-color per led
*/
///
/// Writes the RGB-Color values to the leds.
///
/// @param[in] ledValues The RGB-color per led
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<RgbColor>& ledValues) = 0;
};

View File

@ -12,49 +12,67 @@
// Forward class declarations
namespace Json { class Value; }
/**
* The Led structure contains the definition of the image portion used to determine a single led's
* color.
* <pre>
* |--------------------image--|
* | minX maxX |
* | |-----|minY |
* | | | |
* | |-----|maxY |
* | |
* | |
* | |
* |---------------------------|
* <endpre>
*/
///
/// The Led structure contains the definition of the image portion used to determine a single led's
/// color.
/// @verbatim
/// |--------------------image--|
/// | minX maxX |
/// | |-----|minY |
/// | | | |
/// | |-----|maxY |
/// | |
/// | |
/// | |
/// |---------------------------|
/// @endverbatim
///
struct Led
{
/** The index of the led */
/// The index of the led
unsigned index;
/** The minimum vertical scan line included for this leds color */
/// The minimum vertical scan line included for this leds color
double minX_frac;
/** The maximum vertical scan line included for this leds color */
/// The maximum vertical scan line included for this leds color
double maxX_frac;
/** The minimum horizontal scan line included for this leds color */
/// The minimum horizontal scan line included for this leds color
double minY_frac;
/** The maximum horizontal scan line included for this leds color */
/// The maximum horizontal scan line included for this leds color
double maxY_frac;
};
///
/// The LedString contains the image integration information of the leds
///
class LedString
{
public:
static LedString construct(const Json::Value& ledConfig);
///
/// Constructs the LedString with no leds
///
LedString();
///
/// Destructor of this LedString
///
~LedString();
///
/// Returns the led specifications
///
/// @return The list with led specifications
///
std::vector<Led>& leds();
///
/// Returns the led specifications
///
/// @return The list with led specifications
///
const std::vector<Led>& leds() const;
private:
/// The list with led specifications
std::vector<Led> mLeds;
};

View File

@ -15,43 +15,112 @@
// Hyperion includes
#include <hyperion/LedDevice.h>
///
/// The PriorityMuxer handles the priority channels. Led values input is written to the priority map
/// and the muxer keeps track of all active priorities. The current priority can be queried and per
/// priority the led colors.
///
class PriorityMuxer
{
public:
///
/// The information structure for a single priority channel
///
struct InputInfo
{
/// The priority of this channel
int priority;
/// The absolute timeout of the channel
int64_t timeoutTime_ms;
/// The colors for each led of the channel
std::vector<RgbColor> ledColors;
};
///
/// Constructs the PriorityMuxer for the given number of leds (used to switch to black when
/// there are no priority channels
///
/// @param ledCount The number of leds
///
PriorityMuxer(int ledCount);
///
/// Destructor
///
~PriorityMuxer();
///
/// Returns the current priority
///
/// @return The current priority
///
int getCurrentPriority() const;
///
/// Returns the state (enabled/disabled) of a specific priority channel
/// @param priority The priority channel
/// @return True if the priority channel exists else false
///
bool hasPriority(const int priority) const;
///
/// Returns the number of active priorities
///
/// @return The list with active priorities
///
QList<int> getPriorities() const;
///
/// Returns the information of a specified priority channel
///
/// @param priority The priority channel
///
/// @return The information for the specified priority channel
///
/// @throws std::runtime_error if the priority channel does not exist
///
const InputInfo& getInputInfo(const int priority) const;
///
/// Sets/Updates the data for a priority channel
///
/// @param[in] priority The priority of the channel
/// @param[in] ledColors The led colors of the priority channel
/// @param[in] timeoutTime_ms The absolute timeout time of the channel
///
void setInput(const int priority, const std::vector<RgbColor>& ledColors, const int64_t timeoutTime_ms=-1);
///
/// Clears the specified priority channel
///
/// @param[in] priority The priority of the channel to clear
///
void clearInput(const int priority);
///
/// Clears all priority channels
///
void clearAll();
///
/// Updates the current time. Channels with a configured time out will be checked and cleared if
/// required.
///
/// @param[in] now The current time
///
void setCurrentTime(const int64_t& now);
private:
/// The current priority (lowest value in _activeInputs)
int _currentPriority;
/// The mapping from priority channel to led-information
QMap<int, InputInfo> _activeInputs;
/// The information of the lowest priority channel
InputInfo _lowestPriorityInfo;
/// The lowest possible priority, which is used when no priority channels are active
const static int LOWEST_PRIORITY = std::numeric_limits<int>::max();
};

View File

@ -12,25 +12,48 @@
class JsonClientConnection;
///
/// This class creates a TCP server which accepts connections wich can then send
/// in JSON encoded commands. This interface to Hyperion is used by hyperion-remote
/// to control the leds
///
class JsonServer : public QObject
{
Q_OBJECT
public:
///
/// JsonServer constructor
/// @param hyperion Hyperion instance
/// @param port port number on which to start listening for connections
///
JsonServer(Hyperion * hyperion, uint16_t port = 19444);
~JsonServer();
///
/// @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(JsonClientConnection * connection);
private:
/// Hyperion instance
Hyperion * _hyperion;
/// The TCP server object
QTcpServer _server;
/// List with open connections
QSet<JsonClientConnection *> _openConnections;
};

View File

@ -15,36 +15,65 @@
class ColorTransform
{
public:
/// Default constructor
ColorTransform();
/// Constructor
/// @param threshold
/// @param gamma
/// @param blacklevel
/// @param whitelevel
ColorTransform(double threshold, double gamma, double blacklevel, double whitelevel);
/// Destructor
~ColorTransform();
/// @return The current threshold value
double getThreshold() const;
/// @param threshold New threshold value
void setThreshold(double threshold);
/// @return The current gamma value
double getGamma() const;
/// @param gamma New gamma value
void setGamma(double gamma);
/// @return The current blacklevel value
double getBlacklevel() const;
/// @param blacklevel New blacklevel value
void setBlacklevel(double blacklevel);
/// @return The current whitelevel value
double getWhitelevel() const;
/// @param whitelevel New whitelevel value
void setWhitelevel(double whitelevel);
/// get the transformed value for the given byte value
/// Transform the given byte value
/// @param input The input color byte
/// @return The transformed byte value
uint8_t transform(uint8_t input) const
{
return _mapping[input];
}
private:
/// (re)-initilize the color mapping
void initializeMapping();
private:
/// The threshold value
double _threshold;
/// The gamma value
double _gamma;
/// The blacklevel
double _blacklevel;
/// The whitelevel
double _whitelevel;
/// The mapping from input color to output color
uint8_t _mapping[256];
};

View File

@ -0,0 +1,11 @@
#pragma once
enum GrabbingMode
{
GRABBINGMODE_OFF,
GRABBINGMODE_VIDEO,
GRABBINGMODE_PHOTO,
GRABBINGMODE_AUDIO,
GRABBINGMODE_MENU,
GRABBINGMODE_INVALID
};

View File

@ -3,28 +3,104 @@
// STL includes
#include <cstdint>
///
/// Color transformation to adjust the saturation and value of a RGB color value
///
class HsvTransform
{
public:
///
/// Default constructor
///
HsvTransform();
///
/// Constructor
///
/// @param saturationGain The used saturation gain
/// @param valueGain The used value gain
///
HsvTransform(double saturationGain, double valueGain);
///
/// Destructor
///
~HsvTransform();
///
/// Updates the saturation gain
///
/// @param saturationGain New saturationGain
///
void setSaturationGain(double saturationGain);
///
/// Returns the saturation gain
///
/// @return The current Saturation gain
///
double getSaturationGain() const;
///
/// Updates the value gain
///
/// @param valueGain New value gain
///
void setValueGain(double valueGain);
///
/// Returns the value gain
///
/// @return The current value gain
///
double getValueGain() const;
///
/// Apply the transform the the given RGB values.
///
/// @param red The red color component
/// @param green The green color component
/// @param blue The blue color component
///
/// @note The values are updated in place.
///
void transform(uint8_t & red, uint8_t & green, uint8_t & blue) const;
/// integer version of the conversion are faster, but a little less accurate
/// all values are unsigned 8 bit values and scaled between 0 and 255 except
/// for the hue which is a 16 bit number and scaled between 0 and 360
///
/// Translates an RGB (red, green, blue) color to an HSV (hue, saturation, value) color
///
/// @param[in] red The red RGB-component
/// @param[in] green The green RGB-component
/// @param[in] blue The blue RGB-component
/// @param[out] hue The hue HSV-component
/// @param[out] saturation The saturation HSV-component
/// @param[out] value The value HSV-component
///
/// @note Integer version of the conversion are faster, but a little less accurate all values
/// are unsigned 8 bit values and scaled between 0 and 255 except for the hue which is a 16 bit
/// number and scaled between 0 and 360
///
static void rgb2hsv(uint8_t red, uint8_t green, uint8_t blue, uint16_t & hue, uint8_t & saturation, uint8_t & value);
///
/// Translates an HSV (hue, saturation, value) color to an RGB (red, green, blue) color
///
/// @param[in] hue The hue HSV-component
/// @param[in] saturation The saturation HSV-component
/// @param[in] value The value HSV-component
/// @param[out] red The red RGB-component
/// @param[out] green The green RGB-component
/// @param[out] blue The blue RGB-component
///
/// @note Integer version of the conversion are faster, but a little less accurate all values
/// are unsigned 8 bit values and scaled between 0 and 255 except for the hue which is a 16 bit
/// number and scaled between 0 and 360
///
static void hsv2rgb(uint16_t hue, uint8_t saturation, uint8_t value, uint8_t & red, uint8_t & green, uint8_t & blue);
private:
/// The saturation gain
double _saturationGain;
/// The value gain
double _valueGain;
};

View File

@ -8,31 +8,57 @@
// Forward class declaration
struct RgbColor;
///
/// 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 RgbColor
{
/// The red color channel
uint8_t red;
/// The green color channel
uint8_t green;
/// The blue color channel
uint8_t blue;
/// 'Black' RgbColor (0, 0, 0)
static RgbColor BLACK;
/// 'Red' RgbColor (255, 0, 0)
static RgbColor RED;
/// 'Green' RgbColor (0, 255, 0)
static RgbColor GREEN;
/// 'Blue' RgbColor (0, 0, 255)
static RgbColor BLUE;
/// 'Yellow' RgbColor (255, 255, 0)
static RgbColor YELLOW;
/// 'White' RgbColor (255, 255, 255)
static RgbColor WHITE;
///
/// Checks is this exactly matches another color
///
/// @param other The other color
///
/// @return True if the colors are identical
///
inline bool operator==(const RgbColor& other) const
{
return red == other.red && green == other.green && blue == other.blue;
}
};
/// Assert to ensure that the size of the structure is 'only' 3 bytes
static_assert(sizeof(RgbColor) == 3, "Incorrect size of RgbColor");
///
/// Stream operator to write RgbColor 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 RgbColor& color)
{
os << "{" << unsigned(color.red) << "," << unsigned(color.green) << "," << unsigned(color.blue) << "}";
return os;
}

View File

@ -8,57 +8,127 @@
// Local includes
#include "RgbColor.h"
///
/// The RgbImage holds a 2D matrix of RgbColors's (or image). Width and height of the image are
/// fixed at construction.
///
class RgbImage
{
public:
///
/// Constructor for an image with specified width and height
///
/// @param width The width of the image
/// @param height The height of the image
/// @param background The color of the image (default = BLACK)
///
RgbImage(const unsigned width, const unsigned height, const RgbColor background = RgbColor::BLACK);
///
/// Destructor
///
~RgbImage();
///
/// Returns the width of the image
///
/// @return The width of the image
///
inline unsigned width() const
{
return mWidth;
return _width;
}
///
/// Returns the height of the image
///
/// @return The height of the image
///
inline unsigned height() const
{
return mHeight;
return _height;
}
///
/// Sets the color of a specific pixel in the image
///
/// @param x The x index
/// @param y The y index
/// @param color The new color
///
void setPixel(const unsigned x, const unsigned y, const RgbColor color);
///
/// Returns a const reference to a specified pixel in the image
///
/// @param x The x index
/// @param y The y index
///
/// @return const reference to specified pixel
///
const RgbColor& operator()(const unsigned x, const unsigned y) const;
///
/// Returns a reference to a specified pixel in the image
///
/// @param x The x index
/// @param y The y index
///
/// @return reference to specified pixel
///
RgbColor& operator()(const unsigned x, const unsigned y);
///
/// Copies another image into this image. The images should have exactly the same size.
///
/// @param other The image to copy into this
///
inline void copy(const RgbImage& other)
{
assert(other.mWidth == mWidth);
assert(other.mHeight == mHeight);
assert(other._width == _width);
assert(other._height == _height);
memcpy(mColors, other.mColors, mWidth*mHeight*sizeof(RgbColor));
memcpy(mColors, other.mColors, _width*_height*sizeof(RgbColor));
}
///
/// Returns a memory pointer to the first pixel in the image
/// @return The memory pointer to the first pixel
///
RgbColor* memptr()
{
return mColors;
}
///
/// Returns a const memory pointer to the first pixel in the image
/// @return The const memory pointer to the first pixel
///
const RgbColor* memptr() const
{
return mColors;
}
private:
///
/// Translate x and y coordinate to index of the underlying vector
///
/// @param x The x index
/// @param y The y index
///
/// @return The index into the underlying data-vector
///
inline unsigned toIndex(const unsigned x, const unsigned y) const
{
return y*mWidth + x;
return y*_width + x;
}
private:
const unsigned mWidth;
const unsigned mHeight;
/// The width of the image
const unsigned _width;
/// The height of the image
const unsigned _height;
/** The colors of the image */
RgbColor* mColors;

View File

@ -7,61 +7,186 @@
// jsoncpp includes
#include <json/json.h>
/**
* JsonSchemaChecker is a very basic implementation of json schema.
* The json schema definition draft can be found at
* http://tools.ietf.org/html/draft-zyp-json-schema-03
*
* The following keywords are supported:
* - type
* - required
* - properties
* - items
* - enum
* - minimum
* - maximum
*/
/// JsonSchemaChecker is a very basic implementation of json schema.
/// The json schema definition draft can be found at
/// http://tools.ietf.org/html/draft-zyp-json-schema-03
///
/// The following keywords are supported:
/// - type
/// - required
/// - properties
/// - items
/// - enum
/// - minimum
/// - maximum
/// - addtionalProperties
/// - minItems
/// - maxItems
///
/// And the non-standard:
/// - dependencies
class JsonSchemaChecker
{
public:
JsonSchemaChecker();
virtual ~JsonSchemaChecker();
///
/// @param schema The schema to use
/// @return true upon succes
///
bool setSchema(const Json::Value & schema);
///
/// @brief Validate a JSON structure
/// @param value The JSON value to check
/// @return true when the arguments is valid according to the schema
///
bool validate(const Json::Value & value);
///
/// @return A list of error messages
///
const std::list<std::string> & getMessages() const;
private:
void collectReferences(const Json::Value & schema);
///
/// Validates a json-value against a given schema. Results are stored in the members of this
/// class (_error & _messages)
///
/// @param[in] value The value to validate
/// @param[in] schema The schema against which the value is validated
///
void validate(const Json::Value &value, const Json::Value & schema);
///
/// Adds the given message to the message-queue (with reference to current line-number)
///
/// @param[in] message The message to add to the queue
///
void setMessage(const std::string & message);
///
/// Retrieves all references from the json-value as specified by the schema
///
/// @param[in] value The json-value
/// @param[in] schema The schema
///
void collectDependencies(const Json::Value & value, const Json::Value &schema);
private:
// attribute check functions
///
/// Checks if the given value is of the specified type. If the type does not match _error is set
/// to true and an error-message is added to the message-queue
///
/// @param[in] value The given value
/// @param[in] schema The specified type (as json-value)
///
void checkType(const Json::Value & value, const Json::Value & schema);
///
/// Checks is required properties of an json-object exist and if all properties are of the
/// correct format. If this is not the case _error is set to true and an error-message is added
/// to the message-queue.
///
/// @param[in] value The given json-object
/// @param[in] schema The schema of the json-object
///
void checkProperties(const Json::Value & value, const Json::Value & schema);
///
/// Verifies the additional configured properties of an json-object. If this is not the case
/// _error is set to true and an error-message is added to the message-queue.
///
/// @param value The given json-object
/// @param schema The schema for the json-object
/// @param ignoredProperties The properties that were ignored
///
void checkAdditionalProperties(const Json::Value & value, const Json::Value & schema, const Json::Value::Members & ignoredProperties);
///
/// Checks if references are configued and used correctly. If this is not the case _error is set
/// to true and an error-message is added to the message-queue.
///
/// @param value The given json-object
/// @param schemaLink The schema of the json-object
///
void checkDependencies(const Json::Value & value, const Json::Value & schemaLink);
///
/// Checks if the given value is larger or equal to the specified value. If this is not the case
/// _error is set to true and an error-message is added to the message-queue.
///
/// @param[in] value The given value
/// @param[in] schema The minimum value (as json-value)
///
void checkMinimum(const Json::Value & value, const Json::Value & schema);
///
/// Checks if the given value is smaller or equal to the specified value. If this is not the
/// case _error is set to true and an error-message is added to the message-queue.
///
/// @param[in] value The given value
/// @param[in] schema The maximum value (as json-value)
///
void checkMaximum(const Json::Value & value, const Json::Value & schema);
///
/// Validates all the items of an array.
///
/// @param value The json-array
/// @param schema The schema for the items in the array
///
void checkItems(const Json::Value & value, const Json::Value & schema);
///
/// Checks if a given array has at least a minimum number of items. If this is not the case
/// _error is set to true and an error-message is added to the message-queue.
///
/// @param value The json-array
/// @param schema The minimum size specification (as json-value)
///
void checkMinItems(const Json::Value & value, const Json::Value & schema);
///
/// Checks if a given array has at most a maximum number of items. If this is not the case
/// _error is set to true and an error-message is added to the message-queue.
///
/// @param value The json-array
/// @param schema The maximum size specification (as json-value)
///
void checkMaxItems(const Json::Value & value, const Json::Value & schema);
///
/// Checks if a given array contains only unique items. If this is not the case
/// _error is set to true and an error-message is added to the message-queue.
///
/// @param value The json-array
/// @param schema Bool to enable the check (as json-value)
///
void checkUniqueItems(const Json::Value & value, const Json::Value & schema);
///
/// Checks if an enum value is actually a valid value for that enum. If this is not the case
/// _error is set to true and an error-message is added to the message-queue.
///
/// @param value The enum value
/// @param schema The enum schema definition
///
void checkEnum(const Json::Value & value, const Json::Value & schema);
private:
/// The schema of the entire json-configuration
Json::Value _schema;
/// The current location into a json-configuration structure being checked
std::list<std::string> _currentPath;
/// The result messages collected during the schema verification
std::list<std::string> _messages;
/// Flag indicating an error occured during validation
bool _error;
/// A list with references (string => json-value)
std::map<std::string, const Json::Value *> _references; // ref 2 value
};

View File

@ -14,37 +14,80 @@
// Hyperion includes
#include <hyperion/Hyperion.h>
/// Check if XBMC is playing something. When it does not, this class will send all black data Hyperion to
/// override (grabbed) data with a lower priority
// Utils includes
#include <utils/GrabbingMode.h>
///
/// This class will check if XBMC is playing something. When it does not, this class will send all black data to Hyperion.
/// This allows grabbed screen data to be overriden while in the XBMC menus.
///
/// Note: The json TCP server needs to be enabled manually in XBMC in System/Settings/Network/Services
///
class XBMCVideoChecker : public QObject
{
Q_OBJECT
public:
XBMCVideoChecker(const std::string & address, uint16_t port, uint64_t interval, Hyperion * hyperion, int priority);
///
/// Constructor
///
/// @param address Network address of the XBMC instance
/// @param port Port number to use (XBMC default = 9090)
/// @param interval The interval at which XBMC is polled
/// @param grabVideo Whether or not to grab when the XBMC video player is playing
/// @param grabPhoto Whether or not to grab when the XBMC photo player is playing
/// @param grabAudio Whether or not to grab when the XBMC audio player is playing
/// @param grabMenu Whether or not to grab when nothing is playing (in XBMC menu)
///
XBMCVideoChecker(const std::string & address, uint16_t port, uint64_t interval, bool grabVideo, bool grabPhoto, bool grabAudio, bool grabMenu);
///
/// Start polling XBMC
///
void start();
signals:
void grabbingMode(GrabbingMode grabbingMode);
private slots:
///
/// Send a request to XBMC
///
void sendRequest();
///
/// Receive a reply from XBMC
///
void receiveReply();
private:
/// The network address of the XBMC instance
const QString _address;
/// The port number of XBMC
const uint16_t _port;
/// The JSON-RPC request message
const QByteArray _request;
/// The timer that schedules XBMC queries
QTimer _timer;
/// The QT TCP Socket with connection to XBMC
QTcpSocket _socket;
Hyperion * _hyperion;
/// Flag indicating whether or not to grab when the XBMC video player is playing
bool _grabVideo;
const int _priority;
/// Flag indicating whether or not to grab when the XBMC photo player is playing
bool _grabPhoto;
/// Flag indicating whether or not to grab when the XBMC audio player is playing
bool _grabAudio;
/// Flag indicating whether or not to grab when XBMC is playing nothing (in menu)
bool _grabMenu;
/// Previous emitted grab state
GrabbingMode _previousMode;
};

View File

@ -0,0 +1,35 @@
#include "AbstractBootSequence.h"
AbstractBootSequence::AbstractBootSequence(Hyperion * hyperion, const int64_t interval, const unsigned iterationCnt) :
_timer(),
_hyperion(hyperion),
_priority(0),
_iterationCounter(iterationCnt)
{
_timer.setInterval(interval);
_timer.setSingleShot(false);
QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
}
void AbstractBootSequence::start()
{
_timer.start();
}
void AbstractBootSequence::update()
{
if (_iterationCounter == 0)
{
_timer.stop();
_hyperion->clear(_priority);
return;
}
// Obtain the next led-colors from the child-class
const std::vector<RgbColor>& colors = nextColors();
// Write the colors to hyperion
_hyperion->setColors(_priority, colors, -1);
// Decrease the loop count
--_iterationCounter;
}

View File

@ -0,0 +1,62 @@
#pragma once
// QT includes
#include <QTimer>
// Bootsequence includes
#include <bootsequence/BootSequence.h>
// Hyperion includes
#include <hyperion/Hyperion.h>
///
/// The AbstractBootSequence is an 'abstract' implementation of the BootSequence that handles the
/// event generation and Hyperion connection. Subclasses only need to specify the interval and
/// return the colors for the leds for each iteration.
///
class AbstractBootSequence : public QObject, public BootSequence
{
Q_OBJECT
public:
///
/// Constructs the AbstractBootSequence with the given parameters
///
/// @param hyperion The Hyperion instance
/// @param interval The interval between new led colors
/// @param iterationCnt The number of iteration performed by the boot sequence
///
AbstractBootSequence(Hyperion * hyperion, const int64_t interval, const unsigned iterationCnt);
///
/// Starts the boot-sequence
///
virtual void start();
protected slots:
///
/// Timer slot for handling each interval of the boot-sequence
///
void update();
protected:
///
/// Child-classes must implement this by returning the next led colors in the sequence
///
/// @return The next led colors in the boot sequence
///
virtual const std::vector<RgbColor>& nextColors() = 0;
private:
/// The timer used to generate an 'update' signal every interval
QTimer _timer;
/// The Hyperion instance
Hyperion * _hyperion;
/// The priority of the boot sequence
int _priority;
/// The counter of the number of iterations left
int _iterationCounter;
};

View File

@ -4,6 +4,7 @@
// Local Bootsequence includes
#include "RainbowBootSequence.h"
#include "KittBootSequence.h"
BootSequence * BootSequenceFactory::createBootSequence(Hyperion * hyperion, const Json::Value & jsonConfig)
{
@ -20,11 +21,8 @@ BootSequence * BootSequenceFactory::createBootSequence(Hyperion * hyperion, cons
}
else if (type == "knightrider")
{
std::cout << "KNIGHT RIDER NOT IMPLEMENTED YET" << std::endl;
return nullptr;
// const unsigned duration_ms = jsonConfig["duration_ms"].asUint();
// const std::string colorStr = jsonConfig["color"].asString();
// return new KnightRiderSequence(hyperion, duration_ms);
const unsigned duration_ms = jsonConfig["duration_ms"].asUInt();
return new KittBootSequence(hyperion, duration_ms);
}
std::cerr << "Unknown boot-sequence selected; boot-sequence disabled." << std::endl;

View File

@ -5,17 +5,21 @@ SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/bootsequence)
# Group the headers that go through the MOC compiler
SET(BootsequenceQT_HEADERS
${CURRENT_SOURCE_DIR}/RainbowBootSequence.h
${CURRENT_SOURCE_DIR}/AbstractBootSequence.h
)
SET(BootsequenceHEADERS
${CURRENT_HEADER_DIR}/BootSequence.h
${CURRENT_HEADER_DIR}/BootSequenceFactory.h
${CURRENT_SOURCE_DIR}/RainbowBootSequence.h
${CURRENT_SOURCE_DIR}/KittBootSequence.h
)
SET(BootsequenceSOURCES
${CURRENT_SOURCE_DIR}/AbstractBootSequence.cpp
${CURRENT_SOURCE_DIR}/BootSequenceFactory.cpp
${CURRENT_SOURCE_DIR}/RainbowBootSequence.cpp
${CURRENT_SOURCE_DIR}/KittBootSequence.cpp
)
QT4_WRAP_CPP(BootsequenceHEADERS_MOC ${BootsequenceQT_HEADERS})

View File

@ -0,0 +1,67 @@
// Hyperion includes
#include <hyperion/ImageProcessorFactory.h>
// Local-Bootsequence includes
#include "KittBootSequence.h"
KittBootSequence::KittBootSequence(Hyperion * hyperion, const unsigned duration_ms) :
AbstractBootSequence(hyperion, 100, duration_ms/100),
_processor(ImageProcessorFactory::getInstance().newImageProcessor()),
_image(9, 1),
_ledColors(hyperion->getLedCount(), RgbColor::BLACK),
_forwardMove(false),
_currentLight(0)
{
// empty
}
KittBootSequence::~KittBootSequence()
{
delete _processor;
}
const std::vector<RgbColor>& KittBootSequence::nextColors()
{
// Switch the previous light 'off'
_image(_currentLight, 0) = RgbColor::BLACK;
// Move the current to the next light
moveNextLight();
// Switch the current light 'on'
_image(_currentLight, 0) = RgbColor::RED;
// Translate the 'image' to led colors
_processor->process(_image, _ledColors);
// Return the colors
return _ledColors;
}
void KittBootSequence::moveNextLight()
{
// Increase/Decrease the current light
if (_forwardMove)
{
++_currentLight;
if (_currentLight == _image.width())
{
_forwardMove = false;
--_currentLight;
}
}
else
{
if (_currentLight == 0)
{
_forwardMove = true;
}
else
{
--_currentLight;
}
}
}

View File

@ -0,0 +1,56 @@
#pragma once
// Bootsequence includes
#include "AbstractBootSequence.h"
// Hyperion includes
#include <hyperion/Hyperion.h>
#include <hyperion/ImageProcessor.h>
///
/// The KITT BootSequence is a boot sequence inspired by the Knight Rider car: Knight Industries Two
/// Thousand (aka KITT)
///
class KittBootSequence : public AbstractBootSequence
{
public:
///
/// Constructs the KITT BootSequence
///
/// @param[in] hyperion The Hyperion instance
/// @param[in] duration_ms The length of the sequence [ms]
///
KittBootSequence(Hyperion * hyperion, const unsigned duration_ms);
///
/// Destructor, deletes the processor
///
virtual ~KittBootSequence();
///
/// Returns the next led color sequence
///
/// @return The next colors for the leds
///
virtual const std::vector<RgbColor>& nextColors();
private:
/// Image processor to compute led-colors from the image
ImageProcessor * _processor;
/// 1D-Image of the KITT-grill contains a single red pixel and the rest black
RgbImage _image;
/// The vector with led-colors
std::vector<RgbColor> _ledColors;
/// Direction the red-light is currently moving
bool _forwardMove = true;
/// The location of the current red-light
unsigned _currentLight = 0;
/// Moves the current light to the next (increase or decrease depending on direction)
void moveNextLight();
};

View File

@ -6,49 +6,25 @@
#include "RainbowBootSequence.h"
RainbowBootSequence::RainbowBootSequence(Hyperion * hyperion, const unsigned duration_ms) :
_timer(),
_hyperion(hyperion),
_priority(0),
_ledColors(hyperion->getLedCount()),
_iterationCounter(hyperion->getLedCount())
AbstractBootSequence(hyperion, duration_ms/hyperion->getLedCount(), hyperion->getLedCount()),
_ledColors(hyperion->getLedCount())
{
for (unsigned iLed=0; iLed<_hyperion->getLedCount(); ++iLed)
for (unsigned iLed=0; iLed<hyperion->getLedCount(); ++iLed)
{
RgbColor& color = _ledColors[iLed];
HsvTransform::hsv2rgb(iLed*360/_hyperion->getLedCount(), 255, 255, color.red, color.green, color.blue);
HsvTransform::hsv2rgb(iLed*360/hyperion->getLedCount(), 255, 255, color.red, color.green, color.blue);
}
_timer.setInterval(duration_ms/_hyperion->getLedCount());
_timer.setSingleShot(false);
QObject::connect(&_timer, SIGNAL(timeout()), this, SLOT(update()));
}
void RainbowBootSequence::start()
const std::vector<RgbColor>& RainbowBootSequence::nextColors()
{
_timer.start();
}
void RainbowBootSequence::update()
{
if (_iterationCounter == 0)
// Rotate the colors left
const RgbColor headColor = _ledColors.front();
for (unsigned i=1; i<_ledColors.size(); ++i)
{
_timer.stop();
_hyperion->clear(_priority);
_ledColors[i-1] = _ledColors[i];
}
else
{
// Rotate the colors left
const RgbColor headColor = _ledColors.front();
for (unsigned i=1; i<_ledColors.size(); ++i)
{
_ledColors[i-1] = _ledColors[i];
}
_ledColors.back() = headColor;
_ledColors.back() = headColor;
// Write the colors to hyperion
_hyperion->setColors(_priority, _ledColors, -1);
// Decrease the loop count
--_iterationCounter;
}
return _ledColors;
}

View File

@ -5,19 +5,14 @@
#include <QTimer>
// Bootsequence include
#include <bootsequence/BootSequence.h>
// Hyperion includes
#include <hyperion/Hyperion.h>
#include "AbstractBootSequence.h"
///
/// The RainborBootSequence shows a 'rainbow' (all lights have a different color). The rainbow is
/// rotated over each led during the length of the sequence.
///
class RainbowBootSequence : public QObject, public BootSequence
class RainbowBootSequence : public AbstractBootSequence
{
Q_OBJECT
public:
///
/// Constructs the rainbow boot-sequence. Hyperion is used for writing the led colors. The given
@ -28,27 +23,13 @@ public:
///
RainbowBootSequence(Hyperion * hyperion, const unsigned duration_ms);
///
/// Starts the boot-sequence
///
virtual void start();
private slots:
protected:
///
/// Moves the rainbow one led further
///
void update();
const std::vector<RgbColor>& nextColors();
private:
/// The timer used to generate an 'update' signal every interval
QTimer _timer;
/// The Hyperion instance
Hyperion * _hyperion;
/// The priority of the boot sequence
int _priority;
/// The current color of the boot sequence (the rainbow)
std::vector<RgbColor> _ledColors;
/// The counter of the number of iterations left

View File

@ -60,3 +60,11 @@ void DispmanxWrapper::stop()
// Stop the timer, effectivly stopping the process
_timer.stop();
}
void DispmanxWrapper::setGrabbingMode(GrabbingMode mode)
{
if (mode == GRABBINGMODE_VIDEO)
start();
else
stop();
}

View File

@ -6,32 +6,65 @@
namespace hyperion
{
///
/// The BlackBorder processor is a wrapper around the black-border detector for keeping track of
/// detected borders and count of the type and size of detected borders.
///
class BlackBorderProcessor
{
public:
///
/// Constructor for the BlackBorderProcessor
/// @param unknownFrameCnt The number of frames(images) that need to contain an unknown
/// border before the current border is set to unknown
/// @param borderFrameCnt The number of frames(images) that need to contain a vertical or
/// horizontal border becomes the current border
/// @param blurRemoveCnt The size to add to a horizontal or vertical border (because the
/// outer pixels is blurred (black and color combined))
///
BlackBorderProcessor(
const unsigned unknownFrameCnt,
const unsigned borderFrameCnt,
const unsigned blurRemoveCnt);
///
/// Return the current (detected) border
/// @return The current border
///
BlackBorder getCurrentBorder() const;
///
/// Processes the image. This performs detecion of black-border on the given image and
/// updates the current border accordingly. If the current border is updated the method call
/// will return true else false
///
/// @param image The image to process
///
/// @return True if a different border was detected than the current else false
///
bool process(const RgbImage& image);
private:
/// The number of unknown-borders detected before it becomes the current border
const unsigned _unknownSwitchCnt;
/// The number of horizontal/vertical borders detected before it becomes the current border
const unsigned _borderSwitchCnt;
/// The number of pixels to increase a detected border for removing blury pixels
unsigned _blurRemoveCnt;
/// The blackborder detector
BlackBorderDetector _detector;
/// The current detected border
BlackBorder _currentBorder;
/// The border detected in the previous frame
BlackBorder _previousDetectedBorder;
/// The number of frame the previous detected border matched the incomming border
unsigned _consistentCnt;
};
} // end namespace hyperion

View File

@ -22,12 +22,10 @@ LedDevice* Hyperion::constructDevice(const Json::Value& deviceConfig)
LedDevice* device = nullptr;
if (deviceConfig["type"].asString() == "ws2801")
{
const std::string name = "WS-2801";
const std::string output = deviceConfig["output"].asString();
const unsigned interval = deviceConfig["interval"].asInt();
const unsigned rate = deviceConfig["rate"].asInt();
LedDeviceWs2801* deviceWs2801 = new LedDeviceWs2801(name, output, interval, rate);
LedDeviceWs2801* deviceWs2801 = new LedDeviceWs2801(output, rate);
deviceWs2801->open();
device = deviceWs2801;
@ -117,7 +115,7 @@ unsigned Hyperion::getLedCount() const
return _ledString.leds().size();
}
void Hyperion::setColor(int priority, RgbColor & color, const int timeout_ms)
void Hyperion::setColor(int priority, const RgbColor &color, const int timeout_ms)
{
// create led output
std::vector<RgbColor> ledColors(_ledString.leds().size(), color);
@ -126,7 +124,7 @@ void Hyperion::setColor(int priority, RgbColor & color, const int timeout_ms)
setColors(priority, ledColors, timeout_ms);
}
void Hyperion::setColors(int priority, std::vector<RgbColor>& ledColors, const int timeout_ms)
void Hyperion::setColors(int priority, const std::vector<RgbColor>& ledColors, const int timeout_ms)
{
if (timeout_ms > 0)
{

View File

@ -59,6 +59,8 @@ namespace hyperion
/// Determines the mean-color for each led using the mapping the image given
/// at construction.
///
/// @param[in] image The image from which to extract the led colors
///
/// @return ledColors The vector containing the output
///
std::vector<RgbColor> getMeanLedColor(const RgbImage & image) const;
@ -67,6 +69,7 @@ namespace hyperion
/// Determines the mean color for each led using the mapping the image given
/// at construction.
///
/// @param[in] image The image from which to extract the led colors
/// @param[out] ledColors The vector containing the output
///
void getMeanLedColor(const RgbImage & image, std::vector<RgbColor> & ledColors) const;
@ -83,6 +86,7 @@ namespace hyperion
/// Calculates the 'mean color' of the given list. This is the mean over each color-channel
/// (red, green, blue)
///
/// @param[in] image The image a section from which an average color must be computed
/// @param[in] colors The list with colors
///
/// @return The mean of the given list of colors (or black when empty)

View File

@ -6,14 +6,33 @@
// Hyperion includes
#include <hyperion/LedDevice.h>
///
/// Implementation of the LedDevice that write the led-colors to an
/// ASCII-textfile('/home/pi/LedDevice.out')
///
class LedDeviceTest : public LedDevice
{
public:
///
/// Constructs the test-device, which opens an output stream to the file
///
LedDeviceTest();
///
/// Destructor of this test-device
///
virtual ~LedDeviceTest();
///
/// Writes the given led-color values to the output stream
///
/// @param ledValues The color-value per led
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<RgbColor> & ledValues);
private:
/// The outputstream
std::ofstream _ofs;
};

View File

@ -11,9 +11,7 @@
// hyperion local includes
#include "LedDeviceWs2801.h"
LedDeviceWs2801::LedDeviceWs2801(const std::string& name,
const std::string& outputDevice,
const unsigned interval,
LedDeviceWs2801::LedDeviceWs2801(const std::string& outputDevice,
const unsigned baudrate) :
mDeviceName(outputDevice),
mBaudRate_Hz(baudrate),

View File

@ -9,25 +9,51 @@
// hyperion incluse
#include <hyperion/LedDevice.h>
///
/// Implementation of the LedDevice interface for writing to Ws2801 led device.
///
class LedDeviceWs2801 : public LedDevice
{
public:
LedDeviceWs2801(const std::string& name,
const std::string& outputDevice,
const unsigned interval,
///
/// 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
///
LedDeviceWs2801(const std::string& outputDevice,
const unsigned baudrate);
///
/// Destructor of the LedDevice; closes the output device if it is open
///
virtual ~LedDeviceWs2801();
///
/// Opens and configures the output device
///
/// @return Zero on succes else negative
///
int open();
///
/// 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<RgbColor> &ledValues);
private:
/// The name of the output device
const std::string mDeviceName;
/// The used baudrate of the output device
const int mBaudRate_Hz;
/// The File Identifier of the opened output device (or -1 if not opened)
int mFid;
/// The transfer structure for writing to the spi-device
spi_ioc_transfer spi;
/// The 'latch' time for latching the shifted-value into the leds
timespec latchTime;
};

View File

@ -17,6 +17,7 @@ LedString::LedString()
LedString::~LedString()
{
// empty
}
std::vector<Led>& LedString::leds()

View File

@ -18,44 +18,140 @@
class ImageProcessor;
///
/// The Connection object created by \a JsonServer when a new connection is establshed
///
class JsonClientConnection : public QObject
{
Q_OBJECT
public:
///
/// Constructor
/// @param socket The Socket object for this connection
/// @param hyperion The Hyperion server
///
JsonClientConnection(QTcpSocket * socket, Hyperion * hyperion);
///
/// Destructor
///
~JsonClientConnection();
signals:
///
/// Signal which is emitted when the connection is being closed
/// @param connection This connection object
///
void connectionClosed(JsonClientConnection * 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 JSON message
///
/// @param message the incoming message as string
///
void handleMessage(const std::string & message);
///
/// Handle an incoming JSON Color message
///
/// @param message the incoming message
///
void handleColorCommand(const Json::Value & message);
///
/// Handle an incoming JSON Image message
///
/// @param message the incoming message
///
void handleImageCommand(const Json::Value & message);
///
/// Handle an incoming JSON Server info message
///
/// @param message the incoming message
///
void handleServerInfoCommand(const Json::Value & message);
///
/// Handle an incoming JSON Clear message
///
/// @param message the incoming message
///
void handleClearCommand(const Json::Value & message);
///
/// Handle an incoming JSON Clearall message
///
/// @param message the incoming message
///
void handleClearallCommand(const Json::Value & message);
///
/// Handle an incoming JSON Transform message
///
/// @param message the incoming message
///
void handleTransformCommand(const Json::Value & message);
///
/// Handle an incoming JSON message of unknown type
///
void handleNotImplemented();
///
/// Send a message to the connected client
///
/// @param message The JSON message to send
///
void sendMessage(const Json::Value & 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:
///
/// Check if a JSON messag is valid according to a given JSON schema
///
/// @param message JSON message which need to be checked
/// @param schemaResource Qt esource identifier with the JSON schema
/// @param errors Output error message
///
/// @return true if message conforms the given JSON schema
///
bool checkJson(const Json::Value & message, const QString &schemaResource, std::string & errors);
private:
/// The TCP-Socket that is connected tot the Json-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

@ -1,3 +1,4 @@
#include <iostream>
#include <utils/HsvTransform.h>
HsvTransform::HsvTransform() :
@ -44,6 +45,8 @@ 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;
@ -83,11 +86,21 @@ void HsvTransform::rgb2hsv(uint8_t red, uint8_t green, uint8_t blue, uint16_t &
}
if (rgbMax == red)
hue = 0 + 60 * (green - blue) / (rgbMax - rgbMin);
{
// start from 360 to be sure that we won't assign a negative number to the unsigned hue value
hue = 360 + 60 * (green - blue) / (rgbMax - rgbMin);
if (hue > 359)
hue -= 360;
}
else if (rgbMax == green)
{
hue = 120 + 60 * (blue - red) / (rgbMax - rgbMin);
}
else
{
hue = 240 + 60 * (red - green) / (rgbMax - rgbMin);
}
}
void HsvTransform::hsv2rgb(uint16_t hue, uint8_t saturation, uint8_t value, uint8_t & red, uint8_t & green, uint8_t & blue)
@ -103,7 +116,7 @@ void HsvTransform::hsv2rgb(uint16_t hue, uint8_t saturation, uint8_t value, uint
}
region = hue / 60;
remainder = (hue - (region * 60)) * 6;
remainder = (hue - (region * 60)) * 256 / 60;
p = (value * (255 - saturation)) >> 8;
q = (value * (255 - ((saturation * remainder) >> 8))) >> 8;

View File

@ -8,8 +8,8 @@
RgbImage::RgbImage(const unsigned width, const unsigned height, const RgbColor background) :
mWidth(width),
mHeight(height),
_width(width),
_height(height),
mColors(new RgbColor[width*height])
{
for (unsigned i=0; i<width*height; ++i)
@ -32,8 +32,8 @@ void RgbImage::setPixel(const unsigned x, const unsigned y, const RgbColor color
const RgbColor& RgbImage::operator()(const unsigned x, const unsigned y) const
{
// Debug-mode sanity check on given index
assert(x < mWidth);
assert(y < mHeight);
assert(x < _width);
assert(y < _height);
const unsigned index = toIndex(x, y);
return mColors[index];
@ -42,8 +42,8 @@ const RgbColor& RgbImage::operator()(const unsigned x, const unsigned y) const
RgbColor& RgbImage::operator()(const unsigned x, const unsigned y)
{
// Debug-mode sanity check on given index
assert(x < mWidth);
assert(y < mHeight);
assert(x < _width);
assert(y < _height);
const unsigned index = toIndex(x, y);
return mColors[index];

View File

@ -413,7 +413,7 @@ void JsonSchemaChecker::checkUniqueItems(const Json::Value & value, const Json::
{
// only for arrays
_error = true;
setMessage("maxItems only valid for arrays");
setMessage("uniqueItems only valid for arrays");
return;
}

View File

@ -3,15 +3,18 @@
#include <xbmcvideochecker/XBMCVideoChecker.h>
XBMCVideoChecker::XBMCVideoChecker(const std::string & address, uint16_t port, uint64_t interval_ms, Hyperion * hyperion, int priority) :
XBMCVideoChecker::XBMCVideoChecker(const std::string & address, uint16_t port, uint64_t interval_ms, bool grabVideo, bool grabPhoto, bool grabAudio, bool grabMenu) :
QObject(),
_address(QString::fromStdString(address)),
_port(port),
_request("{\"jsonrpc\":\"2.0\",\"method\":\"Player.GetActivePlayers\",\"id\":1}"),
_timer(),
_socket(),
_hyperion(hyperion),
_priority(priority)
_grabVideo(grabVideo),
_grabPhoto(grabPhoto),
_grabAudio(grabAudio),
_grabMenu(grabMenu),
_previousMode(GRABBINGMODE_INVALID)
{
// setup timer
_timer.setSingleShot(false);
@ -51,17 +54,33 @@ void XBMCVideoChecker::receiveReply()
// expect that the reply is received as a single message. Probably oke considering the size of the expected reply
QString reply(_socket.readAll());
if (reply.contains("playerid"))
GrabbingMode newMode = GRABBINGMODE_INVALID;
if (reply.contains("video"))
{
// something is playing. check for "video" to check if a video is playing
// clear our priority channel to allow the grabbed vido colors to be shown
_hyperion->clear(_priority);
// video is playing
newMode = _grabVideo ? GRABBINGMODE_VIDEO : GRABBINGMODE_OFF;
}
else if (reply.contains("picture"))
{
// photo viewer is playing
newMode = _grabVideo ? GRABBINGMODE_PHOTO : GRABBINGMODE_OFF;
}
else if (reply.contains("audio"))
{
// photo viewer is playing
newMode = _grabVideo ? GRABBINGMODE_AUDIO : GRABBINGMODE_OFF;
}
else
{
// Nothing is playing. set our priority channel completely to black
// The timeout is used to have the channel cleared after 30 seconds of connection problems...
_hyperion->setColor(_priority, RgbColor::BLACK, 30000);
// Nothing is playing.
newMode = _grabMenu ? GRABBINGMODE_MENU : GRABBINGMODE_OFF;
}
// emit new state if applicable
if (newMode != _previousMode)
{
emit grabbingMode(newMode);
_previousMode = newMode;
}
}

View File

@ -3,7 +3,10 @@
/// Simple structure to contain the values of a color transformation
struct ColorTransformValues
{
/// The value for the red color-channel
double valueRed;
/// The value for the green color-channel
double valueGreen;
/// The value for the blue color-channel
double valueBlue;
};

View File

@ -10,13 +10,25 @@
// hyperion-remote includes
#include "ColorTransformValues.h"
/// Data parameter for a color
typedef vlofgren::PODParameter<QColor> ColorParameter;
/// Data parameter for an image
typedef vlofgren::PODParameter<QImage> ImageParameter;
/// Data parameter for color transform values (list of three values)
typedef vlofgren::PODParameter<ColorTransformValues> TransformParameter;
namespace vlofgren {
///
/// Translates a string (as passed on the commandline) to a color
///
/// @param[in] s The string (as passed on the commandline)
///
/// @return The translated color
///
/// @throws Parameter::ParameterRejected If the string did not result in a color
///
template<>
QColor ColorParameter::validate(const std::string& s) throw (Parameter::ParameterRejected)
{

View File

@ -15,30 +15,74 @@
// hyperion-remote includes
#include "ColorTransformValues.h"
///
/// Connection class to setup an connection to the hyperion server and execute commands
///
class JsonConnection
{
public:
///
/// Constructor
///
/// @param address The address of the Hyperion server (for example "192.168.0.32:19444)
/// @param printJson Boolean indicating if the sent and received json is written to stdout
///
JsonConnection(const std::string & address, bool printJson);
///
/// Destructor
///
~JsonConnection();
///
/// Set all leds to the specified color
///
/// @param color The color
/// @param priority The priority
/// @param duration The duration in milliseconds
///
void setColor(QColor color, int priority, int duration);
///
/// Set the leds according to the given image (assume the image is stretched to the display size)
///
/// @param image The image
/// @param priority The priority
/// @param duration The duration in milliseconds
///
void setImage(QImage image, int priority, int duration);
///
/// Retrieve a list of all occupied priority channels
///
/// @return String with the server info
///
QString getServerInfo();
///
/// Clear the given priority channel
///
/// @param priority The priority
///
void clear(int priority);
///
/// Clear all priority channels
///
void clearAll();
///
/// Set the color transform of the leds
/// Note that providing a NULL will leave the settings on the server unchanged
///
/// @note Note that providing a NULL will leave the settings on the server unchanged
///
/// @param saturation The HSV saturation gain
/// @param value The HSV value gain
/// @param threshold The threshold
/// @param gamma The gamma value
/// @param blacklevel The blacklevel
/// @param whitelevel The whitelevel
///
void setTransform(
double * saturation,
double * value,
@ -48,13 +92,28 @@ public:
ColorTransformValues * whitelevel);
private:
///
/// Send a json command message and receive its reply
///
/// @param message The message to send
///
/// @return The returned reply
///
Json::Value sendMessage(const Json::Value & message);
///
/// Parse a reply message
///
/// @param reply The received reply
///
/// @return true if the reply indicates success
///
bool parseReply(const Json::Value & reply);
private:
/// Flag for printing all send and received json-messages to the standard out
bool _printJson;
/// The TCP-Socket with the connection to the server
QTcpSocket _socket;
};

View File

@ -83,7 +83,7 @@ int main(int argc, char** argv)
}
const Json::Value & videoCheckerConfig = config["xbmcVideoChecker"];
XBMCVideoChecker xbmcVideoChecker(videoCheckerConfig["xbmcAddress"].asString(), videoCheckerConfig["xbmcTcpPort"].asUInt(), 1000, &hyperion, 999);
XBMCVideoChecker xbmcVideoChecker(videoCheckerConfig["xbmcAddress"].asString(), videoCheckerConfig["xbmcTcpPort"].asUInt(), 1000, true, true, true, true);
if (videoCheckerConfig["enable"].asBool())
{
xbmcVideoChecker.start();
@ -97,6 +97,7 @@ int main(int argc, char** argv)
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;

View File

@ -6,6 +6,7 @@ if(PNG_FOUND)
include_directories(${PNG_INCLUDE_DIR})
add_executable(viewpng
FbWriter.h
ViewPng.cpp)
target_link_libraries(viewpng

View File

@ -12,14 +12,27 @@
#include <utils/RgbImage.h>
///
/// FbWriter allows direct access tot the FrameBuffer. It writes and image to the framebuffer,
/// adjusting the resolution as required. When destructed the FrameBuffer is switch to original
/// configuration.
///
class FbWriter
{
public:
///
/// Constructs the FrameBuffer writer opening the FrameBuffer device and storing the current
/// configuration.
///
FbWriter()
{
initialise();
}
///
/// Destructor of the write. Switches the FrameBuffer to its origianl configuration and closes
/// the FrameBuffer
///
~FbWriter()
{
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo))
@ -30,26 +43,33 @@ public:
close(fbfd);
}
///
/// Initialises the write, opening the FrameBuffer
///
/// @return Zero on succes else negative
///
int initialise()
{
// Open the file for reading and writing
fbfd = open("/dev/fb0", O_RDWR);
if (!fbfd)
{
printf("Error: cannot open framebuffer device.\n");
return(-1);
std::cerr << "Error: cannot open framebuffer device." << std::endl;
return -1;
}
printf("The framebuffer device was opened successfully.\n");
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
{
printf("Error reading fixed information.\n");
std::cerr << "Error reading fixed information.\n" << std::endl;
return -1;
}
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &orig_vinfo))
{
printf("Error reading variable information.\n");
std::cerr << "Error reading variable information.\n" << std::endl;
return -1;
}
printf("Original %dx%d, %dbpp\n", orig_vinfo.xres, orig_vinfo.yres, orig_vinfo.bits_per_pixel );
@ -57,6 +77,12 @@ public:
return 0;
}
///
/// Writes the given RGB Image to the FrameBuffer. When required the resolution of the
/// FrameBuffer is asjusted to match the given image
///
/// @param image The RGB Image
///
void writeImage(const RgbImage& image)
{
std::cout << "Writing image [" << image.width() << "x" << image.height() << "]" << std::endl;
@ -93,23 +119,16 @@ public:
for (unsigned iY=0; iY<image.height(); ++iY)
{
memcpy(fbp + iY*finfo.line_length, &(image(0, iY)), image.width()*3);
// for (unsigned iX=0; iX<image.width(); ++iX)
// {
// const unsigned pixOffset = iX*3 + iY*finfo.line_length;
// fbp[pixOffset ] = image(iX, iY).red;
// fbp[pixOffset+1] = image(iX, iY).green;
// fbp[pixOffset+2] = image(iX, iY).blue;
// }
}
std::cout << "FINISHED COPYING IMAGE TO FRAMEBUFFER" << std::endl;
// cleanup
munmap(fbp, screensize);
}
// The identifier of the FrameBuffer File-Device
/// The identifier of the FrameBuffer File-Device
int fbfd;
// The 'Fixed' screen information
/// The 'Fixed' screen information
fb_fix_screeninfo finfo;
// The original 'Variable' screen information
/// The original 'Variable' screen information
fb_var_screeninfo orig_vinfo;
};

View File

@ -54,7 +54,7 @@ void setColor(char* colorStr)
unsigned ledCnt = 50;
std::vector<RgbColor> buff(ledCnt, color);
LedDeviceWs2801 ledDevice("SpiPi", "/dev/spidev0.0", 20000, 40000);
LedDeviceWs2801 ledDevice("/dev/spidev0.0", 40000);
ledDevice.open();
ledDevice.write(buff);
}
@ -68,7 +68,7 @@ void doCircle()
unsigned ledCnt = 50;
std::vector<RgbColor> data(ledCnt, RgbColor::BLACK);
LedDeviceWs2801 ledDevice("SpiPi", "/dev/spidev0.0", 20000, 40000);
LedDeviceWs2801 ledDevice("/dev/spidev0.0", 40000);
ledDevice.open();
timespec loopTime;