diff --git a/src/ossia/protocols/artnet/artnet_protocol.cpp b/src/ossia/protocols/artnet/artnet_protocol.cpp index de1dfe2fcdf..df711d418e8 100644 --- a/src/ossia/protocols/artnet/artnet_protocol.cpp +++ b/src/ossia/protocols/artnet/artnet_protocol.cpp @@ -9,9 +9,6 @@ #include -#define ARTNET_NODE_SHORT_NAME "libossia" -#define ARTNET_NODE_LONG_NAME "Libossia Artnet Protocol" - namespace ossia::net { dmx_buffer::dmx_buffer() @@ -22,9 +19,8 @@ dmx_buffer::dmx_buffer() dmx_buffer::~dmx_buffer() = default; -static constexpr int artnet_port_id = 0; artnet_protocol::artnet_protocol( - ossia::net::network_context_ptr ctx, const dmx_config& conf) + ossia::net::network_context_ptr ctx, const dmx_config& conf, std::string_view host) : dmx_protocol_base{ctx, conf} { if(conf.frequency < 1 || conf.frequency > 44) @@ -38,19 +34,27 @@ artnet_protocol::artnet_protocol( // update at higher frequencies => Work TODO // Do not specify ip address for now, artnet will choose one - m_node = artnet_new(nullptr, 1); +#if defined(_NDEBUG) + bool verbose = 0; +#else + bool verbose = 1; +#endif + m_node = artnet_new(host.data(), verbose); if(m_node == NULL) throw std::runtime_error("Artnet new failed"); + static constexpr int artnet_port_id = 0; artnet_set_port_type(m_node, artnet_port_id, ARTNET_ENABLE_OUTPUT, ARTNET_PORT_DMX); artnet_set_port_addr(m_node, artnet_port_id, ARTNET_OUTPUT_PORT, m_conf.universe); - artnet_set_short_name(m_node, ARTNET_NODE_SHORT_NAME); - artnet_set_long_name(m_node, ARTNET_NODE_LONG_NAME); + artnet_set_short_name(m_node, "libossia"); + artnet_set_long_name(m_node, "libossia artnet protocol"); artnet_set_node_type(m_node, ARTNET_RAW); artnet_dump_config(m_node); + std::fflush(stdout); + std::fflush(stderr); if(artnet_start(m_node) != ARTNET_EOK) throw std::runtime_error("Artnet Start failed"); } diff --git a/src/ossia/protocols/artnet/artnet_protocol.hpp b/src/ossia/protocols/artnet/artnet_protocol.hpp index e95661b68ab..e38bfff3223 100644 --- a/src/ossia/protocols/artnet/artnet_protocol.hpp +++ b/src/ossia/protocols/artnet/artnet_protocol.hpp @@ -11,7 +11,8 @@ struct dmx_config; class OSSIA_EXPORT artnet_protocol final : public dmx_protocol_base { public: - artnet_protocol(ossia::net::network_context_ptr, const dmx_config& conf); + artnet_protocol( + ossia::net::network_context_ptr, const dmx_config& conf, std::string_view host); ~artnet_protocol(); void set_device(ossia::net::device_base& dev) override; diff --git a/src/ossia/protocols/artnet/dmxusbpro_protocol.cpp b/src/ossia/protocols/artnet/dmxusbpro_protocol.cpp index c8b2236a7e3..28feed31eb7 100644 --- a/src/ossia/protocols/artnet/dmxusbpro_protocol.cpp +++ b/src/ossia/protocols/artnet/dmxusbpro_protocol.cpp @@ -6,9 +6,10 @@ namespace ossia::net { dmxusbpro_protocol::dmxusbpro_protocol( ossia::net::network_context_ptr ctx, const dmx_config& conf, - const ossia::net::serial_configuration& socket) + const ossia::net::serial_configuration& socket, int version) : dmx_protocol_base{ctx, conf} , m_port{ctx->context} + , m_version{version} { if(conf.frequency < 1 || conf.frequency > 44) throw std::runtime_error("DMX 512 update frequency must be in the range [1, 44] Hz"); @@ -28,6 +29,26 @@ dmxusbpro_protocol::dmxusbpro_protocol( m_timer.set_delay(std::chrono::milliseconds{ static_cast(1000.0f / static_cast(conf.frequency))}); + + switch(m_version) + { + case 1: + break; + case 2: { + + // SEND_DMX_PORT1: 0x06, + // SEND_DMX_PORT2: 0xCA, + // SET_API_KEY: 0x0D, + // SET_PORT_ASSIGNMENT: 0x93 + static constexpr unsigned char set_api_key[]{0x7E, 0x0D, 0x04, 0x00, 0xC9, + 0xA4, 0x03, 0xE4, 0xE7}; + boost::asio::write(m_port, boost::asio::buffer(set_api_key)); + + static constexpr unsigned char set_port_assignment[]{0x7E, 0x93, 0x02, 0x00, + 0x01, 0x01, 0xE7}; + boost::asio::write(m_port, boost::asio::buffer(set_port_assignment)); + } + } } dmxusbpro_protocol::~dmxusbpro_protocol() @@ -38,16 +59,20 @@ dmxusbpro_protocol::~dmxusbpro_protocol() void dmxusbpro_protocol::set_device(ossia::net::device_base& dev) { dmx_protocol_base::set_device(dev); - m_timer.start([this] { this->update_function(); }); + + int command = 0x06; + if(m_version == 2 && this->m_conf.universe >= 1) + command = 0xCA; + m_timer.start([this, command] { this->update_function(command); }); } -void dmxusbpro_protocol::update_function() +void dmxusbpro_protocol::update_function(uint8_t command) { try { // https://cdn.enttec.com/pdf/assets/70304/70304_DMX_USB_PRO_API.pdf // 1: 0x7E - // 1: message code (0x6 for DMX send) + // 1: message code: 0x6 for DMX send / 0xCA for DMX send on port 2 (DMX USB PRO Mk2) // 1: size LSB // 1: size MSB // N: message data: [ @@ -63,7 +88,7 @@ void dmxusbpro_protocol::update_function() constexpr uint8_t data_size_lsb = data_size & 0x00FF; constexpr uint8_t data_size_msb = (data_size & 0xFF00) >> 8; - unsigned char buf[buffer_size]{0x7E, 0x6, data_size_lsb, data_size_msb, 0}; + unsigned char buf[buffer_size]{0x7E, command, data_size_lsb, data_size_msb, 0}; for(uint32_t i = 0; i < channels; i++) buf[5 + i] = m_buffer.data[i]; diff --git a/src/ossia/protocols/artnet/dmxusbpro_protocol.hpp b/src/ossia/protocols/artnet/dmxusbpro_protocol.hpp index a79ac970348..c56085191a9 100644 --- a/src/ossia/protocols/artnet/dmxusbpro_protocol.hpp +++ b/src/ossia/protocols/artnet/dmxusbpro_protocol.hpp @@ -14,16 +14,17 @@ class OSSIA_EXPORT dmxusbpro_protocol final : public dmx_protocol_base public: dmxusbpro_protocol( ossia::net::network_context_ptr, const dmx_config& conf, - const ossia::net::serial_configuration& socket); + const ossia::net::serial_configuration& socket, int version); ~dmxusbpro_protocol(); void set_device(ossia::net::device_base& dev) override; private: - void update_function(); + void update_function(uint8_t command); boost::asio::serial_port m_port; + int m_version = 1; }; } #endif diff --git a/src/ossia/protocols/artnet/e131_protocol.cpp b/src/ossia/protocols/artnet/e131_protocol.cpp index a0ab6e6c9ef..1ec2779355a 100644 --- a/src/ossia/protocols/artnet/e131_protocol.cpp +++ b/src/ossia/protocols/artnet/e131_protocol.cpp @@ -11,7 +11,10 @@ #include #include +#include +namespace +{ #pragma pack(push, 1) struct e131_acn_root_layer { /* ACN Root Layer: 38 bytes */ @@ -62,56 +65,6 @@ enum class e131_option_t E131_OPT_PREVIEW = 7, }; -#pragma pack(pop) -static_assert(sizeof(e131_packet) == 638); - -namespace ossia::net -{ -static boost::asio::ip::address_v4 -e131_host(const dmx_config& conf, const ossia::net::socket_configuration& socket) -{ - if(conf.multicast) - { - return boost::asio::ip::address_v4(0xefff0000 | conf.universe); - } - else - { - return boost::asio::ip::address_v4::from_string(socket.host); - } -} - -e131_protocol::e131_protocol( - ossia::net::network_context_ptr ctx, const dmx_config& conf, - const ossia::net::socket_configuration& socket) - : dmx_protocol_base{ctx, conf} - , m_socket{e131_host(conf, socket), socket.port, ctx->context} -{ - if(conf.frequency < 1 || conf.frequency > 44) - throw std::runtime_error("DMX 512 update frequency must be in the range [1, 44] Hz"); - - m_socket.connect(); - - if(conf.multicast && !socket.host.empty()) - { - m_socket.m_socket.set_option(boost::asio::ip::multicast::outbound_interface( - boost::asio::ip::address_v4::from_string(socket.host))); - } - - m_timer.set_delay(std::chrono::milliseconds{ - static_cast(1000.0f / static_cast(conf.frequency))}); -} - -e131_protocol::~e131_protocol() -{ - stop_processing(); -} - -void e131_protocol::set_device(ossia::net::device_base& dev) -{ - dmx_protocol_base::set_device(dev); - m_timer.start([this] { this->update_function(); }); -} - /* Initialize an E1.31 packet using a universe and a number of slots */ static int e131_pkt_init(e131_packet* packet, const uint16_t universe, const uint16_t num_slots) @@ -174,6 +127,57 @@ e131_pkt_init(e131_packet* packet, const uint16_t universe, const uint16_t num_s return 0; } +#pragma pack(pop) +static_assert(sizeof(e131_packet) == 638); +} + +namespace ossia::net +{ +static boost::asio::ip::address_v4 +e131_host(const dmx_config& conf, const ossia::net::socket_configuration& socket) +{ + if(conf.multicast) + { + return boost::asio::ip::address_v4(0xefff0000 | conf.universe); + } + else + { + return boost::asio::ip::address_v4::from_string(socket.host); + } +} + +e131_protocol::e131_protocol( + ossia::net::network_context_ptr ctx, const dmx_config& conf, + const ossia::net::socket_configuration& socket) + : dmx_protocol_base{ctx, conf} + , m_socket{e131_host(conf, socket), socket.port, ctx->context} +{ + if(conf.frequency < 1 || conf.frequency > 44) + throw std::runtime_error("DMX 512 update frequency must be in the range [1, 44] Hz"); + + m_socket.connect(); + + if(conf.multicast && !socket.host.empty()) + { + m_socket.m_socket.set_option(boost::asio::ip::multicast::outbound_interface( + boost::asio::ip::address_v4::from_string(socket.host))); + } + + m_timer.set_delay(std::chrono::milliseconds{ + static_cast(1000.0f / static_cast(conf.frequency))}); +} + +e131_protocol::~e131_protocol() +{ + stop_processing(); +} + +void e131_protocol::set_device(ossia::net::device_base& dev) +{ + dmx_protocol_base::set_device(dev); + m_timer.start([this] { this->update_function(); }); +} + void e131_protocol::update_function() { static std::atomic_int seq = 0; @@ -200,6 +204,55 @@ void e131_protocol::update_function() } } +e131_input_protocol::e131_input_protocol( + ossia::net::network_context_ptr ctx, const dmx_config& conf, + const ossia::net::socket_configuration& socket) + : dmx_protocol_base{ctx, conf} + , m_socket{socket, ctx->context} +{ + if(conf.frequency < 1 || conf.frequency > 44) + throw std::runtime_error("DMX 512 update frequency must be in the range [1, 44] Hz"); + + m_socket.open(); +} + +e131_input_protocol::~e131_input_protocol() +{ + stop_processing(); +} + +void e131_input_protocol::set_device(ossia::net::device_base& dev) +{ + dmx_protocol_base::set_device(dev); + m_socket.receive( + [](const char* bytes, int sz) { std::cerr << (int)bytes[0] << "\n"; }); +} + +void e131_input_protocol::update_function() +{ + static std::atomic_int seq = 0; + try + { + e131_packet pkt; + e131_pkt_init(&pkt, this->m_conf.universe, 512); + + for(size_t pos = 0; pos < 512; pos++) + pkt.dmp.prop_val[pos + 1] = m_buffer.data[pos]; + pkt.frame.seq_number = seq.fetch_add(1, std::memory_order_relaxed); + + // m_socket.write(reinterpret_cast(&pkt), sizeof(pkt)); + + m_buffer.dirty = false; + } + catch(std::exception& e) + { + ossia::logger().error("write failure: {}", e.what()); + } + catch(...) + { + ossia::logger().error("write failure"); + } +} } #endif