Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: artnet modules #90

Merged
merged 13 commits into from
Feb 2, 2024
142 changes: 99 additions & 43 deletions Artnet/ArtDmx.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
#include <stddef.h>

namespace art_net {
namespace art_dmx {

namespace artdmx {

enum Index : uint16_t {
enum Index : uint16_t
{
ID = 0,
OP_CODE_L = 8,
OP_CODE_H = 9,
Expand All @@ -25,57 +25,113 @@ enum Index : uint16_t {
DATA = 18
};

class ArtDmx {
uint8_t target_net {0};
uint8_t target_subnet {0};
uint8_t target_universe {0};
uint8_t seq {0};
uint8_t phy {0};
struct Destination
{
String ip;
uint8_t net;
uint8_t subnet;
uint8_t universe;
};

public:
void set_header(uint8_t *packet)
{
for (size_t i = 0; i < ID_LENGTH; i++) packet[i] = static_cast<uint8_t>(ARTNET_ID[i]);
packet[OP_CODE_L] = (static_cast<uint16_t>(OpCode::Dmx) >> 0) & 0x00FF;
packet[OP_CODE_H] = (static_cast<uint16_t>(OpCode::Dmx) >> 8) & 0x00FF;
packet[PROTOCOL_VER_H] = (PROTOCOL_VER >> 8) & 0x00FF;
packet[PROTOCOL_VER_L] = (PROTOCOL_VER >> 0) & 0x00FF;
packet[SEQUENCE] = seq++;
packet[PHYSICAL] = phy;
packet[NET] = target_net;
packet[SUBUNI] = (target_subnet << 4) | target_universe;
packet[LENGTH_H] = (512 >> 8) & 0xFF;
packet[LENGTH_L] = (512 >> 0) & 0xFF;
inline bool operator<(const Destination &rhs, const Destination &lhs)
{
if (rhs.ip < lhs.ip) {
return true;
}

void set_universe(const uint32_t universe_) {
target_net = (universe_ >> 8) & 0x7F;
target_subnet = (universe_ >> 4) & 0x0F;
target_universe = universe_ & 0x0F;
if (rhs.ip > lhs.ip) {
return false;
}
void set_universe(const uint8_t net_, const uint8_t subnet_, const uint8_t universe_) {
target_net = net_ & 0x7F;
target_subnet = subnet_ & 0x0F;
target_universe = universe_ & 0x0F;
if (rhs.net < lhs.net) {
return true;
}
void set_physical(const uint8_t i) {
phy = constrain(i, 0, 3);
if (rhs.net > lhs.net) {
return false;
}

uint8_t sequence() const {
return seq;
if (rhs.subnet < lhs.subnet) {
return true;
}

void set_data(uint8_t *packet, const uint8_t* const data, const uint16_t size) {
memcpy((&packet[artdmx::DATA]), data, size);
if (rhs.subnet > lhs.subnet) {
return false;
}
if (rhs.universe < lhs.universe) {
return true;
}
void set_data(uint8_t *packet, const uint16_t ch, const uint8_t data) {
packet[artdmx::DATA + ch] = data;
if (rhs.universe > lhs.universe) {
return false;
}
return false;
}

inline bool operator==(const Destination &rhs, const Destination &lhs)
{
return rhs.ip == lhs.ip && rhs.net == lhs.net && rhs.subnet == lhs.subnet && rhs.universe == lhs.universe;
}

struct Metadata
{
uint8_t sequence;
uint8_t physical;
uint8_t net;
uint8_t subnet;
uint8_t universe;
};

} // namespace artdmx
using CallbackType = std::function<void(const uint8_t *data, uint16_t size, const Metadata &metadata, const RemoteInfo &remote)>;
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
// sender
using LastSendTimeMsMap = std::map<Destination, uint32_t>;
using SequenceMap = std::map<Destination, uint8_t>;
// receiver
using CallbackMap = std::map<uint16_t, CallbackType>;
#else
// sender
using LastSendTimeMsMap = arx::map<Destination, uint32_t>;
using SequenceMap = arx::map<Destination, uint8_t>;
// receiver
using CallbackMap = arx::map<uint16_t, CallbackType>;
#endif

inline Metadata generateMetadataFrom(const uint8_t *packet)
{
Metadata metadata;
metadata.sequence = packet[SEQUENCE];
metadata.physical = packet[PHYSICAL];
metadata.net = packet[NET];
metadata.subnet = (packet[SUBUNI] >> 4) & 0x0F;
metadata.universe = (packet[SUBUNI] >> 0) & 0x0F;
return metadata;
}

inline void setMetadataTo(uint8_t *packet, uint8_t sequence, uint8_t physical, uint8_t net, uint8_t subnet, uint8_t universe)
{
for (size_t i = 0; i < ID_LENGTH; i++) {
packet[i] = static_cast<uint8_t>(ARTNET_ID[i]);
}
packet[OP_CODE_L] = (static_cast<uint16_t>(OpCode::Dmx) >> 0) & 0x00FF;
packet[OP_CODE_H] = (static_cast<uint16_t>(OpCode::Dmx) >> 8) & 0x00FF;
packet[PROTOCOL_VER_H] = (PROTOCOL_VER >> 8) & 0x00FF;
packet[PROTOCOL_VER_L] = (PROTOCOL_VER >> 0) & 0x00FF;
packet[SEQUENCE] = sequence;
packet[PHYSICAL] = physical & 0x03;
packet[NET] = net & 0x7F;
packet[SUBUNI] = ((subnet & 0x0F) << 4) | (universe & 0x0F);
packet[LENGTH_H] = (512 >> 8) & 0xFF;
packet[LENGTH_L] = (512 >> 0) & 0xFF;
}

inline void setDataTo(uint8_t *packet, const uint8_t* const data, uint16_t size)
{
memcpy(packet + art_dmx::DATA, data, size);
}
inline void setDataTo(uint8_t *packet, const uint16_t ch, const uint8_t data)
{
packet[art_dmx::DATA + ch] = data;
}

} // namespace art_dmx
} // namespace art_net

using ArtDmxMetadata = art_net::art_dmx::Metadata;
using ArtDmxCallback = art_net::art_dmx::CallbackType;

#endif // ARTNET_ARTDMX_H
135 changes: 70 additions & 65 deletions Artnet/ArtPollReply.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@
#include <string.h>

namespace art_net {
namespace artpollreply {
namespace art_poll_reply {

union Packet {
struct {
static constexpr size_t NUM_POLLREPLY_PUBLIC_PORT_LIMIT {4};

union Packet
{
struct
{
uint8_t id[8];
uint8_t op_code_l;
uint8_t op_code_h;
Expand Down Expand Up @@ -52,77 +56,78 @@ union Packet {
uint8_t b[239];
};

class ArtPollReply
struct Config
{
uint16_t oem {0x00FF}; // OemUnknown https://github.com/tobiasebsen/ArtNode/blob/master/src/Art-NetOemCodes.h
uint16_t esta_man {0x0000}; // ESTA manufacturer code
uint8_t status1 {0x00}; // Unknown / Normal
uint8_t status2 {0x08}; // sACN capable
String short_name {"Arduino ArtNet"};
String long_name {"Ardino ArtNet Protocol by hideakitai/ArtNet"};
String node_report {""};
};

public:
Packet generate_reply(const IPAddress &my_ip, const uint8_t my_mac[6], uint32_t universe, uint8_t net_switch, uint8_t sub_switch)
{
Packet r;
for (size_t i = 0; i < ID_LENGTH; i++) r.id[i] = static_cast<uint8_t>(ARTNET_ID[i]);
r.op_code_l = ((uint16_t)OpCode::PollReply >> 0) & 0x00FF;
r.op_code_h = ((uint16_t)OpCode::PollReply >> 8) & 0x00FF;
memcpy(r.mac, my_mac, 6);
for (size_t i = 0; i < 4; ++i) r.ip[i] = my_ip[i];
r.port_l = (DEFAULT_PORT >> 0) & 0xFF;
r.port_h = (DEFAULT_PORT >> 8) & 0xFF;
r.ver_h = (PROTOCOL_VER >> 8) & 0x00FF;
r.ver_l = (PROTOCOL_VER >> 0) & 0x00FF;
r.oem_h = 0; // https://github.com/tobiasebsen/ArtNode/blob/master/src/Art-NetOemCodes.h
r.oem_l = 0xFF; // OemUnknown
r.ubea_ver = 0; // UBEA not programmed
r.status_1 = 0x00; // Unknown / Normal
r.esta_man_l = 0; // No EATA manufacture code
r.esta_man_h = 0; // No ESTA manufacture code
memset(r.short_name, 0, 18);
memset(r.long_name, 0, 64);
memset(r.node_report, 0, 64);
memcpy(r.short_name, short_name.c_str(), short_name.length());
memcpy(r.long_name, long_name.c_str(), long_name.length());
memcpy(r.node_report, node_report.c_str(), node_report.length());
r.num_ports_h = 0; // Reserved
r.num_ports_l = 1;
memset(r.sw_in, 0, 4);
memset(r.sw_out, 0, 4);
memset(r.port_types, 0, 4);
memset(r.good_input, 0, 4);
memset(r.good_output, 0, 4);
r.net_sw = net_switch & 0x7F;
r.sub_sw = sub_switch & 0x0F;
// https://github.com/hideakitai/ArtNet/issues/81
r.sw_in[0] = universe & 0x0F;
r.sw_out[0] = 0; // dummy: output port is flexible
r.port_types[0] = 0xC0; // I/O available by DMX512
r.good_input[0] = 0x80; // Data received without error
r.good_output[0] = 0x80; // Data transmitted without error
r.sw_video = 0; // Video display shows local data
r.sw_macro = 0; // No support for macro key inputs
r.sw_remote = 0; // No support for remote trigger inputs
memset(r.spare, 0x00, 3);
r.style = 0x00; // A DMX to / from Art-Net device
for (size_t i = 0; i < 4; ++i) r.bind_ip[i] = my_ip[i];
r.bind_index = 0;
r.status_2 = 0x08; // sACN capable
memset(r.filler, 0x00, 26);

return r;
}

void shortname(const String& sn) {
short_name = sn;
inline Packet generatePacketFrom(const IPAddress &my_ip, const uint8_t my_mac[6], uint16_t universe, const Config &metadata)
{
Packet r;
for (size_t i = 0; i < ID_LENGTH; i++) {
r.id[i] = static_cast<uint8_t>(ARTNET_ID[i]);
}
void longname(const String& ln) {
long_name = ln;
r.op_code_l = ((uint16_t)OpCode::PollReply >> 0) & 0x00FF;
r.op_code_h = ((uint16_t)OpCode::PollReply >> 8) & 0x00FF;
memcpy(r.mac, my_mac, 6);
for (size_t i = 0; i < 4; ++i) {
r.ip[i] = my_ip[i];
}
void nodereport(const String& nr) {
node_report = nr;
r.port_l = (DEFAULT_PORT >> 0) & 0xFF;
r.port_h = (DEFAULT_PORT >> 8) & 0xFF;
r.ver_h = (PROTOCOL_VER >> 8) & 0x00FF;
r.ver_l = (PROTOCOL_VER >> 0) & 0x00FF;
r.oem_h = (metadata.oem >> 8) & 0xFF; //
r.oem_l = (metadata.oem >> 8) & 0xFF;
r.ubea_ver = 0; // UBEA not programmed
r.status_1 = metadata.status1;
r.esta_man_l = (metadata.esta_man >> 8) & 0xFF;
r.esta_man_h = (metadata.esta_man >> 8) & 0xFF;
memset(r.short_name, 0, 18);
memset(r.long_name, 0, 64);
memset(r.node_report, 0, 64);
memcpy(r.short_name, metadata.short_name.c_str(), metadata.short_name.length());
memcpy(r.long_name, metadata.long_name.c_str(), metadata.long_name.length());
memcpy(r.node_report, metadata.node_report.c_str(), metadata.node_report.length());
r.num_ports_h = 0; // Reserved
r.num_ports_l = 1;
memset(r.sw_in, 0, 4);
memset(r.sw_out, 0, 4);
memset(r.port_types, 0, 4);
memset(r.good_input, 0, 4);
memset(r.good_output, 0, 4);
r.net_sw = (universe >> 8) & 0x7F;
r.sub_sw = (universe >> 4) & 0x0F;
// https://github.com/hideakitai/ArtNet/issues/81
r.sw_in[0] = (universe >> 0) & 0x0F;
r.sw_out[0] = 0; // dummy: output port is flexible
r.port_types[0] = 0xC0; // I/O available by DMX512
r.good_input[0] = 0x80; // Data received without error
r.good_output[0] = 0x80; // Data transmitted without error
r.sw_video = 0; // Video display shows local data
r.sw_macro = 0; // No support for macro key inputs
r.sw_remote = 0; // No support for remote trigger inputs
memset(r.spare, 0x00, 3);
r.style = 0x00; // A DMX to / from Art-Net device
for (size_t i = 0; i < 4; ++i) {
r.bind_ip[i] = my_ip[i];
}
};
r.bind_index = 0;
r.status_2 = metadata.status2;
memset(r.filler, 0x00, 26);

return r;
}

} // namespace artpollreply
} // namespace art_poll_reply
} // namespace art_net

using ArtPollReplyConfig = art_net::art_poll_reply::Config;

#endif // ARTNET_ARTPOLLREPLY_H
15 changes: 12 additions & 3 deletions Artnet/ArtSync.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,26 @@
namespace art_net {
namespace art_sync {

enum Index : uint16_t {
enum Index : uint16_t
{
ID = 0,
OP_CODE_L = 8,
OP_CODE_H = 9,
PROTOCOL_VER_H = 10,
PROTOCOL_VER_L = 11,
AUX1 = 12,
AUX2 = 13,

PACKET_SIZE = 14,
};

inline void set_header(uint8_t *packet)
using CallbackType = std::function<void(const ArtNetRemoteInfo &remote)>;

inline void setMetadataTo(uint8_t *packet)
{
for (size_t i = 0; i < ID_LENGTH; i++) packet[i] = static_cast<uint8_t>(ARTNET_ID[i]);
for (size_t i = 0; i < ID_LENGTH; i++) {
packet[i] = static_cast<uint8_t>(ARTNET_ID[i]);
}
packet[OP_CODE_L] = (static_cast<uint16_t>(OpCode::Sync) >> 0) & 0x00FF;
packet[OP_CODE_H] = (static_cast<uint16_t>(OpCode::Sync) >> 8) & 0x00FF;
packet[PROTOCOL_VER_H] = (PROTOCOL_VER >> 8) & 0x00FF;
Expand All @@ -33,4 +40,6 @@ inline void set_header(uint8_t *packet)
} // namespace art_sync
} // namespace art_net

using ArtSyncCallback = art_net::art_sync::CallbackType;

#endif // ARTNET_ART_SYNC_H
Loading
Loading