Merge branch 'master' into macos_compile

Conflicts:
	libsrc/leddevice/CMakeLists.txt
	libsrc/leddevice/LedDeviceFactory.cpp
	test/TestRs232HighSpeed.cpp

Former-commit-id: 5583f2f881
This commit is contained in:
T. van der Zwan 2013-12-28 08:55:06 +01:00
commit fd835b5bfb
27 changed files with 1428 additions and 187 deletions

View File

@ -383,12 +383,14 @@
},
/// 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
/// * xbmcAddress : The IP address of the XBMC-host
/// * xbmcTcpPort : The TCP-port of the XBMC-server
/// * grabVideo : Flag indicating that the frame-grabber is on(true) during video playback
/// * grabPictures : Flag indicating that the frame-grabber is on(true) during picture show
/// * grabAudio : Flag indicating that the frame-grabber is on(true) during audio playback
/// * grabMenu : Flag indicating that the frame-grabber is on(true) in the XBMC menu
/// * grabScreensaver : Flag indicating that the frame-grabber is on(true) when XBMC is on screensaver
/// * enable3DDetection : Flag indicating that the frame-grabber should switch to a 3D compatible modus if a 3D video is playing
"xbmcVideoChecker" :
{
"xbmcAddress" : "127.0.0.1",
@ -396,7 +398,9 @@
"grabVideo" : true,
"grabPictures" : true,
"grabAudio" : true,
"grabMenu" : false
"grabMenu" : false,
"grabScreensaver" : true,
"enable3DDetection" : true
},
/// The configuration of the Json server which enables the json remote interface

View File

@ -144,6 +144,206 @@
"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 }
}
],
@ -171,34 +371,6 @@
"duration_ms" : 3000
},
/// The configuration for the frame-grabber, contains the following items:
/// * width : The width of the grabbed frames [pixels]
/// * height : The height of the grabbed frames [pixels]
/// * frequency_Hz : The frequency of the frame grab [Hz]
// "framegrabber" :
// {
// "width" : 64,
// "height" : 64,
// "frequency_Hz" : 10.0
// },
/// The configuration of the XBMC connection used to enable and disable the frame-grabber. Contains the following fields:
/// * xbmcAddress : The IP address of the XBMC-host
/// * xbmcTcpPort : The TCP-port of the XBMC-server
/// * grabVideo : Flag indicating that the frame-grabber is on(true) during video playback
/// * grabPictures : Flag indicating that the frame-grabber is on(true) during picture show
/// * grabAudio : Flag indicating that the frame-grabber is on(true) during audio playback
/// * grabMenu : Flag indicating that the frame-grabber is on(true) in the XBMC menu
"xbmcVideoChecker" :
{
"xbmcAddress" : "127.0.0.1",
"xbmcTcpPort" : 9090,
"grabVideo" : true,
"grabPictures" : true,
"grabAudio" : true,
"grabMenu" : false
},
/// The configuration of the Json server which enables the json remote interface
/// * port : Port at which the json server is started
"jsonServer" :

View File

@ -45,7 +45,7 @@ void OptionsParser::parse(int argc, const char* argv[]) throw(runtime_error)
vector<string> v(&argv[1], &argv[argc]);
ParserState state(*this, v);
ParserState state(/* *this,*/ v);
for(; !state.end(); state.advance()) {
@ -164,7 +164,7 @@ Parameter& ParameterSet::operator[](char c) const {
for(std::list<Parameter*>::const_iterator i = parameters.begin(); i!= parameters.end(); i++) {
if((*i)->shortOption() == c) return *(*i);
}
throw out_of_range("ParameterSet["+c+string("]"));
throw out_of_range("ParameterSet["+string(&c)+string("]"));
}
@ -185,8 +185,8 @@ Parameter& ParameterSet::operator[](const string& param) const {
*/
ParserState::ParserState(OptionsParser &opts, vector<string>& args) :
opts(opts), arguments(args), iterator(args.begin())
ParserState::ParserState(/*OptionsParser &opts, */vector<string>& args) :
/*opts(opts),*/ arguments(args), iterator(args.begin())
{
}

View File

@ -129,11 +129,11 @@ public:
void advance();
bool end() const;
protected:
ParserState(OptionsParser &opts, std::vector<std::string>& args);
ParserState(/*OptionsParser &opts,*/ std::vector<std::string>& args);
private:
friend class OptionsParser;
OptionsParser &opts;
// OptionsParser &opts;
const std::vector<std::string> &arguments;
std::vector<std::string>::const_iterator iterator;
};

View File

@ -1 +1 @@
bfe21c488f982bc107e7acaa4c90be41a6782f9e
0074a4390b1d8d0c87488a3e7a13ec372786d140

View File

@ -1 +1 @@
c358364291c2377c26ef2912042fae6d7fe50d08
27dcc318ae9a9226676fb33626500e57703d7b6d

View File

@ -9,6 +9,7 @@
#include <utils/ColorRgb.h>
#include <utils/ColorRgba.h>
#include <utils/GrabbingMode.h>
#include <utils/VideoMode.h>
// Forward class declaration
class DispmanxFrameGrabber;
@ -61,6 +62,12 @@ public slots:
///
void setGrabbingMode(const GrabbingMode mode);
///
/// Set the video mode (2D/3D)
/// @param[in] mode The new video mode
///
void setVideoMode(const VideoMode videoMode);
private:
/// The update rate [Hz]
const int _updateInterval_ms;

View File

@ -118,6 +118,22 @@ public:
return _pixels[toIndex(x,y)];
}
/// Resize the image
/// @param width The width of the image
/// @param height The height of the image
void resize(const unsigned width, const unsigned height)
{
if ((width*height) > (_endOfPixels-_pixels))
{
delete[] _pixels;
_pixels = new Pixel_T[width*height + 1];
_endOfPixels = _pixels + width*height;
}
_width = width;
_height = height;
}
///
/// Copies another image into this image. The images should have exactly the same size.
///
@ -165,9 +181,9 @@ private:
private:
/// The width of the image
const unsigned _width;
unsigned _width;
/// The height of the image
const unsigned _height;
unsigned _height;
/// The pixels of the image
Pixel_T* _pixels;

11
include/utils/VideoMode.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
/**
* Enumeration of the possible modes in which video can be playing (2D, 3D)
*/
enum VideoMode
{
VIDEO_2D,
VIDEO_3DSBS,
VIDEO_3DTAB
};

View File

