From cf21ba76c9e4208599ce77de7eb434231100fa5c Mon Sep 17 00:00:00 2001 From: Bjoern Bilger Date: Tue, 4 Mar 2014 20:38:54 +0100 Subject: [PATCH] add support for tinkerforge Former-commit-id: f624e4ea226365d6cc832ebbe51b471559341f33 --- CMakeLists.txt | 7 ++ HyperionConfig.h.in | 3 + cmake/Findlibtinkerforge-1.0.cmake | 96 +++++++++++++++ libsrc/leddevice/CMakeLists.txt | 42 +++++-- libsrc/leddevice/LedDeviceFactory.cpp | 20 +++ libsrc/leddevice/LedDeviceTinkerforge.cpp | 141 ++++++++++++++++++++++ libsrc/leddevice/LedDeviceTinkerforge.h | 82 +++++++++++++ 7 files changed, 384 insertions(+), 7 deletions(-) create mode 100644 cmake/Findlibtinkerforge-1.0.cmake create mode 100644 libsrc/leddevice/LedDeviceTinkerforge.cpp create mode 100644 libsrc/leddevice/LedDeviceTinkerforge.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 34aec49e..9903cbaf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,9 @@ message(STATUS "ENABLE_SPIDEV = " ${ENABLE_SPIDEV}) option(ENABLE_V4L2 "Enable the V4L2 grabber" ON) message(STATUS "ENABLE_V4L2 = " ${ENABLE_V4L2}) +option(ENABLE_TINKERFORGE "Enable the TINKERFORGE device" OFF) +message(STATUS "ENABLE_TINKERFORGE = " ${ENABLE_TINKERFORGE}) + # Createt the configuration file # configure a header file to pass some of the CMake settings # to the source code @@ -62,6 +65,10 @@ set(CMAKE_FIND_LIBRARY_SUFFIXES_OLD) find_package(libusb-1.0 REQUIRED) find_package(Threads REQUIRED) +if (ENABLE_TINKERFORGE) + find_package(libtinkerforge-1.0 REQUIRED) +endif (ENABLE_TINKERFORGE) + include(${QT_USE_FILE}) add_definitions(${QT_DEFINITIONS}) # TODO[TvdZ]: This linking directory should only be added if we are cross compiling diff --git a/HyperionConfig.h.in b/HyperionConfig.h.in index 14500c71..17f040c0 100644 --- a/HyperionConfig.h.in +++ b/HyperionConfig.h.in @@ -8,3 +8,6 @@ // Define to enable the spi-device #cmakedefine ENABLE_SPIDEV + +// Define to enable the spi-device +#cmakedefine ENABLE_TINKERFORGE diff --git a/cmake/Findlibtinkerforge-1.0.cmake b/cmake/Findlibtinkerforge-1.0.cmake new file mode 100644 index 00000000..e9b6b3ba --- /dev/null +++ b/cmake/Findlibtinkerforge-1.0.cmake @@ -0,0 +1,96 @@ +# - Try to find libtinkerforge-1.0 +# Once done this will define +# +# LIBTINKERFORGE_1_FOUND - system has libtinkerforge +# LIBTINKERFORGE_1_INCLUDE_DIRS - the libtinkerforge include directory +# LIBTINKERFORGE_1_LIBRARIES - Link these to use libtinkerforge +# LIBTINKERFORGE_1_DEFINITIONS - Compiler switches required for using libtinkerforge +# +# Adapted from cmake-modules Google Code project +# +# Copyright (c) 2006 Andreas Schneider +# +# (Changes for libtinkerforge) Copyright (c) 2014 Björn Bilger +# +# Redistribution and use is allowed according to the terms of the New BSD license. +# +# CMake-Modules Project New BSD License +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of the CMake-Modules Project nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + + +if (LIBTINKERFORGE_1_LIBRARIES AND LIBTINKERFORGE_1_INCLUDE_DIRS) + # in cache already + set(LIBTINKERFORGE_FOUND TRUE) +else (LIBTINKERFORGE_1_LIBRARIES AND LIBTINKERFORGE_1_INCLUDE_DIRS) + find_path(LIBTINKERFORGE_1_INCLUDE_DIR + NAMES + tinkerforge/tinkerforge.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + PATH_SUFFIXES + tinkerforge-1.0 + ) + + find_library(LIBTINKERFORGE_1_LIBRARY + NAMES + tinkerforge-1.0 + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ) + + set(LIBTINKERFORGE_1_INCLUDE_DIRS + ${LIBTINKERFORGE_1_INCLUDE_DIR} + ) + set(LIBTINKERFORGE_1_LIBRARIES + ${LIBTINKERFORGE_1_LIBRARY} +) + + if (LIBTINKERFORGE_1_INCLUDE_DIRS AND LIBTINKERFORGE_1_LIBRARIES) + set(LIBTINKERFORGE_1_FOUND TRUE) + endif (LIBTINKERFORGE_1_INCLUDE_DIRS AND LIBTINKERFORGE_1_LIBRARIES) + + if (LIBTINKERFORGE_1_FOUND) + if (NOT libtinkerforge_1_FIND_QUIETLY) + message(STATUS "Found libtinkerforge-1.0:") + message(STATUS " - Includes: ${LIBTINKERFORGE_1_INCLUDE_DIRS}") + message(STATUS " - Libraries: ${LIBTINKERFORGE_1_LIBRARIES}") + endif (NOT libtinkerforge_1_FIND_QUIETLY) + else (LIBTINKERFORGE_1_FOUND) + message(FATAL_ERROR "Could not find libtinkerforge") + endif (LIBTINKERFORGE_1_FOUND) + + # show the LIBTINKERFORGE_1_INCLUDE_DIRS and LIBTINKERFORGE_1_LIBRARIES variables only in the advanced view + mark_as_advanced(LIBTINKERFORGE_1_INCLUDE_DIRS LIBTINKERFORGE_1_LIBRARIES) + +endif (LIBTINKERFORGE_1_LIBRARIES AND LIBTINKERFORGE_1_INCLUDE_DIRS) diff --git a/libsrc/leddevice/CMakeLists.txt b/libsrc/leddevice/CMakeLists.txt index 6bfc2fe8..633e8dcd 100644 --- a/libsrc/leddevice/CMakeLists.txt +++ b/libsrc/leddevice/CMakeLists.txt @@ -6,10 +6,20 @@ SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/leddevice) #add libusb and pthreads (required for the Lighpack usb device) find_package(libusb-1.0 REQUIRED) find_package(Threads REQUIRED) +if(ENABLE_TINKERFORGE) + find_package(libtinkerforge-1.0 REQUIRED) +endif(ENABLE_TINKERFORGE) + include_directories( - ../../include/hidapi - ${LIBUSB_1_INCLUDE_DIRS}) # for Lightpack device + ../../include/hidapi + ${LIBUSB_1_INCLUDE_DIRS}) # for Lightpack device + + +if(ENABLE_TINKERFORGE) + include_directories( + ${LIBTINKERFORGE_1_INCLUDE_DIRS}) # for Tinkerforge device +endif(ENABLE_TINKERFORGE) # Group the headers that go through the MOC compiler SET(Leddevice_QT_HEADERS @@ -67,6 +77,17 @@ if(ENABLE_SPIDEV) ) endif(ENABLE_SPIDEV) +if(ENABLE_TINKERFORGE) + SET(Leddevice_HEADERS + ${Leddevice_HEADERS} + ${CURRENT_SOURCE_DIR}/LedDeviceTinkerforge.h + ) + SET(Leddevice_SOURCES + ${Leddevice_SOURCES} + ${CURRENT_SOURCE_DIR}/LedDeviceTinkerforge.cpp + ) +endif(ENABLE_TINKERFORGE) + QT4_WRAP_CPP(Leddevice_HEADERS_MOC ${Leddevice_QT_HEADERS}) @@ -78,12 +99,19 @@ add_library(leddevice ) target_link_libraries(leddevice - hyperion-utils - serialport - ${LIBUSB_1_LIBRARIES} #apt-get install libusb-1.0-0-dev - ${CMAKE_THREAD_LIBS_INIT} - ${QT_LIBRARIES} + hyperion-utils + serialport + ${LIBUSB_1_LIBRARIES} #apt-get install libusb-1.0-0-dev + ${CMAKE_THREAD_LIBS_INIT} + ${QT_LIBRARIES} ) + +if(ENABLE_TINKERFORGE) + target_link_libraries(leddevice + ${LIBTINKERFORGE_1_LIBRARIES} + ) +endif() + if(APPLE) target_link_libraries(leddevice hidapi-mac) else() diff --git a/libsrc/leddevice/LedDeviceFactory.cpp b/libsrc/leddevice/LedDeviceFactory.cpp index 2a9aeb4e..4c596e88 100644 --- a/libsrc/leddevice/LedDeviceFactory.cpp +++ b/libsrc/leddevice/LedDeviceFactory.cpp @@ -16,6 +16,10 @@ #include "LedDeviceWs2801.h" #endif +#ifdef ENABLE_TINKERFORGE + #include "LedDeviceTinkerforge.h" +#endif + #include "LedDeviceAdalight.h" #include "LedDeviceLightpack.h" #include "LedDeviceMultiLightpack.h" @@ -87,6 +91,22 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig) device = deviceWs2801; } #endif + +#ifdef ENABLE_TINKERFORGE + else if (type=="tinkerforge") + { + const std::string host = deviceConfig.get("output", "127.0.0.1").asString(); + const uint16_t port = deviceConfig.get("port", 4223).asInt(); + const std::string uid = deviceConfig["uid"].asString(); + const unsigned rate = deviceConfig["rate"].asInt(); + + LedDeviceTinkerforge* deviceTinkerforge = new LedDeviceTinkerforge(host, port, uid, rate); + deviceTinkerforge->open(); + + device = deviceTinkerforge; + } +#endif + // else if (type == "ws2811") // { // const std::string output = deviceConfig["output"].asString(); diff --git a/libsrc/leddevice/LedDeviceTinkerforge.cpp b/libsrc/leddevice/LedDeviceTinkerforge.cpp new file mode 100644 index 00000000..04cfb151 --- /dev/null +++ b/libsrc/leddevice/LedDeviceTinkerforge.cpp @@ -0,0 +1,141 @@ + +// STL includes +#include +#include + +// Local LedDevice includes +#include "LedDeviceTinkerforge.h" + +static const unsigned MAX_NUM_LEDS = 320; +static const unsigned MAX_NUM_LEDS_SETTABLE = 16; + +LedDeviceTinkerforge::LedDeviceTinkerforge(const std::string &host, uint16_t port, const std::string &uid, const unsigned interval) : + LedDevice(), + _host(host), + _port(port), + _uid(uid), + _interval(interval), + _ipConnection(nullptr), + _ledStrip(nullptr), + _colorChannelSize(0) +{ + // empty +} + +LedDeviceTinkerforge::~LedDeviceTinkerforge() +{ + // Close the device (if it is opened) + if (_ipConnection != nullptr && _ledStrip != nullptr) + { + switchOff(); + } + if (_ipConnection != nullptr) + delete _ipConnection; + if (_ledStrip != nullptr) + delete _ledStrip; +} + +int LedDeviceTinkerforge::open() +{ + _ipConnection = new IPConnection; + ipcon_create(_ipConnection); + + int connectionStatus = ipcon_connect(_ipConnection, _host.c_str(), _port); + if (connectionStatus < 0) + { + std::cerr << "Attempt to connect to master brick (" << _host << ":" << _port << ") failed with status " << connectionStatus << std::endl; + return -1; + } + + _ledStrip = new LEDStrip; + led_strip_create(_ledStrip, _uid.c_str(), _ipConnection); + + int frameStatus = led_strip_set_frame_duration(_ledStrip, _interval); + if (frameStatus < 0) + { + std::cerr << "Attempt to connect to led strip bricklet (led_strip_set_frame_duration()) failed with status " << frameStatus << std::endl; + return -1; + } + + return 0; +} + +int LedDeviceTinkerforge::write(const std::vector &ledValues) +{ + std::cerr << "Write" << std::endl; + + unsigned nrLedValues = ledValues.size(); + + if (nrLedValues > MAX_NUM_LEDS) + { + std::cerr << "Invalid attempt to write led values. Not more than " << MAX_NUM_LEDS << " leds are allowed." << std::endl; + return -1; + } + + if (_colorChannelSize < nrLedValues) + { + _redChannel.resize(nrLedValues, uint8_t(0)); + _greenChannel.resize(nrLedValues, uint8_t(0)); + _blueChannel.resize(nrLedValues, uint8_t(0)); + } + _colorChannelSize = nrLedValues; + + auto redIt = _redChannel.begin(); + auto greenIt = _greenChannel.begin(); + auto blueIt = _blueChannel.begin(); + + for (const ColorRgb &ledValue : ledValues) + { + *redIt = ledValue.red; + redIt++; + *greenIt = ledValue.green; + greenIt++; + *blueIt = ledValue.blue; + blueIt++; + } + + return transferLedData(_ledStrip, 0, _colorChannelSize, &_redChannel[0], &_greenChannel[0], &_blueChannel[0]); +} + +int LedDeviceTinkerforge::switchOff() +{ + std::cerr << "Switchoff" << std::endl; + std::fill(_redChannel.begin(), _redChannel.end(), 0); + std::fill(_greenChannel.begin(), _greenChannel.end(), 0); + std::fill(_blueChannel.begin(), _blueChannel.end(), 0); + + return transferLedData(_ledStrip, 0, _colorChannelSize, &_redChannel[0], &_greenChannel[0], &_blueChannel[0]); +} + +int LedDeviceTinkerforge::transferLedData(LEDStrip *ledStrip, unsigned index, unsigned length, uint8_t *redChannel, uint8_t *greenChannel, uint8_t *blueChannel) +{ + // we need that array size no matter how many leds will really be set + uint8_t _reds[MAX_NUM_LEDS_SETTABLE]; + uint8_t _greens[MAX_NUM_LEDS_SETTABLE]; + uint8_t _blues[MAX_NUM_LEDS_SETTABLE]; + + int status = E_INVALID_PARAMETER; + unsigned i; + unsigned int copyLength; + + if (index >= 0 && length > 0 && index < length && length <= MAX_NUM_LEDS) + { + for (i = index; i < length; i += MAX_NUM_LEDS_SETTABLE) + { + copyLength = (i + MAX_NUM_LEDS_SETTABLE > length) ? length - i : MAX_NUM_LEDS_SETTABLE; + + memcpy(_reds, redChannel + i, copyLength * sizeof(uint8_t)); + memcpy(_greens, greenChannel + i, copyLength * sizeof(uint8_t)); + memcpy(_blues, blueChannel + i, copyLength * sizeof(uint8_t)); + + status = led_strip_set_rgb_values(ledStrip, i, copyLength, _reds, _greens, _blues); + + if (status != E_OK) + { + std::cerr << "Setting led values failed with status " << status << std::endl; + break; + } + } + } + return status; +} diff --git a/libsrc/leddevice/LedDeviceTinkerforge.h b/libsrc/leddevice/LedDeviceTinkerforge.h new file mode 100644 index 00000000..95f43332 --- /dev/null +++ b/libsrc/leddevice/LedDeviceTinkerforge.h @@ -0,0 +1,82 @@ + +#pragma once + +// STL includes +#include + +// Hyperion-Leddevice includes +#include + + +extern "C" { + #include + #include +} + +class LedDeviceTinkerforge : public LedDevice +{ +public: + + LedDeviceTinkerforge(const std::string &host, uint16_t port, const std::string &uid, const unsigned interval); + + virtual ~LedDeviceTinkerforge(); + + /// + /// Attempts to open a connection to the master bricklet and the led strip bricklet. + /// + /// @return Zero on succes else negative + /// + int open(); + + /// + /// Writes the colors to the led strip bricklet + /// + /// @param ledValues The color value for each led + /// + /// @return Zero on success else negative + /// + virtual int write(const std::vector &ledValues); + + /// + /// Switches off the leds + /// + /// @return Zero on success else negative + /// + virtual int switchOff(); + +private: + /// + /// Writes the data to the led strip blicklet + int transferLedData(LEDStrip *ledstrip, unsigned int index, unsigned int length, uint8_t *redChannel, uint8_t *greenChannel, uint8_t *blueChannel); + + /// The host of the master brick + const std::string _host; + + /// The port of the master brick + const uint16_t _port; + + /// The uid of the led strip bricklet + const std::string _uid; + + /// The interval/rate + const unsigned _interval; + + /// ip connection handle + IPConnection *_ipConnection; + + /// led strip handle + LEDStrip *_ledStrip; + + /// buffer for red channel led data + std::vector _redChannel; + + /// buffer for red channel led data + std::vector _greenChannel; + + /// buffer for red channel led data + std::vector _blueChannel; + + /// buffer size of the color channels + unsigned int _colorChannelSize; + +};