diff --git a/Artnet/ArtPollReply.h b/Artnet/ArtPollReply.h index 61207d3..4c0cd64 100644 --- a/Artnet/ArtPollReply.h +++ b/Artnet/ArtPollReply.h @@ -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(ARTNET_ID[i]); @@ -84,7 +84,7 @@ 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); @@ -92,15 +92,12 @@ class ArtPollReply 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 diff --git a/Artnet/Common.h b/Artnet/Common.h index 7631638..76a385a 100644 --- a/Artnet/Common.h +++ b/Artnet/Common.h @@ -65,6 +65,7 @@ constexpr uint16_t PACKET_SIZE {530}; using CallbackAllType = std::function; using CallbackType = std::function; using CallbackArtSync = std::function; +using CallbackArtTrigger = std::function; #if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11 template diff --git a/Artnet/Receiver.h b/Artnet/Receiver.h index ea2ca5e..28cb899 100644 --- a/Artnet/Receiver.h +++ b/Artnet/Receiver.h @@ -5,6 +5,7 @@ #include "Common.h" #include "ArtDmx.h" #include "ArtPollReply.h" +#include "ArtTrigger.h" namespace art_net { @@ -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; @@ -53,12 +55,12 @@ 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(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); @@ -66,12 +68,20 @@ class Receiver_ { 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; @@ -185,13 +195,21 @@ class Receiver_ { callback_all = arx::function_traits::cast(func); } template - inline auto subscribeArtsync(F&& func) -> std::enable_if_t::value> { + inline auto subscribeArtSync(F&& func) -> std::enable_if_t::value> { callback_artsync = arx::function_traits::cast(func); } template - inline auto subscribeArtsync(F* func) -> std::enable_if_t::value> { + inline auto subscribeArtSync(F* func) -> std::enable_if_t::value> { callback_artsync = arx::function_traits::cast(func); } + template + inline auto subscribeArtTrigger(F&& func) -> std::enable_if_t::value> { + callback_arttrigger = arx::function_traits::cast(func); + } + template + inline auto subscribeArtTrigger(F* func) -> std::enable_if_t::value> { + callback_arttrigger = arx::function_traits::cast(func); + } inline void unsubscribe(const uint8_t universe) { auto it = callbacks.find(universe); @@ -203,6 +221,9 @@ class Receiver_ { inline void unsubscribeArtSync() { callback_artsync = nullptr; } + inline void unsubscribeArtTrigger() { + callback_arttrigger = nullptr; + } inline void clear_subscribers() { unsubscribe(); @@ -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 diff --git a/README.md b/README.md index 08d9c94..a15382a 100644 --- a/README.md +++ b/README.md @@ -298,16 +298,15 @@ void sync(const String& ip); ```C++ OpCode parse(); // subscribers -template inline auto subscribe(const uint8_t universe, F&& func); -template inline auto subscribe(const uint8_t universe, F* func); -template inline auto subscribe(F&& func); -template inline auto subscribe(F* func); -template inline auto subscribeArtsync(F&& func); -template inline auto subscribeArtsync(F* func); +template inline auto subscribe(const uint8_t universe, CallbackType); +template inline auto subscribe(CallbackAllTyp); +template inline auto subscribeArtSync(CallbackArtSync); +template inline auto subscribeArtTrigger(CallbackArtTrigger); // callback definitions for subscribers using CallbackAllType = std::function; using CallbackType = std::function; using CallbackArtSync = std::function; +using CallbackArTrigger = std::function; // for FastLED inline void forward(const uint8_t universe, CRGB* leds, const uint16_t num); // unsubscribe @@ -315,6 +314,7 @@ 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);