mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Disentangle LedDevice/LinearColorSmoothing, Bug Fixes & Test support (#654)
* Handle Exceptions in main & Pythoninit * Have SSDPDiscover generic again * Have SSDPDiscover generic again * Change Info- to Debug logs as technical service messages * Nanoleaf - When switched on, ensure UDP mode * Include SQL Database in Cross-Compile instructions * Fix Clazy (QT code checker) and clang Warnings * Stop LedDevice:write for disabled device * Nanoleaf: Fix uint printfs * NanoLeaf: Fix indents to tabs * NanoLeaf - Add debug verbosity switches * Device switchability support, FileDevice with timestamp support * Nanoleaf Light Panels now support External Control V2 * Enhance LedDeviceFile by Timestamp + fix readyness * Stop color stream, if LedDevice disabled * Nanoleaf - remove switchability * Fix MultiColorAdjustment, if led-range is greater lednum * Fix logging * LedFileDevice/LedDevice - add testing support * New "Led Test" effect * LedDeviceFile - Add chrono include + Allow Led rewrites for testing * Stabilize Effects for LedDevices where latchtime = 0 * Update LedDeviceFile, allow latchtime = 0 * Distangle LinearColorSmoothing and LEDDevice, Fix Effect configuration updates * Updates LedDeviceFile - Initialize via Open * Updates LedDeviceNanoleaf - Initialize via Open, Remove throwing exceptions * Updates ProviderUDP - Remove throwing exceptions * Framebuffer - Use precise timer * TestSpi - Align to LedDevice updates * Pretty Print CrossCompileHowTo as markdown-file * Ensure that output is only written when LedDevice is ready * Align APA102 Device to new device staging * Logger - Remove clang warnings on extra semicolon * Devices SPI - Align to Device stages and methods * Fix cppcheck and clang findings * Add Code-Template for new Devices * Align devices to stages and methods, clean-up some code * Allow to reopen LedDevice without restart * Revert change "Remove Connect (PriorityMuxer::visiblePriorityChanged -> Hyperion::update) due to double writes" * Remove visiblePriorityChanged from LedDevice to decouple LedDevice from hyperion logic * Expose LedDevice getLedCount and align signedness
This commit is contained in:
parent
1aba51e85c
commit
ed5455458b
@ -1,77 +1,92 @@
|
||||
#!/bin/bash
|
||||
#Use a clean Raspbian Stretch Lite and Ubuntu 18/19 and run this script
|
||||
##############
|
||||
#ON TARGET
|
||||
#--------------
|
||||
#sudo apt-get install qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libqt5sql5-sqlite aptitude show qt5-default rsync
|
||||
#############
|
||||
#ON HOST
|
||||
#---------
|
||||
# Cross-Compile Hyperion-NG
|
||||
Leverage the power of a host environment (here Ubuntu) compiling for a target platform (here Raspberry Pi).
|
||||
Use a clean Raspbian Stretch Lite (on target) and Ubuntu 18/19 (on host) to execute the steps outlined below.
|
||||
## On the Target system (here Raspberry Pi)
|
||||
Install required additional packages.
|
||||
```
|
||||
sudo apt-get install qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libqt5sql5-sqlite aptitude show qt5-default rsync
|
||||
```
|
||||
## On the Host system (here Ubuntu)
|
||||
Update the Ubuntu environment to the latest stage and install required additional packages.
|
||||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade
|
||||
# !!! TO-DO verify aptitude gcc-multilib
|
||||
|
||||
sudo apt-get -qq -y install git rsync cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libqt5sql5-sqlite
|
||||
#---------
|
||||
|
||||
```
|
||||
|
||||
Refine the target IP or hostname, plus userID as required and set-up cross-compilation environment:
|
||||
```
|
||||
export TARGET_IP=x.x.x.x
|
||||
export TARGET_USER=pi
|
||||
|
||||
```
|
||||
```
|
||||
export CROSSROOT="$HOME/crosscompile"
|
||||
export RASCROSS_DIR="$CROSSROOT/raspberrypi"
|
||||
export ROOTFS_DIR="$RASCROSS_DIR/rootfs"
|
||||
export TOOLCHAIN_DIR="$RASCROSS_DIR/tools"
|
||||
export QT5_DIR="$CROSSROOT/Qt5"
|
||||
|
||||
export HYPERION_DIR="$HOME/hyperion.ng"
|
||||
|
||||
```
|
||||
Get native files from target platform into the host-environment:
|
||||
```
|
||||
mkdir -p "$ROOTFS_DIR/lib"
|
||||
mkdir -p "$ROOTFS_DIR/usr"
|
||||
rsync -rl --delete-after --copy-unsafe-links $TARGET_USER@$TARGET_IP:/lib "$ROOTFS_DIR"
|
||||
rsync -rl --delete-after --copy-unsafe-links $TARGET_USER@$TARGET_IP:/usr/include "$ROOTFS_DIR/usr"
|
||||
rsync -rl --delete-after --copy-unsafe-links $TARGET_USER@$TARGET_IP:/usr/lib "$ROOTFS_DIR/usr"
|
||||
```
|
||||
|
||||
######## RPi specific #########
|
||||
|
||||
### Raspberry Pi specific steps
|
||||
Get Raspberry Pi firmware:
|
||||
```
|
||||
mkdir -p "$RASCROSS_DIR/firmware"
|
||||
git clone --depth 1 https://github.com/raspberrypi/firmware.git "$RASCROSS_DIR/firmware"
|
||||
ln -s "$RASCROSS_DIR/firmware/hardfp/opt" "$ROOTFS_DIR/opt"
|
||||
|
||||
```
|
||||
Get toolchain files which allows to build ARM executables on x86 platforms:
|
||||
```
|
||||
mkdir -p "$TOOLCHAIN_DIR"
|
||||
cd $TOOLCHAIN_DIR
|
||||
wget -c https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf.tar.xz --no-check-certificate
|
||||
tar -xvf gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf.tar.xz
|
||||
|
||||
##### End of RPi specific ######
|
||||
|
||||
######## Qt5 specific #########
|
||||
|
||||
```
|
||||
### Install the Qt5 framework
|
||||
```
|
||||
mkdir -p "$QT5_DIR"
|
||||
cd "$QT5_DIR"
|
||||
|
||||
wget -c http://download.qt.io/archive/qt/5.7/5.7.1/qt-opensource-linux-x64-5.7.1.run
|
||||
chmod +x $QT5_DIR/*.run
|
||||
|
||||
#Display absolute installation directory to be used in Qt5 installer
|
||||
```
|
||||
Display absolute installation directory to be used in Qt5 installer:
|
||||
```
|
||||
echo $HOME/crosscompile/Qt5
|
||||
|
||||
```
|
||||
Start the Qt5 installation.
|
||||
Follow the dialogs and install in absolute directory of ```$HOME/crosscompile/Qt5``` (copy from above)
|
||||
```
|
||||
./qt-opensource-linux-x64-5.7.1.run
|
||||
|
||||
#Follow the dialogs and install in absolute directory of $HOME/crosscompile/Qt5 (copy from above)
|
||||
|
||||
##### End of Qt5 specific ######
|
||||
|
||||
# get the Hyperion sources
|
||||
```
|
||||
### Get the Hyperion-NG source files
|
||||
```
|
||||
git clone --recursive https://github.com/hyperion-project/hyperion.ng.git "$HYPERION_DIR"
|
||||
|
||||
# get requried submodules
|
||||
```
|
||||
### Get required submodules for Hyperion
|
||||
```
|
||||
cd "$HYPERION_DIR"
|
||||
git fetch --recurse-submodules -j2
|
||||
|
||||
#compile
|
||||
```
|
||||
### Compile Hyperion-NG
|
||||
```
|
||||
cd "$HYPERION_DIR"
|
||||
chmod +x "$HYPERION_DIR/bin/"*.sh
|
||||
./bin/create_all_releases.sh
|
||||
```
|
||||
### Transfer output packages to target platform and install Hyperion-NG
|
||||
Output packages for target platform (.deb, .tar.gz, .sh) can be found here:
|
||||
```
|
||||
$HYPERION_DIR/deploy/rpi
|
||||
```
|
||||
# Install Hyperion-NG on target platform
|
||||
t.b.d.
|
||||
|
||||
|
||||
######END
|
@ -40,7 +40,7 @@ Debian 9, Ubuntu 16.04 or higher. Windows is not supported currently.
|
||||
We provide a macOS Build but we can not support this.
|
||||
|
||||
## Building
|
||||
See [CompileHowto](CompileHowto.md) and [CrossCompileHowto](CrossCompileHowto.txt).
|
||||
See [CompileHowto](CompileHowto.md) and [CrossCompileHowto](CrossCompileHowto.md).
|
||||
|
||||
## Download
|
||||
**Please be patient. The first release is coming soon.**
|
||||
|
@ -659,6 +659,8 @@
|
||||
"edt_eff_gif_header_desc": "Dieser Effekt spielt .gif Dateien ab. Bietet die Möglichkeit kleine GIF-Videos abzuspielen.",
|
||||
"edt_eff_candle_header": "Kerze",
|
||||
"edt_eff_candle_header_desc": "Flackerndes Kerzenlicht",
|
||||
"edt_eff_ledtest_header" : "Led Test",
|
||||
"edt_eff_ledtest_header_desc" : "Rotierende Ausgabe von Rot, Grün, Blau, Weiß und Schwarz",
|
||||
"edt_eff_police_header": "Polizei",
|
||||
"edt_eff_police_header_desc": "Lights like a police car in action",
|
||||
"edt_eff_fade_header": "Farbübergang",
|
||||
|
@ -658,6 +658,8 @@
|
||||
"edt_eff_gif_header_desc" : "This effect plays .gif files, provide a simple video like loop as effect.",
|
||||
"edt_eff_candle_header" : "Candle",
|
||||
"edt_eff_candle_header_desc" : "Shimmering candles",
|
||||
"edt_eff_ledtest_header" : "Led Test",
|
||||
"edt_eff_ledtest_header_desc" : "Rotating output: Red, Blue, Green, White, Black",
|
||||
"edt_eff_police_header" : "Police",
|
||||
"edt_eff_police_header_desc" : "Lights like a police car in action",
|
||||
"edt_eff_fade_header" : "Fade",
|
||||
|
@ -10,6 +10,7 @@ colorEndTime = float(hyperion.args.get('color-end-time', 1000)) / 1000
|
||||
repeat = hyperion.args.get('repeat-count', 0)
|
||||
maintainEndCol = hyperion.args.get('maintain-end-color', True)
|
||||
minStepTime = float(hyperion.latchTime)/1000.0
|
||||
if minStepTime == 0: minStepTime = 1
|
||||
currentR = currentG = currentB = 0
|
||||
|
||||
# create color table for fading from start to end color
|
||||
|
12
effects/ledtest.json
Normal file
12
effects/ledtest.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name" : "Led Test",
|
||||
"script" : "ledtest.py",
|
||||
"args" :
|
||||
{
|
||||
"sleepTime" : 0.20,
|
||||
"testleds" : "all",
|
||||
"smoothing-custom-settings" : true,
|
||||
"smoothing-time_ms" : 500,
|
||||
"smoothing-updateFrequency" : 20.0
|
||||
}
|
||||
}
|
60
effects/ledtest.py
Normal file
60
effects/ledtest.py
Normal file
@ -0,0 +1,60 @@
|
||||
# testleds can be :
|
||||
# "all" to test all the leds
|
||||
# a single led number, a list of led numbers
|
||||
|
||||
import hyperion
|
||||
import time
|
||||
#import colorsys
|
||||
|
||||
# Get parameters
|
||||
sleepTime = float(hyperion.args.get('sleepTime', 0.2))
|
||||
testleds = hyperion.args.get('testleds', "all")
|
||||
ledlist = hyperion.args.get('ledlist', "1")
|
||||
|
||||
testlist = ()
|
||||
if (testleds == "list") and (type(ledlist) is str):
|
||||
for s in ledlist.split(','):
|
||||
i = int(s)
|
||||
if (i<hyperion.ledCount):
|
||||
testlist += (i,)
|
||||
elif (testleds == "list") and (type(ledlist) is list):
|
||||
for s in (ledlist):
|
||||
i = int(s)
|
||||
if (i<hyperion.ledCount):
|
||||
testlist += (i,)
|
||||
else:
|
||||
testlist = range(hyperion.ledCount)
|
||||
|
||||
def TestRgb( iteration ):
|
||||
|
||||
switcher = {
|
||||
0: (255, 0, 0),
|
||||
1: (0, 255, 0),
|
||||
2: (0, 0, 255),
|
||||
3: (255, 255, 255),
|
||||
4: (0, 0, 0),
|
||||
}
|
||||
|
||||
return switcher.get(iteration, (127,127,127) )
|
||||
|
||||
ledData = bytearray(hyperion.ledCount * (0,0,0) )
|
||||
i = 0
|
||||
while not hyperion.abort():
|
||||
j = i % 5
|
||||
if (testleds == "all"):
|
||||
for lednum in testlist:
|
||||
rgb = TestRgb( j )
|
||||
ledData[3*lednum+0] = rgb[0]
|
||||
ledData[3*lednum+1] = rgb[1]
|
||||
ledData[3*lednum+2] = rgb[2]
|
||||
else:
|
||||
for lednum in testlist:
|
||||
rgb = TestRgb( j )
|
||||
ledData[3*lednum+0] = rgb[0]
|
||||
ledData[3*lednum+1] = rgb[1]
|
||||
ledData[3*lednum+2] = rgb[2]
|
||||
|
||||
hyperion.setColor (ledData)
|
||||
i += 1
|
||||
time.sleep(sleepTime)
|
||||
|
@ -7,7 +7,9 @@ ledData = bytearray()
|
||||
ledDataBuf = bytearray()
|
||||
color_step = []
|
||||
minStepTime= float(hyperion.latchTime)/1000.0
|
||||
if minStepTime == 0: minStepTime = 1
|
||||
fadeSteps = min(256.0, math.floor(sleepTime/minStepTime))
|
||||
if fadeSteps == 0: fadeSteps = 1
|
||||
|
||||
# Initialize the led data
|
||||
for i in range(hyperion.ledCount):
|
||||
|
77
effects/schema/ledtest.schema.json
Normal file
77
effects/schema/ledtest.schema.json
Normal file
@ -0,0 +1,77 @@
|
||||
{
|
||||
"type":"object",
|
||||
"script" : "ledtest.py",
|
||||
"title":"edt_eff_ledtest_header",
|
||||
"required":true,
|
||||
"properties":{
|
||||
"testleds": {
|
||||
"type": "string",
|
||||
"title":"edt_eff_whichleds",
|
||||
"enum" : ["all","list"],
|
||||
"default" : "all",
|
||||
"options" : {
|
||||
"enum_titles" : ["edt_eff_enum_all", "edt_eff_enum_list"]
|
||||
},
|
||||
"propertyOrder" : 1
|
||||
},
|
||||
"ledlist": {
|
||||
"type": "string",
|
||||
"title":"edt_eff_ledlist",
|
||||
"default" : "1,11,21",
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"testleds": "list"
|
||||
}
|
||||
},
|
||||
"propertyOrder" : 2
|
||||
},
|
||||
"sleepTime": {
|
||||
"type": "number",
|
||||
"title":"edt_eff_sleeptime",
|
||||
"default": 0.15,
|
||||
"minimum" : 0.01,
|
||||
"maximum": 1,
|
||||
"step": 0.01,
|
||||
"append" : "edt_append_s",
|
||||
"propertyOrder" : 6
|
||||
},
|
||||
"smoothing-custom-settings" :
|
||||
{
|
||||
"type" : "boolean",
|
||||
"title" : "edt_eff_smooth_custom",
|
||||
"default" : false,
|
||||
"propertyOrder" : 7
|
||||
},
|
||||
"smoothing-time_ms" :
|
||||
{
|
||||
"type" : "integer",
|
||||
"title" : "edt_eff_smooth_time_ms",
|
||||
"minimum" : 25,
|
||||
"maximum": 600,
|
||||
"default" : 200,
|
||||
"append" : "edt_append_ms",
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"smoothing-custom-settings": true
|
||||
}
|
||||
},
|
||||
"propertyOrder" : 8
|
||||
},
|
||||
"smoothing-updateFrequency" :
|
||||
{
|
||||
"type" : "number",
|
||||
"title" : "edt_eff_smooth_updateFrequency",
|
||||
"minimum" : 1.0,
|
||||
"maximum" : 100.0,
|
||||
"default" : 25.0,
|
||||
"append" : "edt_append_hz",
|
||||
"options": {
|
||||
"dependencies": {
|
||||
"smoothing-custom-settings": true
|
||||
}
|
||||
},
|
||||
"propertyOrder" : 9
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
@ -25,6 +25,7 @@ def getSTime(rt, steps = 360):
|
||||
|
||||
# adapt sleeptime to hardware
|
||||
minStepTime= float(hyperion.latchTime)/1000.0
|
||||
if minStepTime == 0: minStepTime = 1
|
||||
if minStepTime > sleepTime:
|
||||
sleepTime = minStepTime
|
||||
return sleepTime
|
||||
|
@ -7,6 +7,7 @@ for i in range(hyperion.ledCount):
|
||||
|
||||
sleepTime = float(hyperion.args.get('speed', 1.0)) * 0.004
|
||||
minStepTime = float(hyperion.latchTime)/1000.0
|
||||
if minStepTime == 0: minStepTime = 1
|
||||
factor = 1 if sleepTime > minStepTime else int(math.ceil(minStepTime/sleepTime))
|
||||
|
||||
runners = [
|
||||
|
@ -222,6 +222,8 @@ public:
|
||||
|
||||
/// forward smoothing config
|
||||
unsigned addSmoothingConfig(int settlingTime_ms, double ledUpdateFrequency_hz=25.0, unsigned updateDelay=0);
|
||||
unsigned updateSmoothingConfig(unsigned id, int settlingTime_ms=200, double ledUpdateFrequency_hz=25.0, unsigned updateDelay=0);
|
||||
|
||||
|
||||
const VideoMode & getCurrentVideoMode();
|
||||
|
||||
|
@ -37,40 +37,53 @@ public:
|
||||
LedDevice(const QJsonObject& config = QJsonObject(), QObject* parent = nullptr);
|
||||
virtual ~LedDevice();
|
||||
|
||||
/// Switch the leds off (led hardware disable)
|
||||
virtual int switchOff();
|
||||
|
||||
/// Switch the leds on (led hardware enable), used if reinitialization is required for the device implementation
|
||||
virtual int switchOn();
|
||||
|
||||
virtual int setLedValues(const std::vector<ColorRgb>& ledValues);
|
||||
|
||||
///
|
||||
/// @brief Get color order of device
|
||||
/// @return The color order
|
||||
///
|
||||
const QString & getColorOrder() { return _colorOrder; };
|
||||
const QString & getColorOrder() const { return _colorOrder; }
|
||||
|
||||
///
|
||||
/// @brief Set the current active ledDevice type
|
||||
///
|
||||
/// @param deviceType Device's type
|
||||
///
|
||||
void setActiveDeviceType(QString deviceType);
|
||||
void setActiveDeviceType(const QString& deviceType);
|
||||
|
||||
///
|
||||
/// @brief Get the current active ledDevice type
|
||||
///
|
||||
const QString & getActiveDeviceType() { return _activeDeviceType; };
|
||||
const QString & getActiveDeviceType() const { return _activeDeviceType; }
|
||||
|
||||
void setLedCount(int ledCount);
|
||||
int getLedCount() { return _ledCount; }
|
||||
void setLedCount(unsigned int ledCount);
|
||||
unsigned int getLedCount() const { return _ledCount; }
|
||||
|
||||
void setEnable(bool enable);
|
||||
bool enabled() { return _enabled; };
|
||||
int getLatchTime() { return _latchTime_ms; };
|
||||
bool enabled() const { return _enabled; }
|
||||
int getLatchTime() const { return _latchTime_ms; }
|
||||
|
||||
///
|
||||
/// Check, if device is ready to be used
|
||||
/// i.e. initialisation and configuration were successfull
|
||||
///
|
||||
/// @return True if device is ready
|
||||
///
|
||||
bool isReady() const { return _deviceReady; }
|
||||
|
||||
///
|
||||
/// Check, if device is in error state
|
||||
///
|
||||
/// @return True if device is in error
|
||||
///
|
||||
bool isInError() const { return _deviceInError; }
|
||||
|
||||
inline bool componentState() const { return enabled(); }
|
||||
|
||||
/// Prints the RGB-Color values to stdout.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per led
|
||||
///
|
||||
static void printLedValues (const std::vector<ColorRgb>& ledValues );
|
||||
|
||||
inline bool componentState() { return enabled(); };
|
||||
|
||||
public slots:
|
||||
///
|
||||
@ -78,6 +91,53 @@ public slots:
|
||||
///
|
||||
virtual void start() { _deviceReady = (open() == 0 ? true : false);}
|
||||
|
||||
///
|
||||
/// Update the RGB-Color values to the leds.
|
||||
/// Handles refreshing of leds.
|
||||
///
|
||||
/// @param[in] ledValues The RGB-color per led
|
||||
/// @return Zero on success else negative (i.e. device is not ready)
|
||||
///
|
||||
virtual int updateLeds(const std::vector<ColorRgb>& ledValues);
|
||||
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close();
|
||||
|
||||
///
|
||||
/// Enables/disables the device for output.
|
||||
/// If the device is not ready, it will not be enabled
|
||||
///
|
||||
/// @param enable The new state of the device
|
||||
///
|
||||
void setEnable(bool enable); ///
|
||||
|
||||
signals:
|
||||
///
|
||||
/// Emits whenever the led device switches between on/off
|
||||
/// @param newState The new state of the device
|
||||
///
|
||||
void enableStateChanged(bool newState);
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Initialise a device's configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return True if success
|
||||
///
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
///
|
||||
virtual int open();
|
||||
|
||||
///
|
||||
/// Writes the RGB-Color values to the leds.
|
||||
///
|
||||
@ -87,31 +147,6 @@ public slots:
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues) = 0;
|
||||
|
||||
signals:
|
||||
///
|
||||
/// Emits whenever the led device switches between on/off
|
||||
/// @param newState The new state of the device
|
||||
///
|
||||
void enableStateChanged(bool newState);
|
||||
|
||||
///
|
||||
/// PIPER signal for Priority Muxer -> LedDevice
|
||||
///
|
||||
/// @brief Handle priority updates from Priority Muxer
|
||||
/// @param priority The new visible priority
|
||||
///
|
||||
void visiblePriorityChanged(const quint8 &priority);
|
||||
|
||||
protected:
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Opens and configures the output device
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int open();
|
||||
|
||||
///
|
||||
/// Writes "BLACK" to the output stream
|
||||
///
|
||||
@ -119,7 +154,6 @@ protected:
|
||||
///
|
||||
virtual int writeBlack();
|
||||
|
||||
|
||||
// Helper to pipe device config from constructor to start()
|
||||
QJsonObject _devConfig;
|
||||
|
||||
@ -130,26 +164,66 @@ protected:
|
||||
std::vector<uint8_t> _ledBuffer;
|
||||
|
||||
bool _deviceReady;
|
||||
bool _deviceInError;
|
||||
|
||||
QString _activeDeviceType;
|
||||
|
||||
int _ledCount;
|
||||
int _ledRGBCount;
|
||||
int _ledRGBWCount;
|
||||
unsigned int _ledCount;
|
||||
unsigned int _ledRGBCount;
|
||||
unsigned int _ledRGBWCount;
|
||||
|
||||
/// Timer object which makes sure that led data is written at a minimum rate
|
||||
/// e.g. Adalight device will switch off when it does not receive data at least every 15 seconds
|
||||
QTimer _refresh_timer;
|
||||
unsigned int _refresh_timer_interval;
|
||||
qint64 _last_write_time;
|
||||
unsigned int _latchTime_ms;
|
||||
QTimer* _refresh_timer;
|
||||
int _refresh_timer_interval;
|
||||
|
||||
/// timestamp of last write
|
||||
qint64 _last_write_time;
|
||||
|
||||
/// Time a device requires mandatorily between two writes
|
||||
int _latchTime_ms;
|
||||
|
||||
|
||||
protected slots:
|
||||
|
||||
/// Write the last data to the leds again
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
int rewriteLeds();
|
||||
|
||||
/// Switch the leds off
|
||||
/// Writes "Black to LED" or may switch-off the LED hardware, if supported
|
||||
///
|
||||
virtual int switchOff();
|
||||
|
||||
/// Switch the leds on
|
||||
/// May switch-on the LED hardware, if supported
|
||||
///
|
||||
virtual int switchOn();
|
||||
|
||||
/// Set device in error state
|
||||
///
|
||||
/// @param errorMsg The error message to be logged
|
||||
///
|
||||
virtual void setInError( const QString& errorMsg);
|
||||
|
||||
private:
|
||||
std::vector<ColorRgb> _ledValues;
|
||||
bool _componentRegistered;
|
||||
bool _enabled;
|
||||
QString _colorOrder;
|
||||
|
||||
/// Start new refresh cycle
|
||||
///
|
||||
void startRefreshTimer();
|
||||
|
||||
/// Stop refresh cycle
|
||||
///
|
||||
void stopRefreshTimer();
|
||||
|
||||
|
||||
bool _componentRegistered;
|
||||
bool _enabled;
|
||||
bool _refresh_enabled;
|
||||
QString _colorOrder;
|
||||
|
||||
/// Last LED values written
|
||||
std::vector<ColorRgb> _last_ledValues;
|
||||
};
|
||||
|
@ -18,7 +18,7 @@ class LedDeviceWrapper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LedDeviceWrapper(Hyperion* hyperion);
|
||||
explicit LedDeviceWrapper(Hyperion* hyperion);
|
||||
~LedDeviceWrapper();
|
||||
///
|
||||
/// @brief Contructs a new LedDevice, moves to thread and starts
|
||||
@ -57,13 +57,18 @@ public:
|
||||
///
|
||||
/// @brief Return the last enable state
|
||||
///
|
||||
const bool & enabled() { return _enabled; };
|
||||
const bool & enabled() { return _enabled; }
|
||||
|
||||
///
|
||||
/// @brief Get the current colorOrder from device
|
||||
///
|
||||
const QString & getColorOrder();
|
||||
|
||||
///
|
||||
/// @brief Get the number of Leds from device
|
||||
///
|
||||
unsigned int getLedCount() const;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// @brief Handle new component state request
|
||||
@ -80,7 +85,10 @@ signals:
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
int write(const std::vector<ColorRgb>& ledValues);
|
||||
int updateLeds(const std::vector<ColorRgb>& ledValues);
|
||||
|
||||
void setEnable(bool enable);
|
||||
void closeLedDevice();
|
||||
|
||||
private slots:
|
||||
///
|
||||
|
@ -13,19 +13,16 @@
|
||||
#include <utils/global_defines.h>
|
||||
|
||||
// standard log messages
|
||||
//#define _FUNCNAME_ __PRETTY_FUNCTION__
|
||||
#define _FUNCNAME_ __FUNCTION__
|
||||
|
||||
#define Debug(logger, ...) { (logger)->Message(Logger::DEBUG , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__); }
|
||||
#define Info(logger, ...) { (logger)->Message(Logger::INFO , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__); }
|
||||
#define Warning(logger, ...) { (logger)->Message(Logger::WARNING, __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__); }
|
||||
#define Error(logger, ...) { (logger)->Message(Logger::ERROR , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__); }
|
||||
#define Debug(logger, ...) (logger)->Message(Logger::DEBUG , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define Info(logger, ...) (logger)->Message(Logger::INFO , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define Warning(logger, ...) (logger)->Message(Logger::WARNING, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define Error(logger, ...) (logger)->Message(Logger::ERROR , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
|
||||
// conditional log messages
|
||||
#define DebugIf(condition, logger, ...) { if (condition) {(logger)->Message(Logger::DEBUG , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__);} }
|
||||
#define InfoIf(condition, logger, ...) { if (condition) {(logger)->Message(Logger::INFO , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__);} }
|
||||
#define WarningIf(condition, logger, ...) { if (condition) {(logger)->Message(Logger::WARNING , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__);} }
|
||||
#define ErrorIf(condition, logger, ...) { if (condition) {(logger)->Message(Logger::ERROR , __FILE__, _FUNCNAME_, __LINE__, __VA_ARGS__);} }
|
||||
#define DebugIf(condition, logger, ...) if (condition) (logger)->Message(Logger::DEBUG , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define InfoIf(condition, logger, ...) if (condition) (logger)->Message(Logger::INFO , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define WarningIf(condition, logger, ...) if (condition) (logger)->Message(Logger::WARNING , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define ErrorIf(condition, logger, ...) if (condition) (logger)->Message(Logger::ERROR , __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
|
||||
// ================================================================
|
||||
|
||||
@ -55,8 +52,8 @@ public:
|
||||
static LogLevel getLogLevel(QString name="");
|
||||
|
||||
void Message(LogLevel level, const char* sourceFile, const char* func, unsigned int line, const char* fmt, ...);
|
||||
void setMinLevel(LogLevel level) { _minLevel = level; };
|
||||
LogLevel getMinLevel() { return _minLevel; };
|
||||
void setMinLevel(LogLevel level) { _minLevel = level; }
|
||||
LogLevel getMinLevel() { return _minLevel; }
|
||||
|
||||
signals:
|
||||
void newLogMessage(Logger::T_LOG_MESSAGE);
|
||||
@ -83,7 +80,7 @@ class LoggerManager : public QObject
|
||||
|
||||
public:
|
||||
static LoggerManager* getInstance();
|
||||
QVector<Logger::T_LOG_MESSAGE>* getLogMessageBuffer() { return &_logMessageBuffer; };
|
||||
QVector<Logger::T_LOG_MESSAGE>* getLogMessageBuffer() { return &_logMessageBuffer; }
|
||||
|
||||
public slots:
|
||||
void handleNewLogMessage(const Logger::T_LOG_MESSAGE&);
|
||||
|
@ -142,13 +142,13 @@ namespace hyperion {
|
||||
{
|
||||
// Special case for indices '*' => all leds
|
||||
adjustment->setAdjustmentForLed(colorAdjustment->_id, 0, ledCnt-1);
|
||||
//Info(_log, "ColorAdjustment '%s' => [0; %d]", QSTRING_CSTR(colorAdjustment->_id), ledCnt-1);
|
||||
//Info(Logger::getInstance("HYPERION"), "ColorAdjustment '%s' => [0-%d]", QSTRING_CSTR(colorAdjustment->_id), ledCnt-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!overallExp.exactMatch(ledIndicesStr))
|
||||
{
|
||||
//Error(_log, "Given led indices %d not correct format: %s", i, QSTRING_CSTR(ledIndicesStr));
|
||||
//Error(Logger::getInstance("HYPERION"), "Given led indices %d not correct format: %s", i, QSTRING_CSTR(ledIndicesStr));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -175,7 +175,7 @@ namespace hyperion {
|
||||
ss << index;
|
||||
}
|
||||
}
|
||||
//Info(_log, "ColorAdjustment '%s' => [%s]", QSTRING_CSTR(colorAdjustment->_id), ss.str().c_str());
|
||||
//Info(Logger::getInstance("HYPERION"), "ColorAdjustment '%s' => [%s]", QSTRING_CSTR(colorAdjustment->_id), ss.str().c_str());
|
||||
}
|
||||
|
||||
return adjustment;
|
||||
|
@ -111,19 +111,23 @@ void EffectEngine::handleUpdatedEffectList()
|
||||
{
|
||||
_availableEffects.clear();
|
||||
|
||||
unsigned id = 2;
|
||||
for (auto def : _effectFileHandler->getEffects())
|
||||
{
|
||||
// add smoothing configs to Hyperion
|
||||
if (def.args["smoothing-custom-settings"].toBool())
|
||||
{
|
||||
def.smoothCfg = _hyperion->addSmoothingConfig(
|
||||
def.smoothCfg = _hyperion->updateSmoothingConfig(
|
||||
id,
|
||||
def.args["smoothing-time_ms"].toInt(),
|
||||
def.args["smoothing-updateFrequency"].toDouble(),
|
||||
0 );
|
||||
//Debug( _log, "Customs Settings: Update effect %s, script %s, file %s, smoothCfg [%u]", QSTRING_CSTR(def.name), QSTRING_CSTR(def.script), QSTRING_CSTR(def.file), def.smoothCfg);
|
||||
}
|
||||
else
|
||||
{
|
||||
def.smoothCfg = _hyperion->addSmoothingConfig(true);
|
||||
def.smoothCfg = _hyperion->updateSmoothingConfig(id);
|
||||
//Debug( _log, "Default Settings: Update effect %s, script %s, file %s, smoothCfg [%u]", QSTRING_CSTR(def.name), QSTRING_CSTR(def.script), QSTRING_CSTR(def.file), def.smoothCfg);
|
||||
}
|
||||
_availableEffects.push_back(def);
|
||||
}
|
||||
@ -137,7 +141,7 @@ int EffectEngine::runEffect(const QString &effectName, int priority, int timeout
|
||||
|
||||
int EffectEngine::runEffect(const QString &effectName, const QJsonObject &args, int priority, int timeout, const QString &pythonScript, const QString &origin, unsigned smoothCfg, const QString &imageData)
|
||||
{
|
||||
Info( _log, "run effect %s on channel %d", QSTRING_CSTR(effectName), priority);
|
||||
Info( _log, "Run effect \"%s\" on channel %d", QSTRING_CSTR(effectName), priority);
|
||||
|
||||
if (pythonScript.isEmpty())
|
||||
{
|
||||
@ -176,6 +180,7 @@ int EffectEngine::runEffectScript(const QString &script, const QString &name, co
|
||||
_activeEffects.push_back(effect);
|
||||
|
||||
// start the effect
|
||||
Debug(_log, "Start the effect: name [%s], smoothCfg [%u]", QSTRING_CSTR(name), smoothCfg);
|
||||
_hyperion->registerInput(priority, hyperion::COMP_EFFECT, origin, name ,smoothCfg);
|
||||
effect->start();
|
||||
|
||||
|
@ -837,7 +837,7 @@ void V4L2Grabber::stop_capturing()
|
||||
case IO_METHOD_USERPTR:
|
||||
{
|
||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
ErrorIf((xioctl(VIDIOC_STREAMOFF, &type) == -1), _log, "VIDIOC_STREAMOFF error code %d, %s", errno, strerror(errno))
|
||||
ErrorIf((xioctl(VIDIOC_STREAMOFF, &type) == -1), _log, "VIDIOC_STREAMOFF error code %d, %s", errno, strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
// STL includes
|
||||
#include <exception>
|
||||
#include <sstream>
|
||||
@ -105,7 +105,7 @@ void Hyperion::start()
|
||||
|
||||
_ledDeviceWrapper = new LedDeviceWrapper(this);
|
||||
connect(this, &Hyperion::componentStateChanged, _ledDeviceWrapper, &LedDeviceWrapper::handleComponentState);
|
||||
connect(this, &Hyperion::ledDeviceData, _ledDeviceWrapper, &LedDeviceWrapper::write);
|
||||
connect(this, &Hyperion::ledDeviceData, _ledDeviceWrapper, &LedDeviceWrapper::updateLeds);
|
||||
_ledDeviceWrapper->createLedDevice(ledDevice);
|
||||
|
||||
// smoothing
|
||||
@ -176,6 +176,9 @@ void Hyperion::freeObjects(bool emitCloseSignal)
|
||||
|
||||
void Hyperion::handleSettingsUpdate(const settings::type& type, const QJsonDocument& config)
|
||||
{
|
||||
// std::cout << "Hyperion::handleSettingsUpdate" << std::endl;
|
||||
// std::cout << config.toJson().toStdString() << std::endl;
|
||||
|
||||
if(type == settings::COLOR)
|
||||
{
|
||||
const QJsonObject obj = config.object();
|
||||
@ -246,6 +249,12 @@ void Hyperion::handleSettingsUpdate(const settings::type& type, const QJsonDocum
|
||||
// do always reinit until the led devices can handle dynamic changes
|
||||
dev["currentLedCount"] = int(_hwLedCount); // Inject led count info
|
||||
_ledDeviceWrapper->createLedDevice(dev);
|
||||
|
||||
// TODO: Check, if framegrabber frequency is lower than latchtime..., if yes, stop
|
||||
}
|
||||
else if(type == settings::SMOOTHING)
|
||||
{
|
||||
_deviceSmooth->handleSettingsUpdate( type, config);
|
||||
}
|
||||
|
||||
// update once to push single color sets / adjustments/ ledlayout resizes and update ledBuffer color
|
||||
@ -272,6 +281,11 @@ unsigned Hyperion::addSmoothingConfig(int settlingTime_ms, double ledUpdateFrequ
|
||||
return _deviceSmooth->addConfig(settlingTime_ms, ledUpdateFrequency_hz, updateDelay);
|
||||
}
|
||||
|
||||
unsigned Hyperion::updateSmoothingConfig(unsigned id, int settlingTime_ms, double ledUpdateFrequency_hz, unsigned updateDelay)
|
||||
{
|
||||
return _deviceSmooth->updateConfig(id, settlingTime_ms, ledUpdateFrequency_hz, updateDelay);
|
||||
}
|
||||
|
||||
unsigned Hyperion::getLedCount() const
|
||||
{
|
||||
return _ledString.leds().size();
|
||||
@ -319,7 +333,9 @@ bool Hyperion::setInput(const int priority, const std::vector<ColorRgb>& ledColo
|
||||
|
||||
// if this priority is visible, update immediately
|
||||
if(priority == _muxer.getCurrentPriority())
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -342,7 +358,9 @@ bool Hyperion::setInputImage(const int priority, const Image<ColorRgb>& image, i
|
||||
|
||||
// if this priority is visible, update immediately
|
||||
if(priority == _muxer.getCurrentPriority())
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -577,22 +595,26 @@ void Hyperion::update()
|
||||
// Write the data to the device
|
||||
if (_ledDeviceWrapper->enabled())
|
||||
{
|
||||
_deviceSmooth->selectConfig(priorityInfo.smooth_cfg);
|
||||
|
||||
// feed smoothing in pause mode to maintain a smooth transistion back to smooth mode
|
||||
if (_deviceSmooth->enabled() || _deviceSmooth->pause())
|
||||
{
|
||||
_deviceSmooth->setLedValues(_ledBuffer);
|
||||
}
|
||||
// Smoothing is disabled
|
||||
if (! _deviceSmooth->enabled())
|
||||
{
|
||||
//std::cout << "Hyperion::update()> Non-Smoothing - "; LedDevice::printLedValues ( _ledBuffer);
|
||||
emit ledDeviceData(_ledBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
_deviceSmooth->selectConfig(priorityInfo.smooth_cfg);
|
||||
|
||||
// feed smoothing in pause mode to maintain a smooth transistion back to smooth mode
|
||||
if (_deviceSmooth->enabled() || _deviceSmooth->pause())
|
||||
{
|
||||
_deviceSmooth->updateLedValues(_ledBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// LEDDevice is disabled
|
||||
//Debug(_log, "LEDDevice is disabled - no update required");
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// /LEDDevice is disabled
|
||||
// Debug(_log, "LEDDevice is disabled - no update required");
|
||||
//}
|
||||
}
|
||||
|
@ -9,34 +9,38 @@
|
||||
|
||||
using namespace hyperion;
|
||||
|
||||
const int64_t DEFAUL_SETTLINGTIME = 200; // settlingtime in ms
|
||||
const double DEFAUL_UPDATEFREQUENCY = 25; // updatefrequncy in hz
|
||||
const int64_t DEFAUL_UPDATEINTERVALL = static_cast<int64_t>(1000 / DEFAUL_UPDATEFREQUENCY); // updateintervall in ms
|
||||
const unsigned DEFAUL_OUTPUTDEPLAY = 0; // outputdelay in ms
|
||||
|
||||
LinearColorSmoothing::LinearColorSmoothing(const QJsonDocument& config, Hyperion* hyperion)
|
||||
: LedDevice(QJsonObject(), hyperion)
|
||||
: QObject(hyperion)
|
||||
, _log(Logger::getInstance("SMOOTHING"))
|
||||
, _hyperion(hyperion)
|
||||
, _updateInterval(1000)
|
||||
, _settlingTime(200)
|
||||
, _updateInterval(DEFAUL_UPDATEINTERVALL)
|
||||
, _settlingTime(DEFAUL_SETTLINGTIME)
|
||||
, _timer(new QTimer(this))
|
||||
, _outputDelay(0)
|
||||
, _writeToLedsEnable(true)
|
||||
, _outputDelay(DEFAUL_OUTPUTDEPLAY)
|
||||
, _writeToLedsEnable(false)
|
||||
, _continuousOutput(false)
|
||||
, _pause(false)
|
||||
, _currentConfigId(0)
|
||||
, _enabled(true)
|
||||
{
|
||||
// set initial state to true, as LedDevice::enabled() is true by default
|
||||
_hyperion->getComponentRegister().componentStateChanged(hyperion::COMP_SMOOTHING, true);
|
||||
|
||||
// init cfg 0 (default)
|
||||
_cfgList.append({false, 200, 25, 0});
|
||||
addConfig(DEFAUL_SETTLINGTIME, DEFAUL_UPDATEFREQUENCY, DEFAUL_OUTPUTDEPLAY);
|
||||
handleSettingsUpdate(settings::SMOOTHING, config);
|
||||
selectConfig(0, true);
|
||||
|
||||
// add pause on cfg 1
|
||||
SMOOTHING_CFG cfg = {true};
|
||||
SMOOTHING_CFG cfg = {true, 0, 0, 0};
|
||||
_cfgList.append(cfg);
|
||||
|
||||
// listen for comp changes
|
||||
connect(_hyperion, &Hyperion::componentStateChanged, this, &LinearColorSmoothing::componentStateChange);
|
||||
// timer
|
||||
connect(_timer, SIGNAL(timeout()), this, SLOT(updateLeds()));
|
||||
connect(_timer, &QTimer::timeout, this, &LinearColorSmoothing::updateLeds);
|
||||
}
|
||||
|
||||
LinearColorSmoothing::~LinearColorSmoothing()
|
||||
@ -48,16 +52,33 @@ void LinearColorSmoothing::handleSettingsUpdate(const settings::type& type, cons
|
||||
{
|
||||
if(type == settings::SMOOTHING)
|
||||
{
|
||||
QJsonObject obj = config.object();
|
||||
_continuousOutput = obj["continuousOutput"].toBool(true);
|
||||
SMOOTHING_CFG cfg = {false, obj["time_ms"].toInt(200), unsigned(1000.0/obj["updateFrequency"].toDouble(25.0)), unsigned(obj["updateDelay"].toInt(0))};
|
||||
_cfgList[0] = cfg;
|
||||
// if current id is 0, we need to apply the settings (forced)
|
||||
if(!_currentConfigId)
|
||||
selectConfig(0, true);
|
||||
// std::cout << "LinearColorSmoothing::handleSettingsUpdate" << std::endl;
|
||||
// std::cout << config.toJson().toStdString() << std::endl;
|
||||
|
||||
QJsonObject obj = config.object();
|
||||
if(enabled() != obj["enable"].toBool(true))
|
||||
setEnable(obj["enable"].toBool(true));
|
||||
|
||||
_continuousOutput = obj["continuousOutput"].toBool(true);
|
||||
|
||||
SMOOTHING_CFG cfg = {false,
|
||||
static_cast<int64_t>(obj["time_ms"].toInt(DEFAUL_SETTLINGTIME)),
|
||||
static_cast<int64_t>(1000.0/obj["updateFrequency"].toDouble(DEFAUL_UPDATEFREQUENCY)),
|
||||
static_cast<unsigned>(obj["updateDelay"].toInt(DEFAUL_OUTPUTDEPLAY))
|
||||
};
|
||||
//Debug( _log, "smoothing cfg_id %d: pause: %d bool, settlingTime: %d ms, interval: %d ms (%u Hz), updateDelay: %u frames", _currentConfigId, cfg.pause, cfg.settlingTime, cfg.updateInterval, unsigned(1000.0/cfg.updateInterval), cfg.outputDelay );
|
||||
_cfgList[0] = cfg;
|
||||
|
||||
// if current id is 0, we need to apply the settings (forced)
|
||||
if( _currentConfigId == 0)
|
||||
{
|
||||
//Debug( _log, "_currentConfigId == 0");
|
||||
selectConfig(0, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Debug( _log, "_currentConfigId != 0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,42 +93,43 @@ int LinearColorSmoothing::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
||||
_previousTime = QDateTime::currentMSecsSinceEpoch();
|
||||
_previousValues = ledValues;
|
||||
|
||||
//Debug( _log, "Start Smoothing timer: settlingTime: %d ms, interval: %d ms (%u Hz), updateDelay: %u frames", _settlingTime, _updateInterval, unsigned(1000.0/_updateInterval), _outputDelay );
|
||||
QMetaObject::invokeMethod(_timer, "start", Qt::QueuedConnection, Q_ARG(int, _updateInterval));
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::cout << "LinearColorSmoothing::write> "; LedDevice::printLedValues ( ledValues );
|
||||
|
||||
_targetTime = QDateTime::currentMSecsSinceEpoch() + _settlingTime;
|
||||
memcpy(_targetValues.data(), ledValues.data(), ledValues.size() * sizeof(ColorRgb));
|
||||
|
||||
//std::cout << "LinearColorSmoothing::write> _targetValues: "; LedDevice::printLedValues ( _targetValues );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LinearColorSmoothing::switchOff()
|
||||
int LinearColorSmoothing::updateLedValues(const std::vector<ColorRgb>& ledValues)
|
||||
{
|
||||
// We will keep updating the leds (but with pure-black)
|
||||
|
||||
// Clear the smoothing parameters
|
||||
std::fill(_targetValues.begin(), _targetValues.end(), ColorRgb::BLACK);
|
||||
_targetTime = 0;
|
||||
|
||||
// Erase the output-queue
|
||||
for (unsigned i=0; i<_outputQueue.size(); ++i)
|
||||
int retval = 0;
|
||||
if (!_enabled)
|
||||
{
|
||||
_outputQueue.push_back(_targetValues);
|
||||
_outputQueue.pop_front();
|
||||
return -1;
|
||||
}
|
||||
|
||||
emit _hyperion->ledDeviceData(std::vector<ColorRgb>(_ledCount, ColorRgb::BLACK));
|
||||
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
retval = write(ledValues);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LinearColorSmoothing::updateLeds()
|
||||
{
|
||||
int64_t now = QDateTime::currentMSecsSinceEpoch();
|
||||
int deltaTime = _targetTime - now;
|
||||
int64_t deltaTime = _targetTime - now;
|
||||
|
||||
//Debug(_log, "elapsed Time [%d], _targetTime [%d] - now [%d], deltaTime [%d]", now -_previousTime, _targetTime, now, deltaTime);
|
||||
if (deltaTime < 0)
|
||||
{
|
||||
memcpy(_previousValues.data(), _targetValues.data(), _targetValues.size() * sizeof(ColorRgb));
|
||||
@ -119,6 +141,9 @@ void LinearColorSmoothing::updateLeds()
|
||||
else
|
||||
{
|
||||
_writeToLedsEnable = true;
|
||||
|
||||
//std::cout << "LinearColorSmoothing::updateLeds> _previousValues: "; LedDevice::printLedValues ( _previousValues );
|
||||
|
||||
float k = 1.0f - 1.0f * deltaTime / (_targetTime - _previousTime);
|
||||
|
||||
int reddif = 0, greendif = 0, bluedif = 0;
|
||||
@ -138,18 +163,25 @@ void LinearColorSmoothing::updateLeds()
|
||||
}
|
||||
_previousTime = now;
|
||||
|
||||
//std::cout << "LinearColorSmoothing::updateLeds> _targetValues: "; LedDevice::printLedValues ( _targetValues );
|
||||
|
||||
queueColors(_previousValues);
|
||||
}
|
||||
}
|
||||
|
||||
void LinearColorSmoothing::queueColors(const std::vector<ColorRgb> & ledColors)
|
||||
{
|
||||
//Debug(_log, "queueColors - _outputDelay[%d] _outputQueue.size() [%d], _writeToLedsEnable[%d]", _outputDelay, _outputQueue.size(), _writeToLedsEnable);
|
||||
if (_outputDelay == 0)
|
||||
{
|
||||
// No output delay => immediate write
|
||||
if ( _writeToLedsEnable && !_pause)
|
||||
{
|
||||
// if ( ledColors.size() == 0 )
|
||||
// qFatal ("No LedValues! - in LinearColorSmoothing::queueColors() - _outputDelay == 0");
|
||||
// else
|
||||
emit _hyperion->ledDeviceData(ledColors);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -172,29 +204,38 @@ void LinearColorSmoothing::queueColors(const std::vector<ColorRgb> & ledColors)
|
||||
}
|
||||
}
|
||||
|
||||
void LinearColorSmoothing::clearQueuedColors()
|
||||
{
|
||||
QMetaObject::invokeMethod(_timer, "stop", Qt::QueuedConnection);
|
||||
_previousValues.clear();
|
||||
|
||||
_targetValues.clear();
|
||||
}
|
||||
|
||||
void LinearColorSmoothing::componentStateChange(const hyperion::Components component, const bool state)
|
||||
{
|
||||
_writeToLedsEnable = state;
|
||||
if(component == hyperion::COMP_LEDDEVICE)
|
||||
{
|
||||
setEnable(state);
|
||||
clearQueuedColors();
|
||||
}
|
||||
|
||||
if(component == hyperion::COMP_SMOOTHING)
|
||||
{
|
||||
setEnable(state);
|
||||
// update comp register
|
||||
_hyperion->getComponentRegister().componentStateChanged(hyperion::COMP_SMOOTHING, state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LinearColorSmoothing::setEnable(bool enable)
|
||||
{
|
||||
if (!enable)
|
||||
_enabled = enable;
|
||||
if (!_enabled)
|
||||
{
|
||||
QMetaObject::invokeMethod(_timer, "stop", Qt::QueuedConnection);
|
||||
_previousValues.clear();
|
||||
clearQueuedColors();
|
||||
}
|
||||
// update comp register
|
||||
_hyperion->getComponentRegister().componentStateChanged(hyperion::COMP_SMOOTHING, enable);
|
||||
}
|
||||
|
||||
void LinearColorSmoothing::setPause(bool pause)
|
||||
@ -207,17 +248,37 @@ unsigned LinearColorSmoothing::addConfig(int settlingTime_ms, double ledUpdateFr
|
||||
SMOOTHING_CFG cfg = {false, settlingTime_ms, int64_t(1000.0/ledUpdateFrequency_hz), updateDelay};
|
||||
_cfgList.append(cfg);
|
||||
|
||||
//Debug( _log, "smoothing cfg %d: interval: %d ms, settlingTime: %d ms, updateDelay: %d frames", _cfgList.count()-1, cfg.updateInterval, cfg.settlingTime, cfg.outputDelay );
|
||||
//Debug( _log, "smoothing cfg %d: pause: %d bool, settlingTime: %d ms, interval: %d ms (%u Hz), updateDelay: %u frames", _cfgList.count()-1, cfg.pause, cfg.settlingTime, cfg.updateInterval, unsigned(1000.0/cfg.updateInterval), cfg.outputDelay );
|
||||
return _cfgList.count() - 1;
|
||||
}
|
||||
|
||||
unsigned LinearColorSmoothing::updateConfig(unsigned cfgID, int settlingTime_ms, double ledUpdateFrequency_hz, unsigned updateDelay)
|
||||
{
|
||||
unsigned updatedCfgID = cfgID;
|
||||
if ( cfgID < static_cast<unsigned>(_cfgList.count()) )
|
||||
{
|
||||
SMOOTHING_CFG cfg = {false, settlingTime_ms, int64_t(1000.0/ledUpdateFrequency_hz), updateDelay};
|
||||
_cfgList[updatedCfgID] = cfg;
|
||||
}
|
||||
else
|
||||
{
|
||||
updatedCfgID = addConfig ( settlingTime_ms, ledUpdateFrequency_hz, updateDelay);
|
||||
}
|
||||
// Debug( _log, "smoothing updatedCfgID %u: settlingTime: %d ms, "
|
||||
// "interval: %d ms (%u Hz), updateDelay: %u frames", cfgID, _settlingTime, int64_t(1000.0/ledUpdateFrequency_hz), unsigned(ledUpdateFrequency_hz), updateDelay );
|
||||
return updatedCfgID;
|
||||
}
|
||||
|
||||
bool LinearColorSmoothing::selectConfig(unsigned cfg, const bool& force)
|
||||
{
|
||||
if (_currentConfigId == cfg && !force)
|
||||
{
|
||||
//Debug( _log, "selectConfig SAME as before, not FORCED - _currentConfigId [%u], force [%d]", cfg, force);
|
||||
//Debug( _log, "current smoothing cfg: %d, settlingTime: %d ms, interval: %d ms (%u Hz), updateDelay: %u frames", _currentConfigId, _settlingTime, _updateInterval, unsigned(1000.0/_updateInterval), _outputDelay );
|
||||
return true;
|
||||
}
|
||||
|
||||
//Debug( _log, "selectConfig FORCED - _currentConfigId [%u], force [%d]", cfg, force);
|
||||
if ( cfg < (unsigned)_cfgList.count())
|
||||
{
|
||||
_settlingTime = _cfgList[cfg].settlingTime;
|
||||
@ -226,13 +287,23 @@ bool LinearColorSmoothing::selectConfig(unsigned cfg, const bool& force)
|
||||
|
||||
if (_cfgList[cfg].updateInterval != _updateInterval)
|
||||
{
|
||||
|
||||
QMetaObject::invokeMethod(_timer, "stop", Qt::QueuedConnection);
|
||||
_updateInterval = _cfgList[cfg].updateInterval;
|
||||
QMetaObject::invokeMethod(_timer, "start", Qt::QueuedConnection, Q_ARG(int, _updateInterval));
|
||||
if ( this->enabled() && this->_writeToLedsEnable )
|
||||
{
|
||||
//Debug( _log, "_cfgList[cfg].updateInterval != _updateInterval - Restart timer - _updateInterval [%d]", _updateInterval);
|
||||
QMetaObject::invokeMethod(_timer, "start", Qt::QueuedConnection, Q_ARG(int, _updateInterval));
|
||||
}
|
||||
else
|
||||
{
|
||||
//Debug( _log, "Smoothing disabled, do NOT restart timer");
|
||||
}
|
||||
}
|
||||
_currentConfigId = cfg;
|
||||
//DebugIf( enabled() && !_pause, _log, "set smoothing cfg: %d, interval: %d ms, settlingTime: %d ms, updateDelay: %d frames", _currentConfigId, _updateInterval, _settlingTime, _outputDelay );
|
||||
//DebugIf( _pause, _log, "set smoothing cfg: %d, pause", _currentConfigId );
|
||||
// Debug( _log, "current smoothing cfg: %d, settlingTime: %d ms, interval: %d ms (%u Hz), updateDelay: %u frames", _currentConfigId, _settlingTime, _updateInterval, unsigned(1000.0/_updateInterval), _outputDelay );
|
||||
// DebugIf( enabled() && !_pause, _log, "set smoothing cfg: %u settlingTime: %d ms, interval: %d ms, updateDelay: %u frames", _currentConfigId, _settlingTime, _updateInterval, _outputDelay );
|
||||
// DebugIf( _pause, _log, "set smoothing cfg: %d, pause", _currentConfigId );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ class Hyperion;
|
||||
///
|
||||
/// This class processes the requested led values and forwards them to the device after applying
|
||||
/// a linear smoothing effect. This class can be handled as a generic LedDevice.
|
||||
class LinearColorSmoothing : public LedDevice
|
||||
class LinearColorSmoothing : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -35,20 +35,17 @@ public:
|
||||
/// Destructor
|
||||
virtual ~LinearColorSmoothing();
|
||||
|
||||
/// write updated values as input for the smoothing filter
|
||||
/// LED values as input for the smoothing filter
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
|
||||
/// Switch the leds off
|
||||
virtual int switchOff();
|
||||
virtual int updateLedValues(const std::vector<ColorRgb>& ledValues);
|
||||
|
||||
void setEnable(bool enable);
|
||||
void setPause(bool pause);
|
||||
bool pause() { return _pause; } ;
|
||||
bool enabled() { return LedDevice::enabled() && !_pause; };
|
||||
bool pause() const { return _pause; }
|
||||
bool enabled() const { return _enabled && !_pause; }
|
||||
|
||||
///
|
||||
/// @brief Add a new smoothing cfg which can be used with selectConfig()
|
||||
@ -60,6 +57,19 @@ public:
|
||||
///
|
||||
unsigned addConfig(int settlingTime_ms, double ledUpdateFrequency_hz=25.0, unsigned updateDelay=0);
|
||||
|
||||
///
|
||||
/// @brief Update a smoothing cfg which can be used with selectConfig()
|
||||
/// In case the ID does not exist, a smoothing cfg is added
|
||||
///
|
||||
/// @param cfgID Smoothing configuration item to be updated
|
||||
/// @param settlingTime_ms The buffer time
|
||||
/// @param ledUpdateFrequency_hz The frequency of update
|
||||
/// @param updateDelay The delay
|
||||
///
|
||||
/// @return The index of the cfg which can be passed to selectConfig()
|
||||
///
|
||||
unsigned updateConfig(unsigned cfgID, int settlingTime_ms, double ledUpdateFrequency_hz=25.0, unsigned updateDelay=0);
|
||||
|
||||
///
|
||||
/// @brief select a smoothing cfg given by cfg index from addConfig()
|
||||
/// @param cfg The index to use
|
||||
@ -89,12 +99,21 @@ private slots:
|
||||
void componentStateChange(const hyperion::Components component, const bool state);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Pushes the colors into the output queue and popping the head to the led-device
|
||||
*
|
||||
* @param ledColors The colors to queue
|
||||
*/
|
||||
void queueColors(const std::vector<ColorRgb> & ledColors);
|
||||
void clearQueuedColors();
|
||||
|
||||
/// write updated values as input for the smoothing filter
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
|
||||
/// Logger instance
|
||||
Logger* _log;
|
||||
@ -149,4 +168,5 @@ private:
|
||||
QVector<SMOOTHING_CFG> _cfgList;
|
||||
|
||||
unsigned _currentConfigId;
|
||||
bool _enabled;
|
||||
};
|
||||
|
@ -14,6 +14,7 @@ MultiColorAdjustment::~MultiColorAdjustment()
|
||||
for (ColorAdjustment * adjustment : _adjustment)
|
||||
{
|
||||
delete adjustment;
|
||||
_adjustment.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,22 +27,25 @@ void MultiColorAdjustment::addAdjustment(ColorAdjustment * adjustment)
|
||||
void MultiColorAdjustment::setAdjustmentForLed(const QString& id, const unsigned startLed, unsigned endLed)
|
||||
{
|
||||
// abort
|
||||
if(startLed >= endLed)
|
||||
if(startLed > endLed)
|
||||
{
|
||||
Error(_log,"startLed >= endLed -> %d >= %d", startLed, endLed);
|
||||
Error(_log,"startLed > endLed -> %d > %d", startLed, endLed);
|
||||
return;
|
||||
}
|
||||
// catch wrong values
|
||||
if(endLed > _ledAdjustments.size())
|
||||
if(endLed > _ledAdjustments.size()-1)
|
||||
{
|
||||
Warning(_log,"The color calibration 'LED index' field has leds specified which aren't part of your led layout");
|
||||
endLed = _ledAdjustments.size();
|
||||
endLed = _ledAdjustments.size()-1;
|
||||
}
|
||||
|
||||
// Get the identified adjustment (don't care if is nullptr)
|
||||
ColorAdjustment * adjustment = getAdjustment(id);
|
||||
|
||||
//Debug(_log,"ColorAdjustment Profile [%s], startLed[%u], endLed[%u]", QSTRING_CSTR(id), startLed, endLed);
|
||||
for (unsigned iLed=startLed; iLed<=endLed; ++iLed)
|
||||
{
|
||||
//Debug(_log,"_ledAdjustments [%u] -> [%p]", iLed, adjustment);
|
||||
_ledAdjustments[iLed] = adjustment;
|
||||
}
|
||||
}
|
||||
@ -98,6 +102,7 @@ void MultiColorAdjustment::applyAdjustment(std::vector<ColorRgb>& ledColors)
|
||||
ColorAdjustment* adjustment = _ledAdjustments[i];
|
||||
if (adjustment == nullptr)
|
||||
{
|
||||
//std::cout << "MultiColorAdjustment::applyAdjustment() - No transform set for this led : " << i << std::endl;
|
||||
// No transform set for this led (do nothing)
|
||||
continue;
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ SettingsManager::SettingsManager(const quint8& instance, QObject* parent)
|
||||
else
|
||||
_qconfig = dbConfig;
|
||||
|
||||
Debug(_log,"Settings database initialized")
|
||||
Debug(_log,"Settings database initialized");
|
||||
}
|
||||
|
||||
const QJsonDocument SettingsManager::getSetting(const settings::type& type)
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <QStringList>
|
||||
#include <QDir>
|
||||
#include <QDateTime>
|
||||
#include <QEventLoop>
|
||||
#include <QTimer>
|
||||
|
||||
#include "hyperion/Hyperion.h"
|
||||
#include <utils/JsonUtils.h>
|
||||
@ -15,32 +17,62 @@ LedDevice::LedDevice(const QJsonObject& config, QObject* parent)
|
||||
, _devConfig(config)
|
||||
, _log(Logger::getInstance("LEDDEVICE"))
|
||||
, _ledBuffer(0)
|
||||
, _deviceReady(true)
|
||||
, _refresh_timer()
|
||||
, _deviceReady(false)
|
||||
, _deviceInError(false)
|
||||
, _refresh_timer(new QTimer(this))
|
||||
, _refresh_timer_interval(0)
|
||||
, _last_write_time(QDateTime::currentMSecsSinceEpoch())
|
||||
, _latchTime_ms(0)
|
||||
, _componentRegistered(false)
|
||||
, _enabled(true)
|
||||
, _enabled(false)
|
||||
, _refresh_enabled (false)
|
||||
{
|
||||
// setup timer
|
||||
_refresh_timer.setInterval(0);
|
||||
connect(&_refresh_timer, SIGNAL(timeout()), this, SLOT(rewriteLeds()));
|
||||
// setup refreshTimer
|
||||
_refresh_timer->setTimerType(Qt::PreciseTimer);
|
||||
_refresh_timer->setInterval( _refresh_timer_interval );
|
||||
connect(_refresh_timer, SIGNAL(timeout()), this, SLOT(rewriteLeds()));
|
||||
}
|
||||
|
||||
LedDevice::~LedDevice()
|
||||
{
|
||||
|
||||
_refresh_timer->deleteLater();
|
||||
}
|
||||
|
||||
// dummy implemention
|
||||
int LedDevice::open()
|
||||
{
|
||||
setEnable (true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LedDevice::setInError(const QString& errorMsg)
|
||||
{
|
||||
_deviceInError = true;
|
||||
_deviceReady = false;
|
||||
_enabled = false;
|
||||
this->stopRefreshTimer();
|
||||
|
||||
Error(_log, "Device disabled, device '%s' signals error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(errorMsg));
|
||||
emit enableStateChanged(_enabled);
|
||||
}
|
||||
|
||||
void LedDevice::close()
|
||||
{
|
||||
switchOff();
|
||||
this->stopRefreshTimer();
|
||||
}
|
||||
|
||||
void LedDevice::setEnable(bool enable)
|
||||
{
|
||||
if (!_deviceReady && enable)
|
||||
{
|
||||
Debug(_log, "Device '%s' was not ready! Trying to re-open.", QSTRING_CSTR(_activeDeviceType));
|
||||
if ( open() < 0 )
|
||||
{
|
||||
Error(_log, "Device '%s' cannot be enabled, as it is not ready!", QSTRING_CSTR(_activeDeviceType));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// emit signal when state changed
|
||||
if (_enabled != enable)
|
||||
{
|
||||
@ -62,7 +94,7 @@ void LedDevice::setEnable(bool enable)
|
||||
_enabled = enable;
|
||||
}
|
||||
|
||||
void LedDevice::setActiveDeviceType(QString deviceType)
|
||||
void LedDevice::setActiveDeviceType(const QString& deviceType)
|
||||
{
|
||||
_activeDeviceType = deviceType;
|
||||
}
|
||||
@ -71,50 +103,100 @@ bool LedDevice::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_colorOrder = deviceConfig["colorOrder"].toString("RGB");
|
||||
_activeDeviceType = deviceConfig["type"].toString("file").toLower();
|
||||
setLedCount(deviceConfig["currentLedCount"].toInt(1)); // property injected to reflect real led count
|
||||
setLedCount(static_cast<unsigned int>( deviceConfig["currentLedCount"].toInt(1) )); // property injected to reflect real led count
|
||||
|
||||
_latchTime_ms = deviceConfig["latchTime"].toInt(_latchTime_ms);
|
||||
_refresh_timer.setInterval( deviceConfig["rewriteTime"].toInt( _refresh_timer_interval) );
|
||||
if (_refresh_timer.interval() <= (signed)_latchTime_ms )
|
||||
_latchTime_ms =deviceConfig["latchTime"].toInt( _latchTime_ms );
|
||||
_refresh_timer_interval = deviceConfig["rewriteTime"].toInt( _refresh_timer_interval);
|
||||
|
||||
if ( _refresh_timer_interval > 0 )
|
||||
{
|
||||
Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d)", _refresh_timer.interval(), _latchTime_ms);
|
||||
_refresh_timer.setInterval(_latchTime_ms+10);
|
||||
}
|
||||
_refresh_enabled = true;
|
||||
|
||||
if (_refresh_timer_interval <= _latchTime_ms )
|
||||
{
|
||||
int new_refresh_timer_interval = _latchTime_ms + 10;
|
||||
Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d), set rewriteTime to %dms", _latchTime_ms, _refresh_timer_interval, new_refresh_timer_interval);
|
||||
_refresh_timer_interval = new_refresh_timer_interval;
|
||||
_refresh_timer->setInterval( _refresh_timer_interval );
|
||||
}
|
||||
|
||||
//Debug(_log, "Refresh interval = %dms",_refresh_timer_interval );
|
||||
_refresh_timer->setInterval( _refresh_timer_interval );
|
||||
|
||||
_last_write_time = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
this->startRefreshTimer();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int LedDevice::setLedValues(const std::vector<ColorRgb>& ledValues)
|
||||
void LedDevice::startRefreshTimer()
|
||||
{
|
||||
if ( _deviceReady)
|
||||
{
|
||||
_refresh_timer->start();
|
||||
}
|
||||
}
|
||||
|
||||
void LedDevice::stopRefreshTimer()
|
||||
{
|
||||
_refresh_timer->stop();
|
||||
}
|
||||
|
||||
int LedDevice::updateLeds(const std::vector<ColorRgb>& ledValues)
|
||||
{
|
||||
int retval = 0;
|
||||
if (!_deviceReady || !_enabled)
|
||||
if ( !_deviceReady )
|
||||
{
|
||||
std::cout << "LedDevice::updateLeds(), LedDevice NOT ready!" << std::endl;
|
||||
return -1;
|
||||
|
||||
|
||||
// restart the timer
|
||||
if (_refresh_timer.interval() > 0)
|
||||
{
|
||||
_refresh_timer.start();
|
||||
}
|
||||
|
||||
if (_latchTime_ms == 0 || QDateTime::currentMSecsSinceEpoch()-_last_write_time >= _latchTime_ms)
|
||||
else
|
||||
{
|
||||
_ledValues = ledValues;
|
||||
retval = write(ledValues);
|
||||
_last_write_time = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
//else Debug(_log, "latch %d", QDateTime::currentMSecsSinceEpoch()-_last_write_time);
|
||||
qint64 elapsedTime = QDateTime::currentMSecsSinceEpoch() - _last_write_time;
|
||||
if (_latchTime_ms == 0 || elapsedTime >= _latchTime_ms)
|
||||
{
|
||||
//std::cout << "LedDevice::updateLeds(), Elapsed time since last write (" << elapsedTime << ") ms > _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
|
||||
retval = write(ledValues);
|
||||
_last_write_time = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
// if device requires refreshing, save Led-Values and restart the timer
|
||||
if ( _refresh_enabled )
|
||||
{
|
||||
this->startRefreshTimer();
|
||||
_last_ledValues = ledValues;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::cout << "LedDevice::updateLeds(), Skip write. _latchTime_ms (" << _latchTime_ms << ") ms > elapsedTime (" << elapsedTime << ") ms" << std::endl;
|
||||
if ( _refresh_enabled )
|
||||
{
|
||||
//Stop timer to allow for next non-refresh update
|
||||
this->stopRefreshTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDevice::writeBlack()
|
||||
{
|
||||
return _deviceReady ? write(std::vector<ColorRgb>(_ledCount, ColorRgb::BLACK )) : -1;
|
||||
return _deviceReady ? updateLeds(std::vector<ColorRgb>(static_cast<unsigned long>(_ledCount), ColorRgb::BLACK )) : -1;
|
||||
}
|
||||
|
||||
int LedDevice::switchOff()
|
||||
{
|
||||
// Stop refresh timer to ensure that "write Black" is executed
|
||||
this->stopRefreshTimer();
|
||||
|
||||
if ( _latchTime_ms > 0 )
|
||||
{
|
||||
// Wait latchtime before writing black
|
||||
QEventLoop loop;
|
||||
QTimer::singleShot( _latchTime_ms, &loop, SLOT( quit() ) );
|
||||
loop.exec();
|
||||
}
|
||||
int rc = writeBlack();
|
||||
return rc;
|
||||
}
|
||||
@ -124,7 +206,7 @@ int LedDevice::switchOn()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LedDevice::setLedCount(int ledCount)
|
||||
void LedDevice::setLedCount(unsigned int ledCount)
|
||||
{
|
||||
_ledCount = ledCount;
|
||||
_ledRGBCount = _ledCount * sizeof(ColorRgb);
|
||||
@ -133,6 +215,35 @@ void LedDevice::setLedCount(int ledCount)
|
||||
|
||||
int LedDevice::rewriteLeds()
|
||||
{
|
||||
return _enabled ? write(_ledValues) : -1;
|
||||
int retval = -1;
|
||||
|
||||
if ( _deviceReady )
|
||||
{
|
||||
//qint64 elapsedTime = QDateTime::currentMSecsSinceEpoch() - _last_write_time;
|
||||
//std::cout << "LedDevice::rewriteLeds(): Rewrite Leds now, elapsedTime [" << elapsedTime << "] ms" << std::endl;
|
||||
// //:TESTING: Inject "white" output records to differentiate from normal writes
|
||||
// _last_ledValues.clear();
|
||||
// _last_ledValues.resize(static_cast<unsigned long>(_ledCount), ColorRgb::WHITE);
|
||||
// printLedValues(_last_ledValues);
|
||||
// //:TESTING:
|
||||
|
||||
retval = write(_last_ledValues);
|
||||
_last_write_time = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If Device is not ready stop timer
|
||||
this->stopRefreshTimer();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDevice::printLedValues(const std::vector<ColorRgb>& ledValues )
|
||||
{
|
||||
std::cout << "LedValues [" << ledValues.size() <<"] [";
|
||||
for (const ColorRgb& color : ledValues)
|
||||
{
|
||||
std::cout << color;
|
||||
}
|
||||
std::cout << "]" << std::endl;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ LedDevice * LedDeviceFactory::construct(const QJsonObject & deviceConfig)
|
||||
if (dev.first == type)
|
||||
{
|
||||
device = dev.second(deviceConfig);
|
||||
Info(log,"LedDevice '%s' configured.", QSTRING_CSTR(dev.first));
|
||||
Info(log,"LedDevice '%s' found.", QSTRING_CSTR(dev.first));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
87
libsrc/leddevice/LedDeviceTemplate.cpp
Normal file
87
libsrc/leddevice/LedDeviceTemplate.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include "LedDeviceTemplate.h"
|
||||
|
||||
LedDeviceTemplate::LedDeviceTemplate(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDeviceTemplate::~LedDeviceTemplate()
|
||||
{
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceTemplate::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceTemplate(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceTemplate::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
// Initiatiale LedDevice configuration and execution environment
|
||||
// ...
|
||||
if ( 0 /*Error during init*/)
|
||||
{
|
||||
//Build an errortext, illustrative
|
||||
QString errortext = QString ("Error message: %1").arg("errno/text");
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceTemplate::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
// Open/Start LedDevice based on configuration
|
||||
//...
|
||||
|
||||
if ( false /*If opening failed*/ )
|
||||
{
|
||||
//Build an errortext, illustrative
|
||||
errortext = QString ("Failed to xxx. Error message: %1").arg("errno/text");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDeviceTemplate::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
// LedDevice specific closing activites
|
||||
//...
|
||||
}
|
||||
|
||||
int LedDeviceTemplate::write(const std::vector<ColorRgb> & ledValues)
|
||||
{
|
||||
int retval = -1;
|
||||
|
||||
//...
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
60
libsrc/leddevice/LedDeviceTemplate.h
Normal file
60
libsrc/leddevice/LedDeviceTemplate.h
Normal file
@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
|
||||
///
|
||||
/// Implementation of a LedDevice ...
|
||||
/// ...
|
||||
///
|
||||
class LedDeviceTemplate : public LedDevice
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
explicit LedDeviceTemplate(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Destructor of this LedDevice
|
||||
///
|
||||
virtual ~LedDeviceTemplate() override;
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
/// Writes the led color values to the led-device
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
//////
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
};
|
@ -20,7 +20,7 @@ LedDeviceWrapper::LedDeviceWrapper(Hyperion* hyperion)
|
||||
: QObject(hyperion)
|
||||
, _hyperion(hyperion)
|
||||
, _ledDevice(nullptr)
|
||||
, _enabled(true)
|
||||
, _enabled(false)
|
||||
{
|
||||
// prepare the device constrcutor map
|
||||
#define REGISTER(className) LedDeviceWrapper::addToDeviceMap(QString(#className).toLower(), LedDevice##className::construct);
|
||||
@ -30,7 +30,7 @@ LedDeviceWrapper::LedDeviceWrapper(Hyperion* hyperion)
|
||||
|
||||
#undef REGISTER
|
||||
|
||||
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, true);
|
||||
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, false);
|
||||
}
|
||||
|
||||
LedDeviceWrapper::~LedDeviceWrapper()
|
||||
@ -55,8 +55,11 @@ void LedDeviceWrapper::createLedDevice(const QJsonObject& config)
|
||||
connect(thread, &QThread::finished, _ledDevice, &LedDevice::deleteLater);
|
||||
|
||||
// further signals
|
||||
connect(this, &LedDeviceWrapper::write, _ledDevice, &LedDevice::write, Qt::QueuedConnection);
|
||||
connect(_hyperion->getMuxerInstance(), &PriorityMuxer::visiblePriorityChanged, _ledDevice, &LedDevice::visiblePriorityChanged, Qt::QueuedConnection);
|
||||
connect(this, &LedDeviceWrapper::updateLeds, _ledDevice, &LedDevice::updateLeds, Qt::QueuedConnection);
|
||||
connect(this, &LedDeviceWrapper::setEnable, _ledDevice, &LedDevice::setEnable);
|
||||
|
||||
connect(this, &LedDeviceWrapper::closeLedDevice, _ledDevice, &LedDevice::close, Qt::BlockingQueuedConnection);
|
||||
|
||||
connect(_ledDevice, &LedDevice::enableStateChanged, this, &LedDeviceWrapper::handleInternalEnableState, Qt::QueuedConnection);
|
||||
|
||||
// start the thread
|
||||
@ -125,13 +128,21 @@ const QString & LedDeviceWrapper::getColorOrder()
|
||||
return _ledDevice->getColorOrder();
|
||||
}
|
||||
|
||||
unsigned int LedDeviceWrapper::getLedCount() const
|
||||
{
|
||||
return _ledDevice->getLedCount();
|
||||
}
|
||||
|
||||
void LedDeviceWrapper::handleComponentState(const hyperion::Components component, const bool state)
|
||||
{
|
||||
if(component == hyperion::COMP_LEDDEVICE)
|
||||
{
|
||||
_ledDevice->setEnable(state);
|
||||
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, _ledDevice->componentState());
|
||||
_enabled = state;
|
||||
emit setEnable(state);
|
||||
|
||||
//Get device's state, considering situations where it is not ready
|
||||
bool deviceState = _ledDevice->componentState();
|
||||
_hyperion->setNewComponentState(hyperion::COMP_LEDDEVICE, deviceState);
|
||||
_enabled = deviceState;
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,17 +154,18 @@ void LedDeviceWrapper::handleInternalEnableState(bool newState)
|
||||
|
||||
void LedDeviceWrapper::stopDeviceThread()
|
||||
{
|
||||
// turns the leds off
|
||||
_ledDevice->switchOff();
|
||||
// turns the leds off & stop refresh timers
|
||||
emit closeLedDevice();
|
||||
std::cout << "[hyperiond LedDeviceWrapper] <INFO> LedDevice \'" << QSTRING_CSTR(_ledDevice->getActiveDeviceType()) << "\' closed" << std::endl;
|
||||
|
||||
// get current thread
|
||||
QThread* oldThread = _ledDevice->thread();
|
||||
disconnect(oldThread, 0, 0, 0);
|
||||
disconnect(oldThread, nullptr, nullptr, nullptr);
|
||||
oldThread->quit();
|
||||
oldThread->wait();
|
||||
delete oldThread;
|
||||
|
||||
disconnect(_ledDevice, 0, 0, 0);
|
||||
disconnect(_ledDevice, nullptr, nullptr, nullptr);
|
||||
delete _ledDevice;
|
||||
_ledDevice = nullptr;
|
||||
}
|
||||
|
@ -16,11 +16,108 @@ LedDeviceHyperionUsbasp::LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig
|
||||
, _libusbContext(nullptr)
|
||||
, _deviceHandle(nullptr)
|
||||
{
|
||||
init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDeviceHyperionUsbasp::~LedDeviceHyperionUsbasp()
|
||||
{
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceHyperionUsbasp::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceHyperionUsbasp(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceHyperionUsbasp::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
QString ledType = deviceConfig["ledType"].toString("ws2801");
|
||||
if (ledType != "ws2801" && ledType != "ws2812")
|
||||
{
|
||||
QString errortext = QString ("Invalid ledType; must be 'ws2801' or 'ws2812'.");
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_writeLedsCommand = (ledType == "ws2801") ? CMD_WRITE_WS2801 : CMD_WRITE_WS2812;
|
||||
}
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceHyperionUsbasp::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
int error;
|
||||
|
||||
// initialize the usb context
|
||||
if ((error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS)
|
||||
{
|
||||
//Error(_log, "Error while initializing USB context(%d):%s", error, libusb_error_name(error));
|
||||
errortext = QString ("Error while initializing USB context(%1):%2").arg( error).arg(libusb_error_name(error));
|
||||
_libusbContext = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
//libusb_set_debug(_libusbContext, 3);
|
||||
Debug(_log, "USB context initialized");
|
||||
|
||||
// retrieve the list of usb devices
|
||||
libusb_device ** deviceList;
|
||||
ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
|
||||
|
||||
// iterate the list of devices
|
||||
for (ssize_t i = 0 ; i < deviceCount; ++i)
|
||||
{
|
||||
// try to open and initialize the device
|
||||
error = testAndOpen(deviceList[i]);
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
// a device was sucessfully opened. break from list
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// free the device list
|
||||
libusb_free_device_list(deviceList, 1);
|
||||
|
||||
if (_deviceHandle == nullptr)
|
||||
{
|
||||
//Error(_log, "No %s has been found", QSTRING_CSTR(_usbProductDescription));
|
||||
errortext = QString ("No %1 has been found").arg( _usbProductDescription);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDeviceHyperionUsbasp::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
// LedDevice specific closing activites
|
||||
if (_deviceHandle != nullptr)
|
||||
{
|
||||
libusb_release_interface(_deviceHandle, 0);
|
||||
@ -37,69 +134,6 @@ LedDeviceHyperionUsbasp::~LedDeviceHyperionUsbasp()
|
||||
}
|
||||
}
|
||||
|
||||
bool LedDeviceHyperionUsbasp::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
LedDevice::init(deviceConfig);
|
||||
|
||||
QString ledType = deviceConfig["ledType"].toString("ws2801");
|
||||
if (ledType != "ws2801" && ledType != "ws2812")
|
||||
{
|
||||
throw std::runtime_error("HyperionUsbasp: invalid ledType; must be 'ws2801' or 'ws2812'.");
|
||||
}
|
||||
|
||||
_writeLedsCommand = (ledType == "ws2801") ? CMD_WRITE_WS2801 : CMD_WRITE_WS2812;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceHyperionUsbasp::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceHyperionUsbasp(deviceConfig);
|
||||
}
|
||||
|
||||
|
||||
int LedDeviceHyperionUsbasp::open()
|
||||
{
|
||||
int error;
|
||||
|
||||
// initialize the usb context
|
||||
if ((error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS)
|
||||
{
|
||||
Error(_log, "Error while initializing USB context(%d):%s", error, libusb_error_name(error));
|
||||
_libusbContext = nullptr;
|
||||
return -1;
|
||||
}
|
||||
//libusb_set_debug(_libusbContext, 3);
|
||||
Debug(_log, "USB context initialized");
|
||||
|
||||
// retrieve the list of usb devices
|
||||
libusb_device ** deviceList;
|
||||
ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
|
||||
|
||||
// iterate the list of devices
|
||||
for (ssize_t i = 0 ; i < deviceCount; ++i)
|
||||
{
|
||||
// try to open and initialize the device
|
||||
error = testAndOpen(deviceList[i]);
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
// a device was sucessfully opened. break from list
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// free the device list
|
||||
libusb_free_device_list(deviceList, 1);
|
||||
|
||||
if (_deviceHandle == nullptr)
|
||||
{
|
||||
Error(_log, "No %s has been found", QSTRING_CSTR(_usbProductDescription));
|
||||
}
|
||||
|
||||
return _deviceHandle == nullptr ? -1 : 0;
|
||||
}
|
||||
|
||||
int LedDeviceHyperionUsbasp::testAndOpen(libusb_device * device)
|
||||
{
|
||||
libusb_device_descriptor deviceDescriptor;
|
||||
@ -121,6 +155,7 @@ int LedDeviceHyperionUsbasp::testAndOpen(libusb_device * device)
|
||||
|
||||
Info(_log, "%s found: bus=%d address=%d", QSTRING_CSTR(_usbProductDescription), busNumber, addressNumber);
|
||||
|
||||
// TODO: Check, if exceptions via try/catch need to be replaced in Qt environment
|
||||
try
|
||||
{
|
||||
_deviceHandle = openDevice(device);
|
||||
|
@ -27,14 +27,14 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
@ -42,16 +42,23 @@ public:
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
///
|
||||
virtual ~LedDeviceHyperionUsbasp();
|
||||
virtual ~LedDeviceHyperionUsbasp() override;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Opens and configures the output device
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
int open();
|
||||
int open() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Writes the RGB-Color values to the leds.
|
||||
///
|
||||
@ -59,7 +66,7 @@ protected:
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues);
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues) override;
|
||||
|
||||
///
|
||||
/// Test if the device is a Hyperion Usbasp device
|
||||
|
@ -43,16 +43,118 @@ LedDeviceLightpack::LedDeviceLightpack(const QString & serialNumber)
|
||||
, _bitsPerChannel(-1)
|
||||
, _hwLedCount(-1)
|
||||
{
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDeviceLightpack::LedDeviceLightpack(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
, _libusbContext(nullptr)
|
||||
, _deviceHandle(nullptr)
|
||||
, _busNumber(-1)
|
||||
, _addressNumber(-1)
|
||||
, _firmwareVersion({-1,-1})
|
||||
, _bitsPerChannel(-1)
|
||||
, _hwLedCount(-1)
|
||||
{
|
||||
init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDeviceLightpack::~LedDeviceLightpack()
|
||||
{
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceLightpack::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceLightpack(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceLightpack::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
_serialNumber = deviceConfig["output"].toString("");
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceLightpack::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
int error;
|
||||
|
||||
// initialize the usb context
|
||||
if ((error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS)
|
||||
{
|
||||
//Error(_log, "Error while initializing USB context(%d): %s", error, libusb_error_name(error));
|
||||
errortext = QString ("Error while initializing USB context(%1):%2").arg( error).arg(libusb_error_name(error));
|
||||
_libusbContext = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
//libusb_set_debug(_libusbContext, 3);
|
||||
Debug(_log, "USB context initialized");
|
||||
|
||||
// retrieve the list of usb devices
|
||||
libusb_device ** deviceList;
|
||||
ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
|
||||
|
||||
// iterate the list of devices
|
||||
for (ssize_t i = 0 ; i < deviceCount; ++i)
|
||||
{
|
||||
// try to open and initialize the device
|
||||
error = testAndOpen(deviceList[i], _serialNumber);
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
// a device was sucessfully opened. break from list
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// free the device list
|
||||
libusb_free_device_list(deviceList, 1);
|
||||
|
||||
if (_deviceHandle == nullptr)
|
||||
{
|
||||
if (_serialNumber.isEmpty())
|
||||
{
|
||||
//Warning(_log, "No Lightpack device has been found");
|
||||
errortext = QString ("No Lightpack devices were found");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Error(_log,"No Lightpack device has been found with serial %", QSTRING_CSTR(_serialNumber));
|
||||
errortext = QString ("No Lightpack device has been found with serial %1").arg( _serialNumber);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDeviceLightpack::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
// LedDevice specific closing activites
|
||||
if (_deviceHandle != nullptr)
|
||||
{
|
||||
libusb_release_interface(_deviceHandle, LIGHTPACK_INTERFACE);
|
||||
@ -69,68 +171,6 @@ LedDeviceLightpack::~LedDeviceLightpack()
|
||||
}
|
||||
}
|
||||
|
||||
bool LedDeviceLightpack::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
LedDevice::init(deviceConfig);
|
||||
_serialNumber = deviceConfig["output"].toString("");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceLightpack::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceLightpack(deviceConfig);
|
||||
}
|
||||
|
||||
int LedDeviceLightpack::open()
|
||||
{
|
||||
int error;
|
||||
|
||||
// initialize the usb context
|
||||
if ((error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS)
|
||||
{
|
||||
Error(_log, "Error while initializing USB context(%d): %s", error, libusb_error_name(error));
|
||||
_libusbContext = nullptr;
|
||||
return -1;
|
||||
}
|
||||
//libusb_set_debug(_libusbContext, 3);
|
||||
Debug(_log, "USB context initialized");
|
||||
|
||||
// retrieve the list of usb devices
|
||||
libusb_device ** deviceList;
|
||||
ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
|
||||
|
||||
// iterate the list of devices
|
||||
for (ssize_t i = 0 ; i < deviceCount; ++i)
|
||||
{
|
||||
// try to open and initialize the device
|
||||
error = testAndOpen(deviceList[i], _serialNumber);
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
// a device was sucessfully opened. break from list
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// free the device list
|
||||
libusb_free_device_list(deviceList, 1);
|
||||
|
||||
if (_deviceHandle == nullptr)
|
||||
{
|
||||
if (_serialNumber.isEmpty())
|
||||
{
|
||||
Warning(_log, "No Lightpack device has been found");
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(_log,"No Lightpack device has been found with serial %s", QSTRING_CSTR(_serialNumber));
|
||||
}
|
||||
}
|
||||
|
||||
return _deviceHandle == nullptr ? -1 : 0;
|
||||
}
|
||||
|
||||
int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requestedSerialNumber)
|
||||
{
|
||||
libusb_device_descriptor deviceDescriptor;
|
||||
@ -154,6 +194,7 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
|
||||
QString serialNumber;
|
||||
if (deviceDescriptor.iSerialNumber != 0)
|
||||
{
|
||||
// TODO: Check, if exceptions via try/catch need to be replaced in Qt environment
|
||||
try
|
||||
{
|
||||
serialNumber = LedDeviceLightpack::getString(device, deviceDescriptor.iSerialNumber);
|
||||
@ -171,6 +212,7 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
|
||||
if (requestedSerialNumber.isEmpty() || requestedSerialNumber == serialNumber)
|
||||
{
|
||||
// This is it!
|
||||
// TODO: Check, if exceptions via try/catch need to be replaced in Qt environment
|
||||
try
|
||||
{
|
||||
_deviceHandle = openDevice(device);
|
||||
@ -252,7 +294,7 @@ int LedDeviceLightpack::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
||||
int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
|
||||
{
|
||||
int count = qMin(_hwLedCount, _ledCount);
|
||||
int count = qMin(_hwLedCount, static_cast<int>( _ledCount));
|
||||
|
||||
for (int i = 0; i < count ; ++i)
|
||||
{
|
||||
@ -275,8 +317,13 @@ int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
|
||||
|
||||
int LedDeviceLightpack::switchOff()
|
||||
{
|
||||
unsigned char buf[1] = {CMD_OFF_ALL};
|
||||
return writeBytes(buf, sizeof(buf)) == sizeof(buf);
|
||||
int rc = LedDevice::switchOff();
|
||||
if ( _deviceReady )
|
||||
{
|
||||
unsigned char buf[1] = {CMD_OFF_ALL};
|
||||
rc = writeBytes(buf, sizeof(buf)) == sizeof(buf);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
const QString &LedDeviceLightpack::getSerialNumber() const
|
||||
@ -284,11 +331,6 @@ const QString &LedDeviceLightpack::getSerialNumber() const
|
||||
return _serialNumber;
|
||||
}
|
||||
|
||||
int LedDeviceLightpack::getLedCount() const
|
||||
{
|
||||
return _ledCount;
|
||||
}
|
||||
|
||||
int LedDeviceLightpack::writeBytes(uint8_t *data, int size)
|
||||
{
|
||||
// std::cout << "Writing " << size << " bytes: ";
|
||||
|
@ -26,14 +26,14 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceLightpack(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceLightpack(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
@ -41,14 +41,14 @@ public:
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
///
|
||||
virtual ~LedDeviceLightpack();
|
||||
virtual ~LedDeviceLightpack() override;
|
||||
|
||||
///
|
||||
/// Opens and configures the output device
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
int open();
|
||||
int open() override;
|
||||
|
||||
///
|
||||
/// Writes the RGB-Color values to the leds.
|
||||
@ -65,13 +65,19 @@ public:
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int switchOff();
|
||||
virtual int switchOff() override;
|
||||
|
||||
/// Get the serial of the Lightpack
|
||||
const QString & getSerialNumber() const;
|
||||
|
||||
/// Get the number of leds
|
||||
int getLedCount() const;
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
///
|
||||
|
@ -21,7 +21,8 @@ LedDeviceMultiLightpack::LedDeviceMultiLightpack(const QJsonObject &deviceConfig
|
||||
: LedDevice()
|
||||
, _lightpacks()
|
||||
{
|
||||
LedDevice::init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDeviceMultiLightpack::~LedDeviceMultiLightpack()
|
||||
@ -39,39 +40,58 @@ LedDevice* LedDeviceMultiLightpack::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
int LedDeviceMultiLightpack::open()
|
||||
{
|
||||
// retrieve a list with Lightpack serials
|
||||
QStringList serialList = getLightpackSerials();
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
// sort the list of Lightpacks based on the serial to get a fixed order
|
||||
std::sort(_lightpacks.begin(), _lightpacks.end(), compareLightpacks);
|
||||
|
||||
// open each lightpack device
|
||||
foreach (auto serial , serialList)
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
LedDeviceLightpack * device = new LedDeviceLightpack(serial);
|
||||
int error = device->open();
|
||||
// retrieve a list with Lightpack serials
|
||||
QStringList serialList = getLightpackSerials();
|
||||
|
||||
if (error == 0)
|
||||
// sort the list of Lightpacks based on the serial to get a fixed order
|
||||
std::sort(_lightpacks.begin(), _lightpacks.end(), compareLightpacks);
|
||||
|
||||
// open each lightpack device
|
||||
foreach (auto serial , serialList)
|
||||
{
|
||||
_lightpacks.push_back(device);
|
||||
LedDeviceLightpack * device = new LedDeviceLightpack(serial);
|
||||
int error = device->open();
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
_lightpacks.push_back(device);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Error(_log, "Error while creating Lightpack device with serial %s", QSTRING_CSTR(serial));
|
||||
errortext = QString ("Error while creating Lightpack device with serial %1").arg( serial );
|
||||
delete device;
|
||||
}
|
||||
}
|
||||
|
||||
if (_lightpacks.size() == 0)
|
||||
{
|
||||
//Warning(_log, "No Lightpack devices were found");
|
||||
errortext = QString ("No Lightpack devices were found");
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(_log, "Error while creating Lightpack device with serial %s", QSTRING_CSTR(serial));
|
||||
delete device;
|
||||
Info(_log, "%d Lightpack devices were found", _lightpacks.size());
|
||||
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
}
|
||||
|
||||
if (_lightpacks.size() == 0)
|
||||
{
|
||||
Warning(_log, "No Lightpack devices were found");
|
||||
}
|
||||
else
|
||||
{
|
||||
Info(_log, "%d Lightpack devices were found", _lightpacks.size());
|
||||
}
|
||||
|
||||
return _lightpacks.size() > 0 ? 0 : -1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
|
||||
@ -81,7 +101,7 @@ int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
||||
for (LedDeviceLightpack * device : _lightpacks)
|
||||
{
|
||||
int count = qMin(device->getLedCount(), size);
|
||||
int count = qMin(static_cast<int>( device->getLedCount()), size);
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
@ -151,6 +171,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
|
||||
QString serialNumber;
|
||||
if (deviceDescriptor.iSerialNumber != 0)
|
||||
{
|
||||
// TODO: Check, if exceptions via try/catch need to be replaced in Qt environment
|
||||
try
|
||||
{
|
||||
serialNumber = LedDeviceMultiLightpack::getString(deviceList[i], deviceDescriptor.iSerialNumber);
|
||||
|
@ -22,29 +22,30 @@ public:
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
///
|
||||
LedDeviceMultiLightpack(const QJsonObject &);
|
||||
explicit LedDeviceMultiLightpack(const QJsonObject &);
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
///
|
||||
virtual ~LedDeviceMultiLightpack();
|
||||
virtual ~LedDeviceMultiLightpack() override;
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
virtual int switchOff() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Opens and configures the output device7
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
int open();
|
||||
|
||||
int open() override;
|
||||
///
|
||||
/// Switch the leds off
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int switchOff();
|
||||
|
||||
private:
|
||||
///
|
||||
@ -54,7 +55,7 @@ private:
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues);
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues) override;
|
||||
|
||||
static QStringList getLightpackSerials();
|
||||
static QString getString(libusb_device * device, int stringDescriptorIndex);
|
||||
|
@ -4,12 +4,10 @@
|
||||
LedDevicePaintpack::LedDevicePaintpack(const QJsonObject &deviceConfig)
|
||||
: ProviderHID()
|
||||
{
|
||||
ProviderHID::init(deviceConfig);
|
||||
_useFeature = false;
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
|
||||
_ledBuffer.resize(_ledRGBCount + 2, uint8_t(0));
|
||||
_ledBuffer[0] = 3;
|
||||
_ledBuffer[1] = 0;
|
||||
_useFeature = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDevicePaintpack::construct(const QJsonObject &deviceConfig)
|
||||
@ -17,6 +15,17 @@ LedDevice* LedDevicePaintpack::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDevicePaintpack(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDevicePaintpack::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderHID::init(deviceConfig);
|
||||
|
||||
_ledBuffer.resize(_ledRGBCount + 2, uint8_t(0));
|
||||
_ledBuffer[0] = 3;
|
||||
_ledBuffer[1] = 0;
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDevicePaintpack::write(const std::vector<ColorRgb> & ledValues)
|
||||
{
|
||||
auto bufIt = _ledBuffer.begin()+2;
|
||||
|
@ -14,11 +14,18 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDevicePaintpack(const QJsonObject &deviceConfig);
|
||||
explicit LedDevicePaintpack(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the RGB-Color values to the leds.
|
||||
@ -27,5 +34,5 @@ private:
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues);
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues) override;
|
||||
};
|
||||
|
@ -4,9 +4,10 @@
|
||||
LedDeviceRawHID::LedDeviceRawHID(const QJsonObject &deviceConfig)
|
||||
: ProviderHID()
|
||||
{
|
||||
ProviderHID::init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
|
||||
_useFeature = true;
|
||||
_ledBuffer.resize(_ledRGBCount);
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceRawHID::construct(const QJsonObject &deviceConfig)
|
||||
@ -14,14 +15,18 @@ LedDevice* LedDeviceRawHID::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceRawHID(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceRawHID::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderHID::init(deviceConfig);
|
||||
|
||||
_ledBuffer.resize(_ledRGBCount);
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceRawHID::write(const std::vector<ColorRgb> & ledValues)
|
||||
{
|
||||
// write data
|
||||
memcpy(_ledBuffer.data(), ledValues.data(), _ledRGBCount);
|
||||
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
|
||||
}
|
||||
|
||||
void LedDeviceRawHID::rewriteLeds()
|
||||
{
|
||||
writeBytes(_ledBuffer.size(), _ledBuffer.data());
|
||||
}
|
||||
|
@ -18,14 +18,17 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceRawHID(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceRawHID(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
private slots:
|
||||
/// Write the last data to the leds again
|
||||
void rewriteLeds();
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -34,5 +37,5 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
};
|
||||
|
@ -10,26 +10,22 @@
|
||||
#include "ProviderHID.h"
|
||||
|
||||
ProviderHID::ProviderHID()
|
||||
: _useFeature(false)
|
||||
, _deviceHandle(nullptr)
|
||||
, _blockedForDelay(false)
|
||||
: _VendorId(0)
|
||||
, _ProductId(0)
|
||||
, _useFeature(false)
|
||||
, _deviceHandle(nullptr)
|
||||
, _delayAfterConnect_ms (0)
|
||||
, _blockedForDelay(false)
|
||||
{
|
||||
}
|
||||
|
||||
ProviderHID::~ProviderHID()
|
||||
{
|
||||
if (_deviceHandle != nullptr)
|
||||
{
|
||||
hid_close(_deviceHandle);
|
||||
_deviceHandle = nullptr;
|
||||
}
|
||||
|
||||
hid_exit();
|
||||
}
|
||||
|
||||
bool ProviderHID::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
LedDevice::init(deviceConfig);
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
_delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(0);
|
||||
auto VendorIdString = deviceConfig["VID"].toString("0x2341").toStdString();
|
||||
@ -39,64 +35,94 @@ bool ProviderHID::init(const QJsonObject &deviceConfig)
|
||||
_VendorId = std::stoul(VendorIdString, nullptr, 16);
|
||||
_ProductId = std::stoul(ProductIdString, nullptr, 16);
|
||||
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int ProviderHID::open()
|
||||
{
|
||||
// Initialize the usb context
|
||||
int error = hid_init();
|
||||
if (error != 0)
|
||||
{
|
||||
Error(_log, "Error while initializing the hidapi context");
|
||||
return -1;
|
||||
}
|
||||
Debug(_log,"Hidapi initialized");
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
// Open the device
|
||||
Info(_log, "Opening device: VID %04hx PID %04hx\n", _VendorId, _ProductId);
|
||||
_deviceHandle = hid_open(_VendorId, _ProductId, nullptr);
|
||||
|
||||
if (_deviceHandle == nullptr)
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
// Failed to open the device
|
||||
Error(_log,"Failed to open HID device. Maybe your PID/VID setting is wrong? Make sure to add a udev rule/use sudo.");
|
||||
|
||||
// http://www.signal11.us/oss/hidapi/
|
||||
/*
|
||||
std::cout << "Showing a list of all available HID devices:" << std::endl;
|
||||
auto devs = hid_enumerate(0x00, 0x00);
|
||||
auto cur_dev = devs;
|
||||
while (cur_dev) {
|
||||
printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls",
|
||||
cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
|
||||
printf("\n");
|
||||
printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string);
|
||||
printf(" Product: %ls\n", cur_dev->product_string);
|
||||
printf("\n");
|
||||
cur_dev = cur_dev->next;
|
||||
// Initialize the usb context
|
||||
int error = hid_init();
|
||||
if (error != 0)
|
||||
{
|
||||
//Error(_log, "Error while initializing the hidapi context");
|
||||
errortext = "Error while initializing the hidapi context";
|
||||
}
|
||||
hid_free_enumeration(devs);
|
||||
*/
|
||||
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Info(_log,"Opened HID device successful");
|
||||
}
|
||||
|
||||
// Wait after device got opened if enabled
|
||||
if (_delayAfterConnect_ms > 0)
|
||||
{
|
||||
_blockedForDelay = true;
|
||||
QTimer::singleShot(_delayAfterConnect_ms, this, SLOT(unblockAfterDelay()));
|
||||
Debug(_log, "Device blocked for %d ms", _delayAfterConnect_ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug(_log,"Hidapi initialized");
|
||||
|
||||
return 0;
|
||||
// Open the device
|
||||
Info(_log, "Opening device: VID %04hx PID %04hx\n", _VendorId, _ProductId);
|
||||
_deviceHandle = hid_open(_VendorId, _ProductId, nullptr);
|
||||
|
||||
if (_deviceHandle == nullptr)
|
||||
{
|
||||
// Failed to open the device
|
||||
Error(_log,"Failed to open HID device. Maybe your PID/VID setting is wrong? Make sure to add a udev rule/use sudo.");
|
||||
errortext = "Failed to open HID device";
|
||||
|
||||
// http://www.signal11.us/oss/hidapi/
|
||||
/*
|
||||
std::cout << "Showing a list of all available HID devices:" << std::endl;
|
||||
auto devs = hid_enumerate(0x00, 0x00);
|
||||
auto cur_dev = devs;
|
||||
while (cur_dev) {
|
||||
printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls",
|
||||
cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
|
||||
printf("\n");
|
||||
printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string);
|
||||
printf(" Product: %ls\n", cur_dev->product_string);
|
||||
printf("\n");
|
||||
cur_dev = cur_dev->next;
|
||||
}
|
||||
hid_free_enumeration(devs);
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
Info(_log,"Opened HID device successful");
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
// Wait after device got opened if enabled
|
||||
if (_delayAfterConnect_ms > 0)
|
||||
{
|
||||
_blockedForDelay = true;
|
||||
QTimer::singleShot(_delayAfterConnect_ms, this, SLOT(unblockAfterDelay()));
|
||||
Debug(_log, "Device blocked for %d ms", _delayAfterConnect_ms);
|
||||
}
|
||||
}
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ProviderHID::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
// LedDevice specific closing activites
|
||||
if (_deviceHandle != nullptr)
|
||||
{
|
||||
hid_close(_deviceHandle);
|
||||
_deviceHandle = nullptr;
|
||||
}
|
||||
|
||||
hid_exit();
|
||||
}
|
||||
|
||||
int ProviderHID::writeBytes(const unsigned size, const uint8_t * data)
|
||||
{
|
||||
|
@ -24,22 +24,30 @@ public:
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
///
|
||||
virtual ~ProviderHID();
|
||||
virtual ~ProviderHID() override;
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Opens and configures the output device
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
int open();
|
||||
protected:
|
||||
int open() override;
|
||||
|
||||
/**
|
||||
* Writes the given bytes to the HID-device and
|
||||
*
|
||||
|
@ -242,11 +242,6 @@ const std::string &LedDeviceLightpackHidapi::getSerialNumber() const
|
||||
return _serialNumber;
|
||||
}
|
||||
|
||||
int LedDeviceLightpackHidapi::getLedCount() const
|
||||
{
|
||||
return _ledCount;
|
||||
}
|
||||
|
||||
int LedDeviceLightpackHidapi::writeBytes(uint8_t *data, int size)
|
||||
{
|
||||
// std::cout << "Writing " << size << " bytes: ";
|
||||
|
@ -57,9 +57,6 @@ public:
|
||||
/// Get the serial of the Lightpack
|
||||
const std::string & getSerialNumber() const;
|
||||
|
||||
/// Get the number of leds
|
||||
int getLedCount() const;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the RGB-Color values to the leds.
|
||||
|
@ -2,58 +2,105 @@
|
||||
#include "LedDeviceAtmoOrb.h"
|
||||
|
||||
// qt includes
|
||||
#include <QtCore/qmath.h>
|
||||
#include <QEventLoop>
|
||||
#include <QtNetwork>
|
||||
#include <QNetworkReply>
|
||||
#include <QStringList>
|
||||
|
||||
AtmoOrbLight::AtmoOrbLight(unsigned int id)
|
||||
{
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
LedDeviceAtmoOrb::LedDeviceAtmoOrb(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
, _networkmanager (nullptr)
|
||||
, _udpSocket (nullptr)
|
||||
, _multiCastGroupPort (49692)
|
||||
, joinedMulticastgroup (false)
|
||||
, _useOrbSmoothing (false)
|
||||
, _transitiontime (0)
|
||||
, _skipSmoothingDiff (0)
|
||||
, _numLeds (24)
|
||||
|
||||
{
|
||||
init(deviceConfig);
|
||||
_manager = new QNetworkAccessManager();
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceAtmoOrb::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceAtmoOrb(deviceConfig);
|
||||
}
|
||||
|
||||
LedDeviceAtmoOrb::~LedDeviceAtmoOrb()
|
||||
{
|
||||
_networkmanager->deleteLater();
|
||||
_udpSocket->deleteLater();
|
||||
}
|
||||
|
||||
bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
if ( isInitOK )
|
||||
{
|
||||
|
||||
_multicastGroup = deviceConfig["output"].toString().toStdString().c_str();
|
||||
_useOrbSmoothing = deviceConfig["useOrbSmoothing"].toBool(false);
|
||||
_transitiontime = deviceConfig["transitiontime"].toInt(0);
|
||||
_skipSmoothingDiff = deviceConfig["skipSmoothingDiff"].toInt(0);
|
||||
_multiCastGroupPort = static_cast<quint16>(deviceConfig["port"].toInt(49692));
|
||||
_numLeds = deviceConfig["numLeds"].toInt(24);
|
||||
|
||||
const QStringList orbIds = deviceConfig["orbIds"].toString().simplified().remove(" ").split(",", QString::SkipEmptyParts);
|
||||
_orbIds.clear();
|
||||
|
||||
foreach(auto & id_str, orbIds)
|
||||
{
|
||||
bool ok;
|
||||
int id = id_str.toInt(&ok);
|
||||
if (ok)
|
||||
_orbIds.append(id);
|
||||
else
|
||||
Error(_log, "orb id '%s' is not a number", QSTRING_CSTR(id_str));
|
||||
}
|
||||
|
||||
if ( _orbIds.size() == 0 )
|
||||
{
|
||||
this->setInError("No valid OrbIds found!");
|
||||
isInitOK = false;
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceAtmoOrb::initNetwork()
|
||||
{
|
||||
bool isInitOK = true;
|
||||
|
||||
// TODO: Add Network-Error handling
|
||||
_networkmanager = new QNetworkAccessManager();
|
||||
_groupAddress = QHostAddress(_multicastGroup);
|
||||
|
||||
_udpSocket = new QUdpSocket(this);
|
||||
_udpSocket->bind(QHostAddress::AnyIPv4, _multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
|
||||
|
||||
joinedMulticastgroup = _udpSocket->joinMulticastGroup(_groupAddress);
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
|
||||
int LedDeviceAtmoOrb::open()
|
||||
{
|
||||
_multicastGroup = deviceConfig["output"].toString().toStdString().c_str();
|
||||
_useOrbSmoothing = deviceConfig["useOrbSmoothing"].toBool(false);
|
||||
_transitiontime = deviceConfig["transitiontime"].toInt(0);
|
||||
_skipSmoothingDiff = deviceConfig["skipSmoothingDiff"].toInt(0);
|
||||
_multiCastGroupPort = deviceConfig["port"].toInt(49692);
|
||||
_numLeds = deviceConfig["numLeds"].toInt(24);
|
||||
|
||||
const QStringList orbIds = deviceConfig["orbIds"].toString().simplified().remove(" ").split(",", QString::SkipEmptyParts);
|
||||
_orbIds.clear();
|
||||
int retval = -1;
|
||||
_deviceReady = false;
|
||||
|
||||
foreach(auto & id_str, orbIds)
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
bool ok;
|
||||
int id = id_str.toInt(&ok);
|
||||
if (ok)
|
||||
_orbIds.append(id);
|
||||
if ( !initNetwork() )
|
||||
{
|
||||
this->setInError( "Network error!" );
|
||||
}
|
||||
else
|
||||
Error(_log, "orb id '%s' is not a number", QSTRING_CSTR(id_str));
|
||||
{
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return _orbIds.size() > 0;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceAtmoOrb::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceAtmoOrb(deviceConfig);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues)
|
||||
@ -79,7 +126,7 @@ int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues)
|
||||
|
||||
// Iterate through colors and set Orb color
|
||||
// Start off with idx 1 as 0 is reserved for controlling all orbs at once
|
||||
unsigned int idx = 1;
|
||||
int idx = 1;
|
||||
|
||||
for (const ColorRgb &color : ledValues)
|
||||
{
|
||||
@ -125,7 +172,7 @@ int LedDeviceAtmoOrb::write(const std::vector <ColorRgb> &ledValues)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LedDeviceAtmoOrb::setColor(unsigned int orbId, const ColorRgb &color, int commandType)
|
||||
void LedDeviceAtmoOrb::setColor(int orbId, const ColorRgb &color, int commandType)
|
||||
{
|
||||
QByteArray bytes;
|
||||
bytes.resize(5 + _numLeds * 3);
|
||||
@ -155,17 +202,3 @@ void LedDeviceAtmoOrb::sendCommand(const QByteArray &bytes)
|
||||
QByteArray datagram = bytes;
|
||||
_udpSocket->writeDatagram(datagram.data(), datagram.size(), _groupAddress, _multiCastGroupPort);
|
||||
}
|
||||
|
||||
int LedDeviceAtmoOrb::switchOff()
|
||||
{
|
||||
for (auto orbId : _orbIds)
|
||||
{
|
||||
setColor(orbId, ColorRgb::BLACK, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LedDeviceAtmoOrb::~LedDeviceAtmoOrb()
|
||||
{
|
||||
delete _manager;
|
||||
}
|
||||
|
@ -5,25 +5,13 @@
|
||||
#include <QString>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QHostAddress>
|
||||
#include <QMap>
|
||||
#include <QVector>
|
||||
|
||||
// Leddevice includes
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
|
||||
class QUdpSocket;
|
||||
|
||||
class AtmoOrbLight {
|
||||
public:
|
||||
unsigned int id;
|
||||
|
||||
///
|
||||
/// Constructs the light.
|
||||
///
|
||||
/// @param id the orb id
|
||||
AtmoOrbLight(unsigned int id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation for the AtmoOrb
|
||||
*
|
||||
@ -35,52 +23,87 @@ class LedDeviceAtmoOrb : public LedDevice
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
// Last send color map
|
||||
QMap<int, int> lastColorRedMap;
|
||||
QMap<int, int> lastColorGreenMap;
|
||||
QMap<int, int> lastColorBlueMap;
|
||||
|
||||
// Multicast status
|
||||
bool joinedMulticastgroup;
|
||||
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceAtmoOrb(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceAtmoOrb(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Destructor of this device
|
||||
///
|
||||
virtual ~LedDeviceAtmoOrb();
|
||||
virtual ~LedDeviceAtmoOrb() override;
|
||||
|
||||
virtual int switchOff();
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Initialise device's network details
|
||||
///
|
||||
/// @return True if success
|
||||
bool initNetwork();
|
||||
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Sends the given led-color values to the Orbs
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector <ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector <ColorRgb> &ledValues) override;
|
||||
|
||||
///
|
||||
/// Set Orbcolor
|
||||
///
|
||||
/// @param orbId the orb id
|
||||
/// @param color which color to set
|
||||
/// @param commandType which type of command to send (off / smoothing / etc..)
|
||||
///
|
||||
void setColor(int orbId, const ColorRgb &color, int commandType);
|
||||
|
||||
///
|
||||
/// Send Orb command
|
||||
///
|
||||
/// @param bytes the byte array containing command to send over multicast
|
||||
///
|
||||
void sendCommand(const QByteArray &bytes);
|
||||
|
||||
/// QNetworkAccessManager object for sending requests.
|
||||
QNetworkAccessManager *_manager;
|
||||
QNetworkAccessManager *_networkmanager;
|
||||
|
||||
/// QUdpSocket object used to send data over
|
||||
QUdpSocket * _udpSocket;
|
||||
|
||||
/// QHostAddress object of multicast group IP address
|
||||
QHostAddress _groupAddress;
|
||||
|
||||
/// String containing multicast group IP address
|
||||
QString _multicastGroup;
|
||||
|
||||
/// Multicast port to send data to
|
||||
quint16 _multiCastGroupPort;
|
||||
|
||||
// Multicast status
|
||||
bool joinedMulticastgroup;
|
||||
|
||||
/// use Orbs own (external) smoothing algorithm
|
||||
bool _useOrbSmoothing;
|
||||
|
||||
@ -90,34 +113,21 @@ private:
|
||||
// Maximum allowed color difference, will skip Orb (external) smoothing once reached
|
||||
int _skipSmoothingDiff;
|
||||
|
||||
/// Multicast port to send data to
|
||||
int _multiCastGroupPort;
|
||||
|
||||
/// Number of leds in Orb, used to determine buffer size
|
||||
int _numLeds;
|
||||
|
||||
/// QHostAddress object of multicast group IP address
|
||||
QHostAddress _groupAddress;
|
||||
|
||||
/// QUdpSocket object used to send data over
|
||||
QUdpSocket * _udpSocket;
|
||||
|
||||
|
||||
/// Array of the orb ids.
|
||||
QVector<unsigned int> _orbIds;
|
||||
QVector<int> _orbIds;
|
||||
|
||||
// Last send color map
|
||||
QMap<int, int> lastColorRedMap;
|
||||
QMap<int, int> lastColorGreenMap;
|
||||
QMap<int, int> lastColorBlueMap;
|
||||
|
||||
|
||||
|
||||
///
|
||||
/// Set Orbcolor
|
||||
///
|
||||
/// @param orbId the orb id
|
||||
/// @param color which color to set
|
||||
/// @param commandType which type of command to send (off / smoothing / etc..)
|
||||
///
|
||||
void setColor(unsigned int orbId, const ColorRgb &color, int commandType);
|
||||
|
||||
///
|
||||
/// Send Orb command
|
||||
///
|
||||
/// @param bytes the byte array containing command to send over multicast
|
||||
///
|
||||
void sendCommand(const QByteArray &bytes);
|
||||
};
|
||||
|
@ -9,13 +9,13 @@ LedDeviceFadeCandy::LedDeviceFadeCandy(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
, _client(nullptr)
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_client = new QTcpSocket(this);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDeviceFadeCandy::~LedDeviceFadeCandy()
|
||||
{
|
||||
_client->close();
|
||||
_client->deleteLater();
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceFadeCandy::construct(const QJsonObject &deviceConfig)
|
||||
@ -25,45 +25,90 @@ LedDevice* LedDeviceFadeCandy::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceFadeCandy::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
LedDevice::init(deviceConfig);
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
if (_ledCount > MAX_NUM_LEDS)
|
||||
if ( isInitOK )
|
||||
{
|
||||
Error(_log, "fadecandy/opc: Invalid attempt to write led values. Not more than %d leds are allowed.", MAX_NUM_LEDS);
|
||||
return false;
|
||||
if (_ledCount > MAX_NUM_LEDS)
|
||||
{
|
||||
//Error(_log, "fadecandy/opc: Invalid attempt to write led values. Not more than %d leds are allowed.", MAX_NUM_LEDS);
|
||||
QString errortext = QString ("More LED configured than allowed (%1)").arg(MAX_NUM_LEDS);
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_host = deviceConfig["output"].toString("127.0.0.1");
|
||||
_port = deviceConfig["port"].toInt(7890);
|
||||
_channel = deviceConfig["channel"].toInt(0);
|
||||
_gamma = deviceConfig["gamma"].toDouble(1.0);
|
||||
_noDither = ! deviceConfig["dither"].toBool(false);
|
||||
_noInterp = ! deviceConfig["interpolation"].toBool(false);
|
||||
_manualLED = deviceConfig["manualLed"].toBool(false);
|
||||
_ledOnOff = deviceConfig["ledOn"].toBool(false);
|
||||
_setFcConfig = deviceConfig["setFcConfig"].toBool(false);
|
||||
|
||||
_whitePoint_r = 1.0;
|
||||
_whitePoint_g = 1.0;
|
||||
_whitePoint_b = 1.0;
|
||||
|
||||
const QJsonArray whitePointConfig = deviceConfig["whitePoint"].toArray();
|
||||
if ( !whitePointConfig.isEmpty() && whitePointConfig.size() == 3 )
|
||||
{
|
||||
_whitePoint_r = whitePointConfig[0].toDouble() / 255.0;
|
||||
_whitePoint_g = whitePointConfig[1].toDouble() / 255.0;
|
||||
_whitePoint_b = whitePointConfig[2].toDouble() / 255.0;
|
||||
}
|
||||
|
||||
_opc_data.resize( _ledRGBCount + OPC_HEADER_SIZE );
|
||||
_opc_data[0] = _channel;
|
||||
_opc_data[1] = OPC_SET_PIXELS;
|
||||
_opc_data[2] = _ledRGBCount >> 8;
|
||||
_opc_data[3] = _ledRGBCount & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
_host = deviceConfig["output"].toString("127.0.0.1");
|
||||
_port = deviceConfig["port"].toInt(7890);
|
||||
_channel = deviceConfig["channel"].toInt(0);
|
||||
_gamma = deviceConfig["gamma"].toDouble(1.0);
|
||||
_noDither = ! deviceConfig["dither"].toBool(false);
|
||||
_noInterp = ! deviceConfig["interpolation"].toBool(false);
|
||||
_manualLED = deviceConfig["manualLed"].toBool(false);
|
||||
_ledOnOff = deviceConfig["ledOn"].toBool(false);
|
||||
_setFcConfig = deviceConfig["setFcConfig"].toBool(false);
|
||||
|
||||
_whitePoint_r = 1.0;
|
||||
_whitePoint_g = 1.0;
|
||||
_whitePoint_b = 1.0;
|
||||
|
||||
const QJsonArray whitePointConfig = deviceConfig["whitePoint"].toArray();
|
||||
if ( !whitePointConfig.isEmpty() && whitePointConfig.size() == 3 )
|
||||
{
|
||||
_whitePoint_r = whitePointConfig[0].toDouble() / 255.0;
|
||||
_whitePoint_g = whitePointConfig[1].toDouble() / 255.0;
|
||||
_whitePoint_b = whitePointConfig[2].toDouble() / 255.0;
|
||||
}
|
||||
|
||||
_opc_data.resize( _ledRGBCount + OPC_HEADER_SIZE );
|
||||
_opc_data[0] = _channel;
|
||||
_opc_data[1] = OPC_SET_PIXELS;
|
||||
_opc_data[2] = _ledRGBCount >> 8;
|
||||
_opc_data[3] = _ledRGBCount & 0xff;
|
||||
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceFadeCandy::initNetwork()
|
||||
{
|
||||
bool isInitOK = true;
|
||||
|
||||
// TODO: Add Network-Error handling
|
||||
_client = new QTcpSocket(this);
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceFadeCandy::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_deviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
if ( !initNetwork() )
|
||||
{
|
||||
this->setInError( "Network error!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDeviceFadeCandy::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
// LedDevice specific closing activites
|
||||
_client->close();
|
||||
}
|
||||
|
||||
|
||||
bool LedDeviceFadeCandy::isConnected()
|
||||
{
|
||||
return _client->state() == QAbstractSocket::ConnectedState;
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json config for fadecandy
|
||||
///
|
||||
LedDeviceFadeCandy(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceFadeCandy(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the tcp client
|
||||
@ -54,7 +54,30 @@ public:
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Initialise device's network details
|
||||
///
|
||||
/// @return True if success
|
||||
bool initNetwork();
|
||||
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -63,25 +86,7 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues);
|
||||
|
||||
protected:
|
||||
QTcpSocket* _client;
|
||||
QString _host;
|
||||
uint16_t _port;
|
||||
unsigned _channel;
|
||||
QByteArray _opc_data;
|
||||
|
||||
// fadecandy sysEx
|
||||
bool _setFcConfig;
|
||||
double _gamma;
|
||||
double _whitePoint_r;
|
||||
double _whitePoint_g;
|
||||
double _whitePoint_b;
|
||||
bool _noDither;
|
||||
bool _noInterp;
|
||||
bool _manualLED;
|
||||
bool _ledOnOff;
|
||||
virtual int write(const std::vector<ColorRgb>& ledValues) override;
|
||||
|
||||
/// try to establish connection to opc server, if not connected yet
|
||||
///
|
||||
@ -112,4 +117,21 @@ protected:
|
||||
/// sends the configuration to fcserver
|
||||
void sendFadeCandyConfiguration();
|
||||
|
||||
QTcpSocket* _client;
|
||||
QString _host;
|
||||
uint16_t _port;
|
||||
unsigned _channel;
|
||||
QByteArray _opc_data;
|
||||
|
||||
// fadecandy sysEx
|
||||
bool _setFcConfig;
|
||||
double _gamma;
|
||||
double _whitePoint_r;
|
||||
double _whitePoint_g;
|
||||
double _whitePoint_b;
|
||||
bool _noDither;
|
||||
bool _noInterp;
|
||||
bool _manualLED;
|
||||
bool _ledOnOff;
|
||||
|
||||
};
|
||||
|
@ -17,7 +17,7 @@ static const bool verbose = false;
|
||||
static const bool verbose3 = false;
|
||||
|
||||
// Controller configuration settings
|
||||
static const char CONFIG_ADDRESS[] = "output";
|
||||
static const char CONFIG_ADDRESS[] = "host";
|
||||
//static const char CONFIG_PORT[] = "port";
|
||||
static const char CONFIG_AUTH_TOKEN[] ="token";
|
||||
|
||||
@ -85,120 +85,189 @@ LedDevice* LedDeviceNanoleaf::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceNanoleaf(deviceConfig);
|
||||
}
|
||||
|
||||
LedDeviceNanoleaf::~LedDeviceNanoleaf()
|
||||
{
|
||||
_networkmanager->deleteLater();
|
||||
}
|
||||
|
||||
LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_networkmanager = nullptr;
|
||||
_extControlVersion = EXTCTRLVER_V2;
|
||||
_panelLedCount = 0;
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::init(const QJsonObject &deviceConfig) {
|
||||
bool LedDeviceNanoleaf::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
// Overwrite non supported/required features
|
||||
_devConfig["latchTime"] = 0;
|
||||
if (deviceConfig["rewriteTime"].toInt(0) > 0)
|
||||
{
|
||||
Info (_log, "Device Nanoleaf does not require rewrites. Refresh time is ignored.");
|
||||
_devConfig["rewriteTime"] = 0;
|
||||
}
|
||||
|
||||
LedDevice::init(deviceConfig);
|
||||
DebugIf(verbose, _log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
||||
uint configuredLedCount = static_cast<uint>(this->getLedCount());
|
||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
||||
Debug(_log, "LedCount : %u", configuredLedCount);
|
||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
//Set hostname as per configuration and default port
|
||||
_hostname = deviceConfig[ CONFIG_ADDRESS ].toString();
|
||||
_api_port = API_DEFAULT_PORT;
|
||||
_auth_token = deviceConfig[ CONFIG_AUTH_TOKEN ].toString();
|
||||
if ( isInitOK )
|
||||
{
|
||||
uint configuredLedCount = this->getLedCount();
|
||||
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
|
||||
Debug(_log, "LedCount : %u", configuredLedCount);
|
||||
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
|
||||
Debug(_log, "RefreshTime : %d", _refresh_timer_interval);
|
||||
Debug(_log, "LatchTime : %d", this->getLatchTime());
|
||||
|
||||
//If host not configured then discover device
|
||||
if ( _hostname.isEmpty() )
|
||||
//Discover Nanoleaf device
|
||||
if ( !discoverNanoleafDevice() ) {
|
||||
throw std::runtime_error("No target IP defined nor Nanoleaf device discovered");
|
||||
//Set hostname as per configuration and_defaultHost default port
|
||||
_hostname = deviceConfig[ CONFIG_ADDRESS ].toString();
|
||||
_api_port = API_DEFAULT_PORT;
|
||||
_auth_token = deviceConfig[ CONFIG_AUTH_TOKEN ].toString();
|
||||
|
||||
//If host not configured then discover device
|
||||
if ( _hostname.isEmpty() )
|
||||
{
|
||||
//Discover Nanoleaf device
|
||||
if ( !discoverNanoleafDevice() )
|
||||
{
|
||||
this->setInError("No target IP defined nor Nanoleaf device was discovered");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set UDP streaming port
|
||||
_devConfig["host"] = _hostname;
|
||||
_devConfig["port"] = STREAM_CONTROL_DEFAULT_PORT;
|
||||
isInitOK = ProviderUdp::init(_devConfig);
|
||||
|
||||
Debug(_log, "Hostname/IP : %s", QSTRING_CSTR( _hostname ));
|
||||
Debug(_log, "Port : %d", _port);
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::initLeds()
|
||||
{
|
||||
bool isInitOK = true;
|
||||
|
||||
//Get Nanoleaf device details and configuration
|
||||
_networkmanager = new QNetworkAccessManager();
|
||||
|
||||
// Read Panel count and panel Ids
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_ROOT );
|
||||
QJsonDocument doc = getJson( url );
|
||||
if ( this->isInError() )
|
||||
{
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
QJsonObject jsonAllPanelInfo = doc.object();
|
||||
|
||||
QJsonObject jsonAllPanelInfo = doc.object();
|
||||
QString deviceName = jsonAllPanelInfo[DEV_DATA_NAME].toString();
|
||||
_deviceModel = jsonAllPanelInfo[DEV_DATA_MODEL].toString();
|
||||
QString deviceManufacturer = jsonAllPanelInfo[DEV_DATA_MANUFACTURER].toString();
|
||||
_deviceFirmwareVersion = jsonAllPanelInfo[DEV_DATA_FIRMWAREVERSION].toString();
|
||||
|
||||
QString deviceName = jsonAllPanelInfo[DEV_DATA_NAME].toString();
|
||||
_deviceModel = jsonAllPanelInfo[DEV_DATA_MODEL].toString();
|
||||
QString deviceManufacturer = jsonAllPanelInfo[DEV_DATA_MANUFACTURER].toString();
|
||||
_deviceFirmwareVersion = jsonAllPanelInfo[DEV_DATA_FIRMWAREVERSION].toString();
|
||||
Debug(_log, "Name : %s", QSTRING_CSTR( deviceName ));
|
||||
Debug(_log, "Model : %s", QSTRING_CSTR( _deviceModel ));
|
||||
Debug(_log, "Manufacturer : %s", QSTRING_CSTR( deviceManufacturer ));
|
||||
Debug(_log, "FirmwareVersion: %s", QSTRING_CSTR( _deviceFirmwareVersion));
|
||||
|
||||
Debug(_log, "Name : %s", QSTRING_CSTR( deviceName ));
|
||||
Debug(_log, "Model : %s", QSTRING_CSTR( _deviceModel ));
|
||||
Debug(_log, "Manufacturer : %s", QSTRING_CSTR( deviceManufacturer ));
|
||||
Debug(_log, "FirmwareVersion: %s", QSTRING_CSTR( _deviceFirmwareVersion));
|
||||
// Get panel details from /panelLayout/layout
|
||||
QJsonObject jsonPanelLayout = jsonAllPanelInfo[API_PANELLAYOUT].toObject();
|
||||
QJsonObject jsonLayout = jsonPanelLayout[PANEL_LAYOUT].toObject();
|
||||
|
||||
// Get panel details from /panelLayout/layout
|
||||
QJsonObject jsonPanelLayout = jsonAllPanelInfo[API_PANELLAYOUT].toObject();
|
||||
QJsonObject jsonLayout = jsonPanelLayout[PANEL_LAYOUT].toObject();
|
||||
uint panelNum = static_cast<uint>(jsonLayout[PANEL_NUM].toInt());
|
||||
QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray();
|
||||
|
||||
uint panelNum = static_cast<uint>(jsonLayout[PANEL_NUM].toInt());
|
||||
QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray();
|
||||
std::map<uint, std::map<uint, uint>> panelMap;
|
||||
|
||||
std::map<uint, std::map<uint, uint>> panelMap;
|
||||
// Loop over all children.
|
||||
foreach (const QJsonValue & value, positionData)
|
||||
{
|
||||
QJsonObject panelObj = value.toObject();
|
||||
|
||||
// Loop over all children.
|
||||
foreach (const QJsonValue & value, positionData) {
|
||||
QJsonObject panelObj = value.toObject();
|
||||
uint panelId = static_cast<uint>(panelObj[PANEL_ID].toInt());
|
||||
uint panelX = static_cast<uint>(panelObj[PANEL_POS_X].toInt());
|
||||
uint panelY = static_cast<uint>(panelObj[PANEL_POS_Y].toInt());
|
||||
uint panelshapeType = static_cast<uint>(panelObj[PANEL_SHAPE_TYPE].toInt());
|
||||
//uint panelOrientation = static_cast<uint>(panelObj[PANEL_ORIENTATION].toInt());
|
||||
|
||||
uint panelId = static_cast<uint>(panelObj[PANEL_ID].toInt());
|
||||
uint panelX = static_cast<uint>(panelObj[PANEL_POS_X].toInt());
|
||||
uint panelY = static_cast<uint>(panelObj[PANEL_POS_Y].toInt());
|
||||
uint panelshapeType = static_cast<uint>(panelObj[PANEL_SHAPE_TYPE].toInt());
|
||||
//uint panelOrientation = static_cast<uint>(panelObj[PANEL_ORIENTATION].toInt());
|
||||
DebugIf(verbose, _log, "Panel [%u] (%u,%u) - Type: [%u]", panelId, panelX, panelY, panelshapeType );
|
||||
|
||||
DebugIf(verbose, _log, "Panel [%u] (%u,%u) - Type: [%u]", panelId, panelX, panelY, panelshapeType );
|
||||
// Skip Rhythm panels
|
||||
if ( panelshapeType != RHYTM )
|
||||
{
|
||||
panelMap[panelY][panelX] = panelId;
|
||||
}
|
||||
else
|
||||
{ // Reset non support/required features
|
||||
Info(_log, "Rhythm panel skipped.");
|
||||
}
|
||||
}
|
||||
|
||||
// Skip Rhythm panels
|
||||
if ( panelshapeType != RHYTM ) {
|
||||
panelMap[panelY][panelX] = panelId;
|
||||
} else {
|
||||
Info(_log, "Rhythm panel skipped.");
|
||||
// Sort panels top down, left right
|
||||
for(auto posY = panelMap.crbegin(); posY != panelMap.crend(); ++posY)
|
||||
{
|
||||
// posY.first is the first key
|
||||
for(auto const &posX : posY->second)
|
||||
{
|
||||
// posX.first is the second key, posX.second is the data
|
||||
DebugIf(verbose3, _log, "panelMap[%u][%u]=%u", posY->first, posX.first, posX.second );
|
||||
_panelIds.push_back(posX.second);
|
||||
}
|
||||
}
|
||||
this->_panelLedCount = static_cast<uint>(_panelIds.size());
|
||||
_devConfig["hardwareLedCount"] = static_cast<int>(_panelLedCount);
|
||||
|
||||
Debug(_log, "PanelsNum : %u", panelNum);
|
||||
Debug(_log, "PanelLedCount : %u", _panelLedCount);
|
||||
|
||||
// Check. if enough panelds were found.
|
||||
uint configuredLedCount = this->getLedCount();
|
||||
if (_panelLedCount < configuredLedCount )
|
||||
{
|
||||
QString errorReason = QString("Not enough panels [%1] for configured LEDs [%2] found!")
|
||||
.arg(_panelLedCount)
|
||||
.arg(configuredLedCount);
|
||||
this->setInError(errorReason);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( _panelLedCount > this->getLedCount() )
|
||||
{
|
||||
Warning(_log, "Nanoleaf: More panels [%u] than configured LEDs [%u].", _panelLedCount, configuredLedCount );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort panels top down, left right
|
||||
for(auto posY = panelMap.crbegin(); posY != panelMap.crend(); ++posY) {
|
||||
// posY.first is the first key
|
||||
for(auto const &posX : posY->second) {
|
||||
// posX.first is the second key, posX.second is the data
|
||||
DebugIf(verbose3, _log, "panelMap[%u][%u]=%u", posY->first, posX.first, posX.second );
|
||||
_panelIds.push_back(posX.second);
|
||||
}
|
||||
}
|
||||
this->_panelLedCount = static_cast<uint>(_panelIds.size());
|
||||
|
||||
|
||||
Debug(_log, "PanelsNum : %u", panelNum);
|
||||
Debug(_log, "PanelLedCount : %u", _panelLedCount);
|
||||
|
||||
// Check. if enough panelds were found.
|
||||
if (_panelLedCount < configuredLedCount) {
|
||||
|
||||
throw std::runtime_error ( (QString ("Not enough panels [%1] for configured LEDs [%2] found!").arg(_panelLedCount).arg(configuredLedCount)).toStdString() );
|
||||
} else {
|
||||
if ( _panelLedCount > static_cast<uint>(this->getLedCount()) ) {
|
||||
Warning(_log, "Nanoleaf: More panels [%u] than configured LEDs [%u].", _panelLedCount, configuredLedCount );
|
||||
}
|
||||
}
|
||||
|
||||
// Set UDP streaming port
|
||||
_port = STREAM_CONTROL_DEFAULT_PORT;
|
||||
_defaultHost = _hostname;
|
||||
|
||||
switchOn();
|
||||
|
||||
ProviderUdp::init(deviceConfig);
|
||||
|
||||
Debug(_log, "Started successfully" );
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::discoverNanoleafDevice() {
|
||||
int LedDeviceNanoleaf::open()
|
||||
{
|
||||
int retval = -1;
|
||||
_deviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
if ( initLeds() )
|
||||
{
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool LedDeviceNanoleaf::discoverNanoleafDevice()
|
||||
{
|
||||
|
||||
bool isDeviceFound (false);
|
||||
// device searching by ssdp
|
||||
@ -229,7 +298,9 @@ bool LedDeviceNanoleaf::discoverNanoleafDevice() {
|
||||
return isDeviceFound;
|
||||
}
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode() {
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode()
|
||||
{
|
||||
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_EFFECT );
|
||||
QJsonDocument jsonDoc;
|
||||
@ -245,7 +316,8 @@ QString LedDeviceNanoleaf::getUrl(QString host, QString port, QString auth_token
|
||||
return QString(API_URL_FORMAT).arg(host, port, auth_token, endpoint);
|
||||
}
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::getJson(QString url) const {
|
||||
QJsonDocument LedDeviceNanoleaf::getJson(QString url)
|
||||
{
|
||||
|
||||
Debug(_log, "GET: [%s]", QSTRING_CSTR( url ));
|
||||
|
||||
@ -269,7 +341,8 @@ QJsonDocument LedDeviceNanoleaf::getJson(QString url) const {
|
||||
return jsonDoc;
|
||||
}
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::putJson(QString url, QString json) const {
|
||||
QJsonDocument LedDeviceNanoleaf::putJson(QString url, QString json)
|
||||
{
|
||||
|
||||
Debug(_log, "PUT: [%s] [%s]", QSTRING_CSTR( url ), QSTRING_CSTR( json ) );
|
||||
// Perfrom request
|
||||
@ -293,15 +366,15 @@ QJsonDocument LedDeviceNanoleaf::putJson(QString url, QString json) const {
|
||||
return jsonDoc;
|
||||
}
|
||||
|
||||
QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply ) const {
|
||||
QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply )
|
||||
{
|
||||
|
||||
QJsonDocument jsonDoc;
|
||||
|
||||
int httpStatusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
|
||||
Debug(_log, "Reply.httpStatusCode [%d]", httpStatusCode );
|
||||
|
||||
if(reply->error() ==
|
||||
QNetworkReply::NoError)
|
||||
if(reply->error() == QNetworkReply::NoError)
|
||||
{
|
||||
if ( httpStatusCode != 204 ){
|
||||
QByteArray response = reply->readAll();
|
||||
@ -309,8 +382,7 @@ QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply ) const
|
||||
jsonDoc = QJsonDocument::fromJson(response, &error);
|
||||
if (error.error != QJsonParseError::NoError)
|
||||
{
|
||||
Error (_log, "Got invalid response");
|
||||
throw std::runtime_error("");
|
||||
this->setInError ( "Got invalid response" );
|
||||
}
|
||||
else {
|
||||
//Debug
|
||||
@ -326,35 +398,30 @@ QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply ) const
|
||||
QString httpReason = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString();
|
||||
QString advise;
|
||||
switch ( httpStatusCode ) {
|
||||
case 400:
|
||||
advise = "Check Request Body";
|
||||
break;
|
||||
case 401:
|
||||
advise = "Check Authentication Token (API Key)";
|
||||
break;
|
||||
case 404:
|
||||
advise = "Check Resource given";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case 400:
|
||||
advise = "Check Request Body";
|
||||
break;
|
||||
case 401:
|
||||
advise = "Check Authentication Token (API Key)";
|
||||
break;
|
||||
case 404:
|
||||
advise = "Check Resource given";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
errorReason = QString ("%1:%2 [%3 %4] - %5").arg(_hostname, _api_port, QString(httpStatusCode) , httpReason);
|
||||
errorReason = QString ("%1:%2 [%3 %4] - %5").arg(_hostname, _api_port, QString(httpStatusCode) , httpReason, advise);
|
||||
}
|
||||
else {
|
||||
errorReason = QString ("%1:%2 - %3").arg(_hostname, _api_port, reply->errorString());
|
||||
}
|
||||
Error (_log, "%s", QSTRING_CSTR( errorReason ));
|
||||
throw std::runtime_error("Network Error");
|
||||
this->setInError ( errorReason );
|
||||
}
|
||||
// Return response
|
||||
return jsonDoc;
|
||||
}
|
||||
|
||||
|
||||
LedDeviceNanoleaf::~LedDeviceNanoleaf()
|
||||
{
|
||||
delete _networkmanager;
|
||||
}
|
||||
|
||||
int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
|
||||
{
|
||||
@ -396,7 +463,7 @@ int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
|
||||
lowByte = static_cast<uchar>(panelID & 0xFF);
|
||||
|
||||
// Set panels configured
|
||||
if( panelCounter < static_cast<uint>(this->getLedCount()) ) {
|
||||
if( panelCounter < this->getLedCount() ) {
|
||||
color = static_cast<ColorRgb>(ledValues.at(panelCounter));
|
||||
}
|
||||
else
|
||||
@ -437,40 +504,43 @@ int LedDeviceNanoleaf::write(const std::vector<ColorRgb> & ledValues)
|
||||
return retVal;
|
||||
}
|
||||
|
||||
QString LedDeviceNanoleaf::getOnOffRequest (bool isOn ) const {
|
||||
QString LedDeviceNanoleaf::getOnOffRequest (bool isOn ) const
|
||||
{
|
||||
QString state = isOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
|
||||
return QString( "{\"%1\":{\"%2\":%3}}" ).arg(STATE_ON, STATE_ONOFF_VALUE, state);
|
||||
}
|
||||
|
||||
int LedDeviceNanoleaf::switchOn() {
|
||||
Debug(_log, "switchOn()");
|
||||
int LedDeviceNanoleaf::switchOn()
|
||||
{
|
||||
if ( _deviceReady)
|
||||
{
|
||||
// Set Nanoleaf to External Control (UDP) mode
|
||||
Debug(_log, "Set Nanoleaf to External Control (UDP) streaming mode");
|
||||
QJsonDocument responseDoc = changeToExternalControlMode();
|
||||
// Resolve port for Ligh Panels
|
||||
QJsonObject jsonStreamControllInfo = responseDoc.object();
|
||||
if ( ! jsonStreamControllInfo.isEmpty() ) {
|
||||
_port = static_cast<uchar>(jsonStreamControllInfo[STREAM_CONTROL_PORT].toInt());
|
||||
}
|
||||
|
||||
// Set Nanoleaf to External Control (UDP) mode
|
||||
Debug(_log, "Set Nanoleaf to External Control (UDP) streaming mode");
|
||||
QJsonDocument responseDoc = changeToExternalControlMode();
|
||||
// Resolve port for Ligh Panels
|
||||
QJsonObject jsonStreamControllInfo = responseDoc.object();
|
||||
if ( ! jsonStreamControllInfo.isEmpty() ) {
|
||||
_port = static_cast<uchar>(jsonStreamControllInfo[STREAM_CONTROL_PORT].toInt());
|
||||
//Switch on Nanoleaf device
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
|
||||
putJson(url, this->getOnOffRequest(true) );
|
||||
}
|
||||
|
||||
//Switch on Nanoleaf device
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
|
||||
putJson(url, this->getOnOffRequest(true) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LedDeviceNanoleaf::switchOff() {
|
||||
Debug(_log, "switchOff()");
|
||||
|
||||
int LedDeviceNanoleaf::switchOff()
|
||||
{
|
||||
//Set all LEDs to Black
|
||||
int rc = writeBlack();
|
||||
|
||||
//Switch off Nanoleaf device physically
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
|
||||
putJson(url, getOnOffRequest(false) );
|
||||
int rc = LedDevice::switchOff();
|
||||
|
||||
if ( _deviceReady)
|
||||
{
|
||||
//Switch off Nanoleaf device physically
|
||||
QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
|
||||
putJson(url, getOnOffRequest(false) );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -480,7 +550,7 @@ std::string LedDeviceNanoleaf:: uint8_vector_to_hex_string( const std::vector<ui
|
||||
ss << std::hex << std::setfill('0');
|
||||
std::vector<uint8_t>::const_iterator it;
|
||||
|
||||
for (it = buffer.begin(); it != buffer.end(); it++)
|
||||
for (it = buffer.begin(); it != buffer.end(); ++it)
|
||||
{
|
||||
ss << " " << std::setw(2) << static_cast<unsigned>(*it);
|
||||
}
|
||||
|
@ -18,134 +18,143 @@
|
||||
class LedDeviceNanoleaf : public ProviderUdp
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Constructs the LedDevice for Nanoleaf LightPanels (aka Aurora) or Canvas
|
||||
///
|
||||
/// following code shows all config options
|
||||
/// @code
|
||||
/// "device" :
|
||||
/// {
|
||||
/// "type" : "nanoleaf"
|
||||
/// "output" : "hostname or IP", // Optional. If empty, device is tried to be discovered
|
||||
/// "token" : "Authentication Token",
|
||||
/// },
|
||||
///@endcode
|
||||
///
|
||||
/// @param deviceConfig json config for nanoleaf
|
||||
///
|
||||
LedDeviceNanoleaf(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Constructs the LedDevice for Nanoleaf LightPanels (aka Aurora) or Canvas
|
||||
///
|
||||
/// following code shows all config options
|
||||
/// @code
|
||||
/// "device" :
|
||||
/// {
|
||||
/// "type" : "nanoleaf"
|
||||
/// "output" : "hostname or IP", // Optional. If empty, device is tried to be discovered
|
||||
/// "token" : "Authentication Token",
|
||||
/// },
|
||||
///@endcode
|
||||
///
|
||||
/// @param deviceConfig json config for nanoleaf
|
||||
///
|
||||
explicit LedDeviceNanoleaf(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the tcp client
|
||||
///
|
||||
virtual ~LedDeviceNanoleaf();
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the tcp client
|
||||
///
|
||||
virtual ~LedDeviceNanoleaf() override;
|
||||
|
||||
/// Constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
/// Constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
/// Switch the leds on
|
||||
virtual int switchOn();
|
||||
/// Switch the device on
|
||||
virtual int switchOn() override;
|
||||
|
||||
/// Switch the leds off
|
||||
virtual int switchOff();
|
||||
/// Switch the device off
|
||||
virtual int switchOff() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues);
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
///
|
||||
/// Identifies a Nanoleaf device's panel configuration,
|
||||
/// sets device into External Control (UDP) mode
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
/// @exception runtime_error in case device cannot be initialised
|
||||
/// e.g. more LEDs configured than device has panels or network problems
|
||||
///
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Initialise Nanoleaf device's configuration and network address details
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return True if success
|
||||
///
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// Get Nanoleaf device details and configuration
|
||||
///
|
||||
/// @return True, if Nanoleaf device capabilities fit configuration
|
||||
///
|
||||
bool initLeds();
|
||||
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
private:
|
||||
// QNetworkAccessManager object for sending requests.
|
||||
QNetworkAccessManager* _networkmanager;
|
||||
// QNetworkAccessManager object for sending requests.
|
||||
QNetworkAccessManager* _networkmanager;
|
||||
|
||||
QString _hostname;
|
||||
QString _api_port;
|
||||
QString _auth_token;
|
||||
QString _hostname;
|
||||
QString _api_port;
|
||||
QString _auth_token;
|
||||
|
||||
//Nanoleaf device details
|
||||
QString _deviceModel;
|
||||
QString _deviceFirmwareVersion;
|
||||
ushort _extControlVersion;
|
||||
/// The number of panels with leds
|
||||
//Nanoleaf device details
|
||||
QString _deviceModel;
|
||||
QString _deviceFirmwareVersion;
|
||||
ushort _extControlVersion;
|
||||
/// The number of panels with leds
|
||||
uint _panelLedCount;
|
||||
/// Array of the pannel ids.
|
||||
std::vector<uint> _panelIds;
|
||||
/// Array of the pannel ids.
|
||||
std::vector<uint> _panelIds;
|
||||
|
||||
///
|
||||
/// Discover Nanoleaf device via SSDP identifiers
|
||||
///
|
||||
/// @return True, if Nanoleaf device was found
|
||||
///
|
||||
bool discoverNanoleafDevice();
|
||||
///
|
||||
/// Discover Nanoleaf device via SSDP identifiers
|
||||
///
|
||||
/// @return True, if Nanoleaf device was found
|
||||
///
|
||||
bool discoverNanoleafDevice();
|
||||
|
||||
///
|
||||
/// Change Nanoleaf device to External Control (UDP) mode
|
||||
///
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument changeToExternalControlMode();
|
||||
///
|
||||
/// Change Nanoleaf device to External Control (UDP) mode
|
||||
///
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument changeToExternalControlMode();
|
||||
|
||||
///
|
||||
/// Get command to switch Nanoleaf device on or off
|
||||
///
|
||||
/// @param isOn True, if to switch on device
|
||||
/// @return Command to switch device on/off
|
||||
///
|
||||
QString getOnOffRequest (bool isOn ) const;
|
||||
///
|
||||
/// Get command to switch Nanoleaf device on or off
|
||||
///
|
||||
/// @param isOn True, if to switch on device
|
||||
/// @return Command to switch device on/off
|
||||
///
|
||||
QString getOnOffRequest (bool isOn ) const;
|
||||
|
||||
///
|
||||
/// Get command as url
|
||||
///
|
||||
/// @param host Hostname or IP
|
||||
/// @param port IP-Port
|
||||
/// @param _auth_token Authorization token
|
||||
/// @param Endpoint command for request
|
||||
/// @return Url to execute endpoint/command
|
||||
///
|
||||
QString getUrl(QString host, QString port, QString auth_token, QString endpoint) const;
|
||||
///
|
||||
/// Get command as url
|
||||
///
|
||||
/// @param host Hostname or IP
|
||||
/// @param port IP-Port
|
||||
/// @param _auth_token Authorization token
|
||||
/// @param Endpoint command for request
|
||||
/// @return Url to execute endpoint/command
|
||||
///
|
||||
QString getUrl(QString host, QString port, QString auth_token, QString endpoint) const;
|
||||
|
||||
///
|
||||
/// Execute GET request
|
||||
///
|
||||
/// @param url GET request for url
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument getJson(QString url) const;
|
||||
///
|
||||
/// Execute GET request
|
||||
///
|
||||
/// @param url GET request for url
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument getJson(QString url);
|
||||
|
||||
///
|
||||
/// Execute PUT request
|
||||
///
|
||||
/// @param Url for PUT request
|
||||
/// @param json Command for request
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument putJson(QString url, QString json) const;
|
||||
|
||||
///
|
||||
/// Handle replys for GET and PUT requests
|
||||
///
|
||||
/// @param reply Network reply
|
||||
/// @return Response for request, if no error
|
||||
/// @exception runtime_error for network or request errors
|
||||
///
|
||||
QJsonDocument handleReply(QNetworkReply* const &reply ) const;
|
||||
///
|
||||
/// Execute PUT request
|
||||
///
|
||||
/// @param Url for PUT request
|
||||
/// @param json Command for request
|
||||
/// @return Response from device
|
||||
///
|
||||
QJsonDocument putJson(QString url, QString json);
|
||||
|
||||
///
|
||||
/// Handle replys for GET and PUT requests
|
||||
///
|
||||
/// @param reply Network reply
|
||||
/// @return Response for request, if no error
|
||||
///
|
||||
QJsonDocument handleReply(QNetworkReply* const &reply );
|
||||
|
||||
///
|
||||
/// convert vector to hex string
|
||||
|
@ -217,7 +217,7 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDevicePhilipsHue(const QJsonObject &deviceConfig);
|
||||
explicit LedDevicePhilipsHue(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Destructor of this device
|
||||
@ -229,7 +229,7 @@ public:
|
||||
|
||||
public slots:
|
||||
/// thread start
|
||||
virtual void start();
|
||||
virtual void start() override;
|
||||
|
||||
private slots:
|
||||
/// creates new PhilipsHueLight(s) based on user lightid with bridge feedback
|
||||
@ -248,8 +248,8 @@ protected:
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues);
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
/// bridge class
|
||||
|
@ -3,18 +3,8 @@
|
||||
LedDeviceTpm2net::LedDeviceTpm2net(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceTpm2net::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = TPM2_DEFAULT_PORT;
|
||||
ProviderUdp::init(deviceConfig);
|
||||
_tpm2_max = deviceConfig["max-packet"].toInt(170);
|
||||
_tpm2ByteCount = 3 * _ledCount;
|
||||
_tpm2TotalPackets = 1 + _tpm2ByteCount / _tpm2_max;
|
||||
|
||||
return true;
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceTpm2net::construct(const QJsonObject &deviceConfig)
|
||||
@ -22,8 +12,17 @@ LedDevice* LedDeviceTpm2net::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceTpm2net(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceTpm2net::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = TPM2_DEFAULT_PORT;
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
|
||||
// populates the headers
|
||||
_tpm2_max = deviceConfig["max-packet"].toInt(170);
|
||||
_tpm2ByteCount = 3 * _ledCount;
|
||||
_tpm2TotalPackets = 1 + _tpm2ByteCount / _tpm2_max;
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceTpm2net::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
|
@ -3,7 +3,7 @@
|
||||
// hyperion includes
|
||||
#include "ProviderUdp.h"
|
||||
|
||||
#define TPM2_DEFAULT_PORT 65506
|
||||
const ushort TPM2_DEFAULT_PORT = 65506;
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending led colors via udp tpm2.net packets
|
||||
@ -16,17 +16,17 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceTpm2net(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceTpm2net(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -35,7 +35,7 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
int _tpm2_max;
|
||||
int _tpm2ByteCount;
|
||||
|
@ -7,17 +7,8 @@
|
||||
LedDeviceUdpArtNet::LedDeviceUdpArtNet(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceUdpArtNet::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = 6454;
|
||||
ProviderUdp::init(deviceConfig);
|
||||
_artnet_universe = deviceConfig["universe"].toInt(1);
|
||||
_artnet_channelsPerFixture = deviceConfig["channelsPerFixture"].toInt(3);
|
||||
|
||||
return true;
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpArtNet::construct(const QJsonObject &deviceConfig)
|
||||
@ -25,6 +16,16 @@ LedDevice* LedDeviceUdpArtNet::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceUdpArtNet(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceUdpArtNet::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = ARTNET_DEFAULT_PORT;
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
|
||||
_artnet_universe = deviceConfig["universe"].toInt(1);
|
||||
_artnet_channelsPerFixture = deviceConfig["channelsPerFixture"].toInt(3);
|
||||
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
// populates the headers
|
||||
void LedDeviceUdpArtNet::prepare(const unsigned this_universe, const unsigned this_sequence, unsigned this_dmxChannelCount)
|
||||
@ -66,7 +67,7 @@ The Sequence field is set to 0x00 to disable this feature.
|
||||
int dmxIdx = 0; // offset into the current dmx packet
|
||||
|
||||
memset(artnet_packet.raw, 0, sizeof(artnet_packet.raw));
|
||||
for (int ledIdx = 0; ledIdx < _ledRGBCount; ledIdx++)
|
||||
for (unsigned int ledIdx = 0; ledIdx < _ledRGBCount; ledIdx++)
|
||||
{
|
||||
|
||||
artnet_packet.Data[dmxIdx++] = rawdata[ledIdx];
|
||||
@ -90,4 +91,3 @@ The Sequence field is set to 0x00 to disable this feature.
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
*
|
||||
**/
|
||||
|
||||
#define ArtNet_DEFAULT_PORT 5568
|
||||
const ushort ARTNET_DEFAULT_PORT = 6454;
|
||||
|
||||
#define DMX_MAX 512 // 512 usable slots
|
||||
|
||||
@ -47,18 +47,17 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceUdpArtNet(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceUdpArtNet(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -67,13 +66,13 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
void prepare(const unsigned this_universe, const unsigned this_sequence, const unsigned this_dmxChannelCount);
|
||||
|
||||
|
||||
artnet_packet_t artnet_packet;
|
||||
uint8_t _artnet_seq = 1;
|
||||
uint8_t _artnet_channelsPerFixture = 3;
|
||||
unsigned _artnet_universe = 1;
|
||||
int _artnet_channelsPerFixture = 3;
|
||||
int _artnet_universe = 1;
|
||||
};
|
||||
|
@ -7,27 +7,32 @@
|
||||
LedDeviceUdpE131::LedDeviceUdpE131(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = 5568;
|
||||
ProviderUdp::init(deviceConfig);
|
||||
_e131_universe = deviceConfig["universe"].toInt(1);
|
||||
_e131_source_name = deviceConfig["source-name"].toString("hyperion on "+QHostInfo::localHostName());
|
||||
QString _json_cid = deviceConfig["cid"].toString("");
|
||||
|
||||
if (_json_cid.isEmpty())
|
||||
_port = E131_DEFAULT_PORT;
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
{
|
||||
_e131_cid = QUuid::createUuid();
|
||||
Debug( _log, "e131 no cid found, generated %s", QSTRING_CSTR(_e131_cid.toString()));
|
||||
} else {
|
||||
_e131_cid = QUuid(_json_cid);
|
||||
Debug( _log, "e131 cid found, using %s", QSTRING_CSTR(_e131_cid.toString()));
|
||||
}
|
||||
_e131_universe = deviceConfig["universe"].toInt(1);
|
||||
_e131_source_name = deviceConfig["source-name"].toString("hyperion on "+QHostInfo::localHostName());
|
||||
QString _json_cid = deviceConfig["cid"].toString("");
|
||||
|
||||
return true;
|
||||
if (_json_cid.isEmpty())
|
||||
{
|
||||
_e131_cid = QUuid::createUuid();
|
||||
Debug( _log, "e131 no cid found, generated %s", QSTRING_CSTR(_e131_cid.toString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
_e131_cid = QUuid(_json_cid);
|
||||
Debug( _log, "e131 cid found, using %s", QSTRING_CSTR(_e131_cid.toString()));
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpE131::construct(const QJsonObject &deviceConfig)
|
||||
@ -35,7 +40,6 @@ LedDevice* LedDeviceUdpE131::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceUdpE131(deviceConfig);
|
||||
}
|
||||
|
||||
|
||||
// populates the headers
|
||||
void LedDeviceUdpE131::prepare(const unsigned this_universe, const unsigned this_dmxChannelCount)
|
||||
{
|
||||
|
@ -18,7 +18,7 @@
|
||||
*
|
||||
**/
|
||||
|
||||
#define E131_DEFAULT_PORT 5568
|
||||
const ushort E131_DEFAULT_PORT = 5568;
|
||||
|
||||
/* E1.31 Packet Offsets */
|
||||
#define E131_ROOT_PREAMBLE_SIZE 0
|
||||
@ -105,18 +105,17 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceUdpE131(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceUdpE131(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -125,7 +124,7 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
void prepare(const unsigned this_universe, const unsigned this_dmxChannelCount);
|
||||
|
||||
|
@ -3,43 +3,46 @@
|
||||
LedDeviceUdpH801::LedDeviceUdpH801(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpH801::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceUdpH801(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceUdpH801::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
/* The H801 port is fixed */
|
||||
_latchTime_ms = 10;
|
||||
_port = 30977;
|
||||
_defaultHost = "255.255.255.255";
|
||||
ProviderUdp::init(deviceConfig);
|
||||
_port = H801_DEFAULT_PORT;
|
||||
_defaultHost = H801_DEFAULT_HOST;
|
||||
|
||||
_ids.clear();
|
||||
QJsonArray lArray = deviceConfig["lightIds"].toArray();
|
||||
for (int i = 0; i < lArray.size(); i++)
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
{
|
||||
QString id = lArray[i].toString();
|
||||
_ids.push_back(id.toInt(nullptr, 16));
|
||||
_ids.clear();
|
||||
QJsonArray lArray = deviceConfig["lightIds"].toArray();
|
||||
for (int i = 0; i < lArray.size(); i++)
|
||||
{
|
||||
QString id = lArray[i].toString();
|
||||
_ids.push_back(id.toInt(nullptr, 16));
|
||||
}
|
||||
|
||||
_message = QByteArray(_prefix_size + _colors + _id_size * _ids.size() + _suffix_size, 0x00);
|
||||
_message[0] = 0xFB;
|
||||
_message[1] = 0xEB;
|
||||
|
||||
for (int i = 0; i < _ids.length(); i++) {
|
||||
_message[_prefix_size + _colors + i * _id_size + 0] = (_ids[i] >> 0x00) & 0xFF;
|
||||
_message[_prefix_size + _colors + i * _id_size + 1] = (_ids[i] >> 0x08) & 0xFF;
|
||||
_message[_prefix_size + _colors + i * _id_size + 2] = (_ids[i] >> 0x10) & 0xFF;
|
||||
}
|
||||
|
||||
Debug(_log, "H801 using %s:%d", _address.toString().toStdString().c_str(), _port);
|
||||
}
|
||||
|
||||
_message = QByteArray(_prefix_size + _colors + _id_size * _ids.size() + _suffix_size, 0x00);
|
||||
_message[0] = 0xFB;
|
||||
_message[1] = 0xEB;
|
||||
|
||||
for (int i = 0; i < _ids.length(); i++) {
|
||||
_message[_prefix_size + _colors + i * _id_size + 0] = (_ids[i] >> 0x00) & 0xFF;
|
||||
_message[_prefix_size + _colors + i * _id_size + 1] = (_ids[i] >> 0x08) & 0xFF;
|
||||
_message[_prefix_size + _colors + i * _id_size + 2] = (_ids[i] >> 0x10) & 0xFF;
|
||||
}
|
||||
|
||||
Debug(_log, "H801 using %s:%d", _address.toString().toStdString().c_str(), _port);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpH801::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceUdpH801(deviceConfig);
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceUdpH801::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
@ -6,6 +6,11 @@
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending led colors via udp.
|
||||
///
|
||||
///
|
||||
|
||||
const ushort H801_DEFAULT_PORT = 30977;
|
||||
static const char H801_DEFAULT_HOST[] = "255.255.255.255";
|
||||
|
||||
class LedDeviceUdpH801: public ProviderUdp
|
||||
{
|
||||
protected:
|
||||
@ -22,17 +27,16 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceUdpH801(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceUdpH801(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -41,5 +45,5 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
@ -3,8 +3,8 @@
|
||||
LedDeviceUdpRaw::LedDeviceUdpRaw(const QJsonObject &deviceConfig)
|
||||
: ProviderUdp()
|
||||
{
|
||||
_port = 5568;
|
||||
init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpRaw::construct(const QJsonObject &deviceConfig)
|
||||
@ -12,6 +12,13 @@ LedDevice* LedDeviceUdpRaw::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceUdpRaw(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceUdpRaw::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_port = RAW_DEFAULT_PORT;
|
||||
bool isInitOK = ProviderUdp::init(deviceConfig);
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceUdpRaw::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());
|
||||
|
@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion incluse
|
||||
// hyperion includes
|
||||
#include "ProviderUdp.h"
|
||||
|
||||
#define RAW_DEFAULT_PORT 5568
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending led colors via udp.
|
||||
///
|
||||
@ -14,16 +16,24 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceUdpRaw(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceUdpRaw(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
///
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
@ -17,21 +17,22 @@
|
||||
|
||||
ProviderUdp::ProviderUdp()
|
||||
: LedDevice()
|
||||
, _port(1)
|
||||
, _defaultHost("127.0.0.1")
|
||||
, _udpSocket (nullptr)
|
||||
, _port(1)
|
||||
, _defaultHost("127.0.0.1")
|
||||
{
|
||||
_deviceReady = false;
|
||||
_latchTime_ms = 1;
|
||||
_udpSocket = new QUdpSocket(this);
|
||||
}
|
||||
|
||||
ProviderUdp::~ProviderUdp()
|
||||
{
|
||||
_udpSocket->close();
|
||||
_udpSocket->deleteLater();
|
||||
}
|
||||
|
||||
bool ProviderUdp::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
LedDevice::init(deviceConfig);
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
QString host = deviceConfig["host"].toString(_defaultHost);
|
||||
|
||||
@ -41,36 +42,86 @@ bool ProviderUdp::init(const QJsonObject &deviceConfig)
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "Failed to parse %s as an ip address.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
Debug( _log, "Failed to parse [%s] as an ip address.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
QHostInfo info = QHostInfo::fromName(host);
|
||||
if (info.addresses().isEmpty())
|
||||
{
|
||||
Debug( _log, "Failed to parse %s as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
throw std::runtime_error("invalid target address");
|
||||
Debug( _log, "Failed to parse [%s] as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
QString errortext = QString ("Invalid target address [%1]!").arg(host);
|
||||
this->setInError ( errortext );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "Successfully parsed %s as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
_address = info.addresses().first();
|
||||
}
|
||||
Debug( _log, "Successfully parsed %s as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
|
||||
_address = info.addresses().first();
|
||||
}
|
||||
|
||||
_port = deviceConfig["port"].toInt(_port);
|
||||
if ( (_port <= 0) || (_port > MAX_PORT) )
|
||||
int config_port = deviceConfig["port"].toInt(_port);
|
||||
if ( config_port <= 0 || config_port > MAX_PORT )
|
||||
{
|
||||
throw std::runtime_error("invalid target port");
|
||||
QString errortext = QString ("Invalid target port [%1]!").arg(config_port);
|
||||
this->setInError ( errortext );
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_port = static_cast<int>(config_port);
|
||||
Debug( _log, "UDP using %s:%d", _address.toString().toStdString().c_str() , _port );
|
||||
}
|
||||
|
||||
Debug( _log, "UDP using %s:%d", _address.toString().toStdString().c_str() , _port );
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
return true;
|
||||
bool ProviderUdp::initNetwork()
|
||||
{
|
||||
bool isInitOK = true;
|
||||
|
||||
// TODO: Add Network-Error handling
|
||||
_udpSocket = new QUdpSocket(this);
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int ProviderUdp::open()
|
||||
{
|
||||
QHostAddress localAddress = QHostAddress::Any;
|
||||
quint16 localPort = 0;
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
WarningIf( !_udpSocket->bind(localAddress, localPort), _log, "Could not bind local address: %s", strerror(errno));
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
if ( ! initNetwork())
|
||||
{
|
||||
this->setInError( "Network error!" );
|
||||
}
|
||||
else
|
||||
{
|
||||
QHostAddress localAddress = QHostAddress::Any;
|
||||
quint16 localPort = 0;
|
||||
|
||||
return 0;
|
||||
if ( !_udpSocket->bind(localAddress, localPort) )
|
||||
{
|
||||
Warning ( _log, "Could not bind local address: %s", strerror(errno));
|
||||
}
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ProviderUdp::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
// LedDevice specific closing activites
|
||||
if ( _udpSocket != nullptr)
|
||||
{
|
||||
_udpSocket->close();
|
||||
}
|
||||
}
|
||||
|
||||
int ProviderUdp::writeBytes(const unsigned size, const uint8_t * data)
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
class QUdpSocket;
|
||||
|
||||
#define MAX_PORT 65535
|
||||
const ushort MAX_PORT = 65535;
|
||||
|
||||
///
|
||||
/// The ProviderUdp implements an abstract base-class for LedDevices using UDP packets.
|
||||
@ -25,23 +25,37 @@ public:
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
///
|
||||
virtual ~ProviderUdp();
|
||||
virtual ~ProviderUdp() override;
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
/// Initialise device's network details
|
||||
///
|
||||
/// @return True if success
|
||||
bool initNetwork();
|
||||
|
||||
///
|
||||
/// Opens and configures the output device
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
int open();
|
||||
int open() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Writes the given bytes/bits to the UDP-device and sleeps the latch time to ensure that the
|
||||
/// values are latched.
|
||||
|
@ -7,7 +7,9 @@
|
||||
LedDeviceFile::LedDeviceFile(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
_printTimeStamp = false;
|
||||
}
|
||||
|
||||
LedDeviceFile::~LedDeviceFile()
|
||||
@ -21,39 +23,83 @@ LedDevice* LedDeviceFile::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceFile::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
LedDevice::init(deviceConfig);
|
||||
_refresh_timer_interval = 0;
|
||||
bool initOK = LedDevice::init(deviceConfig);
|
||||
|
||||
_fileName = deviceConfig["output"].toString("/dev/null");
|
||||
_printTimeStamp = deviceConfig["printTimeStamp"].toBool(false);
|
||||
|
||||
return true;
|
||||
return initOK;
|
||||
}
|
||||
|
||||
int LedDeviceFile::open()
|
||||
{
|
||||
if ( _ofs.is_open() )
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
if ( _ofs.is_open() )
|
||||
{
|
||||
_ofs.close();
|
||||
}
|
||||
|
||||
_ofs.open( QSTRING_CSTR(_fileName));
|
||||
if ( _ofs.fail() )
|
||||
{
|
||||
errortext = QString ("Failed to open file (%1). Error message: %2").arg(_fileName, strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDeviceFile::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
// LedDevice specific closing activites
|
||||
if ( _ofs )
|
||||
{
|
||||
_ofs.close();
|
||||
if ( _ofs.fail() )
|
||||
{
|
||||
Error( _log, "Failed to close device (%s). Error message: %s", QSTRING_CSTR(_fileName), strerror(errno) );
|
||||
}
|
||||
}
|
||||
_ofs.open( QSTRING_CSTR(_fileName) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LedDeviceFile::write(const std::vector<ColorRgb> & ledValues)
|
||||
{
|
||||
//printLedValues (ledValues);
|
||||
if ( _printTimeStamp )
|
||||
{
|
||||
// get a precise timestamp as a string
|
||||
const auto now = std::chrono::system_clock::now();
|
||||
const auto nowAsTimeT = std::chrono::system_clock::to_time_t(now);
|
||||
const auto nowMs = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
now.time_since_epoch()) % 1000;
|
||||
now.time_since_epoch()) % 1000;
|
||||
|
||||
const auto elapsedTimeMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastWriteTime);
|
||||
|
||||
_ofs
|
||||
<< std::put_time(std::localtime(&nowAsTimeT), "%Y-%m-%d %T")
|
||||
<< '.' << std::setfill('0') << std::setw(3) << nowMs.count();
|
||||
<< '.' << std::setfill('0') << std::setw(3) << nowMs.count()
|
||||
<< " | +" << std::setfill('0') << std::setw(4) << elapsedTimeMs.count();
|
||||
|
||||
lastWriteTime = now;
|
||||
}
|
||||
|
||||
_ofs << " [";
|
||||
for (const ColorRgb& color : ledValues)
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
// STL includes
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
|
||||
// Leddevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
@ -18,12 +19,12 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceFile(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceFile(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Destructor of this test-device
|
||||
///
|
||||
virtual ~LedDeviceFile();
|
||||
virtual ~LedDeviceFile() override;
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
@ -33,16 +34,23 @@ public:
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Opens and configures the output file
|
||||
/// Opens and initiatialises the output device
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
///
|
||||
///
|
||||
virtual int open();
|
||||
virtual int open() override;
|
||||
|
||||
///
|
||||
/// Writes the given led-color values to the output stream
|
||||
///
|
||||
@ -50,7 +58,7 @@ protected:
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
/// The outputstream
|
||||
std::ofstream _ofs;
|
||||
@ -60,4 +68,7 @@ private:
|
||||
QString _fileName;
|
||||
/// Timestamp for the output record
|
||||
bool _printTimeStamp;
|
||||
/// Last write/output timestamp
|
||||
std::chrono::system_clock::time_point lastWriteTime = std::chrono::system_clock::now();
|
||||
|
||||
};
|
||||
|
@ -12,12 +12,15 @@
|
||||
LedDevicePiBlaster::LedDevicePiBlaster(const QJsonObject &deviceConfig)
|
||||
: _fid(nullptr)
|
||||
{
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
// initialise the mapping tables
|
||||
// -1 is invalid
|
||||
// z is also meaningless
|
||||
// { "gpio" : 4, "ledindex" : 0, "ledcolor" : "r" },
|
||||
// initialise the mapping tables
|
||||
// -1 is invalid
|
||||
// z is also meaningless
|
||||
// { "gpio" : 4, "ledindex" : 0, "ledcolor" : "r" },
|
||||
#define TABLE_SZ sizeof(_gpio_to_led)/sizeof(_gpio_to_led[0])
|
||||
|
||||
for (unsigned i=0; i < TABLE_SZ; i++ )
|
||||
@ -25,51 +28,48 @@ LedDevicePiBlaster::LedDevicePiBlaster(const QJsonObject &deviceConfig)
|
||||
_gpio_to_led[i] = -1;
|
||||
_gpio_to_color[i] = 'z';
|
||||
}
|
||||
|
||||
_deviceReady = init(deviceConfig);
|
||||
}
|
||||
|
||||
LedDevicePiBlaster::~LedDevicePiBlaster()
|
||||
{
|
||||
// Close the device (if it is opened)
|
||||
if (_fid != nullptr)
|
||||
{
|
||||
fclose(_fid);
|
||||
_fid = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool LedDevicePiBlaster::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
LedDevice::init(deviceConfig);
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
_deviceName = deviceConfig["output"].toString("/dev/pi-blaster");
|
||||
QJsonArray gpioMapping = deviceConfig["gpiomap"].toArray();
|
||||
|
||||
if (gpioMapping.isEmpty())
|
||||
if ( isInitOK )
|
||||
{
|
||||
throw std::runtime_error("Piblaster: no gpiomap defined.");
|
||||
}
|
||||
QJsonArray gpioMapping = deviceConfig["gpiomap"].toArray();
|
||||
|
||||
// walk through the json config and populate the mapping tables
|
||||
for(QJsonArray::const_iterator gpioArray = gpioMapping.begin(); gpioArray != gpioMapping.end(); ++gpioArray)
|
||||
{
|
||||
const QJsonObject value = (*gpioArray).toObject();
|
||||
const int gpio = value["gpio"].toInt(-1);
|
||||
const int ledindex = value["ledindex"].toInt(-1);
|
||||
const std::string ledcolor = value["ledcolor"].toString("z").toStdString();
|
||||
if (gpioMapping.isEmpty())
|
||||
{
|
||||
this->setInError("PiBlaster: no gpiomap defined.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// ignore missing/invalid settings
|
||||
if ( (gpio >= 0) && (gpio < signed(TABLE_SZ)) && (ledindex >= 0) ){
|
||||
_gpio_to_led[gpio] = ledindex;
|
||||
_gpio_to_color[gpio] = ledcolor[0]; // 1st char of string
|
||||
} else {
|
||||
Warning( _log, "IGNORING gpio %d ledindex %d color %c", gpio,ledindex, ledcolor[0]);
|
||||
// walk through the json config and populate the mapping tables
|
||||
for(QJsonArray::const_iterator gpioArray = gpioMapping.begin(); gpioArray != gpioMapping.end(); ++gpioArray)
|
||||
{
|
||||
const QJsonObject value = (*gpioArray).toObject();
|
||||
const int gpio = value["gpio"].toInt(-1);
|
||||
const int ledindex = value["ledindex"].toInt(-1);
|
||||
const std::string ledcolor = value["ledcolor"].toString("z").toStdString();
|
||||
|
||||
// ignore missing/invalid settings
|
||||
if ( (gpio >= 0) && (gpio < signed(TABLE_SZ)) && (ledindex >= 0) ){
|
||||
_gpio_to_led[gpio] = ledindex;
|
||||
_gpio_to_color[gpio] = ledcolor[0]; // 1st char of string
|
||||
} else {
|
||||
Warning( _log, "IGNORING gpio %d ledindex %d color %c", gpio,ledindex, ledcolor[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
LedDevice* LedDevicePiBlaster::construct(const QJsonObject &deviceConfig)
|
||||
@ -79,30 +79,61 @@ LedDevice* LedDevicePiBlaster::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
int LedDevicePiBlaster::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
if (_fid != nullptr)
|
||||
{
|
||||
// The file pointer is already open
|
||||
errortext = QString ("Device (%1) is already open.").arg(_deviceName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!QFile::exists(_deviceName))
|
||||
{
|
||||
errortext = QString ("The device (%1) does not yet exist.").arg(_deviceName);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_fid = fopen(QSTRING_CSTR(_deviceName), "w");
|
||||
if (_fid == nullptr)
|
||||
{
|
||||
errortext = QString ("Failed to open device (%1). Error message: %2").arg(_deviceName, strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
Info( _log, "Connected to device(%s)", QSTRING_CSTR(_deviceName));
|
||||
retval = 0;
|
||||
setEnable(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LedDevicePiBlaster::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
// LedDevice specific closing activites
|
||||
// Close the device (if it is opened)
|
||||
if (_fid != nullptr)
|
||||
{
|
||||
// The file pointer is already open
|
||||
Error( _log, "Device (%s) is already open.", QSTRING_CSTR(_deviceName) );
|
||||
return -1;
|
||||
}
|
||||
fclose(_fid);
|
||||
_fid = nullptr;
|
||||
}}
|
||||
|
||||
if (!QFile::exists(_deviceName))
|
||||
{
|
||||
Error( _log, "The device (%s) does not yet exist.",QSTRING_CSTR(_deviceName) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
_fid = fopen(QSTRING_CSTR(_deviceName), "w");
|
||||
if (_fid == nullptr)
|
||||
{
|
||||
Error( _log, "Failed to open device (%s). Error message: %s", QSTRING_CSTR(_deviceName), strerror(errno) );
|
||||
return -1;
|
||||
}
|
||||
|
||||
Info( _log, "Connected to device(%s)", QSTRING_CSTR(_deviceName));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LedDevicePiBlaster::write(const std::vector<ColorRgb> & ledValues)
|
||||
{
|
||||
@ -112,11 +143,10 @@ int LedDevicePiBlaster::write(const std::vector<ColorRgb> & ledValues)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int valueIdx = -1;
|
||||
for (unsigned int i=0; i < TABLE_SZ; i++ )
|
||||
{
|
||||
valueIdx = _gpio_to_led[ i ];
|
||||
if ( (valueIdx >= 0) && (valueIdx < _ledCount) )
|
||||
int valueIdx = _gpio_to_led[ i ];
|
||||
if ( (valueIdx >= 0) && (valueIdx < static_cast<int>( _ledCount)) )
|
||||
{
|
||||
double pwmDutyCycle = 0.0;
|
||||
switch (_gpio_to_color[ i ])
|
||||
|
@ -15,27 +15,35 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDevicePiBlaster(const QJsonObject &deviceConfig);
|
||||
explicit LedDevicePiBlaster(const QJsonObject &deviceConfig);
|
||||
|
||||
virtual ~LedDevicePiBlaster();
|
||||
virtual ~LedDevicePiBlaster() override;
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Attempts to open the piblaster-device. This will only succeed if the device is not yet open
|
||||
/// and the device is available.
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
int open();
|
||||
int open() override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -45,7 +53,7 @@ private:
|
||||
///
|
||||
/// @return Zero on success else negative
|
||||
///
|
||||
int write(const std::vector<ColorRgb> &ledValues);
|
||||
int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
/// The name of the output device (very likely '/dev/pi-blaster')
|
||||
QString _deviceName;
|
||||
|
@ -1,64 +1,87 @@
|
||||
#include <exception>
|
||||
|
||||
#include "LedDeviceWS281x.h"
|
||||
|
||||
LedDeviceWS281x::LedDeviceWS281x(const QJsonObject &deviceConfig)
|
||||
: LedDevice()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDeviceWS281x::~LedDeviceWS281x()
|
||||
{
|
||||
if (_deviceReady)
|
||||
{
|
||||
ws2811_fini(&_led_string);
|
||||
}
|
||||
}
|
||||
|
||||
bool LedDeviceWS281x::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
LedDevice::init(deviceConfig);
|
||||
QString errortext;
|
||||
|
||||
QString whiteAlgorithm = deviceConfig["whiteAlgorithm"].toString("white_off");
|
||||
_whiteAlgorithm = RGBW::stringToWhiteAlgorithm(whiteAlgorithm);
|
||||
Debug( _log, "whiteAlgorithm : %s", QSTRING_CSTR(whiteAlgorithm));
|
||||
Debug( _log, "rgbw : %d", deviceConfig["rgbw"].toBool(false) );
|
||||
if (_whiteAlgorithm == RGBW::INVALID)
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
{
|
||||
Error(_log, "unknown whiteAlgorithm %s", QSTRING_CSTR(whiteAlgorithm));
|
||||
return false;
|
||||
|
||||
QString whiteAlgorithm = deviceConfig["whiteAlgorithm"].toString("white_off");
|
||||
|
||||
_whiteAlgorithm = RGBW::stringToWhiteAlgorithm(whiteAlgorithm);
|
||||
if (_whiteAlgorithm == RGBW::INVALID)
|
||||
{
|
||||
errortext = QString ("unknown whiteAlgorithm: %1").arg(whiteAlgorithm);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_channel = deviceConfig["pwmchannel"].toInt(0);
|
||||
if (_channel != 0 && _channel != 1)
|
||||
{
|
||||
errortext = "WS281x: invalid PWM channel; must be 0 or 1.";
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(&_led_string, 0, sizeof(_led_string));
|
||||
_led_string.freq = deviceConfig["freq"].toInt(800000ul);
|
||||
_led_string.dmanum = deviceConfig["dma"].toInt(5);
|
||||
_led_string.channel[_channel].gpionum = deviceConfig["gpio"].toInt(18);
|
||||
_led_string.channel[_channel].count = deviceConfig["leds"].toInt(256);
|
||||
_led_string.channel[_channel].invert = deviceConfig["invert"].toInt(0);
|
||||
_led_string.channel[_channel].strip_type = (deviceConfig["rgbw"].toBool(false) ? SK6812_STRIP_GRBW : WS2811_STRIP_RGB);
|
||||
_led_string.channel[_channel].brightness = 255;
|
||||
|
||||
_led_string.channel[!_channel].gpionum = 0;
|
||||
_led_string.channel[!_channel].invert = _led_string.channel[_channel].invert;
|
||||
_led_string.channel[!_channel].count = 0;
|
||||
_led_string.channel[!_channel].brightness = 0;
|
||||
_led_string.channel[!_channel].strip_type = WS2811_STRIP_RGB;
|
||||
|
||||
Debug( _log, "ws281x strip type : %d", _led_string.channel[_channel].strip_type );
|
||||
|
||||
if (ws2811_init(&_led_string) < 0)
|
||||
{
|
||||
errortext = "Unable to initialize ws281x library.";
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
isInitOK = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_channel = deviceConfig["pwmchannel"].toInt(0);
|
||||
if (_channel != 0 && _channel != 1)
|
||||
if ( !isInitOK)
|
||||
{
|
||||
throw std::runtime_error("WS281x: invalid PWM channel; must be 0 or 1.");
|
||||
this->setInError(errortext);
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
memset(&_led_string, 0, sizeof(_led_string));
|
||||
_led_string.freq = deviceConfig["freq"].toInt(800000ul);
|
||||
_led_string.dmanum = deviceConfig["dma"].toInt(5);
|
||||
_led_string.channel[_channel].gpionum = deviceConfig["gpio"].toInt(18);
|
||||
_led_string.channel[_channel].count = deviceConfig["leds"].toInt(256);
|
||||
_led_string.channel[_channel].invert = deviceConfig["invert"].toInt(0);
|
||||
_led_string.channel[_channel].strip_type = (deviceConfig["rgbw"].toBool(false) ? SK6812_STRIP_GRBW : WS2811_STRIP_RGB);
|
||||
_led_string.channel[_channel].brightness = 255;
|
||||
void LedDeviceWS281x::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
_led_string.channel[!_channel].gpionum = 0;
|
||||
_led_string.channel[!_channel].invert = _led_string.channel[_channel].invert;
|
||||
_led_string.channel[!_channel].count = 0;
|
||||
_led_string.channel[!_channel].brightness = 0;
|
||||
_led_string.channel[!_channel].strip_type = WS2811_STRIP_RGB;
|
||||
|
||||
Debug( _log, "ws281x strip type : %d", _led_string.channel[_channel].strip_type );
|
||||
|
||||
if (ws2811_init(&_led_string) < 0)
|
||||
if (_deviceReady)
|
||||
{
|
||||
throw std::runtime_error("Unable to initialize ws281x library.");
|
||||
ws2811_fini(&_led_string);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceWS281x::construct(const QJsonObject &deviceConfig)
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
#include <ws2811.h>
|
||||
|
||||
@ -19,17 +20,24 @@ public:
|
||||
///
|
||||
/// Destructor of the LedDevice, waits for DMA to complete and then cleans up
|
||||
///
|
||||
~LedDeviceWS281x();
|
||||
|
||||
~LedDeviceWS281x() override;
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -38,7 +46,7 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
ws2811_t _led_string;
|
||||
int _channel;
|
||||
|
@ -5,7 +5,9 @@ LedDeviceAdalight::LedDeviceAdalight(const QJsonObject &deviceConfig)
|
||||
, _headerSize(6)
|
||||
, _ligthBerryAPA102Mode(false)
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
|
||||
connect(this,SIGNAL(receivedData(QByteArray)),this,SLOT(receivedData(QByteArray)));
|
||||
}
|
||||
|
||||
@ -16,7 +18,8 @@ LedDevice* LedDeviceAdalight::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceAdalight::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
ProviderRs232::init(deviceConfig);
|
||||
bool isInitOK = ProviderRs232::init(deviceConfig);
|
||||
|
||||
_ligthBerryAPA102Mode = deviceConfig["lightberry_apa102_mode"].toBool(false);
|
||||
|
||||
// create ledBuffer
|
||||
@ -30,7 +33,7 @@ bool LedDeviceAdalight::init(const QJsonObject &deviceConfig)
|
||||
_ledBuffer.resize(_headerSize + (_ledCount * bytesPerRGBLed) + startFrameSize + endFrameSize, 0x00);
|
||||
|
||||
// init constant data values
|
||||
for (signed iLed=1; iLed<=_ledCount; iLed++)
|
||||
for (signed iLed=1; iLed<= static_cast<int>( _ledCount); iLed++)
|
||||
{
|
||||
_ledBuffer[iLed*4+_headerSize] = 0xFF;
|
||||
}
|
||||
@ -52,14 +55,14 @@ bool LedDeviceAdalight::init(const QJsonObject &deviceConfig)
|
||||
Debug( _log, "Adalight header for %d leds: %c%c%c 0x%02x 0x%02x 0x%02x", _ledCount,
|
||||
_ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3], _ledBuffer[4], _ledBuffer[5] );
|
||||
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceAdalight::write(const std::vector<ColorRgb> & ledValues)
|
||||
{
|
||||
if(_ligthBerryAPA102Mode)
|
||||
{
|
||||
for (signed iLed=1; iLed<=_ledCount; iLed++)
|
||||
for (signed iLed=1; iLed<=static_cast<int>( _ledCount); iLed++)
|
||||
{
|
||||
const ColorRgb& rgb = ledValues[iLed-1];
|
||||
_ledBuffer[iLed*4+7] = rgb.red;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderRs232.h"
|
||||
|
||||
///
|
||||
@ -15,12 +16,12 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceAdalight(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceAdalight(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
void receivedData(QByteArray data);
|
||||
@ -32,7 +33,7 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> & ledValues) override;
|
||||
|
||||
const short _headerSize;
|
||||
bool _ligthBerryAPA102Mode;
|
||||
|
@ -4,7 +4,8 @@
|
||||
LedDeviceAtmo::LedDeviceAtmo(const QJsonObject &deviceConfig)
|
||||
: ProviderRs232()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceAtmo::construct(const QJsonObject &deviceConfig)
|
||||
@ -14,21 +15,27 @@ LedDevice* LedDeviceAtmo::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceAtmo::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
ProviderRs232::init(deviceConfig);
|
||||
bool isInitOK = ProviderRs232::init(deviceConfig);
|
||||
|
||||
if (_ledCount != 5)
|
||||
if ( isInitOK )
|
||||
{
|
||||
Error( _log, "%d channels configured. This should always be 5!", _ledCount);
|
||||
return 0;
|
||||
if (_ledCount != 5)
|
||||
{
|
||||
//Error( _log, "%d channels configured. This should always be 5!", _ledCount);
|
||||
QString errortext = QString ("%1 channels configured. This should always be 5!").arg(_ledCount);
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ledBuffer.resize(4 + 5*3); // 4-byte header, 5 RGB values
|
||||
_ledBuffer[0] = 0xFF; // Startbyte
|
||||
_ledBuffer[1] = 0x00; // StartChannel(Low)
|
||||
_ledBuffer[2] = 0x00; // StartChannel(High)
|
||||
_ledBuffer[3] = 0x0F; // Number of Databytes send (always! 15)
|
||||
}
|
||||
}
|
||||
|
||||
_ledBuffer.resize(4 + 5*3); // 4-byte header, 5 RGB values
|
||||
_ledBuffer[0] = 0xFF; // Startbyte
|
||||
_ledBuffer[1] = 0x00; // StartChannel(Low)
|
||||
_ledBuffer[2] = 0x00; // StartChannel(High)
|
||||
_ledBuffer[3] = 0x0F; // Number of Databytes send (always! 15)
|
||||
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceAtmo::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion incluse
|
||||
// hyperion includes
|
||||
#include "ProviderRs232.h"
|
||||
|
||||
///
|
||||
@ -14,12 +14,12 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceAtmo(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceAtmo(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -28,5 +28,5 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
@ -10,44 +10,8 @@ LedDeviceDMX::LedDeviceDMX(const QJsonObject &deviceConfig)
|
||||
, _dmxLedCount(0)
|
||||
, _dmxChannelCount(0)
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceDMX::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
ProviderRs232::init(deviceConfig);
|
||||
|
||||
QString dmxString = deviceConfig["dmxdevice"].toString("invalid");
|
||||
if (dmxString == "raw")
|
||||
{
|
||||
_dmxDeviceType = 0;
|
||||
_dmxStart = 1;
|
||||
_dmxSlotsPerLed = 3;
|
||||
}
|
||||
else if (dmxString == "McCrypt")
|
||||
{
|
||||
_dmxDeviceType = 1;
|
||||
_dmxStart = 1;
|
||||
_dmxSlotsPerLed = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(_log, "unknown dmx device type %s", QSTRING_CSTR(dmxString));
|
||||
}
|
||||
|
||||
Debug(_log, "_dmxString \"%s\", _dmxDeviceType %d", QSTRING_CSTR(dmxString), _dmxDeviceType );
|
||||
_rs232Port.setStopBits(QSerialPort::TwoStop);
|
||||
|
||||
_dmxLedCount = qMin(_ledCount, 512/_dmxSlotsPerLed);
|
||||
_dmxChannelCount = 1 + _dmxSlotsPerLed * _dmxLedCount;
|
||||
|
||||
Debug(_log, "_dmxStart %d, _dmxSlotsPerLed %d", _dmxStart, _dmxSlotsPerLed);
|
||||
Debug(_log, "_ledCount %d, _dmxLedCount %d, _dmxChannelCount %d", _ledCount, _dmxLedCount, _dmxChannelCount);
|
||||
|
||||
_ledBuffer.resize(_dmxChannelCount, 0);
|
||||
_ledBuffer[0] = 0x00; // NULL START code
|
||||
|
||||
return true;
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceDMX::construct(const QJsonObject &deviceConfig)
|
||||
@ -55,6 +19,48 @@ LedDevice* LedDeviceDMX::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceDMX(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceDMX::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderRs232::init(deviceConfig);
|
||||
|
||||
if ( isInitOK )
|
||||
{
|
||||
QString dmxString = deviceConfig["dmxdevice"].toString("invalid");
|
||||
if (dmxString == "raw")
|
||||
{
|
||||
_dmxDeviceType = 0;
|
||||
_dmxStart = 1;
|
||||
_dmxSlotsPerLed = 3;
|
||||
}
|
||||
else if (dmxString == "McCrypt")
|
||||
{
|
||||
_dmxDeviceType = 1;
|
||||
_dmxStart = 1;
|
||||
_dmxSlotsPerLed = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Error(_log, "unknown dmx device type %s", QSTRING_CSTR(dmxString));
|
||||
QString errortext = QString ("unknown dmx device type: %1").arg(dmxString);
|
||||
this->setInError(errortext);
|
||||
return false;
|
||||
}
|
||||
|
||||
Debug(_log, "_dmxString \"%s\", _dmxDeviceType %d", QSTRING_CSTR(dmxString), _dmxDeviceType );
|
||||
_rs232Port.setStopBits(QSerialPort::TwoStop);
|
||||
|
||||
_dmxLedCount = qMin(static_cast<int>(_ledCount), 512/_dmxSlotsPerLed);
|
||||
_dmxChannelCount = 1 + _dmxSlotsPerLed * _dmxLedCount;
|
||||
|
||||
Debug(_log, "_dmxStart %d, _dmxSlotsPerLed %d", _dmxStart, _dmxSlotsPerLed);
|
||||
Debug(_log, "_ledCount %d, _dmxLedCount %d, _dmxChannelCount %d", _ledCount, _dmxLedCount, _dmxChannelCount);
|
||||
|
||||
_ledBuffer.resize(_dmxChannelCount, 0);
|
||||
_ledBuffer[0] = 0x00; // NULL START code
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceDMX::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
switch (_dmxDeviceType) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion incluse
|
||||
// hyperion includes
|
||||
#include "ProviderRs232.h"
|
||||
|
||||
///
|
||||
@ -14,12 +14,12 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceDMX(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceDMX(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -28,7 +28,7 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
int _dmxDeviceType = 0;
|
||||
int _dmxStart = 1;
|
||||
int _dmxSlotsPerLed = 3;
|
||||
|
@ -4,7 +4,9 @@
|
||||
LedDeviceKarate::LedDeviceKarate(const QJsonObject &deviceConfig)
|
||||
: ProviderRs232()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
|
||||
connect(this,SIGNAL(receivedData(QByteArray)),this,SLOT(receivedData(QByteArray)));
|
||||
}
|
||||
|
||||
@ -15,23 +17,31 @@ LedDevice* LedDeviceKarate::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceKarate::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
ProviderRs232::init(deviceConfig);
|
||||
bool isInitOK = ProviderRs232::init(deviceConfig);
|
||||
|
||||
if (_ledCount != 16)
|
||||
if ( isInitOK )
|
||||
{
|
||||
Error( _log, "%d channels configured. This should always be 16!", _ledCount);
|
||||
return 0;
|
||||
if (_ledCount != 16)
|
||||
{
|
||||
//Error( _log, "%d channels configured. This should always be 16!", _ledCount);
|
||||
QString errortext = QString ("%1 channels configured. This should always be 16!").arg(_ledCount);
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
_ledBuffer.resize(4 + _ledCount * 3); // 4-byte header, 3 RGB values
|
||||
_ledBuffer[0] = 0xAA; // Startbyte
|
||||
_ledBuffer[1] = 0x12; // Send all Channels in Batch
|
||||
_ledBuffer[2] = 0x00; // Checksum
|
||||
_ledBuffer[3] = _ledCount * 3; // Number of Databytes send
|
||||
|
||||
Debug( _log, "Karatelight header for %d leds: 0x%02x 0x%02x 0x%02x 0x%02x", _ledCount,
|
||||
_ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3] );
|
||||
}
|
||||
}
|
||||
|
||||
_ledBuffer.resize(4 + _ledCount * 3); // 4-byte header, 3 RGB values
|
||||
_ledBuffer[0] = 0xAA; // Startbyte
|
||||
_ledBuffer[1] = 0x12; // Send all Channels in Batch
|
||||
_ledBuffer[2] = 0x00; // Checksum
|
||||
_ledBuffer[3] = _ledCount * 3; // Number of Databytes send
|
||||
|
||||
Debug( _log, "Karatelight header for %d leds: 0x%02x 0x%02x 0x%02x 0x%02x", _ledCount,
|
||||
_ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3] );
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceKarate::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion incluse
|
||||
// hyperion includes
|
||||
#include "ProviderRs232.h"
|
||||
|
||||
///
|
||||
@ -15,12 +15,12 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceKarate(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceKarate(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
public slots:
|
||||
void receivedData(QByteArray data);
|
||||
@ -32,5 +32,5 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
@ -9,7 +9,8 @@ struct FrameSpec
|
||||
LedDeviceSedu::LedDeviceSedu(const QJsonObject &deviceConfig)
|
||||
: ProviderRs232()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceSedu::construct(const QJsonObject &deviceConfig)
|
||||
@ -19,7 +20,7 @@ LedDevice* LedDeviceSedu::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceSedu::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
ProviderRs232::init(deviceConfig);
|
||||
bool isInitOK = ProviderRs232::init(deviceConfig);
|
||||
|
||||
std::vector<FrameSpec> frameSpecs{{0xA1, 256}, {0xA2, 512}, {0xB0, 768}, {0xB1, 1536}, {0xB2, 3072} };
|
||||
|
||||
@ -38,11 +39,13 @@ bool LedDeviceSedu::init(const QJsonObject &deviceConfig)
|
||||
|
||||
if (_ledBuffer.size() == 0)
|
||||
{
|
||||
Warning(_log, "More rgb-channels required then available");
|
||||
return false;
|
||||
//Warning(_log, "More rgb-channels required then available");
|
||||
QString errortext = "More rgb-channels required then available";
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceSedu::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion incluse
|
||||
// hyperion includes
|
||||
#include "ProviderRs232.h"
|
||||
|
||||
///
|
||||
@ -14,12 +14,12 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceSedu(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceSedu(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -28,5 +28,5 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
@ -4,7 +4,8 @@
|
||||
LedDeviceTpm2::LedDeviceTpm2(const QJsonObject &deviceConfig)
|
||||
: ProviderRs232()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceTpm2::construct(const QJsonObject &deviceConfig)
|
||||
@ -14,7 +15,7 @@ LedDevice* LedDeviceTpm2::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceTpm2::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
ProviderRs232::init(deviceConfig);
|
||||
bool isInitOK = ProviderRs232::init(deviceConfig);
|
||||
|
||||
_ledBuffer.resize(5 + _ledRGBCount);
|
||||
_ledBuffer[0] = 0xC9; // block-start byte
|
||||
@ -23,7 +24,7 @@ bool LedDeviceTpm2::init(const QJsonObject &deviceConfig)
|
||||
_ledBuffer[3] = _ledRGBCount & 0xFF; // frame size low byte
|
||||
_ledBuffer.back() = 0x36; // block-end byte
|
||||
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceTpm2::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion incluse
|
||||
// hyperion includes
|
||||
#include "ProviderRs232.h"
|
||||
|
||||
///
|
||||
@ -14,12 +14,12 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceTpm2(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceTpm2(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -28,5 +28,5 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
@ -27,6 +27,7 @@ ProviderRs232::ProviderRs232()
|
||||
connect(&_rs232Port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(error(QSerialPort::SerialPortError)));
|
||||
connect(&_rs232Port, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64)));
|
||||
connect(&_rs232Port, SIGNAL(readyRead()), this, SLOT(readyRead()));
|
||||
|
||||
_writeTimeout.setInterval(5000);
|
||||
_writeTimeout.setSingleShot(true);
|
||||
connect(&_writeTimeout, SIGNAL(timeout()), this, SLOT(writeTimeout()));
|
||||
@ -36,7 +37,7 @@ bool ProviderRs232::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
closeDevice();
|
||||
|
||||
LedDevice::init(deviceConfig);
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
_deviceName = deviceConfig["output"].toString("auto");
|
||||
_enableAutoDeviceName = _deviceName == "auto";
|
||||
@ -44,7 +45,16 @@ bool ProviderRs232::init(const QJsonObject &deviceConfig)
|
||||
_delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(1500);
|
||||
_preOpenDelay = deviceConfig["delayBeforeConnect"].toInt(1500);
|
||||
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
|
||||
void ProviderRs232::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
// LedDevice specific closing activites
|
||||
closeDevice();
|
||||
}
|
||||
|
||||
QString ProviderRs232::findSerialDevice()
|
||||
@ -56,7 +66,6 @@ QString ProviderRs232::findSerialDevice()
|
||||
{
|
||||
Info(_log, "found serial device: %s", port.systemLocation().toLocal8Bit().constData());
|
||||
return port.systemLocation();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
@ -122,6 +131,7 @@ void ProviderRs232::error(QSerialPort::SerialPortError error)
|
||||
_deviceReady = false;
|
||||
}
|
||||
_rs232Port.clearError();
|
||||
this->setInError( "Rs232 SerialPortError, see details in previous log lines!" );
|
||||
closeDevice();
|
||||
}
|
||||
}
|
||||
@ -130,7 +140,6 @@ void ProviderRs232::error(QSerialPort::SerialPortError error)
|
||||
ProviderRs232::~ProviderRs232()
|
||||
{
|
||||
disconnect(&_rs232Port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(error(QSerialPort::SerialPortError)));
|
||||
closeDevice();
|
||||
}
|
||||
|
||||
void ProviderRs232::closeDevice()
|
||||
@ -151,9 +160,27 @@ void ProviderRs232::closeDevice()
|
||||
|
||||
int ProviderRs232::open()
|
||||
{
|
||||
return tryOpen(_delayAfterConnect_ms) ? 0 : -1;
|
||||
}
|
||||
int retval = -1;
|
||||
_deviceReady = false;
|
||||
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
if ( tryOpen(_delayAfterConnect_ms) )
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setInError( "Error opening device!" );
|
||||
}
|
||||
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool ProviderRs232::tryOpen(const int delayAfterConnect_ms)
|
||||
{
|
||||
@ -247,16 +274,13 @@ int ProviderRs232::writeBytes(const qint64 size, const uint8_t * data)
|
||||
|
||||
void ProviderRs232::writeTimeout()
|
||||
{
|
||||
Error(_log, "Timeout on write data to %s", _deviceName.toLocal8Bit().constData());
|
||||
closeDevice();
|
||||
//Error(_log, "Timeout on write data to %s", _deviceName.toLocal8Bit().constData());
|
||||
QString errortext = QString ("Timeout on write data to %1").arg(_deviceName);
|
||||
setInError( errortext );
|
||||
close();
|
||||
}
|
||||
|
||||
void ProviderRs232::unblockAfterDelay()
|
||||
{
|
||||
_blockedForDelay = false;
|
||||
}
|
||||
|
||||
int ProviderRs232::rewriteLeds()
|
||||
{
|
||||
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <QTimer>
|
||||
#include <QString>
|
||||
|
||||
// Leddevice includes
|
||||
// LedDevice includes
|
||||
#include <leddevice/LedDevice.h>
|
||||
|
||||
///
|
||||
@ -26,28 +26,33 @@ public:
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
///
|
||||
/// Destructor of the LedDevice; closes the output device if it is open
|
||||
///
|
||||
virtual ~ProviderRs232();
|
||||
virtual ~ProviderRs232() override;
|
||||
|
||||
///
|
||||
/// Opens and configures the output device
|
||||
///
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
int open();
|
||||
int open() override;
|
||||
|
||||
public slots:
|
||||
///
|
||||
/// Closes the output device.
|
||||
/// Includes switching-off the device and stopping refreshes
|
||||
///
|
||||
virtual void close() override;
|
||||
|
||||
private slots:
|
||||
/// Write the last data to the leds again
|
||||
int rewriteLeds();
|
||||
|
||||
/// Unblock the device after a connection delay
|
||||
void writeTimeout();
|
||||
void unblockAfterDelay();
|
||||
void error(QSerialPort::SerialPortError error);
|
||||
void error(QSerialPort::SerialPortError setInError);
|
||||
void bytesWritten(qint64 bytes);
|
||||
void readyRead();
|
||||
|
||||
|
@ -3,7 +3,8 @@
|
||||
LedDeviceAPA102::LedDeviceAPA102(const QJsonObject &deviceConfig)
|
||||
: ProviderSpi()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceAPA102::construct(const QJsonObject &deviceConfig)
|
||||
@ -13,24 +14,26 @@ LedDevice* LedDeviceAPA102::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceAPA102::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
ProviderSpi::init(deviceConfig);
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
|
||||
const unsigned int startFrameSize = 4;
|
||||
const unsigned int endFrameSize = qMax<unsigned int>(((_ledCount + 15) / 16), 4);
|
||||
const unsigned int APAbufferSize = (_ledCount * 4) + startFrameSize + endFrameSize;
|
||||
if ( isInitOK )
|
||||
{
|
||||
const unsigned int startFrameSize = 4;
|
||||
const unsigned int endFrameSize = qMax<unsigned int>(((_ledCount + 15) / 16), 4);
|
||||
const unsigned int APAbufferSize = (_ledCount * 4) + startFrameSize + endFrameSize;
|
||||
|
||||
_ledBuffer.resize(APAbufferSize, 0xFF);
|
||||
_ledBuffer[0] = 0x00;
|
||||
_ledBuffer[1] = 0x00;
|
||||
_ledBuffer[2] = 0x00;
|
||||
_ledBuffer[3] = 0x00;
|
||||
|
||||
return true;
|
||||
_ledBuffer.resize(APAbufferSize, 0xFF);
|
||||
_ledBuffer[0] = 0x00;
|
||||
_ledBuffer[1] = 0x00;
|
||||
_ledBuffer[2] = 0x00;
|
||||
_ledBuffer[3] = 0x00;
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceAPA102::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
for (signed iLed=0; iLed < _ledCount; ++iLed) {
|
||||
for (signed iLed=0; iLed < static_cast<int>( _ledCount); ++iLed) {
|
||||
const ColorRgb& rgb = ledValues[iLed];
|
||||
_ledBuffer[4+iLed*4] = 0xFF;
|
||||
_ledBuffer[4+iLed*4+1] = rgb.red;
|
||||
|
@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion incluse
|
||||
// hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for writing to APA102 led device.
|
||||
///
|
||||
@ -13,12 +12,17 @@ public:
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
///
|
||||
LedDeviceAPA102(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceAPA102(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
private:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
@ -26,5 +30,5 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
@ -45,7 +45,8 @@ LedDeviceAPA104::LedDeviceAPA104(const QJsonObject &deviceConfig)
|
||||
0b11101110,
|
||||
}
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceAPA104::construct(const QJsonObject &deviceConfig)
|
||||
@ -56,15 +57,15 @@ LedDevice* LedDeviceAPA104::construct(const QJsonObject &deviceConfig)
|
||||
bool LedDeviceAPA104::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_baudRate_Hz = 2235000;
|
||||
if ( !ProviderSpi::init(deviceConfig) )
|
||||
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
{
|
||||
return false;
|
||||
WarningIf(( _baudRate_Hz < 2000000 || _baudRate_Hz > 2470000 ), _log, "SPI rate %d outside recommended range (2000000 -> 2470000)", _baudRate_Hz);
|
||||
|
||||
_ledBuffer.resize(_ledRGBCount * SPI_BYTES_PER_COLOUR + SPI_FRAME_END_LATCH_BYTES, 0x00);
|
||||
}
|
||||
WarningIf(( _baudRate_Hz < 2000000 || _baudRate_Hz > 2470000 ), _log, "SPI rate %d outside recommended range (2000000 -> 2470000)", _baudRate_Hz);
|
||||
|
||||
_ledBuffer.resize(_ledRGBCount * SPI_BYTES_PER_COLOUR + SPI_FRAME_END_LATCH_BYTES, 0x00);
|
||||
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceAPA104::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion incluse
|
||||
// hyperion inclusdes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
@ -14,7 +14,7 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceAPA104(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceAPA104(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
@ -24,7 +24,7 @@ public:
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -33,10 +33,9 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
|
||||
const int SPI_BYTES_PER_COLOUR;
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
const int SPI_BYTES_PER_COLOUR;
|
||||
const int SPI_FRAME_END_LATCH_BYTES;
|
||||
|
||||
uint8_t bitpair_to_byte[4];
|
||||
|
@ -3,7 +3,8 @@
|
||||
LedDeviceLpd6803::LedDeviceLpd6803(const QJsonObject &deviceConfig)
|
||||
: ProviderSpi()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceLpd6803::construct(const QJsonObject &deviceConfig)
|
||||
@ -13,13 +14,14 @@ LedDevice* LedDeviceLpd6803::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceLpd6803::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
ProviderSpi::init(deviceConfig);
|
||||
|
||||
unsigned messageLength = 4 + 2*_ledCount + _ledCount/8 + 1;
|
||||
// Initialise the buffer
|
||||
_ledBuffer.resize(messageLength, 0x00);
|
||||
|
||||
return true;
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
{
|
||||
unsigned messageLength = 4 + 2*_ledCount + _ledCount/8 + 1;
|
||||
// Initialise the buffer
|
||||
_ledBuffer.resize(messageLength, 0x00);
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceLpd6803::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// Local hyperion incluse
|
||||
// Local hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
@ -22,12 +22,17 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceLpd6803(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceLpd6803(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -36,5 +41,5 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
@ -3,7 +3,8 @@
|
||||
LedDeviceLpd8806::LedDeviceLpd8806(const QJsonObject &deviceConfig)
|
||||
: ProviderSpi()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceLpd8806::construct(const QJsonObject &deviceConfig)
|
||||
@ -13,15 +14,46 @@ LedDevice* LedDeviceLpd8806::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceLpd8806::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
ProviderSpi::init(deviceConfig);
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
|
||||
const unsigned clearSize = _ledCount/32+1;
|
||||
unsigned messageLength = _ledRGBCount + clearSize;
|
||||
// Initialise the buffer
|
||||
_ledBuffer.resize(messageLength, 0x00);
|
||||
|
||||
// Perform an initial reset to start accepting data on the first led
|
||||
return writeBytes(clearSize, _ledBuffer.data());
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceLpd8806::open()
|
||||
{
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
// General initialisation and configuration of LedDevice
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
// Perform an initial reset to start accepting data on the first led
|
||||
|
||||
const unsigned clearSize = _ledCount/32+1;
|
||||
if ( writeBytes(clearSize, _ledBuffer.data()) < 0 )
|
||||
{
|
||||
errortext = QString ("Failed to do initial write");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything is OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
// On error/exceptions, set LedDevice in error
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int LedDeviceLpd8806::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// Local hyperion incluse
|
||||
// Local hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
@ -83,12 +83,25 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceLpd8806(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceLpd8806(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Opens and initiatialises the output device
|
||||
///
|
||||
/// @return Zero on succes (i.e. device is ready and enabled) else negative
|
||||
///
|
||||
virtual int open() override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -97,5 +110,5 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
@ -3,7 +3,8 @@
|
||||
LedDeviceP9813::LedDeviceP9813(const QJsonObject &deviceConfig)
|
||||
: ProviderSpi()
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceP9813::construct(const QJsonObject &deviceConfig)
|
||||
@ -13,11 +14,12 @@ LedDevice* LedDeviceP9813::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceP9813::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
ProviderSpi::init(deviceConfig);
|
||||
|
||||
_ledBuffer.resize(_ledCount * 4 + 8, 0x00);
|
||||
|
||||
return true;
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
{
|
||||
_ledBuffer.resize(_ledCount * 4 + 8, 0x00);
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceP9813::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion include
|
||||
// hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
@ -14,12 +14,17 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceP9813(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceP9813(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -28,7 +33,7 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
///
|
||||
/// Calculates the required checksum for one led
|
||||
|
@ -1,17 +1,18 @@
|
||||
#include "LedDeviceSk6812SPI.h"
|
||||
|
||||
LedDeviceSk6812SPI::LedDeviceSk6812SPI(const QJsonObject &deviceConfig)
|
||||
LedDeviceSk6812SPI::LedDeviceSk6812SPI(const QJsonObject &deviceConfig)
|
||||
: ProviderSpi()
|
||||
, _whiteAlgorithm(RGBW::INVALID)
|
||||
, SPI_BYTES_PER_COLOUR(4)
|
||||
, bitpair_to_byte {
|
||||
0b10001000,
|
||||
0b10001100,
|
||||
0b11001000,
|
||||
0b11001100,
|
||||
}
|
||||
, _whiteAlgorithm(RGBW::INVALID)
|
||||
, SPI_BYTES_PER_COLOUR(4)
|
||||
, bitpair_to_byte {
|
||||
0b10001000,
|
||||
0b10001100,
|
||||
0b11001000,
|
||||
0b11001100,
|
||||
}
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceSk6812SPI::construct(const QJsonObject &deviceConfig)
|
||||
@ -21,27 +22,31 @@ LedDevice* LedDeviceSk6812SPI::construct(const QJsonObject &deviceConfig)
|
||||
|
||||
bool LedDeviceSk6812SPI::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
QString whiteAlgorithm = deviceConfig["whiteAlgorithm"].toString("white_off");
|
||||
_whiteAlgorithm = RGBW::stringToWhiteAlgorithm(whiteAlgorithm);
|
||||
|
||||
if (_whiteAlgorithm == RGBW::INVALID)
|
||||
{
|
||||
Error(_log, "unknown whiteAlgorithm %s", QSTRING_CSTR(whiteAlgorithm));
|
||||
return false;
|
||||
}
|
||||
Debug( _log, "whiteAlgorithm : %s", QSTRING_CSTR(whiteAlgorithm));
|
||||
|
||||
_baudRate_Hz = 3000000;
|
||||
if ( !ProviderSpi::init(deviceConfig) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
WarningIf(( _baudRate_Hz < 2050000 || _baudRate_Hz > 4000000 ), _log, "SPI rate %d outside recommended range (2050000 -> 4000000)", _baudRate_Hz);
|
||||
|
||||
const int SPI_FRAME_END_LATCH_BYTES = 3;
|
||||
_ledBuffer.resize(_ledRGBWCount * SPI_BYTES_PER_COLOUR + SPI_FRAME_END_LATCH_BYTES, 0x00);
|
||||
|
||||
return true;
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
{
|
||||
QString whiteAlgorithm = deviceConfig["whiteAlgorithm"].toString("white_off");
|
||||
|
||||
_whiteAlgorithm = RGBW::stringToWhiteAlgorithm(whiteAlgorithm);
|
||||
if (_whiteAlgorithm == RGBW::INVALID)
|
||||
{
|
||||
QString errortext = QString ("unknown whiteAlgorithm: %1").arg(whiteAlgorithm);
|
||||
this->setInError(errortext);
|
||||
isInitOK = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug( _log, "whiteAlgorithm : %s", QSTRING_CSTR(whiteAlgorithm));
|
||||
|
||||
WarningIf(( _baudRate_Hz < 2050000 || _baudRate_Hz > 4000000 ), _log, "SPI rate %d outside recommended range (2050000 -> 4000000)", _baudRate_Hz);
|
||||
|
||||
const int SPI_FRAME_END_LATCH_BYTES = 3;
|
||||
_ledBuffer.resize(_ledRGBWCount * SPI_BYTES_PER_COLOUR + SPI_FRAME_END_LATCH_BYTES, 0x00);
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceSk6812SPI::write(const std::vector<ColorRgb> &ledValues)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion incluse
|
||||
// hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
@ -14,7 +14,7 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceSk6812SPI(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceSk6812SPI(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
@ -24,7 +24,7 @@ public:
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
bool init(const QJsonObject &deviceConfig);
|
||||
bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -33,13 +33,12 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
RGBW::WhiteAlgorithm _whiteAlgorithm;
|
||||
|
||||
const int SPI_BYTES_PER_COLOUR;
|
||||
|
||||
const int SPI_BYTES_PER_COLOUR;
|
||||
uint8_t bitpair_to_byte[4];
|
||||
|
||||
|
||||
ColorRgbw _temp_rgbw;
|
||||
};
|
||||
|
@ -36,20 +36,20 @@ Reset time is 50uS = 100 bits = 13 bytes
|
||||
|
||||
*/
|
||||
|
||||
|
||||
LedDeviceSk6822SPI::LedDeviceSk6822SPI(const QJsonObject &deviceConfig)
|
||||
: ProviderSpi()
|
||||
, SPI_BYTES_PER_COLOUR(4)
|
||||
, SPI_BYTES_WAIT_TIME(3)
|
||||
, SPI_FRAME_END_LATCH_BYTES(13)
|
||||
, bitpair_to_byte {
|
||||
0b10001000,
|
||||
0b10001110,
|
||||
0b11101000,
|
||||
0b11101110,
|
||||
}
|
||||
, SPI_BYTES_PER_COLOUR(4)
|
||||
, SPI_BYTES_WAIT_TIME(3)
|
||||
, SPI_FRAME_END_LATCH_BYTES(13)
|
||||
, bitpair_to_byte {
|
||||
0b10001000,
|
||||
0b10001110,
|
||||
0b11101000,
|
||||
0b11101110,
|
||||
}
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceSk6822SPI::construct(const QJsonObject &deviceConfig)
|
||||
@ -60,16 +60,17 @@ LedDevice* LedDeviceSk6822SPI::construct(const QJsonObject &deviceConfig)
|
||||
bool LedDeviceSk6822SPI::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_baudRate_Hz = 2230000;
|
||||
if ( !ProviderSpi::init(deviceConfig) )
|
||||
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
{
|
||||
return false;
|
||||
WarningIf(( _baudRate_Hz < 2000000 || _baudRate_Hz > 2460000 ), _log, "SPI rate %d outside recommended range (2000000 -> 2460000)", _baudRate_Hz);
|
||||
|
||||
_ledBuffer.resize( (_ledRGBCount * SPI_BYTES_PER_COLOUR) + (_ledCount * SPI_BYTES_WAIT_TIME ) + SPI_FRAME_END_LATCH_BYTES, 0x00);
|
||||
// Debug(_log, "_ledBuffer.resize(_ledRGBCount:%d * SPI_BYTES_PER_COLOUR:%d) + ( _ledCount:%d * SPI_BYTES_WAIT_TIME:%d ) + SPI_FRAME_END_LATCH_BYTES:%d, 0x00)", _ledRGBCount, SPI_BYTES_PER_COLOUR, _ledCount, SPI_BYTES_WAIT_TIME, SPI_FRAME_END_LATCH_BYTES);
|
||||
}
|
||||
WarningIf(( _baudRate_Hz < 2000000 || _baudRate_Hz > 2460000 ), _log, "SPI rate %d outside recommended range (2000000 -> 2460000)", _baudRate_Hz);
|
||||
|
||||
_ledBuffer.resize( (_ledRGBCount * SPI_BYTES_PER_COLOUR) + (_ledCount * SPI_BYTES_WAIT_TIME ) + SPI_FRAME_END_LATCH_BYTES, 0x00);
|
||||
// Debug(_log, "_ledBuffer.resize(_ledRGBCount:%d * SPI_BYTES_PER_COLOUR:%d) + ( _ledCount:%d * SPI_BYTES_WAIT_TIME:%d ) + SPI_FRAME_END_LATCH_BYTES:%d, 0x00)", _ledRGBCount, SPI_BYTES_PER_COLOUR, _ledCount, SPI_BYTES_WAIT_TIME, SPI_FRAME_END_LATCH_BYTES);
|
||||
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceSk6822SPI::write(const std::vector<ColorRgb> &ledValues)
|
||||
@ -80,8 +81,8 @@ int LedDeviceSk6822SPI::write(const std::vector<ColorRgb> &ledValues)
|
||||
for (const ColorRgb& color : ledValues)
|
||||
{
|
||||
uint32_t colorBits = ((unsigned int)color.red << 16)
|
||||
| ((unsigned int)color.green << 8)
|
||||
| color.blue;
|
||||
| ((unsigned int)color.green << 8)
|
||||
| color.blue;
|
||||
|
||||
for (int j=SPI_BYTES_PER_LED - 1; j>=0; j--)
|
||||
{
|
||||
@ -93,7 +94,7 @@ int LedDeviceSk6822SPI::write(const std::vector<ColorRgb> &ledValues)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
// debug the whole SPI packet
|
||||
char debug_line[2048];
|
||||
int ptr=0;
|
||||
@ -104,14 +105,14 @@ int LedDeviceSk6822SPI::write(const std::vector<ColorRgb> &ledValues)
|
||||
ptr += snprintf (ptr+debug_line, sizeof(debug_line)-ptr, "%03x: ", i);
|
||||
}
|
||||
|
||||
ptr += snprintf (ptr+debug_line, sizeof(debug_line)-ptr, "%02x ", _ledBuffer.data()[i]);
|
||||
ptr += snprintf (ptr+debug_line, sizeof(debug_line)-ptr, "%02x ", _ledBuffer.data()[i]);
|
||||
|
||||
if ( (i%16 == 15) || ( i == _ledBuffer.size()-1 ) )
|
||||
{
|
||||
Debug(_log, debug_line);
|
||||
ptr = 0;
|
||||
}
|
||||
if ( (i%16 == 15) || ( i == _ledBuffer.size()-1 ) )
|
||||
{
|
||||
Debug(_log, debug_line);
|
||||
ptr = 0;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion incluse
|
||||
// hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
@ -14,7 +14,7 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceSk6822SPI(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceSk6822SPI(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
@ -24,7 +24,7 @@ public:
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -33,12 +33,11 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
const int SPI_BYTES_PER_COLOUR;
|
||||
const int SPI_BYTES_WAIT_TIME;
|
||||
const int SPI_FRAME_END_LATCH_BYTES;
|
||||
|
||||
|
||||
uint8_t bitpair_to_byte[4];
|
||||
};
|
||||
|
@ -3,7 +3,8 @@
|
||||
LedDeviceWs2801::LedDeviceWs2801(const QJsonObject &deviceConfig)
|
||||
: ProviderSpi()
|
||||
{
|
||||
_deviceReady = ProviderSpi::init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceWs2801::construct(const QJsonObject &deviceConfig)
|
||||
@ -11,6 +12,12 @@ LedDevice* LedDeviceWs2801::construct(const QJsonObject &deviceConfig)
|
||||
return new LedDeviceWs2801(deviceConfig);
|
||||
}
|
||||
|
||||
bool LedDeviceWs2801::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceWs2801::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
const unsigned dataLen = _ledCount * sizeof(ColorRgb);
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
@ -13,11 +14,18 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceWs2801(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceWs2801(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
|
||||
///
|
||||
/// Sets configuration
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
protected:
|
||||
///
|
||||
/// Writes the led color values to the led-device
|
||||
@ -25,5 +33,5 @@ protected:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "LedDeviceWs2812SPI.h"
|
||||
|
||||
/*
|
||||
/*
|
||||
From the data sheet:
|
||||
|
||||
(TH+TL=1.25μs±600ns)
|
||||
@ -34,18 +34,19 @@ Reset time is 300uS = 923 bits = 116 bytes
|
||||
|
||||
*/
|
||||
|
||||
LedDeviceWs2812SPI::LedDeviceWs2812SPI(const QJsonObject &deviceConfig)
|
||||
LedDeviceWs2812SPI::LedDeviceWs2812SPI(const QJsonObject &deviceConfig)
|
||||
: ProviderSpi()
|
||||
, SPI_BYTES_PER_COLOUR(4)
|
||||
, SPI_FRAME_END_LATCH_BYTES(116)
|
||||
, bitpair_to_byte {
|
||||
0b10001000,
|
||||
0b10001100,
|
||||
0b11001000,
|
||||
0b11001100,
|
||||
}
|
||||
, SPI_BYTES_PER_COLOUR(4)
|
||||
, SPI_FRAME_END_LATCH_BYTES(116)
|
||||
, bitpair_to_byte {
|
||||
0b10001000,
|
||||
0b10001100,
|
||||
0b11001000,
|
||||
0b11001100,
|
||||
}
|
||||
{
|
||||
_deviceReady = init(deviceConfig);
|
||||
_devConfig = deviceConfig;
|
||||
_deviceReady = false;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceWs2812SPI::construct(const QJsonObject &deviceConfig)
|
||||
@ -56,15 +57,15 @@ LedDevice* LedDeviceWs2812SPI::construct(const QJsonObject &deviceConfig)
|
||||
bool LedDeviceWs2812SPI::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
_baudRate_Hz = 2600000;
|
||||
if ( !ProviderSpi::init(deviceConfig) )
|
||||
|
||||
bool isInitOK = ProviderSpi::init(deviceConfig);
|
||||
if ( isInitOK )
|
||||
{
|
||||
return false;
|
||||
WarningIf(( _baudRate_Hz < 2106000 || _baudRate_Hz > 3075000 ), _log, "SPI rate %d outside recommended range (2106000 -> 3075000)", _baudRate_Hz);
|
||||
|
||||
_ledBuffer.resize(_ledRGBCount * SPI_BYTES_PER_COLOUR + SPI_FRAME_END_LATCH_BYTES, 0x00);
|
||||
}
|
||||
WarningIf(( _baudRate_Hz < 2106000 || _baudRate_Hz > 3075000 ), _log, "SPI rate %d outside recommended range (2106000 -> 3075000)", _baudRate_Hz);
|
||||
|
||||
_ledBuffer.resize(_ledRGBCount * SPI_BYTES_PER_COLOUR + SPI_FRAME_END_LATCH_BYTES, 0x00);
|
||||
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int LedDeviceWs2812SPI::write(const std::vector<ColorRgb> &ledValues)
|
||||
@ -75,8 +76,8 @@ int LedDeviceWs2812SPI::write(const std::vector<ColorRgb> &ledValues)
|
||||
for (const ColorRgb& color : ledValues)
|
||||
{
|
||||
uint32_t colorBits = ((unsigned int)color.red << 16)
|
||||
| ((unsigned int)color.green << 8)
|
||||
| color.blue;
|
||||
| ((unsigned int)color.green << 8)
|
||||
| color.blue;
|
||||
|
||||
for (int j=SPI_BYTES_PER_LED - 1; j>=0; j--)
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion incluse
|
||||
// hyperion includes
|
||||
#include "ProviderSpi.h"
|
||||
|
||||
///
|
||||
@ -14,7 +14,7 @@ public:
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceWs2812SPI(const QJsonObject &deviceConfig);
|
||||
explicit LedDeviceWs2812SPI(const QJsonObject &deviceConfig);
|
||||
|
||||
/// constructs leddevice
|
||||
static LedDevice* construct(const QJsonObject &deviceConfig);
|
||||
@ -24,7 +24,7 @@ public:
|
||||
///
|
||||
/// @param deviceConfig the json device config
|
||||
/// @return true if success
|
||||
virtual bool init(const QJsonObject &deviceConfig);
|
||||
virtual bool init(const QJsonObject &deviceConfig) override;
|
||||
|
||||
private:
|
||||
///
|
||||
@ -33,10 +33,9 @@ private:
|
||||
/// @param ledValues The color-value per led
|
||||
/// @return Zero on succes else negative
|
||||
///
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues);
|
||||
|
||||
const int SPI_BYTES_PER_COLOUR;
|
||||
virtual int write(const std::vector<ColorRgb> &ledValues) override;
|
||||
|
||||
const int SPI_BYTES_PER_COLOUR;
|
||||
const int SPI_FRAME_END_LATCH_BYTES;
|
||||
|
||||
uint8_t bitpair_to_byte[4];
|
||||
|
@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
// STL includes
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
// Linux includes
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
// Local Hyperion includes
|
||||
@ -28,52 +29,95 @@ ProviderSpi::ProviderSpi()
|
||||
|
||||
ProviderSpi::~ProviderSpi()
|
||||
{
|
||||
// close(_fid);
|
||||
}
|
||||
|
||||
bool ProviderSpi::init(const QJsonObject &deviceConfig)
|
||||
{
|
||||
LedDevice::init(deviceConfig);
|
||||
bool isInitOK = LedDevice::init(deviceConfig);
|
||||
|
||||
_deviceName = deviceConfig["output"].toString(_deviceName);
|
||||
_baudRate_Hz = deviceConfig["rate"].toInt(_baudRate_Hz);
|
||||
_spiMode = deviceConfig["spimode"].toInt(_spiMode);
|
||||
_spiDataInvert = deviceConfig["invert"].toBool(_spiDataInvert);
|
||||
|
||||
return true;
|
||||
return isInitOK;
|
||||
}
|
||||
|
||||
int ProviderSpi::open()
|
||||
{
|
||||
Debug(_log, "_baudRate_Hz %d, _latchTime_ns %d", _baudRate_Hz, _latchTime_ms);
|
||||
Debug(_log, "_spiDataInvert %d, _spiMode %d", _spiDataInvert, _spiMode);
|
||||
int retval = -1;
|
||||
QString errortext;
|
||||
_deviceReady = false;
|
||||
|
||||
const int bitsPerWord = 8;
|
||||
|
||||
_fid = ::open(QSTRING_CSTR(_deviceName), O_RDWR);
|
||||
|
||||
if (_fid < 0)
|
||||
if ( init(_devConfig) )
|
||||
{
|
||||
Error( _log, "Failed to open device (%s). Error message: %s", QSTRING_CSTR(_deviceName), strerror(errno) );
|
||||
return -1;
|
||||
|
||||
Debug(_log, "_baudRate_Hz %d, _latchTime_ns %d", _baudRate_Hz, _latchTime_ms);
|
||||
Debug(_log, "_spiDataInvert %d, _spiMode %d", _spiDataInvert, _spiMode);
|
||||
|
||||
const int bitsPerWord = 8;
|
||||
|
||||
_fid = ::open(QSTRING_CSTR(_deviceName), O_RDWR);
|
||||
|
||||
if (_fid < 0)
|
||||
{
|
||||
errortext = QString ("Failed to open device (%1). Error message: %2").arg(_deviceName, strerror(errno));
|
||||
retval = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ioctl(_fid, SPI_IOC_WR_MODE, &_spiMode) == -1 || ioctl(_fid, SPI_IOC_RD_MODE, &_spiMode) == -1)
|
||||
{
|
||||
retval = -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ioctl(_fid, SPI_IOC_WR_BITS_PER_WORD, &bitsPerWord) == -1 || ioctl(_fid, SPI_IOC_RD_BITS_PER_WORD, &bitsPerWord) == -1)
|
||||
{
|
||||
retval = -4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ioctl(_fid, SPI_IOC_WR_MAX_SPEED_HZ, &_baudRate_Hz) == -1 || ioctl(_fid, SPI_IOC_RD_MAX_SPEED_HZ, &_baudRate_Hz) == -1)
|
||||
{
|
||||
retval = -6;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Everything OK -> enable device
|
||||
_deviceReady = true;
|
||||
setEnable(true);
|
||||
retval = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( retval < 0 )
|
||||
{
|
||||
errortext = QString ("Failed to open device (%1). Error Code: %2").arg(_deviceName, retval);
|
||||
}
|
||||
}
|
||||
|
||||
if ( retval < 0 )
|
||||
{
|
||||
this->setInError( errortext );
|
||||
}
|
||||
}
|
||||
|
||||
if (ioctl(_fid, SPI_IOC_WR_MODE, &_spiMode) == -1 || ioctl(_fid, SPI_IOC_RD_MODE, &_spiMode) == -1)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (ioctl(_fid, SPI_IOC_WR_BITS_PER_WORD, &bitsPerWord) == -1 || ioctl(_fid, SPI_IOC_RD_BITS_PER_WORD, &bitsPerWord) == -1)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
void ProviderSpi::close()
|
||||
{
|
||||
LedDevice::close();
|
||||
|
||||
if (ioctl(_fid, SPI_IOC_WR_MAX_SPEED_HZ, &_baudRate_Hz) == -1 || ioctl(_fid, SPI_IOC_RD_MAX_SPEED_HZ, &_baudRate_Hz) == -1)
|
||||
// Device specific closing activites
|
||||
if ( _fid > -1 )
|
||||
{
|
||||
return -6;
|
||||
if ( ::close(_fid) != 0 )
|
||||
{
|
||||
Error( _log, "Failed to close device (%s). Error message: %s", QSTRING_CSTR(_deviceName), strerror(errno) );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ProviderSpi::writeBytes(const unsigned size, const uint8_t * data)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user