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

841 lines
21 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.

/*
packet.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 "artnet.h"
#include "config.h"
#include "acn/pdu-stream.h"
#include "rdm/uid.h"
#include <vector>
namespace ARTNET {
/**
* @brief The packet_data struct
*/
struct packet_data
: public ACN::PDU::pdu_stream_object
{
uint16_t version = VERSION; //!< Protocol Version
};
/**
* @brief The artpoll_data struct
*
* \cite ARTNET This packet is used to discover the presence of other
* Controllers, Nodes and Media Servers. The ArtPoll packet is only sent by
* a Controller. Both Controllers and Nodes respond to the packet.
*/
struct poll_data
: public packet_data
{
poll_data()
: diagnostic_level(DpLow)
{};
TalkToMe talk_to_me; //!< Set behaviour of Node
Priority diagnostic_level; //!< The lowest priority of diagnostics message
virtual size_t streamSize() const override { return 4; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
};
/**
* @brief The artpollreply_data struct
*
* A device, in response to a Controllers ArtPoll, sends the ArtPollReply.
* This packet is also broadcast to the Directed Broadcast address by all
* Art-Net devices on power up.
*/
struct pollreply_data
: public packet_data
{
pollreply_data()
: udp_port(UDP_PORT)
, oem(MY_ARTNET_MANUFACTUER_ID)
, esta_manufacturer(MY_ESTA_MANUFACTURER_ID)
{};
uint32_t my_ip = 0; //!< the Nodes IPv4 address
uint16_t udp_port; //!< The Port is always 0x1936
PortAddress net_sub_switch; //!< Net and Subnet switch positions
OEM oem; //!< the equipment vendor and the feature set
uint8_t ubea_version = 0; //!< the firmware version of the User Bios Extension Area (UBEA)
GeneralStatus status; //!< general status register
uint16_t esta_manufacturer; //!< manufacturer ID
std::string short_name = ""; //!< short name for the Node
std::string long_name = ""; //!< long name for the Node
uint16_t num_ports = 0; //!< the number of input or output ports. Max=4
PortTypes port_types[4]; //!< operation and protocol of each port.
GoodInput good_input[4]; //!< input status of the node.
GoodOutput good_output[4]; //!< output status of the node.
uint8_t SwIn[4]; //!< Bits 3-0 of the 15 bit Port-Address for each input port
uint8_t SwOut[4]; //!< Bits 3-0 of the 15 bit Port-Address for each output port
uint8_t SwVideo = 0; //!< This field is now deprecated.
ActivityReport SwMacro; //!< used for remote event triggering or cueing.
ActivityReport SwRemote; //!< used for remote event triggering or cueing.
Style style; //!< the equipment style of the device.
uint8_t mac_address[6] = {0}; //!< MAC Address
uint32_t bind_ip = 0; //!< the IP of the root device.
uint8_t bind_index = 1; //!< the order of bound devices.
/**
* @brief textual report of the Nodes operating status or operational errors.
* @return
*/
const std::string report() const { return _node_report; };
void set_report(NodeReport, uint, std::string);
virtual size_t streamSize() const override { return 226; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
private:
std::string _node_report = "";
static const size_t _filler_length = 21; //!< length of filler at end of packet
};
/**
* @brief The artipprog_data struct
*
* Program the IPv4 address.
*/
struct ipprog_data
: public packet_data
{
ipprog_data()
: udp_port(UDP_PORT)
{};
union {
uint8_t _raw = 0;
struct {
bool program_ip : 1;
bool program_netmask : 1;
bool program_port : 1;
bool reset_ip_mask_port : 1;
uint8_t reserved : 2;
bool enable_dhcp : 1;
bool enable_programming : 1;
};
} command; //!< Action of this packet
uint32_t ip_address = 0; //!< IP Address to be programmed into Node
uint32_t subnet_mask = 0; //!< Subnet Mask to be programmed into Node
uint16_t udp_port; //!< Depreciated
virtual size_t streamSize() const override { return 24; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
private:
static const size_t _spare_length = 8;
};
/**
* @brief The artipprogreply_data struct
*/
struct ipprogreply_data
: public packet_data
{
ipprogreply_data()
: udp_port(UDP_PORT)
{};
uint32_t ip_address = 0; //!< IP Address of the Node
uint32_t subnet_mask = 0; //!< Subnet Mask of the Node
uint16_t udp_port; //!< Depreciated
union {
uint8_t _raw = 0;
struct {
uint8_t reserved1 : 6;
bool dhcp_enabled : 1;
bool reserved2 : 1;
};
} status; //!< Status flags
virtual size_t streamSize() const override { return 24; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
private:
static const size_t _spare_length = 7;
};
/**
* @brief The address_data struct
*/
struct address_data
: public packet_data
{
PortAddress net_sub_switch; //!< Net and Subnet switch positions
uint8_t bind_index = 1; //!< the order of bound devices.
std::string short_name = ""; //!< short name for the Node
std::string long_name = ""; //!< long name for the Node
uint8_t SwIn[4]; //!< Bits 3-0 of the 15 bit Port-Address for each input port
uint8_t SwOut[4]; //!< Bits 3-0 of the 15 bit Port-Address for each output port
uint8_t SwVideo = 0; //!< This field is now deprecated.
AddressCommand command; //!< Node configuration command.
virtual size_t streamSize() const override { return 97; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
};
/**
* @brief The diagdata_data struct
*/
struct diagdata_data
: public packet_data
{
Priority priority; //!< priority of the diagnostic data
std::string data = ""; //!< ASCII text
virtual size_t streamSize() const override { return 8 + data.length() + 1; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
private:
static const uint16_t _max_data_length = 512; //!< max data length, including null terminator
};
/**
* @brief The timecode_data struct
*/
struct timecode_data
: public packet_data
{
Timecode time; //!< time code
virtual size_t streamSize() const override { return 9; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
};
/**
* @brief The command_data struct
*/
struct command_data
: public packet_data
{
uint16_t esta_manufacturer; //!< manufacturer ID
std::string data = ""; //!< ASCII text
virtual size_t streamSize() const override { return 6 + data.length() + 1; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
private:
static const uint16_t _max_data_length = 512; //!< max data length, including null terminator
};
/**
* @brief The trigger_data struct
*/
struct trigger_data
: public packet_data
{
OEM oem; //!< the equipment vendor and the feature set
uint8_t key; //!< the trigger key
uint8_t subkey; //!< the trigger subkey
uint8_t data[512] = {0}; //!< data array
virtual size_t streamSize() const override { return 520; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
};
/**
* @brief The dmx_data struct
*/
struct dmx_data
: public packet_data
{
uint8_t sequence; //!< to ensure that ArtDmx packets are used in the correct order.
uint8_t physical; //!< the physical input port from which DMX was input
PortAddress universe; //!< Net, Subnet, and universe number
std::vector<uint8_t> data = {0}; //!< data array, initialize null start
virtual size_t streamSize() const override { return 7 + data.size(); };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
};
/**
* @brief The sync_data struct
*/
struct sync_data
: public packet_data
{
virtual size_t streamSize() const override { return 4; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
};
/**
* @brief The nzs_data struct
*/
struct nzs_data
: public packet_data
{
/**
* @brief nzs_data
* @param startcode
*/
nzs_data(uint8_t startcode = 0)
{ data = {startcode}; }
uint8_t sequence; //!< to ensure that ArtDmx packets are used in the correct order.
PortAddress universe; //!< Net, Subnet, and universe number
std::vector<uint8_t> data; //!< data array with startcode
virtual size_t streamSize() const override { return 7 + data.size(); };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
};
/**
* @brief The vlc_data struct
*/
struct vlc_data
: public nzs_data
{
/**
* @brief vlc_data
* @param other
*/
vlc_data(const nzs_data * other = nullptr)
: nzs_data(VLC::START_CODE)
{ if (other) _from_nzs(other); }
union {
uint8_t _raw = 0;
struct {
uint8_t padding : 5; //!< reserved
bool beacon : 1; //!< the transmitter should continuously repeat transmission of this packet until another is received
bool reply : 1; //!< is a reply packet that is in response to the request sent with matching number in the transaction number
bool IEEE : 1; //!< data in the payload area shall be interpreted as IEEE VLC data.
};
} flags; //!< flags for this packet
uint16_t transaction = 0; //!< transaction number which allows VLC transactions to be synchronised
uint16_t address = 0; //!< The slot number, range 1-512, of the device to which this packet is directed.
uint8_t depth = 0; //!< modulation depth expressed as a percentage in the range 1 to 100
uint16_t frequency = 0; //!< modulation frequency of the VLC transmitter expressed in Hz.
uint16_t modulation = 0; //!< modulation type number that the transmitter should use to transmit VLC.
uint16_t language = 0; //!< payload language code
uint16_t beacon_frequency; //!< the frequency in Hertz at which the VLC packet should be repeated.
std::vector<uint8_t> payload; //!< The actual VLC payload.
virtual size_t streamSize() const override { return 30 + data.size(); };
/// The ArtVlc packet is a specially formed ArtNzs packet.
/// compile() MUST BE CALLED prior to streaming.
void compile();
private:
const static size_t _payload_max_length = 480;
uint16_t _checksum() const;
bool _from_nzs(const nzs_data *);
};
/**
* @brief The input_data struct
*/
struct input_data
: public packet_data
{
uint8_t bind_index = 1; //!< the order of bound devices.
uint16_t num_ports = 0; //!< the number of input or output ports. Max=4
union InputFlags {
uint8_t _raw = 0; //!< raw byte
struct {
bool disabled : 1; //!< Set to disable this input.
uint8_t reserved : 7;
};
}; //!< flags for this packet
InputFlags status[4]; //!< input disable status of each port.
virtual size_t streamSize() const override { return 10; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
};
/**
* @brief The firmwaremaster_data struct
*/
struct firmwaremaster_data
: public packet_data
{
FIRMWARE::MasterType type; //!< Defines the packet contents
uint8_t block_id; //!< Counts the consecutive blocks of firmware upload.
uint64_t length; //!< the file size (in words) of the file to be uploaded.
uint16_t block[256] = {0}; //!< the firmware or UBEA data block.
virtual size_t streamSize() const override { return 542; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
private:
const size_t _spare_length = 20;
};
/**
* @brief The firmwarereply_data struct
*/
struct firmwarereply_data
: public packet_data
{
FIRMWARE::ResponseType type; //!< Defines the packet contents
virtual size_t streamSize() const override { return 26; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
private:
const size_t _spare_length = 21;
};
/**
* @brief The todrequest_data struct
*/
struct todrequest_data
: public packet_data
{
std::vector<PortAddress> universes; //!< universes that must respond
virtual size_t streamSize() const override { return 14 + universes.size(); };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
private:
const size_t _max_count = 32;
};
/**
* @brief The toddata_data struct
*/
struct toddata_data
: public packet_data
{
RDM::Version rdm_version = RDM::Standard; //!< supports Draft or Standard RDM
uint8_t port = 1; //!< physical port index
uint8_t bind_index = 1; //!< sub-device
PortAddress universe; //!< responding universe
RDM::TodCommandResponse type = RDM::ResponseTodFull; //!< response type
uint16_t total_count = 0; //!< total device count
uint8_t block_count = 0; //!< index of these devices in total
std::vector<std::shared_ptr<::RDM::UID>> devices; //!< block of up to 200 devices
virtual size_t streamSize() const override { return 18 + devices.size() * 6; }
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
};
/**
* @brief The todcontrol_data struct
*/
struct todcontrol_data
: public packet_data
{
PortAddress universe; //!< unverse that should action command
RDM::TodControlCommand command = RDM::AtcNone; //!< control command
virtual size_t streamSize() const override { return 14; };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
};
/**
* @brief The rdm_data struct
*/
struct rdm_data
: public packet_data
{
RDM::Version rdm_version = RDM::Standard; //!< supports Draft or Standard RDM
PortAddress universe; //!< responding universe
RDM::RdmCommand command = RDM::ArProcess; //!< response type
std::vector<uint8_t> data = {::RDM::SC_RDM}; //!< data array, initialize RDM start
virtual size_t streamSize() const override { return 13 + data.size(); };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
};
/**
* @brief The rdmsub_data struct
*/
struct rdmsub_data
: public packet_data
{
RDM::Version rdm_version = RDM::Standard; //!< supports Draft or Standard RDM
::RDM::UID uid; //!< UID of target RDM device.
uint8_t command_class; //!< Get, Set, GetResponse, SetResponse
::RDM::PID pid; //!< type of parameter
uint16_t subdevice = 0; //!< the first device information contained in packet
std::vector<uint16_t> data; //!< packed data array
virtual size_t streamSize() const override { return 20 + (data.size() * 2); };
virtual void iStream(ACN::PDU::Stream) override;
virtual void oStream(ACN::PDU::Stream) const override;
};
/**
* @brief The ARTNET packet
*
* All UDP packets accepted by the Node conform to the Art-Net protocol
* specification as defined... Any other packets are ignored.
*/
struct Packet
: public ACN::PDU::pdu_stream_object
{
/**
* @brief Packet
* @param data
*/
Packet(std::shared_ptr<packet_data> data = nullptr)
: _opcode(OpNull)
, _data(data)
{}
/**
* @brief opcode
* @return
*/
OpCode opcode() { return _opcode; }
/**
* @brief data
* @return
*/
template<class T>
std::shared_ptr<T> data()
{
#ifdef RTTI_ENABLED
return std::dynamic_pointer_cast<T>(_data);
#else
return std::static_pointer_cast<T>(_data);
#endif
}
/**
* @brief createData
* @param stream
*/
template<class T>
void createData(ACN::PDU::Stream stream = nullptr)
{
if (_data)
return; // already has a data segment
_data = std::make_shared<T>();
if (stream && stream->good())
_data->iStream(stream);
}
size_t streamSize() const override;
void iStream(ACN::PDU::Stream) override;
void oStream(ACN::PDU::Stream) const override;
protected:
OpCode _opcode; //!< Op Code
std::shared_ptr<packet_data> _data; //!< packet data
};
/**
* @brief The ArtPoll Packet
*/
struct ArtPoll
: public Packet
{
ArtPoll()
: Packet(std::make_shared<poll_data>())
{ _opcode = OpPoll; }
};
/**
* @brief The ArtPollReply Packet
*/
struct ArtPollReply
: public Packet
{
ArtPollReply()
: Packet(std::make_shared<pollreply_data>())
{ _opcode = OpPollReply; }
};
/**
* @brief The ArtIpProg Packet
*/
struct ArtIpProg
: public Packet
{
ArtIpProg()
: Packet(std::make_shared<ipprog_data>())
{ _opcode = OpIpProg; }
};
/**
* @brief The ArtIpProgReply Packet
*/
struct ArtIpProgReply
: public Packet
{
ArtIpProgReply()
: Packet(std::make_shared<ipprogreply_data>())
{ _opcode = OpIpProgReply; }
};
/**
* @brief The ArtAddress Packet
*/
struct ArtAddress
: public Packet
{
ArtAddress()
: Packet(std::make_shared<address_data>())
{ _opcode = OpAddress; }
};
/**
* @brief The ArtDiagData Packet
*/
struct ArtDiagData
: public Packet
{
ArtDiagData()
: Packet(std::make_shared<diagdata_data>())
{ _opcode = OpDiagData; }
};
/**
* @brief The ArtTimeCode Packet
*/
struct ArtTimeCode
: public Packet
{
ArtTimeCode()
: Packet(std::make_shared<timecode_data>())
{ _opcode = OpTimeCode; }
};
/**
* @brief The ArtCommand Packet
*/
struct ArtCommand
: public Packet
{
ArtCommand()
: Packet(std::make_shared<command_data>())
{ _opcode = OpCommand; }
};
/**
* @brief The ArtTrigger Packet
*/
struct ArtTrigger
: public Packet
{
ArtTrigger()
: Packet(std::make_shared<trigger_data>())
{ _opcode = OpTrigger; }
};
/**
* @brief The ArtDmx Packet
*/
struct ArtDmx
: public Packet
{
ArtDmx()
: Packet(std::make_shared<dmx_data>())
{ _opcode = OpDmx; }
};
/**
* @brief The ArtSync Packet
*/
struct ArtSync
: public Packet
{
ArtSync()
: Packet(std::make_shared<sync_data>())
{ _opcode = OpSync; }
};
/**
* @brief The ArtNzs Packet
*/
struct ArtNzs
: public Packet
{
ArtNzs()
: Packet(std::make_shared<nzs_data>())
{ _opcode = OpNzs; }
};
/**
* @brief The ArtVlc Packet
*/
struct ArtVlc
: public Packet
{
ArtVlc()
: Packet(std::make_shared<vlc_data>())
{ _opcode = OpNzs; }
};
/**
* @brief The ArtInput Packet
*/
struct ArtInput
: public Packet
{
ArtInput()
: Packet(std::make_shared<input_data>())
{ _opcode = OpInput; }
};
/**
* @brief The ArtFirmwareMaster Packet
*/
struct ArtFirmwareMaster
: public Packet
{
ArtFirmwareMaster()
: Packet(std::make_shared<firmwaremaster_data>())
{ _opcode = OpFirmwareMaster; }
};
/**
* @brief The ArtFirmwareReply Packet
*/
struct ArtFirmwareReply
: public Packet
{
ArtFirmwareReply()
: Packet(std::make_shared<firmwarereply_data>())
{ _opcode = OpFirmwareReply; }
};
/**
* @brief The ArtTodRequest Packet
*/
struct ArtTodRequest
: public Packet
{
ArtTodRequest()
: Packet(std::make_shared<todrequest_data>())
{ _opcode = OpTodRequest; }
};
/**
* @brief The ArtTodData Packet
*/
struct ArtTodData
: public Packet
{
ArtTodData()
: Packet(std::make_shared<toddata_data>())
{ _opcode = OpTodData; }
};
/**
* @brief The ArtTodControl Packet
*/
struct ArtTodControl
: public Packet
{
ArtTodControl()
: Packet(std::make_shared<todcontrol_data>())
{ _opcode = OpTodControl; }
};
/**
* @brief The ArtRdm Packet
*/
struct ArtRdm
: public Packet
{
ArtRdm()
: Packet(std::make_shared<rdm_data>())
{ _opcode = OpRdm; }
};
/**
* @brief The Art Packet
*/
struct ArtRdmSub
: public Packet
{
ArtRdmSub()
: Packet(std::make_shared<rdmsub_data>())
{ _opcode = OpRdmSub; }
};
} // namespace ARTNET