diff --git a/config/hyperion.config.json b/config/hyperion.config.json index 8e361ed0..44931ac4 100644 --- a/config/hyperion.config.json +++ b/config/hyperion.config.json @@ -5,11 +5,15 @@ /// Device configuration contains the following fields: /// * 'name' : The user friendly name of the device (only used for display purposes) /// * 'type' : The type of the device or leds (known types for now are 'ws2801', 'ldp8806', - /// 'lpd6803', 'sedu', 'adalight', 'lightpack', 'test' and 'none') + /// 'lpd6803', 'sedu', 'adalight', 'lightpack', 'philipshue', 'test' and 'none') /// * 'output' : The output specification depends on selected device. This can for example be the /// device specifier, device serial number, or the output file name /// * 'rate' : The baudrate of the output to the device /// * 'colorOrder' : The order of the color bytes ('rgb', 'rbg', 'bgr', etc.). + /// Specific of Philips Hue: + /// * 'username' : The name of user registred on the Philips Hue Bridge + /// * 'switchOffOnBlack' : Define if Hue light switch off when black is detected + /// * 'transitiontime' : Set the time of transition between color of Hue light "device" : { "name" : "MyPi", diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index 9689d97d..b6ed0946 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -52,12 +52,6 @@ public: SATURATION_GAIN, VALUE_GAIN, THRESHOLD, GAMMA, BLACKLEVEL, WHITELEVEL }; - /// Enumeration containing the possible orders of device color byte data - enum ColorOrder - { - ORDER_RGB, ORDER_RBG, ORDER_GRB, ORDER_BRG, ORDER_GBR, ORDER_BGR - }; - /// /// Constructs the Hyperion instance based on the given Json configuration /// @@ -159,7 +153,14 @@ public slots: public: static ColorOrder createColorOrder(const Json::Value & deviceConfig); - static LedString createLedString(const Json::Value & ledsConfig); + /** + * Construct the 'led-string' with the integration area definition per led and the color + * ordering of the RGB channels + * @param ledsConfig The configuration of the led areas + * @param deviceOrder The default RGB channel ordering + * @return The constructed ledstring + */ + static LedString createLedString(const Json::Value & ledsConfig, const ColorOrder deviceOrder); static MultiColorTransform * createLedColorsTransform(const unsigned ledCnt, const Json::Value & colorTransformConfig); static ColorTransform * createColorTransform(const Json::Value & transformConfig); @@ -194,9 +195,6 @@ private: /// The transformation from raw colors to led colors MultiColorTransform * _raw2ledTransform; - /// Value with the desired color byte order - ColorOrder _colorOrder; - /// The actual LedDevice LedDevice * _device; diff --git a/include/hyperion/LedString.h b/include/hyperion/LedString.h index e6adc2c0..2c9a0cb3 100644 --- a/include/hyperion/LedString.h +++ b/include/hyperion/LedString.h @@ -12,6 +12,63 @@ // Forward class declarations namespace Json { class Value; } +/// Enumeration containing the possible orders of device color byte data +enum ColorOrder +{ + ORDER_RGB, ORDER_RBG, ORDER_GRB, ORDER_BRG, ORDER_GBR, ORDER_BGR +}; + +inline std::string colorOrderToString(const ColorOrder colorOrder) +{ + switch (colorOrder) + { + case ORDER_RGB: + return "rgb"; + case ORDER_RBG: + return "rbg"; + case ORDER_GRB: + return "grb"; + case ORDER_BRG: + return "brg"; + case ORDER_GBR: + return "gbr"; + case ORDER_BGR: + return "bgr"; + default: + return "not-a-colororder"; + } +} +inline ColorOrder stringToColorOrder(const std::string & order) +{ + if (order == "rgb") + { + return ORDER_RGB; + } + else if (order == "bgr") + { + return ORDER_BGR; + } + else if (order == "rbg") + { + return ORDER_RBG; + } + else if (order == "brg") + { + return ORDER_BRG; + } + else if (order == "gbr") + { + return ORDER_GBR; + } + else if (order == "grb") + { + return ORDER_GRB; + } + + std::cout << "Unknown color order defined (" << order << "). Using RGB." << std::endl; + return ORDER_RGB; +} + /// /// The Led structure contains the definition of the image portion used to determine a single led's /// color. @@ -40,6 +97,8 @@ struct Led double minY_frac; /// The maximum horizontal scan line included for this leds color double maxY_frac; + /// the color order + ColorOrder colorOrder; }; /// diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index 5e76d8e8..d6657046 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -27,7 +27,7 @@ #include -Hyperion::ColorOrder Hyperion::createColorOrder(const Json::Value &deviceConfig) +ColorOrder Hyperion::createColorOrder(const Json::Value &deviceConfig) { // deprecated: force BGR when the deprecated flag is present and set to true if (deviceConfig.get("bgr-output", false).asBool()) @@ -187,14 +187,16 @@ RgbChannelTransform* Hyperion::createRgbChannelTransform(const Json::Value& colo return transform; } -LedString Hyperion::createLedString(const Json::Value& ledsConfig) +LedString Hyperion::createLedString(const Json::Value& ledsConfig, const ColorOrder deviceOrder) { LedString ledString; + const std::string deviceOrderStr = colorOrderToString(deviceOrder); for (const Json::Value& ledConfig : ledsConfig) { Led led; led.index = ledConfig["index"].asInt(); + const Json::Value& hscanConfig = ledConfig["hscan"]; const Json::Value& vscanConfig = ledConfig["vscan"]; led.minX_frac = std::max(0.0, std::min(1.0, hscanConfig["minimum"].asDouble())); @@ -212,6 +214,10 @@ LedString Hyperion::createLedString(const Json::Value& ledsConfig) std::swap(led.minY_frac, led.maxY_frac); } + // Get the order of the rgb channels for this led (default is device order) + const std::string ledOrderStr = ledConfig.get("colorOrder", deviceOrderStr).asString(); + led.colorOrder = stringToColorOrder(ledOrderStr); + ledString.leds().push_back(led); } @@ -262,10 +268,9 @@ LedDevice * Hyperion::createColorSmoothing(const Json::Value & smoothingConfig, Hyperion::Hyperion(const Json::Value &jsonConfig) : - _ledString(createLedString(jsonConfig["leds"])), + _ledString(createLedString(jsonConfig["leds"], createColorOrder(jsonConfig["device"]))), _muxer(_ledString.leds().size()), _raw2ledTransform(createLedColorsTransform(_ledString.leds().size(), jsonConfig["color"])), - _colorOrder(createColorOrder(jsonConfig["device"])), _device(LedDeviceFactory::construct(jsonConfig["device"])), _effectEngine(nullptr), _timer() @@ -429,10 +434,13 @@ void Hyperion::update() // Apply the transform to each led and color-channel std::vector ledColors = _raw2ledTransform->applyTransform(priorityInfo.ledColors); + const std::vector& leds = _ledString.leds(); + int i = 0; for (ColorRgb& color : ledColors) { + const ColorOrder ledColorOrder = leds.at(i).colorOrder; // correct the color byte order - switch (_colorOrder) + switch (ledColorOrder) { case ORDER_RGB: // leave as it is @@ -463,6 +471,7 @@ void Hyperion::update() break; } } + i++; } // Write the data to the device diff --git a/libsrc/hyperion/hyperion.schema.json b/libsrc/hyperion/hyperion.schema.json index 38192312..e459425b 100644 --- a/libsrc/hyperion/hyperion.schema.json +++ b/libsrc/hyperion/hyperion.schema.json @@ -195,6 +195,10 @@ } }, "additionalProperties" : false + }, + "colorOrder" : { + "type" : "string", + "required" : false } }, "additionalProperties" : false diff --git a/libsrc/leddevice/CMakeLists.txt b/libsrc/leddevice/CMakeLists.txt index 13df6080..06e13278 100755 --- a/libsrc/leddevice/CMakeLists.txt +++ b/libsrc/leddevice/CMakeLists.txt @@ -31,6 +31,7 @@ SET(Leddevice_HEADERS ${CURRENT_SOURCE_DIR}/LedDeviceTest.h ${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.h ${CURRENT_SOURCE_DIR}/LedDeviceTpm2.h + ${CURRENT_SOURCE_DIR}/LedDeviceAtmo.h ) SET(Leddevice_SOURCES @@ -49,6 +50,7 @@ SET(Leddevice_SOURCES ${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.cpp ${CURRENT_SOURCE_DIR}/LedDevicePhilipsHue.cpp ${CURRENT_SOURCE_DIR}/LedDeviceTpm2.cpp + ${CURRENT_SOURCE_DIR}/LedDeviceAtmo.cpp ) if(ENABLE_SPIDEV) diff --git a/libsrc/leddevice/LedDeviceAtmo.cpp b/libsrc/leddevice/LedDeviceAtmo.cpp new file mode 100644 index 00000000..dbcb48bd --- /dev/null +++ b/libsrc/leddevice/LedDeviceAtmo.cpp @@ -0,0 +1,38 @@ + +// STL includes +#include +#include + +// hyperion local includes +#include "LedDeviceAtmo.h" + +LedDeviceAtmo::LedDeviceAtmo(const std::string& outputDevice, const unsigned baudrate) : + LedRs232Device(outputDevice, baudrate), + _ledBuffer(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) +} + +int LedDeviceAtmo::write(const std::vector &ledValues) +{ + // The protocol is shomehow limited. we always need to send exactly 5 channels + header + // (19 bytes) for the hardware to recognize the data + if (ledValues.size() != 5) + { + std::cerr << "AtmoLight: " << ledValues.size() << " channels configured. This should always be 5!" << std::endl; + return 0; + } + + // write data + memcpy(4 + _ledBuffer.data(), ledValues.data(), ledValues.size() * sizeof(ColorRgb)); + return writeBytes(_ledBuffer.size(), _ledBuffer.data()); +} + +int LedDeviceAtmo::switchOff() +{ + memset(4 + _ledBuffer.data(), 0, _ledBuffer.size() - 4); + return writeBytes(_ledBuffer.size(), _ledBuffer.data()); +} diff --git a/libsrc/leddevice/LedDeviceAtmo.h b/libsrc/leddevice/LedDeviceAtmo.h new file mode 100644 index 00000000..f6bf4a44 --- /dev/null +++ b/libsrc/leddevice/LedDeviceAtmo.h @@ -0,0 +1,38 @@ +#pragma once + +// STL includes +#include + +// hyperion incluse +#include "LedRs232Device.h" + +/// +/// Implementation of the LedDevice interface for writing to serial device using tpm2 protocol. +/// +class LedDeviceAtmo : public LedRs232Device +{ +public: + /// + /// Constructs the LedDevice for attached serial device using supporting tpm2 protocol + /// All LEDs in the stripe are handled as one frame + /// + /// @param outputDevice The name of the output device (eg '/dev/ttyAMA0') + /// @param baudrate The used baudrate for writing to the output device + /// + LedDeviceAtmo(const std::string& outputDevice, const unsigned baudrate); + + /// + /// 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); + + /// Switch the leds off + virtual int switchOff(); + +private: + /// The buffer containing the packed RGB values + std::vector _ledBuffer; +}; diff --git a/libsrc/leddevice/LedDeviceFactory.cpp b/libsrc/leddevice/LedDeviceFactory.cpp index a7f78319..a3e49a4a 100755 --- a/libsrc/leddevice/LedDeviceFactory.cpp +++ b/libsrc/leddevice/LedDeviceFactory.cpp @@ -32,6 +32,7 @@ #include "LedDeviceHyperionUsbasp.h" #include "LedDevicePhilipsHue.h" #include "LedDeviceTpm2.h" +#include "LedDeviceAtmo.h" #ifdef ENABLE_WS2812BPWM #include "LedDeviceWS2812b.h" @@ -211,6 +212,15 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig) deviceTpm2->open(); device = deviceTpm2; } + else if (type == "atmo") + { + const std::string output = deviceConfig["output"].asString(); + const unsigned rate = 38400; + + LedDeviceAtmo * deviceAtmo = new LedDeviceAtmo(output, rate); + deviceAtmo->open(); + device = deviceAtmo; + } #ifdef ENABLE_WS2812BPWM else if (type == "ws2812b") { diff --git a/libsrc/leddevice/LedDevicePiBlaster.cpp b/libsrc/leddevice/LedDevicePiBlaster.cpp index 6bdcf726..7271931e 100644 --- a/libsrc/leddevice/LedDevicePiBlaster.cpp +++ b/libsrc/leddevice/LedDevicePiBlaster.cpp @@ -80,11 +80,13 @@ int LedDevicePiBlaster::write(const std::vector & ledValues) return -1; } + std::vector iPins = {4, 17, 18, 27, 21, 22, 23, 24, 25}; + unsigned colorIdx = 0; - for (unsigned iChannel=0; iChannel<8; ++iChannel) + for (std::vector::iterator it = iPins.begin(); it != iPins.end(); ++it) { double pwmDutyCycle = 0.0; - switch (_channelAssignment[iChannel]) + switch (_channelAssignment[*it]) { case 'r': pwmDutyCycle = ledValues[colorIdx].red / 255.0; @@ -102,7 +104,7 @@ int LedDevicePiBlaster::write(const std::vector & ledValues) continue; } - fprintf(_fid, "%i=%f\n", iChannel, pwmDutyCycle); +// fprintf(_fid, "%i=%f\n", iChannel, pwmDutyCycle); fflush(_fid); } @@ -117,11 +119,13 @@ int LedDevicePiBlaster::switchOff() return -1; } - for (unsigned iChannel=0; iChannel<8; ++iChannel) + std::vector iPins = {4, 17, 18, 21, 22, 23, 24, 25}; + + for (std::vector::iterator it = iPins.begin(); it != iPins.end(); ++it) { - if (_channelAssignment[iChannel] != ' ') + if (_channelAssignment[*it] != ' ') { - fprintf(_fid, "%i=%f\n", iChannel, 0.0); + fprintf(_fid, "%i=%f\n", *it, 0.0); fflush(_fid); } } diff --git a/test/TestImage2LedsMap.cpp b/test/TestImage2LedsMap.cpp index 5def8632..b3ba4242 100644 --- a/test/TestImage2LedsMap.cpp +++ b/test/TestImage2LedsMap.cpp @@ -23,7 +23,7 @@ int main() return -1; } - const LedString ledString = Hyperion::createLedString(config["leds"]); + const LedString ledString = Hyperion::createLedString(config["leds"], Hyperion::createColorOrder(config["device"])); const ColorRgb testColor = {64, 123, 12};