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/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; + +};