514 lines
15 KiB
C++
514 lines
15 KiB
C++
/**
|
|
* @RDE_HEADER@
|
|
* DDS specific parts for a session
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*
|
|
* Created by Christian Ehrlicher, SLSE, 2017-02-27
|
|
*/
|
|
|
|
#include "lts_session_data_dds.h"
|
|
|
|
#ifdef BUILD_RTI
|
|
#include <DDS/DDSConnector/dds_connector.h>
|
|
#include <DDS/DTC/generic_dtc_impl.h>
|
|
#include <DDS/QosProfile/DDS_DefaultQos.h>
|
|
#include <Lts/Common/ProjectConfig/project_defines.h>
|
|
#include <NGLLogger/NGLLoggerBootstrap.h>
|
|
#include <QtCore/QDebug>
|
|
#include <QtCore/QSet>
|
|
#include <QtCore/QVector>
|
|
|
|
namespace
|
|
{
|
|
// Convert LtsSession::PartitionType to IDL::PartitionType
|
|
IDL::PartitionType toIdlPartitionType(LtsSession::PartitionType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case LtsSession::PartitionType::Any:
|
|
return IDL::PartitionType::Any;
|
|
case LtsSession::PartitionType::Global:
|
|
return IDL::PartitionType::Global;
|
|
case LtsSession::PartitionType::Exercise:
|
|
return IDL::PartitionType::Exercise;
|
|
case LtsSession::PartitionType::AllExercises:
|
|
return IDL::PartitionType::AllExercises;
|
|
case LtsSession::PartitionType::Replay:
|
|
return IDL::PartitionType::Replay;
|
|
case LtsSession::PartitionType::Invalid:
|
|
default:
|
|
return IDL::PartitionType::Any;
|
|
}
|
|
}
|
|
} // namespace
|
|
|
|
namespace LtsSession
|
|
{
|
|
/**
|
|
* We have to make sure that only one DdsConnector for a specific domain/partion/tye/connStr
|
|
* exists because we don't want to have more than one DomainParticipant and Publisher/Subscriber
|
|
* per domain/partion/tye/connStr. Therefore this ugly-looking key
|
|
*/
|
|
|
|
//
|
|
// DdsConnectionContainer
|
|
//
|
|
class DdsConnectionContainer
|
|
{
|
|
struct DdsConnection : public DdsConnectionParams
|
|
{
|
|
std::weak_ptr<DDSConnector::DdsConnector> ddsConnector = std::weak_ptr<DDSConnector::DdsConnector>();
|
|
|
|
DdsConnection() = default;
|
|
|
|
explicit DdsConnection(const DdsConnectionParams& p) : DdsConnectionParams(p) {}
|
|
};
|
|
|
|
QVector<DdsConnection> ddsConnections;
|
|
|
|
public:
|
|
std::shared_ptr<DDSConnector::DdsConnector> findGlobalConnection()
|
|
{
|
|
for (int i = ddsConnections.size() - 1; i >= 0; --i)
|
|
{
|
|
const DdsConnection& conn = ddsConnections.at(i);
|
|
if (toIdlPartitionType(conn.partitionType) != IDL::PartitionType::Global)
|
|
continue;
|
|
auto ret = conn.ddsConnector.lock();
|
|
if (ret != nullptr)
|
|
return ret;
|
|
// ddsConnector is a nullptr -> useless -> remove
|
|
ddsConnections.removeAt(i);
|
|
}
|
|
Q_ASSERT(false);
|
|
return std::shared_ptr<DDSConnector::DdsConnector>();
|
|
}
|
|
|
|
std::shared_ptr<DDSConnector::DdsConnector> findConnection(const DdsConnectionParams& connParams)
|
|
{
|
|
for (int i = ddsConnections.size() - 1; i >= 0; --i)
|
|
{
|
|
const DdsConnection& conn = ddsConnections.at(i);
|
|
if (conn != connParams)
|
|
continue;
|
|
auto ret = conn.ddsConnector.lock();
|
|
if (ret != nullptr)
|
|
return ret;
|
|
// ddsConnector is a nullptr -> useless -> remove
|
|
ddsConnections.removeAt(i);
|
|
}
|
|
return std::shared_ptr<DDSConnector::DdsConnector>();
|
|
}
|
|
|
|
dds::domain::DomainParticipant findMatchingDomainParticipant(const DdsConnectionParams& connParams)
|
|
{
|
|
for (int i = ddsConnections.size() - 1; i >= 0; --i)
|
|
{
|
|
const DdsConnection& conn = ddsConnections.at(i);
|
|
if (!connParams.hasSameDomainParams(conn))
|
|
continue;
|
|
auto ret = conn.ddsConnector.lock();
|
|
if (ret != nullptr)
|
|
return ret->getDomainParticipant();
|
|
// ddsConnector is a nullptr -> useless -> remove
|
|
ddsConnections.removeAt(i);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void insertConnection(const DdsConnectionParams& connParams,
|
|
const std::shared_ptr<DDSConnector::DdsConnector>& ddsConnector)
|
|
{
|
|
DdsConnection val(connParams);
|
|
val.ddsConnector = ddsConnector;
|
|
|
|
ddsConnections += val;
|
|
}
|
|
};
|
|
Q_GLOBAL_STATIC(DdsConnectionContainer, s_ddsConnections)
|
|
|
|
class DataPluginContainer
|
|
{
|
|
public:
|
|
struct DataPluginValue
|
|
{
|
|
QString identifier;
|
|
std::weak_ptr<DataPluginBase::Interface> weakIfc;
|
|
|
|
bool operator==(const DataPluginValue& o) const
|
|
{
|
|
return identifier == o.identifier && weakIfc.lock().get() == o.weakIfc.lock().get();
|
|
}
|
|
};
|
|
|
|
QMap<DdsConnectionParams, QSet<DataPluginValue>> m_dataPlugins;
|
|
|
|
public:
|
|
QMap<QString, std::shared_ptr<DataPluginBase::Interface>> findDataPlugins(const DdsConnectionParams& connParams);
|
|
void insertDataPlugins(const DdsConnectionParams& connParams,
|
|
const QMap<QString, std::shared_ptr<DataPluginBase::Interface>>& dataPlugins);
|
|
};
|
|
|
|
uint qHash(const DataPluginContainer::DataPluginValue& val)
|
|
{
|
|
qint64 ptr = reinterpret_cast<qint64>(val.weakIfc.lock().get());
|
|
return ::qHash(val.identifier) ^ ::qHash(ptr);
|
|
}
|
|
|
|
QMap<QString, std::shared_ptr<DataPluginBase::Interface>>
|
|
DataPluginContainer::findDataPlugins(const DdsConnectionParams& connParams)
|
|
{
|
|
QMap<QString, std::shared_ptr<DataPluginBase::Interface>> ret;
|
|
DdsConnectionParams key(connParams);
|
|
key.exerciseId = 0;
|
|
|
|
auto it = m_dataPlugins.find(key);
|
|
if (it != m_dataPlugins.end())
|
|
{
|
|
QSet<DataPluginValue>& cont = it.value();
|
|
auto itCont = cont.begin();
|
|
while (itCont != cont.end())
|
|
{
|
|
auto spPlugin = itCont->weakIfc.lock();
|
|
if (spPlugin)
|
|
{
|
|
ret[itCont->identifier] = spPlugin;
|
|
++itCont;
|
|
}
|
|
else
|
|
{
|
|
itCont = cont.erase(itCont);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void DataPluginContainer::insertDataPlugins(
|
|
const DdsConnectionParams& connParams, const QMap<QString, std::shared_ptr<DataPluginBase::Interface>>& dataPlugins)
|
|
{
|
|
DdsConnectionParams key(connParams);
|
|
key.exerciseId = 0;
|
|
|
|
QSet<DataPluginValue> cont;
|
|
cont.reserve(dataPlugins.size());
|
|
for (auto it = dataPlugins.begin(); it != dataPlugins.end(); ++it)
|
|
{
|
|
DataPluginValue val;
|
|
val.identifier = it.key();
|
|
val.weakIfc = it.value();
|
|
cont += val;
|
|
}
|
|
|
|
m_dataPlugins[key].unite(cont);
|
|
}
|
|
|
|
Q_GLOBAL_STATIC(DataPluginContainer, s_dataPlugins)
|
|
|
|
//
|
|
// LtsSessionDataDds
|
|
//
|
|
LtsSessionDataDds::LtsSessionDataDds(QObject* parent)
|
|
: QObject(parent), m_exerciseId(-1), m_emittedTime(0), m_curMSecSinceEpoch(0), m_active(true), m_fetcher(nullptr),
|
|
m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("LtsSession.Session"))
|
|
{
|
|
}
|
|
|
|
LtsSessionDataDds::~LtsSessionDataDds()
|
|
{
|
|
m_dtcPartitionTime = nullptr;
|
|
m_ddsConnector = nullptr;
|
|
delete m_fetcher;
|
|
}
|
|
|
|
bool LtsSessionDataDds::init(const DdsConnectionParams& connParams)
|
|
{
|
|
|
|
m_ddsConnector = s_ddsConnections->findConnection(connParams);
|
|
m_exerciseId = connParams.exerciseId;
|
|
m_qosFileList = QStringList(connParams.qos_file);
|
|
if (m_ddsConnector == nullptr)
|
|
{
|
|
// maybe we can at least find a useful DomainParticipant?
|
|
dds::domain::DomainParticipant dp = s_ddsConnections->findMatchingDomainParticipant(connParams);
|
|
if (dp != nullptr)
|
|
return init(dp, connParams);
|
|
#ifdef WIN_32
|
|
DDS::QosProfile::ConnectionType type = DDS::QosProfile::ConnectionType::Tablet;
|
|
#else
|
|
DDS::QosProfile::ConnectionType type = DDS::QosProfile::ConnectionType::Client;
|
|
#endif
|
|
|
|
m_ddsConnector = std::make_shared<DDSConnector::DdsConnector>(
|
|
connParams.domainId, toIdlPartitionType(connParams.partitionType), connParams.partitionId,
|
|
connParams.exerciseId, // same as partition Id in live but not in replay
|
|
type);
|
|
s_ddsConnections()->insertConnection(connParams, m_ddsConnector);
|
|
}
|
|
return initInternal();
|
|
}
|
|
|
|
bool LtsSessionDataDds::init(const dds::domain::DomainParticipant& dp, const DdsConnectionParams& connParams)
|
|
{
|
|
Q_ASSERT(dp.domain_id() == connParams.domainId);
|
|
|
|
m_ddsConnector = s_ddsConnections->findConnection(connParams);
|
|
m_exerciseId = connParams.exerciseId;
|
|
|
|
QStringList qosList;
|
|
if (!connParams.qos_file.isEmpty())
|
|
{
|
|
qosList.append(connParams.qos_file);
|
|
}
|
|
|
|
if (!qosList.isEmpty())
|
|
m_qosFileList = qosList;
|
|
else
|
|
m_qosFileList.clear();
|
|
|
|
#ifdef WIN_32
|
|
DDS::QosProfile::ConnectionType type = DDS::QosProfile::ConnectionType::Tablet;
|
|
#else
|
|
DDS::QosProfile::ConnectionType type = DDS::QosProfile::ConnectionType::Client;
|
|
#endif
|
|
|
|
if (m_ddsConnector == nullptr)
|
|
{
|
|
m_ddsConnector =
|
|
std::make_shared<DDSConnector::DdsConnector>(dp, toIdlPartitionType(connParams.partitionType), type, connParams.partitionId);
|
|
|
|
s_ddsConnections()->insertConnection(connParams, m_ddsConnector);
|
|
}
|
|
return initInternal();
|
|
}
|
|
|
|
Fetcher* LtsSessionDataDds::fetcher(const QString& yourPluginsName)
|
|
{
|
|
if (m_fetcher == nullptr)
|
|
m_fetcher = new Fetcher(this, yourPluginsName);
|
|
|
|
return m_fetcher;
|
|
}
|
|
|
|
QString LtsSessionDataDds::partitionTypeString(PartitionType partitionType)
|
|
{
|
|
switch (partitionType)
|
|
{
|
|
case PartitionType::AllExercises:
|
|
return QStringLiteral("AllExercises");
|
|
case PartitionType::Any:
|
|
return QStringLiteral("Any");
|
|
case PartitionType::Exercise:
|
|
return QStringLiteral("Exercise");
|
|
case PartitionType::Global:
|
|
return QStringLiteral("Global");
|
|
case PartitionType::Replay:
|
|
return QStringLiteral("Replay");
|
|
}
|
|
|
|
return QStringLiteral("Invalid (%1)").arg(int(partitionType));
|
|
}
|
|
|
|
LtsSession::PartitionType LtsSessionDataDds::toPartitionType(IDL::PartitionType idlType)
|
|
{
|
|
switch (idlType)
|
|
{
|
|
case IDL::PartitionType::Any: return PartitionType::Any;
|
|
case IDL::PartitionType::Exercise: return PartitionType::Exercise;
|
|
case IDL::PartitionType::Replay: return PartitionType::Replay;
|
|
case IDL::PartitionType::AllExercises: return PartitionType::AllExercises;
|
|
case IDL::PartitionType::Global: return PartitionType::Global;
|
|
default: return PartitionType::Invalid;
|
|
}
|
|
}
|
|
|
|
QString LtsSessionDataDds::toString() const
|
|
{
|
|
return QStringLiteral("(LtsSessionDataDds: id=%1, partitionId=%2, partitionType=%3(%4), exerciseId=%5)")
|
|
.arg((qulonglong)this)
|
|
.arg(partitionId())
|
|
.arg(static_cast<int>(partitionType()))
|
|
.arg(partitionTypeString(partitionType()))
|
|
.arg(exerciseId());
|
|
}
|
|
|
|
int LtsSessionDataDds::domainId() const
|
|
{
|
|
return m_ddsConnector ? m_ddsConnector->getDomainId() : -1;
|
|
}
|
|
|
|
int LtsSessionDataDds::exerciseId() const
|
|
{
|
|
return m_exerciseId;
|
|
}
|
|
|
|
int LtsSessionDataDds::partitionId() const
|
|
{
|
|
return m_ddsConnector ? m_ddsConnector->getPartitionId() : -1;
|
|
}
|
|
|
|
PartitionType LtsSessionDataDds::partitionType() const
|
|
{
|
|
return m_ddsConnector ? toPartitionType(m_ddsConnector->getPartitionType()) : PartitionType::Global;
|
|
}
|
|
|
|
QStringList LtsSessionDataDds::qosFile() const
|
|
{
|
|
return m_ddsConnector ? m_qosFileList : QStringList();
|
|
}
|
|
|
|
QUrl LtsSessionDataDds::tcpConnectionUrl() const
|
|
{
|
|
return m_ddsConnector ? m_ddsConnector->getTcpConnectionUrl() : QUrl();
|
|
}
|
|
|
|
DdsConnectionParams LtsSessionDataDds::connParams() const
|
|
{
|
|
DdsConnectionParams connParams;
|
|
connParams.domainId = domainId();
|
|
connParams.exerciseId = exerciseId();
|
|
connParams.partitionId = partitionId();
|
|
connParams.partitionType = partitionType();
|
|
connParams.qos_file = qosFile();
|
|
connParams.tcpConnectionUrl = tcpConnectionUrl();
|
|
return connParams;
|
|
}
|
|
|
|
bool LtsSessionDataDds::initInternal()
|
|
{
|
|
if (!m_ddsConnector || !m_ddsConnector->init(m_qosFileList))
|
|
{
|
|
ERROR_LOG(m_logger) << "DDS connector could not be initialized - session aborted!";
|
|
m_ddsConnector = nullptr;
|
|
return false;
|
|
}
|
|
|
|
m_ddsConnector->initPublisherSubscriber();
|
|
m_ddsConnectorGlobal = s_ddsConnections->findGlobalConnection();
|
|
if (!m_ddsConnectorGlobal)
|
|
m_ddsConnectorGlobal = m_ddsConnector;
|
|
|
|
m_dtcPartitionTime.reset(m_ddsConnector->createDTC<DTC::PartitionTimeImpl>());
|
|
assert(m_dtcPartitionTime.get());
|
|
|
|
m_dtcPartitionTime->setSubscriberCallback([this](const Core::PartitionTime& data, DataModification) {
|
|
m_curMSecSinceEpoch = data.timeStamp();
|
|
emit partitionTimeChangedInternal();
|
|
});
|
|
connect(this, &LtsSessionDataDds::partitionTimeChangedInternal, this,
|
|
&LtsSessionDataDds::onPartitionTimeChangedInternal, Qt::QueuedConnection);
|
|
return true;
|
|
}
|
|
|
|
void LtsSessionDataDds::onPartitionTimeChangedInternal()
|
|
{
|
|
if (!m_active)
|
|
return;
|
|
if (m_emittedTime == m_curMSecSinceEpoch)
|
|
return;
|
|
m_emittedTime = m_curMSecSinceEpoch;
|
|
emit partitionTimeChanged(m_curMSecSinceEpoch);
|
|
}
|
|
|
|
QMap<QString, std::shared_ptr<DataPluginBase::Interface>> LtsSessionDataDds::availableDataPluginInterfaces() const
|
|
{
|
|
return s_dataPlugins->findDataPlugins(connParams());
|
|
}
|
|
|
|
void LtsSessionDataDds::addAvailablaeDataPluginInterfaces(
|
|
const QMap<QString, std::shared_ptr<DataPluginBase::Interface>>& dataPlugins)
|
|
{
|
|
s_dataPlugins->insertDataPlugins(connParams(), dataPlugins);
|
|
}
|
|
|
|
} // namespace LtsSession
|
|
|
|
#else // !BUILD_RTI - Stub implementation for non-RTI builds
|
|
|
|
namespace LtsSession
|
|
{
|
|
|
|
LtsSessionDataDds::LtsSessionDataDds(QObject* parent)
|
|
: QObject(parent), m_exerciseId(-1), m_emittedTime(0), m_curMSecSinceEpoch(0), m_active(true), m_fetcher(nullptr)
|
|
{
|
|
}
|
|
|
|
LtsSessionDataDds::~LtsSessionDataDds()
|
|
{
|
|
// m_fetcher is void* in stub mode, no deletion needed
|
|
}
|
|
|
|
bool LtsSessionDataDds::init(const DdsConnectionParams& /*connParams*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool LtsSessionDataDds::init(const void* /*dp*/, const DdsConnectionParams& /*connParams*/)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void* LtsSessionDataDds::fetcher(const QString& /*yourPluginsName*/)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
QString LtsSessionDataDds::partitionTypeString(PartitionType /*partitionType*/)
|
|
{
|
|
return QString();
|
|
}
|
|
|
|
QString LtsSessionDataDds::toString() const
|
|
{
|
|
return QStringLiteral("(LtsSessionDataDds: STUB - no RTI support)");
|
|
}
|
|
|
|
int LtsSessionDataDds::domainId() const
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int LtsSessionDataDds::exerciseId() const
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int LtsSessionDataDds::partitionId() const
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
PartitionType LtsSessionDataDds::partitionType() const
|
|
{
|
|
return PartitionType::Global;
|
|
}
|
|
|
|
QStringList LtsSessionDataDds::qosFile() const
|
|
{
|
|
return QStringList();
|
|
}
|
|
|
|
QUrl LtsSessionDataDds::tcpConnectionUrl() const
|
|
{
|
|
return QUrl();
|
|
}
|
|
|
|
DdsConnectionParams LtsSessionDataDds::connParams() const
|
|
{
|
|
return DdsConnectionParams();
|
|
}
|
|
|
|
bool LtsSessionDataDds::initInternal()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void LtsSessionDataDds::onPartitionTimeChangedInternal()
|
|
{
|
|
}
|
|
|
|
} // namespace LtsSession
|
|
|
|
#endif // BUILD_RTI
|