Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ArtNzs opcode #106

Merged
merged 2 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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::Nzs) >> 0) & 0x00FF;
packet[OP_CODE_H] = (static_cast<uint16_t>(OpCode::Nzs) >> 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_nzs::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
Loading