2022-06-08 16:05:06 -04:00
/*
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 {
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.
} ;
} ;
2023-05-20 13:20:33 -04:00
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 ;
2022-06-08 16:05:06 -04:00
} ;
} ;
} ;
} ;
/// @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 node’ s 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 {
2022-06-09 16:51:14 -04:00
/**
* @ brief OEM
* @ param value
*/
OEM ( uint16_t value = oem_unknown ) : word ( value ) { }
2022-06-08 16:05:06 -04:00
union {
2022-06-09 16:51:14 -04:00
uint16_t word ;
2022-06-08 16:05:06 -04:00
struct {
uint16_t manufacturer : 15 ;
bool extended_features : 1 ;
} ;
} ;
} ;
/**
* @ brief The Authority enum
*/
enum Authority : uint8_t {
AuthorityUnkown = 0 b00 , //!< Port-Address Programming Authority unknown.
AuthorityLocal = 0 b01 , //!< Port-Address set by front panel controls.
AuthorityRemote = 0 b10 , //!< All or part of Port-Address programmed by network
AuthorityUnused = 0 b11 , //!< not used
} ;
/**
* @ brief The Indicator enum
*/
enum Indicator : uint8_t {
IndicatorUnknown = 0 b00 , //!< Indicator state unknown.
IndicatorIdentify = 0 b01 , //!< Indicators in Locate / Identify Mode.
IndicatorMute = 0 b10 , //!< Indicators in Mute Mode.
IndicatorNormal = 0 b11 , //!< Indicators in Normal Mode.
} ;
/**
* @ brief The FailoverMode enum
*/
enum FailoverMode : uint8_t {
FailoverHoldLast = 0 b00 , //!< Hold last state.
FailoverAllZeros = 0 b01 , //!< All output to zero.
FailoverAllFull = 0 b10 , //!< All output to full.
FailoverScenePlayback = 0 b11 , //!< 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 ; //!< Node’ s 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 = 0 b000000 ,
Protocol_MIDI = 0 b000001 ,
Protocol_Avab = 0 b000010 ,
Protocol_CMX = 0 b000011 ,
Protocol_ADB = 0 b000100 ,
Protocol_ArtNet = 0 b000101 ,
} ;
/**
* @ 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 SIP’ s.
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 SIP’ s.
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