Skip to content

Commit

Permalink
Merge pull request #89 from hideakitai/feature/send-one-art-port-repl…
Browse files Browse the repository at this point in the history
…y-per-subscribed-universe

Feature: send one art port reply per subscribed universe
  • Loading branch information
hideakitai authored Jan 31, 2024
2 parents c4e4189 + 1e5efa4 commit 85ed660
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 28 deletions.
19 changes: 8 additions & 11 deletions Artnet/ArtPollReply.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class ArtPollReply
String node_report {""};

public:
Packet generate_reply(const IPAddress &my_ip, const uint8_t my_mac[6], const CallbackMap &callbacks, uint8_t net_switch, uint8_t sub_switch)
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]);
Expand All @@ -84,23 +84,20 @@ class ArtPollReply
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 = (callbacks.size() > NUM_POLLREPLY_PUBLIC_PORT_LIMIT) ? NUM_POLLREPLY_PUBLIC_PORT_LIMIT : callbacks.size();
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;
size_t i = 0;
for (const auto& pair : callbacks) {
r.sw_in[i] = pair.first & 0x0F;
r.sw_out[i] = i; // dummy: output port is flexible
r.port_types[i] = 0xC0; // I/O available by DMX512
r.good_input[i] = 0x80; // Data received without error
r.good_output[i] = 0x80; // Data transmitted without error
if (++i >= NUM_POLLREPLY_PUBLIC_PORT_LIMIT) break;
}
// 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
Expand Down
1 change: 1 addition & 0 deletions Artnet/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ constexpr uint16_t PACKET_SIZE {530};
using CallbackAllType = std::function<void(const uint32_t universe, const uint8_t* data, const uint16_t size)>;
using CallbackType = std::function<void(const uint8_t* data, const uint16_t size)>;
using CallbackArtSync = std::function<void(void)>;
using CallbackArtTrigger = std::function<void(uint16_t oem, uint8_t key, uint8_t sub_key, const uint8_t *payload, uint16_t size)>;

#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
template <uint16_t SIZE>
Expand Down
45 changes: 34 additions & 11 deletions Artnet/Receiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "Common.h"
#include "ArtDmx.h"
#include "ArtPollReply.h"
#include "ArtTrigger.h"

