Resolves latest issues in Lts/Common Lts/DDS

This commit is contained in:
torsten committed 2026-09-06 18:45:59 +02:00
1 parent e398f4903d
commit b656e1aaa9
25 files changed
+537 -47

No files matched your search

+12 -11
View File
@@ -96,7 +96,7 @@ include_directories(${CMAKE_BINARY_DIR}/Lts/Common/LtsUtils/LtsUtilsCore)
include_directories(${CMAKE_SOURCE_DIR}/include/Viewer/SituationMap)
include_directories(${CMAKE_SOURCE_DIR}/include/OperatorManagement)
include_directories(${CMAKE_SOURCE_DIR}/include/FileManagement)
SET(CMAKE_CXX_STANDARD 23)
SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
SET(CMAKE_CXX_VISIBILITY_PRESET hidden)
@@ -222,7 +222,7 @@ endif()
# Find Qt6 core components first (without OpenGL which may not be available)
find_package(Qt6 6.2 COMPONENTS Concurrent Core LinguistTools Network
Multimedia Sql SerialPort Test Xml Positioning QUIET)
Multimedia Sql SerialPort Test Xml Positioning Svg QUIET)
if(Qt6_FOUND)
# Skip GUI find_package - it fails without OpenGL. We'll create manual targets below.
@@ -336,14 +336,7 @@ if(NOT TARGET Qt6::Test AND EXISTS "${QT6_LIB_DIR}/libQt6Test.so.6")
message(STATUS "Manually configured Qt6 Test target")
endif()
# Stub Qt6::Svg target if not available (needed by multiple plugins)
if(NOT TARGET Qt6::Svg)
add_library(Qt6::Svg INTERFACE IMPORTED)
set_target_properties(Qt6::Svg PROPERTIES
INTERFACE_COMPILE_DEFINITIONS "QT_NO_SVG"
)
message(STATUS "Created stub target for Qt6::Svg (library not available)")
endif()
# Qt6::Svg target should be found by find_package above
# Stub Qt6::Multimedia target if not available (needed by OscSystemGuiPlugin, etc.)
if(NOT TARGET Qt6::Multimedia)
@@ -423,7 +416,15 @@ MESSAGE(STATUS "Qt version is ${Qt6Core_VERSION}, GUI available: ${QT6_GUI_AVAIL
# RTI Connext DDS - manuelle Konfiguration da keine CMake Config Files vorhanden
#
IF(BUILD_RTI)
SET(RTI_INSTALL_DIR "/repo/external/rti_connext_dds-7.7.0" CACHE PATH "RTI Connext DDS installation directory")
# Support environment variable override, otherwise use relative path from repo root
IF(DEFINED ENV{DDS_PATH})
SET(RTI_INSTALL_DIR "$ENV{DDS_PATH}" CACHE PATH "RTI Connext DDS installation directory")
ELSE()
# CMAKE_SOURCE_DIR is qt6-migrated-legatus, RTI is at ../../../external/
SET(RTI_INSTALL_DIR "${CMAKE_SOURCE_DIR}/../../../external/rti_connext_dds-7.7.0" CACHE PATH "RTI Connext DDS installation directory")
ENDIF()
# Also set RTI_DIR for FindRTI.cmake compatibility (used by subdirectories)
SET(RTI_DIR "${RTI_INSTALL_DIR}" CACHE PATH "RTI base path" FORCE)
IF(EXISTS "${RTI_INSTALL_DIR}")
SET(RTI_LIB_DIR "${RTI_INSTALL_DIR}/lib/x64Linux4gcc8.5.0")
SET(RTI_INCLUDE_DIR "${RTI_INSTALL_DIR}/include/ndds/hpp")
@@ -146,6 +146,7 @@ IF(BUILD_GRANTLEE AND TARGET KF6::TextTemplate)
LtsCommandLineParser
nglcoreapplication
Qt6::Core
KF6::TextTemplate
)
NGL_WRAP_UI(codegen_gui_uics
@@ -17,6 +17,10 @@ GeneratorGrantleeBase::GeneratorGrantleeBase(const char* loggerName)
, m_structBuilder(nullptr)
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger(loggerName))
{
// Add KTextTemplate plugin path for loading default tags/filters
// KTextTemplate plugins are in /usr/lib/x86_64-linux-gnu/qt6/plugins/kf6/ktexttemplate
// QT_PLUGIN_PATH should point to the parent directory containing the category folders
m_engine->addPluginPath(QStringLiteral("/usr/lib/x86_64-linux-gnu/qt6/plugins"));
}
GeneratorGrantleeBase::~GeneratorGrantleeBase()
@@ -12,11 +12,11 @@ QString IdlStructWrapper::extensibility2String(dds::core::xtypes::ExtensibilityK
{
switch (extensiblity.underlying())
{
case dds::core::xtypes::ExtensibilityKind_def::FINAL:
case dds::core::xtypes::ExtensibilityKind_def::type::FINAL:
return QStringLiteral("FINAL_EXTENSIBILITY");
case dds::core::xtypes::ExtensibilityKind_def::MUTABLE:
case dds::core::xtypes::ExtensibilityKind_def::type::MUTABLE:
return QStringLiteral("MUTABLE_EXTENSIBILITY");
case dds::core::xtypes::ExtensibilityKind_def::EXTENSIBLE:
case dds::core::xtypes::ExtensibilityKind_def::type::EXTENSIBLE:
return QStringLiteral("EXTENSIBLE_EXTENSIBILITY");
}
Q_ASSERT_X(false, "IdlStructWrapper::extensibility2String", "Unknown extensiblity kind");
@@ -71,7 +71,7 @@ QString MemberInformationWrapper::ddsToJsonElement() const
const QString getValue = isCppStruct() ? cppMemberName() : cppMemberName() + QStringLiteral("()");
return QStringLiteral("if (element.") + optionalAccess + QStringLiteral(") ") +
QStringLiteral("obj[QStringLiteral(\"") + cppMemberName() + QStringLiteral("\")] = ") + cppToJsonPre() +
QStringLiteral("element.") + getValue + cppToJsonPost();
QStringLiteral("*element.") + getValue + cppToJsonPost();
}
QString MemberInformationWrapper::jsonElementToDds() const
@@ -856,10 +856,12 @@ bool StructBuilder::fixupQVariantConversions(MemberInformation& mi) const
svcName += QStringLiteral("::");
mi.cpp.type = svcName + mi.enumeration->enumName;
mi.cpp.fromVariantPre2 =
QStringLiteral("static_cast<") + svcName + mi.enumeration->enumName + QStringLiteral("_def::type>(");
QStringLiteral("static_cast<") + svcName + mi.enumeration->enumName + QStringLiteral(">(");
mi.cpp.fromVariantPost = QStringLiteral(".toInt())");
mi.cpp.toVariantPre = QStringLiteral("static_cast<int>(");
mi.cpp.toVariantPost = QStringLiteral(".underlying())");
mi.cpp.toVariantPost.clear();
mi.cpp.toJsonPre = QStringLiteral("toJson(static_cast<int>(");
mi.cpp.toJsonPost = QStringLiteral("))");
if (!mi.enumeration->values.isEmpty())
{
mi.cpp.defaultValue =
@@ -874,6 +876,8 @@ bool StructBuilder::fixupQVariantConversions(MemberInformation& mi) const
mi.cpp.type = QStringLiteral("qint64");
mi.cpp.fromVariantPost = QStringLiteral(".toLongLong()");
mi.cpp.fromJsonPost = QStringLiteral(".toDouble()");
mi.cpp.toJsonPre = QStringLiteral("static_cast<qint64>(");
mi.cpp.toJsonPost = QStringLiteral(")");
mi.cpp.defaultValue = QLatin1Char('0');
}
else if (datatype == QLatin1String("boolean") || datatype == QLatin1String("bool"))
@@ -49,6 +49,7 @@ NGL_TARGET_LINK_LIBRARIES(LtsSessionDataDds
$<$<BOOL:${BUILD_RTI}>:$<IF:$<TARGET_EXISTS:ddsconnector>,ddsconnector,>>
PUBLIC
$<$<BOOL:${BUILD_RTI}>:nddscore>
$<$<BOOL:${BUILD_RTI}>:ddsQoS>
NGLLogger
Qt6::Core
)
@@ -56,6 +57,7 @@ IF(BUILD_RTI)
NGL_TARGET_INCLUDE_DIRECTORIES(LtsSessionDataDds
PUBLIC
${RTI_INCLUDE_DIR}
${CMAKE_SOURCE_DIR}/Lts
)
NGL_TARGET_LINK_DIRECTORIES(LtsSessionDataDds
PRIVATE
@@ -13,12 +13,37 @@
#ifdef BUILD_RTI
#include <DDS/DDSConnector/dds_connector.h>
#include <DDS/DTC/generic_dtc_impl.h>
#include <DDS/QosProfile/DDS_DefaultQos>
#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
{
/**
@@ -217,7 +242,7 @@ bool LtsSessionDataDds::init(const DdsConnectionParams& connParams)
#endif
m_ddsConnector = std::make_shared<DDSConnector::DdsConnector>(
connParams.domainId, connParams.partitionType, connParams.partitionId,
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);
@@ -252,7 +277,7 @@ bool LtsSessionDataDds::init(const dds::domain::DomainParticipant& dp, const Dds
if (m_ddsConnector == nullptr)
{
m_ddsConnector =
std::make_shared<DDSConnector::DdsConnector>(dp, connParams.partitionType, type, connParams.partitionId);
std::make_shared<DDSConnector::DdsConnector>(dp, toIdlPartitionType(connParams.partitionType), type, connParams.partitionId);
s_ddsConnections()->insertConnection(connParams, m_ddsConnector);
}
@@ -286,6 +311,19 @@ QString LtsSessionDataDds::partitionTypeString(PartitionType partitionType)
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)")
@@ -313,7 +351,7 @@ int LtsSessionDataDds::partitionId() const
PartitionType LtsSessionDataDds::partitionType() const
{
return m_ddsConnector ? m_ddsConnector->getPartitionType() : PartitionType::Global;
return m_ddsConnector ? toPartitionType(m_ddsConnector->getPartitionType()) : PartitionType::Global;
}
QStringList LtsSessionDataDds::qosFile() const
@@ -23,14 +23,15 @@
#ifdef BUILD_RTI
#include <dds/domain/DomainParticipant.hpp>
#include "INGLLogger.h"
#include "DDS/Core/core_dtc_types.h"
namespace DDSConnector { class DdsConnector; }
namespace DTC { template<typename T> class GenericDTCImpl; }
namespace Core { struct PartitionTime; }
namespace DataPluginBase { class Interface; }
class Fetcher;
namespace GuiPluginBase { class Interface; }
#else
// Forward declarations for stub types
namespace DataPluginBase { class Interface; }
namespace GuiPluginBase { class Interface; }
#endif
namespace LtsSession
@@ -46,6 +47,8 @@ enum class PartitionType {
Invalid = -1
};
class Fetcher;
struct DdsConnectionParams
{
int domainId = -1;
@@ -150,6 +153,26 @@ class LTSSESSIONDATADDS_EXPORT LtsSessionDataDds : public QObject
template<typename T, typename S>
bool getDtc(std::shared_ptr<S> &val) const;
// Foreign GUI interface retrieval - used by Fetcher helper class
template<typename S>
bool getForeignGuiInterface(std::shared_ptr<S> &val) const
{
#ifdef BUILD_RTI
for (const auto &i : m_guiPluginInterfaces)
{
val = std::dynamic_pointer_cast<S>(i);
if (val)
return true;
}
val.reset();
if (m_logger.isDebug())
m_logger.debug() << "Cannot find foreign gui ifc " << typeid(S).name() << " in " << toString();
#else
val.reset();
#endif
return false;
}
signals:
void partitionTimeChanged(qint64 newPartitionTime);
void partitionTimeChangedInternal();
@@ -158,6 +181,7 @@ class LTSSESSIONDATADDS_EXPORT LtsSessionDataDds : public QObject
#ifdef BUILD_RTI
bool initInternal();
void onPartitionTimeChangedInternal();
static LtsSession::PartitionType toPartitionType(IDL::PartitionType idlType);
// Member variables - only with RTI
int m_exerciseId;
@@ -170,6 +194,8 @@ class LTSSESSIONDATADDS_EXPORT LtsSessionDataDds : public QObject
std::shared_ptr<DTC::GenericDTCImpl<Core::PartitionTime>> m_dtcPartitionTime;
NGL::INGLLogger& m_logger;
QMap<QString, std::shared_ptr<DataPluginBase::Interface>> m_dataPluginInterfaces;
QMap<QString, std::shared_ptr<GuiPluginBase::Interface>> m_guiPluginInterfaces;
QStringList m_qosFileList;
#else
// Stub implementation - minimal members
bool initInternal();
@@ -183,6 +209,65 @@ class LTSSESSIONDATADDS_EXPORT LtsSessionDataDds : public QObject
#endif
};
#ifdef BUILD_RTI
class Fetcher
{
public:
Fetcher(LtsSessionDataDds *sessionDataDds, const QString &caller)
: m_sessionDataDds(sessionDataDds)
, m_errors(false)
, m_caller(caller)
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("LtsSession.Fetcher"))
, m_optional(false)
{
}
LtsSessionDataDds *m_sessionDataDds;
bool m_errors;
QString m_caller;
QString m_whatWillNotWork;
NGL::INGLLogger &m_logger;
bool m_optional;
QString m_resultType;
QString m_getterFunctionType;
template <typename ForeignGuiInterface>
void getForeignGuiInterface(std::shared_ptr<ForeignGuiInterface> &foreignGuiInterface, const QString &whatWillNotWork /* only fill if optional */, bool optional)
{
if (!m_sessionDataDds->getForeignGuiInterface(foreignGuiInterface))
{
m_whatWillNotWork = whatWillNotWork;
m_optional = optional;
m_resultType = QString::fromUtf8(typeid(ForeignGuiInterface).name());
m_getterFunctionType = QStringLiteral("gui interface");
print();
}
}
bool status() const
{
return !m_errors;
}
void print()
{
m_errors = true;
QString msg(QStringLiteral("%1 cannot find '%2' in %3 %4"));
if (m_optional)
{
INFO_LOG(m_logger) << msg.arg(m_caller, m_resultType, m_sessionDataDds->toString(), QStringLiteral("' - optional but %1 will not work").arg(m_whatWillNotWork));
}
else // critical
{
ERROR_LOG(m_logger) << msg.arg(m_caller, m_resultType, m_sessionDataDds->toString(), QStringLiteral(" which is required"));
}
}
};
#endif
} // namespace LtsSession
// Template method implementations - must be in header
@@ -20,8 +20,8 @@ SET(SRCS_hdr_only
ADD_LIBRARY(LtsUtilsCoreHeaderOnly INTERFACE)
TARGET_INCLUDE_DIRECTORIES(LtsUtilsCoreHeaderOnly
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/../..
${CMAKE_CURRENT_BINARY_DIR}/../..
${CMAKE_CURRENT_SOURCE_DIR}/../
${CMAKE_CURRENT_BINARY_DIR}/../
)
TARGET_SOURCES(LtsUtilsCoreHeaderOnly INTERFACE ${SRCS_hdr_only})
@@ -40,8 +40,8 @@ SET(SRCS
NGL_ADD_LIBRARY2(ALL LtsUtilsCore SHARED ${SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(LtsUtilsCore
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../..
${CMAKE_CURRENT_BINARY_DIR}/../..
${CMAKE_CURRENT_SOURCE_DIR}/../
${CMAKE_CURRENT_BINARY_DIR}/../
)
NGL_TARGET_LINK_LIBRARIES(LtsUtilsCore
PUBLIC
@@ -37,12 +37,29 @@ CODEGEN_TOPIC_TYPEDEFS(SRCS_common ${xml_FILE})
# generate core_[d|f]tc.h
CODEGEN_CLIENT_TOPICS_IFC(SRCS_common ${xml_FILE})
# Get the generated core_dtc.h path for manual MOC handling
SET(CORE_DTC_H_GENERATED "${CMAKE_CURRENT_BINARY_DIR}/core_dtc.h")
NGL_ADD_LIBRARY2(WS AAR HLA SV ddscore SHARED ${SRCS_common})
# Skip AUTOMOC for generated header - it will be processed manually with correct dependencies
SET_SOURCE_FILES_PROPERTIES(${CORE_DTC_H_GENERATED} PROPERTIES SKIP_AUTOMOC ON)
# Ensure AUTOMOC can find generated headers - add include path
TARGET_INCLUDE_DIRECTORIES(ddscore
PUBLIC
${CMAKE_CURRENT_BINARY_DIR}/../../
)
NGL_TARGET_INCLUDE_DIRECTORIES(ddscore
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../../
${CMAKE_CURRENT_BINARY_DIR}/../../
)
# Manually add MOC for the generated core_dtc.h with proper include paths
QT6_WRAP_CPP(ddscore_moc_sources ${CORE_DTC_H_GENERATED}
OPTIONS --include core_dtc.h -I${CMAKE_CURRENT_BINARY_DIR}/../.. -I${CMAKE_CURRENT_SOURCE_DIR}/../..
)
TARGET_SOURCES(ddscore PRIVATE ${ddscore_moc_sources})
IF(BUILD_RTI)
NGL_TARGET_LINK_LIBRARIES(ddscore
PRIVATE
@@ -20,7 +20,7 @@ SET(SRCS
NGL_ADD_LIBRARY2(AAR SV WS HLA ddsconnector SHARED ${SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(ddsconnector
INTERFACE
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../../
${CMAKE_SOURCE_DIR}
)
@@ -5,6 +5,7 @@
#include "generic_dtc.h"
#include <DDS/Generic/generic_data_reader.h>
#include <DDS/Generic/generic_logger.h>
#include <DDS/Generic/subscriber_listener.h>
#include <QtCore/QTimer>
#include <dds/core/cond/StatusCondition.hpp>
@@ -475,7 +475,7 @@ class GenericFtcImpl final : public GenericFtc<TOPICTYPE_REQUEST, TOPICTYPE_REPL
bool checkSlots(ClassicRequest& request, const char* replySlot, const char* errorSlot)
{
const QByteArray baReply = QByteArray::number(QSIGNAL_CODE) + "signalSignature(" +
const QByteArray baReply = QString::number(QSIGNAL_CODE).toLatin1() + "signalSignature(" +
TopicNameHelper::replyTopicTypeName() + ",int,bool)";
request.replySlot = DDS::Helper::getMethod(m_logger, m_objToInform, replySlot, baReply.data());
if (!request.replySlot.isValid())
@@ -483,7 +483,7 @@ class GenericFtcImpl final : public GenericFtc<TOPICTYPE_REQUEST, TOPICTYPE_REPL
if (errorSlot)
{
const QByteArray baError = QByteArray::number(QSIGNAL_CODE) + "signalSignature(int,int,int)";
const QByteArray baError = QString::number(QSIGNAL_CODE).toLatin1() + "signalSignature(int,int,int)";
request.errorSlot = DDS::Helper::getMethod(m_logger, m_objToInform, errorSlot, baError.data());
if (!request.errorSlot.isValid())
return false;
@@ -31,7 +31,7 @@ inline QByteArray toReadable(const rti::core::Guid& guid)
inline QByteArray toReadable(const rti::core::SequenceNumber& seqNo, const rti::core::Guid& guid)
{
return "SeqNo: " + QByteArray::number(seqNo.value()) + ", Guid-DW: " + toReadable(guid);
return "SeqNo: " + QString::number(seqNo.value()).toLatin1() + ", Guid-DW: " + toReadable(guid);
}
inline QByteArray toReadable(const rti::core::SampleIdentity& identiy)
@@ -331,7 +331,7 @@ template <typename TOPICTYPE> class GenericDataReaderContentFilter final : publi
{
qint64 ptr = reinterpret_cast<qint64>(this);
const QByteArray name = QByteArray(DDS::topic_type_name<TopicType>::value().c_str()) +
"- content filter 0x" + QByteArray::number(ptr, 16);
"- content filter 0x" + QString::number(ptr, 16).toLatin1();
m_filteredTopic = dds::topic::ContentFilteredTopic<TopicType>(BaseClass::m_ddsTopic, name.data(), m_filter);
BaseClass::m_dataReader = DataReader(ddsSubscriber, m_filteredTopic);
}
@@ -24,7 +24,7 @@ ENDIF()
NGL_ADD_LIBRARY2(AAR SV HLA WS ddsQoS SHARED ${SRCS})
NGL_TARGET_INCLUDE_DIRECTORIES(ddsQoS
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/../../../
${CMAKE_CURRENT_SOURCE_DIR}/../../
)
NGL_TARGET_LINK_LIBRARIES(ddsQoS
PRIVATE
@@ -21,7 +21,7 @@ static inline QByteArray toReadable(const rti::core::Guid& guid)
static inline QByteArray toReadable(const rti::core::SequenceNumber& seqNo, const rti::core::Guid& guid)
{
return "SeqNo: " + QByteArray::number(seqNo.value()) + ", Guid-DW: " + toReadable(guid);
return "SeqNo: " + QString::number(seqNo.value()).toLatin1() + ", Guid-DW: " + toReadable(guid);
}
static inline QByteArray toReadable(const rti::core::SampleIdentity& identiy)
@@ -16,7 +16,7 @@
#include <LtsCoordTrans/lts_coord_trans.h>
#include <LtsUtilsCore/qpoint3d.h>
#include <QtCore/QVector>
#include <QVector2D>
#include <Qt6GuiCore/QVector2D>
#include <cmath>
#include <iomanip> // std::setprecision
@@ -29,7 +29,8 @@
SET(_rti_gcc_arch "")
IF(NOT RTI_DIR)
# Check if RTI_DIR is not set OR is empty (cached empty string from previous failed detection)
IF(NOT RTI_DIR OR RTI_DIR STREQUAL "")
SET(_arch "unknown")
IF(WIN32)
SET(_RTI_DIR $ENV{DDS_PATH})
@@ -63,8 +64,10 @@ IF(NOT RTI_DIR)
ELSE(WIN32)
SET(_RTI_DIR $ENV{DDS_PATH})
IF(NOT _RTI_DIR)
# Try local external directory first
IF(EXISTS "${CMAKE_SOURCE_DIR}/../external/rti_connext_dds-7.7.0")
# Try local external directory first (check multiple levels for different repo structures)
IF(EXISTS "${CMAKE_SOURCE_DIR}/../../../external/rti_connext_dds-7.7.0")
SET(_RTI_DIR "${CMAKE_SOURCE_DIR}/../../../external/rti_connext_dds-7.7.0")
ELSEIF(EXISTS "${CMAKE_SOURCE_DIR}/../external/rti_connext_dds-7.7.0")
SET(_RTI_DIR "${CMAKE_SOURCE_DIR}/../external/rti_connext_dds-7.7.0")
ELSEIF(EXISTS "${CMAKE_SOURCE_DIR}/external/rti_connext_dds-7.7.0")
SET(_RTI_DIR "${CMAKE_SOURCE_DIR}/external/rti_connext_dds-7.7.0")
@@ -56,9 +56,10 @@ MACRO(_CODEGEN_ACTION action srcList xmlIn in_files out_files)
SET(_cg ngl_codegen)
SET(_cg $<TARGET_FILE:ngl_codegen>)
SET(_env "QT_PLUGIN_PATH=/usr/lib/x86_64-linux-gnu/qt6/plugins/kf6/ktexttemplate")
ADD_CUSTOM_COMMAND(OUTPUT ${${out_files}}
COMMAND ${_cg}
COMMAND ${CMAKE_COMMAND} -E env ${_env} ${_cg}
ARGS -s ${xmlIn}
-a ${action}
-o ${CMAKE_CURRENT_BINARY_DIR}
@@ -168,10 +169,11 @@ MACRO(CODEGEN_SQL srcList xmlFile_in)
SET(out_dir_sql "${CMAKE_BINARY_DIR}/share/Lts/sql/")
SET(out_file_sql "${out_dir_sql}/${svcNameOut}.sql")
SET(action "SQL")
SET(_cg $<TARGET_FILE:ngl_codegen>)
ADD_CUSTOM_COMMAND(OUTPUT ${out_file_sql}
COMMAND ${CMAKE_COMMAND}
ARGS -E make_directory ${out_dir_sql}
COMMAND ngl_codegen
COMMAND ${CMAKE_COMMAND} -E env QT_PLUGIN_PATH=/usr/lib/x86_64-linux-gnu/qt6/plugins/kf6/ktexttemplate ${_cg}
ARGS -s ${xmlFile_in}
-a ${action}
-o ${out_dir_sql}
@@ -1,6 +1,6 @@
/**
* @RDE_HEADER@
* DTC TypeDefinitions - Stub für BUILD_RTI=OFF
* DTC TypeDefinitions
* $Id$
* $HeadURL$
* $Author$
@@ -8,12 +8,18 @@
#pragma once
// Stub für BUILD_RTI=OFF - keine RTI Connext DDS Verfügbarkeit
// Diese Header ermöglicht Kompilierung ohne RTI DDS Dependencies
#include <functional>
#include <string>
#include <LtsUtils/LtsUtilsCore/data_modification_enum.h>
#include <LtsUtilsCore/data_modification_enum.h>
#ifdef BUILD_RTI
// Use actual RTI Connext DDS types
#include <dds/sub/LoanedSamples.hpp>
#include <dds/sub/SampleInfo.hpp>
// DataModification enum is provided by LtsUtilsCore/data_modification_enum.h
#else
// Stub für BUILD_RTI=OFF - keine RTI Connext DDS Verfügbarkeit
// Diese Header ermöglicht Kompilierung ohne RTI DDS Dependencies
// Forward declarations für DDS-Typen (Stubs)
namespace dds {
@@ -29,6 +35,14 @@ namespace sub {
}
}
// Stub enum for BUILD_RTI=OFF
enum class DataModification {
Added,
Modified,
Removed
};
#endif
namespace NGLLogger
{
class INGLLogger;
@@ -0,0 +1,318 @@
/**
* @RDE_HEADER@
* DataTopicClient (DTC) - Generic
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <DDS/Generic/generic_data_reader.h>
#include <DDS/Generic/subscriber_listener.h>
#include <QTimer>
#include <dds/core/cond/StatusCondition.hpp>
#include <dds/core/cond/WaitSet.hpp>
#include "generic_dtc.h"
namespace DDSGeneric
{
class DynamicDataReader;
}
namespace DTC
{
template<typename SuperClass>
class GenericDtcImplSubscriberTemplate : public DDSGeneric::SubscriberListenerCallback, public SuperClass
{
public:
using DataReaderObject = typename SuperClass::DataReaderObject;
using SubscriberCallback = typename SuperClass::SubscriberCallback;
using TopicTypeRead = typename DataReaderObject::TopicType;
using TopicTypeSubscribe = typename DataReaderObject::TopicType;
using DataReader = typename DataReaderObject::DataReader;
GenericDtcImplSubscriberTemplate(const dds::domain::DomainParticipant &domainParticipant,
const dds::sub::Subscriber &ddsSubscriber,
DDSGeneric::SubscriberListener *subscriberListener,
const std::string &topicName = DDS::Helper::getShortTopicName(DDS::topic_type_name<TopicTypeRead>::value()))
: m_subscriberListener(subscriberListener)
, m_dataReaderObject(new DataReaderObject)
, m_subscriberCallback(nullptr)
, m_writerState(0)
, m_logger(DDS::getLogger(DDS::topic_type_name<TopicTypeRead>::value(), DDS::DataType::DATA_TOPIC_CLIENT))
{
createInternal(m_dataReaderObject->create(domainParticipant, ddsSubscriber, topicName));
}
GenericDtcImplSubscriberTemplate(const dds::domain::DomainParticipant &domainParticipant,
const dds::sub::Subscriber &ddsSubscriber,
DDSGeneric::SubscriberListener *subscriberListener,
const dds::topic::Filter &filter,
const std::string &topicName)
: m_subscriberListener(subscriberListener)
, m_dataReaderObject(new DataReaderObject)
, m_subscriberCallback(nullptr)
, m_writerState(0)
, m_logger(DDS::getLogger(DDS::topic_type_name<TopicTypeRead>::value(), DDS::DataType::DATA_TOPIC_CLIENT))
{
createInternal(m_dataReaderObject->create(domainParticipant, ddsSubscriber, topicName, filter));
}
GenericDtcImplSubscriberTemplate(const dds::domain::DomainParticipant &domainParticipant,
const dds::sub::Subscriber &ddsSubscriber,
DDSGeneric::SubscriberListener *subscriberListener,
const dds::core::xtypes::StructType &structType,
const std::string &topicName)
: m_subscriberListener(subscriberListener)
, m_dataReaderObject(new DataReaderObject)
, m_subscriberCallback(nullptr)
, m_logger(DDS::getLogger(DDS::topic_type_name<TopicTypeRead>::value(), DDS::DataType::DATA_TOPIC_CLIENT))
{
createInternal(m_dataReaderObject->create(domainParticipant, ddsSubscriber, topicName, structType));
}
~GenericDtcImplSubscriberTemplate()
{
if (m_dataReaderObject && m_subscriberCallback)
m_subscriberListener->removeCallback(m_dataReaderObject->getDataReader(), this);
delete m_dataReaderObject;
}
bool setSubscriberCallback(const SubscriberCallback &subscriberCallback) override final
{
if (m_subscriberCallback)
{
WARNING_LOG(m_logger) << "Can not set subscriber callback - already set ...";
return false;
}
if (!m_subscriberListener)
{
WARNING_LOG(m_logger) << "Can not set subscriber callback - no subscriber listener ...";
return false;
}
m_subscriberCallback = subscriberCallback;
if (!m_dataReaderObject)
{
WARNING_LOG(m_logger) << "Can not set subscriber callback - no data reader object ...";
return false;
}
m_dataReaderObject->setHaveSubscriberCallback(m_subscriberCallback != nullptr);
return true;
}
dds::sub::LoanedSamples<TopicTypeRead> readAlive() const override final
{
if (!m_dataReaderObject)
return dds::sub::LoanedSamples<TopicTypeRead>();
bool bSeenUnreadSamples = false;
auto ret = m_dataReaderObject->readAlive(bSeenUnreadSamples);
if (bSeenUnreadSamples)
QTimer::singleShot(0, this, &GenericDtcImplSubscriberTemplate::unreadSamplesDuringRead);
return ret;
}
dds::sub::LoanedSamples<TopicTypeRead> takeAlive() const override final
{
if (!m_dataReaderObject)
return dds::sub::LoanedSamples<TopicTypeRead>();
bool bSeenUnreadSamples = false;
auto ret = m_dataReaderObject->takeAlive(bSeenUnreadSamples);
if (bSeenUnreadSamples)
QTimer::singleShot(0, this, &GenericDtcImplSubscriberTemplate::unreadSamplesDuringRead);
return ret;
}
dds::sub::LoanedSamples<TopicTypeRead> takeDisposed() const override final
{
if (!m_dataReaderObject)
return dds::sub::LoanedSamples<TopicTypeRead>();
return m_dataReaderObject->takeDisposed();
}
bool hasSamples() const override final
{
if (!m_dataReaderObject)
return false;
return m_dataReaderObject->hasSamples();
}
DataReaderObject *dataReader() const override final
{
return m_dataReaderObject;
}
bool waitForHistoricalData(int timeoutMSec) override
{
if (m_dataReaderObject == nullptr ||
m_dataReaderObject->getDataReader() == nullptr)
return false;
const bool bWaitForever = (timeoutMSec < 0);
auto dr = m_dataReaderObject->getDataReader();
try
{
if (dr.subscription_matched_status().current_count() == 0)
{
dds::core::cond::WaitSet ws;
dds::core::cond::StatusCondition cond(dr);
cond.enabled_statuses(dds::core::status::StatusMask::subscription_matched());
ws.attach_condition(cond);
const dds::core::Duration waitTimeout(bWaitForever ? dds::core::Duration::infinite() : dds::core::Duration::from_millisecs(timeoutMSec));
const dds::core::cond::WaitSet::ConditionSeq seq(ws.wait(waitTimeout));
// empty sequence -> timeout
if (seq.empty())
return false;
}
dr.wait_for_historical_data(dds::core::Duration(1));
}
catch (const dds::core::Exception &)
{
// timeout
return false;
}
return true;
}
protected:
void unreadSamplesDuringRead()
{
droDataAvailable(DDS::topic_type_name<TopicTypeRead>::value(), m_dataReaderObject->topicName());
}
void droDataAvailable(const std::string &topicType, const std::string &topicName) override final
{
Q_UNUSED(topicType);
if (m_writerState.testAndSetRelaxed(1, 0))
{
DEBUG_LOG(m_logger) << "Recreate Reader for topic " << topicName
<< ", type name " << DDS::topic_type_name<TopicTypeRead>::value();
if (m_subscriberListener)
m_subscriberListener->removeCallback(m_dataReaderObject->getDataReader(), this);
m_dataReaderObject->recreateReader();
if (m_subscriberListener)
m_subscriberListener->addCallback(m_dataReaderObject->getDataReader(), this);
}
DEBUG_LOG(m_logger) << "IN droDataAvailable(), topic name: " << topicName
<< ", type name " << DDS::topic_type_name<TopicTypeRead>::value()
<< ", this: " << this
<< ", m_dataReaderObject: " << m_dataReaderObject
<< ", hasSamples: " << (m_dataReaderObject ? m_dataReaderObject->hasSamples() : -1);
if (m_subscriberListener)
m_subscriberListener->enableCallback(m_dataReaderObject->getDataReader(), this);
if (!m_dataReaderObject || !m_subscriberCallback)
return;
m_dataReaderObject->read(m_subscriberCallback);
}
void noWriterAnymore(const std::string &topicType, const std::string &topicName) override
{
Q_UNUSED(topicType);
Q_UNUSED(topicName);
m_writerState = -1;
}
void writerAvailable(const std::string &topicType, const std::string &topicName) override
{
Q_UNUSED(topicType);
Q_UNUSED(topicName);
m_writerState.testAndSetRelaxed(-1, 1);
}
bool createInternal(bool droInitOk)
{
if (!droInitOk)
{
ERROR_LOG(m_logger) << "Error initializing DRO for type " << DDS::topic_type_name<TopicTypeRead>::value();
delete m_dataReaderObject;
m_dataReaderObject = nullptr;
return false;
}
if (m_subscriberListener)
{
DEBUG_LOG(m_logger) << "subscriberListener exists, adding type "
<< DDS::topic_type_name<TopicTypeRead>::value();
m_subscriberListener->addCallback(m_dataReaderObject->getDataReader(), this);
}
else
{
DEBUG_LOG(m_logger) << "Cannot add DTC to subscriberListener callback - type: "
<< DDS::topic_type_name<TopicTypeRead>::value();
}
m_dataReaderObject->setHaveSubscriberCallback(m_subscriberListener != nullptr);
return true;
}
private:
DDSGeneric::SubscriberListener *m_subscriberListener;
// DataReaderObjects (DROs)
DataReaderObject *m_dataReaderObject;
// Callback for data processing
SubscriberCallback m_subscriberCallback;
QAtomicInt m_writerState;
NGL::INGLLogger &m_logger;
};
// Typed topic callback (DataReader)
template<typename DRO_OBJECT>
class GenericDtcImpl final
: public GenericDtcImplSubscriberTemplate<GenericDtc<DRO_OBJECT>>
{
using BaseClass = GenericDtcImplSubscriberTemplate<GenericDtc<DRO_OBJECT>>;
public:
using BaseClass::BaseClass;
};
// Typed topic callback (DataReader) with SampleInfo
template<typename DRO_OBJECT>
class GenericDtcImplSampleInfo final
: public GenericDtcImplSubscriberTemplate<GenericDtcSampleInfo<DRO_OBJECT>>
{
using BaseClass = GenericDtcImplSubscriberTemplate<GenericDtcSampleInfo<DRO_OBJECT>>;
public:
using BaseClass::BaseClass;
};
// Dynamic topic callback (DynamicDataReader)
template<typename DRO_OBJECT>
class DdtcImpl final
: public GenericDtcImplSubscriberTemplate<Ddtc<DRO_OBJECT>>
{
using BaseClass = GenericDtcImplSubscriberTemplate<Ddtc<DRO_OBJECT>>;
public:
using BaseClass::BaseClass;
};
// Dynamic topic callback (DynamicDataReader) with SampleInfo
template<typename DRO_OBJECT>
class DdtcImplSampleInfo final
: public GenericDtcImplSubscriberTemplate<DdtcSampleInfo<DRO_OBJECT>>
{
using BaseClass = GenericDtcImplSubscriberTemplate<DdtcSampleInfo<DRO_OBJECT>>;
public:
using BaseClass::BaseClass;
};
} // namespace DTC
Whitespace-only changes.