Skip to content

Commit

Permalink
feat: add ArtNzs opcode
Browse files Browse the repository at this point in the history
  • Loading branch information
japhsc committed Jun 19, 2024
1 parent 007da61 commit 90e9c66
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 6 deletions.
88 changes: 88 additions & 0 deletions Artnet/ArtNzs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#pragma once
#ifndef ARTNET_ARTNZS_H
#define ARTNET_ARTNZS_H

#include "Common.h"
#include <stdint.h>
#include <stddef.h>

namespace art_net {
namespace art_nzs {

enum Index : uint16_t
{
ID = 0,
OP_CODE_L = 8,
OP_CODE_H = 9,
PROTOCOL_VER_H = 10,
PROTOCOL_VER_L = 11,
SEQUENCE = 12,
START_CODE = 13,
SUBUNI = 14,
NET = 15,
LENGTH_H = 16,
LENGTH_L = 17,
DATA = 18
};

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

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
// receiver
using CallbackMap = std::map<uint16_t, CallbackType>;
#else
// receiver
using CallbackMap = arx::stdx::map<uint16_t, CallbackType>;
#endif

inline Metadata generateMetadataFrom(const uint8_t *packet)
{
Metadata metadata;
metadata.sequence = packet[SEQUENCE];
metadata.start_code = packet[START_CODE];
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 start_code, 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[START_CODE] = start_code & 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_nzs::DATA, data, size);
}
inline void setDataTo(uint8_t *packet, const uint16_t ch, const uint8_t data)
{
packet[art_nzs::DATA + ch] = data;
}

} // namespace art_nzs
} // namespace art_net

using ArtNzsMetadata = art_net::art_nzs::Metadata;

#endif // ARTNET_ARTNZS_H
40 changes: 39 additions & 1 deletion Artnet/Receiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "Common.h"
#include "ArtDmx.h"
#include "ArtNzs.h"
#include "ArtPollReply.h"
#include "ArtTrigger.h"
#include "ArtSync.h"
Expand All @@ -18,6 +19,7 @@ class Receiver_

art_dmx::CallbackMap callback_art_dmx_universes;
art_dmx::CallbackType callback_art_dmx;
art_nzs::CallbackMap callback_art_nzs_universes;
art_sync::CallbackType callback_art_sync;
art_trigger::CallbackType callback_art_trigger;
ArtPollReplyConfig art_poll_reply_config;
Expand Down Expand Up @@ -81,6 +83,16 @@ class Receiver_
op_code = OpCode::Dmx;
break;
}
case OpCode::Nzs: {
art_nzs::Metadata metadata = art_nzs::generateMetadataFrom(this->packet.data());
for (auto& cb : this->callback_art_nzs_universes) {
if (this->getArtDmxUniverse15bit() == cb.first) {
cb.second(this->getArtDmxData(), size - HEADER_SIZE, metadata, remote_info);
}
}
op_code = OpCode::Nzs;
break;
}
case OpCode::Poll: {
this->sendArtPollReply(remote_info);
op_code = OpCode::Poll;
Expand Down Expand Up @@ -156,6 +168,14 @@ class Receiver_
this->callback_art_dmx_universes.insert(std::make_pair(universe, arx::function_traits<Fn>::cast(func)));
}

// subscribe artnzs packet for specified universe (15 bit)
template <typename Fn>
auto subscribeArtNzsUniverse(uint16_t universe, const Fn &func)
-> std::enable_if_t<arx::is_callable<Fn>::value>
{
this->callback_art_nzs_universes.insert(std::make_pair(universe, arx::function_traits<Fn>::cast(func)));
}

// subscribe artdmx packet for all universes
template <typename Fn>
auto subscribeArtDmx(const Fn &func)
Expand Down Expand Up @@ -200,6 +220,14 @@ class Receiver_
this->callback_art_dmx = nullptr;
}

void unsubscribeArtNzsUniverse(uint16_t universe)
{
auto it = this->callback_art_nzs_universes.find(universe);
if (it != this->callback_art_nzs_universes.end()) {
this->callback_art_nzs_universes.erase(it);
}
}

