Files
qt6-migration-pipeline/Lts/DDS/FTS/connext.h
T

503 lines
15 KiB
C++
Executable File

#pragma once
#include <dds/core/cond/GuardCondition.hpp>
#include <dds/core/cond/StatusCondition.hpp>
#include <dds/core/cond/WaitSet.hpp>
#include <dds/domain/DomainParticipant.hpp>
#include <dds/pub/DataWriter.hpp>
#include <dds/pub/Publisher.hpp>
#include <dds/sub/DataReader.hpp>
#include <dds/sub/SampleInfo.hpp>
#include <dds/sub/Subscriber.hpp>
#include <dds/topic/ContentFilteredTopic.hpp>
#include <dds/topic/find.hpp>
#include <rti/pub/WriteParams.hpp>
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace connext
{
namespace DebugInfo
{
inline QByteArray toReadable(const rti::core::Guid &guid)
{
const QByteArray str(reinterpret_cast<const char *>(&guid[0]), 16);
return str.toHex();
}
inline QByteArray toReadable(const rti::core::SequenceNumber &seqNo,
const rti::core::Guid &guid)
{
return "SeqNo: " + QByteArray::number(seqNo.value()) +
", Guid-DW: " + toReadable(guid);
}
inline QByteArray toReadable(const rti::core::SampleIdentity &identiy)
{
return toReadable(identiy.sequence_number(), identiy.writer_guid());
}
}
template<typename T>
dds::topic::Topic<T> getTopic(const dds::domain::DomainParticipant &participant,
const std::string &topicName)
{
using DataTopic = dds::topic::Topic<T>;
auto ret = dds::topic::find<DataTopic>(participant, topicName);
if (ret != nullptr)
return ret;
return DataTopic(participant, topicName);
}
template<typename T>
class SampleBase
{
protected:
SampleBase() = default;
virtual ~SampleBase() = default;
public:
void set_data(const T &data)
{
m_data = data;
}
T &data()
{
return m_data;
}
const T &data() const
{
return m_data;
}
protected:
T m_data;
};
template<typename T>
class WriteSample : public SampleBase<T>
{
public:
WriteSample() = default;
void set_info(const rti::pub::WriteParams &info)
{
m_info = info;
}
rti::pub::WriteParams &info()
{
return m_info;
}
const rti::pub::WriteParams &info() const
{
return m_info;
}
private:
rti::pub::WriteParams m_info;
};
template<typename T>
class WriteSampleRef
{
public:
WriteSampleRef()
: m_data_ptr(nullptr)
, m_info_ptr(nullptr)
{}
void set_data(T *data_ptr)
{
m_data_ptr = data_ptr;
}
T &data()
{
return *m_data_ptr;
}
void set_info(rti::pub::WriteParams *info_ptr)
{
m_info_ptr = info_ptr;
}
rti::pub::WriteParams &info()
{
return *m_info_ptr;
}
private:
T *m_data_ptr;
rti::pub::WriteParams *m_info_ptr;
};
template<typename T>
class Sample : public SampleBase<T>
{
public:
Sample() = default;
void set_info(const dds::sub::SampleInfo &info)
{
m_info = info;
}
dds::sub::SampleInfo &info()
{
return m_info;
}
const dds::sub::SampleInfo &info() const
{
return m_info;
}
void set_identity(const rti::core::SampleIdentity &identity)
{
m_identity = identity;
}
const rti::core::SampleIdentity &identity() const
{
return m_identity;
}
private:
dds::sub::SampleInfo m_info;
rti::core::SampleIdentity m_identity;
};
class RequesterParams
{
public:
explicit RequesterParams(const dds::domain::DomainParticipant &participant)
: m_participant(participant)
, m_publisher(nullptr)
, m_subscriber(nullptr)
{}
virtual ~RequesterParams() = default;
const std::string &request_topic_name() const
{
return m_request_topic_name;
}
void request_topic_name(const std::string &request_topic_name)
{
m_request_topic_name = request_topic_name;
}
const std::string &reply_topic_name() const
{
return m_reply_topic_name;
}
void reply_topic_name(const std::string &reply_topic_name)
{
m_reply_topic_name = reply_topic_name;
}
const dds::domain::DomainParticipant &domainParticipant() const
{
return m_participant;
}
const dds::pub::Publisher &publisher() const
{
return m_publisher;
}
void publisher(const dds::pub::Publisher &publisher)
{
m_publisher = publisher;
}
const dds::sub::Subscriber &subscriber() const
{
return m_subscriber;
}
void subscriber(const dds::sub::Subscriber &subscriber)
{
m_subscriber = subscriber;
}
const dds::pub::qos::DataWriterQos &datawriter_qos() const
{
return m_datawriter_qos;
}
void datawriter_qos(const dds::pub::qos::DataWriterQos &datawriter_qos)
{
m_datawriter_qos = datawriter_qos;
}
const dds::sub::qos::DataReaderQos &datareader_qos() const
{
return m_datareader_qos;
}
void datareader_qos(const dds::sub::qos::DataReaderQos &datareader_qos)
{
m_datareader_qos = datareader_qos;
}
protected:
dds::domain::DomainParticipant m_participant;
dds::pub::Publisher m_publisher;
dds::sub::Subscriber m_subscriber;
dds::pub::qos::DataWriterQos m_datawriter_qos;
dds::sub::qos::DataReaderQos m_datareader_qos;
std::string m_request_topic_name;
std::string m_reply_topic_name;
};
template <typename REQUEST, typename REPLY>
class ReplierParams : public RequesterParams
{
public:
using RequesterParams::RequesterParams;
};
template<typename REQUEST, typename REPLY>
class ReplyRequestBase
{
protected:
explicit ReplyRequestBase(const connext::RequesterParams &requesterParams)
: m_requestTopic(getTopic<REQUEST>(requesterParams.domainParticipant(),
requesterParams.request_topic_name()))
, m_replyTopic(getTopic<REPLY>(requesterParams.domainParticipant(),
requesterParams.reply_topic_name()))
{}
virtual ~ReplyRequestBase() = default;
protected:
dds::topic::Topic<REQUEST> m_requestTopic;
dds::topic::Topic<REPLY> m_replyTopic;
};
template<typename REQUEST, typename REPLY>
class Requester final : public ReplyRequestBase<REQUEST, REPLY>
{
public:
explicit Requester(const connext::RequesterParams &requesterParams)
: ReplyRequestBase<REQUEST, REPLY>(requesterParams)
, m_requesterParams(requesterParams)
, m_dataWriter(nullptr)
, m_dataReader(nullptr)
, m_contentFilteredTopic(nullptr)
, m_curInstanceHandle(dds::core::InstanceHandle::nil())
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("connext.requester"))
{}
void create_contentfilter(bool bNewDataWriter)
{
if (!bNewDataWriter && m_contentFilteredTopic != nullptr)
return;
rti::core::policy::DataWriterProtocol dwp;
m_dataWriter.qos() >> dwp;
const rti::core::Guid dwGuid = dwp.virtual_guid();
const QByteArray writerGuid = DebugInfo::toReadable(dwGuid);
const QByteArray filterContent = "@related_sample_identity.writer_guid.value = &hex(" + writerGuid + ")";
if (m_contentFilteredTopic == nullptr)
{
const std::string rtName = ReplyRequestBase<REQUEST, REPLY>::m_replyTopic.name();
const QByteArray filterName(QByteArray::fromRawData(rtName.c_str(), static_cast<int>(rtName.size())) +
QByteArray(" ") + writerGuid);
m_contentFilteredTopic = dds::topic::ContentFilteredTopic<REPLY>(ReplyRequestBase<REQUEST, REPLY>::m_replyTopic,
filterName.data(),
dds::topic::Filter(filterContent.data()));
}
else
{
m_contentFilteredTopic->filter(dds::topic::Filter(filterContent.data()));
}
DEBUG_LOG(m_logger) << "content filter for topic "
<< ReplyRequestBase<REQUEST, REPLY>::m_requestTopic.name()
<< " - related_sample_identity should be: "
<< writerGuid;
}
void send_request(connext::WriteSample<REQUEST> &request)
{
bool bNewDataWriter = false;
if (m_dataWriter == nullptr)
{
m_dataWriter = dds::pub::DataWriter<REQUEST>(m_requesterParams.publisher(),
ReplyRequestBase<REQUEST, REPLY>::m_requestTopic,
m_requesterParams.datawriter_qos());
bNewDataWriter = true;
}
else
{
}
create_contentfilter(bNewDataWriter);
if (m_dataReader == nullptr)
{
m_dataReader = dds::sub::DataReader<REPLY>(m_requesterParams.subscriber(),
m_contentFilteredTopic,
m_requesterParams.datareader_qos());
}
m_curInstanceHandle = m_dataWriter.register_instance(request.data());
request.info().replace_automatic_values(true);
request.info().identity(rti::core::SampleIdentity::automatic());
m_dataWriter->write(request.data(), request.info());
const rti::core::SampleIdentity currentSampleIdentity = request.info().identity();
DEBUG_LOG(m_logger) << "send_request for topic "
<< ReplyRequestBase<REQUEST, REPLY>::m_requestTopic.name()
<< ", m_currentSampleIdentity: "
<< DebugInfo::toReadable(currentSampleIdentity);
}
bool receive_reply(connext::Sample<REPLY> &reply,
const dds::core::Duration &duration)
{
auto condition(dds::sub::cond::ReadCondition(m_dataReader, dds::sub::status::SampleState::not_read()));
dds::core::cond::WaitSet waitset;
waitset.attach_condition(condition);
bool bRet = false;
while (true)
{
if (m_dataReader->take(reply.data(), reply.info()) && reply.info().valid())
{
DEBUG_LOG(m_logger) << "receive_reply for topic "
<< ReplyRequestBase<REQUEST, REPLY>::m_requestTopic.name()
<< ", SampleIdentity - original publication virtual: "
<< DebugInfo::toReadable(reply.info()->original_publication_virtual_sample_identity());
DEBUG_LOG(m_logger) << "receive_reply for topic "
<< ReplyRequestBase<REQUEST, REPLY>::m_requestTopic.name()
<< ", SampleIdentity - related original: "
<< DebugInfo::toReadable(reply.info()->related_original_publication_virtual_sample_identity());
bRet = true;
break;
}
dds::core::cond::WaitSet::ConditionSeq activeConditionsSeq = waitset.wait(duration);
if (activeConditionsSeq.empty())
{
ERROR_LOG(m_logger) << "Bailing out!";
break;
}
}
static const rti::core::SampleFlag irs(rti::core::SampleFlag::intermediate_reply_sequence());
if ((reply.info()->flag() & irs) == 0)
{
if (!m_curInstanceHandle.is_nil())
{
DEBUG_LOG(m_logger) << "Keyed topic - disposing instance: "
<< ReplyRequestBase<REQUEST, REPLY>::m_requestTopic.name();
m_dataWriter.dispose_instance(m_curInstanceHandle);
}
}
return bRet;
}
dds::pub::DataWriter<REQUEST> get_request_datawriter() const { return m_dataWriter; }
dds::sub::DataReader<REPLY> get_request_datareader() const { return m_dataReader; }
private:
connext::RequesterParams m_requesterParams;
dds::pub::DataWriter<REQUEST> m_dataWriter;
dds::sub::DataReader<REPLY> m_dataReader;
dds::topic::ContentFilteredTopic<REPLY> m_contentFilteredTopic;
dds::core::InstanceHandle m_curInstanceHandle;
NGL::INGLLogger &m_logger;
};
template<typename REQUEST, typename REPLY>
class Replier final : public ReplyRequestBase<REQUEST, REPLY>
{
public:
explicit Replier(const connext::ReplierParams<REQUEST, REPLY> &replierParams)
: ReplyRequestBase<REQUEST, REPLY>(replierParams)
, m_replierParams(replierParams)
, m_dataWriter(dds::pub::DataWriter<REPLY>(replierParams.publisher(),
ReplyRequestBase<REQUEST, REPLY>::m_replyTopic,
replierParams.datawriter_qos()))
, m_dataReader(dds::sub::DataReader<REQUEST>(replierParams.subscriber(),
ReplyRequestBase<REQUEST, REPLY>::m_requestTopic,
replierParams.datareader_qos()))
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("connext.replier"))
{}
void send_reply(connext::WriteSample<REPLY> &reply,
const rti::core::SampleIdentity &identity,
bool bLastSample = true)
{
connext::WriteSampleRef<REPLY> replyRef;
replyRef.set_data(&reply.data());
replyRef.set_info(&reply.info());
return send_reply(replyRef, identity, bLastSample);
}
void send_reply(connext::WriteSampleRef<REPLY> &reply,
const rti::core::SampleIdentity &identity,
bool bLastSample = true)
{
DEBUG_LOG(m_logger) << "send_reply for topic "
<< ReplyRequestBase<REQUEST, REPLY>::m_requestTopic.name()
<< ", sampleIdentity: " << DebugInfo::toReadable(identity);
rti::core::SampleFlag sf = reply.info().flag();
if (bLastSample)
sf &= ~rti::core::SampleFlag::intermediate_reply_sequence();
else
sf |= rti::core::SampleFlag::intermediate_reply_sequence();
reply.info().flag(sf);
reply.info().related_sample_identity(identity);
DEBUG_LOG(m_logger) << "send_reply for topic "
<< ReplyRequestBase<REQUEST, REPLY>::m_requestTopic.name()
<< ", related sampleIdentity: " << DebugInfo::toReadable(reply.info().related_sample_identity());
m_dataWriter->write(reply.data(), reply.info());
}
bool receive_request(connext::Sample<REQUEST> &request)
{
if (!m_dataReader->take(request.data(), request.info()))
return false;
if (request.info().valid())
{
DEBUG_LOG(m_logger) << "receive_request for topic "
<< ReplyRequestBase<REQUEST, REPLY>::m_requestTopic.name()
<< ", sampleIdentity publication_virtual_sample_identity: "
<< DebugInfo::toReadable(request.info()->publication_virtual_sample_identity())
<< ", original_publication_virtual_sample_identity: "
<< DebugInfo::toReadable(request.info()->original_publication_virtual_sample_identity())
<< ", related_original_publication_virtual_sample_identity: "
<< DebugInfo::toReadable(request.info()->related_original_publication_virtual_sample_identity())
<< " with timestamp_ " << request.info().source_timestamp().to_millisecs();
request.set_identity(request.info()->original_publication_virtual_sample_identity());
}
return request.info().valid();
}
dds::pub::DataWriter<REPLY> get_request_datawriter() const { return m_dataWriter; }
dds::sub::DataReader<REQUEST> get_request_datareader() const { return m_dataReader; }
private:
connext::ReplierParams<REQUEST, REPLY> m_replierParams;
dds::pub::DataWriter<REPLY> m_dataWriter;
dds::sub::DataReader<REQUEST> m_dataReader;
NGL::INGLLogger &m_logger;
};
}