From ed5455458b11d26f3f7de9082e533c173f3d7a4e Mon Sep 17 00:00:00 2001 From: LordGrey <48840279+Lord-Grey@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:21:58 +0100 Subject: [PATCH] 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 --- CrossCompileHowto.txt => CrossCompileHowto.md | 93 +++-- README.md | 2 +- assets/webconfig/i18n/de.json | 2 + assets/webconfig/i18n/en.json | 2 + effects/fade.py | 1 + effects/ledtest.json | 12 + effects/ledtest.py | 60 ++++ effects/random.py | 2 + effects/schema/ledtest.schema.json | 77 ++++ effects/swirl.py | 1 + effects/traces.py | 1 + include/hyperion/Hyperion.h | 2 + include/leddevice/LedDevice.h | 182 +++++++--- include/leddevice/LedDeviceWrapper.h | 14 +- include/utils/Logger.h | 25 +- include/utils/hyperion.h | 6 +- libsrc/effectengine/EffectEngine.cpp | 11 +- libsrc/grabber/v4l2/V4L2Grabber.cpp | 2 +- libsrc/hyperion/Hyperion.cpp | 50 ++- libsrc/hyperion/LinearColorSmoothing.cpp | 161 ++++++--- libsrc/hyperion/LinearColorSmoothing.h | 36 +- libsrc/hyperion/MultiColorAdjustment.cpp | 13 +- libsrc/hyperion/SettingsManager.cpp | 2 +- libsrc/leddevice/LedDevice.cpp | 179 +++++++-- libsrc/leddevice/LedDeviceFactory.cpp | 2 +- libsrc/leddevice/LedDeviceTemplate.cpp | 87 +++++ libsrc/leddevice/LedDeviceTemplate.h | 60 ++++ libsrc/leddevice/LedDeviceWrapper.cpp | 34 +- .../dev_hid/LedDeviceHyperionUsbasp.cpp | 163 +++++---- .../dev_hid/LedDeviceHyperionUsbasp.h | 19 +- .../leddevice/dev_hid/LedDeviceLightpack.cpp | 184 ++++++---- libsrc/leddevice/dev_hid/LedDeviceLightpack.h | 20 +- .../dev_hid/LedDeviceMultiLightpack.cpp | 73 ++-- .../dev_hid/LedDeviceMultiLightpack.h | 15 +- .../leddevice/dev_hid/LedDevicePaintpack.cpp | 19 +- libsrc/leddevice/dev_hid/LedDevicePaintpack.h | 11 +- libsrc/leddevice/dev_hid/LedDeviceRawHID.cpp | 19 +- libsrc/leddevice/dev_hid/LedDeviceRawHID.h | 13 +- libsrc/leddevice/dev_hid/ProviderHID.cpp | 144 +++++--- libsrc/leddevice/dev_hid/ProviderHID.h | 16 +- .../deactivated/LedDeviceLightpack-hidapi.cpp | 5 - .../deactivated/LedDeviceLightpack-hidapi.h | 3 - libsrc/leddevice/dev_net/LedDeviceAtmoOrb.cpp | 133 ++++--- libsrc/leddevice/dev_net/LedDeviceAtmoOrb.h | 106 +++--- .../leddevice/dev_net/LedDeviceFadeCandy.cpp | 119 ++++-- libsrc/leddevice/dev_net/LedDeviceFadeCandy.h | 64 ++-- .../leddevice/dev_net/LedDeviceNanoleaf.cpp | 340 +++++++++++------- libsrc/leddevice/dev_net/LedDeviceNanoleaf.h | 225 ++++++------ .../leddevice/dev_net/LedDevicePhilipsHue.h | 8 +- libsrc/leddevice/dev_net/LedDeviceTpm2net.cpp | 25 +- libsrc/leddevice/dev_net/LedDeviceTpm2net.h | 14 +- .../leddevice/dev_net/LedDeviceUdpArtNet.cpp | 26 +- libsrc/leddevice/dev_net/LedDeviceUdpArtNet.h | 19 +- libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp | 36 +- libsrc/leddevice/dev_net/LedDeviceUdpE131.h | 15 +- libsrc/leddevice/dev_net/LedDeviceUdpH801.cpp | 59 +-- libsrc/leddevice/dev_net/LedDeviceUdpH801.h | 16 +- libsrc/leddevice/dev_net/LedDeviceUdpRaw.cpp | 11 +- libsrc/leddevice/dev_net/LedDeviceUdpRaw.h | 16 +- libsrc/leddevice/dev_net/ProviderUdp.cpp | 89 ++++- libsrc/leddevice/dev_net/ProviderUdp.h | 24 +- libsrc/leddevice/dev_other/LedDeviceFile.cpp | 64 +++- libsrc/leddevice/dev_other/LedDeviceFile.h | 27 +- .../dev_other/LedDevicePiBlaster.cpp | 142 +++++--- .../leddevice/dev_other/LedDevicePiBlaster.h | 20 +- .../leddevice/dev_rpi_pwm/LedDeviceWS281x.cpp | 99 +++-- .../leddevice/dev_rpi_pwm/LedDeviceWS281x.h | 20 +- .../dev_serial/LedDeviceAdalight.cpp | 13 +- .../leddevice/dev_serial/LedDeviceAdalight.h | 7 +- libsrc/leddevice/dev_serial/LedDeviceAtmo.cpp | 33 +- libsrc/leddevice/dev_serial/LedDeviceAtmo.h | 8 +- libsrc/leddevice/dev_serial/LedDeviceDMX.cpp | 82 +++-- libsrc/leddevice/dev_serial/LedDeviceDMX.h | 8 +- .../leddevice/dev_serial/LedDeviceKarate.cpp | 40 ++- libsrc/leddevice/dev_serial/LedDeviceKarate.h | 8 +- libsrc/leddevice/dev_serial/LedDeviceSedu.cpp | 13 +- libsrc/leddevice/dev_serial/LedDeviceSedu.h | 8 +- libsrc/leddevice/dev_serial/LedDeviceTpm2.cpp | 7 +- libsrc/leddevice/dev_serial/LedDeviceTpm2.h | 8 +- libsrc/leddevice/dev_serial/ProviderRs232.cpp | 50 ++- libsrc/leddevice/dev_serial/ProviderRs232.h | 19 +- libsrc/leddevice/dev_spi/LedDeviceAPA102.cpp | 29 +- libsrc/leddevice/dev_spi/LedDeviceAPA102.h | 14 +- libsrc/leddevice/dev_spi/LedDeviceAPA104.cpp | 17 +- libsrc/leddevice/dev_spi/LedDeviceAPA104.h | 11 +- libsrc/leddevice/dev_spi/LedDeviceLpd6803.cpp | 18 +- libsrc/leddevice/dev_spi/LedDeviceLpd6803.h | 13 +- libsrc/leddevice/dev_spi/LedDeviceLpd8806.cpp | 40 ++- libsrc/leddevice/dev_spi/LedDeviceLpd8806.h | 21 +- libsrc/leddevice/dev_spi/LedDeviceP9813.cpp | 14 +- libsrc/leddevice/dev_spi/LedDeviceP9813.h | 13 +- .../leddevice/dev_spi/LedDeviceSk6812SPI.cpp | 63 ++-- libsrc/leddevice/dev_spi/LedDeviceSk6812SPI.h | 13 +- .../leddevice/dev_spi/LedDeviceSk6822SPI.cpp | 55 +-- libsrc/leddevice/dev_spi/LedDeviceSk6822SPI.h | 9 +- libsrc/leddevice/dev_spi/LedDeviceWs2801.cpp | 9 +- libsrc/leddevice/dev_spi/LedDeviceWs2801.h | 12 +- .../leddevice/dev_spi/LedDeviceWs2812SPI.cpp | 41 +-- libsrc/leddevice/dev_spi/LedDeviceWs2812SPI.h | 11 +- libsrc/leddevice/dev_spi/ProviderSpi.cpp | 94 +++-- libsrc/leddevice/dev_spi/ProviderSpi.h | 13 +- .../dev_tinker/LedDeviceTinkerforge.cpp | 146 ++++---- .../dev_tinker/LedDeviceTinkerforge.h | 18 +- libsrc/leddevice/schemas/schema-file.json | 4 +- libsrc/leddevice/schemas/schema-nanoleaf.json | 2 +- .../FramebufferWrapper.cpp | 1 + test/TestSpi.cpp | 6 +- 107 files changed, 2980 insertions(+), 1551 deletions(-) rename CrossCompileHowto.txt => CrossCompileHowto.md (52%) create mode 100644 effects/ledtest.json create mode 100644 effects/ledtest.py create mode 100644 effects/schema/ledtest.schema.json create mode 100644 libsrc/leddevice/LedDeviceTemplate.cpp create mode 100644 libsrc/leddevice/LedDeviceTemplate.h diff --git a/CrossCompileHowto.txt b/CrossCompileHowto.md similarity index 52% rename from CrossCompileHowto.txt rename to CrossCompileHowto.md index 2dc5280f..365af84c 100644 --- a/CrossCompileHowto.txt +++ b/CrossCompileHowto.md @@ -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 diff --git a/README.md b/README.md index 5b236a2a..9637846d 100644 --- a/README.md +++ b/README.md @@ -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.** diff --git a/assets/webconfig/i18n/de.json b/assets/webconfig/i18n/de.json index cd941856..6cb10e38 100644 --- a/assets/webconfig/i18n/de.json +++ b/assets/webconfig/i18n/de.json @@ -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", diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json index 16090412..56630bba 100644 --- a/assets/webconfig/i18n/en.json +++ b/assets/webconfig/i18n/en.json @@ -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", diff --git a/effects/fade.py b/effects/fade.py index 20dd7591..8b2d2918 100644 --- a/effects/fade.py +++ b/effects/fade.py @@ -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 diff --git a/effects/ledtest.json b/effects/ledtest.json new file mode 100644 index 00000000..3c4c4c27 --- /dev/null +++ b/effects/ledtest.json @@ -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 + } +} diff --git a/effects/ledtest.py b/effects/ledtest.py new file mode 100644 index 00000000..0174c3ab --- /dev/null +++ b/effects/ledtest.py @@ -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 sleepTime: sleepTime = minStepTime return sleepTime diff --git a/effects/traces.py b/effects/traces.py index 473c55d9..1183a47f 100644 --- a/effects/traces.py +++ b/effects/traces.py @@ -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 = [ diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index 1b606aaf..d83bcd54 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -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(); diff --git a/include/leddevice/LedDevice.h b/include/leddevice/LedDevice.h index 6c7502c6..a587d5b0 100644 --- a/include/leddevice/LedDevice.h +++ b/include/leddevice/LedDevice.h @@ -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& 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& 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& 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& 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 _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 _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 _last_ledValues; }; diff --git a/include/leddevice/LedDeviceWrapper.h b/include/leddevice/LedDeviceWrapper.h index bfee35e6..347146cb 100644 --- a/include/leddevice/LedDeviceWrapper.h +++ b/include/leddevice/LedDeviceWrapper.h @@ -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& ledValues); + int updateLeds(const std::vector& ledValues); + + void setEnable(bool enable); + void closeLedDevice(); private slots: /// diff --git a/include/utils/Logger.h b/include/utils/Logger.h index 40ef199c..237ff6f8 100644 --- a/include/utils/Logger.h +++ b/include/utils/Logger.h @@ -13,19 +13,16 @@ #include // 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* getLogMessageBuffer() { return &_logMessageBuffer; }; + QVector* getLogMessageBuffer() { return &_logMessageBuffer; } public slots: void handleNewLogMessage(const Logger::T_LOG_MESSAGE&); diff --git a/include/utils/hyperion.h b/include/utils/hyperion.h index 7e3e03a3..7c19e295 100644 --- a/include/utils/hyperion.h +++ b/include/utils/hyperion.h @@ -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; diff --git a/libsrc/effectengine/EffectEngine.cpp b/libsrc/effectengine/EffectEngine.cpp index 4e7d1c67..1b693ac7 100644 --- a/libsrc/effectengine/EffectEngine.cpp +++ b/libsrc/effectengine/EffectEngine.cpp @@ -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(); diff --git a/libsrc/grabber/v4l2/V4L2Grabber.cpp b/libsrc/grabber/v4l2/V4L2Grabber.cpp index 43db07c3..82f3749d 100644 --- a/libsrc/grabber/v4l2/V4L2Grabber.cpp +++ b/libsrc/grabber/v4l2/V4L2Grabber.cpp @@ -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; } diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index df2089ad..adb48414 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -1,4 +1,4 @@ - + // STL includes #include #include @@ -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& 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& 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"); + //} } diff --git a/libsrc/hyperion/LinearColorSmoothing.cpp b/libsrc/hyperion/LinearColorSmoothing.cpp index 4fbfcaa3..7db7c4cd 100644 --- a/libsrc/hyperion/LinearColorSmoothing.cpp +++ b/libsrc/hyperion/LinearColorSmoothing.cpp @@ -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(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(obj["time_ms"].toInt(DEFAUL_SETTLINGTIME)), + static_cast(1000.0/obj["updateFrequency"].toDouble(DEFAUL_UPDATEFREQUENCY)), + static_cast(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 &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& 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(_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 & 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 & 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(_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; } diff --git a/libsrc/hyperion/LinearColorSmoothing.h b/libsrc/hyperion/LinearColorSmoothing.h index 87bbc170..e7d40d62 100644 --- a/libsrc/hyperion/LinearColorSmoothing.h +++ b/libsrc/hyperion/LinearColorSmoothing.h @@ -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 &ledValues); - - /// Switch the leds off - virtual int switchOff(); + virtual int updateLedValues(const std::vector& 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 & 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 &ledValues); /// Logger instance Logger* _log; @@ -149,4 +168,5 @@ private: QVector _cfgList; unsigned _currentConfigId; + bool _enabled; }; diff --git a/libsrc/hyperion/MultiColorAdjustment.cpp b/libsrc/hyperion/MultiColorAdjustment.cpp index f7afad46..0c88667e 100644 --- a/libsrc/hyperion/MultiColorAdjustment.cpp +++ b/libsrc/hyperion/MultiColorAdjustment.cpp @@ -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& 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; } diff --git a/libsrc/hyperion/SettingsManager.cpp b/libsrc/hyperion/SettingsManager.cpp index 5d4cc81b..f8bdb319 100644 --- a/libsrc/hyperion/SettingsManager.cpp +++ b/libsrc/hyperion/SettingsManager.cpp @@ -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) diff --git a/libsrc/leddevice/LedDevice.cpp b/libsrc/leddevice/LedDevice.cpp index 7fce3e27..8da0ba5a 100644 --- a/libsrc/leddevice/LedDevice.cpp +++ b/libsrc/leddevice/LedDevice.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "hyperion/Hyperion.h" #include @@ -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( 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& ledValues) +void LedDevice::startRefreshTimer() +{ + if ( _deviceReady) + { + _refresh_timer->start(); + } +} + +void LedDevice::stopRefreshTimer() +{ + _refresh_timer->stop(); +} + +int LedDevice::updateLeds(const std::vector& 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(_ledCount, ColorRgb::BLACK )) : -1; + return _deviceReady ? updateLeds(std::vector(static_cast(_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(_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& ledValues ) +{ + std::cout << "LedValues [" << ledValues.size() <<"] ["; + for (const ColorRgb& color : ledValues) + { + std::cout << color; + } + std::cout << "]" << std::endl; +} diff --git a/libsrc/leddevice/LedDeviceFactory.cpp b/libsrc/leddevice/LedDeviceFactory.cpp index 0d38c6ce..017771ef 100644 --- a/libsrc/leddevice/LedDeviceFactory.cpp +++ b/libsrc/leddevice/LedDeviceFactory.cpp @@ -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; } } diff --git a/libsrc/leddevice/LedDeviceTemplate.cpp b/libsrc/leddevice/LedDeviceTemplate.cpp new file mode 100644 index 00000000..b9128ae5 --- /dev/null +++ b/libsrc/leddevice/LedDeviceTemplate.cpp @@ -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 & ledValues) +{ + int retval = -1; + + //... + + return retval; +} + + diff --git a/libsrc/leddevice/LedDeviceTemplate.h b/libsrc/leddevice/LedDeviceTemplate.h new file mode 100644 index 00000000..d548f8be --- /dev/null +++ b/libsrc/leddevice/LedDeviceTemplate.h @@ -0,0 +1,60 @@ +#pragma once + +// LedDevice includes +#include + +/// +/// 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 & ledValues) override; + +private: + + +}; diff --git a/libsrc/leddevice/LedDeviceWrapper.cpp b/libsrc/leddevice/LedDeviceWrapper.cpp index 2027a3c5..a52d6a22 100644 --- a/libsrc/leddevice/LedDeviceWrapper.cpp +++ b/libsrc/leddevice/LedDeviceWrapper.cpp @@ -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] 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; } diff --git a/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.cpp b/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.cpp index 85553c19..833d4d2f 100644 --- a/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.cpp +++ b/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.cpp @@ -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); diff --git a/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.h b/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.h index f1a8c307..47a8ca1d 100644 --- a/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.h +++ b/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.h @@ -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& ledValues); + virtual int write(const std::vector& ledValues) override; /// /// Test if the device is a Hyperion Usbasp device diff --git a/libsrc/leddevice/dev_hid/LedDeviceLightpack.cpp b/libsrc/leddevice/dev_hid/LedDeviceLightpack.cpp index eb3db0b2..df9cfe64 100644 --- a/libsrc/leddevice/dev_hid/LedDeviceLightpack.cpp +++ b/libsrc/leddevice/dev_hid/LedDeviceLightpack.cpp @@ -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 &ledValues) int LedDeviceLightpack::write(const ColorRgb * ledValues, int size) { - int count = qMin(_hwLedCount, _ledCount); + int count = qMin(_hwLedCount, static_cast( _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: "; diff --git a/libsrc/leddevice/dev_hid/LedDeviceLightpack.h b/libsrc/leddevice/dev_hid/LedDeviceLightpack.h index c9b34ce2..85a12258 100644 --- a/libsrc/leddevice/dev_hid/LedDeviceLightpack.h +++ b/libsrc/leddevice/dev_hid/LedDeviceLightpack.h @@ -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: /// diff --git a/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.cpp b/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.cpp index 3c951a9c..d2a5b1dd 100644 --- a/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.cpp +++ b/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.cpp @@ -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 &ledValues) @@ -81,7 +101,7 @@ int LedDeviceMultiLightpack::write(const std::vector &ledValues) for (LedDeviceLightpack * device : _lightpacks) { - int count = qMin(device->getLedCount(), size); + int count = qMin(static_cast( 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); diff --git a/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.h b/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.h index 419e5bed..c1bec619 100644 --- a/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.h +++ b/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.h @@ -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& ledValues); + virtual int write(const std::vector& ledValues) override; static QStringList getLightpackSerials(); static QString getString(libusb_device * device, int stringDescriptorIndex); diff --git a/libsrc/leddevice/dev_hid/LedDevicePaintpack.cpp b/libsrc/leddevice/dev_hid/LedDevicePaintpack.cpp index 8a984dcb..14939760 100644 --- a/libsrc/leddevice/dev_hid/LedDevicePaintpack.cpp +++ b/libsrc/leddevice/dev_hid/LedDevicePaintpack.cpp @@ -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 & ledValues) { auto bufIt = _ledBuffer.begin()+2; diff --git a/libsrc/leddevice/dev_hid/LedDevicePaintpack.h b/libsrc/leddevice/dev_hid/LedDevicePaintpack.h index 1c2eb9d7..86f1967d 100644 --- a/libsrc/leddevice/dev_hid/LedDevicePaintpack.h +++ b/libsrc/leddevice/dev_hid/LedDevicePaintpack.h @@ -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& ledValues); + virtual int write(const std::vector& ledValues) override; }; diff --git a/libsrc/leddevice/dev_hid/LedDeviceRawHID.cpp b/libsrc/leddevice/dev_hid/LedDeviceRawHID.cpp index a8cf153a..0e940b32 100644 --- a/libsrc/leddevice/dev_hid/LedDeviceRawHID.cpp +++ b/libsrc/leddevice/dev_hid/LedDeviceRawHID.cpp @@ -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 & ledValues) { // write data memcpy(_ledBuffer.data(), ledValues.data(), _ledRGBCount); return writeBytes(_ledBuffer.size(), _ledBuffer.data()); } - -void LedDeviceRawHID::rewriteLeds() -{ - writeBytes(_ledBuffer.size(), _ledBuffer.data()); -} diff --git a/libsrc/leddevice/dev_hid/LedDeviceRawHID.h b/libsrc/leddevice/dev_hid/LedDeviceRawHID.h index 701def80..45310712 100644 --- a/libsrc/leddevice/dev_hid/LedDeviceRawHID.h +++ b/libsrc/leddevice/dev_hid/LedDeviceRawHID.h @@ -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 & ledValues); + virtual int write(const std::vector & ledValues) override; }; diff --git a/libsrc/leddevice/dev_hid/ProviderHID.cpp b/libsrc/leddevice/dev_hid/ProviderHID.cpp index 76be0e70..224b0260 100644 --- a/libsrc/leddevice/dev_hid/ProviderHID.cpp +++ b/libsrc/leddevice/dev_hid/ProviderHID.cpp @@ -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) { diff --git a/libsrc/leddevice/dev_hid/ProviderHID.h b/libsrc/leddevice/dev_hid/ProviderHID.h index d718462b..9d8cff2c 100644 --- a/libsrc/leddevice/dev_hid/ProviderHID.h +++ b/libsrc/leddevice/dev_hid/ProviderHID.h @@ -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 * diff --git a/libsrc/leddevice/dev_hid/deactivated/LedDeviceLightpack-hidapi.cpp b/libsrc/leddevice/dev_hid/deactivated/LedDeviceLightpack-hidapi.cpp index a518cfe0..2bacc1c1 100644 --- a/libsrc/leddevice/dev_hid/deactivated/LedDeviceLightpack-hidapi.cpp +++ b/libsrc/leddevice/dev_hid/deactivated/LedDeviceLightpack-hidapi.cpp @@ -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: "; diff --git a/libsrc/leddevice/dev_hid/deactivated/LedDeviceLightpack-hidapi.h b/libsrc/leddevice/dev_hid/deactivated/LedDeviceLightpack-hidapi.h index 6ab5de06..57f1287e 100644 --- a/libsrc/leddevice/dev_hid/deactivated/LedDeviceLightpack-hidapi.h +++ b/libsrc/leddevice/dev_hid/deactivated/LedDeviceLightpack-hidapi.h @@ -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. diff --git a/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.cpp b/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.cpp index a731b9d8..b3f3e991 100644 --- a/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.cpp +++ b/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.cpp @@ -2,58 +2,105 @@ #include "LedDeviceAtmoOrb.h" // qt includes -#include -#include #include -#include -#include - -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(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 &ledValues) @@ -79,7 +126,7 @@ int LedDeviceAtmoOrb::write(const std::vector &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 &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; -} diff --git a/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.h b/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.h index bbc36a87..d6b74210 100644 --- a/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.h +++ b/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.h @@ -5,25 +5,13 @@ #include #include #include -#include #include -// Leddevice includes +// LedDevice includes #include 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 lastColorRedMap; - QMap lastColorGreenMap; - QMap 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 &ledValues); + virtual int write(const std::vector &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 _orbIds; + QVector _orbIds; + + // Last send color map + QMap lastColorRedMap; + QMap lastColorGreenMap; + QMap 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); }; diff --git a/libsrc/leddevice/dev_net/LedDeviceFadeCandy.cpp b/libsrc/leddevice/dev_net/LedDeviceFadeCandy.cpp index cb01fcab..23355369 100644 --- a/libsrc/leddevice/dev_net/LedDeviceFadeCandy.cpp +++ b/libsrc/leddevice/dev_net/LedDeviceFadeCandy.cpp @@ -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; diff --git a/libsrc/leddevice/dev_net/LedDeviceFadeCandy.h b/libsrc/leddevice/dev_net/LedDeviceFadeCandy.h index 7d8318ad..e3cf0bdb 100644 --- a/libsrc/leddevice/dev_net/LedDeviceFadeCandy.h +++ b/libsrc/leddevice/dev_net/LedDeviceFadeCandy.h @@ -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& 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& 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; + }; diff --git a/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp b/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp index ce0d54c5..aabd5ded 100644 --- a/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp +++ b/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp @@ -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(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(jsonLayout[PANEL_NUM].toInt()); + QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray(); - uint panelNum = static_cast(jsonLayout[PANEL_NUM].toInt()); - QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray(); + std::map> panelMap; - std::map> 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(panelObj[PANEL_ID].toInt()); + uint panelX = static_cast(panelObj[PANEL_POS_X].toInt()); + uint panelY = static_cast(panelObj[PANEL_POS_Y].toInt()); + uint panelshapeType = static_cast(panelObj[PANEL_SHAPE_TYPE].toInt()); + //uint panelOrientation = static_cast(panelObj[PANEL_ORIENTATION].toInt()); - uint panelId = static_cast(panelObj[PANEL_ID].toInt()); - uint panelX = static_cast(panelObj[PANEL_POS_X].toInt()); - uint panelY = static_cast(panelObj[PANEL_POS_Y].toInt()); - uint panelshapeType = static_cast(panelObj[PANEL_SHAPE_TYPE].toInt()); - //uint panelOrientation = static_cast(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(_panelIds.size()); + _devConfig["hardwareLedCount"] = static_cast(_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(_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(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 & ledValues) { @@ -396,7 +463,7 @@ int LedDeviceNanoleaf::write(const std::vector & ledValues) lowByte = static_cast(panelID & 0xFF); // Set panels configured - if( panelCounter < static_cast(this->getLedCount()) ) { + if( panelCounter < this->getLedCount() ) { color = static_cast(ledValues.at(panelCounter)); } else @@ -437,40 +504,43 @@ int LedDeviceNanoleaf::write(const std::vector & 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(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(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::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(*it); } diff --git a/libsrc/leddevice/dev_net/LedDeviceNanoleaf.h b/libsrc/leddevice/dev_net/LedDeviceNanoleaf.h index 11cac7eb..4fc28734 100644 --- a/libsrc/leddevice/dev_net/LedDeviceNanoleaf.h +++ b/libsrc/leddevice/dev_net/LedDeviceNanoleaf.h @@ -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 & 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 & 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 _panelIds; + /// Array of the pannel ids. + std::vector _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 diff --git a/libsrc/leddevice/dev_net/LedDevicePhilipsHue.h b/libsrc/leddevice/dev_net/LedDevicePhilipsHue.h index d42407bc..655fe1cc 100644 --- a/libsrc/leddevice/dev_net/LedDevicePhilipsHue.h +++ b/libsrc/leddevice/dev_net/LedDevicePhilipsHue.h @@ -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 & ledValues); - bool init(const QJsonObject &deviceConfig); + virtual int write(const std::vector & ledValues) override; + bool init(const QJsonObject &deviceConfig) override; private: /// bridge class diff --git a/libsrc/leddevice/dev_net/LedDeviceTpm2net.cpp b/libsrc/leddevice/dev_net/LedDeviceTpm2net.cpp index 58d2f9d9..3a6ac537 100644 --- a/libsrc/leddevice/dev_net/LedDeviceTpm2net.cpp +++ b/libsrc/leddevice/dev_net/LedDeviceTpm2net.cpp @@ -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 &ledValues) { diff --git a/libsrc/leddevice/dev_net/LedDeviceTpm2net.h b/libsrc/leddevice/dev_net/LedDeviceTpm2net.h index 308e3d7e..2abdae83 100644 --- a/libsrc/leddevice/dev_net/LedDeviceTpm2net.h +++ b/libsrc/leddevice/dev_net/LedDeviceTpm2net.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; int _tpm2_max; int _tpm2ByteCount; diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.cpp b/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.cpp index 50f2b168..fe23311d 100644 --- a/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.cpp +++ b/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.cpp @@ -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; } - diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.h b/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.h index 08abede2..813633bb 100644 --- a/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.h +++ b/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.h @@ -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 &ledValues); + virtual int write(const std::vector &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; }; diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp b/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp index da52e88f..14a80c64 100644 --- a/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp +++ b/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp @@ -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) { diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpE131.h b/libsrc/leddevice/dev_net/LedDeviceUdpE131.h index 5591b123..26457fba 100644 --- a/libsrc/leddevice/dev_net/LedDeviceUdpE131.h +++ b/libsrc/leddevice/dev_net/LedDeviceUdpE131.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; void prepare(const unsigned this_universe, const unsigned this_dmxChannelCount); diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpH801.cpp b/libsrc/leddevice/dev_net/LedDeviceUdpH801.cpp index 0c48f55c..18d08a44 100644 --- a/libsrc/leddevice/dev_net/LedDeviceUdpH801.cpp +++ b/libsrc/leddevice/dev_net/LedDeviceUdpH801.cpp @@ -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 &ledValues) diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpH801.h b/libsrc/leddevice/dev_net/LedDeviceUdpH801.h index c698a6ca..223d281d 100644 --- a/libsrc/leddevice/dev_net/LedDeviceUdpH801.h +++ b/libsrc/leddevice/dev_net/LedDeviceUdpH801.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; }; diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpRaw.cpp b/libsrc/leddevice/dev_net/LedDeviceUdpRaw.cpp index e1fed640..0b49cbb1 100644 --- a/libsrc/leddevice/dev_net/LedDeviceUdpRaw.cpp +++ b/libsrc/leddevice/dev_net/LedDeviceUdpRaw.cpp @@ -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 &ledValues) { const uint8_t * dataPtr = reinterpret_cast(ledValues.data()); diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpRaw.h b/libsrc/leddevice/dev_net/LedDeviceUdpRaw.h index 38071716..a3beb82a 100644 --- a/libsrc/leddevice/dev_net/LedDeviceUdpRaw.h +++ b/libsrc/leddevice/dev_net/LedDeviceUdpRaw.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; }; diff --git a/libsrc/leddevice/dev_net/ProviderUdp.cpp b/libsrc/leddevice/dev_net/ProviderUdp.cpp index 0caf9367..a4d145ad 100644 --- a/libsrc/leddevice/dev_net/ProviderUdp.cpp +++ b/libsrc/leddevice/dev_net/ProviderUdp.cpp @@ -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(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) diff --git a/libsrc/leddevice/dev_net/ProviderUdp.h b/libsrc/leddevice/dev_net/ProviderUdp.h index bc204c6d..697ed3bf 100644 --- a/libsrc/leddevice/dev_net/ProviderUdp.h +++ b/libsrc/leddevice/dev_net/ProviderUdp.h @@ -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. diff --git a/libsrc/leddevice/dev_other/LedDeviceFile.cpp b/libsrc/leddevice/dev_other/LedDeviceFile.cpp index 380862d6..8adcbb11 100644 --- a/libsrc/leddevice/dev_other/LedDeviceFile.cpp +++ b/libsrc/leddevice/dev_other/LedDeviceFile.cpp @@ -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 & 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( - now.time_since_epoch()) % 1000; + now.time_since_epoch()) % 1000; + + const auto elapsedTimeMs = std::chrono::duration_cast(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) { diff --git a/libsrc/leddevice/dev_other/LedDeviceFile.h b/libsrc/leddevice/dev_other/LedDeviceFile.h index 338487d7..c27dee42 100644 --- a/libsrc/leddevice/dev_other/LedDeviceFile.h +++ b/libsrc/leddevice/dev_other/LedDeviceFile.h @@ -2,6 +2,7 @@ // STL includes #include +#include // Leddevice includes #include @@ -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 & ledValues); + virtual int write(const std::vector & 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(); + }; diff --git a/libsrc/leddevice/dev_other/LedDevicePiBlaster.cpp b/libsrc/leddevice/dev_other/LedDevicePiBlaster.cpp index f929ee20..72b5a823 100644 --- a/libsrc/leddevice/dev_other/LedDevicePiBlaster.cpp +++ b/libsrc/leddevice/dev_other/LedDevicePiBlaster.cpp @@ -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 & ledValues) { @@ -112,11 +143,10 @@ int LedDevicePiBlaster::write(const std::vector & 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( _ledCount)) ) { double pwmDutyCycle = 0.0; switch (_gpio_to_color[ i ]) diff --git a/libsrc/leddevice/dev_other/LedDevicePiBlaster.h b/libsrc/leddevice/dev_other/LedDevicePiBlaster.h index 35115e29..fb6ff795 100644 --- a/libsrc/leddevice/dev_other/LedDevicePiBlaster.h +++ b/libsrc/leddevice/dev_other/LedDevicePiBlaster.h @@ -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 &ledValues); + int write(const std::vector &ledValues) override; /// The name of the output device (very likely '/dev/pi-blaster') QString _deviceName; diff --git a/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.cpp b/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.cpp index 553b6082..ca93aa76 100644 --- a/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.cpp +++ b/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.cpp @@ -1,64 +1,87 @@ -#include - #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) diff --git a/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.h b/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.h index 27d3c27c..2af413f4 100644 --- a/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.h +++ b/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.h @@ -1,5 +1,6 @@ #pragma once +// LedDevice includes #include #include @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; ws2811_t _led_string; int _channel; diff --git a/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp b/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp index ecc5d8c3..462c3452 100644 --- a/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp +++ b/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp @@ -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( _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 & ledValues) { if(_ligthBerryAPA102Mode) { - for (signed iLed=1; iLed<=_ledCount; iLed++) + for (signed iLed=1; iLed<=static_cast( _ledCount); iLed++) { const ColorRgb& rgb = ledValues[iLed-1]; _ledBuffer[iLed*4+7] = rgb.red; diff --git a/libsrc/leddevice/dev_serial/LedDeviceAdalight.h b/libsrc/leddevice/dev_serial/LedDeviceAdalight.h index 23d1d163..5caed855 100644 --- a/libsrc/leddevice/dev_serial/LedDeviceAdalight.h +++ b/libsrc/leddevice/dev_serial/LedDeviceAdalight.h @@ -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 & ledValues); + virtual int write(const std::vector & ledValues) override; const short _headerSize; bool _ligthBerryAPA102Mode; diff --git a/libsrc/leddevice/dev_serial/LedDeviceAtmo.cpp b/libsrc/leddevice/dev_serial/LedDeviceAtmo.cpp index 78418fb9..7e4b9189 100644 --- a/libsrc/leddevice/dev_serial/LedDeviceAtmo.cpp +++ b/libsrc/leddevice/dev_serial/LedDeviceAtmo.cpp @@ -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 &ledValues) diff --git a/libsrc/leddevice/dev_serial/LedDeviceAtmo.h b/libsrc/leddevice/dev_serial/LedDeviceAtmo.h index 475c024a..7c662ed3 100644 --- a/libsrc/leddevice/dev_serial/LedDeviceAtmo.h +++ b/libsrc/leddevice/dev_serial/LedDeviceAtmo.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; }; diff --git a/libsrc/leddevice/dev_serial/LedDeviceDMX.cpp b/libsrc/leddevice/dev_serial/LedDeviceDMX.cpp index 7b8ba3d4..ecc0d6aa 100644 --- a/libsrc/leddevice/dev_serial/LedDeviceDMX.cpp +++ b/libsrc/leddevice/dev_serial/LedDeviceDMX.cpp @@ -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(_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 &ledValues) { switch (_dmxDeviceType) { diff --git a/libsrc/leddevice/dev_serial/LedDeviceDMX.h b/libsrc/leddevice/dev_serial/LedDeviceDMX.h index c4f20d69..6bf15790 100644 --- a/libsrc/leddevice/dev_serial/LedDeviceDMX.h +++ b/libsrc/leddevice/dev_serial/LedDeviceDMX.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; int _dmxDeviceType = 0; int _dmxStart = 1; int _dmxSlotsPerLed = 3; diff --git a/libsrc/leddevice/dev_serial/LedDeviceKarate.cpp b/libsrc/leddevice/dev_serial/LedDeviceKarate.cpp index da5ec096..44b20af5 100644 --- a/libsrc/leddevice/dev_serial/LedDeviceKarate.cpp +++ b/libsrc/leddevice/dev_serial/LedDeviceKarate.cpp @@ -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 &ledValues) diff --git a/libsrc/leddevice/dev_serial/LedDeviceKarate.h b/libsrc/leddevice/dev_serial/LedDeviceKarate.h index 7be619e3..b531f29c 100644 --- a/libsrc/leddevice/dev_serial/LedDeviceKarate.h +++ b/libsrc/leddevice/dev_serial/LedDeviceKarate.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; }; diff --git a/libsrc/leddevice/dev_serial/LedDeviceSedu.cpp b/libsrc/leddevice/dev_serial/LedDeviceSedu.cpp index 36d86e7d..b2bcdeb3 100644 --- a/libsrc/leddevice/dev_serial/LedDeviceSedu.cpp +++ b/libsrc/leddevice/dev_serial/LedDeviceSedu.cpp @@ -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 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 &ledValues) diff --git a/libsrc/leddevice/dev_serial/LedDeviceSedu.h b/libsrc/leddevice/dev_serial/LedDeviceSedu.h index 02d2fac2..2ceced2b 100644 --- a/libsrc/leddevice/dev_serial/LedDeviceSedu.h +++ b/libsrc/leddevice/dev_serial/LedDeviceSedu.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; }; diff --git a/libsrc/leddevice/dev_serial/LedDeviceTpm2.cpp b/libsrc/leddevice/dev_serial/LedDeviceTpm2.cpp index 24210089..d9668ec3 100644 --- a/libsrc/leddevice/dev_serial/LedDeviceTpm2.cpp +++ b/libsrc/leddevice/dev_serial/LedDeviceTpm2.cpp @@ -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 &ledValues) diff --git a/libsrc/leddevice/dev_serial/LedDeviceTpm2.h b/libsrc/leddevice/dev_serial/LedDeviceTpm2.h index 11b923c2..55b9e613 100644 --- a/libsrc/leddevice/dev_serial/LedDeviceTpm2.h +++ b/libsrc/leddevice/dev_serial/LedDeviceTpm2.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; }; diff --git a/libsrc/leddevice/dev_serial/ProviderRs232.cpp b/libsrc/leddevice/dev_serial/ProviderRs232.cpp index 3e20fbc1..295dc491 100644 --- a/libsrc/leddevice/dev_serial/ProviderRs232.cpp +++ b/libsrc/leddevice/dev_serial/ProviderRs232.cpp @@ -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()); -} diff --git a/libsrc/leddevice/dev_serial/ProviderRs232.h b/libsrc/leddevice/dev_serial/ProviderRs232.h index 748b8678..36b454a3 100644 --- a/libsrc/leddevice/dev_serial/ProviderRs232.h +++ b/libsrc/leddevice/dev_serial/ProviderRs232.h @@ -5,7 +5,7 @@ #include #include -// Leddevice includes +// LedDevice includes #include /// @@ -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(); diff --git a/libsrc/leddevice/dev_spi/LedDeviceAPA102.cpp b/libsrc/leddevice/dev_spi/LedDeviceAPA102.cpp index 3a114024..b2ad5de0 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceAPA102.cpp +++ b/libsrc/leddevice/dev_spi/LedDeviceAPA102.cpp @@ -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(((_ledCount + 15) / 16), 4); - const unsigned int APAbufferSize = (_ledCount * 4) + startFrameSize + endFrameSize; + if ( isInitOK ) + { + const unsigned int startFrameSize = 4; + const unsigned int endFrameSize = qMax(((_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 &ledValues) { - for (signed iLed=0; iLed < _ledCount; ++iLed) { + for (signed iLed=0; iLed < static_cast( _ledCount); ++iLed) { const ColorRgb& rgb = ledValues[iLed]; _ledBuffer[4+iLed*4] = 0xFF; _ledBuffer[4+iLed*4+1] = rgb.red; diff --git a/libsrc/leddevice/dev_spi/LedDeviceAPA102.h b/libsrc/leddevice/dev_spi/LedDeviceAPA102.h index 4bb84f62..3e048538 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceAPA102.h +++ b/libsrc/leddevice/dev_spi/LedDeviceAPA102.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; }; diff --git a/libsrc/leddevice/dev_spi/LedDeviceAPA104.cpp b/libsrc/leddevice/dev_spi/LedDeviceAPA104.cpp index f134cb03..a273de88 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceAPA104.cpp +++ b/libsrc/leddevice/dev_spi/LedDeviceAPA104.cpp @@ -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 &ledValues) diff --git a/libsrc/leddevice/dev_spi/LedDeviceAPA104.h b/libsrc/leddevice/dev_spi/LedDeviceAPA104.h index 23f9500d..b4ecd3b9 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceAPA104.h +++ b/libsrc/leddevice/dev_spi/LedDeviceAPA104.h @@ -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 &ledValues); - - const int SPI_BYTES_PER_COLOUR; + virtual int write(const std::vector &ledValues) override; + const int SPI_BYTES_PER_COLOUR; const int SPI_FRAME_END_LATCH_BYTES; uint8_t bitpair_to_byte[4]; diff --git a/libsrc/leddevice/dev_spi/LedDeviceLpd6803.cpp b/libsrc/leddevice/dev_spi/LedDeviceLpd6803.cpp index eae8b31c..0d5f3c6d 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceLpd6803.cpp +++ b/libsrc/leddevice/dev_spi/LedDeviceLpd6803.cpp @@ -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 &ledValues) diff --git a/libsrc/leddevice/dev_spi/LedDeviceLpd6803.h b/libsrc/leddevice/dev_spi/LedDeviceLpd6803.h index fd0da312..c9ab7d49 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceLpd6803.h +++ b/libsrc/leddevice/dev_spi/LedDeviceLpd6803.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; }; diff --git a/libsrc/leddevice/dev_spi/LedDeviceLpd8806.cpp b/libsrc/leddevice/dev_spi/LedDeviceLpd8806.cpp index aaec88b0..42c17d96 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceLpd8806.cpp +++ b/libsrc/leddevice/dev_spi/LedDeviceLpd8806.cpp @@ -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 &ledValues) diff --git a/libsrc/leddevice/dev_spi/LedDeviceLpd8806.h b/libsrc/leddevice/dev_spi/LedDeviceLpd8806.h index b921a30d..95eb8c04 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceLpd8806.h +++ b/libsrc/leddevice/dev_spi/LedDeviceLpd8806.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; }; diff --git a/libsrc/leddevice/dev_spi/LedDeviceP9813.cpp b/libsrc/leddevice/dev_spi/LedDeviceP9813.cpp index bc76aea0..d8656b71 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceP9813.cpp +++ b/libsrc/leddevice/dev_spi/LedDeviceP9813.cpp @@ -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 &ledValues) diff --git a/libsrc/leddevice/dev_spi/LedDeviceP9813.h b/libsrc/leddevice/dev_spi/LedDeviceP9813.h index af3fb337..cd6d1670 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceP9813.h +++ b/libsrc/leddevice/dev_spi/LedDeviceP9813.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; /// /// Calculates the required checksum for one led diff --git a/libsrc/leddevice/dev_spi/LedDeviceSk6812SPI.cpp b/libsrc/leddevice/dev_spi/LedDeviceSk6812SPI.cpp index f995ba9a..d8aeb114 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceSk6812SPI.cpp +++ b/libsrc/leddevice/dev_spi/LedDeviceSk6812SPI.cpp @@ -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 &ledValues) diff --git a/libsrc/leddevice/dev_spi/LedDeviceSk6812SPI.h b/libsrc/leddevice/dev_spi/LedDeviceSk6812SPI.h index 2c35cbb9..8905e3af 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceSk6812SPI.h +++ b/libsrc/leddevice/dev_spi/LedDeviceSk6812SPI.h @@ -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 &ledValues); + virtual int write(const std::vector &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; }; diff --git a/libsrc/leddevice/dev_spi/LedDeviceSk6822SPI.cpp b/libsrc/leddevice/dev_spi/LedDeviceSk6822SPI.cpp index 61eb1c0c..f85d8f8f 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceSk6822SPI.cpp +++ b/libsrc/leddevice/dev_spi/LedDeviceSk6822SPI.cpp @@ -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 &ledValues) @@ -80,8 +81,8 @@ int LedDeviceSk6822SPI::write(const std::vector &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 &ledValues) } -/* + /* // debug the whole SPI packet char debug_line[2048]; int ptr=0; @@ -104,14 +105,14 @@ int LedDeviceSk6822SPI::write(const std::vector &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()); diff --git a/libsrc/leddevice/dev_spi/LedDeviceSk6822SPI.h b/libsrc/leddevice/dev_spi/LedDeviceSk6822SPI.h index 41d18cf0..6098c177 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceSk6822SPI.h +++ b/libsrc/leddevice/dev_spi/LedDeviceSk6822SPI.h @@ -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 &ledValues); + virtual int write(const std::vector &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]; }; diff --git a/libsrc/leddevice/dev_spi/LedDeviceWs2801.cpp b/libsrc/leddevice/dev_spi/LedDeviceWs2801.cpp index b52cfc02..029dbc7e 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceWs2801.cpp +++ b/libsrc/leddevice/dev_spi/LedDeviceWs2801.cpp @@ -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 &ledValues) { const unsigned dataLen = _ledCount * sizeof(ColorRgb); diff --git a/libsrc/leddevice/dev_spi/LedDeviceWs2801.h b/libsrc/leddevice/dev_spi/LedDeviceWs2801.h index b405344e..d349c558 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceWs2801.h +++ b/libsrc/leddevice/dev_spi/LedDeviceWs2801.h @@ -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 &ledValues); + virtual int write(const std::vector &ledValues) override; }; diff --git a/libsrc/leddevice/dev_spi/LedDeviceWs2812SPI.cpp b/libsrc/leddevice/dev_spi/LedDeviceWs2812SPI.cpp index b98db68f..b536c9ec 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceWs2812SPI.cpp +++ b/libsrc/leddevice/dev_spi/LedDeviceWs2812SPI.cpp @@ -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 &ledValues) @@ -75,8 +76,8 @@ int LedDeviceWs2812SPI::write(const std::vector &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--) { diff --git a/libsrc/leddevice/dev_spi/LedDeviceWs2812SPI.h b/libsrc/leddevice/dev_spi/LedDeviceWs2812SPI.h index 4da3d9fb..5ff14cf8 100644 --- a/libsrc/leddevice/dev_spi/LedDeviceWs2812SPI.h +++ b/libsrc/leddevice/dev_spi/LedDeviceWs2812SPI.h @@ -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 &ledValues); - - const int SPI_BYTES_PER_COLOUR; + virtual int write(const std::vector &ledValues) override; + const int SPI_BYTES_PER_COLOUR; const int SPI_FRAME_END_LATCH_BYTES; uint8_t bitpair_to_byte[4]; diff --git a/libsrc/leddevice/dev_spi/ProviderSpi.cpp b/libsrc/leddevice/dev_spi/ProviderSpi.cpp index 7a3211b4..4787484a 100644 --- a/libsrc/leddevice/dev_spi/ProviderSpi.cpp +++ b/libsrc/leddevice/dev_spi/ProviderSpi.cpp @@ -1,4 +1,4 @@ - + // STL includes #include #include @@ -7,6 +7,7 @@ // Linux includes #include +#include #include // 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) diff --git a/libsrc/leddevice/dev_spi/ProviderSpi.h b/libsrc/leddevice/dev_spi/ProviderSpi.h index 390eab81..cf8e2e4d 100644 --- a/libsrc/leddevice/dev_spi/ProviderSpi.h +++ b/libsrc/leddevice/dev_spi/ProviderSpi.h @@ -22,19 +22,26 @@ 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 ~ProviderSpi(); + virtual ~ProviderSpi() 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; protected: /// diff --git a/libsrc/leddevice/dev_tinker/LedDeviceTinkerforge.cpp b/libsrc/leddevice/dev_tinker/LedDeviceTinkerforge.cpp index d1eac74d..a35d7d4f 100644 --- a/libsrc/leddevice/dev_tinker/LedDeviceTinkerforge.cpp +++ b/libsrc/leddevice/dev_tinker/LedDeviceTinkerforge.cpp @@ -15,92 +15,110 @@ LedDeviceTinkerforge::LedDeviceTinkerforge(const QJsonObject &deviceConfig) , _ledStrip(nullptr) , _colorChannelSize(0) { - init(deviceConfig); + _devConfig = deviceConfig; + _deviceReady = false; } LedDeviceTinkerforge::~LedDeviceTinkerforge() { - // Close the device (if it is opened) - if (_ipConnection != nullptr && _ledStrip != nullptr) - { - switchOff(); - } - // Clean up claimed resources delete _ipConnection; delete _ledStrip; } -bool LedDeviceTinkerforge::init(const QJsonObject &deviceConfig) -{ - LedDevice::init(deviceConfig); - - _host = deviceConfig["output"].toString("127.0.0.1"); - _port = deviceConfig["port"].toInt(4223); - _uid = deviceConfig["uid"].toString(); - _interval = deviceConfig["rate"].toInt(); - - if ((unsigned)_ledCount > MAX_NUM_LEDS) - { - Error(_log,"Invalid attempt to write led values. Not more than %d leds are allowed.", MAX_NUM_LEDS); - return -1; - } - - if (_colorChannelSize < (unsigned)_ledCount) - { - _redChannel.resize(_ledCount, uint8_t(0)); - _greenChannel.resize(_ledCount, uint8_t(0)); - _blueChannel.resize(_ledCount, uint8_t(0)); - } - _colorChannelSize = _ledCount; - - return true; -} - LedDevice* LedDeviceTinkerforge::construct(const QJsonObject &deviceConfig) { return new LedDeviceTinkerforge(deviceConfig); } + +bool LedDeviceTinkerforge::init(const QJsonObject &deviceConfig) +{ + bool isInitOK = LedDevice::init(deviceConfig); + if (isInitOK) + { + _host = deviceConfig["output"].toString("127.0.0.1"); + _port = deviceConfig["port"].toInt(4223); + _uid = deviceConfig["uid"].toString(); + _interval = deviceConfig["rate"].toInt(); + + if ((unsigned)_ledCount > MAX_NUM_LEDS) + { + QString errortext = QString ("Initialization error. Not more than %1 leds are allowed.").arg(MAX_NUM_LEDS); + this->setInError(errortext); + isInitOK = false; + } + else + { + if (_colorChannelSize < (unsigned)_ledCount) + { + _redChannel.resize(_ledCount, uint8_t(0)); + _greenChannel.resize(_ledCount, uint8_t(0)); + _blueChannel.resize(_ledCount, uint8_t(0)); + } + _colorChannelSize = _ledCount; + isInitOK = true; + } + } + return isInitOK; +} + int LedDeviceTinkerforge::open() { - // Check if connection is already createds - if (_ipConnection != nullptr) + int retval = -1; + QString errortext; + _deviceReady = false; + + if ( init(_devConfig) ) { - Error(_log, "Attempt to open existing connection; close before opening"); - return 0; + + // Check if connection is already createds + if (_ipConnection != nullptr) + { + Error(_log, "Attempt to open existing connection; close before opening"); + } + else + { + // Initialise a new connection + _ipConnection = new IPConnection; + ipcon_create(_ipConnection); + + int connectionStatus = ipcon_connect(_ipConnection, QSTRING_CSTR(_host), _port); + if (connectionStatus < 0) + { + Error(_log, "Attempt to connect to master brick (%s:%d) failed with status %d", QSTRING_CSTR(_host), _port, connectionStatus); + } + else + { + // Create the 'LedStrip' + _ledStrip = new LEDStrip; + led_strip_create(_ledStrip, QSTRING_CSTR(_uid), _ipConnection); + + int frameStatus = led_strip_set_frame_duration(_ledStrip, _interval); + if (frameStatus < 0) + { + Error(_log,"Attempt to connect to led strip bricklet (led_strip_set_frame_duration()) failed with status %d", frameStatus); + } + else + { + // Everything is OK -> enable device + _deviceReady = true; + setEnable(true); + retval = 0; + } + } + } + // On error/exceptions, set LedDevice in error + if ( retval < 0 ) + { + this->setInError( "Error opening device!" ); + } } - - // Initialise a new connection - _ipConnection = new IPConnection; - ipcon_create(_ipConnection); - - int connectionStatus = ipcon_connect(_ipConnection, QSTRING_CSTR(_host), _port); - if (connectionStatus < 0) - { - Error(_log, "Attempt to connect to master brick (%s:%d) failed with status %d", QSTRING_CSTR(_host), _port, connectionStatus); - return 0; - } - - // Create the 'LedStrip' - _ledStrip = new LEDStrip; - led_strip_create(_ledStrip, QSTRING_CSTR(_uid), _ipConnection); - - int frameStatus = led_strip_set_frame_duration(_ledStrip, _interval); - if (frameStatus < 0) - { - Error(_log,"Attempt to connect to led strip bricklet (led_strip_set_frame_duration()) failed with status %d", frameStatus); - return 0; - } - - return 1; + return retval; } int LedDeviceTinkerforge::write(const std::vector &ledValues) { - if(!_deviceReady) - return 0; - auto redIt = _redChannel.begin(); auto greenIt = _greenChannel.begin(); auto blueIt = _blueChannel.begin(); diff --git a/libsrc/leddevice/dev_tinker/LedDeviceTinkerforge.h b/libsrc/leddevice/dev_tinker/LedDeviceTinkerforge.h index fd086cf1..8cf8633a 100644 --- a/libsrc/leddevice/dev_tinker/LedDeviceTinkerforge.h +++ b/libsrc/leddevice/dev_tinker/LedDeviceTinkerforge.h @@ -8,7 +8,6 @@ // Hyperion-Leddevice includes #include - extern "C" { #include #include @@ -22,26 +21,27 @@ public: /// /// @param deviceConfig json device config /// - LedDeviceTinkerforge(const QJsonObject &deviceConfig); + explicit LedDeviceTinkerforge(const QJsonObject &deviceConfig); - virtual ~LedDeviceTinkerforge(); + virtual ~LedDeviceTinkerforge() 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); - - /// constructs leddevice - static LedDevice* construct(const QJsonObject &deviceConfig); + bool init(const QJsonObject &deviceConfig) override; +protected: /// /// Attempts to open a connection to the master bricklet and the led strip bricklet. /// /// @return Zero on succes else negative /// - int open(); + virtual int open() override; private: /// @@ -51,7 +51,7 @@ private: /// /// @return Zero on success else negative /// - virtual int write(const std::vector &ledValues); + virtual int write(const std::vector &ledValues) override; /// /// Writes the data to the led strip blicklet diff --git a/libsrc/leddevice/schemas/schema-file.json b/libsrc/leddevice/schemas/schema-file.json index 0767f499..7f8a069d 100644 --- a/libsrc/leddevice/schemas/schema-file.json +++ b/libsrc/leddevice/schemas/schema-file.json @@ -11,9 +11,9 @@ "latchTime": { "type": "integer", "title":"edt_dev_spec_latchtime_title", - "default": 1, + "default": 0, "append" : "edt_append_ms", - "minimum": 1, + "minimum": 0, "maximum": 1000, "access" : "expert", "propertyOrder" : 2 diff --git a/libsrc/leddevice/schemas/schema-nanoleaf.json b/libsrc/leddevice/schemas/schema-nanoleaf.json index 9d12c158..4bf6e39d 100644 --- a/libsrc/leddevice/schemas/schema-nanoleaf.json +++ b/libsrc/leddevice/schemas/schema-nanoleaf.json @@ -2,7 +2,7 @@ "type":"object", "required":true, "properties":{ - "output": { + "host": { "type": "string", "title":"edt_dev_spec_targetIpHost_title", "propertyOrder" : 1 diff --git a/src/hyperion-framebuffer/FramebufferWrapper.cpp b/src/hyperion-framebuffer/FramebufferWrapper.cpp index 66568288..cd0348da 100644 --- a/src/hyperion-framebuffer/FramebufferWrapper.cpp +++ b/src/hyperion-framebuffer/FramebufferWrapper.cpp @@ -6,6 +6,7 @@ FramebufferWrapper::FramebufferWrapper(const QString & device, const unsigned gr _timer(this), _grabber(device,grabWidth, grabHeight) { + _timer.setTimerType(Qt::PreciseTimer); _timer.setSingleShot(false); _timer.setInterval(updateRate_Hz); diff --git a/test/TestSpi.cpp b/test/TestSpi.cpp index a20199d9..f83c7253 100644 --- a/test/TestSpi.cpp +++ b/test/TestSpi.cpp @@ -63,7 +63,7 @@ void setColor(char* colorStr) LedDeviceWs2801 ledDevice(deviceConfig); ledDevice.open(); - ledDevice.setLedValues(buff); + ledDevice.updateLeds(buff); } bool _running = true; @@ -112,7 +112,7 @@ void doCircle() data[curLed_2] = color_2; - ledDevice.setLedValues(data); + ledDevice.updateLeds(data); nanosleep(&loopTime, NULL); } @@ -121,7 +121,7 @@ void doCircle() data[curLed_1] = ColorRgb::BLACK; data[curLed_2] = ColorRgb::BLACK; - ledDevice.setLedValues(data); + ledDevice.updateLeds(data); } #include