1
0
Fork 0
OpenLCP/protocol/artnet/artnet.h

562 lines
22 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
artnet.h
Copyright (c) 2022 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <cstdint>
/**
* @brief \cite ARTNET Art-Net is an Ethernet protocol based on the TCP/IP protocol
* suite.
*
* Its purpose is to allow transfer of large amounts of DMX512 data
* over a wide area using standard networking technology.
*/
namespace ARTNET {
/// @brief \cite ARTNET Universe Addressing
///
/// > The Port-Address of each DMX512 Universe is encoded as a 15-bit number
struct PortAddress {
/**
* @brief PortAddress
* @param v
*/
PortAddress(uint16_t v = 0) : value(v) {};
/**
* @brief PortAddress
* @param n
* @param s
*/
PortAddress(uint8_t n, uint8_t s) : subuni(s), net(n) {}
union {
uint16_t value;
struct {
union {
uint8_t subuni;
struct {
uint8_t universe : 4; //!< A single DMX512 frame of 512 channels is referred to as a Universe.
uint8_t subnet : 4; //!< A group of 16 consecutive universes is referred to as a sub-net.
};
};
union{
uint8_t _net;
struct {
uint8_t net : 7; //!< A group of 16 consecutive Sub-Nets or 256 consecutive Universes is referred to as a net. There are 128 Nets in total.
bool reserved : 1;
};
};
};
};
};
/// @brief \cite ARTNET Protocol Operation
///
/// > The UDP port used as both source and destination is 0x1936.
static const uint16_t UDP_PORT = 6454;
/// @brief Packet ID
///
/// > Array of 8 characters, the final character is a null termination.
/// > Value = A r t - N e t 0x00
static const uint8_t PACKET_IDENTIFIER[] = { 0x41, 0x72, 0x74, 0x2D,
0x4E, 0x65, 0x74, 0x00};
/// @brief \cite ARTNET Art-Net protocol revision number.
///
/// Current value 14. Controllers should ignore communication with nodes
/// using a protocol version lower than 14.
static const uint16_t VERSION = 14;
/// @brief \cite ARTNET Table 1 - OpCodes
///
/// The OpCode defines the class of data following within the UDP packet.
/// The following table details the legal OpCode values used in Art-Net packets
enum OpCode : uint16_t {
OpNull = 0x0000, //!< no-op. Ignore this packet.
OpPoll = 0x2000, //!< an ArtPoll packet, no other data is contained in this UDP packet.
OpPollReply = 0x2100, //!< an ArtPollReply Packet. It contains device status information.
OpDiagData = 0x2300, //!< Diagnostics and data logging packet.
OpCommand = 0x2400, //!< Used to send text based parameter commands.
// OpOutput = 0x5000, //!< an ArtDmx data packet. It contains zero start code DMX512 information for a single Universe.
OpDmx = 0x5000, //!< an ArtDmx data packet. It contains zero start code DMX512 information for a single Universe.
OpNzs = 0x5100, //!< an ArtNzs data packet. It contains non-zero start code (except RDM) DMX512 information for a single Universe.
OpSync = 0x5200, //!< an ArtSync data packet. It is used to force synchronous transfer of ArtDmx packets to a nodes output.
OpAddress = 0x6000, //!< an ArtAddress packet. It contains remote programming information for a Node.
OpInput = 0x7000, //!< an ArtInput packet. It contains enable disable data for DMX inputs.
OpTodRequest = 0x8000, //!< an ArtTodRequest packet. It is used to request a Table of Devices (ToD) for RDM discovery.
OpTodData = 0x8100, //!< an ArtTodData packet. It is used to send a Table of Devices (ToD) for RDM discovery.
OpTodControl = 0x8200, //!< an ArtTodControl packet. It is used to send RDM discovery control messages.
OpRdm = 0x8300, //!< an ArtRdm packet. It is used to send all non discovery RDM messages.
OpRdmSub = 0x8400, //!< an ArtRdmSub packet. It is used to send compressed, RDM Sub-Device data.
OpVideoSetup = 0xA010, //!< an ArtVideoSetup packet. It contains video screen setup information for nodes that implement the extended video features.
OpVideoPalette = 0xA020, //!< an ArtVideoPalette packet. It contains colour palette setup information for nodes that implement the extended video features.
OpVideoData = 0xA040, //!< an ArtVideoData packet. It contains display data for nodes that implement the extended video features.
OpMacMaster = 0xF000, //!< depreciated
OpMacSlave = 0xF100, //!< depreciated
OpFirmwareMaster = 0xF200, //!< an ArtFirmwareMaster packet. It is used to upload new firmware or firmware extensions to the Node.
OpFirmwareReply = 0xF300, //!< an ArtFirmwareReply packet. It is returned by the node to acknowledge receipt of an ArtFirmwareMaster packet or ArtFileTnMaster packet.
OpFileTnMaster = 0xF400, //!< Uploads user file to node.
OpFileFnMaster = 0xF500, //!< Downloads user file from node.
OpFileFnReply = 0xF600, //!< Server to Node acknowledge for download packets.
OpIpProg = 0xF800, //!< an ArtIpProg packet. It is used to re- programme the IP, Mask and Port address of the Node.
OpIpProgReply = 0xF900, //!< an ArtIpProgReply packet. It is returned by the node to acknowledge receipt of an ArtIpProg packet.
OpMedia = 0x9000, //!< an ArtMedia packet. It is Unicast by a Media Server and acted upon by a Controller.
OpMediaPatch = 0x9100, //!< an ArtMediaPatch packet. It is Unicast by a Controller and acted upon by a Media Server.
OpMediaControl = 0x9200, //!< an ArtMediaControl packet. It is Unicast by a Controller and acted upon by a Media Server.
OpMediaContrlReply = 0x9300, //!< an ArtMediaControlReply packet. It is Unicast by a Media Server and acted upon by a Controller.
OpTimeCode = 0x9700, //!< an ArtTimeCode packet. It is used to transport time code over the network.
OpTimeSync = 0x9800, //!< Used to synchronise real time date and clock
OpTrigger = 0x9900, //!< Used to send trigger macros
OpDirectory = 0x9A00, //!< Requests a node's file list
OpDirectoryReply = 0x9B00 //!< Replies to OpDirectory with file list
};
/// OEM is unknown or non-registered type
static const uint16_t oem_unknown = 0x00ff;
/// Used by ArtTrigger for general purpose codes
static const uint16_t oem_gobal = 0xffff;
/// @brief \cite ARTNET Table 3 - NodeReport Codes
enum NodeReport : uint16_t {
RcDebug = 0x0000, //!< Booted in debug mode (Only used in development)
RcPowerOk = 0x0001, //!< Power On Tests successful
RcPowerFail = 0x0002, //!< Hardware tests failed at Power On
RcSocketWr1 = 0x0003, //!< Last UDP from Node failed due to truncated length, Most likely caused by a collision.
RcParseFail = 0x0004, //!< Unable to identify last UDP transmission. Check OpCode and packet length.
RcUdpFail = 0x0005, //!< Unable to open Udp Socket in last transmission attempt
RcShNameOk = 0x0006, //!< Confirms that Short Name programming via ArtAddress, was successful.
RcLoNameOk = 0x0007, //!< Confirms that Long Name programming via ArtAddress, was successful.
RcDmxError = 0x0008, //!< DMX512 receive errors detected.
RcDmxUdpFull = 0x0009, //!< Ran out of internal DMX transmit buffers.
RcDmxRxFull = 0x000A, //!< Ran out of internal DMX Rx buffers.
RcSwitchErr = 0x000B, //!< Rx Universe switches conflict.
RcConfigErr = 0x000C, //!< Product configuration does not match firmware.
RcDmxShort = 0x000D, //!< DMX output short detected. See GoodOutput field.
RcFirmwareFail = 0x000E, //!< Last attempt to upload new firmware failed.
RcUserFail = 0x000F, //!< User changed switch settings when address locked by remote programming. User changes ignored.
RcFactoryRes = 0x0010 //!< Factory reset has occurred.
};
/// \cite ARTNET Table 4 - Style Codes
enum Style : uint8_t {
StNode = 0x00, //!< A DMX to / from Art-Net device
StController = 0x01, //!< A lighting console.
StMedia = 0x02, //!< A Media Server.
StRoute = 0x03, //!< A network routing device.
StBackup = 0x04, //!< A backup device.
StConfig = 0x05, //!< A configuration or diagnostic tool
StVisual = 0x06 //!< A visualiser
};
/// \cite ARTNET Table 5 - Priority Codes
enum Priority : uint8_t {
DpLow = 0x10, //!< Low priority message.
DpMed = 0x40, //!< Medium priority message.
DpHigh = 0x80, //!< High priority message.
DpCritial = 0xE0, //!< Critical priority message.
DpVolatile = 0xF0 //!< Volatile message.
};
/// Set the communication behavior during ArtPoll
struct TalkToMe {
union {
uint8_t _raw = 0;
struct {
bool depreciated : 1;
bool reply_on_change : 1; //!< Send ArtPollReply whenever Node conditions change.
bool diag_enable : 1; //!< Send me diagnostics messages.
bool diag_unicast : 1; //!< Diagnostics messages are unicast. (if bit 2).
bool VLC_disable : 1; //!< Disable VLC transmission.
uint8_t reserved : 3;
};
};
};
/**
* @brief The OEM word
*
* Describes the equipment vendor and the feature set available.
* Bit 15 high indicates extended features available.
*/
struct OEM {
/**
* @brief OEM
* @param value
*/
OEM(uint16_t value = oem_unknown) : word(value) {}
union {
uint16_t word;
struct {
uint16_t manufacturer : 15;
bool extended_features : 1;
};
};
};
/**
* @brief The Authority enum
*/
enum Authority : uint8_t {
AuthorityUnkown = 0b00, //!< Port-Address Programming Authority unknown.
AuthorityLocal = 0b01, //!< Port-Address set by front panel controls.
AuthorityRemote = 0b10, //!< All or part of Port-Address programmed by network
AuthorityUnused = 0b11, //!< not used
};
/**
* @brief The Indicator enum
*/
enum Indicator : uint8_t {
IndicatorUnknown = 0b00, //!< Indicator state unknown.
IndicatorIdentify = 0b01, //!< Indicators in Locate / Identify Mode.
IndicatorMute = 0b10, //!< Indicators in Mute Mode.
IndicatorNormal = 0b11, //!< Indicators in Normal Mode.
};
/**
* @brief The FailoverMode enum
*/
enum FailoverMode : uint8_t {
FailoverHoldLast = 0b00, //!< Hold last state.
FailoverAllZeros = 0b01, //!< All output to zero.
FailoverAllFull = 0b10, //!< All output to full.
FailoverScenePlayback = 0b11, //!< Playback failover scene.
};
/**
* @brief The General_Status register
*/
struct GeneralStatus {
union {
uint8_t _raw1 = 0;
struct {
bool ubea_valid : 1; //!< UBEA present and not corrupt.
bool rdm_capable : 1; //!< Capable of Remote Device Management (RDM).
bool boot_failsafe : 1; //!< Booted from ROM
bool reserved1 : 1; //!< not implimented
Authority authority : 2; //!< Port-Address Programming Authority
Indicator indicator : 2; //!< Indicator State
};
};
union {
uint8_t _raw2 = 0;
struct {
bool web_config_available : 1; //!< supports web browser configuration.
bool DHCP_active : 1; //!< Nodes IP is DHCP configured.
bool DHCP_capable : 1; //!< Node is DHCP capable.
bool port_address_15b : 1; //!< Node supports 15 bit Port-Address
bool sACN_capable : 1; //!< Node is able to switch between Art-Net and sACN.
bool squawking : 1; //!< is sqawking
bool io_remote_set : 1; //!> Node supports switching of output style using ArtCommand.
bool remote_RDM : 1; //!> Node supports control of RDM using ArtCommand.
};
};
union {
uint8_t _raw3 = 0;
struct {
uint8_t reserved3 : 5; //!< Not used, set to zero
bool failover_capable : 1; //!< Node supports fail-over.
FailoverMode failover_mode : 2; //!< network data loss behavior.
};
};
};
/**
* @brief The KnownProtocols enum
*
* Protocols elegible to be reported in the PortTypes array
*/
enum KnownProtocols : uint8_t {
Protocol_DMX = 0b000000,
Protocol_MIDI = 0b000001,
Protocol_Avab = 0b000010,
Protocol_CMX = 0b000011,
Protocol_ADB = 0b000100,
Protocol_ArtNet = 0b000101,
};
/**
* @brief The PortTypes struct
*
* An array of 4 PortTypes are reported in the ArtPollReply packet.
*/
struct PortTypes {
union {
uint8_t _raw = 0;
struct {
KnownProtocols protocol : 6;
bool can_input : 1;
bool can_output : 1;
};
};
};
/**
* @brief The GoodInput struct
*
* An array of 4 GoodInput are reported in the ArtPollReply packet.
*/
struct GoodInput {
union {
uint8_t _raw = 0;
struct {
uint8_t reserved : 2; //!< Unused and transmitted as zero.
bool rx_errors : 1; //!< Receive errors detected.
bool disabled : 1; //!< Input is disabled.
bool DMX_text : 1; //!< includes DMX512 text packets.
bool DMX_SIP : 1; //!< includes DMX512 SIPs.
bool DMX_test : 1; //!< includes DMX512 test packets.
bool active : 1; //!< Data received.
};
};
};
/**
* @brief The GoodOutput struct
*
* An array of 4 GoodOutput are reported in the ArtPollReply packet.
*/
struct GoodOutput {
union {
uint8_t _rawA = 0;
struct {
bool sACN_enabled : 1; //!< Output is selected to transmit sACN.
bool merge_LTP : 1; //!< Merge Mode is LTP.
bool output_short : 1; //!< DMX output short detected on power up.
bool merge_ArtNet : 1; //!< Output is merging ArtNet data.
bool DMX_text : 1; //!< includes DMX512 text packets.
bool DMX_SIP : 1; //!< includes DMX512 SIPs.
bool DMX_test : 1; //!< includes DMX512 test packets.
bool active : 1; //!< Data received.
};
};
union {
uint8_t _rawB = 0;
struct {
uint8_t reserved : 6; //!< Not used, set to zero
bool output_continuous : 1; //!< oposite of changes-only
bool rdm_disabled : 1; //!< RDM disabled
};
};
};
/**
* @brief The ActivityReport struct
*
* reported in the ArtPollReply packet as SwMacro and SwRemote
*/
struct ActivityReport {
union {
uint8_t _raw = 0;
struct {
bool active_1 : 1;
bool active_2 : 1;
bool active_3 : 1;
bool active_4 : 1;
bool active_5 : 1;
bool active_6 : 1;
bool active_7 : 1;
bool active_8 : 1;
};
};
};
/**
* @brief The AddressCommand enum
*/
enum AddressCommand : uint8_t {
// Node configuration commands:
AcNone = 0x00, //!< No action
AcCancelMerge = 0x01, //!< if in merge mode, cancel
AcLedNormal = 0x02, //!< set front panel indicators to normal
AcLedMute = 0x03, //!< switch off front panel indicators
AcLedLocate = 0x04, //!< flash front panel indicators
AcResetRxFlags = 0x05, //!< reset SIP, Text, Test and Error flags
// Fail-over configuration commands:
AcFailHold = 0x08, //!< hold last look
AcFailZero = 0x09, //!< output zeros on data loss
AcFailFull = 0x0a, //!< output full on data loss
AcFailScene = 0x0b, //!< output scene on data loss
AcFailRecord = 0x0c, //!< record current output state as failover scene
// Port configuration commands:
AcMergeLtp0 = 0x10, //!< set port 0 to merge LTP
AcMergeLtp1 = 0x11, //!< set port 1 to merge LTP
AcMergeLtp2 = 0x12, //!< set port 2 to merge LTP
AcMergeLtp3 = 0x13, //!< set port 3 to merge LTP
AcMergeHtp0 = 0x50, //!< set port 0 to merge HTP
AcMergeHtp1 = 0x51, //!< set port 1 to merge HTP
AcMergeHtp2 = 0x52, //!< set port 2 to merge HTP
AcMergeHtp3 = 0x53, //!< set port 3 to merge HTP
AcArtNetSel0 = 0x60, //!< set port 0 protocol to Art-Net
AcArtNetSel1 = 0x61, //!< set port 1 protocol to Art-Net
AcArtNetSel2 = 0x62, //!< set port 2 protocol to Art-Net
AcArtNetSel3 = 0x63, //!< set port 3 protocol to Art-Net
AcAcnSel0 = 0x70, //!< set port 0 protocol to sACN
AcAcnSel1 = 0x71, //!< set port 1 protocol to sACN
AcAcnSel2 = 0x72, //!< set port 2 protocol to sACN
AcAcnSel3 = 0x73, //!< set port 3 protocol to sACN
AcClearOp0 = 0x90, //!< clear output buffer for port 0
AcClearOp1 = 0x91, //!< clear output buffer for port 1
AcClearOp2 = 0x92, //!< clear output buffer for port 2
AcClearOp3 = 0x93, //!< clear output buffer for port 3
AcStyleDelta0 = 0xa0, //!< set port 0 to changes-only
AcStyleDelta1 = 0xa1, //!< set port 1 to changes-only
AcStyleDelta2 = 0xa2, //!< set port 2 to changes-only
AcStyleDelta3 = 0xa3, //!< set port 3 to changes-only
AcStyleConst0 = 0xb0, //!< set port 0 to constant output
AcStyleConst1 = 0xb1, //!< set port 1 to constant output
AcStyleConst2 = 0xb2, //!< set port 2 to constant output
AcStyleConst3 = 0xb3, //!< set port 3 to constant output
AcRdEnable0 = 0xc0, //!< enable RDM for port 0
AcRdEnable1 = 0xc1, //!< enable RDM for port 1
AcRdEnable2 = 0xc2, //!< enable RDM for port 2
AcRdEnable3 = 0xc3, //!< enable RDM for port 3
AcRdmDisable0 = 0xd0, //!< disable RDM for port 0
AcRdmDisable1 = 0xd1, //!< disable RDM for port 1
AcRdmDisable2 = 0xd2, //!< disable RDM for port 2
AcRdmDisable3 = 0xd3, //!< disable RDM for port 3
};
/**
* @brief The TimecodeType enum
*/
enum TimecodeType : uint8_t {
Film = 0, //!< 24 fps
EBU = 1, //!< 25 fps
DF = 3, //!< 29.97 fps
SMPTE = 4, //!< 30 fps
};
/**
* @brief The Timecode struct
*/
struct Timecode {
uint8_t frame; //!< 24-30, depending on type
uint8_t seconds; //!< 0-59
uint8_t minutes; //!< 0-59
uint8_t hours; //!< 0-24
TimecodeType type; //!< framerate
};
// Table 7 ArtTrigger Key Values.
/// The SubKey field contains an ASCII character which the receiving device
/// should process as if it were a keyboard press.
static const uint8_t KeyAscii = 0;
/// The SubKey field contains the number of a Macro which the receiving
/// device should execute.
static const uint8_t KeyMacro = 1;
/// The SubKey field contains a soft-key number which the receiving device
/// should process as if it were a soft-key keyboard press.
static const uint8_t KeySoft = 2;
/// The SubKey field contains the number of a Show which the receiving
/// device should run.
static const uint8_t KeyShow = 3;
static const std::size_t Short_Name_Length = 18; //!< string length
static const std::size_t Long_Name_Length = 64; //!< string length
static const std::size_t Node_Report_Length = 64; //!< string length
/// \cite ARTNET
/// ...to allow transition between synchronous and non-synchronous modes, a
/// node shall time out to non-synchronous operation if an ArtSync is not
/// received for 4 seconds or more.
static const uint16_t SYNC_LOSS_TIMEOUT = 4000;
namespace VLC {
/// The DMX512 start code of this (ArtVlc) packet is set to 0x91.
static const uint8_t START_CODE = 0x91;
/// Magic number used to identify this packet.
static const uint8_t MagicNumber[] = {0x41, 0x4c, 0x45};
/// Payload contains a simple text string representing a URL.
static const uint16_t BeaconURL = 0x0000;
/// Payload contains a simple ASCII text message
static const uint16_t BeaconText = 0x0001;
} // namespace ARTNET::VLC
namespace FIRMWARE {
/// Type of firmware master packet
enum MasterType : uint8_t {
FirmFirst = 0x00, //!< The first packet of a firmware upload.
FirmCont = 0x01, //!< A consecutive continuation packet of a firmware upload.
FirmLast = 0x02, //!< The last packet of a firmware upload.
UbeaFirst = 0x03, //!< The first packet of a UBEA upload.
UbeaCont = 0x04, //!< A consecutive continuation packet of a UBEA upload.
UbeaLast = 0x05, //!< The last packet of a UBEA upload.
};
/// Type of firmware reply packet
enum ResponseType : uint8_t {
FirmBlockGood = 0x00, //!< Last packet recieved successfully.
FirmAllGood = 0x01, //!< All firmware receieved successfully.
FirmFail = 0xff, //!< Firmware upload failed.
};
} // namespace ARTNET::FIRMWARE
namespace RDM {
enum Version : uint8_t {
Draft = 0x00, //!< RDM DRAFT V1.0
Standard = 0x01, //!< RDM V1.0
};
enum TodRequestCommand : uint8_t {
TodFull = 0x00, //!< Send the Entire TOD
};
enum TodCommandResponse : uint8_t {
ResponseTodFull = 0x00, //!< entire or packet in sequence of the entire TOD.
ResponseTodNak = 0xff, //!< TOD is not available or discovery is incomplete.
};
enum TodControlCommand : uint8_t {
AtcNone = 0x00, //!< No action.
AtcFlush = 0x01, //!< The node flushes its TOD and instigates full discovery.
};
enum RdmCommand : uint8_t {
ArProcess = 0x00, //!< Process RDM Packet.
};
} // namespace ARTNET::RDM
/// @brief Communication Activity
///
/// On if any Art-Net packets detected on network, timeout after 6 seconds.
static const uint16_t DATA_LOSS_TIMEOUT = 6000;
} // namespace ARTNET