void unsubscribeArtSync()
{
this->callback_art_sync = nullptr;
Expand Down Expand Up @@ -299,8 +327,18 @@ class Receiver_
uint8_t my_mac[6];
this->macAddress(my_mac);

arx::stdx::map<uint16_t, bool> universes;

for (const auto &cb_pair : this->callback_art_dmx_universes) {
art_poll_reply::Packet reply = art_poll_reply::generatePacketFrom(my_ip, my_mac, cb_pair.first, this->art_poll_reply_config);
universes[cb_pair.first] = true;
}

for (const auto &cb_pair : this->callback_art_nzs_universes) {
universes[cb_pair.first] = true;
}

for (const auto &u_pair : universes) {
art_poll_reply::Packet reply = art_poll_reply::generatePacketFrom(my_ip, my_mac, u_pair.first, this->art_poll_reply_config);
this->stream->beginPacket(remote.ip, DEFAULT_PORT);
this->stream->write(reply.b, sizeof(art_poll_reply::Packet));
this->stream->endPacket();
Expand Down
80 changes: 75 additions & 5 deletions Artnet/Sender.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "Common.h"
#include "ArtDmx.h"
#include "ArtNzs.h"
#include "ArtTrigger.h"
#include "ArtSync.h"

Expand All @@ -15,7 +16,8 @@ class Sender_
S* stream;
Array<PACKET_SIZE> packet;
art_dmx::LastSendTimeMsMap last_send_times;
art_dmx::SequenceMap sequences;
art_dmx::SequenceMap dmx_sequences;
art_dmx::SequenceMap nzs_sequences;

public:
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
Expand Down Expand Up @@ -60,6 +62,40 @@ class Sender_
}
}

// streaming artnzs packet
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)
{
art_nzs::setDataTo(this->packet.data(), ch, data);
}

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)
{
this->streamArtNzsTo(ip, net, subnet, universe, 0, 0);
}
void streamArtNzsTo(const String& ip, uint8_t net, uint8_t subnet, uint8_t universe, uint8_t start_code)
{
art_dmx::Destination dest {ip, net, subnet, universe};
uint32_t now = millis();
if (this->last_send_times.find(dest) == this->last_send_times.end()) {
this->last_send_times.insert(std::make_pair(dest, uint32_t(0)));
}
if (now >= this->last_send_times[dest] + DEFAULT_INTERVAL_MS) {
this->sendArxNzsInternal(dest, start_code);
this->last_send_times[dest] = now;
}
}

// one-line artdmx sender
void sendArtDmx(const String& ip, uint16_t universe15bit, const uint8_t* const data, uint16_t size)
{
Expand All @@ -79,6 +115,25 @@ class Sender_
this->sendArxDmxInternal(dest, physical);
}

// one-line artnzs sender
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)
{
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)
{
art_dmx::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)
{
art_trigger::setDataTo(packet.data(), oem, key, subkey, payload, size);
Expand All @@ -104,12 +159,27 @@ class Sender_
return;
}
#endif
if (this->sequences.find(dest) == this->sequences.end()) {
this->sequences.insert(std::make_pair(dest, uint8_t(0)));
if (this->dmx_sequences.find(dest) == this->dmx_sequences.end()) {
this->dmx_sequences.insert(std::make_pair(dest, uint8_t(0)));
}
art_dmx::setMetadataTo(this->packet.data(), this->dmx_sequences[dest], physical, dest.net, dest.subnet, dest.universe);
this->sendRawData(dest.ip, DEFAULT_PORT, this->packet.data(), this->packet.size());
this->dmx_sequences[dest] = (this->dmx_sequences[dest] + 1) % 256;
}

void sendArxNzsInternal(const art_dmx::Destination &dest, uint8_t start_code)
{
#ifdef ARTNET_ENABLE_WIFI
if (!isNetworkReady()) {
return;
}
#endif
if (this->nzs_sequences.find(dest) == this->nzs_sequences.end()) {
this->nzs_sequences.insert(std::make_pair(dest, uint8_t(0)));
}
art_dmx::setMetadataTo(this->packet.data(), this->sequences[dest], physical, dest.net, dest.subnet, dest.universe);
art_nzs::setMetadataTo(this->packet.data(), this->nzs_sequences[dest], start_code, dest.net, dest.subnet, dest.universe);
this->sendRawData(dest.ip, DEFAULT_PORT, this->packet.data(), this->packet.size());
this->sequences[dest] = (this->sequences[dest] + 1) % 256;
this->nzs_sequences[dest] = (this->nzs_sequences[dest] + 1) % 256;
}

void sendRawData(const String& ip, uint16_t port, const uint8_t* const data, size_t size)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ If you have already installed this library before v0.3.0, please follow:

- Supports following protocols:
- ArtDmx
- ArtNzs
- ArtPoll/ArtPollReply
- ArtTrigger
- ArtSync
Expand Down

0 comments on commit 90e9c66

Please sign in to comment.