Compare commits
2
Commits
e398f4903d
...
6513a267e2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6513a267e2 | ||
|
|
b656e1aaa9 |
No files matched your search
@@ -0,0 +1,228 @@
|
||||
# BUILD_RTI=ON Validation Report
|
||||
|
||||
## Executive Summary
|
||||
|
||||
The Lts/DDS module has been successfully migrated to Qt6 with RTI Connext DDS 7.7 integration enabled (`BUILD_RTI=ON`). All core DDS targets compile and link successfully in the Docker build environment.
|
||||
|
||||
**Date:** 2026-09-06
|
||||
**Build Environment:** Ubuntu 26.04, Qt 6.10.2, RTI Connext DDS 7.7
|
||||
**C++ Standard:** C++17 (required for RTI 7.7 compatibility)
|
||||
|
||||
---
|
||||
|
||||
## Build Results
|
||||
|
||||
### Successfully Built Targets
|
||||
|
||||
| Target | Library | Size | Status |
|
||||
|--------|---------|------|--------|
|
||||
| ddscore | libddscore.so | 4.3M | ✅ |
|
||||
| ddsftccore | libddsftccore.so | 550K | ✅ |
|
||||
| ddsQoS | libddsQoS.so | 1.6M | ✅ |
|
||||
| ddsconnector | libddsconnector.so | 4.4M | ✅ |
|
||||
| ddsgen | libddsgen.so | 3.1M | ✅ |
|
||||
|
||||
### Build Configuration
|
||||
|
||||
```bash
|
||||
# Docker image
|
||||
legatus-qt6-build:latest
|
||||
|
||||
# CMake configuration
|
||||
cmake -DBUILD_RTI=ON -DCMAKE_CXX_STANDARD=17 ..
|
||||
|
||||
# RTI License
|
||||
/home/torsten/swy/sandbox/rti_license.dat (empty development license)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Issues Resolved
|
||||
|
||||
### 1. Qt5 API Deprecations (Qt6 Migration)
|
||||
|
||||
**Problem:** `QByteArray::number()` is deprecated/removed in Qt6
|
||||
|
||||
**Solution:** Replace with `QString::number(value).toLatin1()`
|
||||
|
||||
**Files Modified:**
|
||||
- `Lts/DDS/FTC/generic_ftc_impl.h` (2 occurrences)
|
||||
- `Lts/DDS/FTS/connext.h` (1 occurrence)
|
||||
- `Lts/DDS/Routing/routing_plugin.h` (1 occurrence)
|
||||
- `Lts/DDS/Generic/generic_data_reader.h` (1 occurrence)
|
||||
|
||||
### 2. C++ Standard Compatibility
|
||||
|
||||
**Problem:** RTI 7.7 requires C++17, not C++23
|
||||
|
||||
**Solution:** Changed `CMAKE_CXX_STANDARD` from 23 to 17 in parent CMakeLists.txt (line 99)
|
||||
|
||||
### 3. AUTOMOC vs Codegen Timing
|
||||
|
||||
**Problem:** AUTOMOC runs at configure time, but codegen macros run at build time. Generated files like `core_dtc.h` don't exist when moc tries to process them.
|
||||
|
||||
**Solution:**
|
||||
```cmake
|
||||
# Skip AUTOMOC for generated files
|
||||
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/core_dtc.h SKIP_AUTOMOC ON)
|
||||
|
||||
# Manually invoke QT6_WRAP_CPP with proper dependencies
|
||||
qt6_wrap_cpp(NGLEXTRA_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/core_dtc.h
|
||||
OPTIONS -I${CMAKE_SOURCE_DIR}/include -I${CMAKE_SOURCE_DIR}/Lts)
|
||||
```
|
||||
|
||||
### 4. RTI Library Path Resolution
|
||||
|
||||
**Problem:** RTI libraries exist on host at `/home/torsten/swy/sandbox/external/rti_connext_dds-7.7.0/lib/x64Linux4gcc8.5.0/` but must be mounted to `/workspace/external/rti_connext_dds-7.7.0` in container.
|
||||
|
||||
**Solution:** Updated `cmake/FindRTI.cmake` to search `${CMAKE_SOURCE_DIR}/../../../external/` path
|
||||
|
||||
### 5. PartitionType Enum Conversion
|
||||
|
||||
**Problem:** Both `LtsSession::PartitionType` and `IDL::PartitionType` exist with different naming conventions (SCREAMING_SNAKE_CASE vs PascalCase)
|
||||
|
||||
**Solution:** Added conversion functions in `lts_session_data_dds.h/.cpp`:
|
||||
```cpp
|
||||
IDL::PartitionType toIdlPartitionType(PartitionType type);
|
||||
PartitionType toPartitionType(IDL::PartitionType type);
|
||||
```
|
||||
|
||||
### 6. Missing Fetcher Class
|
||||
|
||||
**Problem:** Legacy version has `Fetcher` inline helper class and `m_guiPluginInterfaces` member that were missing from migrated version.
|
||||
|
||||
**Solution:** Added to `lts_session_data_dds.h`:
|
||||
- `m_guiPluginInterfaces` member variable
|
||||
- `getForeignGuiInterface<S>()` template method
|
||||
- `Fetcher` class inline definition
|
||||
|
||||
### 7. Missing generic_dtc_impl.h
|
||||
|
||||
**Problem:** File was missing from migrated version's `include/DDS/DTC/` directory, causing incomplete type errors.
|
||||
|
||||
**Solution:** Copied from legacy version to migrated version.
|
||||
|
||||
### 8. RTI Header Conflicts
|
||||
|
||||
**Problem:** `generic_dtc.h` had stub definitions for `LoanedSamples` and `SampleInfo` that conflicted with RTI's actual headers.
|
||||
|
||||
**Solution:** Added conditional compilation guards:
|
||||
```cpp
|
||||
#ifdef BUILD_RTI
|
||||
#include <dds/sub/LoanedSamples.hpp>
|
||||
#include <dds/sub/SampleInfo.hpp>
|
||||
#else
|
||||
// Stub definitions for BUILD_RTI=OFF
|
||||
#endif
|
||||
```
|
||||
|
||||
### 9. DataModification Enum Conflict
|
||||
|
||||
**Problem:** Stub enum in `generic_dtc.h` (Added, Modified, Removed) conflicted with `LtsUtilsCore/data_modification_enum.h` (eAdded, eModified, eRemoved).
|
||||
|
||||
**Solution:** Only define stub enum when `BUILD_RTI=OFF`.
|
||||
|
||||
---
|
||||
|
||||
## File Changes Summary
|
||||
|
||||
| File | Change Type | Description |
|
||||
|------|-------------|-------------|
|
||||
| `CMakeLists.txt` | Modified | C++17 standard, RTI path resolution |
|
||||
| `cmake/FindRTI.cmake` | Modified | Added external/ directory search path |
|
||||
| `Lts/DDS/Core/CMakeLists.txt` | Modified | AUTOMOC skip, manual QT6_WRAP_CPP |
|
||||
| `Lts/DDS/QosProfile/CMakeLists.txt` | Modified | Fixed include path |
|
||||
| `Lts/DDS/DDSConnector/CMakeLists.txt` | Modified | INTERFACE to PUBLIC include |
|
||||
| `Lts/Common/LtsSession/CMakeLists.txt` | Modified | Added ddsQoS link, fixed include path |
|
||||
| `Lts/Common/LtsSession/lts_session_data_dds.h` | Modified | Added members, Fetcher class, conversion functions |
|
||||
| `Lts/Common/LtsSession/lts_session_data_dds.cpp` | Modified | Implemented conversion functions |
|
||||
| `Lts/DDS/FTC/generic_ftc_impl.h` | Modified | Qt5 API fixes |
|
||||
| `Lts/DDS/FTS/connext.h` | Modified | Qt5 API fix |
|
||||
| `Lts/DDS/Routing/routing_plugin.h` | Modified | Qt5 API fix |
|
||||
| `Lts/DDS/Generic/generic_data_reader.h` | Modified | Qt5 API fix |
|
||||
| `include/DDS/Core/core.hpp` | Renamed | → core.hpp.stub (was blocking generated file) |
|
||||
| `include/DDS/Core/core_dtc_types.h` | Renamed | → core_dtc_types.h.stub (was blocking generated files) |
|
||||
| `include/DDS/DTC/generic_dtc_impl.h` | Added | Copied from legacy |
|
||||
| `include/DDS/DTC/generic_dtc.h` | Modified | Conditional RTI headers, enum fix |
|
||||
| `rti_license.dat` | Created | Empty development license |
|
||||
|
||||
---
|
||||
|
||||
## Known Issues (Out of Scope)
|
||||
|
||||
### 1. ddsfts Build Failure
|
||||
|
||||
**Status:** ❌ Not Built
|
||||
**Cause:** Missing `pdm.idl` from ProjectDataManagement module
|
||||
|
||||
**Details:**
|
||||
The `ddsfts` target depends on IDL files from the ProjectDataManagement module which is not part of the DDS migration scope. The build fails with:
|
||||
```
|
||||
File pdm.idl not found
|
||||
```
|
||||
|
||||
**Resolution Path:**
|
||||
- Requires ProjectDataManagement module to be migrated first
|
||||
- Or create stub pdm.idl for build purposes only
|
||||
|
||||
### 2. ProjectDataManagement Module
|
||||
|
||||
**Location:**
|
||||
- `Lts/Plugins/ProjectDataManagement/`
|
||||
- `Lts/Services/ProjectDataManagement/`
|
||||
|
||||
**Status:** Not migrated
|
||||
**Dependencies:** Required by ddsfts and other Project-related plugins
|
||||
|
||||
**Known Issues:**
|
||||
- pdm.idl not available for DDS codegen
|
||||
- Potential Qt5 API usage (unverified)
|
||||
- CMake configuration not updated for Qt6
|
||||
|
||||
### 3. Project Plugin Qt6 Migration Issues
|
||||
|
||||
**Affected Plugins:**
|
||||
- ProjectEtsPlugin
|
||||
- ProjectAhtcPlugin
|
||||
- ProjectPluginBase
|
||||
- Other Project* plugins
|
||||
|
||||
**Error Type:** `moc "Undefined interface"` errors
|
||||
**Status:** Pre-existing issues, unrelated to DDS/RTI migration
|
||||
|
||||
---
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
- [x] RTI license file created and accessible
|
||||
- [x] RTI libraries mounted and discoverable by CMake
|
||||
- [x] C++17 standard enforced
|
||||
- [x] Qt5 API deprecations resolved
|
||||
- [x] Code generation runs during build (verified via nddsgen warnings in output)
|
||||
- [x] No stub/placeholder files for generated code
|
||||
- [x] ddscore builds successfully
|
||||
- [x] ddsftccore builds successfully
|
||||
- [x] ddsQoS builds successfully
|
||||
- [x] ddsconnector builds successfully
|
||||
- [x] ddsgen builds successfully
|
||||
- [ ] ddsfts builds (blocked by pdm.idl)
|
||||
- [ ] ProjectDataManagement migrated (out of scope)
|
||||
- [ ] Project plugins Qt6 migration (out of scope)
|
||||
|
||||
---
|
||||
|
||||
## Recommendations
|
||||
|
||||
1. **For ddsfts:** Coordinate with ProjectDataManagement team to migrate pdm.idl or create temporary stub
|
||||
2. **For Project Plugins:** Address Qt6 migration issues in parallel workstream
|
||||
3. **For Future RTI Updates:** Document RTI version compatibility matrix (RTI 7.7 → C++17)
|
||||
4. **For Codegen:** Consider caching generated files to speed up clean builds
|
||||
|
||||
---
|
||||
|
||||
## Contact
|
||||
|
||||
For questions about this migration, refer to:
|
||||
- Migration prompt: `./prompts/combined-migration-subfolder-dds-rti-compact.prompt.md`
|
||||
- Build documentation: `./app/Dockerfile`
|
||||
- RTI configuration: `./cmake/FindRTI.cmake`
|
||||
@@ -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")
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
# DDS/RTI Migration - Continuation Prompt
|
||||
|
||||
## Context
|
||||
|
||||
This prompt continues the Qt6 migration work for the Lts/DDS module with RTI Connext DDS 7.7 integration. The core DDS targets (ddscore, ddsftccore, ddsQoS, ddsconnector, ddsgen) have been successfully migrated and build with `BUILD_RTI=ON`.
|
||||
|
||||
## Completed Work
|
||||
|
||||
See `BUILD_RTI_VALIDATION_REPORT.md` for detailed results of completed migration work.
|
||||
|
||||
## Remaining Tasks
|
||||
|
||||
### Priority 1: ddsfts Module
|
||||
|
||||
**Location:** `Lts/DDS/FTS/`
|
||||
|
||||
**Blocker:** Missing `pdm.idl` from ProjectDataManagement module
|
||||
|
||||
**Required Actions:**
|
||||
1. Check if `pdm.idl` exists in legacy Qt5 version
|
||||
2. If exists, copy to migrated version's IDL directory
|
||||
3. Verify CMakeLists.txt references correct IDL path
|
||||
4. If pdm.idl doesn't exist, create minimal stub for build purposes:
|
||||
```idl
|
||||
module ProjectDataManagement {
|
||||
// Stub IDL for build purposes
|
||||
struct ProjectData {
|
||||
string id;
|
||||
};
|
||||
};
|
||||
```
|
||||
5. Rebuild ddsfts target
|
||||
6. Verify no additional RTI header conflicts
|
||||
|
||||
**Files to Check:**
|
||||
- `qt-migration-legatus/qt5-before/qt5-legatus-legacy/Lts/DDS/FTS/` (legacy)
|
||||
- `qt-migration-legatus/qt6-after/qt6-migrated-legatus/Lts/DDS/FTS/` (migrated)
|
||||
- `Lts/Plugins/ProjectDataManagement/` (source of pdm.idl)
|
||||
- `Lts/Services/ProjectDataManagement/` (source of pdm.idl)
|
||||
|
||||
### Priority 2: ProjectDataManagement Module Migration
|
||||
|
||||
**Locations:**
|
||||
- `Lts/Plugins/ProjectDataManagement/`
|
||||
- `Lts/Services/ProjectDataManagement/`
|
||||
|
||||
**Migration Checklist:**
|
||||
- [ ] Inventory all Qt5 API usage (QByteArray::number, deprecated signals/slots, etc.)
|
||||
- [ ] Update CMakeLists.txt for Qt6 (find_package(Qt6 COMPONENTS ...))
|
||||
- [ ] Verify KTextTemplate configuration for any IDL codegen
|
||||
- [ ] Check for AUTOMOC timing issues with generated files
|
||||
- [ ] Update include paths if necessary
|
||||
- [ ] Build with BUILD_RTI=ON to verify compatibility
|
||||
- [ ] Run any existing tests
|
||||
|
||||
**Qt5 API Patterns to Search:**
|
||||
```bash
|
||||
# In ProjectDataManagement directories
|
||||
grep -r "QByteArray::number" --include="*.h" --include="*.cpp"
|
||||
grep -r "QRegExp" --include="*.h" --include="*.cpp"
|
||||
grep -r "QDesktopWidget" --include="*.h" --include="*.cpp"
|
||||
grep -r "QApplication::desktop" --include="*.h" --include="*.cpp"
|
||||
```
|
||||
|
||||
**CMake Updates Needed:**
|
||||
```cmake
|
||||
# Qt5 pattern (legacy)
|
||||
find_package(Qt5 REQUIRED COMPONENTS Core Widgets)
|
||||
|
||||
# Qt6 pattern (migrated)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Widgets)
|
||||
qt_standardize_properties()
|
||||
```
|
||||
|
||||
### Priority 3: Project Plugin Qt6 Migration
|
||||
|
||||
**Affected Plugins:**
|
||||
- `Lts/Plugins/ProjectEtsPlugin/`
|
||||
- `Lts/Plugins/ProjectAhtcPlugin/`
|
||||
- `Lts/Plugins/ProjectPluginBase/`
|
||||
- `Lts/Plugins/Project*Plugin/`
|
||||
|
||||
**Known Error:** `moc "Undefined interface"`
|
||||
|
||||
**Investigation Steps:**
|
||||
1. Check Q_PLUGIN_METADATA declarations
|
||||
2. Verify interface classes have Q_DECLARE_INTERFACE
|
||||
3. Check for missing Q_OBJECT macros
|
||||
4. Verify AUTOMOC is enabled in CMakeLists.txt
|
||||
5. Check for circular dependencies between plugins
|
||||
|
||||
**Common Qt6 Migration Issues:**
|
||||
- Q_PLUGIN_METADATA requires QJsonDocument in Qt6
|
||||
- Interface UUIDs must be consistent
|
||||
- Plugin loading may require Q_PLUGIN_IMPORT in addition to Q_PLUGIN_METADATA
|
||||
|
||||
---
|
||||
|
||||
## Build Commands
|
||||
|
||||
### Standard DDS Build (Working)
|
||||
```bash
|
||||
docker run --rm -it \
|
||||
-v /home/torsten/swy/sandbox:/workspace \
|
||||
-v /home/torsten/swy/sandbox/rti_license.dat:/workspace/rti_license.dat:ro \
|
||||
legatus-qt6-build:latest \
|
||||
bash -c "cd /workspace/qt-migration-legatus/qt6-after/qt6-migrated-legatus && \
|
||||
mkdir -p build && cd build && \
|
||||
cmake -DBUILD_RTI=ON -DCMAKE_CXX_STANDARD=17 .. && \
|
||||
make -j8 ddscore ddsftccore ddsQoS ddsconnector ddsgen"
|
||||
```
|
||||
|
||||
### Full DDS Build (Including ddsfts)
|
||||
```bash
|
||||
docker run --rm -it \
|
||||
-v /home/torsten/swy/sandbox:/workspace \
|
||||
-v /home/torsten/swy/sandbox/rti_license.dat:/workspace/rti_license.dat:ro \
|
||||
legatus-qt6-build:latest \
|
||||
bash -c "cd /workspace/qt-migration-legatus/qt6-after/qt6-migrated-legatus && \
|
||||
mkdir -p build && cd build && \
|
||||
cmake -DBUILD_RTI=ON -DCMAKE_CXX_STANDARD=17 .. && \
|
||||
make -j8 ddscore ddsftccore ddsQoS ddsconnector ddsgen ddsfts"
|
||||
```
|
||||
|
||||
### ProjectDataManagement Build (After Migration)
|
||||
```bash
|
||||
docker run --rm -it \
|
||||
-v /home/torsten/swy/sandbox:/workspace \
|
||||
-v /home/torsten/swy/sandbox/rti_license.dat:/workspace/rti_license.dat:ro \
|
||||
legatus-qt6-build:latest \
|
||||
bash -c "cd /workspace/qt-migration-legatus/qt6-after/qt6-migrated-legatus && \
|
||||
mkdir -p build && cd build && \
|
||||
cmake -DBUILD_RTI=ON -DCMAKE_CXX_STANDARD=17 .. && \
|
||||
make -j8 ProjectDataManagement"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Known Issues Reference
|
||||
|
||||
### Issue: ddsfts Build Failure
|
||||
- **Severity:** High (blocks complete DDS module build)
|
||||
- **Root Cause:** Missing pdm.idl dependency
|
||||
- **Workaround:** Create stub pdm.idl or migrate ProjectDataManagement first
|
||||
- **Files Involved:** `Lts/DDS/FTS/CMakeLists.txt`, `Lts/Plugins/ProjectDataManagement/`
|
||||
|
||||
### Issue: ProjectDataManagement Not Migrated
|
||||
- **Severity:** Medium (blocks ddsfts, affects Project plugins)
|
||||
- **Root Cause:** Not yet started in current migration wave
|
||||
- **Workaround:** None - requires full migration
|
||||
- **Files Involved:** `Lts/Plugins/ProjectDataManagement/`, `Lts/Services/ProjectDataManagement/`
|
||||
|
||||
### Issue: Project Plugin moc Errors
|
||||
- **Severity:** Medium (affects plugin loading, not DDS core)
|
||||
- **Root Cause:** Qt6 plugin interface changes
|
||||
- **Workaround:** Build without plugins or fix Q_PLUGIN_METADATA declarations
|
||||
- **Files Involved:** `Lts/Plugins/Project*Plugin/`
|
||||
|
||||
---
|
||||
|
||||
## Testing Guidelines
|
||||
|
||||
### After ddsfts Build
|
||||
1. Verify libddsfts.so is created
|
||||
2. Check for undefined symbols: `nm -D libddsfts.so | grep U`
|
||||
3. Test plugin loading if applicable
|
||||
|
||||
### After ProjectDataManagement Migration
|
||||
1. Build ddsfts and verify success
|
||||
2. Run any ProjectDataManagement unit tests
|
||||
3. Verify pdm.idl codegen produces expected headers
|
||||
4. Test integration with DDS module
|
||||
|
||||
### After Project Plugin Migration
|
||||
1. Build all Project*Plugin targets
|
||||
2. Verify plugins load at runtime
|
||||
3. Test plugin interfaces with host application
|
||||
4. Check for moc warnings in build output
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
### ddsfts Module
|
||||
- [ ] ddsfts target builds without errors
|
||||
- [ ] libddsfts.so is created
|
||||
- [ ] No undefined symbol errors
|
||||
- [ ] pdm.idl codegen runs successfully
|
||||
|
||||
### ProjectDataManagement Module
|
||||
- [ ] All Qt5 API usage replaced with Qt6 equivalents
|
||||
- [ ] CMakeLists.txt uses Qt6 find_package
|
||||
- [ ] Module builds with BUILD_RTI=ON
|
||||
- [ ] No moc warnings or errors
|
||||
- [ ] pdm.idl generates expected headers
|
||||
|
||||
### Project Plugins
|
||||
- [ ] All Project*Plugin targets build
|
||||
- [ ] No "Undefined interface" moc errors
|
||||
- [ ] Plugins load successfully at runtime
|
||||
- [ ] Plugin interfaces work correctly
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- RTI 7.7 requires C++17 (not C++23)
|
||||
- Empty rti_license.dat is valid for development
|
||||
- Code generation must happen during build (no pre-generated files)
|
||||
- AUTOMOC timing issues require SKIP_AUTOMOC + manual QT6_WRAP_CPP for generated files
|
||||
- RTI headers conflict with stub definitions - use #ifdef BUILD_RTI guards
|
||||
@@ -0,0 +1,255 @@
|
||||
# Known Issues - ddsfts and ProjectDataManagement
|
||||
|
||||
## Overview
|
||||
|
||||
This document tracks known issues blocking the complete migration of the DDS module, specifically the ddsfts target and its dependency on ProjectDataManagement.
|
||||
|
||||
---
|
||||
|
||||
## Issue #1: ddsfts Build Failure
|
||||
|
||||
### Status
|
||||
❌ **Blocked** - Cannot build until pdm.idl is available
|
||||
|
||||
### Error Message
|
||||
```
|
||||
File pdm.idl not found
|
||||
[Error from nddsgen codegen step]
|
||||
```
|
||||
|
||||
### Root Cause
|
||||
The `ddsfts` target depends on IDL files from the ProjectDataManagement module. The file `pdm.idl` is not present in the migrated codebase because:
|
||||
1. ProjectDataManagement module has not been migrated yet
|
||||
2. The IDL file may not exist in the expected location
|
||||
3. CMake IDL search paths may not be configured correctly
|
||||
|
||||
### Impact
|
||||
- ddsfts library cannot be built
|
||||
- Any code depending on ddsfts is blocked
|
||||
- Complete DDS module validation is incomplete
|
||||
|
||||
### Location
|
||||
- **Target:** `Lts/DDS/FTS/CMakeLists.txt`
|
||||
- **Dependency:** `Lts/Plugins/ProjectDataManagement/` or `Lts/Services/ProjectDataManagement/`
|
||||
- **Missing File:** `pdm.idl`
|
||||
|
||||
### Resolution Options
|
||||
|
||||
#### Option A: Migrate ProjectDataManagement First (Recommended)
|
||||
1. Migrate ProjectDataManagement module to Qt6
|
||||
2. Ensure pdm.idl is in correct location
|
||||
3. Update ddsfts CMakeLists.txt to reference correct IDL path
|
||||
4. Rebuild ddsfts
|
||||
|
||||
**Pros:** Proper long-term solution
|
||||
**Cons:** Requires additional migration work
|
||||
|
||||
#### Option B: Create Stub pdm.idl (Temporary)
|
||||
1. Create minimal pdm.idl stub in `include/DDS/FTS/` or similar
|
||||
2. Define only the types needed by ddsfts
|
||||
3. Document as temporary workaround
|
||||
4. Replace with real pdm.idl after ProjectDataManagement migration
|
||||
|
||||
**Pros:** Unblocks ddsfts build quickly
|
||||
**Cons:** May not match actual IDL, could cause runtime issues
|
||||
|
||||
#### Option C: Exclude ddsfts from Build (Workaround)
|
||||
1. Wrap ddsfts in additional CMake conditional
|
||||
2. Build other DDS targets without ddsfts
|
||||
3. Document ddsfts as temporarily unavailable
|
||||
|
||||
**Pros:** Allows other DDS targets to be used
|
||||
**Cons:** Incomplete DDS module
|
||||
|
||||
### Investigation Steps
|
||||
|
||||
1. **Search for pdm.idl in legacy version:**
|
||||
```bash
|
||||
find qt-migration-legatus/qt5-before -name "pdm.idl"
|
||||
```
|
||||
|
||||
2. **Check ProjectDataManagement directories:**
|
||||
```bash
|
||||
ls -la Lts/Plugins/ProjectDataManagement/
|
||||
ls -la Lts/Services/ProjectDataManagement/
|
||||
```
|
||||
|
||||
3. **Check ddsfts CMakeLists.txt for IDL references:**
|
||||
```bash
|
||||
grep -n "pdm" Lts/DDS/FTS/CMakeLists.txt
|
||||
grep -n "IDL" Lts/DDS/FTS/CMakeLists.txt
|
||||
```
|
||||
|
||||
4. **Search for pdm references in code:**
|
||||
```bash
|
||||
grep -r "pdm" Lts/DDS/FTS/ --include="*.h" --include="*.cpp"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Issue #2: ProjectDataManagement Module Not Migrated
|
||||
|
||||
### Status
|
||||
⚠️ **Not Started** - Requires full Qt6 migration
|
||||
|
||||
### Locations
|
||||
- `Lts/Plugins/ProjectDataManagement/`
|
||||
- `Lts/Services/ProjectDataManagement/`
|
||||
|
||||
### Known Dependencies
|
||||
- ddsfts (blocks ddsfts build)
|
||||
- ProjectEtsPlugin (likely depends on ProjectDataManagement)
|
||||
- ProjectAhtcPlugin (likely depends on ProjectDataManagement)
|
||||
- Other Project* plugins
|
||||
|
||||
### Migration Checklist
|
||||
|
||||
#### Phase 1: Assessment
|
||||
- [ ] Inventory all source files (.h, .cpp)
|
||||
- [ ] Inventory all IDL files (.idl)
|
||||
- [ ] Review CMakeLists.txt structure
|
||||
- [ ] Identify Qt5 API usage
|
||||
- [ ] Identify code generation requirements
|
||||
|
||||
#### Phase 2: Qt6 API Migration
|
||||
- [ ] Replace QByteArray::number() → QString::number().toLatin1()
|
||||
- [ ] Replace QRegExp → QRegularExpression
|
||||
- [ ] Replace QDesktopWidget → QScreen
|
||||
- [ ] Update signal/slot syntax if needed
|
||||
- [ ] Update any deprecated Qt classes
|
||||
|
||||
#### Phase 3: CMake Configuration
|
||||
- [ ] Change find_package(Qt5...) to find_package(Qt6...)
|
||||
- [ ] Add qt_standardize_properties()
|
||||
- [ ] Configure KTextTemplate for IDL codegen
|
||||
- [ ] Fix include paths
|
||||
- [ ] Set CMAKE_CXX_STANDARD to 17
|
||||
|
||||
#### Phase 4: RTI Integration
|
||||
- [ ] Verify BUILD_RTI compatibility
|
||||
- [ ] Check for RTI header conflicts
|
||||
- [ ] Test with BUILD_RTI=ON
|
||||
|
||||
#### Phase 5: Validation
|
||||
- [ ] Build without errors
|
||||
- [ ] No moc warnings
|
||||
- [ ] Run unit tests if available
|
||||
- [ ] Verify IDL codegen output
|
||||
|
||||
### Potential Issues
|
||||
|
||||
#### Qt5 API Usage (Expected)
|
||||
Based on patterns in other modules, expect to find:
|
||||
- `QByteArray::number()` - Replace with `QString::number().toLatin1()`
|
||||
- `QRegExp` - Replace with `QRegularExpression`
|
||||
- `QApplication::desktop()` - Replace with `QGuiApplication::primaryScreen()`
|
||||
|
||||
#### Code Generation
|
||||
- May use KTextTemplate for IDL → C++ generation
|
||||
- Check for AUTOMOC timing issues with generated files
|
||||
- May need SKIP_AUTOMOC + manual QT6_WRAP_CPP pattern
|
||||
|
||||
#### Include Paths
|
||||
- Legacy paths may reference `LtsUtils/` instead of `Lts/`
|
||||
- Check all `#include` directives after migration
|
||||
|
||||
---
|
||||
|
||||
## Issue #3: Project Plugin Qt6 Migration Issues
|
||||
|
||||
### Status
|
||||
⚠️ **Pre-existing Issues** - Unrelated to DDS/RTI migration
|
||||
|
||||
### Affected Plugins
|
||||
- ProjectEtsPlugin
|
||||
- ProjectAhtcPlugin
|
||||
- ProjectPluginBase
|
||||
- Project*Plugin (other Project plugins)
|
||||
|
||||
### Error Type
|
||||
```
|
||||
moc: Undefined interface
|
||||
```
|
||||
|
||||
### Root Cause Analysis Needed
|
||||
1. Check Q_PLUGIN_METADATA declarations
|
||||
2. Verify Q_DECLARE_INTERFACE in interface classes
|
||||
3. Check for missing Q_OBJECT macros
|
||||
4. Verify AUTOMOC is enabled
|
||||
5. Check for circular dependencies
|
||||
|
||||
### Investigation Commands
|
||||
```bash
|
||||
# Find all Project plugins
|
||||
find Lts/Plugins -name "*Project*Plugin" -type d
|
||||
|
||||
# Check for Q_PLUGIN_METADATA
|
||||
grep -r "Q_PLUGIN_METADATA" Lts/Plugins/Project*Plugin/ --include="*.h"
|
||||
|
||||
# Check for Q_DECLARE_INTERFACE
|
||||
grep -r "Q_DECLARE_INTERFACE" Lts/Plugins/Project*Plugin/ --include="*.h"
|
||||
|
||||
# Check CMakeLists.txt for AUTOMOC
|
||||
grep -r "AUTOMOC" Lts/Plugins/Project*Plugin/CMakeLists.txt
|
||||
```
|
||||
|
||||
### Common Qt6 Plugin Issues
|
||||
|
||||
#### Issue: Q_PLUGIN_METADATA requires QJsonDocument
|
||||
**Qt5:**
|
||||
```cpp
|
||||
Q_PLUGIN_METADATA(IID "com.example.PluginInterface" FILE "plugin.json")
|
||||
```
|
||||
|
||||
**Qt6:** May require additional QJsonDocument handling
|
||||
|
||||
#### Issue: Interface UUID Changes
|
||||
Plugin interface UUIDs must be consistent between:
|
||||
- Q_DECLARE_INTERFACE declaration
|
||||
- Q_PLUGIN_METADATA IID string
|
||||
- Plugin loader expectations
|
||||
|
||||
#### Issue: Plugin Loading
|
||||
Qt6 may require both Q_PLUGIN_METADATA and Q_PLUGIN_IMPORT for proper plugin loading.
|
||||
|
||||
---
|
||||
|
||||
## Resolution Priority
|
||||
|
||||
| Priority | Issue | Impact | Effort | Recommendation |
|
||||
|----------|-------|--------|--------|----------------|
|
||||
| 1 | ddsfts missing pdm.idl | High (blocks DDS) | Low-Medium | Create stub or migrate ProjectDataManagement |
|
||||
| 2 | ProjectDataManagement migration | High (enables ddsfts) | High | Full migration required |
|
||||
| 3 | Project plugin moc errors | Medium (plugins only) | Medium | Fix after DDS module complete |
|
||||
|
||||
---
|
||||
|
||||
## Action Items
|
||||
|
||||
### Immediate (Unblock ddsfts)
|
||||
- [ ] Search for pdm.idl in legacy codebase
|
||||
- [ ] If found, copy to migrated version
|
||||
- [ ] If not found, create minimal stub
|
||||
- [ ] Update ddsfts CMakeLists.txt if needed
|
||||
- [ ] Rebuild ddsfts
|
||||
|
||||
### Short-term (Complete DDS module)
|
||||
- [ ] Migrate ProjectDataManagement module
|
||||
- [ ] Verify all DDS targets build with BUILD_RTI=ON
|
||||
- [ ] Document any remaining issues
|
||||
|
||||
### Long-term (Complete Qt6 migration)
|
||||
- [ ] Migrate all Project* plugins
|
||||
- [ ] Fix moc "Undefined interface" errors
|
||||
- [ ] Verify plugin loading at runtime
|
||||
- [ ] Run full test suite
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- BUILD_RTI Validation Report: `BUILD_RTI_VALIDATION_REPORT.md`
|
||||
- Migration Continuation Prompt: `DDS_RTI_MIGRATION_CONTINUATION_PROMPT.md`
|
||||
- Migration Instructions: `../prompts/combined-migration-subfolder-dds-rti-compact.prompt.md`
|
||||
- RTI Configuration: `../cmake/FindRTI.cmake`
|
||||
- Build Environment: `../app/Dockerfile`
|
||||
@@ -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)
|
||||
|
||||
+1
-1
@@ -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}
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -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.
Reference in new issue
Block a user