1
0
Fork 0

support discovering available sACN universes

This commit is contained in:
Kevin Matz 2021-06-02 09:29:27 -04:00
parent 15b611983a
commit 50f29808ef
5 changed files with 242 additions and 3 deletions

View File

@ -33,6 +33,7 @@ set(SOURCE_FILES
dmx/universe.h
sacn/data.cpp
sacn/data.h
sacn/extended.cpp
sacn/extended.h
sacn/receiver.cpp
sacn/receiver.h

103
sacn/extended.cpp Normal file
View File

@ -0,0 +1,103 @@
/*
extended.cpp
Copyright (c) 2021 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "extended.h"
namespace SACN {
namespace EXTENDED {
frame_sync_header::frame_sync_header(PDU::Stream stream) {
sequence_number = stream->read8();
sync_address = stream->read16();
stream->read(reserved, sizeof(reserved));
if (stream->gcount() != sizeof(reserved))
stream->setstate(stream->rdstate() | std::ios_base::failbit);
}
frame_discovery_header::frame_discovery_header(PDU::Stream stream) {
stream->read(source_name, sizeof(source_name));
if (stream->gcount() != sizeof(source_name))
stream->setstate(stream->rdstate() | std::ios_base::failbit);
stream->read(reserved, sizeof(reserved));
if (stream->gcount() != sizeof(reserved))
stream->setstate(stream->rdstate() | std::ios_base::failbit);
}
Pdu::Pdu(PDU::Stream stream)
: PDU::Pdu(stream, 4) // vectors are 4 octets
{
if (stream->fail()) return;
if (!buffer_->good()) return;
if (flags_.hasHeader)
switch(vector()) {
case VECTOR_E131_EXTENDED_SYNCHRONIZATION:
setHeader(new frame_sync_header(buffer_));
break;
case VECTOR_E131_EXTENDED_DISCOVERY:
setHeader(new frame_discovery_header(buffer_));
break;
default:
break;
}
}
namespace DISCOVERY {
discovery_list_header::discovery_list_header(PDU::Stream stream) {
page = stream->read8();
last_page = stream->read8();
}
Pdu::Pdu(PDU::Stream stream)
: PDU::Pdu(stream, 4) // vectors are 4 octets
{
if (stream->fail()) return;
if (!buffer_->good()) return;
if (flags_.hasHeader)
setHeader(new discovery_list_header(buffer_));
}
/**
Construct a Universe Source from an sACN discovery layer PDU
*/
DiscoveredUniverse::DiscoveredUniverse(const std::shared_ptr<EXTENDED::DISCOVERY::Pdu> pdu) {
auto root_header = (RLP::rlp_header*)pdu->parent()->parent()->header();
cid_ = root_header->cid;
auto frame_header = (EXTENDED::frame_discovery_header*)pdu->parent()->header();
description_ = std::string((char*)frame_header->source_name);
universe_ = pdu->buffer()->read16();
}
} // DISCOVERY
} // EXTENDED
} // SACN

View File

@ -24,6 +24,7 @@
#pragma once
#include "sacn.h"
#include <functional>
namespace SACN {
using namespace ACN;
@ -37,6 +38,7 @@ struct frame_sync_header : PDU::pdu_header {
uint8_t sequence_number;
uint16_t sync_address;
uint8_t reserved[2];
frame_sync_header(PDU::Stream);
};
@ -44,14 +46,56 @@ struct frame_sync_header : PDU::pdu_header {
struct frame_discovery_header : PDU::pdu_header {
uint8_t source_name[64];
uint8_t reserved[4];
frame_discovery_header(PDU::Stream);
};
class Pdu
: public PDU::Pdu
{
public:
Pdu(PDU::Stream);
};
namespace DISCOVERY {
// Table 8-9: E1.31 Universe Discovery Packet Universe Discovery Layer
struct discovery_list_header : PDU::pdu_header {
uint8_t page;
uint8_t last_page;
discovery_list_header(PDU::Stream);
};
class Pdu
: public PDU::Pdu
{
public:
Pdu(PDU::Stream);
};
/**
universe metadata
*/
class DiscoveredUniverse
{
public:
DiscoveredUniverse(const std::shared_ptr<EXTENDED::DISCOVERY::Pdu>);
const UUID::uuid cid() const {return cid_;};
const std::string description() const {return description_;}
const uint16_t universe() const {return universe_;}
private:
UUID::uuid cid_;
std::string description_;
uint16_t universe_;
};
using Watcher = std::function<void(std::shared_ptr<DiscoveredUniverse>)>;
} // DISCOVERY
} // EXTENDED
} // SACN

View File

