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'];
|
devRPiSPI = ['apa102', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'ws2812spi'];
|
||||||
devRPiPWM = ['ws281x'];
|
devRPiPWM = ['ws281x'];
|
||||||
devRPiGPIO = ['piblaster'];
|
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'];
|
devUSB = ['adalight', 'dmx', 'atmo', 'hyperionusbasp', 'lightpack', 'multilightpack', 'paintpack', 'rawhid', 'sedu', 'tpm2'];
|
||||||
|
|
||||||
var optArr = [[]];
|
var optArr = [[]];
|
||||||
|
@ -37,6 +37,7 @@ SET(Leddevice_HEADERS
|
|||||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpRaw.h
|
${CURRENT_SOURCE_DIR}/LedDeviceUdpRaw.h
|
||||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpH801.h
|
${CURRENT_SOURCE_DIR}/LedDeviceUdpH801.h
|
||||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpE131.h
|
${CURRENT_SOURCE_DIR}/LedDeviceUdpE131.h
|
||||||
|
${CURRENT_SOURCE_DIR}/LedDeviceUdpArtNet.h
|
||||||
${CURRENT_SOURCE_DIR}/ProviderUdp.h
|
${CURRENT_SOURCE_DIR}/ProviderUdp.h
|
||||||
${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.h
|
${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.h
|
||||||
${CURRENT_SOURCE_DIR}/LedDeviceTpm2.h
|
${CURRENT_SOURCE_DIR}/LedDeviceTpm2.h
|
||||||
@ -65,6 +66,7 @@ SET(Leddevice_SOURCES
|
|||||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpRaw.cpp
|
${CURRENT_SOURCE_DIR}/LedDeviceUdpRaw.cpp
|
||||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpH801.cpp
|
${CURRENT_SOURCE_DIR}/LedDeviceUdpH801.cpp
|
||||||
${CURRENT_SOURCE_DIR}/LedDeviceUdpE131.cpp
|
${CURRENT_SOURCE_DIR}/LedDeviceUdpE131.cpp
|
||||||
|
${CURRENT_SOURCE_DIR}/LedDeviceUdpArtNet.cpp
|
||||||
${CURRENT_SOURCE_DIR}/ProviderUdp.cpp
|
${CURRENT_SOURCE_DIR}/ProviderUdp.cpp
|
||||||
${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.cpp
|
${CURRENT_SOURCE_DIR}/LedDeviceHyperionUsbasp.cpp
|
||||||
${CURRENT_SOURCE_DIR}/LedDevicePhilipsHue.cpp
|
${CURRENT_SOURCE_DIR}/LedDevicePhilipsHue.cpp
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "LedDeviceTpm2net.h"
|
#include "LedDeviceTpm2net.h"
|
||||||
#include "LedDeviceUdpRaw.h"
|
#include "LedDeviceUdpRaw.h"
|
||||||
#include "LedDeviceUdpE131.h"
|
#include "LedDeviceUdpE131.h"
|
||||||
|
#include "LedDeviceUdpArtNet.h"
|
||||||
#include "LedDeviceHyperionUsbasp.h"
|
#include "LedDeviceHyperionUsbasp.h"
|
||||||
#include "LedDevicePhilipsHue.h"
|
#include "LedDevicePhilipsHue.h"
|
||||||
#include "LedDeviceTpm2.h"
|
#include "LedDeviceTpm2.h"
|
||||||
@ -91,6 +92,7 @@ LedDevice * LedDeviceFactory::construct(const QJsonObject & deviceConfig, const
|
|||||||
REGISTER(Tpm2net);
|
REGISTER(Tpm2net);
|
||||||
REGISTER(UdpRaw);
|
REGISTER(UdpRaw);
|
||||||
REGISTER(UdpE131);
|
REGISTER(UdpE131);
|
||||||
|
REGISTER(UdpArtNet);
|
||||||
REGISTER(UdpH801);
|
REGISTER(UdpH801);
|
||||||
REGISTER(PhilipsHue);
|
REGISTER(PhilipsHue);
|
||||||
REGISTER(AtmoOrb);
|
REGISTER(AtmoOrb);
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
<file alias="schema-tpm2net">schemas/schema-tpm2net.json</file>
|
<file alias="schema-tpm2net">schemas/schema-tpm2net.json</file>
|
||||||
<file alias="schema-tpm2">schemas/schema-tpm2.json</file>
|
<file alias="schema-tpm2">schemas/schema-tpm2.json</file>
|
||||||
<file alias="schema-udpe131">schemas/schema-e131.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-udph801">schemas/schema-h801.json</file>
|
||||||
<file alias="schema-udpraw">schemas/schema-udpraw.json</file>
|
<file alias="schema-udpraw">schemas/schema-udpraw.json</file>
|
||||||
<file alias="schema-ws2801">schemas/schema-ws2801.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…
x
Reference in New Issue
Block a user