LLRP wire format
This commit is contained in:
parent
2c304859b9
commit
fa13e03ffa
214
rdmnet/llrp.cpp
214
rdmnet/llrp.cpp
|
@ -23,10 +23,44 @@
|
|||
*/
|
||||
|
||||
#include "llrp.h"
|
||||
#include "rdmnet.h"
|
||||
|
||||
namespace RDMnet {
|
||||
namespace LLRP {
|
||||
|
||||
/**
|
||||
* @brief llrp_data::iStream
|
||||
*/
|
||||
void llrp_data::iStream(ACN::PDU::Stream stream)
|
||||
{
|
||||
/// Destination CID - The Destination CID indicates the CID of the intended
|
||||
/// recipient of this PDU.
|
||||
uint8_t * buffer = new uint8_t[UUID_LENGTH];
|
||||
stream->read(buffer, UUID_LENGTH);
|
||||
if (stream->gcount() != UUID_LENGTH)
|
||||
stream->setstate(std::ios_base::failbit);
|
||||
destination = UUID::uuid(buffer);
|
||||
delete[] buffer;
|
||||
|
||||
/// Transaction Number - The Transaction Number allows an LLRP Manager to
|
||||
/// associate reply messages with requests.
|
||||
*stream >> transaction;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief llrp_data::oStream
|
||||
* @param stream
|
||||
*/
|
||||
void llrp_data::oStream(ACN::PDU::Stream stream) const
|
||||
{
|
||||
stream->write(destination.bytes(), UUID_LENGTH);
|
||||
*stream << transaction;
|
||||
if (child)
|
||||
child->oStream(stream);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief LLRP::Pdu::Pdu
|
||||
*/
|
||||
|
@ -40,13 +74,95 @@ Pdu::Pdu()
|
|||
* @brief LLRP::Pdu::iStream
|
||||
* @param stream
|
||||
*/
|
||||
void Pdu::iStream([[maybe_unused]] ACN::PDU::Stream stream)
|
||||
void Pdu::iStream(ACN::PDU::Stream stream)
|
||||
{
|
||||
RDMnet::Pdu::iStream(stream); // do base class first
|
||||
if (stream->fail()) return;
|
||||
if (!stream_->good()) return;
|
||||
|
||||
/// has no header
|
||||
|
||||
auto payload = new llrp_data();
|
||||
payload->iStream(stream_);
|
||||
data_ = payload;
|
||||
|
||||
switch (vector_) {
|
||||
case VECTOR_LLRP_PROBE_REQUEST:
|
||||
{
|
||||
auto block = ACN::PDU::Block<ProbeRequest::Pdu>();
|
||||
block.readBlock(stream_, std::shared_ptr<ACN::PDU::Pdu>(this));
|
||||
if (!block.pdu->empty())
|
||||
payload->child = block.pdu->front();
|
||||
}
|
||||
break;
|
||||
case VECTOR_LLRP_PROBE_REPLY:
|
||||
{
|
||||
auto block = ACN::PDU::Block<ProbeReply::Pdu>();
|
||||
block.readBlock(stream_, std::shared_ptr<ACN::PDU::Pdu>(this));
|
||||
if (!block.pdu->empty())
|
||||
payload->child = block.pdu->front();
|
||||
}
|
||||
break;
|
||||
case VECTOR_LLRP_RDM_CMD:
|
||||
{
|
||||
auto block = ACN::PDU::Block<RdmCmd::Pdu>();
|
||||
block.readBlock(stream_, std::shared_ptr<ACN::PDU::Pdu>(this));
|
||||
if (!block.pdu->empty())
|
||||
payload->child = block.pdu->front();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
stream_->setstate(std::ios_base::failbit);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!payload->child)
|
||||
stream_->setstate(std::ios_base::failbit);
|
||||
}
|
||||
|
||||
|
||||
namespace ProbeRequest {
|
||||
|
||||
/**
|
||||
* @brief request_data::iStream
|
||||
* @param stream
|
||||
*/
|
||||
void request_data::iStream(ACN::PDU::Stream stream)
|
||||
{
|
||||
auto readUID = [stream] (RDM::UID& uid) {
|
||||
*stream >> uid.device;
|
||||
*stream >> uid.manufacturer;
|
||||
};
|
||||
|
||||
readUID(lower);
|
||||
readUID(upper);
|
||||
*stream >> filter.value;
|
||||
while (stream->good()) {
|
||||
known.emplace_back(RDM::UID());
|
||||
readUID(known.back());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief request_data::oStream
|
||||
* @param stream
|
||||
*/
|
||||
void request_data::oStream(ACN::PDU::Stream stream) const
|
||||
{
|
||||
auto writeUID = [stream] (const RDM::UID& uid) {
|
||||
*stream << uid.device;
|
||||
*stream << uid.manufacturer;
|
||||
};
|
||||
|
||||
writeUID(lower);
|
||||
writeUID(upper);
|
||||
*stream << filter.value;
|
||||
for ( auto& id : known )
|
||||
writeUID(id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief LLRP::ProbeRequest::Pdu::Pdu
|
||||
*/
|
||||
|
@ -60,8 +176,16 @@ Pdu::Pdu()
|
|||
* @brief LLRP::ProbeRequest::Pdu::iStream
|
||||
* @param stream
|
||||
*/
|
||||
void Pdu::iStream([[maybe_unused]] ACN::PDU::Stream stream)
|
||||
void Pdu::iStream(ACN::PDU::Stream stream)
|
||||
{
|
||||
RDMnet::Pdu::iStream(stream); // do base class first
|
||||
if (stream->fail()) return;
|
||||
if (!stream_->good()) return;
|
||||
|
||||
/// LLRP::PDU has no header
|
||||
|
||||
data_ = new request_data();
|
||||
data_->iStream(stream_);
|
||||
}
|
||||
|
||||
} // namespace ProbeRequest
|
||||
|
@ -69,6 +193,31 @@ void Pdu::iStream([[maybe_unused]] ACN::PDU::Stream stream)
|
|||
|
||||
namespace ProbeReply {
|
||||
|
||||
/**
|
||||
* @brief reply_data::iStream
|
||||
*/
|
||||
void reply_data::iStream(ACN::PDU::Stream stream)
|
||||
{
|
||||
*stream >> id.device;
|
||||
*stream >> id.manufacturer;
|
||||
stream->read(address, sizeof(address));
|
||||
if (stream->gcount() != sizeof(address))
|
||||
stream->setstate(std::ios_base::failbit);
|
||||
*stream >> type;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief reply_data::oStream
|
||||
*/
|
||||
void reply_data::oStream(ACN::PDU::Stream stream) const
|
||||
{
|
||||
*stream << id.device;
|
||||
*stream << id.manufacturer;
|
||||
stream->write(address, sizeof(address));
|
||||
*stream << type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief LLRP::ProbeReply::Pdu::Pdu
|
||||
*/
|
||||
|
@ -82,12 +231,71 @@ Pdu::Pdu()
|
|||
* @brief LLRP::ProbeReply::Pdu::iStream
|
||||
* @param stream
|
||||
*/
|
||||
void Pdu::iStream([[maybe_unused]] ACN::PDU::Stream stream)
|
||||
void Pdu::iStream(ACN::PDU::Stream stream)
|
||||
{
|
||||
RDMnet::Pdu::iStream(stream); // do base class first
|
||||
if (stream->fail()) return;
|
||||
if (!stream_->good()) return;
|
||||
|
||||
/// has no header
|
||||
|
||||
data_ = new reply_data();
|
||||
data_->iStream(stream_);
|
||||
}
|
||||
|
||||
} // namespace ProbeReply
|
||||
|
||||
|
||||
namespace RdmCmd {
|
||||
|
||||
/**
|
||||
* @brief rdm_data::iStream
|
||||
*/
|
||||
void rdm_data::iStream(ACN::PDU::Stream stream)
|
||||
{
|
||||
data.push_back(VECTOR_RDM_CMD_RDM_DATA);
|
||||
while (stream->good())
|
||||
data.push_back(stream->readType<uint8_t>());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief rdm_data::oStream
|
||||
*/
|
||||
void rdm_data::oStream(ACN::PDU::Stream stream) const
|
||||
{
|
||||
for (size_t i = 1; i < data.size(); i++ )
|
||||
*stream << data.at(i);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief LLRP::RdmCmd::Pdu::Pdu
|
||||
*/
|
||||
Pdu::Pdu()
|
||||
: RDMnet::Pdu(1)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief LLRP::ProbeReply::Pdu::iStream
|
||||
* @param stream
|
||||
*/
|
||||
void Pdu::iStream(ACN::PDU::Stream stream)
|
||||
{
|
||||
RDMnet::Pdu::iStream(stream); // do base class first
|
||||
if (stream->fail()) return;
|
||||
if (!stream_->good()) return;
|
||||
|
||||
/// has no header
|
||||
|
||||
data_ = new rdm_data();
|
||||
data_->iStream(stream_);
|
||||
}
|
||||
|
||||
} // namespace RdmCmd
|
||||
|
||||
|
||||
} // namespace LLRP
|
||||
} // namespace RDMnet
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "pdu.h"
|
||||
#include "rdm/uid.h"
|
||||
#include "uuid/uuid.h"
|
||||
|
||||
namespace RDMnet {
|
||||
namespace LLRP {
|
||||
|
@ -38,6 +40,20 @@ namespace LLRP {
|
|||
* large network.
|
||||
*/
|
||||
|
||||
|
||||
/// 5.4 Packet Structure
|
||||
struct llrp_data
|
||||
: public ACN::PDU::pdu_data
|
||||
{
|
||||
UUID::uuid destination; //!< The receiver's unique CID or LLRP_BROADCAST_CID,
|
||||
uint32_t transaction; //!< Used to match request / response messages.
|
||||
std::shared_ptr<ACN::PDU::Pdu> child; //!< Probe Request PDU, Probe Reply PDU or RDM Command PDU...
|
||||
size_t streamSize() const override { return 20 + child->streamSize(); }
|
||||
void iStream(ACN::PDU::Stream) override;
|
||||
void oStream(ACN::PDU::Stream) const override;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The LLRP::Pdu class
|
||||
*/
|
||||
|
@ -52,6 +68,40 @@ public:
|
|||
|
||||
namespace ProbeRequest {
|
||||
|
||||
/**
|
||||
* @brief The filter_t struct
|
||||
* This bit field indicates a filter to be checked against the state of an
|
||||
* LLRP Target.
|
||||
*/
|
||||
struct filter_t {
|
||||
union {
|
||||
uint16_t value = 0;
|
||||
struct __attribute__((packed)) {
|
||||
bool client_tcp_inactive : 1;
|
||||
bool brokers_only : 1;
|
||||
uint16_t reserved : 14;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The request_data struct
|
||||
* Table 5-2: Probe Request PDU
|
||||
*/
|
||||
struct request_data
|
||||
: public ACN::PDU::pdu_data
|
||||
{
|
||||
RDM::UID lower;
|
||||
RDM::UID upper;
|
||||
filter_t filter;
|
||||
std::vector<RDM::UID> known;
|
||||
size_t streamSize() const override { return 14 + (6 * known.size()); }
|
||||
void iStream(ACN::PDU::Stream) override;
|
||||
void oStream(ACN::PDU::Stream) const override;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The LLRP::ProbeRequest::Pdu class
|
||||
*/
|
||||
|
@ -67,6 +117,18 @@ public:
|
|||
|
||||
namespace ProbeReply {
|
||||
|
||||
struct reply_data
|
||||
: public ACN::PDU::pdu_data
|
||||
{
|
||||
RDM::UID id;
|
||||
uint8_t address[6];
|
||||
uint8_t type;
|
||||
size_t streamSize() const override { return 13; }
|
||||
void iStream(ACN::PDU::Stream) override;
|
||||
void oStream(ACN::PDU::Stream) const override;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief The LLRP::ProbeReply::Pdu class
|
||||
*/
|
||||
|
@ -80,7 +142,29 @@ public:
|
|||
|
||||
} // namespace ProbeReply
|
||||
|
||||
namespace RdmCmd {
|
||||
|
||||
struct rdm_data
|
||||
: public ACN::PDU::pdu_data
|
||||
{
|
||||
std::vector<uint8_t> data;
|
||||
size_t streamSize() const override { return (data.size() > 0) ? data.size() - 1 : 0; }
|
||||
void iStream(ACN::PDU::Stream) override;
|
||||
void oStream(ACN::PDU::Stream) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The LLRP::RdmCmd::Pdu class
|
||||
*/
|
||||
class Pdu
|
||||
: public RDMnet::Pdu
|
||||
{
|
||||
public:
|
||||
Pdu();
|
||||
void iStream(ACN::PDU::Stream) override;
|
||||
};
|
||||
|
||||
} // namespace RdmCmd
|
||||
|
||||
|
||||
} // namespace LLRP
|
||||
|
|
|
@ -30,13 +30,19 @@ namespace RDMnet {
|
|||
namespace LLRP {
|
||||
|
||||
/**
|
||||
* @brief The LLRP::Manager class
|
||||
* @brief 5.1.1 LLRP Manager
|
||||
* LLRP Managers issue LLRP discovery probes and issue configuration change
|
||||
* commands. LLRP Managers might be found on lighting consoles or other
|
||||
* configuration tool equipment.
|
||||
*/
|
||||
class Manager
|
||||
{
|
||||
public:
|
||||
Manager();
|
||||
virtual ~Manager();
|
||||
|
||||
virtual void sendProbeRequest() {};
|
||||
virtual void receiveProbeReply() {};
|
||||
};
|
||||
|
||||
} // namespace LLRP
|
||||
|
|
|
@ -30,13 +30,20 @@ namespace RDMnet {
|
|||
namespace LLRP {
|
||||
|
||||
/**
|
||||
* @brief The LLRP::Target class
|
||||
* @brief 5.1.2 LLRP Target
|
||||
* LLRP Targets receive and act on LLRP discovery and configuration commands.
|
||||
* LLRP Targets enable remote administration of network configuration. All
|
||||
* Brokers, Controllers, and Devices also operate as LLRP Targets.
|
||||
*/
|
||||
class Target
|
||||
{
|
||||
public:
|
||||
Target();
|
||||
virtual ~Target();
|
||||
|
||||
virtual void setup() = 0; //!< listens on LLRP_PORT
|
||||
virtual void receiveProbeRequest() {};
|
||||
virtual void sendProbeReply() {};
|
||||
};
|
||||
|
||||
} // namespace LLRP
|
||||
|
|
Loading…
Reference in New Issue