namespace art_net {

Expand All @@ -18,6 +19,7 @@ class Receiver_ {
CallbackMap callbacks;
CallbackAllType callback_all;
CallbackArtSync callback_artsync;
CallbackArtTrigger callback_arttrigger;
S* stream;
bool b_verbose {false};
artpollreply::ArtPollReply artpollreply_ctx;
Expand Down Expand Up @@ -53,25 +55,33 @@ class Receiver_ {

OpCode op_code = OpCode::NA;
if (checkID(d)) {
remote_ip = stream->S::remoteIP();
remote_port = (uint16_t)stream->S::remotePort();
OpCode received_op_code = static_cast<OpCode>(opcode(d));
switch (received_op_code) {
case OpCode::Dmx: {
memcpy(packet.data(), d, size);
remote_ip = stream->S::remoteIP();
remote_port = (uint16_t)stream->S::remotePort();
if (callback_all) callback_all(universe15bit(), data(), size - HEADER_SIZE);
for (auto& c : callbacks)
if (universe15bit() == c.first) c.second(data(), size - HEADER_SIZE);
op_code = OpCode::Dmx;
break;
}
case OpCode::Poll: {
remote_ip = stream->S::remoteIP();
remote_port = (uint16_t)stream->S::remotePort();
poll_reply();
op_code = OpCode::Poll;
break;
}
case OpCode::Trigger: {
if (callback_arttrigger) {
uint16_t oem = (d[art_trigger::OEM_H] << 8) | d[art_trigger::OEM_L];
uint8_t key = d[art_trigger::KEY];
uint8_t sub_key = d[art_trigger::SUB_KEY];
callback_arttrigger(oem, key, sub_key, d + art_trigger::PAYLOAD, size - art_trigger::PAYLOAD);
}
op_code = OpCode::Trigger;
break;
}
case OpCode::Sync: {
if (callback_artsync) callback_artsync();
op_code = OpCode::Sync;
Expand Down Expand Up @@ -185,13 +195,21 @@ class Receiver_ {
callback_all = arx::function_traits<F>::cast(func);
}
template <typename F>
inline auto subscribeArtsync(F&& func) -> std::enable_if_t<arx::is_callable<F>::value> {
inline auto subscribeArtSync(F&& func) -> std::enable_if_t<arx::is_callable<F>::value> {
callback_artsync = arx::function_traits<F>::cast(func);
}
template <typename F>
inline auto subscribeArtsync(F* func) -> std::enable_if_t<arx::is_callable<F>::value> {
inline auto subscribeArtSync(F* func) -> std::enable_if_t<arx::is_callable<F>::value> {
callback_artsync = arx::function_traits<F>::cast(func);
}
template <typename F>
inline auto subscribeArtTrigger(F&& func) -> std::enable_if_t<arx::is_callable<F>::value> {
callback_arttrigger = arx::function_traits<F>::cast(func);
}
template <typename F>
inline auto subscribeArtTrigger(F* func) -> std::enable_if_t<arx::is_callable<F>::value> {
callback_arttrigger = arx::function_traits<F>::cast(func);
}

inline void unsubscribe(const uint8_t universe) {
auto it = callbacks.find(universe);
Expand All @@ -203,6 +221,9 @@ class Receiver_ {
inline void unsubscribeArtSync() {
callback_artsync = nullptr;
}
inline void unsubscribeArtTrigger() {
callback_arttrigger = nullptr;
}

inline void clear_subscribers() {
unsubscribe();
Expand Down Expand Up @@ -279,11 +300,13 @@ class Receiver_ {
const IPAddress my_subnet = subnetMask();
uint8_t my_mac[6];
macAddress(my_mac);
artpollreply::Packet r = artpollreply_ctx.generate_reply(my_ip, my_mac, callbacks, net_switch, sub_switch);
static const IPAddress local_broadcast_addr = IPAddress((uint32_t)my_ip | ~(uint32_t)my_subnet);
stream->beginPacket(local_broadcast_addr, DEFAULT_PORT);
stream->write(r.b, sizeof(artpollreply::Packet));
stream->endPacket();
for (const auto &cb_pair : callbacks) {
artpollreply::Packet r = artpollreply_ctx.generate_reply(my_ip, my_mac, cb_pair.first, net_switch, sub_switch);
static const IPAddress local_broadcast_addr = IPAddress((uint32_t)my_ip | ~(uint32_t)my_subnet);
stream->beginPacket(local_broadcast_addr, DEFAULT_PORT);
stream->write(r.b, sizeof(artpollreply::Packet));
stream->endPacket();
}
}

#ifdef ARTNET_ENABLE_WIFI
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,23 +298,23 @@ void sync(const String& ip);
```C++
OpCode parse();
// subscribers
template <typename F> inline auto subscribe(const uint8_t universe, F&& func);
template <typename F> inline auto subscribe(const uint8_t universe, F* func);
template <typename F> inline auto subscribe(F&& func);
template <typename F> inline auto subscribe(F* func);
template <typename F> inline auto subscribeArtsync(F&& func);
template <typename F> inline auto subscribeArtsync(F* func);
template <typename F> inline auto subscribe(const uint8_t universe, CallbackType);
template <typename F> inline auto subscribe(CallbackAllTyp);
template <typename F> inline auto subscribeArtSync(CallbackArtSync);
template <typename F> inline auto subscribeArtTrigger(CallbackArtTrigger);
// callback definitions for subscribers
using CallbackAllType = std::function<void(const uint32_t universe, const uint8_t* data, const uint16_t size)>;
using CallbackType = std::function<void(const uint8_t* data, const uint16_t size)>;
using CallbackArtSync = std::function<void(void)>;
using CallbackArTrigger = std::function<void(uint16_t oem, uint8_t key, uint8_t sub_key, const uint8_t *payload, uint16_t size)>;
// for FastLED
inline void forward(const uint8_t universe, CRGB* leds, const uint16_t num);
// unsubscribe
inline void unsubscribe(const uint8_t universe);
inline void unsubscribe();
inline void clear_subscribers();
inline void unsubscribeArtSync();
inline void unsubscribeArtTrigger();
// ArtPollReply information
void shortname(const String& sn);
void longname(const String& ln);
Expand Down

0 comments on commit 85ed660

Please sign in to comment.