@ -23,7 +23,6 @@
*/
#include "receiver.h"
#include "data.h"
namespace SACN {
@ -56,11 +55,29 @@ SACN::Universe * Receiver::universe(uint16_t universe) {
return 0;
}
void Receiver::discoveryStart() {
subscribe(SACN::E131_DISCOVERY_UNIVERSE);
}
void Receiver::discoveryStop() {
unsubscribe(SACN::E131_DISCOVERY_UNIVERSE);
}
/**
register a discovery consumer callback function
@param const Watcher something that wants to know about available universes.
*/
void Receiver::onDiscovered(const EXTENDED::DISCOVERY::Watcher cb) {
discoveryCallbacks_.push_back(cb);
}
/**
Receive VECTOR_ROOT_E131_DATA vector'd packets.
@param pdu is a shared pointer to the PDU
@param root is a shared pointer to the PDU
*/
void Receiver::rootDataHandler(std::shared_ptr<RLP::Pdu> root) {
auto block = PDU::readBlock<DATA::Pdu>(root->buffer(), root);
@ -82,6 +99,70 @@ void Receiver::rootDataHandler(std::shared_ptr<RLP::Pdu> root) {
}
/**
Receive VECTOR_ROOT_E131_EXTENDED vector'd packets.
@param root is a shared pointer to the PDU
*/
void Receiver::rootExtendedHandler(std::shared_ptr<RLP::Pdu> root) {
auto block = PDU::readBlock<EXTENDED::Pdu>(root->buffer(), root);
if (root->buffer()->fail())
return;
for(auto const &frame : *block) {
switch(frame->vector()) {
// 6.3 E1.31 Synchronization Packet Framing Layer
case VECTOR_E131_EXTENDED_SYNCHRONIZATION:
syncPacketHandler(frame);
break;
// 6.4 E1.31 Universe Discovery Packet Framing Layer
case VECTOR_E131_EXTENDED_DISCOVERY:
discoveryPacketHandler(frame);
break;
default:
break;
}
}
}
void Receiver::discoveryPacketHandler(std::shared_ptr<EXTENDED::Pdu> frame) {
auto block = PDU::readBlock<EXTENDED::DISCOVERY::Pdu>(frame->buffer(), frame);
if (frame->buffer()->fail())
return;
for(auto const &pdu : *block) {
// 8 Universe Discovery Layer
// Universe Discovery data only appears in E1.31 Universe Discovery
// Packets and shall not be included in E1.31 Data Packets or E1.31
// Synchronization Packets.
switch(pdu->vector()) {
case VECTOR_UNIVERSE_DISCOVERY_UNIVERSE_LIST:
discoveryListHanlder(pdu);
break;
default:
break;
}
}
}
void Receiver::discoveryListHanlder(std::shared_ptr<EXTENDED::DISCOVERY::Pdu> pdu) {
// header may be inherited. check that one exists
if (!pdu->header())
return;
while(pdu->buffer()->good()) {
auto found = std::shared_ptr<EXTENDED::DISCOVERY::DiscoveredUniverse>
(new EXTENDED::DISCOVERY::DiscoveredUniverse(pdu));
if (pdu->buffer()->fail()) break;
if (!pdu->buffer()->good()) break;
for (const auto &cb : discoveryCallbacks_)
cb(found);
}
}
/**
Receive `VECTOR_ROOT_E131_DATA -> VECTOR_E131_DATA_PACKET` vector'd packets.

View File

@ -24,9 +24,11 @@
#pragma once
#include "data.h"
#include "extended.h"
#include "sacn.h"
#include "universe.h"
#include <unordered_map>
#include <vector>
namespace SACN {
@ -39,16 +41,24 @@ public:
virtual void unsubscribe(const uint16_t);
SACN::Universe * universe(uint16_t universe);
void discoveryStart();
void discoveryStop();
void onDiscovered(const EXTENDED::DISCOVERY::Watcher);
protected:
// process data frames
void rootDataHandler(std::shared_ptr<RLP::Pdu>);
void dataPacketHandler(std::shared_ptr<DATA::Pdu>);
// process extended frames
void rootExtendedHandler(std::shared_ptr<RLP::Pdu>) {};
void rootExtendedHandler(std::shared_ptr<RLP::Pdu>);
void syncPacketHandler(std::shared_ptr<EXTENDED::Pdu>) {};
void discoveryPacketHandler(std::shared_ptr<EXTENDED::Pdu>);
void discoveryListHanlder(std::shared_ptr<EXTENDED::DISCOVERY::Pdu>);
private:
std::unordered_map <uint16_t, SACN::Universe *> universes_;
std::vector<EXTENDED::DISCOVERY::Watcher> discoveryCallbacks_;
};
};