diff --git a/CHANGELOG.md b/CHANGELOG.md index 2da80f3b5..72668be8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### ✨ Added ---- +- Support of RGBW in **e1.31** led devices. ### 🔧 Changed diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json index 8e24e7bbe..1a0f73850 100644 --- a/assets/webconfig/i18n/en.json +++ b/assets/webconfig/i18n/en.json @@ -688,6 +688,7 @@ "edt_dev_spec_devices_discovery_inprogress": "Discovery in progress", "edt_dev_spec_dithering_title": "Dithering", "edt_dev_spec_dmaNumber_title": "DMA channel", + "edt_dev_spec_dmx_max_title": "DMX maximal number of channels", "edt_dev_spec_fullBrightnessAtStart_title": "Full brightness at start", "edt_dev_spec_gamma_title": "Gamma", "edt_dev_spec_globalBrightnessControlMaxLevel_title": "Max Current Level", diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp b/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp index 1be48dc3e..f27cbc831 100644 --- a/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp +++ b/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp @@ -39,6 +39,7 @@ const int DMX_MAX = 512; // 512 usable slots LedDeviceUdpE131::LedDeviceUdpE131(const QJsonObject &deviceConfig) : ProviderUdp(deviceConfig) + , _whiteAlgorithm(RGBW::WhiteAlgorithm::INVALID) { } @@ -58,9 +59,21 @@ bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig) _port = deviceConfig[CONFIG_PORT].toInt(E131_DEFAULT_PORT); _e131_universe = deviceConfig["universe"].toInt(1); + _e131_dmx_max = deviceConfig["dmx-max"].toInt(DMX_MAX); _e131_source_name = deviceConfig["source-name"].toString("hyperion on "+QHostInfo::localHostName()); QString _json_cid = deviceConfig["cid"].toString(""); + // Initialize white algorithm + QString whiteAlgorithmStr = deviceConfig["whiteAlgorithm"].toString("white_off"); + _whiteAlgorithm = RGBW::stringToWhiteAlgorithm(whiteAlgorithmStr); + if (_whiteAlgorithm == RGBW::WhiteAlgorithm::INVALID) + { + QString errortext = QString("unknown whiteAlgorithm: %1").arg(whiteAlgorithmStr); + this->setInError(errortext); + return false; + } + Debug(_log, "whiteAlgorithm : %s", QSTRING_CSTR(whiteAlgorithmStr)); + if (_json_cid.isEmpty()) { _e131_cid = QUuid::createUuid(); @@ -138,35 +151,57 @@ void LedDeviceUdpE131::prepare(unsigned this_universe, unsigned this_dmxChannelC int LedDeviceUdpE131::write(const std::vector &ledValues) { - int retVal = 0; + int retVal = 0; int thisChannelCount = 0; - int dmxChannelCount = _ledRGBCount; - const uint8_t * rawdata = reinterpret_cast(ledValues.data()); + int dmxChannelCount = (_whiteAlgorithm == RGBW::WhiteAlgorithm::WHITE_OFF) ? _ledRGBCount : _ledRGBWCount; // if white_off we expect 3 channels per LED otherwise 4 + + // Create a temporary buffer for RGB or RGBW data + std::vector tempBuffer(dmxChannelCount); + uint8_t* rawDataPtr = tempBuffer.data(); + + int currentChannel = 0; + for (const ColorRgb& color : ledValues) + { + if (_whiteAlgorithm == RGBW::WhiteAlgorithm::WHITE_OFF) + { + rawDataPtr[currentChannel++] = color.red; + rawDataPtr[currentChannel++] = color.green; + rawDataPtr[currentChannel++] = color.blue; + } + else + { + RGBW::Rgb_to_Rgbw(color, &_temp_rgbw, _whiteAlgorithm); + rawDataPtr[currentChannel++] = _temp_rgbw.red; + rawDataPtr[currentChannel++] = _temp_rgbw.green; + rawDataPtr[currentChannel++] = _temp_rgbw.blue; + rawDataPtr[currentChannel++] = _temp_rgbw.white; + } + } _e131_seq++; for (int rawIdx = 0; rawIdx < dmxChannelCount; rawIdx++) { - if (rawIdx % DMX_MAX == 0) // start of new packet + if (rawIdx % _e131_dmx_max == 0) // start of new packet { - thisChannelCount = (dmxChannelCount - rawIdx < DMX_MAX) ? dmxChannelCount % DMX_MAX : DMX_MAX; -// is this the last packet? ? ^^ last packet : ^^ earlier packets + thisChannelCount = (dmxChannelCount - rawIdx < _e131_dmx_max) ? dmxChannelCount % _e131_dmx_max : _e131_dmx_max; + // is this the last packet? ? ^^ last packet : ^^ earlier packets - prepare(_e131_universe + rawIdx / DMX_MAX, thisChannelCount); + prepare(_e131_universe + rawIdx / _e131_dmx_max, thisChannelCount); e131_packet.sequence_number = _e131_seq; } - e131_packet.property_values[1 + rawIdx%DMX_MAX] = rawdata[rawIdx]; + e131_packet.property_values[1 + rawIdx % _e131_dmx_max] = rawDataPtr[rawIdx]; -// is this the last byte of last packet || last byte of other packets - if ( (rawIdx == dmxChannelCount-1) || (rawIdx %DMX_MAX == DMX_MAX-1) ) + // is this the last byte of last packet || last byte of other packets + if ((rawIdx == dmxChannelCount - 1) || (rawIdx % _e131_dmx_max == _e131_dmx_max - 1)) { #undef e131debug #if e131debug Debug (_log, "send packet: rawidx %d dmxchannelcount %d universe: %d, packetsz %d" , rawIdx , dmxChannelCount - , _e131_universe + rawIdx / DMX_MAX + , _e131_universe + rawIdx / _e131_dmx_max , E131_DMP_DATA + 1 + thisChannelCount ); #endif diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpE131.h b/libsrc/leddevice/dev_net/LedDeviceUdpE131.h index 0397eeda7..899eac57f 100644 --- a/libsrc/leddevice/dev_net/LedDeviceUdpE131.h +++ b/libsrc/leddevice/dev_net/LedDeviceUdpE131.h @@ -3,6 +3,8 @@ // hyperion includes #include "ProviderUdp.h" +#include "utils/ColorRgbw.h" +#include "utils/RgbToRgbw.h" #include @@ -139,9 +141,14 @@ class LedDeviceUdpE131 : public ProviderUdp e131_packet_t e131_packet; uint8_t _e131_seq = 0; uint8_t _e131_universe = 1; + int _e131_dmx_max = 512; uint8_t _acn_id[12] = {0x41, 0x53, 0x43, 0x2d, 0x45, 0x31, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00 }; QString _e131_source_name; QUuid _e131_cid; + + // RGBW specific members + RGBW::WhiteAlgorithm _whiteAlgorithm; + ColorRgbw _temp_rgbw; }; #endif // LEDEVICEUDPE131_H diff --git a/libsrc/leddevice/schemas/schema-e131.json b/libsrc/leddevice/schemas/schema-e131.json index 027407272..a6637470a 100644 --- a/libsrc/leddevice/schemas/schema-e131.json +++ b/libsrc/leddevice/schemas/schema-e131.json @@ -22,6 +22,12 @@ "default": 1, "propertyOrder": 3 }, + "dmx-max": { + "type": "integer", + "title": "edt_dev_spec_dmx_max_title", + "default": 512, + "propertyOrder": 4 + }, "latchTime": { "type": "integer", "title": "edt_dev_spec_latchtime_title", @@ -30,12 +36,43 @@ "minimum": 0, "maximum": 1000, "access": "expert", - "propertyOrder": 4 + "propertyOrder": 5 }, "cid": { "type": "string", "title": "edt_dev_spec_cid_title", - "propertyOrder": 5 + "propertyOrder": 6 + }, + + "whiteAlgorithm": { + "type": "string", + "title":"edt_dev_spec_whiteLedAlgor_title", + "enum" : [ + "subtract_minimum", + "sub_min_cool_adjust", + "sub_min_warm_adjust", + "cold_white", + "neutral_white", + "auto", + "auto_max", + "auto_accurate", + "white_off" + ], + "default": "white_off", + "options" : { + "enum_titles" : [ + "edt_dev_enum_subtract_minimum", + "edt_dev_enum_sub_min_cool_adjust", + "edt_dev_enum_sub_min_warm_adjust", + "edt_dev_enum_cold_white", + "edt_dev_enum_neutral_white", + "edt_dev_enum_auto", + "edt_dev_enum_auto_max", + "edt_dev_enum_auto_accurate", + "edt_dev_enum_white_off" + ] + }, + "propertyOrder" : 7 } }, "additionalProperties": true