1
0
Fork 0
OpenLCP/platform/qt/qsacnnode.cpp

180 lines
4.2 KiB
C++

#include "qsacnnode.h"
#include <QDebug>
#include <QMetaEnum>
#include <QNetworkDatagram>
#include <QNetworkInterface>
/**
* @brief QSacnNode::QSacnNode
* @param parent
* @param cid
*/
QSacnNode::QSacnNode(QObject *parent, QUuid cid)
: Component(UUID::uuid(cid.toString().toStdString()))
, QUdpSocket(parent)
{
fctn_ = "OpenLCP QSacnNode";
bind(QHostAddress::AnyIPv4, sACN::ACN_SDT_MULTICAST_PORT);
connect(this, &QUdpSocket::readyRead,
this, &QSacnNode::udpReceive);
sACN::Receiver::onDiscovered([this](){ emit discoveryUpdates(); });
}
/**
* @brief QSacnNode::~QSacnNode
*/
QSacnNode::~QSacnNode()
{
auto rx_list = rx_universes.keys();
for (const auto & num : rx_list)
QSacnNode::unsubscribe(num);
auto tx_list = tx_universes.keys();
for (const auto & num : tx_list)
QSacnNode::terminate(num);
}
/**
* @brief QSacnNode::subscribe
* @param num
*/
void QSacnNode::subscribe(const uint16_t num)
{
if (Receiver::universe(num)) // already subscribed
return;
if (num != sACN::E131_DISCOVERY_UNIVERSE)
{
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));
}
for (QNetworkInterface &iface : QNetworkInterface::allInterfaces())
joinMulticastGroup(IPv4MulticastAddress(num), iface);
for (QNetworkInterface &iface : QNetworkInterface::allInterfaces())
joinMulticastGroup(IPv6MulticastAddress(num), iface);
}
/**
* @brief QSacnNode::unsubscribe
* @param num
*/
void QSacnNode::unsubscribe(const uint16_t num)
{
for (QNetworkInterface &iface : QNetworkInterface::allInterfaces())
leaveMulticastGroup(IPv4MulticastAddress(num), iface);
for (QNetworkInterface &iface : QNetworkInterface::allInterfaces())
leaveMulticastGroup(IPv6MulticastAddress(num), iface);
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);
}
}
/**
* @brief QSacnNode::create
* @param num
*/
void QSacnNode::create(const uint16_t num)
{
if (Source::universe(num)) // already created
return;
Source::create(num);
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)) {
qDebug() << "Terminating universe " << QString::number(num);
Source::terminate(num);
emit terminating(tx_universes.value(num));
tx_universes.take(num)->deleteLater();
}
}
/**
* @brief QSacnNode::UdpPayloadReceiver
*/
void QSacnNode::udpReceive()
{
while (hasPendingDatagrams()) {
QNetworkDatagram datagram = receiveDatagram();
// Expecting IANA registered Session Data Transport traffic
if (datagram.destinationPort() != sACN::ACN_SDT_MULTICAST_PORT)
return;
// wrap a PDU io stream around the QNetworkDatagram data buffer
auto stream = std::make_shared<ACN::PDU::pdu_stream>(
reinterpret_cast<uint8_t*>(datagram.data().data()),
datagram.data().length());
UdpPayloadReceiver(stream);
}
}
/**
* @brief QSacnNode::rlpSend
* @param stream
* @param ip
*/
void QSacnNode::rlpSend(const ACN::PDU::Stream stream,
const ACN::SDT::UDP::ipAddress& ip)
{
QHostAddress addr;
switch (ip.type) {
case ACN::SDT::SDT_ADDR_IPV4:
addr = QHostAddress(ip.address.ipv4.value);
break;
case ACN::SDT::SDT_ADDR_IPV6:
addr = QHostAddress(ip.address.ipv6.bytes);
break;
default:
return;
}
writeDatagram(reinterpret_cast<char*>(stream->base()), stream->size(),
addr, ip.port);
}
/**
* @brief QSacnNode::universe
* @param u
* @return
*/
QSacnUniverse* QSacnNode::universe(const uint16_t u)
{
return rx_universes.value(u);
}
/**
* @brief QSacnNode::source
* @param u
* @return
*/
QSacnUniverse *QSacnNode::source(const uint16_t u)
{
return tx_universes.value(u);
}