@ -16,6 +16,7 @@
// Utils includes
#include <utils/GrabbingMode.h>
#include <utils/VideoMode.h>
///
/// This class will check if XBMC is playing something. When it does not, this class will send all black data to Hyperion.
@ -33,13 +34,14 @@ public:
///
/// @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)
/// @param grabScreensaver Whether or not to grab when the XBMC screensaver is activated
/// @param enable3DDetection Wheter or not to enable the detection of 3D movies playing
///
XBMCVideoChecker(const std::string & address, uint16_t port, uint64_t interval, bool grabVideo, bool grabPhoto, bool grabAudio, bool grabMenu);
XBMCVideoChecker(const std::string & address, uint16_t port, bool grabVideo, bool grabPhoto, bool grabAudio, bool grabMenu, bool grabScreensaver, bool enable3DDetection);
///
/// Start polling XBMC
@ -47,19 +49,37 @@ public:
void start();
signals:
/// Signal emitted when the grabbing mode changes
void grabbingMode(GrabbingMode grabbingMode);
private slots:
///
/// Send a request to XBMC
///
void sendRequest();
/// Signal emitted when a 3D movie is detected
void videoMode(VideoMode videoMode);
///
private slots:
/// Receive a reply from XBMC
///
void receiveReply();
/// Called when connected to XBMC
void connected();
/// Called when disconnected from XBMC
void disconnected();
/// reconnect to XBMC
void reconnect();
/// Called when a connection error was encountered
void connectionError(QAbstractSocket::SocketError error);
private:
/// Set the grabbing mode
void setGrabbingMode(GrabbingMode grabbingMode);
void setScreensaverMode(bool isOnScreensaver);
/// Set the video mode
void setVideoMode(VideoMode videoMode);
private:
/// The network address of the XBMC instance
const QString _address;
@ -67,27 +87,42 @@ private:
/// The port number of XBMC
const uint16_t _port;
/// The JSON-RPC request message
const QByteArray _request;
/// The JSON-RPC message to check the active player
const QString _activePlayerRequest;
/// The timer that schedules XBMC queries
QTimer _timer;
/// The JSON-RPC message to check the currently playing file
const QString _currentPlayingItemRequest;
/// The JSON-RPC message to check the screensaver
const QString _checkScreensaverRequest;
/// The QT TCP Socket with connection to XBMC
QTcpSocket _socket;
/// Flag indicating whether or not to grab when the XBMC video player is playing
bool _grabVideo;
const bool _grabVideo;
/// Flag indicating whether or not to grab when the XBMC photo player is playing
bool _grabPhoto;
const bool _grabPhoto;
/// Flag indicating whether or not to grab when the XBMC audio player is playing
bool _grabAudio;
const bool _grabAudio;
/// Flag indicating whether or not to grab when XBMC is playing nothing (in menu)
bool _grabMenu;
const bool _grabMenu;
/// Previous emitted grab state
GrabbingMode _previousMode;
/// Flag inidcating whether or not to grab when the XBMC screensaver is activated
const bool _grabScreensaver;
/// Flag indicating wheter or not to enable the detection of 3D movies playing
const bool _enable3DDetection;
/// Flag indicating if XBMC is on screensaver
bool _previousScreensaverMode;
/// Previous emitted grab mode
GrabbingMode _previousGrabbingMode;
/// Previous emitted video mode
VideoMode _previousVideoMode;
};

View File

@ -61,10 +61,29 @@ void DispmanxFrameGrabber::setFlags(const int vc_flags)
_vc_flags = vc_flags;
}
void DispmanxFrameGrabber::setVideoMode(const VideoMode videoMode)
{
switch (videoMode) {
case VIDEO_3DSBS:
vc_dispmanx_rect_set(&_rectangle, 0, 0, _width/2, _height);
break;
case VIDEO_3DTAB:
vc_dispmanx_rect_set(&_rectangle, 0, 0, _width, _height/2);
break;
case VIDEO_2D:
default:
vc_dispmanx_rect_set(&_rectangle, 0, 0, _width, _height);
break;
}
}
void DispmanxFrameGrabber::grabFrame(Image<ColorRgba> & image)
{
// Sanity check of the given image size
assert(image.width() == _width && image.height() == _height);
// resize the given image if needed
if (image.width() != unsigned(_rectangle.width) || image.height() != unsigned(_rectangle.height))
{
image.resize(_rectangle.width, _rectangle.height);
}
// Open the connection to the display
_vc_display = vc_dispmanx_display_open(0);
@ -74,7 +93,7 @@ void DispmanxFrameGrabber::grabFrame(Image<ColorRgba> & image)
// Read the snapshot into the memory
void* image_ptr = image.memptr();
const unsigned destPitch = _width * sizeof(ColorRgba);
const unsigned destPitch = _rectangle.width * sizeof(ColorRgba);
vc_dispmanx_resource_read_data(_vc_resource, &_rectangle, image_ptr, destPitch);
// Close the displaye

View File

@ -10,6 +10,7 @@
// Utils includes
#include <utils/Image.h>
#include <utils/ColorRgba.h>
#include <utils/VideoMode.h>
///
/// The DispmanxFrameGrabber is used for creating snapshots of the display (screenshots) with a
@ -34,6 +35,12 @@ public:
///
void setFlags(const int vc_flags);
///
/// Set the video mode (2D/3D)
/// @param[in] mode The new video mode
///
void setVideoMode(const VideoMode videoMode);
///
/// Captures a single snapshot of the display and writes the data to the given image. The
/// provided image should have the same dimensions as the configured values (_width and
@ -58,8 +65,7 @@ private:
int _vc_flags;
/// With of the captured snapshot [pixels]
unsigned _width;
const unsigned _width;
/// Height of the captured snapshot [pixels]
unsigned _height;
const unsigned _height;
};

View File

@ -81,3 +81,8 @@ void DispmanxWrapper::setGrabbingMode(const GrabbingMode mode)
break;
}
}
void DispmanxWrapper::setVideoMode(const VideoMode mode)
{
_frameGrabber->setVideoMode(mode);
}

View File

@ -255,6 +255,14 @@
"grabMenu" : {
"type" : "boolean",
"required" : true
},
"grabScreensaver" : {
"type" : "boolean",
"required" : false
},
"enable3DDetection" : {
"type" : "boolean",
"required" : false
}
},
"additionalProperties" : false

View File

