From 0ed5b00685f3f8a96feb860e7264e9f7c817817a Mon Sep 17 00:00:00 2001 From: Hideaki Tai Date: Mon, 13 Oct 2025 22:19:37 +0900 Subject: [PATCH 01/10] refactor: remove redundant ARTNET_ENABLE_ETHER/WIFI --- Artnet/ReceiverTraits.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Artnet/ReceiverTraits.h b/Artnet/ReceiverTraits.h index c951c8d..def9d62 100644 --- a/Artnet/ReceiverTraits.h +++ b/Artnet/ReceiverTraits.h @@ -25,6 +25,10 @@ template bool isNetworkReady(T&& x) { return IsNetworkReady>::get(std::forward(x)); } +template +bool isNetworkReady(T&& x) { + return IsNetworkReady>::isNetworkReady(std::forward(x)); +} template IPAddress getLocalIP(); From da2f9fa05f2ac543c1cdf8c15dc51ce487a8f2f8 Mon Sep 17 00:00:00 2001 From: Hideaki Tai Date: Tue, 14 Oct 2025 14:25:49 +0900 Subject: [PATCH 02/10] feat: add examples for multiple interfaces in one sketch --- .../Multiple/send_receive/send_receive.ino | 101 ++++++++++++++++ .../switch_interface/switch_interface.ino | 111 ++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 examples/Multiple/send_receive/send_receive.ino create mode 100644 examples/Multiple/switch_interface/switch_interface.ino diff --git a/examples/Multiple/send_receive/send_receive.ino b/examples/Multiple/send_receive/send_receive.ino new file mode 100644 index 0000000..292124e --- /dev/null +++ b/examples/Multiple/send_receive/send_receive.ino @@ -0,0 +1,101 @@ +#include +#include + +// WiFi stuff +const char* ssid = "your-ssid"; +const char* pwd = "your-password"; +const IPAddress ip_wifi(192, 168, 1, 201); +const IPAddress gateway(192, 168, 1, 1); +const IPAddress subnet(255, 255, 255, 0); +// Ethernet stuff +const IPAddress ip_ether(192, 168, 0, 201); +uint8_t mac[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB}; + +ArtnetEther artnet_ether; +ArtnetWiFi artnet_wifi; +const String target_ip = "192.168.1.200"; +uint8_t universe = 1; // 0 - 15 + +const uint16_t size = 512; +uint8_t data[size]; +uint8_t value = 0; + +// if Artnet packet comes to this universe, this function is called +void onArtDmxUniverse(const uint8_t *data, uint16_t size, const ArtDmxMetadata& metadata, const ArtNetRemoteInfo& remote) +{ + Serial.print("lambda : artnet data from "); + Serial.print(remote.ip); + Serial.print(":"); + Serial.print(remote.port); + Serial.print(", universe = "); + Serial.print(universe); + Serial.print(", size = "); + Serial.print(size); + Serial.print(") :"); + for (size_t i = 0; i < size; ++i) { + Serial.print(data[i]); + Serial.print(","); + } + Serial.println(); +}; + +// if Artnet packet comes, this function is called to every universe +void onArtDmx(const uint8_t *data, uint16_t size, const ArtDmxMetadata& metadata, const ArtNetRemoteInfo& remote) +{ + Serial.print("received ArtNet data from "); + Serial.print(remote.ip); + Serial.print(":"); + Serial.print(remote.port); + Serial.print(", net = "); + Serial.print(metadata.net); + Serial.print(", subnet = "); + Serial.print(metadata.subnet); + Serial.print(", universe = "); + Serial.print(metadata.universe); + Serial.print(", sequence = "); + Serial.print(metadata.sequence); + Serial.print(", size = "); + Serial.print(size); + Serial.println(")"); +}; + +void setup() { + Serial.begin(115200); + + // WiFi stuff + WiFi.begin(ssid, pwd); + WiFi.config(ip_wifi, gateway, subnet); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(500); + } + Serial.print("WiFi connected, IP = "); + Serial.println(WiFi.localIP()); + // ArtnetWiFi + artnet_wifi.begin(); + artnet_wifi.subscribeArtDmxUniverse(universe, onArtDmxUniverse); + artnet_wifi.subscribeArtDmx(onArtDmx); + + // Ethernet stuff + Ethernet.begin(mac, ip_ether); + // ArtnetEther + artnet_ether.begin(); + artnet_ether.subscribeArtDmxUniverse(universe, onArtDmxUniverse); + artnet_ether.subscribeArtDmx(onArtDmx); +} + +void loop() { + // check if artnet packet has come and execute callback + artnet_wifi.parse(); + artnet_ether.parse(); + + value = (millis() / 4) % 256; + memset(data, value, size); + + artnet_wifi.setArtDmxData(data, size); + artnet_ether.setArtDmxData(data, size); + + // automatically send set data in 40fps + artnet_wifi.streamArtDmxTo(target_ip, universe); + artnet_ether.streamArtDmxTo(target_ip, universe); +} diff --git a/examples/Multiple/switch_interface/switch_interface.ino b/examples/Multiple/switch_interface/switch_interface.ino new file mode 100644 index 0000000..1fbe4d7 --- /dev/null +++ b/examples/Multiple/switch_interface/switch_interface.ino @@ -0,0 +1,111 @@ +#include +#include + +// WiFi stuff +const char* ssid = "your-ssid"; +const char* pwd = "your-password"; +const IPAddress ip_wifi(192, 168, 1, 201); +const IPAddress gateway(192, 168, 1, 1); +const IPAddress subnet(255, 255, 255, 0); +// Ethernet stuff +const IPAddress ip_ether(192, 168, 0, 201); +uint8_t mac[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB}; + +// TODO: Switching the following instances at runtime +ArtnetEther artnet_ether; +ArtnetWiFi artnet_wifi; +const String target_ip = "192.168.1.200"; +uint8_t universe = 1; // 0 - 15 + +const uint16_t size = 512; +uint8_t data[size]; +uint8_t value = 0; + +// Emulate runtime switching +bool use_wifi = true; + +// if Artnet packet comes to this universe, this function is called +void onArtDmxUniverse(const uint8_t *data, uint16_t size, const ArtDmxMetadata& metadata, const ArtNetRemoteInfo& remote) +{ + Serial.print("lambda : artnet data from "); + Serial.print(remote.ip); + Serial.print(":"); + Serial.print(remote.port); + Serial.print(", universe = "); + Serial.print(universe); + Serial.print(", size = "); + Serial.print(size); + Serial.print(") :"); + for (size_t i = 0; i < size; ++i) { + Serial.print(data[i]); + Serial.print(","); + } + Serial.println(); +}; + +// if Artnet packet comes, this function is called to every universe +void onArtDmx(const uint8_t *data, uint16_t size, const ArtDmxMetadata& metadata, const ArtNetRemoteInfo& remote) +{ + Serial.print("received ArtNet data from "); + Serial.print(remote.ip); + Serial.print(":"); + Serial.print(remote.port); + Serial.print(", net = "); + Serial.print(metadata.net); + Serial.print(", subnet = "); + Serial.print(metadata.subnet); + Serial.print(", universe = "); + Serial.print(metadata.universe); + Serial.print(", sequence = "); + Serial.print(metadata.sequence); + Serial.print(", size = "); + Serial.print(size); + Serial.println(")"); +}; + +void setup() { + Serial.begin(115200); + + // TODO: Switching the following instances at runtime + if (use_wifi) { + Serial.println("Use WiFi for ArtNet"); + // WiFi stuff + WiFi.begin(ssid, pwd); + WiFi.config(ip_wifi, gateway, subnet); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(500); + } + Serial.print("WiFi connected, IP = "); + Serial.println(WiFi.localIP()); + // ArtnetWiFi + artnet_wifi.begin(); + artnet_wifi.subscribeArtDmxUniverse(universe, onArtDmxUniverse); + artnet_wifi.subscribeArtDmx(onArtDmx); + } else { + Serial.println("Use Ethernet for ArtNet"); + // Ethernet stuff + Ethernet.begin(mac, ip_ether); + // ArtnetEther + artnet_ether.begin(); + artnet_ether.subscribeArtDmxUniverse(universe, onArtDmxUniverse); + artnet_ether.subscribeArtDmx(onArtDmx); + } +} + +void loop() { + // TODO: Switching the following instances at runtime + // check if artnet packet has come and execute callback + artnet_wifi.parse(); + artnet_ether.parse(); + + value = (millis() / 4) % 256; + memset(data, value, size); + + artnet_wifi.setArtDmxData(data, size); + artnet_ether.setArtDmxData(data, size); + + // automatically send set data in 40fps + artnet_wifi.streamArtDmxTo(target_ip, universe); + artnet_ether.streamArtDmxTo(target_ip, universe); +} From 75dbf21a87c7ffd78880fae6c6392d52f08e5447 Mon Sep 17 00:00:00 2001 From: Hideaki Tai Date: Tue, 14 Oct 2025 18:10:57 +0900 Subject: [PATCH 03/10] refactor: remove function templates from receiver methods --- Artnet/Receiver.h | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/Artnet/Receiver.h b/Artnet/Receiver.h index 415a21f..ecfac64 100644 --- a/Artnet/Receiver.h +++ b/Artnet/Receiver.h @@ -140,9 +140,7 @@ class Receiver_ } // subscribe artdmx packet for specified net, subnet, and universe - template - auto subscribeArtDmxUniverse(uint8_t net, uint8_t subnet, uint8_t universe, const Fn &func) - -> std::enable_if_t::value> + void subscribeArtDmxUniverse(uint8_t net, uint8_t subnet, uint8_t universe, const ArtDmxCallback& func) { if (net > 0x7F) { this->logger->println(F("net should be less than 0x7F")); @@ -161,42 +159,33 @@ class Receiver_ } // subscribe artdmx packet for specified universe (15 bit) - template - auto subscribeArtDmxUniverse(uint16_t universe, const Fn &func) - -> std::enable_if_t::value> + void subscribeArtDmxUniverse(uint16_t universe, const ArtDmxCallback& func) { - this->callback_art_dmx_universes.insert(std::make_pair(universe, arx::function_traits::cast(func))); + this->callback_art_dmx_universes.insert(std::make_pair(universe, func)); } // subscribe artnzs packet for specified universe (15 bit) - template - auto subscribeArtNzsUniverse(uint16_t universe, const Fn &func) - -> std::enable_if_t::value> + void subscribeArtNzsUniverse(uint16_t universe, const ArtNzsCallback& func) { - this->callback_art_nzs_universes.insert(std::make_pair(universe, arx::function_traits::cast(func))); + this->callback_art_nzs_universes.insert(std::make_pair(universe, func)); } // subscribe artdmx packet for all universes - template - auto subscribeArtDmx(const Fn &func) - -> std::enable_if_t::value> + void subscribeArtDmx(const ArtDmxCallback& func) { - this->callback_art_dmx = arx::function_traits::cast(func); + this->callback_art_dmx = func; } // subscribe other packets - template - auto subscribeArtSync(const Fn &func) - -> std::enable_if_t::value> + void subscribeArtSync(const ArtSyncCallback& func) { - this->callback_art_sync = arx::function_traits::cast(func); + this->callback_art_sync = func; } - template - auto subscribeArtTrigger(const Fn &func) - -> std::enable_if_t::value> + // subscribe art_trigger packet + void subscribeArtTrigger(const ArtTriggerCallback& func) { - this->callback_art_trigger = arx::function_traits::cast(func); + this->callback_art_trigger = func; } void unsubscribeArtDmxUniverse(uint8_t net, uint8_t subnet, uint8_t universe) From 7286fc60a75ff5b413467a47faccfc06c57bbb97 Mon Sep 17 00:00:00 2001 From: Hideaki Tai Date: Wed, 15 Oct 2025 05:13:37 +0900 Subject: [PATCH 04/10] fix: examples to use dynamic dispatch --- .../switch_interface/switch_interface.ino | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/examples/Multiple/switch_interface/switch_interface.ino b/examples/Multiple/switch_interface/switch_interface.ino index 1fbe4d7..d12ece3 100644 --- a/examples/Multiple/switch_interface/switch_interface.ino +++ b/examples/Multiple/switch_interface/switch_interface.ino @@ -11,9 +11,7 @@ const IPAddress subnet(255, 255, 255, 0); const IPAddress ip_ether(192, 168, 0, 201); uint8_t mac[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB}; -// TODO: Switching the following instances at runtime -ArtnetEther artnet_ether; -ArtnetWiFi artnet_wifi; +std::unique_ptr artnet; const String target_ip = "192.168.1.200"; uint8_t universe = 1; // 0 - 15 @@ -66,7 +64,6 @@ void onArtDmx(const uint8_t *data, uint16_t size, const ArtDmxMetadata& metadata void setup() { Serial.begin(115200); - // TODO: Switching the following instances at runtime if (use_wifi) { Serial.println("Use WiFi for ArtNet"); // WiFi stuff @@ -79,33 +76,31 @@ void setup() { Serial.print("WiFi connected, IP = "); Serial.println(WiFi.localIP()); // ArtnetWiFi - artnet_wifi.begin(); - artnet_wifi.subscribeArtDmxUniverse(universe, onArtDmxUniverse); - artnet_wifi.subscribeArtDmx(onArtDmx); + artnet = std::make_unique(); + artnet->begin(); + artnet->subscribeArtDmxUniverse(universe, onArtDmxUniverse); + artnet->subscribeArtDmx(onArtDmx); } else { Serial.println("Use Ethernet for ArtNet"); // Ethernet stuff Ethernet.begin(mac, ip_ether); // ArtnetEther - artnet_ether.begin(); - artnet_ether.subscribeArtDmxUniverse(universe, onArtDmxUniverse); - artnet_ether.subscribeArtDmx(onArtDmx); + artnet = std::make_unique(); + artnet->begin(); + artnet->subscribeArtDmxUniverse(universe, onArtDmxUniverse); + artnet->subscribeArtDmx(onArtDmx); } } void loop() { - // TODO: Switching the following instances at runtime // check if artnet packet has come and execute callback - artnet_wifi.parse(); - artnet_ether.parse(); + artnet->parse(); value = (millis() / 4) % 256; memset(data, value, size); - artnet_wifi.setArtDmxData(data, size); - artnet_ether.setArtDmxData(data, size); + artnet->setArtDmxData(data, size); // automatically send set data in 40fps - artnet_wifi.streamArtDmxTo(target_ip, universe); - artnet_ether.streamArtDmxTo(target_ip, universe); + artnet->streamArtDmxTo(target_ip, universe); } From 53f662ae9c182c3087c4e8f7210d984aa451a88d Mon Sep 17 00:00:00 2001 From: Hideaki Tai Date: Wed, 15 Oct 2025 05:16:31 +0900 Subject: [PATCH 05/10] feat: introduce interface classes for Sender, Receiver, and Manager --- Artnet/Manager.h | 14 +++----- Artnet/ManagerTraits.h | 20 ++++++++++++ Artnet/Receiver.h | 63 ++++++++++++++++++------------------ Artnet/ReceiverTraits.h | 71 +++++++++++++++++++++++++++++++++++++++++ Artnet/Sender.h | 45 +++++++++++++------------- Artnet/SenderTraits.h | 52 ++++++++++++++++++++++++++++++ 6 files changed, 203 insertions(+), 62 deletions(-) create mode 100644 Artnet/ManagerTraits.h create mode 100644 Artnet/SenderTraits.h diff --git a/Artnet/Manager.h b/Artnet/Manager.h index 9559870..f5116ee 100644 --- a/Artnet/Manager.h +++ b/Artnet/Manager.h @@ -1,32 +1,28 @@ #pragma once #ifndef ARTNET_MANAGER_H +#define ARTNET_MANAGER_H #include "Common.h" #include "Receiver.h" #include "Sender.h" +#include "ManagerTraits.h" namespace art_net { template -class Manager : public Sender_, public Receiver_ +class Manager : public IManager, public Sender_, public Receiver_ { S stream; public: - void begin(uint16_t recv_port = DEFAULT_PORT) + void begin(uint16_t port = DEFAULT_PORT) override { - this->stream.begin(recv_port); + this->stream.begin(port); this->Sender_::attach(this->stream); this->Receiver_::attach(this->stream); } - - void parse() - { - this->Receiver_::parse(); - } }; - } // namespace art_net #endif // ARTNET_MANAGER_H diff --git a/Artnet/ManagerTraits.h b/Artnet/ManagerTraits.h new file mode 100644 index 0000000..2042f42 --- /dev/null +++ b/Artnet/ManagerTraits.h @@ -0,0 +1,20 @@ +#pragma once +#ifndef ARTNET_MANAGER_TRAITS_H +#define ARTNET_MANAGER_TRAITS_H + +#include "ReceiverTraits.h" +#include "SenderTraits.h" + +namespace art_net { + +struct IManager : virtual ISender_, virtual IReceiver_ +{ + virtual ~IManager() = default; + virtual void begin(uint16_t port = DEFAULT_PORT) = 0; +}; + +} // namespace art_net + +using ArtnetInterface = art_net::IManager; + +#endif // ARTNET_MANAGER_TRAITS_H diff --git a/Artnet/Receiver.h b/Artnet/Receiver.h index ecfac64..a8e5bae 100644 --- a/Artnet/Receiver.h +++ b/Artnet/Receiver.h @@ -8,6 +8,7 @@ #include "ArtPollReply.h" #include "ArtTrigger.h" #include "ArtSync.h" +#include "ReceiverTraits.h" namespace art_net { @@ -22,7 +23,7 @@ static NoPrint no_log; } // namespace template -class Receiver_ +class Receiver_ : virtual IReceiver_ { S *stream; Array packet; @@ -45,7 +46,7 @@ class Receiver_ } #endif - OpCode parse() + OpCode parse() override { if (!isNetworkReady()) { return OpCode::NoPacket; @@ -140,7 +141,7 @@ class Receiver_ } // subscribe artdmx packet for specified net, subnet, and universe - void subscribeArtDmxUniverse(uint8_t net, uint8_t subnet, uint8_t universe, const ArtDmxCallback& func) + void subscribeArtDmxUniverse(uint8_t net, uint8_t subnet, uint8_t universe, const ArtDmxCallback& func) override { if (net > 0x7F) { this->logger->println(F("net should be less than 0x7F")); @@ -159,57 +160,57 @@ class Receiver_ } // subscribe artdmx packet for specified universe (15 bit) - void subscribeArtDmxUniverse(uint16_t universe, const ArtDmxCallback& func) + void subscribeArtDmxUniverse(uint16_t universe, const ArtDmxCallback& func) override { this->callback_art_dmx_universes.insert(std::make_pair(universe, func)); } // subscribe artnzs packet for specified universe (15 bit) - void subscribeArtNzsUniverse(uint16_t universe, const ArtNzsCallback& func) + void subscribeArtNzsUniverse(uint16_t universe, const ArtNzsCallback& func) override { this->callback_art_nzs_universes.insert(std::make_pair(universe, func)); } // subscribe artdmx packet for all universes - void subscribeArtDmx(const ArtDmxCallback& func) + void subscribeArtDmx(const ArtDmxCallback& func) override { this->callback_art_dmx = func; } // subscribe other packets - void subscribeArtSync(const ArtSyncCallback& func) + void subscribeArtSync(const ArtSyncCallback& func) override { this->callback_art_sync = func; } // subscribe art_trigger packet - void subscribeArtTrigger(const ArtTriggerCallback& func) + void subscribeArtTrigger(const ArtTriggerCallback& func) override { this->callback_art_trigger = func; } - void unsubscribeArtDmxUniverse(uint8_t net, uint8_t subnet, uint8_t universe) + void unsubscribeArtDmxUniverse(uint8_t net, uint8_t subnet, uint8_t universe) override { uint16_t u = ((uint16_t)net << 8) | ((uint16_t)subnet << 4) | (uint16_t)universe; this->unsubscribeArtDmxUniverse(u); } - void unsubscribeArtDmxUniverse(uint16_t universe) + void unsubscribeArtDmxUniverse(uint16_t universe) override { auto it = this->callback_art_dmx_universes.find(universe); if (it != this->callback_art_dmx_universes.end()) { this->callback_art_dmx_universes.erase(it); } } - void unsubscribeArtDmxUniverses() + void unsubscribeArtDmxUniverses() override { this->callback_art_dmx_universes.clear(); } - void unsubscribeArtDmx() + void unsubscribeArtDmx() override { this->callback_art_dmx = nullptr; } - void unsubscribeArtNzsUniverse(uint16_t universe) + void unsubscribeArtNzsUniverse(uint16_t universe) override { auto it = this->callback_art_nzs_universes.find(universe); if (it != this->callback_art_nzs_universes.end()) { @@ -217,23 +218,23 @@ class Receiver_ } } - void unsubscribeArtSync() + void unsubscribeArtSync() override { this->callback_art_sync = nullptr; } - void unsubscribeArtTrigger() + void unsubscribeArtTrigger() override { this->callback_art_trigger = nullptr; } #ifdef FASTLED_VERSION - void forwardArtDmxDataToFastLED(uint8_t net, uint8_t subnet, uint8_t universe, CRGB* leds, uint16_t num) + void forwardArtDmxDataToFastLED(uint8_t net, uint8_t subnet, uint8_t universe, CRGB* leds, uint16_t num) override { uint16_t u = ((uint16_t)net << 8) | ((uint16_t)subnet << 4) | (uint16_t)universe; this->forwardArtDmxDataToFastLED(u, leds, num); } - void forwardArtDmxDataToFastLED(uint16_t universe, CRGB* leds, uint16_t num) + void forwardArtDmxDataToFastLED(uint16_t universe, CRGB* leds, uint16_t num) override { this->subscribeArtDmxUniverse(universe, [this, leds, num](const uint8_t* data, const uint16_t size, const ArtDmxMetadata &, const RemoteInfo &) { size_t n; @@ -259,47 +260,47 @@ class Receiver_ #endif // https://art-net.org.uk/how-it-works/discovery-packets/artpollreply/ - void setArtPollReplyConfigOem(uint16_t oem) + void setArtPollReplyConfigOem(uint16_t oem) override { this->art_poll_reply_config.oem = oem; } - void setArtPollReplyConfigEstaMan(uint16_t esta_man) + void setArtPollReplyConfigEstaMan(uint16_t esta_man) override { this->art_poll_reply_config.esta_man = esta_man; } - void setArtPollReplyConfigStatus1(uint8_t status1) + void setArtPollReplyConfigStatus1(uint8_t status1) override { this->art_poll_reply_config.status1 = status1; } - void setArtPollReplyConfigStatus2(uint8_t status2) + void setArtPollReplyConfigStatus2(uint8_t status2) override { this->art_poll_reply_config.status2 = status2; } - void setArtPollReplyConfigShortName(const String &short_name) + void setArtPollReplyConfigShortName(const String &short_name) override { this->art_poll_reply_config.short_name = short_name; } - void setArtPollReplyConfigLongName(const String &long_name) + void setArtPollReplyConfigLongName(const String &long_name) override { this->art_poll_reply_config.long_name = long_name; } - void setArtPollReplyConfigNodeReport(const String &node_report) + void setArtPollReplyConfigNodeReport(const String &node_report) override { this->art_poll_reply_config.node_report = node_report; } - void setArtPollReplyConfigSwIn(size_t index, uint8_t sw_in) + void setArtPollReplyConfigSwIn(size_t index, uint8_t sw_in) override { if (index < 4) { this->art_poll_reply_config.sw_in[index] = sw_in; } } - void setArtPollReplyConfigSwIn(uint8_t sw_in[4]) + void setArtPollReplyConfigSwIn(uint8_t sw_in[4]) override { for (size_t i = 0; i < 4; ++i) { this->art_poll_reply_config.sw_in[i] = sw_in[i]; } } - void setArtPollReplyConfigSwIn(uint8_t sw_in_0, uint8_t sw_in_1, uint8_t sw_in_2, uint8_t sw_in_3) + void setArtPollReplyConfigSwIn(uint8_t sw_in_0, uint8_t sw_in_1, uint8_t sw_in_2, uint8_t sw_in_3) override { this->setArtPollReplyConfigSwIn(0, sw_in_0); this->setArtPollReplyConfigSwIn(1, sw_in_1); @@ -315,7 +316,7 @@ class Receiver_ const String &long_name, const String &node_report, uint8_t sw_in[4] - ) { + ) override { this->setArtPollReplyConfigOem(oem); this->setArtPollReplyConfigEstaMan(esta_man); this->setArtPollReplyConfigStatus1(status1); @@ -325,12 +326,12 @@ class Receiver_ this->setArtPollReplyConfigNodeReport(node_report); this->setArtPollReplyConfigSwIn(sw_in); } - void setArtPollReplyConfig(const ArtPollReplyConfig &cfg) + void setArtPollReplyConfig(const ArtPollReplyConfig &cfg) override { this->art_poll_reply_config = cfg; } - void setLogger(Print* logger) + void setLogger(Print* logger) override { this->logger = logger; } @@ -413,7 +414,7 @@ class Receiver_ }; template -class Receiver : public Receiver_ +class Receiver : public IReceiver, public Receiver_ { S stream; diff --git a/Artnet/ReceiverTraits.h b/Artnet/ReceiverTraits.h index def9d62..a09c3b3 100644 --- a/Artnet/ReceiverTraits.h +++ b/Artnet/ReceiverTraits.h @@ -2,6 +2,13 @@ #ifndef ARTNET_RECEIVER_TRAITS_H #define ARTNET_RECEIVER_TRAITS_H +#include "Common.h" +#include "ArtDmx.h" +#include "ArtNzs.h" +#include "ArtPollReply.h" +#include "ArtTrigger.h" +#include "ArtSync.h" + namespace art_net { template struct LocalIP; @@ -39,6 +46,70 @@ void getMacAddress(uint8_t mac[6]); template bool isNetworkReady(); +struct IReceiver_ +{ + virtual ~IReceiver_() = default; + + virtual OpCode parse() = 0; + // subscribe artdmx packet for specified net, subnet, and universe + virtual void subscribeArtDmxUniverse(uint8_t net, uint8_t subnet, uint8_t universe, const ArtDmxCallback& func) = 0; + // subscribe artdmx packet for specified universe (15 bit) + virtual void subscribeArtDmxUniverse(uint16_t universe, const ArtDmxCallback& func) = 0; + // subscribe artnzs packet for specified universe (15 bit) + virtual void subscribeArtNzsUniverse(uint16_t universe, const ArtNzsCallback& func) = 0; + // subscribe artdmx packet for all universes + virtual void subscribeArtDmx(const ArtDmxCallback& func) = 0; + // subscribe other packets + virtual void subscribeArtSync(const ArtSyncCallback& func) = 0; + // subscribe art_trigger packet + virtual void subscribeArtTrigger(const ArtTriggerCallback& func) = 0; + + virtual void unsubscribeArtDmxUniverse(uint8_t net, uint8_t subnet, uint8_t universe) = 0; + virtual void unsubscribeArtDmxUniverse(uint16_t universe) = 0; + virtual void unsubscribeArtDmxUniverses() = 0; + virtual void unsubscribeArtDmx() = 0; + virtual void unsubscribeArtNzsUniverse(uint16_t universe) = 0; + virtual void unsubscribeArtSync() = 0; + virtual void unsubscribeArtTrigger() = 0; + +#ifdef FASTLED_VERSION + virtual void forwardArtDmxDataToFastLED(uint8_t net, uint8_t subnet, uint8_t universe, CRGB* leds, uint16_t num) = 0; + virtual void forwardArtDmxDataToFastLED(uint16_t universe, CRGB* leds, uint16_t num) = 0; +#endif + + // https://art-net.org.uk/how-it-works/discovery-packets/artpollreply/ + virtual void setArtPollReplyConfigOem(uint16_t oem) = 0; + virtual void setArtPollReplyConfigEstaMan(uint16_t esta_man) = 0; + virtual void setArtPollReplyConfigStatus1(uint8_t status1) = 0; + virtual void setArtPollReplyConfigStatus2(uint8_t status2) = 0; + virtual void setArtPollReplyConfigShortName(const String &short_name) = 0; + virtual void setArtPollReplyConfigLongName(const String &long_name) = 0; + virtual void setArtPollReplyConfigNodeReport(const String &node_report) = 0; + virtual void setArtPollReplyConfigSwIn(size_t index, uint8_t sw_in) = 0; + virtual void setArtPollReplyConfigSwIn(uint8_t sw_in[4]) = 0; + virtual void setArtPollReplyConfigSwIn(uint8_t sw_in_0, uint8_t sw_in_1, uint8_t sw_in_2, uint8_t sw_in_3) = 0; + virtual void setArtPollReplyConfig( + uint16_t oem, + uint16_t esta_man, + uint8_t status1, + uint8_t status2, + const String &short_name, + const String &long_name, + const String &node_report, + uint8_t sw_in[4] + ) = 0; + virtual void setArtPollReplyConfig(const ArtPollReplyConfig &cfg) = 0; + virtual void setLogger(Print* logger) = 0; +}; + +struct IReceiver : virtual IReceiver_ +{ + virtual ~IReceiver() = default; + virtual void begin(uint16_t recv_port = DEFAULT_PORT) = 0; +}; + } // namespace art_net +using ArtnetReceiverInterface = art_net::IReceiver; + #endif // ARTNET_RECEIVER_TRAITS_H diff --git a/Artnet/Sender.h b/Artnet/Sender.h index 7fb3fc5..41ae3dc 100644 --- a/Artnet/Sender.h +++ b/Artnet/Sender.h @@ -7,11 +7,12 @@ #include "ArtNzs.h" #include "ArtTrigger.h" #include "ArtSync.h" +#include "SenderTraits.h" namespace art_net { template -class Sender_ +class Sender_ : virtual ISender_ { S* stream; Array packet; @@ -29,27 +30,27 @@ class Sender_ #endif // streaming artdmx packet - void setArtDmxData(const uint8_t* const data, uint16_t size) + void setArtDmxData(const uint8_t* const data, uint16_t size) override { art_dmx::setDataTo(this->packet.data(), data, size); } - void setArtDmxData(uint16_t ch, uint8_t data) + void setArtDmxData(uint16_t ch, uint8_t data) override { art_dmx::setDataTo(this->packet.data(), ch, data); } - void streamArtDmxTo(const String& ip, uint16_t universe15bit) + void streamArtDmxTo(const String& ip, uint16_t universe15bit) override { uint8_t net = (universe15bit >> 8) & 0x7F; uint8_t subnet = (universe15bit >> 4) & 0x0F; uint8_t universe = (universe15bit >> 0) & 0x0F; this->streamArtDmxTo(ip, net, subnet, universe, 0); } - void streamArtDmxTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe) + void streamArtDmxTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe) override { this->streamArtDmxTo(ip, net, subnet, universe, 0); } - void streamArtDmxTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t physical) + void streamArtDmxTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t physical) override { Destination dest {ip, net, subnet, universe}; uint32_t now = millis(); @@ -63,27 +64,27 @@ class Sender_ } // streaming artnzs packet - void setArtNzsData(const uint8_t* const data, uint16_t size) + void setArtNzsData(const uint8_t* const data, uint16_t size) override { art_nzs::setDataTo(this->packet.data(), data, size); } - void setArtNzsData(uint16_t ch, uint8_t data) + void setArtNzsData(uint16_t ch, uint8_t data) override { art_nzs::setDataTo(this->packet.data(), ch, data); } - void streamArtNzsTo(const String& ip, uint16_t universe15bit) + void streamArtNzsTo(const String& ip, uint16_t universe15bit) override { uint8_t net = (universe15bit >> 8) & 0x7F; uint8_t subnet = (universe15bit >> 4) & 0x0F; uint8_t universe = (universe15bit >> 0) & 0x0F; this->streamArtNzsTo(ip, net, subnet, universe, 0); } - void streamArtNzsTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe) + void streamArtNzsTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe) override { this->streamArtNzsTo(ip, net, subnet, universe, 0); } - void streamArtNzsTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t start_code) + void streamArtNzsTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t start_code) override { Destination dest {ip, net, subnet, universe}; uint32_t now = millis(); @@ -97,18 +98,18 @@ class Sender_ } // one-line artdmx sender - void sendArtDmx(const String& ip, uint16_t universe15bit, const uint8_t* const data, uint16_t size) + void sendArtDmx(const String& ip, uint16_t universe15bit, const uint8_t* const data, uint16_t size) override { uint8_t net = (universe15bit >> 8) & 0x7F; uint8_t subnet = (universe15bit >> 4) & 0x0F; uint8_t universe = (universe15bit >> 0) & 0x0F; this->sendArtDmx(ip, net, subnet, universe, 0, data, size); } - void sendArtDmx(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, const uint8_t* const data, uint16_t size) + void sendArtDmx(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, const uint8_t* const data, uint16_t size) override { this->sendArtDmx(ip, net, subnet, universe, 0, data, size); } - void sendArtDmx(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t physical, const uint8_t *data, uint16_t size) + void sendArtDmx(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t physical, const uint8_t *data, uint16_t size) override { Destination dest {ip, net, subnet, universe}; this->setArtDmxData(data, size); @@ -116,31 +117,31 @@ class Sender_ } // one-line artnzs sender - void sendArtNzs(const String& ip, uint16_t universe15bit, const uint8_t* const data, uint16_t size) + void sendArtNzs(const String& ip, uint16_t universe15bit, const uint8_t* const data, uint16_t size) override { uint8_t net = (universe15bit >> 8) & 0x7F; uint8_t subnet = (universe15bit >> 4) & 0x0F; uint8_t universe = (universe15bit >> 0) & 0x0F; this->sendArtNzs(ip, net, subnet, universe, data, size); } - void sendArtNzs(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, const uint8_t* const data, uint16_t size) + void sendArtNzs(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, const uint8_t* const data, uint16_t size) override { this->sendArtNzs(ip, net, subnet, universe, 0, data, size); } - void sendArtNzs(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t start_code, const uint8_t *data, uint16_t size) + void sendArtNzs(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t start_code, const uint8_t *data, uint16_t size) override { Destination dest {ip, net, subnet, universe}; this->setArtNzsData(data, size); this->sendArxNzsInternal(dest, start_code); } - void sendArtTrigger(const String& ip, uint16_t oem = 0, uint8_t key = 0, uint8_t subkey = 0, const uint8_t *payload = nullptr, uint16_t size = 512) + void sendArtTrigger(const String& ip, uint16_t oem = 0, uint8_t key = 0, uint8_t subkey = 0, const uint8_t *payload = nullptr, uint16_t size = 512) override { art_trigger::setDataTo(packet.data(), oem, key, subkey, payload, size); this->sendRawData(ip, DEFAULT_PORT, packet.data(), packet.size()); } - void sendArtSync(const String& ip) + void sendArtSync(const String& ip) override { art_sync::setMetadataTo(packet.data()); this->sendRawData(ip, DEFAULT_PORT, packet.data(), art_sync::PACKET_SIZE); @@ -189,14 +190,14 @@ class Sender_ }; template -class Sender : public Sender_ +class Sender : public ISender, public Sender_ { S stream; public: - void begin() + void begin(uint16_t send_port = DEFAULT_PORT) { - this->stream.begin(DEFAULT_PORT); + this->stream.begin(send_port); this->Sender_::attach(this->stream); } }; diff --git a/Artnet/SenderTraits.h b/Artnet/SenderTraits.h new file mode 100644 index 0000000..a2469f5 --- /dev/null +++ b/Artnet/SenderTraits.h @@ -0,0 +1,52 @@ +#pragma once +#ifndef ARTNET_SENDER_TRAITS_H +#define ARTNET_SENDER_TRAITS_H + +namespace art_net { + +struct ISender_ +{ + virtual ~ISender_() = default; + + // streaming artdmx packet + virtual void setArtDmxData(const uint8_t* const data, uint16_t size) = 0; + virtual void setArtDmxData(uint16_t ch, uint8_t data) = 0; + + virtual void streamArtDmxTo(const String& ip, uint16_t universe15bit) = 0; + virtual void streamArtDmxTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe) = 0; + virtual void streamArtDmxTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t physical) = 0; + + // streaming artnzs packet + virtual void setArtNzsData(const uint8_t* const data, uint16_t size) = 0; + virtual void setArtNzsData(uint16_t ch, uint8_t data) = 0; + + virtual void streamArtNzsTo(const String& ip, uint16_t universe15bit) = 0; + virtual void streamArtNzsTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe) = 0; + virtual void streamArtNzsTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t start_code) = 0; + + // one-line artdmx sender + virtual void sendArtDmx(const String& ip, uint16_t universe15bit, const uint8_t* const data, uint16_t size) = 0; + virtual void sendArtDmx(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, const uint8_t* const data, uint16_t size) = 0; + virtual void sendArtDmx(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t physical, const uint8_t *data, uint16_t size) = 0; + + // one-line artnzs sender + virtual void sendArtNzs(const String& ip, uint16_t universe15bit, const uint8_t* const data, uint16_t size) = 0; + virtual void sendArtNzs(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, const uint8_t* const data, uint16_t size) = 0; + virtual void sendArtNzs(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t start_code, const uint8_t *data, uint16_t size) = 0; + + virtual void sendArtTrigger(const String& ip, uint16_t oem = 0, uint8_t key = 0, uint8_t subkey = 0, const uint8_t *payload = nullptr, uint16_t size = 512) = 0; + + virtual void sendArtSync(const String& ip) = 0; +}; + +struct ISender : virtual ISender_ +{ + virtual ~ISender() = default; + virtual void begin(uint16_t send_port = DEFAULT_PORT) = 0; +}; + +} // namespace art_net + +using ArtnetSenderInterface = art_net::ISender; + +#endif // ARTNET_SENDER_TRAITS_H From 63a36db438b634e6ac95fe9849fa8b957562cdae Mon Sep 17 00:00:00 2001 From: Hideaki Tai Date: Wed, 15 Oct 2025 05:44:34 +0900 Subject: [PATCH 06/10] fix: do not use interface for avr boards (low memory) --- Artnet/Receiver.h | 66 ++++++++++++++++++++++++++--------------------- Artnet/Sender.h | 44 ++++++++++++++++++------------- 2 files changed, 63 insertions(+), 47 deletions(-) diff --git a/Artnet/Receiver.h b/Artnet/Receiver.h index a8e5bae..55118f7 100644 --- a/Artnet/Receiver.h +++ b/Artnet/Receiver.h @@ -23,7 +23,11 @@ static NoPrint no_log; } // namespace template +#ifndef ARDUINO_ARCH_AVR class Receiver_ : virtual IReceiver_ +#else +class Receiver_ +#endif { S *stream; Array packet; @@ -46,7 +50,7 @@ class Receiver_ : virtual IReceiver_ } #endif - OpCode parse() override + OpCode parse() { if (!isNetworkReady()) { return OpCode::NoPacket; @@ -141,7 +145,7 @@ class Receiver_ : virtual IReceiver_ } // subscribe artdmx packet for specified net, subnet, and universe - void subscribeArtDmxUniverse(uint8_t net, uint8_t subnet, uint8_t universe, const ArtDmxCallback& func) override + void subscribeArtDmxUniverse(uint8_t net, uint8_t subnet, uint8_t universe, const ArtDmxCallback& func) { if (net > 0x7F) { this->logger->println(F("net should be less than 0x7F")); @@ -160,57 +164,57 @@ class Receiver_ : virtual IReceiver_ } // subscribe artdmx packet for specified universe (15 bit) - void subscribeArtDmxUniverse(uint16_t universe, const ArtDmxCallback& func) override + void subscribeArtDmxUniverse(uint16_t universe, const ArtDmxCallback& func) { this->callback_art_dmx_universes.insert(std::make_pair(universe, func)); } // subscribe artnzs packet for specified universe (15 bit) - void subscribeArtNzsUniverse(uint16_t universe, const ArtNzsCallback& func) override + void subscribeArtNzsUniverse(uint16_t universe, const ArtNzsCallback& func) { this->callback_art_nzs_universes.insert(std::make_pair(universe, func)); } // subscribe artdmx packet for all universes - void subscribeArtDmx(const ArtDmxCallback& func) override + void subscribeArtDmx(const ArtDmxCallback& func) { this->callback_art_dmx = func; } // subscribe other packets - void subscribeArtSync(const ArtSyncCallback& func) override + void subscribeArtSync(const ArtSyncCallback& func) { this->callback_art_sync = func; } // subscribe art_trigger packet - void subscribeArtTrigger(const ArtTriggerCallback& func) override + void subscribeArtTrigger(const ArtTriggerCallback& func) { this->callback_art_trigger = func; } - void unsubscribeArtDmxUniverse(uint8_t net, uint8_t subnet, uint8_t universe) override + void unsubscribeArtDmxUniverse(uint8_t net, uint8_t subnet, uint8_t universe) { uint16_t u = ((uint16_t)net << 8) | ((uint16_t)subnet << 4) | (uint16_t)universe; this->unsubscribeArtDmxUniverse(u); } - void unsubscribeArtDmxUniverse(uint16_t universe) override + void unsubscribeArtDmxUniverse(uint16_t universe) { auto it = this->callback_art_dmx_universes.find(universe); if (it != this->callback_art_dmx_universes.end()) { this->callback_art_dmx_universes.erase(it); } } - void unsubscribeArtDmxUniverses() override + void unsubscribeArtDmxUniverses() { this->callback_art_dmx_universes.clear(); } - void unsubscribeArtDmx() override + void unsubscribeArtDmx() { this->callback_art_dmx = nullptr; } - void unsubscribeArtNzsUniverse(uint16_t universe) override + void unsubscribeArtNzsUniverse(uint16_t universe) { auto it = this->callback_art_nzs_universes.find(universe); if (it != this->callback_art_nzs_universes.end()) { @@ -218,23 +222,23 @@ class Receiver_ : virtual IReceiver_ } } - void unsubscribeArtSync() override + void unsubscribeArtSync() { this->callback_art_sync = nullptr; } - void unsubscribeArtTrigger() override + void unsubscribeArtTrigger() { this->callback_art_trigger = nullptr; } #ifdef FASTLED_VERSION - void forwardArtDmxDataToFastLED(uint8_t net, uint8_t subnet, uint8_t universe, CRGB* leds, uint16_t num) override + void forwardArtDmxDataToFastLED(uint8_t net, uint8_t subnet, uint8_t universe, CRGB* leds, uint16_t num) { uint16_t u = ((uint16_t)net << 8) | ((uint16_t)subnet << 4) | (uint16_t)universe; this->forwardArtDmxDataToFastLED(u, leds, num); } - void forwardArtDmxDataToFastLED(uint16_t universe, CRGB* leds, uint16_t num) override + void forwardArtDmxDataToFastLED(uint16_t universe, CRGB* leds, uint16_t num) { this->subscribeArtDmxUniverse(universe, [this, leds, num](const uint8_t* data, const uint16_t size, const ArtDmxMetadata &, const RemoteInfo &) { size_t n; @@ -260,47 +264,47 @@ class Receiver_ : virtual IReceiver_ #endif // https://art-net.org.uk/how-it-works/discovery-packets/artpollreply/ - void setArtPollReplyConfigOem(uint16_t oem) override + void setArtPollReplyConfigOem(uint16_t oem) { this->art_poll_reply_config.oem = oem; } - void setArtPollReplyConfigEstaMan(uint16_t esta_man) override + void setArtPollReplyConfigEstaMan(uint16_t esta_man) { this->art_poll_reply_config.esta_man = esta_man; } - void setArtPollReplyConfigStatus1(uint8_t status1) override + void setArtPollReplyConfigStatus1(uint8_t status1) { this->art_poll_reply_config.status1 = status1; } - void setArtPollReplyConfigStatus2(uint8_t status2) override + void setArtPollReplyConfigStatus2(uint8_t status2) { this->art_poll_reply_config.status2 = status2; } - void setArtPollReplyConfigShortName(const String &short_name) override + void setArtPollReplyConfigShortName(const String &short_name) { this->art_poll_reply_config.short_name = short_name; } - void setArtPollReplyConfigLongName(const String &long_name) override + void setArtPollReplyConfigLongName(const String &long_name) { this->art_poll_reply_config.long_name = long_name; } - void setArtPollReplyConfigNodeReport(const String &node_report) override + void setArtPollReplyConfigNodeReport(const String &node_report) { this->art_poll_reply_config.node_report = node_report; } - void setArtPollReplyConfigSwIn(size_t index, uint8_t sw_in) override + void setArtPollReplyConfigSwIn(size_t index, uint8_t sw_in) { if (index < 4) { this->art_poll_reply_config.sw_in[index] = sw_in; } } - void setArtPollReplyConfigSwIn(uint8_t sw_in[4]) override + void setArtPollReplyConfigSwIn(uint8_t sw_in[4]) { for (size_t i = 0; i < 4; ++i) { this->art_poll_reply_config.sw_in[i] = sw_in[i]; } } - void setArtPollReplyConfigSwIn(uint8_t sw_in_0, uint8_t sw_in_1, uint8_t sw_in_2, uint8_t sw_in_3) override + void setArtPollReplyConfigSwIn(uint8_t sw_in_0, uint8_t sw_in_1, uint8_t sw_in_2, uint8_t sw_in_3) { this->setArtPollReplyConfigSwIn(0, sw_in_0); this->setArtPollReplyConfigSwIn(1, sw_in_1); @@ -316,7 +320,7 @@ class Receiver_ : virtual IReceiver_ const String &long_name, const String &node_report, uint8_t sw_in[4] - ) override { + ) { this->setArtPollReplyConfigOem(oem); this->setArtPollReplyConfigEstaMan(esta_man); this->setArtPollReplyConfigStatus1(status1); @@ -326,12 +330,12 @@ class Receiver_ : virtual IReceiver_ this->setArtPollReplyConfigNodeReport(node_report); this->setArtPollReplyConfigSwIn(sw_in); } - void setArtPollReplyConfig(const ArtPollReplyConfig &cfg) override + void setArtPollReplyConfig(const ArtPollReplyConfig &cfg) { this->art_poll_reply_config = cfg; } - void setLogger(Print* logger) override + void setLogger(Print* logger) { this->logger = logger; } @@ -414,7 +418,11 @@ class Receiver_ : virtual IReceiver_ }; template +#ifndef ARDUINO_ARCH_AVR class Receiver : public IReceiver, public Receiver_ +#else +class Receiver : public Receiver_ +#endif { S stream; diff --git a/Artnet/Sender.h b/Artnet/Sender.h index 41ae3dc..f198a7e 100644 --- a/Artnet/Sender.h +++ b/Artnet/Sender.h @@ -12,7 +12,11 @@ namespace art_net { template +#ifndef ARDUINO_ARCH_AVR class Sender_ : virtual ISender_ +#else +class Sender_ +#endif { S* stream; Array packet; @@ -30,27 +34,27 @@ class Sender_ : virtual ISender_ #endif // streaming artdmx packet - void setArtDmxData(const uint8_t* const data, uint16_t size) override + void setArtDmxData(const uint8_t* const data, uint16_t size) { art_dmx::setDataTo(this->packet.data(), data, size); } - void setArtDmxData(uint16_t ch, uint8_t data) override + void setArtDmxData(uint16_t ch, uint8_t data) { art_dmx::setDataTo(this->packet.data(), ch, data); } - void streamArtDmxTo(const String& ip, uint16_t universe15bit) override + void streamArtDmxTo(const String& ip, uint16_t universe15bit) { uint8_t net = (universe15bit >> 8) & 0x7F; uint8_t subnet = (universe15bit >> 4) & 0x0F; uint8_t universe = (universe15bit >> 0) & 0x0F; this->streamArtDmxTo(ip, net, subnet, universe, 0); } - void streamArtDmxTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe) override + void streamArtDmxTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe) { this->streamArtDmxTo(ip, net, subnet, universe, 0); } - void streamArtDmxTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t physical) override + void streamArtDmxTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t physical) { Destination dest {ip, net, subnet, universe}; uint32_t now = millis(); @@ -64,27 +68,27 @@ class Sender_ : virtual ISender_ } // streaming artnzs packet - void setArtNzsData(const uint8_t* const data, uint16_t size) override + void setArtNzsData(const uint8_t* const data, uint16_t size) { art_nzs::setDataTo(this->packet.data(), data, size); } - void setArtNzsData(uint16_t ch, uint8_t data) override + void setArtNzsData(uint16_t ch, uint8_t data) { art_nzs::setDataTo(this->packet.data(), ch, data); } - void streamArtNzsTo(const String& ip, uint16_t universe15bit) override + void streamArtNzsTo(const String& ip, uint16_t universe15bit) { uint8_t net = (universe15bit >> 8) & 0x7F; uint8_t subnet = (universe15bit >> 4) & 0x0F; uint8_t universe = (universe15bit >> 0) & 0x0F; this->streamArtNzsTo(ip, net, subnet, universe, 0); } - void streamArtNzsTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe) override + void streamArtNzsTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe) { this->streamArtNzsTo(ip, net, subnet, universe, 0); } - void streamArtNzsTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t start_code) override + void streamArtNzsTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t start_code) { Destination dest {ip, net, subnet, universe}; uint32_t now = millis(); @@ -98,18 +102,18 @@ class Sender_ : virtual ISender_ } // one-line artdmx sender - void sendArtDmx(const String& ip, uint16_t universe15bit, const uint8_t* const data, uint16_t size) override + void sendArtDmx(const String& ip, uint16_t universe15bit, const uint8_t* const data, uint16_t size) { uint8_t net = (universe15bit >> 8) & 0x7F; uint8_t subnet = (universe15bit >> 4) & 0x0F; uint8_t universe = (universe15bit >> 0) & 0x0F; this->sendArtDmx(ip, net, subnet, universe, 0, data, size); } - void sendArtDmx(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, const uint8_t* const data, uint16_t size) override + void sendArtDmx(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, const uint8_t* const data, uint16_t size) { this->sendArtDmx(ip, net, subnet, universe, 0, data, size); } - void sendArtDmx(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t physical, const uint8_t *data, uint16_t size) override + void sendArtDmx(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t physical, const uint8_t *data, uint16_t size) { Destination dest {ip, net, subnet, universe}; this->setArtDmxData(data, size); @@ -117,31 +121,31 @@ class Sender_ : virtual ISender_ } // one-line artnzs sender - void sendArtNzs(const String& ip, uint16_t universe15bit, const uint8_t* const data, uint16_t size) override + void sendArtNzs(const String& ip, uint16_t universe15bit, const uint8_t* const data, uint16_t size) { uint8_t net = (universe15bit >> 8) & 0x7F; uint8_t subnet = (universe15bit >> 4) & 0x0F; uint8_t universe = (universe15bit >> 0) & 0x0F; this->sendArtNzs(ip, net, subnet, universe, data, size); } - void sendArtNzs(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, const uint8_t* const data, uint16_t size) override + void sendArtNzs(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, const uint8_t* const data, uint16_t size) { this->sendArtNzs(ip, net, subnet, universe, 0, data, size); } - void sendArtNzs(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t start_code, const uint8_t *data, uint16_t size) override + void sendArtNzs(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t start_code, const uint8_t *data, uint16_t size) { Destination dest {ip, net, subnet, universe}; this->setArtNzsData(data, size); this->sendArxNzsInternal(dest, start_code); } - void sendArtTrigger(const String& ip, uint16_t oem = 0, uint8_t key = 0, uint8_t subkey = 0, const uint8_t *payload = nullptr, uint16_t size = 512) override + void sendArtTrigger(const String& ip, uint16_t oem = 0, uint8_t key = 0, uint8_t subkey = 0, const uint8_t *payload = nullptr, uint16_t size = 512) { art_trigger::setDataTo(packet.data(), oem, key, subkey, payload, size); this->sendRawData(ip, DEFAULT_PORT, packet.data(), packet.size()); } - void sendArtSync(const String& ip) override + void sendArtSync(const String& ip) { art_sync::setMetadataTo(packet.data()); this->sendRawData(ip, DEFAULT_PORT, packet.data(), art_sync::PACKET_SIZE); @@ -190,7 +194,11 @@ class Sender_ : virtual ISender_ }; template +#ifndef ARDUINO_ARCH_AVR class Sender : public ISender, public Sender_ +#else +class Sender : public Sender_ +#endif { S stream; From 37a524e129dee5c5d3f8e0b9901a55eb87515cf7 Mon Sep 17 00:00:00 2001 From: Hideaki Tai Date: Wed, 15 Oct 2025 05:58:50 +0900 Subject: [PATCH 07/10] chore: requires ArxTypeTraits >= 0.3.2 --- examples/Multiple/switch_interface/switch_interface.ino | 5 ++++- library.json | 2 +- library.properties | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/Multiple/switch_interface/switch_interface.ino b/examples/Multiple/switch_interface/switch_interface.ino index d12ece3..20afd48 100644 --- a/examples/Multiple/switch_interface/switch_interface.ino +++ b/examples/Multiple/switch_interface/switch_interface.ino @@ -11,7 +11,10 @@ const IPAddress subnet(255, 255, 255, 0); const IPAddress ip_ether(192, 168, 0, 201); uint8_t mac[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB}; -std::unique_ptr artnet; +// To switch between ArtnetWiFi and ArtnetEther at runtime, use pointer to the interface +// std::unique_ptr artnet; // if you only need sender functions +// std::unique_ptr artnet; // if you only need receiver functions +std::unique_ptr artnet; // if you need both sender and receiver functions const String target_ip = "192.168.1.200"; uint8_t universe = 1; // 0 - 15 diff --git a/library.json b/library.json index 35200f8..919d0ea 100644 --- a/library.json +++ b/library.json @@ -17,6 +17,6 @@ "platforms": "*", "dependencies": { "hideakitai/ArxContainer": ">=0.6.0", - "hideakitai/ArxTypeTraits": "*" + "hideakitai/ArxTypeTraits": ">=0.3.2" } } diff --git a/library.properties b/library.properties index b3a97b3..e5a7ffb 100644 --- a/library.properties +++ b/library.properties @@ -7,4 +7,4 @@ paragraph=Art-Net Sender/Receiver for Arduino (Ethernet, WiFi) category=Communication url=https://github.com/hideakitai/ArtNet architectures=* -depends=ArxContainer (>=0.6.0), ArxTypeTraits +depends=ArxContainer (>=0.6.0), ArxTypeTraits (>=0.3.2) From 540178cd20593e7775985774f2858d417e89ff45 Mon Sep 17 00:00:00 2001 From: Hideaki Tai Date: Fri, 17 Oct 2025 02:12:40 +0900 Subject: [PATCH 08/10] ci: add build test for multiple interface examples --- .github/workflows/build.yml | 49 +++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b21855f..bfacece 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -385,3 +385,52 @@ jobs: - name: FastLED - source-url: https://github.com/JAndrassy/EthernetENC.git verbose: true + + build-multi: + name: "Build Test (Multiple): ${{matrix.board.arch}}:${{matrix.board.name}}" + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + board: + - vendor: esp8266 + arch: esp8266 + name: generic + - vendor: esp32 + arch: esp32 + name: esp32 + - vendor: esp32 + arch: esp32 + name: esp32s3 + - vendor: esp32 + arch: esp32 + name: esp32c3 + include: + - index: https://arduino.esp8266.com/stable/package_esp8266com_index.json + board: + vendor: esp8266 + - index: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json + board: + vendor: esp32 + steps: + - uses: actions/checkout@v4 + - uses: arduino/arduino-lint-action@v1 + with: + library-manager: update + - name: compile example sketchs + uses: arduino/compile-sketches@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fqbn: ${{matrix.board.vendor}}:${{matrix.board.arch}}:${{matrix.board.name}} + platforms: | + - name: ${{matrix.board.vendor}}:${{matrix.board.arch}} + source-url: ${{matrix.index}} + sketch-paths: | + - examples/Multiple + libraries: | + - source-path: ./ + - name: ArxContainer + - name: ArxTypeTraits + - name: WiFi + - name: Ethernet + verbose: true From d7d6d3c3794964a490ce832797110479dd433393 Mon Sep 17 00:00:00 2001 From: Hideaki Tai Date: Fri, 17 Oct 2025 02:33:49 +0900 Subject: [PATCH 09/10] docs: update README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d4f7ca..223d66f 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ - ETH (ESP32) - NativeEthernet (Teensy 4.1) - Supports a lot of boards which can use Ethernet or WiFi +- Supports using multiple network interfaces in the same sketch - Multiple receiver callbacks depending on universe - Mutilple destination streaming with sender - One-line send to desired destination @@ -84,7 +85,7 @@ Where `{interface}` is one of the following depending on the interface you want | ETH (ESP32) | ArtnetETH.h | ArtnetETH | | NativeEthernet| ArtnetNativeEther.h | ArtnetNativeEther | -Also, you can use multiple interfaces in the same sketch. +You can use multiple interfaces in the same sketch if your platform supports using multiple network interfaces simultaneously without conflicts (e.g., ESP32 can use both WiFi and Ethernet at the same time, but Raspberry Pi Pico W cannot). See [examples/Multiple](examples/Multiple) for more details. ### ArtnetReceiver From 970c03e41004fda0c4c3f8dc43bc9ffc594a2feb Mon Sep 17 00:00:00 2001 From: Hideaki Tai Date: Fri, 17 Oct 2025 02:34:06 +0900 Subject: [PATCH 10/10] chore: bump version v0.9.0 --- library.json | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 919d0ea..8fbcf1d 100644 --- a/library.json +++ b/library.json @@ -11,7 +11,7 @@ "url": "https://github.com/hideakitai", "maintainer": true }, - "version": "0.8.3", + "version": "0.9.0", "license": "MIT", "frameworks": "*", "platforms": "*", diff --git a/library.properties b/library.properties index e5a7ffb..8c3b95a 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ArtNet -version=0.8.3 +version=0.9.0 author=hideakitai maintainer=hideakitai sentence=Art-Net Sender/Receiver for Arduino (Ethernet, WiFi)