OpenLCP/platform/qt/sacn/qsacnnode.cpp

303 lines
7.6 KiB
C++
Raw Normal View History

#include "qsacnnode.h"
#include <QDebug>
2021-09-06 07:02:22 -04:00
#include <QMetaEnum>
#include <QNetworkDatagram>
2021-07-30 14:40:03 -04:00
#include <QNetworkInterface>
2021-07-30 14:40:03 -04:00
/**
* @brief QSacnNode::QSacnNode
* @param parent
* @param cid
* @param fctn
2021-07-30 14:40:03 -04:00
*/
QSacnNode::QSacnNode(QObject *parent, QUuid cid, QString fctn, bool ipv4, bool ipv6)
: Component(UUID::uuid(cid.toString().toStdString()), fctn.toStdString(), ipv4, ipv6)
2022-12-09 21:00:38 -05:00
, QObject(parent)
, rx_socket_(new QUdpSocket(this))
, tx_socket_(new QUdpSocket(this))
{
2022-12-09 21:00:38 -05:00
rx_socket_->bind(QHostAddress::AnyIPv4, sACN::ACN_SDT_MULTICAST_PORT);
tx_socket_->bind(QHostAddress::AnyIPv4);
2022-12-09 21:00:38 -05:00
connect(rx_socket_, &QUdpSocket::readyRead,
2021-08-06 12:14:29 -04:00
this, &QSacnNode::udpReceive);
2021-09-07 09:15:11 -04:00
sACN::Receiver::onDiscovered([this](){ emit discoveryUpdates(); });
}
/**
* @brief QSacnNode::~QSacnNode
*/
QSacnNode::~QSacnNode()
{
if (Receiver::discoveryEnabled())
QSacnNode::unsubscribe(sACN::E131_DISCOVERY_UNIVERSE);
2022-12-04 10:34:57 -05:00
foreach (const auto num, rx_universes.keys())
QSacnNode::unsubscribe(num);
2022-12-04 10:34:57 -05:00
foreach (const auto num, tx_universes.keys())
QSacnNode::terminate(num);
}
void QSacnNode::setIPv4(const bool enable)
{
Node::setIPv4(enable);
QList<QHostAddress> groups;
foreach (const auto & universe, rx_universes)
groups.append(IPv4MulticastAddress(universe->number()));
if (discoveryEnabled())
groups.append(IPv4MulticastAddress(sACN::E131_DISCOVERY_UNIVERSE));
if (enable)
{
qDebug() << "Enabling IPv4";
foreach (const auto & ip, groups)
{
qDebug() << "Joining IGMP Group" << ip.toString();
for (QNetworkInterface &iface : QNetworkInterface::allInterfaces())
2022-12-09 21:00:38 -05:00
rx_socket_->joinMulticastGroup(ip, iface);
}
}
else
{
qDebug() << "Disabling IPv4";
foreach (const auto & ip, groups)
{
qDebug() << "Leaving IGMP Group" << ip.toString();
for (QNetworkInterface &iface : QNetworkInterface::allInterfaces())
2022-12-09 21:00:38 -05:00
rx_socket_->leaveMulticastGroup(ip, iface);
}
}
}
void QSacnNode::setIPv6(const bool enable)
{
Node::setIPv6(enable);
QList<QHostAddress> groups;
foreach (const auto & universe, rx_universes)
groups.append(IPv6MulticastAddress(universe->number()));
if (discoveryEnabled())
groups.append(IPv6MulticastAddress(sACN::E131_DISCOVERY_UNIVERSE));
if (enable)
{
qDebug() << "Enabling IPv6";
foreach (const auto & ip, groups)
{
qDebug() << "Joining MLD Group" << ip.toString();
for (QNetworkInterface &iface : QNetworkInterface::allInterfaces())
2022-12-09 21:00:38 -05:00
rx_socket_->joinMulticastGroup(ip, iface);
}
}
else
{
qDebug() << "Disabling IPv6";
foreach (const auto & ip, groups)
{
qDebug() << "Leaving MLD Group" << ip.toString();
for (QNetworkInterface &iface : QNetworkInterface::allInterfaces())
2022-12-09 21:00:38 -05:00
rx_socket_->leaveMulticastGroup(ip, iface);
}
}
}
2021-07-30 14:40:03 -04:00
/**
* @brief QSacnNode::subscribe
* @param num
*/
void QSacnNode::subscribe(const uint16_t num)
{
if (Receiver::universe(num)) // already subscribed
return;
switch (num) {
case sACN::E131_DISCOVERY_UNIVERSE:
{
if (discoveryEnabled())
return;
qDebug() << "Enabling sACN Discovery";
}
break;
default:
2021-09-06 07:02:22 -04:00
{
qDebug() << "Subscribing to universe" << QString::number(num);
Receiver::subscribe(num);
rx_universes.emplace(num, new QSacnUniverse(this, Receiver::universe(num)));
emit subscribing(rx_universes.value(num));
}
break;
}
if (enable_IPv4)
{
qDebug() << "Joining IGMP Group" << IPv4MulticastAddress(num).toString();
for (QNetworkInterface &iface : QNetworkInterface::allInterfaces())
2022-12-09 21:00:38 -05:00
rx_socket_->joinMulticastGroup(IPv4MulticastAddress(num), iface);
}
if (enable_IPv6)
{
qDebug() << "Joining MLD Group" << IPv6MulticastAddress(num).toString();
for (QNetworkInterface &iface : QNetworkInterface::allInterfaces())
2022-12-09 21:00:38 -05:00
rx_socket_->joinMulticastGroup(IPv6MulticastAddress(num), iface);
}
}
2021-07-30 14:40:03 -04:00
/**
* @brief QSacnNode::unsubscribe
* @param num
*/
void QSacnNode::unsubscribe(const uint16_t num)
{
switch (num) {
case sACN::E131_DISCOVERY_UNIVERSE:
{
if (!discoveryEnabled())
return;
qDebug() << "Disabling sACN Discovery";
}
break;
default:
{
if (Receiver::universe(num)) {
qDebug() << "Unsubscribing from universe " << QString::number(num);
emit unsubscribing(rx_universes.value(num));
rx_universes.take(num)->deleteLater();
Receiver::unsubscribe(num);
}
}
break;
}
if (enable_IPv4)
{
qDebug() << "Leaving IGMP Group" << IPv4MulticastAddress(num).toString();
for (QNetworkInterface &iface : QNetworkInterface::allInterfaces())
2022-12-09 21:00:38 -05:00
rx_socket_->leaveMulticastGroup(IPv4MulticastAddress(num), iface);
}
if (enable_IPv6)
{
qDebug() << "Leaving MLD Group" << IPv6MulticastAddress(num).toString();
for (QNetworkInterface &iface : QNetworkInterface::allInterfaces())
2022-12-09 21:00:38 -05:00
rx_socket_->leaveMulticastGroup(IPv6MulticastAddress(num), iface);
}
}
/**
* @brief QSacnNode::create
* @param num
*/
void QSacnNode::create(const uint16_t num)
{
2021-09-08 16:14:39 -04:00
if (Source::universe(num)) // already created
return;
2022-12-02 13:08:08 -05:00
qDebug() << "Creating universe " << QString::number(num);
Source::create(num);
2021-09-06 07:02:22 -04:00
tx_universes.emplace(num, new QSacnUniverse(this, Source::universe(num)));
emit creating(tx_universes.value(num));
}
/**
* @brief QSacnNode::terminate
* @param num
*/
void QSacnNode::terminate(const uint16_t num)
{
if (Source::universe(num)) {
2021-09-06 07:02:22 -04:00
qDebug() << "Terminating universe " << QString::number(num);
Source::terminate(num);
2021-09-06 07:02:22 -04:00
emit terminating(tx_universes.value(num));
delete tx_universes.take(num);
}
}
2022-12-04 10:36:37 -05:00
2021-07-30 14:40:03 -04:00
/**
* @brief QSacnNode::UdpPayloadReceiver
*/
2021-08-06 12:14:29 -04:00
void QSacnNode::udpReceive()
{
2022-12-09 21:00:38 -05:00
while (rx_socket_->hasPendingDatagrams())
2022-12-02 13:08:08 -05:00
{
2022-12-09 21:00:38 -05:00
auto datagram = rx_socket_->receiveDatagram();
2022-12-02 13:08:08 -05:00
// expecting IANA registered Session Data Transport traffic
if (datagram.destinationPort() != sACN::ACN_SDT_MULTICAST_PORT)
return;
// only receive over configured protocols
switch (datagram.senderAddress().protocol()) {
2022-12-09 21:00:38 -05:00
case QUdpSocket::IPv4Protocol:
if (!enable_IPv4)
return;
break;
2022-12-09 21:00:38 -05:00
case QUdpSocket::IPv6Protocol:
if (!enable_IPv6)
return;
break;
default:
return;
}
// wrap a PDU i/o stream around the QNetworkDatagram data buffer
auto data = datagram.data();
2023-04-02 13:24:55 -04:00
auto stream = std::make_shared<bufferstream>(
reinterpret_cast<uint8_t*>(data.data()), data.length());
UdpPayloadReceiver(stream);
}
}
2021-09-06 07:02:22 -04:00
/**
* @brief QSacnNode::sendUDP
2021-09-06 07:02:22 -04:00
* @param stream
* @param ip
*/
void QSacnNode::sendUDP(const ACN::PDU::Stream stream,
2022-12-09 21:00:38 -05:00
const ACN::SDT::UDP::ipAddress& ip) const
{
QHostAddress addr;
switch (ip.type) {
case ACN::SDT::SDT_ADDR_IPV4:
if (!enable_IPv4)
return;
addr = QHostAddress(ip.address.ipv4.value);
break;
case ACN::SDT::SDT_ADDR_IPV6:
if (!enable_IPv6)
return;
addr = QHostAddress(ip.address.ipv6.bytes);
break;
default:
return;
}
2022-12-09 21:00:38 -05:00
tx_socket_->writeDatagram(reinterpret_cast<char*>(stream->base()), stream->size(), addr, ip.port);
}
2021-09-07 09:15:11 -04:00
/**
* @brief QSacnNode::sendTCP
* @param stream
* @param ip
*/
void QSacnNode::sendTCP(const ACN::PDU::Stream stream,
2022-12-09 21:00:38 -05:00
const ACN::SDT::UDP::ipAddress& ip) const
{
Q_UNUSED(stream)
Q_UNUSED(ip)
qDebug() << "sACN uses UDP only. Stop trying to send TCP!";
}