@ -24,6 +24,8 @@ SET(Leddevice_HEADERS
${CURRENT_SOURCE_DIR}/LedDeviceTest.h
${CURRENT_SOURCE_DIR}/LedDeviceSedu.h
${CURRENT_SOURCE_DIR}/LedDeviceWs2812b.h
${CURRENT_SOURCE_DIR}/LedDeviceWs2811.h
${CURRENT_SOURCE_DIR}/LedDeviceLightpack.h
${CURRENT_SOURCE_DIR}/LedDevicePaintpack.h
${CURRENT_SOURCE_DIR}/LedDeviceMultiLightpack.h
@ -37,6 +39,9 @@ SET(Leddevice_SOURCES
${CURRENT_SOURCE_DIR}/LedRs232Device.cpp
${CURRENT_SOURCE_DIR}/LedDeviceSedu.cpp
${CURRENT_SOURCE_DIR}/LedDeviceTest.cpp
${CURRENT_SOURCE_DIR}/LedDeviceWs2811.cpp
${CURRENT_SOURCE_DIR}/LedDeviceWs2812b.cpp
${CURRENT_SOURCE_DIR}/LedDeviceAdalight.cpp
${CURRENT_SOURCE_DIR}/LedDeviceLightpack.cpp
${CURRENT_SOURCE_DIR}/LedDevicePaintpack.cpp
${CURRENT_SOURCE_DIR}/LedDeviceMultiLightpack.cpp

View File

@ -7,11 +7,12 @@
#include "LedDeviceLpd6803.h"
#include "LedDeviceLpd8806.h"
#include "LedDeviceWs2801.h"
#include "LedDeviceWs2811.h"
#endif
#include "LedDeviceSedu.h"
#include "LedDeviceTest.h"
#include "LedDeviceWs2811.h"
#include "LedDeviceWs2812b.h"
#include "LedDeviceAdalight.h"
#include "LedDevicePaintpack.h"
#include "LedDeviceLightpack.h"
@ -37,23 +38,6 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
device = deviceWs2801;
}
// else if (type == "ws2811")
// {
// const std::string output = deviceConfig["output"].asString();
// const std::string outputSpeed = deviceConfig["output"].asString();
// const std::string timingOption = deviceConfig["timingOption"].asString();
// ws2811::SpeedMode speedMode = (outputSpeed == "high")? ws2811::highspeed : ws2811::lowspeed;
// if (outputSpeed != "high" && outputSpeed != "low")
// {
// std::cerr << "Incorrect speed-mode selected for WS2811: " << outputSpeed << " != {'high', 'low'}" << std::endl;
// }
// LedDeviceWs2811 * deviceWs2811 = new LedDeviceWs2811(output, ws2811::fromString(timingOption, ws2811::option_2855), speedMode);
// deviceWs2811->open();
// device = deviceWs2811;
// }
else if (type == "lpd6803" || type == "ldp6803")
{
const std::string output = deviceConfig["output"].asString();
@ -75,6 +59,30 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
device = deviceLpd8806;
}
#endif
// else if (type == "ws2811")
// {
// const std::string output = deviceConfig["output"].asString();
// const std::string outputSpeed = deviceConfig["output"].asString();
// const std::string timingOption = deviceConfig["timingOption"].asString();
// ws2811::SpeedMode speedMode = (outputSpeed == "high")? ws2811::highspeed : ws2811::lowspeed;
// if (outputSpeed != "high" && outputSpeed != "low")
// {
// std::cerr << "Incorrect speed-mode selected for WS2811: " << outputSpeed << " != {'high', 'low'}" << std::endl;
// }
// LedDeviceWs2811 * deviceWs2811 = new LedDeviceWs2811(output, ws2811::fromString(timingOption, ws2811::option_2855), speedMode);
// deviceWs2811->open();
// device = deviceWs2811;
// }
else if (type == "ws2812b")
{
LedDeviceWs2812b * deviceWs2812b = new LedDeviceWs2812b();
deviceWs2812b->open();
device = deviceWs2812b;
}
else if (type == "adalight")
{
const std::string output = deviceConfig["output"].asString();

View File

@ -0,0 +1,114 @@
// Linux includes
#include <unistd.h>
// Local Hyperion-Leddevice includes
#include "LedDeviceWs2812b.h"
LedDeviceWs2812b::LedDeviceWs2812b() :
LedRs232Device("/dev/ttyAMA0", 4000000)
{
fillTable();
}
int LedDeviceWs2812b::write(const std::vector<ColorRgb> & ledValues)
{
// Ensure the size of the led-buffer
if (_ledBuffer.size() != ledValues.size()*3)
{
_ledBuffer.resize(ledValues.size()*3);
}
// Translate the channel of each color to a signal
for (unsigned iLed=0; iLed<ledValues.size(); ++iLed)
{
const ColorRgb & color = ledValues[iLed];
_ledBuffer[3*iLed] = _byte2signalTable[color.red];
_ledBuffer[3*iLed + 1] = _byte2signalTable[color.green];
_ledBuffer[3*iLed + 2] = _byte2signalTable[color.blue];
}
const int result = writeBytes(_ledBuffer.size()*sizeof(ByteSignal), reinterpret_cast<uint8_t *>(_ledBuffer.data()));
// Official latch time is 50us (lets give it 50us more)
usleep(100);
return result;
}
int LedDeviceWs2812b::switchOff()
{
// Set all bytes in the signal buffer to zero
for (ByteSignal & signal : _ledBuffer)
{
signal = _byte2signalTable[0];
}
return writeBytes(_ledBuffer.size()*sizeof(ByteSignal), reinterpret_cast<uint8_t *>(_ledBuffer.data()));
}
void LedDeviceWs2812b::fillTable()
{
_byte2signalTable.clear();
for (int byte=0; byte<256; ++byte)
{
const ByteSignal signal = byte2Signal(uint8_t(byte));
_byte2signalTable.push_back(signal);
}
}
LedDeviceWs2812b::ByteSignal LedDeviceWs2812b::byte2Signal(const uint8_t byte) const
{
ByteSignal result;
result.bit_12 = bits2Signal(byte & 0x80, byte & 0x40);
result.bit_34 = bits2Signal(byte & 0x20, byte & 0x10);
result.bit_56 = bits2Signal(byte & 0x08, byte & 0x04);
result.bit_78 = bits2Signal(byte & 0x02, byte & 0x01);
return result;
}
uint8_t LedDeviceWs2812b::bits2Signal(const bool bit1, const bool bit2) const
{
// See https://github.com/tvdzwan/hyperion/wiki/Ws2812b for the explanation of the given
// translations
// Encoding scheme 1
// 00 1 1000 1100 0 1 0111 0011 0 1 1100 1110 0 0xCE
// 01 1 1000 1110 0 1 0111 0001 0 1 1000 1110 0 0x8E
// 10 1 1100 1100 0 1 0011 0011 0 1 1100 1100 0 0xCC
// 11 1 1100 1110 0 1 0011 0001 0 1 1000 1100 0 0x8C
// Encoding schem 2
// 00 - 1 0000 1000 0 - 1 1111 0111 0 - 1 1110 1111 0 - 0xEF
// 01 - 1 0000 1111 0 - 1 1111 0000 0 - 1 0000 1111 0 - 0x0F
// 10 - 1 1110 1000 0 - 1 0001 0111 0 - 1 1110 1000 0 - 0xE8
// 11 - 1 1110 1111 0 - 1 0001 0000 0 - 1 0000 1000 0 - 0x08
if (bit1)
{
if (bit2)
{
// return 0x08;
return 0x8C;
}
else
{
// return 0xE8;
return 0xCC;
}
}
else
{
if (bit2)
{
// return 0x0F;
return 0x8E;
}
else
{
// return 0xEF;
return 0xCE;
}
}
return 0x00;
}

View File

@ -0,0 +1,76 @@
#pragma once
// Hyperion leddevice includes
#include "LedRs232Device.h"
///
/// The LedDevice for controlling a string of WS2812B leds. These are controlled over the mini-UART
/// of the RPi (/dev/ttyAMA0).
///
class LedDeviceWs2812b : public LedRs232Device
{
public:
///
/// Constructs the device (all required parameters are hardcoded)
///
LedDeviceWs2812b();
///
/// Write the color data the the WS2812B led string
///
/// @param ledValues The color data
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> & ledValues);
///
/// Write zero to all leds(that have been written by a previous write operation)
///
/// @return Zero on succes else negative
///
virtual int switchOff();
private:
///
/// Structure holding the four output-bytes corresponding to a single input byte
///
struct ByteSignal
{
uint8_t bit_12;
uint8_t bit_34;
uint8_t bit_56;
uint8_t bit_78;
};
/// Translation table from single input-byte to output-bytes
std::vector<ByteSignal> _byte2signalTable;
///
/// Fills the translation table (_byte2signalTable)
///
void fillTable();
///
/// Computes the output bytes that belong to a given input-byte (no table lookup)
///
/// @param byte The input byte
/// @return The four bytes (ByteSignal) for the output signal
///
ByteSignal byte2Signal(const uint8_t byte) const;
///
/// Translates two bits to a single byte
///
/// @param bit1 The value of the first bit (1=true, zero=false)
/// @param bit1 The value of the ssecond bit (1=true, zero=false)
///
/// @return The output-byte for the given two bit
///
uint8_t bits2Signal(const bool bit1, const bool bit2) const;
///
/// The output buffer for writing bytes to the output
///
std::vector<ByteSignal> _ledBuffer;
};

View File

@ -57,7 +57,9 @@ int LedRs232Device::writeBytes(const unsigned size, const uint8_t * data)
try
{
_rs232Port.flushOutput();
_rs232Port.write(data, size);
_rs232Port.flush();
}
catch (const serial::SerialException & serialExc)
{
@ -77,6 +79,7 @@ int LedRs232Device::writeBytes(const unsigned size, const uint8_t * data)
{
_rs232Port.open();
_rs232Port.write(data, size);
_rs232Port.flush();
}
catch (const std::exception & e)
{

View File

@ -1,52 +1,50 @@
// Qt includes
#include <QUrl>
#include <QRegExp>
#include <QStringRef>
#include <xbmcvideochecker/XBMCVideoChecker.h>
XBMCVideoChecker::XBMCVideoChecker(const std::string & address, uint16_t port, uint64_t interval_ms, bool grabVideo, bool grabPhoto, bool grabAudio, bool grabMenu) :
// Request player example:
// {"id":666,"jsonrpc":"2.0","method":"Player.GetActivePlayers"}
// {"id":666,"jsonrpc":"2.0","result":[{"playerid":1,"type":"video"}]}
// Request playing item example:
// {"id":667,"jsonrpc":"2.0","method":"Player.GetItem","params":{"playerid":1,"properties":["file"]}}
// {"id":667,"jsonrpc":"2.0","result":{"item":{"file":"smb://xbmc:xbmc@192.168.53.12/video/Movies/Avatar (2009)/Avatar.mkv","label":"Avatar","type":"unknown"}}}
// Request if screensaver is on
// {"id":668,"jsonrpc":"2.0","method":"XBMC.GetInfoBooleans","params":{"booleans":["System.ScreenSaverActive"]}}
// {"id":668,"jsonrpc":"2.0","result":{"System.ScreenSaverActive":false}}
XBMCVideoChecker::XBMCVideoChecker(const std::string & address, uint16_t port, bool grabVideo, bool grabPhoto, bool grabAudio, bool grabMenu, bool grabScreensaver, bool enable3DDetection) :
QObject(),
_address(QString::fromStdString(address)),
_port(port),
_request(R"({"jsonrpc":"2.0","method":"Player.GetActivePlayers","id":666})"),
_timer(),
_activePlayerRequest(R"({"id":666,"jsonrpc":"2.0","method":"Player.GetActivePlayers"})"),
_currentPlayingItemRequest(R"({"id":667,"jsonrpc":"2.0","method":"Player.GetItem","params":{"playerid":%1,"properties":["file"]}})"),
_checkScreensaverRequest(R"({"id":668,"jsonrpc":"2.0","method":"XBMC.GetInfoBooleans","params":{"booleans":["System.ScreenSaverActive"]}})"),
_socket(),
_grabVideo(grabVideo),
_grabPhoto(grabPhoto),
_grabAudio(grabAudio),
_grabMenu(grabMenu),
_previousMode(GRABBINGMODE_INVALID)
_grabScreensaver(grabScreensaver),
_enable3DDetection(enable3DDetection),
_previousScreensaverMode(false),
_previousGrabbingMode(GRABBINGMODE_INVALID),
_previousVideoMode(VIDEO_2D)
{
// setup timer
_timer.setSingleShot(false);
_timer.setInterval(interval_ms);
connect(&_timer, SIGNAL(timeout()), this, SLOT(sendRequest()));
// setup socket
connect(&_socket, SIGNAL(readyRead()), this, SLOT(receiveReply()));
connect(&_socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(&_socket, SIGNAL(connected()), this, SLOT(connected()));
connect(&_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectionError(QAbstractSocket::SocketError)));
}
void XBMCVideoChecker::start()
{
_timer.start();
}
void XBMCVideoChecker::sendRequest()
{
switch (_socket.state())
{
case QTcpSocket::UnconnectedState:
// not connected. try to connect
std::cout << "Connecting to " << _address.toStdString() << ":" << _port << " to check XBMC player status" << std::endl;
_socket.connectToHost(_address, _port);
break;
case QTcpSocket::ConnectedState:
// write the request on the socket
_socket.write(_request);
break;
default:
// whatever. let's check again at the next timer tick
break;
}
reconnect();
}
void XBMCVideoChecker::receiveReply()
@ -54,62 +52,220 @@ 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());
// check if the resply is a reply to one of my requests
if (!reply.contains("\"id\":666"))
std::cout << "Message from XBMC: " << reply.toStdString() << std::endl;
if (reply.contains("\"method\":\"Player.OnPlay\""))
{
// probably not. Leave this mreply as is and don't act on it
// send a request for the current player state
_socket.write(_activePlayerRequest.toUtf8());
return;
}
else if (reply.contains("\"method\":\"Player.OnStop\""))
{
// the player has stopped
setGrabbingMode(_grabMenu ? GRABBINGMODE_MENU : GRABBINGMODE_OFF);
setVideoMode(VIDEO_2D);
}
else if (reply.contains("\"method\":\"GUI.OnScreensaverActivated\""))
{
setScreensaverMode(!_grabScreensaver);
}
else if (reply.contains("\"method\":\"GUI.OnScreensaverDeactivated\""))
{
setScreensaverMode(false);
}
else if (reply.contains("\"id\":666"))
{
// Result of Player.GetActivePlayers
GrabbingMode newMode = GRABBINGMODE_INVALID;
if (reply.contains("video"))
{
// video is playing
newMode = _grabVideo ? GRABBINGMODE_VIDEO : GRABBINGMODE_OFF;
}
else if (reply.contains("picture"))
{
// picture viewer is playing
newMode = _grabPhoto ? GRABBINGMODE_PHOTO : GRABBINGMODE_OFF;
}
else if (reply.contains("audio"))
{
// audio is playing
newMode = _grabAudio ? GRABBINGMODE_AUDIO : GRABBINGMODE_OFF;
}
else
{
// Nothing is playing.
newMode = _grabMenu ? GRABBINGMODE_MENU : GRABBINGMODE_OFF;
}
// always start a new video in 2D mode
emit videoMode(VIDEO_2D);
// emit new state if applicable
if (newMode != _previousMode && newMode != GRABBINGMODE_INVALID)
{
switch (newMode)
if (reply.contains("video"))
{
case GRABBINGMODE_VIDEO:
std::cout << "XBMC checker: switching to VIDEO mode" << std::endl;
break;
case GRABBINGMODE_PHOTO:
std::cout << "XBMC checker: switching to PHOTO mode" << std::endl;
break;
case GRABBINGMODE_AUDIO:
std::cout << "XBMC checker: switching to AUDIO mode" << std::endl;
break;
case GRABBINGMODE_MENU:
std::cout << "XBMC checker: switching to MENU mode" << std::endl;
break;
case GRABBINGMODE_OFF:
std::cout << "XBMC checker: switching to OFF mode" << std::endl;
break;
case GRABBINGMODE_INVALID:
std::cout << "XBMC checker: switching to INVALID mode" << std::endl;
break;
}
// video is playing
setGrabbingMode(_grabVideo ? GRABBINGMODE_VIDEO : GRABBINGMODE_OFF);
emit grabbingMode(newMode);
_previousMode = newMode;
// we need to get the filename
// first retrieve the playerid
QString key = "\"playerid\":";
QRegExp regex(key + "(\\d+)");
int pos = regex.indexIn(reply);
if (pos > 0)
{
// now request info of the playing item
QStringRef idText(&reply, pos + key.length(), regex.matchedLength() - key.length());
_socket.write(_currentPlayingItemRequest.arg(idText.toString()).toUtf8());
}
}
else if (reply.contains("picture"))
{
// picture viewer is playing
setGrabbingMode(_grabPhoto ? GRABBINGMODE_PHOTO : GRABBINGMODE_OFF);
}
else if (reply.contains("audio"))
{
// audio is playing
setGrabbingMode(_grabAudio ? GRABBINGMODE_AUDIO : GRABBINGMODE_OFF);
}
else
{
// Nothing is playing.
setGrabbingMode(_grabMenu ? GRABBINGMODE_MENU : GRABBINGMODE_OFF);
}
}
else if (reply.contains("\"id\":667"))
{
// result of Player.GetItem
// TODO: what if the filename contains a '"'. In Json this should have been escaped
QRegExp regex("\"file\":\"((?!\").)*\"");
int pos = regex.indexIn(reply);
if (pos > 0)
{
QStringRef filename = QStringRef(&reply, pos+8, regex.matchedLength()-9);
if (filename.contains("3DSBS", Qt::CaseInsensitive) || filename.contains("HSBS", Qt::CaseInsensitive))
{
setVideoMode(VIDEO_3DSBS);
}
else if (filename.contains("3DTAB", Qt::CaseInsensitive) || filename.contains("HTAB", Qt::CaseInsensitive))
{
setVideoMode(VIDEO_3DTAB);
}
else
{
setVideoMode(VIDEO_2D);
}
}
}
else if (reply.contains("\"id\":668"))
{
// result of System.ScreenSaverActive
bool active = reply.contains("\"System.ScreenSaverActive\":true");
setScreensaverMode(!_grabScreensaver && active);
}
}
void XBMCVideoChecker::connected()
{
std::cout << "XBMC Connected" << std::endl;
// send a request for the current player state
_socket.write(_activePlayerRequest.toUtf8());
_socket.write(_checkScreensaverRequest.toUtf8());
}
void XBMCVideoChecker::disconnected()
{
std::cout << "XBMC Disconnected" << std::endl;
reconnect();
}
void XBMCVideoChecker::reconnect()
{
if (_socket.state() == QTcpSocket::ConnectedState)
{
return;
}
// try to connect
switch (_socket.state())
{
case QTcpSocket::ConnectingState:
// Somehow when XBMC restarts we get stuck in connecting state
// If we get here we tried to connect already for 5 seconds. abort and try again in 1 second.
_socket.reset();
_socket.waitForDisconnected(50);
QTimer::singleShot(1000, this, SLOT(reconnect()));
break;
case QTcpSocket::UnconnectedState:
_socket.connectToHost(_address, _port);
QTimer::singleShot(10000, this, SLOT(reconnect()));
break;
default:
QTimer::singleShot(10000, this, SLOT(reconnect()));
break;
}
}
void XBMCVideoChecker::connectionError(QAbstractSocket::SocketError error)
{
std::cout << "XBMC Connection error (" << error << ")" << std::endl;
// close the socket
_socket.close();
}
void XBMCVideoChecker::setGrabbingMode(GrabbingMode newGrabbingMode)
{
if (newGrabbingMode == _previousGrabbingMode)
{
// no change
return;
}
switch (newGrabbingMode)
{
case GRABBINGMODE_VIDEO:
std::cout << "XBMC checker: switching to VIDEO mode" << std::endl;
break;
case GRABBINGMODE_PHOTO:
std::cout << "XBMC checker: switching to PHOTO mode" << std::endl;
break;
case GRABBINGMODE_AUDIO:
std::cout << "XBMC checker: switching to AUDIO mode" << std::endl;
break;
case GRABBINGMODE_MENU:
std::cout << "XBMC checker: switching to MENU mode" << std::endl;
break;
case GRABBINGMODE_OFF:
std::cout << "XBMC checker: switching to OFF mode" << std::endl;
break;
case GRABBINGMODE_INVALID:
std::cout << "XBMC checker: switching to INVALID mode" << std::endl;
break;
}
// only emit the new state when we want to grab in screensaver mode or when the screensaver is deactivated
if (!_previousScreensaverMode)
{
emit grabbingMode(newGrabbingMode);
}
_previousGrabbingMode = newGrabbingMode;
}
void XBMCVideoChecker::setScreensaverMode(bool isOnScreensaver)
{
if (isOnScreensaver == _previousScreensaverMode)
{
// no change
return;
}
emit grabbingMode(isOnScreensaver ? GRABBINGMODE_OFF : _previousGrabbingMode);
_previousScreensaverMode = isOnScreensaver;
}
void XBMCVideoChecker::setVideoMode(VideoMode newVideoMode)
{
if (newVideoMode == _previousVideoMode)
{
// no change
return;
}
switch (newVideoMode)
{
case VIDEO_2D:
std::cout << "XBMC checker: switching to 2D mode" << std::endl;
break;
case VIDEO_3DSBS:
std::cout << "XBMC checker: switching to 3D SBS mode" << std::endl;
break;
case VIDEO_3DTAB:
std::cout << "XBMC checker: switching to 3D TAB mode" << std::endl;
break;
}
emit videoMode(newVideoMode);
_previousVideoMode = newVideoMode;
}

View File

@ -41,6 +41,10 @@ public class XbmcPanel extends JPanel {
private JComboBox<String> mPictureCombo;
private JLabel mAudioLabel;
private JComboBox<String> mAudioCombo;
private JLabel mScreensaverLabel;
private JComboBox<String> mScreensaverCombo;
private JLabel mEnable3DLabel;
private JComboBox<String> mEnable3DCombo;
public XbmcPanel(final MiscConfig pMiscConfig) {
super();
@ -130,6 +134,24 @@ public class XbmcPanel extends JPanel {
mAudioCombo.addActionListener(mActionListener);
add(mAudioCombo);
mScreensaverLabel = new JLabel("Screensaver");
add(mScreensaverLabel);
mScreensaverCombo = new JComboBox<>(new String[] {"On", "Off"});
mScreensaverCombo.setSelectedItem(mMiscConfig.mScreensaverOn? "On": "Off");
mScreensaverCombo.setToolTipText("Enables('On') or disables('Off') the ambi-light when the XBMC screensaver is active");
mScreensaverCombo.addActionListener(mActionListener);
add(mScreensaverCombo);
mEnable3DLabel = new JLabel("3D checking");
add(mEnable3DLabel);
mEnable3DCombo = new JComboBox<>(new String[] {"On", "Off"});
mEnable3DCombo.setSelectedItem(mMiscConfig.m3DCheckingEnabled ? "On": "Off");
mEnable3DCombo.setToolTipText("Enables('On') or disables('Off') switching to 3D mode when a 3D video file is started");
mEnable3DCombo.addActionListener(mActionListener);
add(mEnable3DCombo);
GroupLayout layout = new GroupLayout(this);
layout.setAutoCreateGaps(true);
setLayout(layout);
@ -143,6 +165,8 @@ public class XbmcPanel extends JPanel {
.addComponent(mVideoLabel)
.addComponent(mPictureLabel)
.addComponent(mAudioLabel)
.addComponent(mScreensaverLabel)
.addComponent(mEnable3DLabel)
)
.addGroup(layout.createParallelGroup()
.addComponent(mXbmcCheck)
@ -152,6 +176,8 @@ public class XbmcPanel extends JPanel {
.addComponent(mVideoCombo)
.addComponent(mPictureCombo)
.addComponent(mAudioCombo)
.addComponent(mScreensaverCombo)
.addComponent(mEnable3DCombo)
));
layout.setVerticalGroup(layout.createSequentialGroup()
.addComponent(mXbmcCheck)
@ -178,6 +204,14 @@ public class XbmcPanel extends JPanel {
.addGroup(layout.createParallelGroup()
.addComponent(mAudioLabel)
.addComponent(mAudioCombo)
)
.addGroup(layout.createParallelGroup()
.addComponent(mScreensaverLabel)
.addComponent(mScreensaverCombo)
)
.addGroup(layout.createParallelGroup()
.addComponent(mEnable3DLabel)
.addComponent(mEnable3DCombo)
));
toggleEnabled(mMiscConfig.mXbmcCheckerEnabled);
@ -198,6 +232,10 @@ public class XbmcPanel extends JPanel {
mPictureCombo.setEnabled(pEnabled);
mAudioLabel.setEnabled(pEnabled);
mAudioCombo.setEnabled(pEnabled);
mScreensaverLabel.setEnabled(pEnabled);
mScreensaverCombo.setEnabled(pEnabled);
mEnable3DLabel.setEnabled(pEnabled);
mEnable3DCombo.setEnabled(pEnabled);
}
private final ChangeListener mChangeListener = new ChangeListener() {
@ -216,6 +254,8 @@ public class XbmcPanel extends JPanel {
mMiscConfig.mVideoOn = (mVideoCombo.getSelectedItem() == "On");
mMiscConfig.mPictureOn = (mPictureCombo.getSelectedItem() == "On");
mMiscConfig.mAudioOn = (mAudioCombo.getSelectedItem() == "On");
mMiscConfig.mScreensaverOn = (mScreensaverCombo.getSelectedItem() == "On");
mMiscConfig.m3DCheckingEnabled = (mEnable3DCombo.getSelectedItem() == "On");
toggleEnabled(mMiscConfig.mXbmcCheckerEnabled);
}

View File

@ -40,6 +40,10 @@ public class MiscConfig {
public boolean mPictureOn = true;
/** Flag indicating that the frame-grabber is on during audio playback */
public boolean mAudioOn = true;
/** Flag indicating that the frame-grabber is on when xbmc is on screensaver */
public boolean mScreensaverOn = true;
/** Flag indicating that the frame-grabber is should take actions when a 3D file is playing */
public boolean m3DCheckingEnabled = true;
/** Flag indicating that the JSON interface is enabled */
public boolean mJsonInterfaceEnabled = true;
@ -103,12 +107,14 @@ public class MiscConfig {
String xbmcComment =
"The configuration of the XBMC connection used to enable and disable the frame-grabber. Contains the following fields: \n" +
" * xbmcAddress : The IP address of the XBMC-host\n" +
" * xbmcTcpPort : The TCP-port of the XBMC-server\n" +
" * grabVideo : Flag indicating that the frame-grabber is on(true) during video playback\n" +
" * grabPictures : Flag indicating that the frame-grabber is on(true) during picture show\n" +
" * grabAudio : Flag indicating that the frame-grabber is on(true) during audio playback\n" +
" * grabMenu : Flag indicating that the frame-grabber is on(true) in the XBMC menu\n";
" * xbmcAddress : The IP address of the XBMC-host\n" +
" * xbmcTcpPort : The TCP-port of the XBMC-server\n" +
" * grabVideo : Flag indicating that the frame-grabber is on(true) during video playback\n" +
" * grabPictures : Flag indicating that the frame-grabber is on(true) during picture show\n" +
" * grabAudio : Flag indicating that the frame-grabber is on(true) during audio playback\n" +
" * grabMenu : Flag indicating that the frame-grabber is on(true) in the XBMC menu\n" +
" * grabScreensaver : Flag indicating that the frame-grabber is on(true) when XBMC is on screensaver\n" +
" * enable3DDetection : Flag indicating that the frame-grabber should switch to a 3D compatible modus if a 3D video is playing\n";
strBuf.writeComment(xbmcComment);
strBuf.toggleComment(!mXbmcCheckerEnabled);
@ -118,7 +124,9 @@ public class MiscConfig {
strBuf.addValue("grabVideo", mVideoOn, false);
strBuf.addValue("grabPictures", mPictureOn, false);
strBuf.addValue("grabAudio", mAudioOn, false);
strBuf.addValue("grabMenu", mMenuOn, true);
strBuf.addValue("grabMenu", mMenuOn, false);
strBuf.addValue("grabScreensaver", mScreensaverOn, false);
strBuf.addValue("enable3DDetection", m3DCheckingEnabled, true);
strBuf.stopObject();
strBuf.toggleComment(false);

View File

@ -123,11 +123,12 @@ int main(int argc, char** argv)
xbmcVideoChecker = new XBMCVideoChecker(
videoCheckerConfig["xbmcAddress"].asString(),
videoCheckerConfig["xbmcTcpPort"].asUInt(),
1000,
videoCheckerConfig["grabVideo"].asBool(),
videoCheckerConfig["grabPictures"].asBool(),
videoCheckerConfig["grabAudio"].asBool(),
videoCheckerConfig["grabMenu"].asBool());
videoCheckerConfig["grabMenu"].asBool(),
videoCheckerConfig.get("grabScreensaver", true).asBool(),
videoCheckerConfig.get("enable3DDetection", true).asBool());
xbmcVideoChecker->start();
std::cout << "XBMC video checker created and started" << std::endl;
@ -148,6 +149,7 @@ int main(int argc, char** argv)
if (xbmcVideoChecker != nullptr)
{
QObject::connect(xbmcVideoChecker, SIGNAL(grabbingMode(GrabbingMode)), dispmanx, SLOT(setGrabbingMode(GrabbingMode)));
QObject::connect(xbmcVideoChecker, SIGNAL(videoMode(VideoMode)), dispmanx, SLOT(setVideoMode(VideoMode)));
}
dispmanx->start();

View File

@ -53,8 +53,16 @@ add_executable(test_qtscreenshot TestQtScreenshot.cpp)
target_link_libraries(test_qtscreenshot
${QT_LIBRARIES})
add_executable(determineWs2811Timing DetermineWs2811Timing.cpp)
add_executable(test_rs232highspeed
TestRs232HighSpeed.cpp
../libsrc/leddevice/LedRs232Device.cpp)
../libsrc/leddevice/LedRs232Device.cpp
../libsrc/leddevice/LedDeviceWs2812b.cpp)
target_link_libraries(test_rs232highspeed
serialport)
if(NOT APPLE AND UNIX)
include_directories(/usr/include)
add_executable(test_uartHighSpeed TestUartHighSpeed.cpp)
endif()

View File

@ -0,0 +1,62 @@
// STl includes
#include <iostream>
#include <cmath>
bool requiredTiming(const int tHigh_ns, const int tLow_ns, const int error_ns, const int nrBits)
{
std::cout << "=== " << nrBits << " bits case ===== " << std::endl;
double bitLength_ns = (tHigh_ns + tLow_ns)/double(nrBits);
double baudrate_Hz = 1.0 / bitLength_ns * 1e9;
std::cout << "Required bit length: " << bitLength_ns << "ns => baudrate = " << baudrate_Hz << std::endl;
double highBitsExact = tHigh_ns/bitLength_ns;
int highBits = std::round(highBitsExact);
double lowBitsExact = tLow_ns/bitLength_ns;
int lowBits = std::round(lowBitsExact);
std::cout << "Bit division: high=" << highBits << "(" << highBitsExact << "); low=" << lowBits << "(" << lowBitsExact << ")" << std::endl;
double highBitsError = std::fabs(highBitsExact - highBits);
double lowBitsError = std::fabs(highBitsExact - highBits);
double highError_ns = highBitsError * bitLength_ns;
double lowError_ns = lowBitsError * bitLength_ns;
if (highError_ns > error_ns || lowError_ns > error_ns)
{
std::cerr << "Timing error outside specs: " << highError_ns << "; " << lowError_ns << " > " << error_ns << std::endl;
}
else
{
std::cout << "Timing within margins: " << highError_ns << "; " << lowError_ns << " < " << error_ns << std::endl;
}
return true;
}
int main()
{
// 10bits
requiredTiming(400, 850, 150, 10); // Zero
requiredTiming(800, 450, 150, 10); // One
// 6bits
requiredTiming(400, 850, 150, 6); // Zero
requiredTiming(800, 450, 150, 6); // One
// 5bits
requiredTiming(400, 850, 150, 5); // Zero
requiredTiming(800, 450, 150, 5); // One
requiredTiming(650, 600, 150, 5); // One
// 4bits
requiredTiming(400, 850, 150, 4); // Zero
requiredTiming(800, 450, 150, 4); // One
// 3bits
requiredTiming(400, 850, 150, 3); // Zero
requiredTiming(800, 450, 150, 3); // One
return 0;
}

View File

@ -1,32 +1,260 @@
// Hyperion includes
// STL includes
#include <iostream>
#include <random>
// Serialport includes
#include <serial/serial.h>
int testSerialPortLib();
int testHyperionDevice(int argc, char** argv);
int testWs2812bDevice();
int main(int argc, char** argv)
{
// if (argc == 1)
// {
// return testSerialPortLib();
// }
// else
// {
// return testHyperionDevice(argc, argv);
// }
return testWs2812bDevice();
}
int testSerialPortLib()
{
serial::Serial rs232Port("/dev/ttyAMA0", 4000000);
std::default_random_engine generator;
std::uniform_int_distribution<int> distribution(1,2);
std::vector<uint8_t> data;
for (int i=0; i<9; ++i)
{
int coinFlip = distribution(generator);
if (coinFlip == 1)
{
data.push_back(0xCE);
data.push_back(0xCE);
data.push_back(0xCE);
data.push_back(0xCE);
}
else
{
data.push_back(0x8C);
data.push_back(0x8C);
data.push_back(0x8C);
data.push_back(0x8C);
}
}
std::cout << "Type 'c' to continue, 'q' or 'x' to quit: ";
while (true)
{
char c = getchar();
if (c == 'q' || c == 'x')
{
break;
}
if (c != 'c')
{
continue;
}
rs232Port.flushOutput();
rs232Port.write(data);
rs232Port.flush();
data.clear();
for (int i=0; i<9; ++i)
{
int coinFlip = distribution(generator);
if (coinFlip == 1)
{
data.push_back(0xCE);
data.push_back(0xCE);
data.push_back(0xCE);
data.push_back(0xCE);
}
else
{
data.push_back(0x8C);
data.push_back(0x8C);
data.push_back(0x8C);
data.push_back(0x8C);
}
}
}
try
{
rs232Port.close();
}
catch (const std::runtime_error& excp)
{
std::cout << "Caught exception: " << excp.what() << std::endl;
return -1;
}
return 0;
}
#include "../libsrc/leddevice/LedRs232Device.h"
class TestDevice : public LedRs232Device
{
public:
TestDevice() :
LedRs232Device("/dev/ttyAMA0", 2000000)
LedRs232Device("/dev/ttyAMA0", 4000000)
{
// empty
open();
}
int write(const std::vector<ColorRgb> &ledValues)
{
std::vector<uint8_t> bytes(ledValues.size() * 3 * 4);
uint8_t * bytePtr = bytes.data();
for (ColorRgb color : ledValues)
{
byte2Signal(color.green, bytePtr);
bytePtr += 4;
byte2Signal(color.red, bytePtr);
bytePtr += 4;
byte2Signal(color.blue, bytePtr);
bytePtr += 4;
}
writeBytes(bytes.size(), bytes.data());
return 0;
}
int write(const std::vector<ColorRgb> &ledValues) { return 0; }
int switchOff() { return 0; };
void writeTestSequence()
void writeTestSequence(const std::vector<uint8_t> & data)
{
uint8_t data = 'T';
writeBytes(data.size(), data.data());
}
writeBytes(1, &data);
void byte2Signal(const uint8_t byte, uint8_t * output)
{
output[0] = bits2Signal(byte & 0x80, byte & 0x40);
output[1] = bits2Signal(byte & 0x20, byte & 0x10);
output[2] = bits2Signal(byte & 0x08, byte & 0x04);
output[3] = bits2Signal(byte & 0x02, byte & 0x01);
}
uint8_t bits2Signal(const bool bit1, const bool bit2)
{
if (bit1)
{
if (bit2)
{
return 0x8C;
}
else
{
return 0xCC;
}
}
else
{
if (bit2)
{
return 0x8E;
}
else
{
return 0xCE;
}
}
return 0x00;
}
};
int main()
int testHyperionDevice(int argc, char** argv)
{
TestDevice device;
device.writeTestSequence();
TestDevice rs232Device;
if (argc > 1 && strncmp(argv[1], "off", 3) == 0)
{
rs232Device.write(std::vector<ColorRgb>(150, {0, 0, 0}));
return 0;
}
int loopCnt = 0;
std::cout << "Type 'c' to continue, 'q' or 'x' to quit: ";
while (true)
{
char c = getchar();
if (c == 'q' || c == 'x')
{
break;
}
if (c != 'c')
{
continue;
}
rs232Device.write(std::vector<ColorRgb>(loopCnt, {255, 255, 255}));
++loopCnt;
}
rs232Device.write(std::vector<ColorRgb>(150, {0, 0, 0}));
return 0;
}
#include "../libsrc/leddevice/LedDeviceWs2812b.h"
#include <unistd.h>
int testWs2812bDevice()
{
LedDeviceWs2812b device;
device.open();
std::cout << "Type 'c' to continue, 'q' or 'x' to quit: ";
int loopCnt = 0;
while (true)
{
// char c = getchar();
// if (c == 'q' || c == 'x')
// {
// break;
// }
// if (c != 'c')
// {
// continue;
// }
if (loopCnt%4 == 0)
device.write(std::vector<ColorRgb>(25, {255, 0, 0}));
else if (loopCnt%4 == 1)
device.write(std::vector<ColorRgb>(25, {0, 255, 0}));
else if (loopCnt%4 == 2)
device.write(std::vector<ColorRgb>(25, {0, 0, 255}));
else if (loopCnt%4 == 3)
device.write(std::vector<ColorRgb>(25, {17, 188, 66}));
++loopCnt;
usleep(200000);
if (loopCnt > 200)
{
break;
}
}
device.write(std::vector<ColorRgb>(150, {0, 0, 0}));
device.switchOff();
return 0;
}

248
test/TestUartHighSpeed.cpp Normal file
View File

@ -0,0 +1,248 @@
#include <random>
#include <iostream>
#include <stdio.h>
#include <unistd.h> //Used for UART
#include <fcntl.h> //Used for UART
#include <termios.h> //Used for UART
#include <sys/ioctl.h>
#include <linux/serial.h>
#include <csignal>
#include <cstdint>
#include <bitset>
#include <vector>
#include <pthread.h>
#include <sched.h>
void set_realtime_priority() {
int ret;
// We'll operate on the currently running thread.
pthread_t this_thread = pthread_self();
// struct sched_param is used to store the scheduling priority
struct sched_param params;
// We'll set the priority to the maximum.
params.sched_priority = sched_get_priority_max(SCHED_FIFO);
std::cout << "Trying to set thread realtime prio = " << params.sched_priority << std::endl;
// Attempt to set thread real-time priority to the SCHED_FIFO policy
ret = pthread_setschedparam(this_thread, SCHED_FIFO, &params);
if (ret != 0) {
// Print the error
std::cout << "Unsuccessful in setting thread realtime prio (erno=" << ret << ")" << std::endl;
return;
}
// Now verify the change in thread priority
int policy = 0;
ret = pthread_getschedparam(this_thread, &policy, &params);
if (ret != 0) {
std::cout << "Couldn't retrieve real-time scheduling paramers" << std::endl;
return;
}
// Check the correct policy was applied
if(policy != SCHED_FIFO) {
std::cout << "Scheduling is NOT SCHED_FIFO!" << std::endl;
} else {
std::cout << "SCHED_FIFO OK" << std::endl;
}
// Print thread scheduling priority
std::cout << "Thread priority is " << params.sched_priority << std::endl;
}
struct ColorSignal
{
uint8_t green_1;
uint8_t green_2;
uint8_t green_3;
uint8_t green_4;
uint8_t red_1;
uint8_t red_2;
uint8_t red_3;
uint8_t red_4;
uint8_t blue_1;
uint8_t blue_2;
uint8_t blue_3;
uint8_t blue_4;
};
static ColorSignal RED_Signal = { 0xCE, 0xCE, 0xCE, 0xCE,
0xCE, 0x8C, 0x8C, 0x8C,
0xCE, 0xCE, 0xCE, 0xCE };
static ColorSignal GREEN_Signal = { 0xCE, 0x8C, 0x8C, 0x8C,
0xCE, 0xCE, 0xCE, 0xCE,
0xCE, 0xCE, 0xCE, 0xCE };
static ColorSignal BLUE_Signal = { 0xCE, 0xCE, 0xCE, 0xCE,
0xCE, 0xCE, 0xCE, 0xCE,
0xCE, 0x8C, 0x8C, 0x8C};
static ColorSignal BLACK_Signal = { 0xCE, 0xCE, 0xCE, 0xCE,
0xCE, 0xCE, 0xCE, 0xCE,
0xCE, 0xCE, 0xCE, 0xCE};
static volatile bool _running;
void signal_handler(int signum)
{
_running = false;
}
int main()
{
_running = true;
signal(SIGTERM, &signal_handler);
//-------------------------
//----- SETUP USART 0 -----
//-------------------------
//At bootup, pins 8 and 10 are already set to UART0_TXD, UART0_RXD (ie the alt0 function) respectively
int uart0_filestream = -1;
//OPEN THE UART
//The flags (defined in fcntl.h):
// Access modes (use 1 of these):
// O_RDONLY - Open for reading only.
// O_RDWR - Open for reading and writing.
// O_WRONLY - Open for writing only.
//
// O_NDELAY / O_NONBLOCK (same function) - Enables nonblocking mode. When set read requests on the file can return immediately with a failure status
// if there is no input immediately available (instead of blocking). Likewise, write requests can also return
// immediately with a failure status if the output can't be written immediately.
//
// O_NOCTTY - When set and path identifies a terminal device, open() shall not cause the terminal device to become the controlling terminal for the process.
uart0_filestream = open("/dev/ttyAMA0", O_WRONLY | O_NOCTTY | O_NDELAY); //Open in non blocking read/write mode
if (uart0_filestream == -1)
{
//ERROR - CAN'T OPEN SERIAL PORT
printf("Error - Unable to open UART. Ensure it is not in use by another application\n");
}
// if (0)
{
//CONFIGURE THE UART
//The flags (defined in /usr/include/termios.h - see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html):
// Baud rate:- B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000
// CSIZE:- CS5, CS6, CS7, CS8
// CLOCAL - Ignore modem status lines
// CREAD - Enable receiver
// IGNPAR = Ignore characters with parity errors
// ICRNL - Map CR to NL on input (Use for ASCII comms where you want to auto correct end of line characters - don't use for bianry comms!)
// PARENB - Parity enable
// PARODD - Odd parity (else even)
struct termios options;
tcgetattr(uart0_filestream, &options);
options.c_cflag = B4000000 | CS8 | CLOCAL; //<Set baud rate
options.c_iflag = IGNPAR;
options.c_oflag = 0;
options.c_lflag = 0;
cfmakeraw(&options);
std::cout << "options.c_cflag = " << options.c_cflag << std::endl;
std::cout << "options.c_iflag = " << options.c_iflag << std::endl;
std::cout << "options.c_oflag = " << options.c_oflag << std::endl;
std::cout << "options.c_lflag = " << options.c_lflag << std::endl;
tcflush(uart0_filestream, TCIFLUSH);
tcsetattr(uart0_filestream, TCSANOW, &options);
// Let's verify configured options
tcgetattr(uart0_filestream, &options);
std::cout << "options.c_cflag = " << options.c_cflag << std::endl;
std::cout << "options.c_iflag = " << options.c_iflag << std::endl;
std::cout << "options.c_oflag = " << options.c_oflag << std::endl;
std::cout << "options.c_lflag = " << options.c_lflag << std::endl;
}
{
struct serial_struct ser;
if (-1 == ioctl(uart0_filestream, TIOCGSERIAL, &ser))
{
std::cerr << "Failed to obtian 'serial_struct' for setting custom baudrate" << std::endl;
}
std::cout << "Current divisor: " << ser.custom_divisor << " ( = " << ser.baud_base << " / 4000000" << std::endl;
// set custom divisor
ser.custom_divisor = ser.baud_base / 8000000;
// update flags
ser.flags &= ~ASYNC_SPD_MASK;
ser.flags |= ASYNC_SPD_CUST;
std::cout << "Current divisor: " << ser.custom_divisor << " ( = " << ser.baud_base << " / 8000000" << std::endl;
if (-1 == ioctl(uart0_filestream, TIOCSSERIAL, &ser))
{
std::cerr << "Failed to configure 'serial_struct' for setting custom baudrate" << std::endl;
}
// Check result
if (-1 == ioctl(uart0_filestream, TIOCGSERIAL, &ser))
{
std::cerr << "Failed to obtian 'serial_struct' for setting custom baudrate" << std::endl;
}
std::cout << "Current divisor: " << ser.custom_divisor << " ( = " << ser.baud_base << " / 4000000" << std::endl;
}
if (uart0_filestream < 0)
{
std::cerr << "Opening the device has failed" << std::endl;
return -1;
}
//----- TX BYTES -----
std::vector<ColorSignal> signalData(10, RED_Signal);
int loopCnt = 0;
std::cout << "Type 'c' to continue, 'q' or 'x' to quit: ";
while (_running)
{
char c = getchar();
if (c == 'q' || c == 'x')
{
break;
}
if (c != 'c')
{
continue;
}
set_realtime_priority();
for (int iRun=0; iRun<10; ++iRun)
{
// tcflush(uart0_filestream, TCOFLUSH);
write(uart0_filestream, signalData.data(), signalData.size()*sizeof(ColorSignal));
tcdrain(uart0_filestream);
usleep(100000);
++loopCnt;
if (loopCnt%3 == 2)
signalData = std::vector<ColorSignal>(10, GREEN_Signal);
else if(loopCnt%3 == 1)
signalData = std::vector<ColorSignal>(10, BLUE_Signal);
else if(loopCnt%3 == 0)
signalData = std::vector<ColorSignal>(10, RED_Signal);
}
}
signalData = std::vector<ColorSignal>(50, BLACK_Signal);
write(uart0_filestream, signalData.data(), signalData.size()*sizeof(ColorSignal));
//----- CLOSE THE UART -----
close(uart0_filestream);
std::cout << "Program finished" << std::endl;
return 0;
}