mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Artnet (#440)
* Started implementing artnet/DMX support It compiles, but certainly wont work just yet * Fix up packet data and length correct default udp port The data looks ok in wireshark * Code cleanup Sequence runs from 1..255 not 0 fix universe > 255 * code cleanups and force even number of channels * Fix potential endianness issue * added support for 'x' channels per fixture with zero padding its very basic support for now - it needs better multi universe support
This commit is contained in:
parent
564d4578d3
commit
64fc6a9003
@ -474,7 +474,7 @@ $(document).ready(function() {
|
||||
devRPiSPI = ['apa102', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'ws2812spi'];
|
||||
devRPiPWM = ['ws281x'];
|
||||
devRPiGPIO = ['piblaster'];
|
||||
devNET = ['atmoorb', 'fadecandy', 'philipshue', 'tinkerforge', 'tpm2net', 'udpe131', 'udph801', 'udpraw'];
|
||||
devNET = ['atmoorb', 'fadecandy', 'philipshue', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udph801', 'udpraw'];
|
||||
devUSB = ['adalight', 'dmx', 'atmo', 'hyperionusbasp', 'lightpack', 'multilightpack', 'paintpack', 'rawhid', 'sedu', 'tpm2'];
|
||||
|
||||
var optArr = [[]];
|
||||
|
@ -37,6 +37,7 @@ SET(Leddevice_HEADERS
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpRaw.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpH801.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpE131.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpArtNet.h
|
||||
${CURRENT_SOURCE_DIR}/ProviderUdp.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceTpm2.h
|
||||
@ -65,6 +66,7 @@ SET(Leddevice_SOURCES
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpRaw.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpH801.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpE131.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpArtNet.cpp
|
||||
${CURRENT_SOURCE_DIR}/ProviderUdp.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedDevicePhilipsHue.cpp
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "LedDeviceTpm2net.h"
|
||||
#include "LedDeviceUdpRaw.h"
|
||||
#include "LedDeviceUdpE131.h"
|
||||
#include "LedDeviceUdpArtNet.h"
|
||||
#include "LedDeviceHyperionUsbasp.h"
|
||||
#include "LedDevicePhilipsHue.h"
|
||||
#include "LedDeviceTpm2.h"
|
||||
@ -91,6 +92,7 @@ LedDevice * LedDeviceFactory::construct(const QJsonObject & deviceConfig, const
|
||||
REGISTER(Tpm2net);
|
||||
REGISTER(UdpRaw);
|
||||
REGISTER(UdpE131);
|
||||
REGISTER(UdpArtNet);
|
||||
REGISTER(UdpH801);
|
||||
REGISTER(PhilipsHue);
|
||||
REGISTER(AtmoOrb);
|
||||
|
@ -24,6 +24,7 @@
|
||||
<file alias="schema-tpm2net">schemas/schema-tpm2net.json</file>
|
||||
<file alias="schema-tpm2">schemas/schema-tpm2.json</file>
|
||||
<file alias="schema-udpe131">schemas/schema-e131.json</file>
|
||||
<file alias="schema-udpartnet">schemas/schema-artnet.json</file>
|
||||
<file alias="schema-udph801">schemas/schema-h801.json</file>
|
||||
<file alias="schema-udpraw">schemas/schema-udpraw.json</file>
|
||||
<file alias="schema-ws2801">schemas/schema-ws2801.json</file>
|
||||
|
93
libsrc/leddevice/LedDeviceUdpArtNet.cpp
Normal file
93
libsrc/leddevice/LedDeviceUdpArtNet.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <QHostInfo>
|
||||
|
||||
// hyperion local includes
|
||||
#include "LedDeviceUdpArtNet.h"
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
LedDevice* LedDeviceUdpArtNet::construct(const QJsonObject &deviceConfig)
|
||||
{
|
||||
return new LedDeviceUdpArtNet(deviceConfig);
|
||||
}
|
||||
|
||||
|
||||
// populates the headers
|
||||
void LedDeviceUdpArtNet::prepare(const unsigned this_universe, const unsigned this_sequence, unsigned this_dmxChannelCount)
|
||||
{
|
||||
// WTF? why do the specs say:
|
||||
// "This value should be an even number in the range 2 – 512. "
|
||||
if (this_dmxChannelCount & 0x1)
|
||||
{
|
||||
this_dmxChannelCount++;
|
||||
}
|
||||
|
||||
memcpy (artnet_packet.ID, "Art-Net\0", 8);
|
||||
|
||||
artnet_packet.OpCode = htons(0x0050); // OpOutput / OpDmx
|
||||
artnet_packet.ProtVer = htons(0x000e);
|
||||
artnet_packet.Sequence = this_sequence;
|
||||
artnet_packet.Physical = 0;
|
||||
artnet_packet.SubUni = this_universe & 0xff ;
|
||||
artnet_packet.Net = (this_universe >> 8) & 0x7f;
|
||||
artnet_packet.Length = htons(this_dmxChannelCount);
|
||||
|
||||
}
|
||||
|
||||
int LedDeviceUdpArtNet::write(const std::vector<ColorRgb> &ledValues)
|
||||
{
|
||||
int retVal = 0;
|
||||
int thisUniverse = _artnet_universe;
|
||||
const uint8_t * rawdata = reinterpret_cast<const uint8_t *>(ledValues.data());
|
||||
|
||||
/*
|
||||
This field is incremented in the range 0x01 to 0xff to allow the receiving node to resequence packets.
|
||||
The Sequence field is set to 0x00 to disable this feature.
|
||||
*/
|
||||
if (_artnet_seq++ == 0)
|
||||
{
|
||||
_artnet_seq = 1;
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
|
||||
artnet_packet.Data[dmxIdx++] = rawdata[ledIdx];
|
||||
if ( (ledIdx % 3 == 2) && (ledIdx > 0) )
|
||||
{
|
||||
dmxIdx += (_artnet_channelsPerFixture-3);
|
||||
}
|
||||
|
||||
// is this the last byte of last packet || last byte of other packets
|
||||
if ( (ledIdx == _ledRGBCount-1) || (dmxIdx >= DMX_MAX) )
|
||||
{
|
||||
prepare(thisUniverse, _artnet_seq, dmxIdx);
|
||||
retVal &= writeBytes(18 + std::min(dmxIdx, DMX_MAX), artnet_packet.raw);
|
||||
|
||||
memset(artnet_packet.raw, 0, sizeof(artnet_packet.raw));
|
||||
thisUniverse ++;
|
||||
dmxIdx = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
79
libsrc/leddevice/LedDeviceUdpArtNet.h
Normal file
79
libsrc/leddevice/LedDeviceUdpArtNet.h
Normal file
@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
// hyperion includes
|
||||
#include "ProviderUdp.h"
|
||||
|
||||
#include <QUuid>
|
||||
|
||||
/**
|
||||
*
|
||||
* This program is provided free for you to use in any way that you wish,
|
||||
* subject to the laws and regulations where you are using it. Due diligence
|
||||
* is strongly suggested before using this code. Please give credit where due.
|
||||
*
|
||||
**/
|
||||
|
||||
#define ArtNet_DEFAULT_PORT 5568
|
||||
|
||||
#define DMX_MAX 512 // 512 usable slots
|
||||
|
||||
// http://stackoverflow.com/questions/16396013/artnet-packet-structure
|
||||
typedef union
|
||||
{
|
||||
struct {
|
||||
char ID[8]; // "Art-Net"
|
||||
uint16_t OpCode; // See Doc. Table 1 - OpCodes eg. 0x5000 OpOutput / OpDmx
|
||||
uint16_t ProtVer; // 0x0e00 (aka 14)
|
||||
uint8_t Sequence; // monotonic counter
|
||||
uint8_t Physical; // 0x00
|
||||
uint8_t SubUni; // low universe (0-255)
|
||||
uint8_t Net; // high universe (not used)
|
||||
uint16_t Length; // data length (2 - 512)
|
||||
uint8_t Data[ DMX_MAX ]; // universe data
|
||||
} __attribute__((packed));
|
||||
|
||||
uint8_t raw[ 18 + DMX_MAX ];
|
||||
|
||||
} artnet_packet_t;
|
||||
|
||||
///
|
||||
/// Implementation of the LedDevice interface for sending led colors via udp/E1.31 packets
|
||||
///
|
||||
class LedDeviceUdpArtNet : public ProviderUdp
|
||||
{
|
||||
public:
|
||||
///
|
||||
/// Constructs specific LedDevice
|
||||
///
|
||||
/// @param deviceConfig json device config
|
||||
///
|
||||
LedDeviceUdpArtNet(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);
|
||||
|
||||
|
||||
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<ColorRgb> &ledValues);
|
||||
|
||||
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;
|
||||
};
|
42
libsrc/leddevice/schemas/schema-artnet.json
Normal file
42
libsrc/leddevice/schemas/schema-artnet.json
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"type":"object",
|
||||
"required":true,
|
||||
"properties":{
|
||||
"host" : {
|
||||
"type": "string",
|
||||
"title":"edt_dev_spec_targetIp_title",
|
||||
"propertyOrder" : 1
|
||||
},
|
||||
"port" : {
|
||||
"type": "integer",
|
||||
"title":"edt_dev_spec_port_title",
|
||||
"default": 6454,
|
||||
"minimum" : 0,
|
||||
"maximum" : 65535,
|
||||
"propertyOrder" : 2
|
||||
},
|
||||
"universe": {
|
||||
"type": "integer",
|
||||
"title":"edt_dev_spec_universe_title",
|
||||
"default": 1,
|
||||
"propertyOrder" : 3
|
||||
},
|
||||
"channelsPerFixture": {
|
||||
"type": "integer",
|
||||
"title":"edt_dev_spec_chanperfixture_title",
|
||||
"default": 3,
|
||||
"propertyOrder" : 4
|
||||
},
|
||||
"latchTime": {
|
||||
"type": "integer",
|
||||
"title":"edt_dev_spec_latchtime_title",
|
||||
"default": 1,
|
||||
"append" : "edt_append_ms",
|
||||
"minimum": 1,
|
||||
"maximum": 1000,
|
||||
"access" : "expert",
|
||||
"propertyOrder" : 5
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
Loading…
Reference in New Issue
Block a user