diff --git a/.github/workflows/docker-reusable-workflow.yml b/.github/workflows/docker-reusable-workflow.yml index 531eb4de..22753ac9 100644 --- a/.github/workflows/docker-reusable-workflow.yml +++ b/.github/workflows/docker-reusable-workflow.yml @@ -82,10 +82,21 @@ jobs: -t ${{ env.DDSENABLER_COMPOSE_TEST_DOCKER_IMAGE }} \ -f Dockerfile . - # Check Docker images exist - - name: Check if Docker images exist + # Check DDS Enabler Docker images exist + - name: Check if DDS Enabler Docker images exist run: | - [ -n "$(docker images -q ${{ env.DDSENABLER_COMPOSE_TEST_DOCKER_IMAGE }})" ] || echo "DDS Enabler Docker image does not exists" + [ -n "$(docker images -q ${{ env.DDSENABLER_COMPOSE_TEST_DOCKER_IMAGE }})" ] || echo "DDS Enabler Docker image does not exist" + + # Pull ROS 2 Docker image + - name: Pull ROS 2 Docker image + run: | + docker image pull \ + ${{ env.DDSENABLER_COMPOSE_TEST_ROS2_DOCKER_IMAGE }} + + # Check ROS 2 Docker images exist + - name: Check if ROS 2 Docker images exist + run: | + [ -n "$(docker images -q ${{ env.DDSENABLER_COMPOSE_TEST_ROS2_DOCKER_IMAGE }})" ] || echo "ROS 2 Docker image does not exist" - name: Download dependencies and install requirements uses: ./src/.github/actions/project_dependencies diff --git a/.github/workflows/reusable-workflow.yml b/.github/workflows/reusable-workflow.yml index cabcc123..47a7964e 100644 --- a/.github/workflows/reusable-workflow.yml +++ b/.github/workflows/reusable-workflow.yml @@ -72,7 +72,7 @@ jobs: uses: eProsima/eProsima-CI/multiplatform/colcon_build_test@main with: packages_names: ${{ env.code_packages_names }} - cmake_args: -DBUILD_TESTS=ON -DCMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} + cmake_args: -DBUILD_TESTS=ON -DCMAKE_BUILD_TYPE=${{ matrix.cmake_build_type }} -DCOMPILE_EXAMPLES=ON workspace_dependencies: install ctest_args: --label-exclude "xfail" colcon_meta_file: src/.github/workflows/configurations/${{ runner.os }}/colcon.meta diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4124dc36..e3180dab 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,7 +38,7 @@ on: dependencies_artifact_postfix: description: 'Postfix name to add to artifact name to download dependencies. This is use to download a specific artifact version from eProsima-CI.' required: true - default: '_nightly' + default: '_ddsenabler' pull_request: push: @@ -51,7 +51,7 @@ jobs: name: reusable_tests uses: ./.github/workflows/reusable-ubuntu-ci.yml with: - dependencies_artifact_postfix: ${{ inputs.dependencies_artifact_postfix || '_nightly' }} + dependencies_artifact_postfix: ${{ inputs.dependencies_artifact_postfix || '_ddsenabler' }} ref: ${{ github.ref }} secrets: inherit @@ -59,7 +59,7 @@ jobs: name: reusable_tests uses: ./.github/workflows/reusable-windows-ci.yml with: - dependencies_artifact_postfix: ${{ inputs.dependencies_artifact_postfix || '_nightly' }} + dependencies_artifact_postfix: ${{ inputs.dependencies_artifact_postfix || '_ddsenabler' }} ref: ${{ github.ref }} secrets: inherit @@ -72,6 +72,6 @@ jobs: devutils_branch: ${{ inputs.devutils_branch || 'main' }} ddspipe_branch: ${{ inputs.ddspipe_branch || 'main' }} ddsenabler_branch: ${{ inputs.ddsenabler_branch || github.head_ref || github.ref_name }} - dependencies_artifact_postfix: ${{ inputs.dependencies_artifact_postfix || '_nightly' }} + dependencies_artifact_postfix: ${{ inputs.dependencies_artifact_postfix || '_ddsenabler' }} ref: ${{ github.ref }} secrets: inherit diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..d666beed --- /dev/null +++ b/.gitignore @@ -0,0 +1,64 @@ + +### C++ ### +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +### Vim ### +# swap +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +# session +Session.vim +# temporary +.netrwhist +*~ +# auto-generated tag files +tags + +build/ +install/ +log/ + +### Visual Studio ### +.vs + +### Visual Studio Code ### +.vscode + +### Documentation ### +docs/rst/_static/css/online_eprosima_rtd_theme.css + + +### Python ### +# Precompile files +__pycache__ diff --git a/ddsenabler/DDS_ENABLER_CONFIGURATION.json b/ddsenabler/DDS_ENABLER_CONFIGURATION.json index 3be31cdc..4bdfa292 100644 --- a/ddsenabler/DDS_ENABLER_CONFIGURATION.json +++ b/ddsenabler/DDS_ENABLER_CONFIGURATION.json @@ -23,7 +23,9 @@ } ] }, - "ddsenabler": null, + "ddsenabler": { + "initial-publish-wait": 500 + }, "specs": { "threads": 12, "logging": { diff --git a/ddsenabler/DDS_ENABLER_CONFIGURATION.yaml b/ddsenabler/DDS_ENABLER_CONFIGURATION.yaml index d06934f0..4702da85 100644 --- a/ddsenabler/DDS_ENABLER_CONFIGURATION.yaml +++ b/ddsenabler/DDS_ENABLER_CONFIGURATION.yaml @@ -13,6 +13,7 @@ dds: # DDS Enabler configuration ddsenabler: + initial-publish-wait: 500 #Specs configuration specs: diff --git a/ddsenabler/examples/CLIParser.hpp b/ddsenabler/examples/CLIParser.hpp index 2548d9f3..a9469f4f 100644 --- a/ddsenabler/examples/CLIParser.hpp +++ b/ddsenabler/examples/CLIParser.hpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -28,10 +29,16 @@ class CLIParser struct example_config { - uint32_t expected_types_ = 0; - uint32_t expected_data_ = 0; - uint32_t timeout_seconds = 30; - std::string config_file_path_ = ""; + uint32_t expected_types = 0; + uint32_t expected_topics = 0; + uint32_t expected_data = 0; + uint32_t timeout = 30; + std::string config_file_path = ""; + std::string persistence_path = ""; + std::string publish_path = ""; + std::string publish_topic = ""; + uint32_t publish_period = 500; + uint32_t publish_initial_wait = 0; }; /** @@ -44,18 +51,31 @@ class CLIParser static void print_help( uint8_t return_code) { - std::cout << "Usage: ddsenabler_example " << - std::endl; - std::cout << "" << - std::endl; - std::cout << "expected_types: number of types to be expected" << - std::endl; - std::cout << "expected_data: number of data to be expected" << - std::endl; - std::cout << "timeout: time to wait before stopping the program if the data is not received" << - std::endl; - std::cout << "path/to/config/file: absolute path to the configuration file" << - std::endl; + std::cout << "Usage: ddsenabler_example [options]" << std::endl; + std::cout << "" << std::endl; + std::cout << "--config Path to the configuration file" << std::endl; + std::cout << " (Default: '')" << std::endl; + std::cout << "--expected-types Number of types expected to be received" << std::endl; + std::cout << " (Default: 0)" << std::endl; + std::cout << "--expected-topics Number of topics expected to be received" << std::endl; + std::cout << " (Default: 0)" << std::endl; + std::cout << "--expected-data Number of samples expected to be received" << std::endl; + std::cout << " (Default: 0)" << std::endl; + std::cout << "--timeout Time (seconds) to wait before stopping the" << std::endl; + std::cout << " program if expectations are not met" << std::endl; + std::cout << " (Default: 30)" << std::endl; + std::cout << "--persistence-path Path to the persistence directory" << std::endl; + std::cout << " (Default: '')" << std::endl; + std::cout << "--publish-path Path to the directory with the samples" << std::endl; + std::cout << " to be published" << std::endl; + std::cout << " (Default: '')" << std::endl; + std::cout << "--publish-topic Topic name in which samples are published" << std::endl; + std::cout << " (Default: '')" << std::endl; + std::cout << "--publish-period Data publication period in milliseconds" << std::endl; + std::cout << " (Default: 500)" << std::endl; + std::cout << "--publish-initial-wait Time (seconds) to wait before starting" << std::endl; + std::cout << " data publication" << std::endl; + std::cout << " (Default: 0)" << std::endl; std::exit(return_code); } @@ -74,22 +94,224 @@ class CLIParser { example_config config; - if (argc < 5) + if (argc < 2) { - std::cerr << "Missing entity argument" << std::endl; + std::cerr << "Configuration file path is required" << std::endl; print_help(EXIT_FAILURE); } - try + for (int i = 1; i < argc; ++i) { - config.expected_types_ = std::stoi(argv[1]); - config.expected_data_ = std::stoi(argv[2]); - config.timeout_seconds = std::stoi(argv[3]); - config.config_file_path_ = argv[4]; + std::string arg = argv[i]; + + if (arg == "-h" || arg == "--help") + { + print_help(EXIT_SUCCESS); + } + else if (arg == "--config") + { + if (++i < argc) + { + config.config_file_path = argv[i]; + if (!std::filesystem::exists(config.config_file_path)) + { + std::cerr << "Invalid configuration file path: " << config.config_file_path << std::endl; + print_help(EXIT_FAILURE); + } + } + else + { + std::cerr << "Failed to parse --config argument" << std::endl; + print_help(EXIT_FAILURE); + } + } + else if (arg == "--expected-types") + { + if (++i < argc) + { + try + { + config.expected_types = static_cast(std::stoi(argv[i])); + } + catch (const std::exception& e) + { + std::cerr << "Invalid --expected-types argument " << std::string(argv[i]) << ": " << + std::string(e.what()) << std::endl; + print_help(EXIT_FAILURE); + } + } + else + { + std::cerr << "Failed to parse --expected-types argument" << std::endl; + print_help(EXIT_FAILURE); + } + } + else if (arg == "--expected-topics") + { + if (++i < argc) + { + try + { + config.expected_topics = static_cast(std::stoi(argv[i])); + } + catch (const std::exception& e) + { + std::cerr << "Invalid --expected-topics argument " << std::string(argv[i]) << ": " << + std::string(e.what()) << std::endl; + print_help(EXIT_FAILURE); + } + } + else + { + std::cerr << "Failed to parse --expected-topics argument" << std::endl; + print_help(EXIT_FAILURE); + } + } + else if (arg == "--expected-data") + { + if (++i < argc) + { + try + { + config.expected_data = static_cast(std::stoi(argv[i])); + } + catch (const std::exception& e) + { + std::cerr << "Invalid --expected-data argument " << std::string(argv[i]) << ": " << std::string( + e.what()) << std::endl; + print_help(EXIT_FAILURE); + } + } + else + { + std::cerr << "Failed to parse --expected-data argument" << std::endl; + print_help(EXIT_FAILURE); + } + } + else if (arg == "--timeout") + { + if (++i < argc) + { + try + { + config.timeout = static_cast(std::stoi(argv[i])); + } + catch (const std::exception& e) + { + std::cerr << "Invalid --timeout argument " << std::string(argv[i]) << ": " << std::string( + e.what()) << std::endl; + print_help(EXIT_FAILURE); + } + } + else + { + std::cerr << "Failed to parse --timeout argument" << std::endl; + print_help(EXIT_FAILURE); + } + } + else if (arg == "--persistence-path") + { + if (++i < argc) + { + config.persistence_path = argv[i]; + } + else + { + std::cerr << "Failed to parse --persistence-path argument" << std::endl; + print_help(EXIT_FAILURE); + } + } + else if (arg == "--publish-path") + { + if (++i < argc) + { + config.publish_path = argv[i]; + if (!std::filesystem::exists(config.publish_path) || + !std::filesystem::is_directory(config.publish_path)) + { + std::cerr << "Invalid publish path: " << config.publish_path << std::endl; + print_help(EXIT_FAILURE); + } + } + else + { + std::cerr << "Failed to parse --publish-path argument" << std::endl; + print_help(EXIT_FAILURE); + } + } + else if (arg == "--publish-topic") + { + if (++i < argc) + { + config.publish_topic = argv[i]; + } + else + { + std::cerr << "Failed to parse --publish-topic argument" << std::endl; + print_help(EXIT_FAILURE); + } + } + else if (arg == "--publish-period") + { + if (++i < argc) + { + try + { + config.publish_period = static_cast(std::stoi(argv[i])); + } + catch (const std::exception& e) + { + std::cerr << "Invalid --publish-period argument " << std::string(argv[i]) << ": " << + std::string( + e.what()) << std::endl; + print_help(EXIT_FAILURE); + } + } + else + { + std::cerr << "Failed to parse --publish-period argument" << std::endl; + print_help(EXIT_FAILURE); + } + } + else if (arg == "--publish-initial-wait") + { + if (++i < argc) + { + try + { + config.publish_initial_wait = static_cast(std::stoi(argv[i])); + } + catch (const std::exception& e) + { + std::cerr << "Invalid --publish-initial-wait argument " << std::string(argv[i]) << ": " << + std::string( + e.what()) << std::endl; + print_help(EXIT_FAILURE); + } + } + else + { + std::cerr << "Failed to parse --publish-initial-wait argument" << std::endl; + print_help(EXIT_FAILURE); + } + } + else + { + std::cerr << "Failed to parse unknown argument: " << arg << std::endl; + print_help(EXIT_FAILURE); + } } - catch (const std::exception& e) + + if (config.config_file_path.empty()) { - EPROSIMA_LOG_ERROR(CLI_PARSER, "Error parsing command line arguments: " << e.what()); + std::cerr << "Configuration file path is required" << std::endl; + print_help(EXIT_FAILURE); + } + + // Check that if publish path is set, publish topic is also set + if (!config.publish_path.empty() && config.publish_topic.empty()) + { + std::cerr << "Publish topic is required when publish path is set" << std::endl; print_help(EXIT_FAILURE); } @@ -123,4 +345,3 @@ class CLIParser } }; - diff --git a/ddsenabler/examples/config.yml b/ddsenabler/examples/config.yml index 7fc78ef3..5cc4050d 100644 --- a/ddsenabler/examples/config.yml +++ b/ddsenabler/examples/config.yml @@ -21,3 +21,6 @@ dds: transport: shm whitelist-interfaces: - "127.0.0.1" + +ddsenabler: + initial-publish-wait: 500 diff --git a/ddsenabler/examples/main.cpp b/ddsenabler/examples/main.cpp index 4e4d8a5b..9976c3f6 100644 --- a/ddsenabler/examples/main.cpp +++ b/ddsenabler/examples/main.cpp @@ -17,77 +17,358 @@ * */ +#include #include +#include +#include +#include +#include #include +#include #include -#include +#include #include "ddsenabler/dds_enabler_runner.hpp" #include "ddsenabler/DDSEnabler.hpp" + #include "CLIParser.hpp" +#include "utils.hpp" +CLIParser::example_config config; uint32_t received_types_ = 0; +uint32_t received_topics_ = 0; uint32_t received_data_ = 0; -std::mutex type_received_mutex_; -std::mutex data_received_mutex_; +std::mutex app_mutex_; +std::condition_variable app_cv_; bool stop_app_ = false; -// Static type callback -static void test_type_callback( - const char* typeName, - const char* topicName, - const char* serializedType) +const std::string SAMPLES_SUBDIR = "samples"; +const std::string TYPES_SUBDIR = "types"; +const std::string TOPICS_SUBDIR = "topics"; + +// Static log callback +void test_log_callback( + const char* file_name, + int line_no, + const char* func_name, + int category, + const char* msg) +{ + // NOTE: Default stdout logs can be disabled via configuration ("logging": {"stdout": false}) to avoid duplicated traces + + std::stringstream ss; + ss << file_name << ":" << line_no << " (" << func_name << "): " << msg << std::endl; + if (category == eprosima::utils::Log::Kind::Info) + { + std::cout << "[INFO] " << ss.str(); + } + else if (category == eprosima::utils::Log::Kind::Warning) + { + std::cerr << "[WARNING] " << ss.str(); + } + else if (category == eprosima::utils::Log::Kind::Error) + { + std::cerr << "[ERROR] " << ss.str(); + } +} + +// Static type notification callback +static void test_type_notification_callback( + const char* type_name, + const char* serialized_type, + const unsigned char* serialized_type_internal, + uint32_t serialized_type_internal_size, + const char* data_placeholder) +{ + bool notify = false; + { + std::lock_guard lock(app_mutex_); + notify = ++received_types_ >= config.expected_types; + std::cout << "Type callback received: " << type_name << ", Total types: " << + received_types_ << std::endl << serialized_type << std::endl << std::endl; + if (!config.persistence_path.empty() && + !save_type_to_file((std::filesystem::path(config.persistence_path) / TYPES_SUBDIR).string(), type_name, + serialized_type_internal, serialized_type_internal_size)) + { + std::cerr << "Failed to save type: " << type_name << std::endl; + } + } + if (notify) + { + app_cv_.notify_all(); + } +} + +// Static type query callback +static bool test_type_query_callback( + const char* type_name, + std::unique_ptr& serialized_type_internal, + uint32_t& serialized_type_internal_size) +{ + if (config.persistence_path.empty()) + { + std::cerr << "Persistence path is not set, cannot query type: " << type_name << std::endl; + return false; + } + + // Load the type from file + if (!load_type_from_file((std::filesystem::path(config.persistence_path) / TYPES_SUBDIR).string(), type_name, + serialized_type_internal, serialized_type_internal_size)) + { + std::cerr << "Failed to load type: " << type_name << std::endl; + return false; + } + return true; +} + +// Static topic notification callback +static void test_topic_notification_callback( + const char* topic_name, + const char* type_name, + const char* serialized_qos) +{ + bool notify = false; + { + std::lock_guard lock(app_mutex_); + notify = ++received_topics_ >= config.expected_topics; + std::cout << "Topic callback received: " << topic_name << " of type " << type_name << ", Total topics: " << + received_topics_ << std::endl << serialized_qos << std::endl << std::endl; + if (!config.persistence_path.empty() && + !save_topic_to_file((std::filesystem::path(config.persistence_path) / TOPICS_SUBDIR).string(), + topic_name, + type_name, serialized_qos)) + { + std::cerr << "Failed to save topic: " << topic_name << std::endl; + } + } + if (notify) + { + app_cv_.notify_all(); + } +} + +// Static type query callback +static bool test_topic_query_callback( + const char* topic_name, + std::string& type_name, + std::string& serialized_qos) { - std::lock_guard lock(type_received_mutex_); + if (config.persistence_path.empty()) + { + std::cerr << "Persistence path is not set, cannot query topic: " << topic_name << std::endl; + return false; + } - received_types_++; - std::cout << "Type callback received: " << typeName << ", Total types: " << - received_types_ << std::endl; + // Load the topic from file + if (!load_topic_from_file((std::filesystem::path(config.persistence_path) / TOPICS_SUBDIR).string(), topic_name, + type_name, + serialized_qos)) + { + std::cerr << "Failed to load topic: " << topic_name << std::endl; + return false; + } + return true; } -// Static data callback -static void test_data_callback( - const char* typeName, - const char* topicName, +// Static data notification callback +static void test_data_notification_callback( + const char* topic_name, const char* json, - int64_t publishTime) + int64_t publish_time) { - std::lock_guard lock(data_received_mutex_); + bool notify = false; + { + std::lock_guard lock(app_mutex_); + notify = ++received_data_ >= config.expected_data; + std::cout << "Data callback received: " << topic_name << ", Total data: " << + received_data_ << std::endl << json << std::endl << std::endl; + if (!config.persistence_path.empty() && + !save_data_to_file((std::filesystem::path(config.persistence_path) / SAMPLES_SUBDIR).string(), + topic_name, json, + publish_time)) + { + std::cerr << "Failed to save data for topic: " << topic_name << std::endl; + } + } + if (notify) + { + app_cv_.notify_all(); + } +} + +bool validate_received( + const CLIParser::example_config& config) +{ + return (received_types_ >= config.expected_types) && + (received_topics_ >= config.expected_topics) && + (received_data_ >= config.expected_data); +} - received_data_++; - std::cout << "Data callback received: " << typeName << ", Total data: " << - received_data_ << std::endl; +bool expected_received( + const CLIParser::example_config& config) +{ + if (!config.expected_types && !config.expected_topics && !config.expected_data) + { + // No expectations set, return false to avoid immediate exit + return false; + } + return validate_received(config); } -int get_received_types() +void init_persistence( + const std::string& persistence_path) { - std::lock_guard lock(type_received_mutex_); + auto ensure_directory_exists = [](const std::filesystem::path& path) + { + if (!std::filesystem::exists(path) && !std::filesystem::create_directories(path)) + { + std::cerr << "Failed to create directory: " << path << std::endl; + } + }; - return received_types_; + if (!persistence_path.empty()) + { + ensure_directory_exists(persistence_path); + std::vector subdirs = {SAMPLES_SUBDIR, TYPES_SUBDIR, TOPICS_SUBDIR}; + for (const auto& sub : subdirs) + { + ensure_directory_exists(std::filesystem::path(persistence_path) / sub); + } + } } -int get_received_data() +void get_sorted_files( + const std::string& directory, + std::vector>& files) { - std::lock_guard lock(data_received_mutex_); + for (const auto& entry : std::filesystem::directory_iterator(directory)) + { + if (entry.is_regular_file()) + { + std::string filename = entry.path().filename().string(); + try + { + // assumes name is just a number + files.emplace_back(entry.path(), static_cast(std::stoll(filename))); + } + catch (const std::invalid_argument& e) + { + std::cerr << "Skipping non-numeric file: " << filename << std::endl; + } + } + } - return received_data_; + // Sort files by numeric value + std::sort(files.begin(), files.end(), + [](const auto& a, const auto& b) + { + return a.second < b.second; + }); +} + +void publish_routine( + std::shared_ptr enabler, + const std::string& publish_path, + const std::string& topic_name, + uint32_t publish_period, + uint32_t publish_initial_wait, + std::mutex& app_mutex, + std::condition_variable& app_cv, + bool& stop_app) +{ + // Wait a bit before starting to publish so types and topics can be discovered + std::this_thread::sleep_for(std::chrono::milliseconds(publish_initial_wait)); + + // Get collection of files to publish, sorted in increasing order by their name (assumed to be numeric) + std::vector> sample_files; + get_sorted_files(publish_path, sample_files); + + for (const auto& [path, number] : sample_files) + { + std::ifstream file(path, std::ios::binary); + if (file) + { + std::string file_content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + + if (enabler->publish(topic_name, file_content)) + { + std::cout << "Published content from file: " << path.filename() << " in topic: " + << topic_name << std::endl; + } + else + { + std::cerr << "Failed to publish content from file: " << path.filename() << " in topic: " + << topic_name << std::endl; + } + } + else + { + std::cerr << "Failed to open file: " << path << std::endl; + } + + // Wait publish period or until stop signal is received + std::unique_lock lock(app_mutex); + if (app_cv.wait_for(lock, std::chrono::milliseconds(publish_period), + [&stop_app] + { + return stop_app; + })) + { + std::cout << "Publish routine stopped." << std::endl; + return; + } + } } void signal_handler( int signum) { std::cout << "Signal " << CLIParser::parse_signal(signum) << " received, stopping..." << std::endl; - stop_app_ = true; + { + std::lock_guard lock(app_mutex_); + stop_app_ = true; + } + app_cv_.notify_all(); } int main( int argc, char** argv) { - CLIParser::example_config config = CLIParser::parse_cli_options(argc, argv); + using namespace eprosima::ddsenabler; + + eprosima::utils::Log::ReportFilenames(true); + + config = CLIParser::parse_cli_options(argc, argv); - std::unique_ptr enabler; - create_dds_enabler(config.config_file_path_.c_str(), test_data_callback, test_type_callback, nullptr, enabler); + init_persistence(config.persistence_path); + + CallbackSet callbacks{ + test_log_callback, + { + test_type_notification_callback, + test_topic_notification_callback, + test_data_notification_callback, + test_type_query_callback, + test_topic_query_callback + } + }; + + std::shared_ptr enabler; + if (!create_dds_enabler(config.config_file_path.c_str(), callbacks, enabler)) + { + std::cerr << "Failed to create DDS Enabler with the provided configuration." << std::endl; + return EXIT_FAILURE; + } + + std::thread publish_thread; + if (!config.publish_path.empty()) + { + publish_thread = std::thread(publish_routine, + enabler, config.publish_path, config.publish_topic, config.publish_period, + config.publish_initial_wait, std::ref( + app_mutex_), std::ref(app_cv_), std::ref(stop_app_)); + } signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); @@ -96,23 +377,27 @@ int main( signal(SIGHUP, signal_handler); #endif // _WIN32 - // Loop until timeout seconds - auto end_time = std::chrono::steady_clock::now() + std::chrono::seconds(config.timeout_seconds); - while (std::chrono::steady_clock::now() < end_time) + int ret_code = EXIT_SUCCESS; { - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - if (stop_app_) + std::unique_lock lock(app_mutex_); + if (app_cv_.wait_for(lock, std::chrono::seconds(config.timeout), + [] + { + return stop_app_ || expected_received(config); + })) { - return EXIT_SUCCESS; + ret_code = EXIT_SUCCESS; } - else if (get_received_types() >= config.expected_types_ && - get_received_data() >= config.expected_data_) + else { - std::cout << "Received enough data, stopping..." << std::endl; - return EXIT_SUCCESS; + std::cerr << "Timeout reached, stopping..." << std::endl; + ret_code = validate_received(config) ? EXIT_SUCCESS : EXIT_FAILURE; } } - std::cout << "Timeout reached, stopping..." << std::endl; - return EXIT_FAILURE; + if (publish_thread.joinable()) + { + publish_thread.join(); + } + return ret_code; } diff --git a/ddsenabler/examples/utils.hpp b/ddsenabler/examples/utils.hpp new file mode 100644 index 00000000..e49c73ed --- /dev/null +++ b/ddsenabler/examples/utils.hpp @@ -0,0 +1,364 @@ +// Copyright 2025 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include + +#pragma once + +// TODO: move these methods somewhere they can be reused + +std::string safe_file_name( + const std::string& name) +{ + std::string safe_name = name; + for (auto& c : safe_name) + { + if (c == ':' || c == '/' || c == '\\') + { + c = '_'; + } + } + return safe_name; +} + +bool save_type_to_file( + const std::string& directory, + const char* type_name, + const unsigned char*& serialized_type_internal, + uint32_t serialized_type_internal_size) +{ + // Check if directory exists + if (!std::filesystem::exists(directory)) + { + std::cerr << "Directory does not exist: " << directory << std::endl; + return false; + } + + // Remove problematic characters + std::string safe_type_name = safe_file_name(type_name); + + // Construct full file path + auto file_path = std::filesystem::path(directory) / (safe_type_name + ".bin"); + + // Check if already exists, do nothing if it does + if (std::filesystem::exists(file_path)) + { + std::cout << "File already exists: " << file_path << std::endl; + return true; + } + + // Open file in binary mode + std::ofstream ofs(file_path, std::ios::binary); + if (!ofs) + { + std::cerr << "Error opening file for writing: " << file_path << std::endl; + return false; + } + + // Write the binary data + ofs.write(reinterpret_cast(serialized_type_internal), serialized_type_internal_size); + + if (!ofs.good()) + { + std::cerr << "Error writing to file: " << file_path << std::endl; + return false; + } + + ofs.close(); + return true; +} + +bool load_type_from_file( + const std::string& directory, + const char* type_name, + std::unique_ptr& serialized_type_internal, + uint32_t& serialized_type_internal_size) +{ + // Check if directory exists + if (!std::filesystem::exists(directory)) + { + std::cerr << "Directory does not exist: " << directory << std::endl; + return false; + } + + // Remove problematic characters + std::string safe_type_name = safe_file_name(type_name); + + // Construct full file path + auto file_path = std::filesystem::path(directory) / (safe_type_name + ".bin"); + + // Check if exists + if (!std::filesystem::exists(file_path)) + { + std::cerr << "File does not exist: " << file_path << std::endl; + return false; + } + + // Open file in binary mode, position at end to get size + std::ifstream ifs(file_path, std::ios::binary | std::ios::ate); + if (!ifs) + { + std::cerr << "Error opening file for reading: " << file_path << std::endl; + return false; + } + + // Get file size + std::streamsize size = ifs.tellg(); + if (size <= 0) + { + std::cerr << "File is empty or invalid: " << file_path << std::endl; + return false; + } + serialized_type_internal_size = static_cast(size); + + // Allocate memory with unique_ptr + std::unique_ptr temp_buffer(new unsigned char[serialized_type_internal_size]); + + // Read the data + ifs.seekg(0, std::ios::beg); + if (!ifs.read(reinterpret_cast(temp_buffer.get()), serialized_type_internal_size)) + { + std::cerr << "Error reading file: " << file_path << std::endl; + serialized_type_internal_size = 0; + return false; + } + + // Transfer ownership and cast to const + serialized_type_internal = std::unique_ptr(std::move(temp_buffer)); + + return true; +} + +bool save_topic_to_file( + const std::string& directory, + const char* topic_name, + const char* type_name, + const char* serialized_qos) +{ + // Check if directory exists + if (!std::filesystem::exists(directory)) + { + std::cerr << "Directory does not exist: " << directory << std::endl; + return false; + } + + // Remove problematic characters + std::string safe_topic_name = safe_file_name(topic_name); + + // Construct full file path + auto file_path = std::filesystem::path(directory) / (safe_topic_name + ".bin"); + + // Check if already exists, do nothing if it does + if (std::filesystem::exists(file_path)) + { + std::cout << "File already exists: " << file_path << std::endl; + return true; + } + + // Open file in binary mode + std::ofstream ofs(file_path, std::ios::binary); + if (!ofs) + { + std::cerr << "Error opening file for writing: " << file_path << std::endl; + return false; + } + + // Write type name + uint32_t len_type_name = static_cast(std::strlen(type_name)); + ofs.write(reinterpret_cast(&len_type_name), sizeof(len_type_name)); + ofs.write(type_name, len_type_name); + + // Write serialized QoS + uint32_t len_serialized_qos = static_cast(std::strlen(serialized_qos)); + ofs.write(reinterpret_cast(&len_serialized_qos), sizeof(len_serialized_qos)); + ofs.write(serialized_qos, len_serialized_qos); + + if (!ofs.good()) + { + std::cerr << "Error writing to file: " << file_path << std::endl; + return false; + } + + ofs.close(); + return true; +} + +bool load_topic_from_file( + const std::string& directory, + const char* topic_name, + std::string& type_name, + std::string& serialized_qos) +{ + // Check if directory exists + if (!std::filesystem::exists(directory)) + { + std::cerr << "Directory does not exist: " << directory << std::endl; + return false; + } + + // Remove problematic characters + std::string safe_topic_name = safe_file_name(topic_name); + + // Construct full file path + auto file_path = std::filesystem::path(directory) / (safe_topic_name + ".bin"); + + // Check if exists + if (!std::filesystem::exists(file_path)) + { + std::cerr << "File does not exist: " << file_path << std::endl; + return false; + } + + // Open file in binary mode + std::ifstream ifs(file_path, std::ios::binary); + if (!ifs) + { + std::cerr << "Error opening file for reading: " << file_path << std::endl; + return false; + } + + uint32_t len_type_name = 0, len_serialized_qos = 0; + + // Read type name length + ifs.read(reinterpret_cast(&len_type_name), sizeof(len_type_name)); + if (!ifs.good() || len_type_name == 0) + { + std::cerr << "Error reading type name length." << std::endl; + return false; + } + + // Read type name + std::vector type_name_buffer(len_type_name); + ifs.read(type_name_buffer.data(), len_type_name); + if (!ifs.good()) + { + std::cerr << "Error reading type name." << std::endl; + return false; + } + + // Read serialized QoS length + ifs.read(reinterpret_cast(&len_serialized_qos), sizeof(len_serialized_qos)); + if (!ifs.good() || len_serialized_qos == 0) + { + std::cerr << "Error reading serialized qos length." << std::endl; + return false; + } + + // Read serialized QoS + std::vector serialized_qos_buffer(len_serialized_qos); + ifs.read(serialized_qos_buffer.data(), len_serialized_qos); + if (!ifs.good()) + { + std::cerr << "Error reading serialized qos." << std::endl; + return false; + } + + type_name.assign(type_name_buffer.begin(), type_name_buffer.end()); + serialized_qos.assign(serialized_qos_buffer.begin(), serialized_qos_buffer.end()); + + return true; +} + +bool save_data_to_file( + const std::string& directory, + const std::string& topic_name, + const std::string& json, + int64_t publish_time) +{ + // Check if directory exists + if (!std::filesystem::exists(directory)) + { + std::cerr << "Directory does not exist: " << directory << std::endl; + return false; + } + + // Remove problematic characters + std::string safe_topic_name = safe_file_name(topic_name); + + // Construct topic folder path + auto topic_path = std::filesystem::path(directory) / safe_topic_name; + + // Create directory if it does not exist + if (!std::filesystem::exists(topic_path) && !std::filesystem::create_directories(topic_path)) + { + std::cerr << "Error creating directory: " << topic_path << std::endl; + return false; + } + + // Construct full file path + auto file_path = topic_path / std::to_string(publish_time); + + // Check if exists, fail if it does + if (std::filesystem::exists(file_path)) + { + std::cerr << "File already exists: " << file_path << std::endl; + return false; + } + + // Open file in text mode + std::ofstream ofs(file_path); + if (!ofs) + { + std::cerr << "Error opening file for writing: " << file_path << std::endl; + return false; + } + + // Check if JSON is valid + nlohmann::json full_json; + try + { + full_json = nlohmann::json::parse(json); + } + catch (const nlohmann::json::parse_error& e) + { + std::cerr << "Error parsing JSON: " << e.what() << std::endl; + return false; + } + + // Extract the DDS data + auto it = full_json.find(topic_name); + if (it == full_json.end()) + { + std::cerr << "Error: JSON does not contain data for topic: " << topic_name << std::endl; + return false; + } + nlohmann::json& json_data = (*it)["data"]; + + if (json_data.empty()) + { + std::cerr << "Error: No data found for topic: " << topic_name << std::endl; + return false; + } + + if (json_data.size() > 1) + { + std::cerr << "Warning: Multiple data entries found for topic: " << topic_name + << ". Only the first one will be written to file." << std::endl; + } + + // Write DDS data only + ofs << std::setw(4) << json_data.begin().value(); + if (!ofs.good()) + { + std::cerr << "Error writing to file: " << file_path << std::endl; + return false; + } + + ofs.close(); + return true; +} diff --git a/ddsenabler/include/ddsenabler/CallbackSet.hpp b/ddsenabler/include/ddsenabler/CallbackSet.hpp new file mode 100644 index 00000000..0f3fc0af --- /dev/null +++ b/ddsenabler/include/ddsenabler/CallbackSet.hpp @@ -0,0 +1,60 @@ +// Copyright 2025 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file CallbackSet.hpp + */ + +#pragma once + +#include + +namespace eprosima { +namespace ddsenabler { + +/** + * @brief Struct that encapsulates all the DDS related callbacks used by the DDS Enabler. + */ +struct DdsCallbacks +{ + //! Callback for notifying the reception of DDS types + participants::DdsTypeNotification type_notification{nullptr}; + + //! Callback for notifying the reception of DDS topics + participants::DdsTopicNotification topic_notification{nullptr}; + + //! Callback for notifying the reception of DDS data + participants::DdsDataNotification data_notification{nullptr}; + + //! Callback for requesting information of a DDS type + participants::DdsTypeQuery type_query{nullptr}; + + //! Callback for requesting information of a DDS topic + participants::DdsTopicQuery topic_query{nullptr}; +}; + +/** + * @brief Struct that encapsulates all the callbacks used by the DDS Enabler. + */ +struct CallbackSet +{ + //! Callback executed when consuming log messages + participants::DdsLogFunc log{nullptr}; + + //! DDS related callbacks + DdsCallbacks dds; +}; + +} /* namespace ddsenabler */ +} /* namespace eprosima */ diff --git a/ddsenabler/include/ddsenabler/DDSEnabler.hpp b/ddsenabler/include/ddsenabler/DDSEnabler.hpp index 3489c391..76c3a10f 100644 --- a/ddsenabler/include/ddsenabler/DDSEnabler.hpp +++ b/ddsenabler/include/ddsenabler/DDSEnabler.hpp @@ -19,10 +19,10 @@ #pragma once #include -#include + +#include #include -#include #include #include @@ -33,14 +33,16 @@ #include #include -#include -#include - +#include #include #include +#include +#include #include +#include +#include namespace eprosima { namespace ddsenabler { @@ -53,29 +55,17 @@ class DDSEnabler public: /** - * DDSEnabler constructor by required values and event handler reference. + * DDSEnabler constructor by required values. * * Creates DDSEnabler instance with given configuration. * * @param configuration: Structure encapsulating all enabler configuration options. - * @param event_handler: Reference to event handler used for thread synchronization in main application. + * @param callbacks: Set of callbacks to be used by the enabler. */ + DDSENABLER_DllAPI DDSEnabler( const yaml::EnablerConfiguration& configuration, - std::shared_ptr event_handler); - - - void set_data_callback( - participants::DdsNotification callback) - { - cb_handler_.get()->set_data_callback(callback); - } - - void set_type_callback( - participants::DdsTypeNotification callback) - { - cb_handler_.get()->set_type_callback(callback); - } + const CallbackSet& callbacks); /** * Associate the file watcher to the configuration file and establish the callback to reload the configuration. @@ -84,6 +74,7 @@ class DDSEnabler * * @return \c true if operation was succesful, \c false otherwise. */ + DDSENABLER_DllAPI bool set_file_watcher( const std::string& file_path); @@ -96,9 +87,22 @@ class DDSEnabler * @return \c RETCODE_NO_DATA if new allowed topics list is the same as the previous one * @return \c RETCODE_ERROR if any other error has occurred. */ + DDSENABLER_DllAPI utils::ReturnCode reload_configuration( yaml::EnablerConfiguration& new_configuration); + /** + * Publish a JSON message to the specified topic. + * + * @param topic_name: The name of the topic to publish to. + * @param json: The JSON message to publish. + * @return \c true if the message was published successfully, \c false otherwise. + */ + DDSENABLER_DllAPI + bool publish( + const std::string& topic_name, + const std::string& json); + protected: /** @@ -109,6 +113,18 @@ class DDSEnabler void load_internal_topics_( yaml::EnablerConfiguration& configuration); + /** + * Set the internal callbacks used by the enabler. + * + * @param callbacks: The set of callbacks to be used by the enabler. + */ + void set_internal_callbacks_( + const CallbackSet& callbacks); + + //! Store reference to DomainParticipantFactory to avoid Fast-DDS singletons being destroyed before they should + std::shared_ptr part_factory_ = + eprosima::fastdds::dds::DomainParticipantFactory::get_shared_instance(); + //! Configuration of the DDS Enabler yaml::EnablerConfiguration configuration_; @@ -127,18 +143,15 @@ class DDSEnabler //! CB Handler std::shared_ptr cb_handler_; - //! Dynamic Types Participant - std::shared_ptr dyn_participant_; + //! DDS Participant + std::shared_ptr dds_participant_; - //! Schema Participant - std::shared_ptr enabler_participant_; + //! Enabler Participant + std::shared_ptr enabler_participant_; //! DDS Pipe std::unique_ptr pipe_; - //! Reference to event handler used for thread synchronization in main application - std::shared_ptr event_handler_; - //! Config File watcher handler std::unique_ptr file_watcher_handler_; diff --git a/ddsenabler/include/ddsenabler/dds_enabler_runner.hpp b/ddsenabler/include/ddsenabler/dds_enabler_runner.hpp index e3236031..ea51c40a 100644 --- a/ddsenabler/include/ddsenabler/dds_enabler_runner.hpp +++ b/ddsenabler/include/ddsenabler/dds_enabler_runner.hpp @@ -19,35 +19,42 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include - -#include - #include -#include -#include "ddsenabler/DDSEnabler.hpp" +#include +#include -using namespace eprosima::ddspipe; -using namespace eprosima::ddsenabler; +#include namespace eprosima { namespace ddsenabler { +/** + * @brief Create a DDS Enabler instance from a configuration file path. + * + * @param [in] configuration_path Path to the configuration file. + * @param [in] callbacks Set of callbacks to be used by the DDS Enabler. + * @param [out] enabler Output parameter to hold the created DDS Enabler instance. + * @return true if the DDS Enabler was created successfully, false otherwise. + */ +DDSENABLER_DllAPI bool create_dds_enabler( - const char* ddsEnablerConfigFile, - participants::DdsNotification data_callback, - participants::DdsTypeNotification type_callback, - participants::DdsLogFunc log_callback, - std::unique_ptr& enabler); - + const char* configuration_path, + const CallbackSet& callbacks, + std::shared_ptr& enabler); +/** + * @brief Create a DDS Enabler instance from a configuration object. + * + * @param [in] configuration DDS Enabler configuration object. + * @param [in] callbacks Set of callbacks to be used by the DDS Enabler. + * @param [out] enabler Output parameter to hold the created DDS Enabler instance. + * @return true if the DDS Enabler was created successfully, false otherwise. + */ +DDSENABLER_DllAPI +bool create_dds_enabler( + yaml::EnablerConfiguration configuration, + const CallbackSet& callbacks, + std::shared_ptr& enabler); } /* namespace ddsenabler */ } /* namespace eprosima */ diff --git a/ddsenabler/src/cpp/DDSEnabler.cpp b/ddsenabler/src/cpp/DDSEnabler.cpp index fae299f1..fcf9669a 100644 --- a/ddsenabler/src/cpp/DDSEnabler.cpp +++ b/ddsenabler/src/cpp/DDSEnabler.cpp @@ -12,9 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include - #include #include @@ -34,9 +31,8 @@ using namespace eprosima::utils; DDSEnabler::DDSEnabler( const yaml::EnablerConfiguration& configuration, - std::shared_ptr event_handler) + const CallbackSet& callbacks) : configuration_(configuration) - , event_handler_(event_handler) { // Load the Enabler's internal topics from a configuration object. load_internal_topics_(configuration_); @@ -53,12 +49,12 @@ DDSEnabler::DDSEnabler( // Create CB Handler configuration participants::CBHandlerConfiguration handler_config; - // Create DynTypes Participant - dyn_participant_ = std::make_shared( + // Create DDS Participant + dds_participant_ = std::make_shared( configuration_.simple_configuration, payload_pool_, discovery_database_); - dyn_participant_->init(); + dds_participant_->init(); // Create CB Handler cb_handler_ = std::make_shared( @@ -66,7 +62,7 @@ DDSEnabler::DDSEnabler( payload_pool_); // Create Enabler Participant - enabler_participant_ = std::make_shared( + enabler_participant_ = std::make_shared( configuration_.enabler_configuration, payload_pool_, discovery_database_, @@ -77,20 +73,31 @@ DDSEnabler::DDSEnabler( // Populate Participant Database participants_database_->add_participant( - dyn_participant_->id(), - dyn_participant_); + dds_participant_->id(), + dds_participant_); participants_database_->add_participant( enabler_participant_->id(), enabler_participant_); // Create DDS Pipe + // NOTE: Create disabled, and enable after all callbacks are set to avoid missing notifications pipe_ = std::make_unique( configuration_.ddspipe_configuration, discovery_database_, payload_pool_, participants_database_, thread_pool_); + + // Set user defined callbacks in all internal entities requiring it + set_internal_callbacks_(callbacks); + + // Enable DDS Pipe after having set all callbacks + if (pipe_->enable() != utils::ReturnCode::RETCODE_OK) + { + throw utils::InitializationException( + utils::Formatter() << "Failed to enable DDS Pipe."); + } } bool DDSEnabler::set_file_watcher( @@ -121,11 +128,13 @@ bool DDSEnabler::set_file_watcher( } else if (ret == utils::ReturnCode::RETCODE_NO_DATA) { - EPROSIMA_LOG_INFO(DDSENABLER_EXECUTION, "No relevant changes in configuration file " << file_path); + EPROSIMA_LOG_INFO(DDSENABLER_EXECUTION, + "No relevant changes in configuration file " << file_path); } else { - EPROSIMA_LOG_WARNING(DDSENABLER_EXECUTION, "Failed to reload configuration from file " << file_path); + EPROSIMA_LOG_WARNING(DDSENABLER_EXECUTION, + "Failed to reload configuration from file " << file_path); } } catch (const std::exception& e) @@ -136,7 +145,8 @@ bool DDSEnabler::set_file_watcher( }; // Creating FileWatcher event handler - file_watcher_handler_ = std::make_unique(file_watcher_callback, file_path); + file_watcher_handler_ = std::make_unique(file_watcher_callback, + file_path); return true; } @@ -176,5 +186,37 @@ void DDSEnabler::load_internal_topics_( } } +void DDSEnabler::set_internal_callbacks_( + const CallbackSet& callbacks) +{ + if (callbacks.dds.type_notification) + { + cb_handler_->set_type_notification_callback(callbacks.dds.type_notification); + } + if (callbacks.dds.topic_notification) + { + cb_handler_->set_topic_notification_callback(callbacks.dds.topic_notification); + } + if (callbacks.dds.data_notification) + { + cb_handler_->set_data_notification_callback(callbacks.dds.data_notification); + } + if (callbacks.dds.type_query) + { + cb_handler_->set_type_query_callback(callbacks.dds.type_query); + } + if (callbacks.dds.topic_query) + { + enabler_participant_->set_topic_query_callback(callbacks.dds.topic_query); + } +} + +bool DDSEnabler::publish( + const std::string& topic_name, + const std::string& json) +{ + return enabler_participant_->publish(topic_name, json); +} + } /* namespace ddsenabler */ } /* namespace eprosima */ diff --git a/ddsenabler/src/cpp/dds_enabler_runner.cpp b/ddsenabler/src/cpp/dds_enabler_runner.cpp index 551b30c0..aa58fd1a 100644 --- a/ddsenabler/src/cpp/dds_enabler_runner.cpp +++ b/ddsenabler/src/cpp/dds_enabler_runner.cpp @@ -17,14 +17,18 @@ * */ -#include #include -#include "fastdds/dds/log/FileConsumer.hpp" +#include +#include +#include +#include -#include "ddsenabler/dds_enabler_runner.hpp" +#include -#include +#include + +#include using namespace eprosima::ddspipe; @@ -32,30 +36,64 @@ namespace eprosima { namespace ddsenabler { bool create_dds_enabler( - const char* ddsEnablerConfigFile, - participants::DdsNotification data_callback, - participants::DdsTypeNotification type_callback, - participants::DdsLogFunc log_callback, - std::unique_ptr& enabler) + const char* configuration_path, + const CallbackSet& callbacks, + std::shared_ptr& enabler) { std::string dds_enabler_config_file = ""; - if (ddsEnablerConfigFile != NULL) + if (configuration_path != NULL) { - dds_enabler_config_file = ddsEnablerConfigFile; + dds_enabler_config_file = configuration_path; } - // Encapsulating execution in block to erase all memory correctly before closing process try { // Load configuration from file eprosima::ddsenabler::yaml::EnablerConfiguration configuration(dds_enabler_config_file); + // Create DDS Enabler instance + if (!create_dds_enabler( + configuration, + callbacks, + enabler)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_EXECUTION, + "Failed to create DDS Enabler from configuration file: " << dds_enabler_config_file); + return false; + } + + // Set the file watcher to reload the configuration if the file changes + if (!enabler->set_file_watcher(dds_enabler_config_file)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_EXECUTION, + "Failed to set file watcher."); + return false; + } + } + catch (const eprosima::utils::ConfigurationException& e) + { + EPROSIMA_LOG_ERROR(DDSENABLER_EXECUTION, + "Error Loading DDS Enabler Configuration. Error message:\n " << e.what()); + return false; + } + + return true; +} + +bool create_dds_enabler( + yaml::EnablerConfiguration configuration, + const CallbackSet& callbacks, + std::shared_ptr& enabler) +{ + try + { // Verify that the configuration is correct eprosima::utils::Formatter error_msg; if (!configuration.is_valid(error_msg)) { - throw eprosima::utils::ConfigurationException( - eprosima::utils::Formatter() << "Invalid configuration: " << error_msg); + EPROSIMA_LOG_ERROR(DDSENABLER_EXECUTION, + "Invalid configuration: " << error_msg); + return false; } // Logging @@ -65,11 +103,11 @@ bool create_dds_enabler( eprosima::utils::Log::ClearConsumers(); eprosima::utils::Log::SetVerbosity(log_configuration.verbosity); - if (log_callback) + if (callbacks.log) { // User callback Log Consumer auto* log_consumer = new eprosima::ddsenabler::participants::DDSEnablerLogConsumer(&log_configuration); - log_consumer->set_log_callback(log_callback); + log_consumer->set_log_callback(callbacks.log); eprosima::utils::Log::RegisterConsumer( std::unique_ptr(log_consumer)); @@ -94,23 +132,8 @@ bool create_dds_enabler( EPROSIMA_LOG_INFO(DDSENABLER_EXECUTION, "Starting DDS Enabler execution."); - // Create a multiple event handler that handles all events that make the enabler stop - auto close_handler = std::make_shared(); - - // Create DDSEnabler and set the context broker callbacks - enabler.reset(new DDSEnabler(configuration, close_handler)); - - // TODO: avoid setting callback after having created "enabled" enabler (e.g. pass and set in construction) - enabler->set_data_callback(data_callback); - enabler->set_type_callback(type_callback); - - // Set the file watcher to reload the configuration if the file changes - if (!enabler->set_file_watcher(dds_enabler_config_file)) - { - EPROSIMA_LOG_ERROR(DDSENABLER_EXECUTION, - "Failed to set file watcher."); - return false; - } + // Create DDSEnabler + enabler.reset(new DDSEnabler(configuration, callbacks)); EPROSIMA_LOG_INFO(DDSENABLER_EXECUTION, "DDS Enabler running."); @@ -118,8 +141,7 @@ bool create_dds_enabler( catch (const eprosima::utils::ConfigurationException& e) { EPROSIMA_LOG_ERROR(DDSENABLER_EXECUTION, - "Error Loading DDS Enabler Configuration from file " << dds_enabler_config_file << - ". Error message:\n " << e.what()); + "Error Loading DDS Enabler Configuration. Error message:\n " << e.what()); return false; } catch (const eprosima::utils::InitializationException& e) diff --git a/ddsenabler/test/DDSEnablerTester.hpp b/ddsenabler/test/DDSEnablerTester.hpp index b80c3ff0..a3c65e43 100644 --- a/ddsenabler/test/DDSEnablerTester.hpp +++ b/ddsenabler/test/DDSEnablerTester.hpp @@ -24,7 +24,7 @@ #include #include -#include "DDSEnabler.hpp" +#include "ddsenabler/dds_enabler_runner.hpp" using namespace eprosima::ddspipe; using namespace eprosima::ddsenabler; @@ -56,6 +56,7 @@ class DDSEnablerTester : public ::testing::Test { std::cout << "Setting up test..." << std::endl; received_types_ = 0; + received_topics_ = 0; received_data_ = 0; current_test_instance_ = this; // Set the current instance for callbacks } @@ -65,33 +66,42 @@ class DDSEnablerTester : public ::testing::Test { std::cout << "Tearing down test..." << std::endl; std::cout << "Received types before reset: " << received_types_ << std::endl; + std::cout << "Received topics before reset: " << received_topics_ << std::endl; std::cout << "Received data before reset: " << received_data_ << std::endl; received_types_ = 0; + received_topics_ = 0; received_data_ = 0; current_test_instance_ = nullptr; } // Create the DDSEnabler and bind the static callbacks - std::unique_ptr create_ddsenabler() + std::shared_ptr create_ddsenabler() { YAML::Node yml; eprosima::ddsenabler::yaml::EnablerConfiguration configuration(yml); configuration.simple_configuration->domain = DOMAIN_; - auto close_handler = std::make_shared(); - - auto enabler = std::make_unique(configuration, close_handler); + CallbackSet callbacks{ + test_log_callback, + { + test_type_notification_callback, + test_topic_notification_callback, + test_data_notification_callback, + test_type_query_callback, + test_topic_query_callback + } + }; - // Bind the static callbacks (no captures allowed) - enabler->set_data_callback(test_data_callback); - enabler->set_type_callback(test_type_callback); + // Create DDS Enabler + std::shared_ptr enabler; + bool result = create_dds_enabler(configuration, callbacks, enabler); return enabler; } // Create the DDSEnabler and bind the static callbacks - std::unique_ptr create_ddsenabler_w_history() + std::shared_ptr create_ddsenabler_w_history() { const char* yml_str = R"( @@ -112,15 +122,18 @@ class DDSEnablerTester : public ::testing::Test return nullptr; } - auto close_handler = std::make_shared(); - - auto enabler = std::make_unique(configuration, close_handler); - - // Bind the static callbacks (no captures allowed) - enabler->set_data_callback(test_data_callback); - enabler->set_type_callback(test_type_callback); + CallbackSet callbacks{ + test_log_callback, + { + test_type_notification_callback, + test_topic_notification_callback, + test_data_notification_callback, + test_type_query_callback, + test_topic_query_callback + } + }; - return enabler; + return std::make_shared(configuration, callbacks); } bool create_publisher( @@ -249,39 +262,84 @@ class DDSEnablerTester : public ::testing::Test return true; } - // Static type callback - static void test_type_callback( - const char* typeName, - const char* topicName, - const char* serializedType) + // eprosima::ddsenabler::participants::DdsDataNotification data_notification; + static void test_data_notification_callback( + const char* topic_name, + const char* json, + int64_t publish_time) + { + if (current_test_instance_) + { + std::lock_guard lock(current_test_instance_->data_received_mutex_); + + current_test_instance_->received_data_++; + std::cout << "Data callback received: " << topic_name << ", Total data: " << + current_test_instance_->received_data_ << std::endl; + } + } + + // eprosima::ddsenabler::participants::DdsTypeNotification type_notification; + static void test_type_notification_callback( + const char* type_name, + const char* serialized_type, + const unsigned char* serialized_type_internal, + uint32_t serialized_type_internal_size, + const char* data_placeholder) { if (current_test_instance_) { std::lock_guard lock(current_test_instance_->type_received_mutex_); current_test_instance_->received_types_++; - std::cout << "Type callback received: " << typeName << ", Total types: " << + std::cout << "Type callback received: " << type_name << ", Total types: " << current_test_instance_->received_types_ << std::endl; } } - // Static data callback - static void test_data_callback( - const char* typeName, - const char* topicName, - const char* json, - int64_t publishTime) + // eprosima::ddsenabler::participants::DdsTopicNotification topic_notification + static void test_topic_notification_callback( + const char* topic_name, + const char* type_name, + const char* serialized_qos) { if (current_test_instance_) { - std::lock_guard lock(current_test_instance_->data_received_mutex_); + std::lock_guard lock(current_test_instance_->topic_received_mutex_); - current_test_instance_->received_data_++; - std::cout << "Data callback received: " << typeName << ", Total data: " << - current_test_instance_->received_data_ << std::endl; + current_test_instance_->received_topics_++; + std::cout << "Topic callback received: " << topic_name << ", Total topics: " << + current_test_instance_->received_topics_ << std::endl; } } + // eprosima::ddsenabler::participants::DdsTopicQuery topic_query; + static bool test_topic_query_callback( + const char* topic_name, + std::string& type_name, + std::string& serialized_qos) + { + return false; + } + + // eprosima::ddsenabler::participants::DdsTypeQuery type_query; + static bool test_type_query_callback( + const char* type_name, + std::unique_ptr& serialized_type_internal, + uint32_t& serialized_type_internal_size) + { + return false; + } + + //eprosima::ddsenabler::participants::DdsLogFunc log_callback; + static void test_log_callback( + const char* fileName, + int lineNo, + const char* funcName, + int category, + const char* msg) + { + } + int get_received_types() { if (current_test_instance_) @@ -296,6 +354,20 @@ class DDSEnablerTester : public ::testing::Test } } + int get_received_topics() + { + if (current_test_instance_) + { + std::lock_guard lock(current_test_instance_->topic_received_mutex_); + + return current_test_instance_->received_topics_; + } + else + { + return 0; + } + } + int get_received_data() { if (current_test_instance_) @@ -315,10 +387,12 @@ class DDSEnablerTester : public ::testing::Test // Test-specific received counters int received_types_ = 0; + int received_topics_ = 0; int received_data_ = 0; - // Mutex for synchronizing access to received_types_ and received_data_ + // Mutex for synchronizing access to received_types_, received_topics_ and received_data_ std::mutex type_received_mutex_; + std::mutex topic_received_mutex_; std::mutex data_received_mutex_; }; diff --git a/ddsenabler/test/ddsEnablerTests/DdsEnablerTest.cpp b/ddsenabler/test/ddsEnablerTests/DdsEnablerTest.cpp index 1eab3927..85305197 100644 --- a/ddsenabler/test/ddsEnablerTests/DdsEnablerTest.cpp +++ b/ddsenabler/test/ddsEnablerTests/DdsEnablerTest.cpp @@ -44,7 +44,7 @@ TEST_F(DDSEnablerTest, ddsenabler_reload_configuration) eprosima::utils::Formatter error_msg; ASSERT_TRUE(configuration.is_valid(error_msg)); - ASSERT_NO_THROW(enabler.get()->reload_configuration(configuration)); + ASSERT_NO_THROW(enabler->reload_configuration(configuration)); } TEST_F(DDSEnablerTest, send_type1) @@ -59,13 +59,15 @@ TEST_F(DDSEnablerTest, send_type1) ASSERT_TRUE(create_publisher(a_type)); - ASSERT_EQ(get_received_types(), 0); + ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), 0); // Send data ASSERT_TRUE(send_samples(a_type)); ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), num_samples_); } @@ -81,13 +83,15 @@ TEST_F(DDSEnablerTest, send_many_type1) ASSERT_TRUE(create_publisher(a_type)); - ASSERT_EQ(get_received_types(), 0); + ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), 0); // Send data ASSERT_TRUE(send_samples(a_type)); ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), num_samples_); } @@ -103,13 +107,15 @@ TEST_F(DDSEnablerTest, send_type2) ASSERT_TRUE(create_publisher(a_type)); - ASSERT_EQ(get_received_types(), 0); + ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), 0); // Send data ASSERT_TRUE(send_samples(a_type)); ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), num_samples_); } @@ -125,19 +131,22 @@ TEST_F(DDSEnablerTest, send_type3) ASSERT_TRUE(create_publisher(a_type)); - ASSERT_EQ(get_received_types(), 0); + ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), 0); // Send data ASSERT_TRUE(send_samples(a_type)); ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), num_samples_); // Send data ASSERT_TRUE(send_samples(a_type)); ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), num_samples_ * 2); } @@ -153,13 +162,15 @@ TEST_F(DDSEnablerTest, send_type4) ASSERT_TRUE(create_publisher(a_type)); - ASSERT_EQ(get_received_types(), 0); + ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), 0); // Send data ASSERT_TRUE(send_samples(a_type)); ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), num_samples_); } @@ -175,13 +186,15 @@ TEST_F(DDSEnablerTest, send_multiple_types) ASSERT_TRUE(create_publisher(a_type1)); - ASSERT_EQ(get_received_types(), 0); + ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), 0); // Send data ASSERT_TRUE(send_samples(a_type1)); ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), num_samples_); KnownType a_type2; @@ -189,13 +202,15 @@ TEST_F(DDSEnablerTest, send_multiple_types) ASSERT_TRUE(create_publisher(a_type2)); - ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_types(), 2); + ASSERT_EQ(get_received_topics(), 2); ASSERT_EQ(get_received_data(), num_samples_); // Send data ASSERT_TRUE(send_samples(a_type2)); ASSERT_EQ(get_received_types(), 2); + ASSERT_EQ(get_received_topics(), 2); ASSERT_EQ(get_received_data(), num_samples_ * 2); KnownType a_type3; @@ -203,13 +218,15 @@ TEST_F(DDSEnablerTest, send_multiple_types) ASSERT_TRUE(create_publisher(a_type3)); - ASSERT_EQ(get_received_types(), 2); + ASSERT_EQ(get_received_types(), 3); + ASSERT_EQ(get_received_topics(), 3); ASSERT_EQ(get_received_data(), num_samples_ * 2); // Send data ASSERT_TRUE(send_samples(a_type3)); ASSERT_EQ(get_received_types(), 3); + ASSERT_EQ(get_received_topics(), 3); ASSERT_EQ(get_received_data(), num_samples_ * 3); KnownType a_type4; @@ -217,13 +234,15 @@ TEST_F(DDSEnablerTest, send_multiple_types) ASSERT_TRUE(create_publisher(a_type4)); - ASSERT_EQ(get_received_types(), 3); + ASSERT_EQ(get_received_types(), 4); + ASSERT_EQ(get_received_topics(), 4); ASSERT_EQ(get_received_data(), num_samples_ * 3); // Send data ASSERT_TRUE(send_samples(a_type4)); ASSERT_EQ(get_received_types(), 4); + ASSERT_EQ(get_received_topics(), 4); ASSERT_EQ(get_received_data(), num_samples_ * 4); } @@ -239,13 +258,15 @@ TEST_F(DDSEnablerTest, send_repeated_type) ASSERT_TRUE(create_publisher(a_type)); - ASSERT_EQ(get_received_types(), 0); + ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), 0); // Send data ASSERT_TRUE(send_samples(a_type)); ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), num_samples_); KnownType another_type; @@ -257,20 +278,23 @@ TEST_F(DDSEnablerTest, send_repeated_type) ASSERT_TRUE(send_samples(another_type)); ASSERT_EQ(get_received_types(), 2); + ASSERT_EQ(get_received_topics(), 2); ASSERT_EQ(get_received_data(), num_samples_ * 2); KnownType same_type; same_type.type_sup_.reset(new DDSEnablerTestType1PubSubType()); - ASSERT_TRUE(create_publisher(same_type)); + ASSERT_TRUE(create_publisher(same_type)); // and topic ASSERT_EQ(get_received_types(), 2); + ASSERT_EQ(get_received_topics(), 2); ASSERT_EQ(get_received_data(), num_samples_ * 2); // Send data ASSERT_TRUE(send_samples(same_type)); ASSERT_EQ(get_received_types(), 2); + ASSERT_EQ(get_received_topics(), 2); ASSERT_EQ(get_received_data(), num_samples_ * 3); } @@ -313,6 +337,7 @@ TEST_F(DDSEnablerTest, send_history_smaller_than_writer) std::this_thread::sleep_for(std::chrono::milliseconds(history_depth * 100)); ASSERT_EQ(get_received_types(), 1); + ASSERT_EQ(get_received_topics(), 1); ASSERT_EQ(get_received_data(), history_depth); } @@ -356,6 +381,7 @@ TEST_F(DDSEnablerTest, send_history_multiple_types) std::this_thread::sleep_for(std::chrono::milliseconds(types * history_depth * 100)); ASSERT_EQ(get_received_types(), types); + ASSERT_EQ(get_received_topics(), types); ASSERT_EQ(get_received_data(), types * history_depth); } diff --git a/ddsenabler/test/ddsEnablerTests/ReloadConfig.cpp b/ddsenabler/test/ddsEnablerTests/ReloadConfig.cpp index 6fb1ac82..e41581d9 100644 --- a/ddsenabler/test/ddsEnablerTests/ReloadConfig.cpp +++ b/ddsenabler/test/ddsEnablerTests/ReloadConfig.cpp @@ -22,29 +22,72 @@ #include #include -// Static type callback -void type_callback( - const char* typeName, - const char* topicName, - const char* serializedType) +static uint32_t data_callback_count = 0; + +// Empty callbacks just to create the enabler being tested + +// eprosima::ddsenabler::participants::DdsDataNotification data_notification; +void test_data_notification_callback( + const char* topic_name, + const char* json, + int64_t publish_time) { } -static uint32_t data_callback_count = 0; +// eprosima::ddsenabler::participants::DdsTypeNotification type_notification; +void test_type_notification_callback( + const char* type_name, + const char* serialized_type, + const unsigned char* serialized_type_internal, + uint32_t serialized_type_internal_size, + const char* data_placeholder) +{ +} -// Static data callback -void data_callback( - const char* typeName, - const char* topicName, - const char* json, - int64_t publishTime) +// eprosima::ddsenabler::participants::DdsTopicNotification topic_notification; +void test_topic_notification_callback( + const char* topic_name, + const char* type_name, + const char* serialized_qos) +{ +} + +// eprosima::ddsenabler::participants::DdsTopicQuery topic_query; +bool test_topic_query_callback( + const char* topic_name, + std::string& type_name, + std::string& serialized_qos) +{ + return false; +} + +// eprosima::ddsenabler::participants::DdsTypeQuery type_query; +bool test_type_query_callback( + const char* type_name, + std::unique_ptr& serialized_type_internal, + uint32_t& serialized_type_internal_size) { + return false; } -void write_json_file(const std::string filePath, bool block) { +//eprosima::ddsenabler::participants::DdsLogFunc log_callback; +void test_log_callback( + const char* file_name, + int line_no, + const char* func_name, + int category, + const char* msg) +{ +} + +void write_json_file( + const std::string filePath, + bool block) +{ // The JSON template with a placeholder for the domain - std::string jsonTemplate = R"({ + std::string jsonTemplate = + R"({ "dds": { "ddsmodule": { "dds": { @@ -70,22 +113,31 @@ void write_json_file(const std::string filePath, bool block) { // Replace the %d placeholder with the provided domain char buffer[1024]; - snprintf(buffer, sizeof(buffer), jsonTemplate.c_str(), block ? "\n \"blocklist\": [\n {\n \"name\": \"*\"\n }\n ]," : ""); + snprintf(buffer, sizeof(buffer), + jsonTemplate.c_str(), + block ? "\n \"blocklist\": [\n {\n \"name\": \"*\"\n }\n ]," : ""); // Write the formatted JSON to the file std::ofstream outFile(filePath); - if (outFile.is_open()) { + if (outFile.is_open()) + { outFile << buffer; outFile.close(); - } else { + } + else + { throw std::ios_base::failure("Failed to open the file for writing."); } } -void write_yaml_file(const std::string filePath, bool block) { +void write_yaml_file( + const std::string filePath, + bool block) +{ // The JSON template with a placeholder for the domain - std::string Template = R"( + std::string Template = + R"( dds: domain: 0 @@ -104,10 +156,13 @@ void write_yaml_file(const std::string filePath, bool block) { // Write the formatted YAML to the file std::ofstream outFile(filePath); - if (outFile.is_open()) { + if (outFile.is_open()) + { outFile << buffer; outFile.close(); - } else { + } + else + { throw std::ios_base::failure("Failed to open the file for writing."); } } @@ -118,15 +173,20 @@ namespace eprosima { namespace ddsenabler { // Class that exposes the protected attribute configuration_ -class DDSEnablerAccessor : public DDSEnabler { +class DDSEnablerAccessor : public DDSEnabler +{ public: + using DDSEnabler::DDSEnabler; - const void get_allowed_topics(std::shared_ptr& ptr) const { + const void get_allowed_topics( + std::shared_ptr& ptr) const + { std::lock_guard lock(mutex_); ptr = std::make_shared( this->configuration_.ddspipe_configuration.allowlist, this->configuration_.ddspipe_configuration.blocklist); } + }; // Test the configuration reload when the json configuration file is modified @@ -135,9 +195,20 @@ TEST(ReloadConfig, json) auto configfile = "./file_watcher_test.json"; write_json_file(configfile, false); + CallbackSet callbacks{ + test_log_callback, + { + test_type_notification_callback, + test_topic_notification_callback, + test_data_notification_callback, + test_type_query_callback, + test_topic_query_callback + } + }; + // Create DDS Enabler - std::unique_ptr enabler; - ASSERT_TRUE(create_dds_enabler(configfile, data_callback, type_callback, nullptr, enabler)); + std::shared_ptr enabler; + ASSERT_TRUE(create_dds_enabler(configfile, callbacks, enabler)); // Create DDSEnablerAccessor to access protected configuration auto enabler_accessor = static_cast(enabler.get()); @@ -166,10 +237,20 @@ TEST(ReloadConfig, yaml) auto configfile = "./file_watcher_test.yaml"; write_yaml_file(configfile, 0); + CallbackSet callbacks{ + test_log_callback, + { + test_type_notification_callback, + test_topic_notification_callback, + test_data_notification_callback, + test_type_query_callback, + test_topic_query_callback + } + }; + // Create DDS Enabler - std::unique_ptr enabler; - bool result = create_dds_enabler(configfile, data_callback, type_callback, nullptr, enabler); - ASSERT_TRUE(result); + std::shared_ptr enabler; + ASSERT_TRUE(create_dds_enabler(configfile, callbacks, enabler)); // Create DDSEnablerAccessor to access protected configuration auto enabler_accessor = static_cast(enabler.get()); diff --git a/ddsenabler/test/ddsEnablerTypedTests/CMakeLists.txt b/ddsenabler/test/ddsEnablerTypedTests/CMakeLists.txt index 7e776b41..0de57b01 100644 --- a/ddsenabler/test/ddsEnablerTypedTests/CMakeLists.txt +++ b/ddsenabler/test/ddsEnablerTypedTests/CMakeLists.txt @@ -469,86 +469,87 @@ set(TEST_LIST ddsenabler_send_samples_MutableUnionStruct ddsenabler_send_samples_MutableWCharStruct ddsenabler_send_samples_InnerStructOptional - ddsenabler_send_samples_array_short_align_1_optional - ddsenabler_send_samples_array_short_align_2_optional - ddsenabler_send_samples_array_short_align_4_optional - ddsenabler_send_samples_array_short_optional - ddsenabler_send_samples_boolean_align_1_optional - ddsenabler_send_samples_boolean_align_2_optional - ddsenabler_send_samples_boolean_align_4_optional - ddsenabler_send_samples_boolean_optional - ddsenabler_send_samples_char_align_1_optional - ddsenabler_send_samples_char_align_2_optional - ddsenabler_send_samples_char_align_4_optional - ddsenabler_send_samples_char_optional - ddsenabler_send_samples_double_align_1_optional - ddsenabler_send_samples_double_align_2_optional - ddsenabler_send_samples_double_align_4_optional - ddsenabler_send_samples_double_optional - ddsenabler_send_samples_float_align_1_optional - ddsenabler_send_samples_float_align_2_optional - ddsenabler_send_samples_float_align_4_optional - ddsenabler_send_samples_float_optional - ddsenabler_send_samples_long_align_1_optional - ddsenabler_send_samples_long_align_2_optional - ddsenabler_send_samples_long_align_4_optional - ddsenabler_send_samples_long_optional - ddsenabler_send_samples_longdouble_align_1_optional - ddsenabler_send_samples_longdouble_align_2_optional - ddsenabler_send_samples_longdouble_align_4_optional - ddsenabler_send_samples_longdouble_optional - ddsenabler_send_samples_longlong_align_1_optional - ddsenabler_send_samples_longlong_align_2_optional - ddsenabler_send_samples_longlong_align_4_optional - ddsenabler_send_samples_longlong_optional - ddsenabler_send_samples_map_short_align_1_optional - ddsenabler_send_samples_map_short_align_2_optional - ddsenabler_send_samples_map_short_align_4_optional - ddsenabler_send_samples_map_short_optional - ddsenabler_send_samples_octet_align_1_optional - ddsenabler_send_samples_octet_align_2_optional - ddsenabler_send_samples_octet_align_4_optional - ddsenabler_send_samples_octet_optional - ddsenabler_send_samples_opt_struct_align_1_optional - ddsenabler_send_samples_opt_struct_align_2_optional - ddsenabler_send_samples_opt_struct_align_4_optional - ddsenabler_send_samples_opt_struct_optional - ddsenabler_send_samples_sequence_short_align_1_optional - ddsenabler_send_samples_sequence_short_align_2_optional - ddsenabler_send_samples_sequence_short_align_4_optional - ddsenabler_send_samples_sequence_short_optional - ddsenabler_send_samples_short_align_1_optional - ddsenabler_send_samples_short_align_2_optional - ddsenabler_send_samples_short_align_4_optional - ddsenabler_send_samples_short_optional - ddsenabler_send_samples_string_bounded_align_1_optional - ddsenabler_send_samples_string_bounded_align_2_optional - ddsenabler_send_samples_string_bounded_align_4_optional - ddsenabler_send_samples_string_bounded_optional - ddsenabler_send_samples_string_unbounded_align_1_optional - ddsenabler_send_samples_string_unbounded_align_2_optional - ddsenabler_send_samples_string_unbounded_align_4_optional - ddsenabler_send_samples_string_unbounded_optional - ddsenabler_send_samples_struct_align_1_optional - ddsenabler_send_samples_struct_align_2_optional - ddsenabler_send_samples_struct_align_4_optional - ddsenabler_send_samples_struct_optional - ddsenabler_send_samples_ulong_align_1_optional - ddsenabler_send_samples_ulong_align_2_optional - ddsenabler_send_samples_ulong_align_4_optional - ddsenabler_send_samples_ulong_optional - ddsenabler_send_samples_ulonglong_align_1_optional - ddsenabler_send_samples_ulonglong_align_2_optional - ddsenabler_send_samples_ulonglong_align_4_optional - ddsenabler_send_samples_ulonglong_optional - ddsenabler_send_samples_ushort_align_1_optional - ddsenabler_send_samples_ushort_align_2_optional - ddsenabler_send_samples_ushort_align_4_optional - ddsenabler_send_samples_ushort_optional - ddsenabler_send_samples_wchar_align_1_optional - ddsenabler_send_samples_wchar_align_2_optional - ddsenabler_send_samples_wchar_align_4_optional - ddsenabler_send_samples_wchar_optional + # TODO: comment out when optionals are supported + # ddsenabler_send_samples_array_short_align_1_optional + # ddsenabler_send_samples_array_short_align_2_optional + # ddsenabler_send_samples_array_short_align_4_optional + # ddsenabler_send_samples_array_short_optional + # ddsenabler_send_samples_boolean_align_1_optional + # ddsenabler_send_samples_boolean_align_2_optional + # ddsenabler_send_samples_boolean_align_4_optional + # ddsenabler_send_samples_boolean_optional + # ddsenabler_send_samples_char_align_1_optional + # ddsenabler_send_samples_char_align_2_optional + # ddsenabler_send_samples_char_align_4_optional + # ddsenabler_send_samples_char_optional + # ddsenabler_send_samples_double_align_1_optional + # ddsenabler_send_samples_double_align_2_optional + # ddsenabler_send_samples_double_align_4_optional + # ddsenabler_send_samples_double_optional + # ddsenabler_send_samples_float_align_1_optional + # ddsenabler_send_samples_float_align_2_optional + # ddsenabler_send_samples_float_align_4_optional + # ddsenabler_send_samples_float_optional + # ddsenabler_send_samples_long_align_1_optional + # ddsenabler_send_samples_long_align_2_optional + # ddsenabler_send_samples_long_align_4_optional + # ddsenabler_send_samples_long_optional + # ddsenabler_send_samples_longdouble_align_1_optional + # ddsenabler_send_samples_longdouble_align_2_optional + # ddsenabler_send_samples_longdouble_align_4_optional + # ddsenabler_send_samples_longdouble_optional + # ddsenabler_send_samples_longlong_align_1_optional + # ddsenabler_send_samples_longlong_align_2_optional + # ddsenabler_send_samples_longlong_align_4_optional + # ddsenabler_send_samples_longlong_optional + # ddsenabler_send_samples_map_short_align_1_optional + # ddsenabler_send_samples_map_short_align_2_optional + # ddsenabler_send_samples_map_short_align_4_optional + # ddsenabler_send_samples_map_short_optional + # ddsenabler_send_samples_octet_align_1_optional + # ddsenabler_send_samples_octet_align_2_optional + # ddsenabler_send_samples_octet_align_4_optional + # ddsenabler_send_samples_octet_optional + # ddsenabler_send_samples_opt_struct_align_1_optional + # ddsenabler_send_samples_opt_struct_align_2_optional + # ddsenabler_send_samples_opt_struct_align_4_optional + # ddsenabler_send_samples_opt_struct_optional + # ddsenabler_send_samples_sequence_short_align_1_optional + # ddsenabler_send_samples_sequence_short_align_2_optional + # ddsenabler_send_samples_sequence_short_align_4_optional + # ddsenabler_send_samples_sequence_short_optional + # ddsenabler_send_samples_short_align_1_optional + # ddsenabler_send_samples_short_align_2_optional + # ddsenabler_send_samples_short_align_4_optional + # ddsenabler_send_samples_short_optional + # ddsenabler_send_samples_string_bounded_align_1_optional + # ddsenabler_send_samples_string_bounded_align_2_optional + # ddsenabler_send_samples_string_bounded_align_4_optional + # ddsenabler_send_samples_string_bounded_optional + # ddsenabler_send_samples_string_unbounded_align_1_optional + # ddsenabler_send_samples_string_unbounded_align_2_optional + # ddsenabler_send_samples_string_unbounded_align_4_optional + # ddsenabler_send_samples_string_unbounded_optional + # ddsenabler_send_samples_struct_align_1_optional + # ddsenabler_send_samples_struct_align_2_optional + # ddsenabler_send_samples_struct_align_4_optional + # ddsenabler_send_samples_struct_optional + # ddsenabler_send_samples_ulong_align_1_optional + # ddsenabler_send_samples_ulong_align_2_optional + # ddsenabler_send_samples_ulong_align_4_optional + # ddsenabler_send_samples_ulong_optional + # ddsenabler_send_samples_ulonglong_align_1_optional + # ddsenabler_send_samples_ulonglong_align_2_optional + # ddsenabler_send_samples_ulonglong_align_4_optional + # ddsenabler_send_samples_ulonglong_optional + # ddsenabler_send_samples_ushort_align_1_optional + # ddsenabler_send_samples_ushort_align_2_optional + # ddsenabler_send_samples_ushort_align_4_optional + # ddsenabler_send_samples_ushort_optional + # ddsenabler_send_samples_wchar_align_1_optional + # ddsenabler_send_samples_wchar_align_2_optional + # ddsenabler_send_samples_wchar_align_4_optional + # ddsenabler_send_samples_wchar_optional ddsenabler_send_samples_BooleanStruct ddsenabler_send_samples_CharStruct ddsenabler_send_samples_DoubleStruct diff --git a/ddsenabler/test/ddsEnablerTypedTests/DdsEnablerTypedTest.cpp b/ddsenabler/test/ddsEnablerTypedTests/DdsEnablerTypedTest.cpp index 5e6a023a..01aa630a 100644 --- a/ddsenabler/test/ddsEnablerTypedTests/DdsEnablerTypedTest.cpp +++ b/ddsenabler/test/ddsEnablerTypedTests/DdsEnablerTypedTest.cpp @@ -47,7 +47,8 @@ class DDSEnablerTypedTest : public ddsenablertester::DDSEnablerTester \ ASSERT_TRUE(create_publisher(a_type)); \ \ - ASSERT_EQ(get_received_types(), 0); \ + ASSERT_EQ(get_received_types(), 1); \ + ASSERT_EQ(get_received_topics(), 1); \ ASSERT_EQ(get_received_data(), 0); \ \ /* Send data */ \ @@ -57,6 +58,7 @@ class DDSEnablerTypedTest : public ddsenablertester::DDSEnablerTester std::this_thread::sleep_for(std::chrono::milliseconds(wait_after_publication_ms)); \ \ ASSERT_EQ(get_received_types(), 1); \ + ASSERT_EQ(get_received_topics(), 1); \ ASSERT_EQ(get_received_data(), num_samples_); \ } @@ -658,104 +660,105 @@ DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_MutableUShortStruct, Mutabl DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_MutableUnionStruct, MutableUnionStructPubSubType); DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_MutableWCharStruct, MutableWCharStructPubSubType); DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_InnerStructOptional, InnerStructOptionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_array_short_align_1_optional, +// TODO: comment out when optionals are supported +/* DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_array_short_align_1_optional, array_short_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_array_short_align_2_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_array_short_align_2_optional, array_short_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_array_short_align_4_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_array_short_align_4_optional, array_short_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_array_short_optional, array_short_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_boolean_align_1_optional, boolean_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_boolean_align_2_optional, boolean_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_boolean_align_4_optional, boolean_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_boolean_optional, boolean_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_char_align_1_optional, char_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_char_align_2_optional, char_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_char_align_4_optional, char_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_char_optional, char_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_double_align_1_optional, double_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_double_align_2_optional, double_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_double_align_4_optional, double_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_double_optional, double_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_float_align_1_optional, float_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_float_align_2_optional, float_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_float_align_4_optional, float_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_float_optional, float_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_long_align_1_optional, long_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_long_align_2_optional, long_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_long_align_4_optional, long_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_long_optional, long_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longdouble_align_1_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_array_short_optional, array_short_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_boolean_align_1_optional, boolean_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_boolean_align_2_optional, boolean_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_boolean_align_4_optional, boolean_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_boolean_optional, boolean_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_char_align_1_optional, char_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_char_align_2_optional, char_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_char_align_4_optional, char_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_char_optional, char_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_double_align_1_optional, double_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_double_align_2_optional, double_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_double_align_4_optional, double_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_double_optional, double_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_float_align_1_optional, float_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_float_align_2_optional, float_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_float_align_4_optional, float_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_float_optional, float_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_long_align_1_optional, long_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_long_align_2_optional, long_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_long_align_4_optional, long_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_long_optional, long_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longdouble_align_1_optional, longdouble_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longdouble_align_2_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longdouble_align_2_optional, longdouble_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longdouble_align_4_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longdouble_align_4_optional, longdouble_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longdouble_optional, longdouble_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longlong_align_1_optional, longlong_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longlong_align_2_optional, longlong_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longlong_align_4_optional, longlong_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longlong_optional, longlong_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_map_short_align_1_optional, map_short_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_map_short_align_2_optional, map_short_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_map_short_align_4_optional, map_short_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_map_short_optional, map_short_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_octet_align_1_optional, octet_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_octet_align_2_optional, octet_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_octet_align_4_optional, octet_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_octet_optional, octet_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_opt_struct_align_1_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longdouble_optional, longdouble_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longlong_align_1_optional, longlong_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longlong_align_2_optional, longlong_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longlong_align_4_optional, longlong_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_longlong_optional, longlong_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_map_short_align_1_optional, map_short_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_map_short_align_2_optional, map_short_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_map_short_align_4_optional, map_short_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_map_short_optional, map_short_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_octet_align_1_optional, octet_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_octet_align_2_optional, octet_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_octet_align_4_optional, octet_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_octet_optional, octet_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_opt_struct_align_1_optional, opt_struct_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_opt_struct_align_2_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_opt_struct_align_2_optional, opt_struct_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_opt_struct_align_4_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_opt_struct_align_4_optional, opt_struct_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_opt_struct_optional, opt_struct_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_sequence_short_align_1_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_opt_struct_optional, opt_struct_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_sequence_short_align_1_optional, sequence_short_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_sequence_short_align_2_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_sequence_short_align_2_optional, sequence_short_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_sequence_short_align_4_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_sequence_short_align_4_optional, sequence_short_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_sequence_short_optional, sequence_short_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_short_align_1_optional, short_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_short_align_2_optional, short_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_short_align_4_optional, short_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_short_optional, short_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_bounded_align_1_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_sequence_short_optional, sequence_short_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_short_align_1_optional, short_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_short_align_2_optional, short_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_short_align_4_optional, short_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_short_optional, short_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_bounded_align_1_optional, string_bounded_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_bounded_align_2_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_bounded_align_2_optional, string_bounded_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_bounded_align_4_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_bounded_align_4_optional, string_bounded_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_bounded_optional, string_bounded_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_unbounded_align_1_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_bounded_optional, string_bounded_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_unbounded_align_1_optional, string_unbounded_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_unbounded_align_2_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_unbounded_align_2_optional, string_unbounded_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_unbounded_align_4_optional, + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_unbounded_align_4_optional, string_unbounded_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_unbounded_optional, string_unbounded_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_struct_align_1_optional, struct_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_struct_align_2_optional, struct_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_struct_align_4_optional, struct_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_struct_optional, struct_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulong_align_1_optional, ulong_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulong_align_2_optional, ulong_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulong_align_4_optional, ulong_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulong_optional, ulong_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulonglong_align_1_optional, ulonglong_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulonglong_align_2_optional, ulonglong_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulonglong_align_4_optional, ulonglong_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulonglong_optional, ulonglong_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ushort_align_1_optional, ushort_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ushort_align_2_optional, ushort_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ushort_align_4_optional, ushort_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ushort_optional, ushort_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_wchar_align_1_optional, wchar_align_1_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_wchar_align_2_optional, wchar_align_2_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_wchar_align_4_optional, wchar_align_4_optionalPubSubType); -DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_wchar_optional, wchar_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_string_unbounded_optional, string_unbounded_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_struct_align_1_optional, struct_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_struct_align_2_optional, struct_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_struct_align_4_optional, struct_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_struct_optional, struct_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulong_align_1_optional, ulong_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulong_align_2_optional, ulong_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulong_align_4_optional, ulong_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulong_optional, ulong_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulonglong_align_1_optional, ulonglong_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulonglong_align_2_optional, ulonglong_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulonglong_align_4_optional, ulonglong_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ulonglong_optional, ulonglong_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ushort_align_1_optional, ushort_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ushort_align_2_optional, ushort_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ushort_align_4_optional, ushort_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_ushort_optional, ushort_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_wchar_align_1_optional, wchar_align_1_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_wchar_align_2_optional, wchar_align_2_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_wchar_align_4_optional, wchar_align_4_optionalPubSubType); + DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_wchar_optional, wchar_optionalPubSubType); */ DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_BooleanStruct, BooleanStructPubSubType); DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_CharStruct, CharStructPubSubType); DEFINE_DDSENABLER_TYPED_TEST(ddsenabler_send_samples_DoubleStruct, DoubleStructPubSubType); diff --git a/ddsenabler_participants/README.md b/ddsenabler_participants/README.md deleted file mode 100644 index 749bea32..00000000 --- a/ddsenabler_participants/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# eProsima DDS Enabler Participants - -`ddsenabler_participants` subpackage. - -> :warning: **TODO** diff --git a/ddsenabler_participants/include/ddsenabler_participants/CBCallbacks.hpp b/ddsenabler_participants/include/ddsenabler_participants/CBCallbacks.hpp index 8e88c4f6..cb5dc971 100644 --- a/ddsenabler_participants/include/ddsenabler_participants/CBCallbacks.hpp +++ b/ddsenabler_participants/include/ddsenabler_participants/CBCallbacks.hpp @@ -19,38 +19,94 @@ #pragma once #include +#include +#include namespace eprosima { namespace ddsenabler { namespace participants { /** - * DdsLogFunc - callback for reception of DDS types + * DdsLogFunc - callback executed when consuming log messages + * + * @param [in] file_name Name of the file where the log was generated + * @param [in] line_no Line number in the file where the log was generated + * @param [in] func_name Name of the function where the log was generated + * @param [in] category Category of the log message + * @param [in] msg Log message content */ -typedef void (*DdsLogFunc)( - const char* fileName, - int lineNo, - const char* funcName, +typedef void (* DdsLogFunc)( + const char* file_name, + int line_no, + const char* func_name, int category, const char* msg); /** - * DdsTypeNotification - callback for reception of DDS types + * DdsTypeNotification - callback for notifying the reception of DDS types + * + * @param [in] type_name Name of the received type + * @param [in] serialized_type Serialized type in IDL format + * @param [in] serialized_type_internal Serialized type in internal format + * @param [in] serialized_type_internal_size Size of the serialized type in internal format + * @param [in] data_placeholder JSON data placeholder */ -typedef void (*DdsTypeNotification)( - const char* typeName, - const char* topicName, - const char* serializedType); +typedef void (* DdsTypeNotification)( + const char* type_name, + const char* serialized_type, + const unsigned char* serialized_type_internal, + uint32_t serialized_type_internal_size, + const char* data_placeholder); /** - * DdsNotification - callback for reception of DDS data + * DdsTopicNotification - callback for notifying the reception of DDS topics + * + * @param [in] topic_name Name of the received topic + * @param [in] type_name Name of the type associated with the topic + * @param [in] serialized_qos Serialized Quality of Service (QoS) of the topic */ -typedef void (*DdsNotification)( - const char* typeName, - const char* topicName, +typedef void (* DdsTopicNotification)( + const char* topic_name, + const char* type_name, + const char* serialized_qos); + +/** + * DdsDataNotification - callback for notifying the reception of DDS data + * + * @param [in] topic_name Name of the topic from which the data was received + * @param [in] json JSON representation of the data + * @param [in] publish_time Time (nanoseconds since epoch) when the data was published + */ +typedef void (* DdsDataNotification)( + const char* topic_name, const char* json, - int64_t publishTime); + int64_t publish_time); + +/** + * DdsTypeQuery - callback for requesting information (serialized description and size) of a DDS type + * + * @param [in] type_name Name of the type to query + * @param [out] serialized_type_internal Pointer to the serialized type in internal format + * @param [out] serialized_type_internal_size Size of the serialized type in internal format + * @return \c true if the type was found and the information was retrieved successfully, \c false otherwise + */ +typedef bool (* DdsTypeQuery)( + const char* type_name, + std::unique_ptr& serialized_type_internal, + uint32_t& serialized_type_internal_size); +/** + * DdsTopicQuery - callback for requesting information (type and QoS) of a DDS topic + * + * @param [in] topic_name Name of the topic to query + * @param [out] type_name Name of the type associated with the topic + * @param [out] serialized_qos Serialized Quality of Service (QoS) of the topic + * @return \c true if the topic was found and the information was retrieved successfully, \c false otherwise + */ +typedef bool (* DdsTopicQuery)( + const char* topic_name, + std::string& type_name, + std::string& serialized_qos); } /* namespace participants */ } /* namespace ddsenabler */ diff --git a/ddsenabler_participants/include/ddsenabler_participants/CBHandler.hpp b/ddsenabler_participants/include/ddsenabler_participants/CBHandler.hpp index 317708cb..e47d6d86 100644 --- a/ddsenabler_participants/include/ddsenabler_participants/CBHandler.hpp +++ b/ddsenabler_participants/include/ddsenabler_participants/CBHandler.hpp @@ -18,13 +18,11 @@ #pragma once -#include #include -#include -#include +#include +#include #include -#include -#include +#include #include #include @@ -33,6 +31,7 @@ #include +#include #include #include #include @@ -60,7 +59,7 @@ namespace ddsenabler { namespace participants { /** - * Class that manages the interaction between DDS Pipe \c (SchemaParticipant) and CB. + * Class that manages the interaction between \c EnablerParticipant and CB. * Payloads are efficiently passed from DDS Pipe to CB without copying data (only references). * * @implements ISchemaHandler @@ -90,8 +89,7 @@ class CBHandler : public ddspipe::participants::ISchemaHandler ~CBHandler(); /** - * @brief Create and store in \c schemas_ an OMG IDL (.idl format) schema. - * Any samples following this schema that were received before the schema itself are moved to the memory buffer. + * @brief Add a type schema, associated to the given \c dyn_type and \c type_id. * * @param [in] dyn_type DynamicType containing the type information required to generate the schema. * @param [in] type_id TypeIdentifier of the type. @@ -102,9 +100,16 @@ class CBHandler : public ddspipe::participants::ISchemaHandler const fastdds::dds::xtypes::TypeIdentifier& type_id) override; /** - * @brief Add a data sample, associated to the given \c topic. + * @brief Add a topic, associated to the given \c topic. * - * The sample is added to buffer without schema. + * @param [in] topic DDS topic to be added. + */ + DDSENABLER_PARTICIPANTS_DllAPI + void add_topic( + const ddspipe::core::types::DdsTopic& topic); + + /** + * @brief Add a data sample, associated to the given \c topic. * * @param [in] topic DDS topic associated to this sample. * @param [in] data payload data to be added. @@ -114,33 +119,152 @@ class CBHandler : public ddspipe::participants::ISchemaHandler const ddspipe::core::types::DdsTopic& topic, ddspipe::core::types::RtpsPayloadData& data) override; + /** + * @brief Get the TypeIdentifier associated to the given type name. + * + * @param [in] type_name Name of the type to be retrieved. + * @param [out] type_identifier TypeIdentifier of the type. + * @return \c true if the type was found, \c false otherwise. + */ + DDSENABLER_PARTICIPANTS_DllAPI + bool get_type_identifier( + const std::string& type_name, + fastdds::dds::xtypes::TypeIdentifier& type_identifier); + + /** + * @brief Get the serialized data (payload) associated to the given type name from a JSON string. + * + * @param [in] type_name Name of the type of the data to be serialized. + * @param [in] json JSON string containing the data to be serialized. + * @param [out] payload Payload reference where the serialized data will be stored. + * @return \c true if the data was successfully serialized, \c false otherwise. + */ + DDSENABLER_PARTICIPANTS_DllAPI + bool get_serialized_data( + const std::string& type_name, + const std::string& json, + ddspipe::core::types::Payload& payload); + + /** + * @brief Set the data notification callback. + * + * @param [in] callback Callback to be set. + */ + DDSENABLER_PARTICIPANTS_DllAPI + void set_data_notification_callback( + participants::DdsDataNotification callback) + { + cb_writer_->set_data_notification_callback(callback); + } + /** + * @brief Set the topic notification callback. + * + * @param [in] callback Callback to be set. + */ DDSENABLER_PARTICIPANTS_DllAPI - void set_data_callback( - participants::DdsNotification callback) + void set_topic_notification_callback( + participants::DdsTopicNotification callback) { - cb_writer_.get()->set_data_callback(callback); + cb_writer_->set_topic_notification_callback(callback); } + /** + * @brief Set the type notification callback. + * + * @param [in] callback Callback to be set. + */ DDSENABLER_PARTICIPANTS_DllAPI - void set_type_callback( + void set_type_notification_callback( participants::DdsTypeNotification callback) { - cb_writer_.get()->set_type_callback(callback); + cb_writer_->set_type_notification_callback(callback); + } + + /** + * @brief Set the type query callback. + * + * @param [in] callback Callback to be set. + */ + DDSENABLER_PARTICIPANTS_DllAPI + void set_type_query_callback( + participants::DdsTypeQuery callback) + { + type_query_callback_ = callback; } protected: + /** + * @brief Add a schema, associated to the given \c dyn_type and \c type_id. + * + * @param [in] dyn_type DynamicType containing the type information required to generate the schema. + * @param [in] type_id TypeIdentifier of the type. + * @param [in] write_schema Whether to write the schema to CB or not. + */ + void add_schema_nts_( + const fastdds::dds::DynamicType::_ref_type& dyn_type, + const fastdds::dds::xtypes::TypeIdentifier& type_id, + bool write_schema = true); + + /** + * @brief Add a schema, associated to the given \c type_id and \c type_obj. + * + * @param [in] type_id TypeIdentifier of the type. + * @param [in] type_obj TypeObject of the type. + * @param [in] write_schema Whether to write the schema to CB or not. + * @return \c true if the schema was added successfully, \c false otherwise. + */ + bool add_schema_nts_( + const fastdds::dds::xtypes::TypeIdentifier& type_id, + const fastdds::dds::xtypes::TypeObject& type_obj, + bool write_schema = true); + + /** + * @brief Write the schema to CB. + * + * @param [in] dyn_type DynamicType containing the type information required to generate the schema. + * @param [in] type_id TypeIdentifier of the type. + */ + void write_schema_nts_( + const fastdds::dds::DynamicType::_ref_type& dyn_type, + const fastdds::dds::xtypes::TypeIdentifier& type_id); + + /** + * @brief Write the topic to CB. + * + * @param [in] topic DDS topic to be added. + */ + void write_topic_nts_( + const ddspipe::core::types::DdsTopic& topic); + /** * @brief Write to CB. * * @param [in] msg CBMessage to be added * @param [in] dyn_type DynamicType containing the type information required. */ - void write_sample( + void write_sample_nts_( const CBMessage& msg, const fastdds::dds::DynamicType::_ref_type& dyn_type); + /** + * @brief Register a type using the given serialized type data. + * + * @param [in] type_name Name of the type to be registered. + * @param [in] serialized_type Pointer to the serialized type data. + * @param [in] serialized_type_size Size of the serialized type data. + * @param [out] type_identifier TypeIdentifier of the registered type. + * @param [out] type_object TypeObject of the registered type. + * @return \c true if the type was registered successfully, \c false otherwise. + */ + bool register_type_nts_( + const std::string& type_name, + const unsigned char* serialized_type, + uint32_t serialized_type_size, + fastdds::dds::xtypes::TypeIdentifier& type_identifier, + fastdds::dds::xtypes::TypeObject& type_object); + //! Handler configuration CBHandlerConfiguration configuration_; @@ -151,13 +275,17 @@ class CBHandler : public ddspipe::participants::ISchemaHandler std::unique_ptr cb_writer_; //! Schemas map - std::unordered_map schemas_; + std::map> schemas_; //! Unique sequence number assigned to received messages. It is incremented with every sample added unsigned int unique_sequence_number_{0}; //! Mutex synchronizing access to object's data structures std::mutex mtx_; + + //! Callback to request types from the user + DdsTypeQuery type_query_callback_; }; } /* namespace participants */ diff --git a/ddsenabler_participants/include/ddsenabler_participants/CBWriter.hpp b/ddsenabler_participants/include/ddsenabler_participants/CBWriter.hpp index cf1e607e..c10b8596 100644 --- a/ddsenabler_participants/include/ddsenabler_participants/CBWriter.hpp +++ b/ddsenabler_participants/include/ddsenabler_participants/CBWriter.hpp @@ -18,15 +18,14 @@ #pragma once -#include +#include -#include #include +#include +#include -#include #include -#include #include #include @@ -34,6 +33,11 @@ namespace eprosima { namespace ddsenabler { namespace participants { +/** + * @brief Helper class encapsulating the logic to write data, topics and schemas to the CB. + * + * @warning This class is not thread-safe. + */ class CBWriter { @@ -46,65 +50,86 @@ class CBWriter ~CBWriter() = default; DDSENABLER_PARTICIPANTS_DllAPI - void set_data_callback( - DdsNotification callback) + void set_data_notification_callback( + DdsDataNotification callback) { - std::lock_guard lock(mutex_); - data_callback_ = callback; + data_notification_callback_ = callback; } DDSENABLER_PARTICIPANTS_DllAPI - void set_type_callback( + void set_type_notification_callback( DdsTypeNotification callback) { - std::lock_guard lock(mutex_); - type_callback_ = callback; + type_notification_callback_ = callback; + } + + DDSENABLER_PARTICIPANTS_DllAPI + void set_topic_notification_callback( + DdsTopicNotification callback) + { + topic_notification_callback_ = callback; } /** - * @brief Writes data. + * @brief Writes the schema of a DynamicType to CB. * - * @param [in] msg Pointer to the data to be written. * @param [in] dyn_type DynamicType containing the type information required. + * @param [in] type_id TypeIdentifier of the DynamicType. */ DDSENABLER_PARTICIPANTS_DllAPI - void write_data( - const CBMessage& msg, - const fastdds::dds::DynamicType::_ref_type& dyn_type); + void write_schema( + const fastdds::dds::DynamicType::_ref_type& dyn_type, + const fastdds::dds::xtypes::TypeIdentifier& type_id); -protected: + /** + * @brief Writes the topic to CB. + * + * @param [in] topic DDS topic to be added. + */ + DDSENABLER_PARTICIPANTS_DllAPI + void write_topic( + const ddspipe::core::types::DdsTopic& topic); /** - * @brief Writes the type information used in this topic the first time it is received. + * @brief Writes data. * - * @param [in] msg Pointer to the data. + * @param [in] msg Pointer to the data to be written. * @param [in] dyn_type DynamicType containing the type information required. */ DDSENABLER_PARTICIPANTS_DllAPI - void write_schema( + void write_data( const CBMessage& msg, const fastdds::dds::DynamicType::_ref_type& dyn_type); +protected: + /** * @brief Returns the dyn_data of a dyn_type. * * @param [in] msg Pointer to the data. * @param [in] dyn_type DynamicType containing the type information required. */ - DDSENABLER_PARTICIPANTS_DllAPI - fastdds::dds::DynamicData::_ref_type get_dynamic_data( + fastdds::dds::DynamicData::_ref_type get_dynamic_data_( const CBMessage& msg, const fastdds::dds::DynamicType::_ref_type& dyn_type) noexcept; - //! Schemas map - std::unordered_map stored_schemas_; - - // The mutex to protect the calls to write - std::mutex mutex_; + /** + * @brief Returns the pubsub type of a dyn_type. + * + * @param [in] dyn_type DynamicType from which to get the pubsub type. + * @return The pubsub type associated to the given dyn_type. + * @note If the pubsub type is not already created, it will be created and stored in the map. + */ + fastdds::dds::DynamicPubSubType get_pubsub_type_( + const fastdds::dds::DynamicType::_ref_type& dyn_type) noexcept; // Callbacks to notify the CB - DdsNotification data_callback_; - DdsTypeNotification type_callback_; + DdsDataNotification data_notification_callback_; + DdsTypeNotification type_notification_callback_; + DdsTopicNotification topic_notification_callback_; + + // Map to store the pubsub types associated to dynamic types so they can be reused + std::map dynamic_pubsub_types_; }; } /* namespace participants */ diff --git a/ddsenabler_participants/include/ddsenabler_participants/DDSEnablerLogConsumer.hpp b/ddsenabler_participants/include/ddsenabler_participants/DDSEnablerLogConsumer.hpp index 5da12bb5..d1730fe9 100644 --- a/ddsenabler_participants/include/ddsenabler_participants/DDSEnablerLogConsumer.hpp +++ b/ddsenabler_participants/include/ddsenabler_participants/DDSEnablerLogConsumer.hpp @@ -47,6 +47,7 @@ class DDSEnablerLogConsumer : public utils::BaseLogConsumer { } + DDSENABLER_PARTICIPANTS_DllAPI void set_log_callback( DdsLogFunc callback) { diff --git a/ddsenabler_participants/include/ddsenabler_participants/DdsParticipant.hpp b/ddsenabler_participants/include/ddsenabler_participants/DdsParticipant.hpp new file mode 100644 index 00000000..a75be37d --- /dev/null +++ b/ddsenabler_participants/include/ddsenabler_participants/DdsParticipant.hpp @@ -0,0 +1,46 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file DdsParticipant.hpp + */ + +#pragma once + +#include + +#include + +namespace eprosima { +namespace ddsenabler { +namespace participants { + +class DdsParticipant : public ddspipe::participants::DynTypesParticipant +{ +public: + + DDSENABLER_PARTICIPANTS_DllAPI + DdsParticipant( + std::shared_ptr participant_configuration, + std::shared_ptr payload_pool, + std::shared_ptr discovery_database); + + DDSENABLER_PARTICIPANTS_DllAPI + std::shared_ptr create_writer( + const ddspipe::core::ITopic& topic) override; +}; + +} /* namespace participants */ +} /* namespace ddsenabler */ +} /* namespace eprosima */ diff --git a/ddsenabler_participants/include/ddsenabler_participants/EnablerParticipant.hpp b/ddsenabler_participants/include/ddsenabler_participants/EnablerParticipant.hpp new file mode 100644 index 00000000..4eed52ef --- /dev/null +++ b/ddsenabler_participants/include/ddsenabler_participants/EnablerParticipant.hpp @@ -0,0 +1,83 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file EnablerParticipant.hpp + */ + +#pragma once + +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace eprosima { +namespace ddsenabler { +namespace participants { + +class EnablerParticipant : public ddspipe::participants::SchemaParticipant +{ +public: + + DDSENABLER_PARTICIPANTS_DllAPI + EnablerParticipant( + std::shared_ptr participant_configuration, + std::shared_ptr payload_pool, + std::shared_ptr discovery_database, + std::shared_ptr schema_handler); + + DDSENABLER_PARTICIPANTS_DllAPI + std::shared_ptr create_reader( + const ddspipe::core::ITopic& topic) override; + + DDSENABLER_PARTICIPANTS_DllAPI + bool publish( + const std::string& topic_name, + const std::string& json); + + DDSENABLER_PARTICIPANTS_DllAPI + void set_topic_query_callback( + participants::DdsTopicQuery callback) + { + topic_query_callback_ = callback; + } + +protected: + + std::shared_ptr lookup_reader_nts_( + const std::string& topic_name, + std::string& type_name) const; + + std::shared_ptr lookup_reader_nts_( + const std::string& topic_name) const; + + std::map> readers_; + + std::mutex mtx_; + + std::condition_variable cv_; + + DdsTopicQuery topic_query_callback_; +}; + +} /* namespace participants */ +} /* namespace ddsenabler */ +} /* namespace eprosima */ diff --git a/ddsenabler_participants/include/ddsenabler_participants/EnablerParticipantConfiguration.hpp b/ddsenabler_participants/include/ddsenabler_participants/EnablerParticipantConfiguration.hpp new file mode 100644 index 00000000..5d58779c --- /dev/null +++ b/ddsenabler_participants/include/ddsenabler_participants/EnablerParticipantConfiguration.hpp @@ -0,0 +1,48 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License\. + +#pragma once + +#include + +#include + +namespace eprosima { +namespace ddsenabler { +namespace participants { + +/** + * This data struct represents a configuration for a EnablerParticipant + */ +struct EnablerParticipantConfiguration : public ddspipe::participants::ParticipantConfiguration +{ +public: + + ///////////////////////// + // CONSTRUCTORS + ///////////////////////// + + DDSENABLER_PARTICIPANTS_DllAPI + EnablerParticipantConfiguration() = default; + + ///////////////////////// + // VARIABLES + ///////////////////////// + + unsigned int initial_publish_wait {0u}; +}; + +} /* namespace participants */ +} /* namespace ddspipe */ +} /* namespace eprosima */ diff --git a/ddsenabler_participants/include/ddsenabler_participants/constants.hpp b/ddsenabler_participants/include/ddsenabler_participants/constants.hpp new file mode 100644 index 00000000..133b9f9d --- /dev/null +++ b/ddsenabler_participants/include/ddsenabler_participants/constants.hpp @@ -0,0 +1,33 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file constants.hpp + */ + +#pragma once + +namespace eprosima { +namespace ddsenabler { +namespace participants { + +// QoS serialization +constexpr const char* QOS_SERIALIZATION_RELIABILITY("reliability"); +constexpr const char* QOS_SERIALIZATION_DURABILITY("durability"); +constexpr const char* QOS_SERIALIZATION_OWNERSHIP("ownership"); +constexpr const char* QOS_SERIALIZATION_KEYED("keyed"); + +} /* namespace participants */ +} /* namespace ddsenabler */ +} /* namespace eprosima */ diff --git a/ddsenabler_participants/include/ddsenabler_participants/serialization.hpp b/ddsenabler_participants/include/ddsenabler_participants/serialization.hpp new file mode 100644 index 00000000..2f27df1f --- /dev/null +++ b/ddsenabler_participants/include/ddsenabler_participants/serialization.hpp @@ -0,0 +1,122 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file serialization.hpp + */ + +#pragma once + +#include +#include + +#include +#include + +#include + +#include + +namespace eprosima { +namespace ddsenabler { +namespace participants { +namespace serialization { + +/** + * @brief Serialize a \c TopicQoS struct into a string. + * + * @param [in] qos TopicQoS to be serialized + * @return Serialized TopicQoS string + */ +std::string serialize_qos( + const ddspipe::core::types::TopicQoS& qos); + +/** + * @brief Deserialize a serialized \c TopicQoS string. + * + * @param [in] qos_str Serialized \c TopicQoS string + * @return Deserialized TopicQoS + */ +ddspipe::core::types::TopicQoS deserialize_qos( + const std::string& qos_str); + +/** + * @brief Serialize a dynamic type into a \c DynamicTypesCollection. + * + * @param [in] type_name Name of the dynamic type + * @param [in] type_identifier Type identifier of the dynamic type + * @param [in,out] dynamic_types Collection to store the serialized dynamic type + * @return True if serialization was successful, false otherwise + */ +bool serialize_dynamic_type( + const std::string& type_name, + const fastdds::dds::xtypes::TypeIdentifier& type_identifier, + DynamicTypesCollection& dynamic_types); + +/** + * @brief Serialize a dynamic type into a \c DynamicTypesCollection. + * + * @param [in] type_identifier Type identifier of the dynamic type + * @param [in] type_object Type object of the dynamic type + * @param [in] type_name Name of the dynamic type + * @param [in,out] dynamic_types Collection to store the serialized dynamic type + * @return True if serialization was successful, false otherwise + */ +bool serialize_dynamic_type( + const fastdds::dds::xtypes::TypeIdentifier& type_identifier, + const fastdds::dds::xtypes::TypeObject& type_object, + const std::string& type_name, + DynamicTypesCollection& dynamic_types); + +/** + * @brief Deserialize a dynamic type from a \c DynamicTypesCollection. + * + * @param [in] dynamic_type DynamicType to be deserialized + * @param [out] type_name Name of the deserialized dynamic type + * @param [out] type_identifier Type identifier of the deserialized dynamic type + * @param [out] type_object Type object of the deserialized dynamic type + * @return True if deserialization was successful, false otherwise + */ +bool deserialize_dynamic_type( + const DynamicType& dynamic_type, + std::string& type_name, + fastdds::dds::xtypes::TypeIdentifier& type_identifier, + fastdds::dds::xtypes::TypeObject& type_object); + +/** + * @brief Serialize a collection of dynamic types into a serialized payload. + * + * @param [in] dynamic_types Collection of dynamic types to be serialized + * @return Serialized payload containing the dynamic types + */ +std::unique_ptr serialize_dynamic_types( + const DynamicTypesCollection& dynamic_types); + +/** + * @brief Deserialize a serialized payload containing dynamic types into a collection. + * + * @param [in] dynamic_types_payload Pointer to the serialized payload + * @param [in] dynamic_types_payload_size Size of the serialized payload + * @param [out] dynamic_types Collection to store the deserialized dynamic types + * @return True if deserialization was successful, false otherwise + */ +bool deserialize_dynamic_types( + const unsigned char* dynamic_types_payload, + uint32_t dynamic_types_payload_size, + DynamicTypesCollection& dynamic_types); + +} /* namespace serialization */ +} /* namespace participants */ +} /* namespace ddsenabler */ +} /* namespace eprosima */ diff --git a/ddsenabler_participants/include/ddsenabler_participants/types/dynamic_types_collection/DynamicTypesCollection.hpp b/ddsenabler_participants/include/ddsenabler_participants/types/dynamic_types_collection/DynamicTypesCollection.hpp new file mode 100644 index 00000000..ff2c281c --- /dev/null +++ b/ddsenabler_participants/include/ddsenabler_participants/types/dynamic_types_collection/DynamicTypesCollection.hpp @@ -0,0 +1,431 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DynamicTypesCollection.hpp + * This header file contains the declaration of the described types in the IDL file. + * + * This file was generated by the tool fastddsgen. + */ + +#ifndef FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTION_HPP +#define FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTION_HPP + +#include +#include +#include +#include + +#include + +#if defined(_WIN32) +#if defined(EPROSIMA_USER_DLL_EXPORT) +#define eProsima_user_DllExport __declspec( dllexport ) +#else +#define eProsima_user_DllExport +#endif // EPROSIMA_USER_DLL_EXPORT +#else +#define eProsima_user_DllExport +#endif // _WIN32 + +#if defined(_WIN32) +#if defined(EPROSIMA_USER_DLL_EXPORT) +#if defined(DYNAMICTYPESCOLLECTION_SOURCE) +#define DYNAMICTYPESCOLLECTION_DllAPI __declspec( dllexport ) +#else +#define DYNAMICTYPESCOLLECTION_DllAPI __declspec( dllimport ) +#endif // DYNAMICTYPESCOLLECTION_SOURCE +#else +#define DYNAMICTYPESCOLLECTION_DllAPI +#endif // EPROSIMA_USER_DLL_EXPORT +#else +#define DYNAMICTYPESCOLLECTION_DllAPI +#endif // _WIN32 + +namespace eprosima { + +namespace ddsenabler { + +namespace participants { + +/*! + * @brief This class represents the structure DynamicType defined by the user in the IDL file. + * @ingroup DynamicTypesCollection + */ +class DynamicType +{ +public: + + /*! + * @brief Default constructor. + */ + eProsima_user_DllExport DynamicType() + { + } + + /*! + * @brief Default destructor. + */ + eProsima_user_DllExport ~DynamicType() + { + } + + /*! + * @brief Copy constructor. + * @param x Reference to the object DynamicType that will be copied. + */ + eProsima_user_DllExport DynamicType( + const DynamicType& x) + { + m_type_name = x.m_type_name; + + m_type_identifier = x.m_type_identifier; + + m_type_object = x.m_type_object; + + } + + /*! + * @brief Move constructor. + * @param x Reference to the object DynamicType that will be copied. + */ + eProsima_user_DllExport DynamicType( + DynamicType&& x) noexcept + { + m_type_name = std::move(x.m_type_name); + m_type_identifier = std::move(x.m_type_identifier); + m_type_object = std::move(x.m_type_object); + } + + /*! + * @brief Copy assignment. + * @param x Reference to the object DynamicType that will be copied. + */ + eProsima_user_DllExport DynamicType& operator =( + const DynamicType& x) + { + + m_type_name = x.m_type_name; + + m_type_identifier = x.m_type_identifier; + + m_type_object = x.m_type_object; + + return *this; + } + + /*! + * @brief Move assignment. + * @param x Reference to the object DynamicType that will be copied. + */ + eProsima_user_DllExport DynamicType& operator =( + DynamicType&& x) noexcept + { + + m_type_name = std::move(x.m_type_name); + m_type_identifier = std::move(x.m_type_identifier); + m_type_object = std::move(x.m_type_object); + return *this; + } + + /*! + * @brief Comparison operator. + * @param x DynamicType object to compare. + */ + eProsima_user_DllExport bool operator ==( + const DynamicType& x) const + { + return (m_type_name == x.m_type_name && + m_type_identifier == x.m_type_identifier && + m_type_object == x.m_type_object); + } + + /*! + * @brief Comparison operator. + * @param x DynamicType object to compare. + */ + eProsima_user_DllExport bool operator !=( + const DynamicType& x) const + { + return !(*this == x); + } + + /*! + * @brief This function copies the value in member type_name + * @param _type_name New value to be copied in member type_name + */ + eProsima_user_DllExport void type_name( + const std::string& _type_name) + { + m_type_name = _type_name; + } + + /*! + * @brief This function moves the value in member type_name + * @param _type_name New value to be moved in member type_name + */ + eProsima_user_DllExport void type_name( + std::string&& _type_name) + { + m_type_name = std::move(_type_name); + } + + /*! + * @brief This function returns a constant reference to member type_name + * @return Constant reference to member type_name + */ + eProsima_user_DllExport const std::string& type_name() const + { + return m_type_name; + } + + /*! + * @brief This function returns a reference to member type_name + * @return Reference to member type_name + */ + eProsima_user_DllExport std::string& type_name() + { + return m_type_name; + } + + + /*! + * @brief This function copies the value in member type_identifier + * @param _type_identifier New value to be copied in member type_identifier + */ + eProsima_user_DllExport void type_identifier( + const std::string& _type_identifier) + { + m_type_identifier = _type_identifier; + } + + /*! + * @brief This function moves the value in member type_identifier + * @param _type_identifier New value to be moved in member type_identifier + */ + eProsima_user_DllExport void type_identifier( + std::string&& _type_identifier) + { + m_type_identifier = std::move(_type_identifier); + } + + /*! + * @brief This function returns a constant reference to member type_identifier + * @return Constant reference to member type_identifier + */ + eProsima_user_DllExport const std::string& type_identifier() const + { + return m_type_identifier; + } + + /*! + * @brief This function returns a reference to member type_identifier + * @return Reference to member type_identifier + */ + eProsima_user_DllExport std::string& type_identifier() + { + return m_type_identifier; + } + + + /*! + * @brief This function copies the value in member type_object + * @param _type_object New value to be copied in member type_object + */ + eProsima_user_DllExport void type_object( + const std::string& _type_object) + { + m_type_object = _type_object; + } + + /*! + * @brief This function moves the value in member type_object + * @param _type_object New value to be moved in member type_object + */ + eProsima_user_DllExport void type_object( + std::string&& _type_object) + { + m_type_object = std::move(_type_object); + } + + /*! + * @brief This function returns a constant reference to member type_object + * @return Constant reference to member type_object + */ + eProsima_user_DllExport const std::string& type_object() const + { + return m_type_object; + } + + /*! + * @brief This function returns a reference to member type_object + * @return Reference to member type_object + */ + eProsima_user_DllExport std::string& type_object() + { + return m_type_object; + } + + + +private: + + std::string m_type_name; + std::string m_type_identifier; + std::string m_type_object; + +}; +/*! + * @brief This class represents the structure DynamicTypesCollection defined by the user in the IDL file. + * @ingroup DynamicTypesCollection + */ +class DynamicTypesCollection +{ +public: + + /*! + * @brief Default constructor. + */ + eProsima_user_DllExport DynamicTypesCollection() + { + } + + /*! + * @brief Default destructor. + */ + eProsima_user_DllExport ~DynamicTypesCollection() + { + } + + /*! + * @brief Copy constructor. + * @param x Reference to the object DynamicTypesCollection that will be copied. + */ + eProsima_user_DllExport DynamicTypesCollection( + const DynamicTypesCollection& x) + { + m_dynamic_types = x.m_dynamic_types; + + } + + /*! + * @brief Move constructor. + * @param x Reference to the object DynamicTypesCollection that will be copied. + */ + eProsima_user_DllExport DynamicTypesCollection( + DynamicTypesCollection&& x) noexcept + { + m_dynamic_types = std::move(x.m_dynamic_types); + } + + /*! + * @brief Copy assignment. + * @param x Reference to the object DynamicTypesCollection that will be copied. + */ + eProsima_user_DllExport DynamicTypesCollection& operator =( + const DynamicTypesCollection& x) + { + + m_dynamic_types = x.m_dynamic_types; + + return *this; + } + + /*! + * @brief Move assignment. + * @param x Reference to the object DynamicTypesCollection that will be copied. + */ + eProsima_user_DllExport DynamicTypesCollection& operator =( + DynamicTypesCollection&& x) noexcept + { + + m_dynamic_types = std::move(x.m_dynamic_types); + return *this; + } + + /*! + * @brief Comparison operator. + * @param x DynamicTypesCollection object to compare. + */ + eProsima_user_DllExport bool operator ==( + const DynamicTypesCollection& x) const + { + return (m_dynamic_types == x.m_dynamic_types); + } + + /*! + * @brief Comparison operator. + * @param x DynamicTypesCollection object to compare. + */ + eProsima_user_DllExport bool operator !=( + const DynamicTypesCollection& x) const + { + return !(*this == x); + } + + /*! + * @brief This function copies the value in member dynamic_types + * @param _dynamic_types New value to be copied in member dynamic_types + */ + eProsima_user_DllExport void dynamic_types( + const std::vector& _dynamic_types) + { + m_dynamic_types = _dynamic_types; + } + + /*! + * @brief This function moves the value in member dynamic_types + * @param _dynamic_types New value to be moved in member dynamic_types + */ + eProsima_user_DllExport void dynamic_types( + std::vector&& _dynamic_types) + { + m_dynamic_types = std::move(_dynamic_types); + } + + /*! + * @brief This function returns a constant reference to member dynamic_types + * @return Constant reference to member dynamic_types + */ + eProsima_user_DllExport const std::vector& dynamic_types() const + { + return m_dynamic_types; + } + + /*! + * @brief This function returns a reference to member dynamic_types + * @return Reference to member dynamic_types + */ + eProsima_user_DllExport std::vector& dynamic_types() + { + return m_dynamic_types; + } + + + +private: + + std::vector m_dynamic_types; + +}; + +} // namespace participants + +} // namespace ddsenabler + +} // namespace eprosima + +#endif // _FAST_DDS_GENERATED_EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTION_HPP_ + + diff --git a/ddsenabler_participants/include/ddsenabler_participants/types/dynamic_types_collection/DynamicTypesCollection.idl b/ddsenabler_participants/include/ddsenabler_participants/types/dynamic_types_collection/DynamicTypesCollection.idl new file mode 100644 index 00000000..c47ffe33 --- /dev/null +++ b/ddsenabler_participants/include/ddsenabler_participants/types/dynamic_types_collection/DynamicTypesCollection.idl @@ -0,0 +1,19 @@ +module eprosima { +module ddsenabler { +module participants { + +struct DynamicType +{ + string type_name; + string type_identifier; + string type_object; +}; + +struct DynamicTypesCollection +{ + sequence dynamic_types; +}; + +}; +}; +}; diff --git a/ddsenabler_participants/include/ddsenabler_participants/types/dynamic_types_collection/DynamicTypesCollectionPubSubTypes.hpp b/ddsenabler_participants/include/ddsenabler_participants/types/dynamic_types_collection/DynamicTypesCollectionPubSubTypes.hpp new file mode 100644 index 00000000..612a4984 --- /dev/null +++ b/ddsenabler_participants/include/ddsenabler_participants/types/dynamic_types_collection/DynamicTypesCollectionPubSubTypes.hpp @@ -0,0 +1,213 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DynamicTypesCollectionPubSubTypes.hpp + * This header file contains the declaration of the serialization functions. + * + * This file was generated by the tool fastddsgen. + */ + + +#ifndef FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTION_PUBSUBTYPES_HPP +#define FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTION_PUBSUBTYPES_HPP + +#include +#include +#include +#include +#include + +#include "DynamicTypesCollection.hpp" + + +#if !defined(FASTDDS_GEN_API_VER) || (FASTDDS_GEN_API_VER != 3) +#error \ + Generated DynamicTypesCollection is not compatible with current installed Fast DDS. Please, regenerate it with fastddsgen. +#endif // FASTDDS_GEN_API_VER + +namespace eprosima +{ + namespace ddsenabler + { + namespace participants + { + + /*! + * @brief This class represents the TopicDataType of the type DynamicType defined by the user in the IDL file. + * @ingroup DynamicTypesCollection + */ + class DynamicTypePubSubType : public eprosima::fastdds::dds::TopicDataType + { + public: + + typedef DynamicType type; + + eProsima_user_DllExport DynamicTypePubSubType(); + + eProsima_user_DllExport ~DynamicTypePubSubType() override; + + eProsima_user_DllExport bool serialize( + const void* const data, + eprosima::fastdds::rtps::SerializedPayload_t& payload, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool deserialize( + eprosima::fastdds::rtps::SerializedPayload_t& payload, + void* data) override; + + eProsima_user_DllExport uint32_t calculate_serialized_size( + const void* const data, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool compute_key( + eprosima::fastdds::rtps::SerializedPayload_t& payload, + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport bool compute_key( + const void* const data, + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport void* create_data() override; + + eProsima_user_DllExport void delete_data( + void* data) override; + + //Register TypeObject representation in Fast DDS TypeObjectRegistry + eProsima_user_DllExport void register_type_object_representation() override; + + #ifdef TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + eProsima_user_DllExport inline bool is_bounded() const override + { + return false; + } + + #endif // TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + + #ifdef TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + + eProsima_user_DllExport inline bool is_plain( + eprosima::fastdds::dds::DataRepresentationId_t data_representation) const override + { + static_cast(data_representation); + return false; + } + + #endif // TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + + #ifdef TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + eProsima_user_DllExport inline bool construct_sample( + void* memory) const override + { + static_cast(memory); + return false; + } + + #endif // TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + + private: + + eprosima::fastdds::MD5 md5_; + unsigned char* key_buffer_; + + }; + + /*! + * @brief This class represents the TopicDataType of the type DynamicTypesCollection defined by the user in the IDL file. + * @ingroup DynamicTypesCollection + */ + class DynamicTypesCollectionPubSubType : public eprosima::fastdds::dds::TopicDataType + { + public: + + typedef DynamicTypesCollection type; + + eProsima_user_DllExport DynamicTypesCollectionPubSubType(); + + eProsima_user_DllExport ~DynamicTypesCollectionPubSubType() override; + + eProsima_user_DllExport bool serialize( + const void* const data, + eprosima::fastdds::rtps::SerializedPayload_t& payload, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool deserialize( + eprosima::fastdds::rtps::SerializedPayload_t& payload, + void* data) override; + + eProsima_user_DllExport uint32_t calculate_serialized_size( + const void* const data, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool compute_key( + eprosima::fastdds::rtps::SerializedPayload_t& payload, + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport bool compute_key( + const void* const data, + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport void* create_data() override; + + eProsima_user_DllExport void delete_data( + void* data) override; + + //Register TypeObject representation in Fast DDS TypeObjectRegistry + eProsima_user_DllExport void register_type_object_representation() override; + + #ifdef TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + eProsima_user_DllExport inline bool is_bounded() const override + { + return false; + } + + #endif // TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + + #ifdef TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + + eProsima_user_DllExport inline bool is_plain( + eprosima::fastdds::dds::DataRepresentationId_t data_representation) const override + { + static_cast(data_representation); + return false; + } + + #endif // TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + + #ifdef TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + eProsima_user_DllExport inline bool construct_sample( + void* memory) const override + { + static_cast(memory); + return false; + } + + #endif // TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + + private: + + eprosima::fastdds::MD5 md5_; + unsigned char* key_buffer_; + + }; + } // namespace participants + } // namespace ddsenabler +} // namespace eprosima + +#endif // FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTION_PUBSUBTYPES_HPP + diff --git a/ddsenabler_participants/include/ddsenabler_participants/types/dynamic_types_collection/DynamicTypesCollectionTypeObjectSupport.hpp b/ddsenabler_participants/include/ddsenabler_participants/types/dynamic_types_collection/DynamicTypesCollectionTypeObjectSupport.hpp new file mode 100644 index 00000000..6d6c5471 --- /dev/null +++ b/ddsenabler_participants/include/ddsenabler_participants/types/dynamic_types_collection/DynamicTypesCollectionTypeObjectSupport.hpp @@ -0,0 +1,78 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DynamicTypesCollectionTypeObjectSupport.hpp + * Header file containing the API required to register the TypeObject representation of the described types in the IDL file + * + * This file was generated by the tool fastddsgen. + */ + +#ifndef FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTION_TYPE_OBJECT_SUPPORT_HPP +#define FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTION_TYPE_OBJECT_SUPPORT_HPP + +#include + + +#if defined(_WIN32) +#if defined(EPROSIMA_USER_DLL_EXPORT) +#define eProsima_user_DllExport __declspec( dllexport ) +#else +#define eProsima_user_DllExport +#endif // EPROSIMA_USER_DLL_EXPORT +#else +#define eProsima_user_DllExport +#endif // _WIN32 + +#ifndef DOXYGEN_SHOULD_SKIP_THIS_PUBLIC + +namespace eprosima { +namespace ddsenabler { +namespace participants { +/** + * @brief Register DynamicType related TypeIdentifier. + * Fully-descriptive TypeIdentifiers are directly registered. + * Hash TypeIdentifiers require to fill the TypeObject information and hash it, consequently, the TypeObject is + * indirectly registered as well. + * + * @param[out] TypeIdentifier of the registered type. + * The returned TypeIdentifier corresponds to the complete TypeIdentifier in case of hashed TypeIdentifiers. + * Invalid TypeIdentifier is returned in case of error. + */ +eProsima_user_DllExport void register_DynamicType_type_identifier( + eprosima::fastdds::dds::xtypes::TypeIdentifierPair& type_ids); + +/** + * @brief Register DynamicTypesCollection related TypeIdentifier. + * Fully-descriptive TypeIdentifiers are directly registered. + * Hash TypeIdentifiers require to fill the TypeObject information and hash it, consequently, the TypeObject is + * indirectly registered as well. + * + * @param[out] TypeIdentifier of the registered type. + * The returned TypeIdentifier corresponds to the complete TypeIdentifier in case of hashed TypeIdentifiers. + * Invalid TypeIdentifier is returned in case of error. + */ +eProsima_user_DllExport void register_DynamicTypesCollection_type_identifier( + eprosima::fastdds::dds::xtypes::TypeIdentifierPair& type_ids); + +} // namespace participants + +} // namespace ddsenabler + +} // namespace eprosima + + +#endif // DOXYGEN_SHOULD_SKIP_THIS_PUBLIC + +#endif // FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTION_TYPE_OBJECT_SUPPORT_HPP diff --git a/ddsenabler_participants/src/cpp/CBHandler.cpp b/ddsenabler_participants/src/cpp/CBHandler.cpp index 36cc0c3f..3fbe3c51 100644 --- a/ddsenabler_participants/src/cpp/CBHandler.cpp +++ b/ddsenabler_participants/src/cpp/CBHandler.cpp @@ -16,19 +16,17 @@ * @file CBHandler.cpp */ -#include -#include -#include -#include - -#include +#include +#include +#include #include -#include +#include +#include -#include #include -#include -#include + +#include +#include #include @@ -62,33 +60,39 @@ void CBHandler::add_schema( { std::lock_guard lock(mtx_); - auto received_type = dyn_type->get_name().to_string(); - - assert(nullptr != dyn_type); + add_schema_nts_(dyn_type, type_id); +} - // Check if it exists already - auto it = schemas_.find(type_id); - if (it != schemas_.end()) - { - return; - } +void CBHandler::add_topic( + const DdsTopic& topic) +{ + std::lock_guard lock(mtx_); - // Add to schemas map EPROSIMA_LOG_INFO(DDSENABLER_CB_HANDLER, - "Adding schema with name " << dyn_type->get_name().to_string() << "."); + "Adding topic: " << topic << "."); - schemas_[type_id] = dyn_type; + write_topic_nts_(topic); } void CBHandler::add_data( const DdsTopic& topic, RtpsPayloadData& data) { - std::unique_lock lock(mtx_); + std::lock_guard lock(mtx_); EPROSIMA_LOG_INFO(DDSENABLER_CB_HANDLER, "Adding data in topic: " << topic << "."); + fastdds::dds::DynamicType::_ref_type dyn_type; + auto it = schemas_.find(topic.type_name); + if (it == schemas_.end()) + { + EPROSIMA_LOG_WARNING(DDSENABLER_CB_HANDLER, + "Schema for type " << topic.type_name << " not available."); + return; + } + dyn_type = it->second.second; + CBMessage msg; msg.sequence_number = unique_sequence_number_++; msg.publish_time = data.source_timestamp; @@ -116,47 +120,254 @@ void CBHandler::add_data( throw utils::InconsistencyException(STR_ENTRY << "Received sample with no payload."); } + write_sample_nts_(msg, dyn_type); +} + +bool CBHandler::get_type_identifier( + const std::string& type_name, + fastdds::dds::xtypes::TypeIdentifier& type_identifier) +{ + std::lock_guard lock(mtx_); + + auto it = schemas_.find(type_name); + if (it != schemas_.end()) + { + type_identifier = it->second.first; + return true; + } + + // Try to retrieve it from local registry + fastdds::dds::xtypes::TypeIdentifierPair type_ids; + if (fastdds::dds::RETCODE_OK == + fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + type_name, type_ids)) + { + // Get complete type object + type_identifier = + (fastdds::dds::xtypes::EK_COMPLETE == + type_ids.type_identifier1()._d()) ? type_ids.type_identifier1() : type_ids.type_identifier2(); + fastdds::dds::xtypes::TypeObject type_object; + if (fastdds::dds::RETCODE_OK == + fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_object( + type_identifier, type_object)) + { + // If already in the registry, just add it to schemas map. Also report to the user the schema and all + // associated data required for persistence in case she does not have it yet. + if (add_schema_nts_(type_identifier, type_object, true)) + { + return true; + } + // If failed to add schema from the type object found in the registry, attempt requesting it to the user + } + } + + if (!type_query_callback_) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_HANDLER, + "Type query callback not set."); + return false; + } + + std::unique_ptr serialized_type; + uint32_t serialized_type_size; + if (!type_query_callback_(type_name.c_str(), serialized_type, serialized_type_size)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_HANDLER, + "Type query callback failed to retrieve " << type_name << " type."); + return false; + } + + // Register the type obtained through the type query callback + fastdds::dds::xtypes::TypeObject type_object; + if (!register_type_nts_(type_name, serialized_type.get(), serialized_type_size, type_identifier, type_object)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_HANDLER, + "Failed to register type " << type_name << "."); + return false; + } + + // Add to schemas map, but do not report it to the user as it is the exact same information we obtained through the + // type query callback. + add_schema_nts_(type_identifier, type_object, false); + + return true; +} + +bool CBHandler::get_serialized_data( + const std::string& type_name, + const std::string& json, + Payload& payload) +{ + std::lock_guard lock(mtx_); + fastdds::dds::DynamicType::_ref_type dyn_type; - fastdds::dds::xtypes::TypeIdentifier type_id; + auto it = schemas_.find(type_name); + if (it == schemas_.end()) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_HANDLER, + "Failed to deserialize data for type " << type_name << " : schema not available."); + return false; + } + dyn_type = it->second.second; - if (eprosima::fastdds::dds::xtypes::TK_NONE != topic.type_identifiers.type_identifier1()._d()) + fastdds::dds::DynamicData::_ref_type dyn_data; + if ((fastdds::dds::RETCODE_OK != + fastdds::dds::json_deserialize(json, dyn_type, fastdds::dds::DynamicDataJsonFormat::EPROSIMA, + dyn_data)) || !dyn_data) { - type_id = topic.type_identifiers.type_identifier1(); + EPROSIMA_LOG_ERROR(DDSENABLER_CB_HANDLER, + "Failed to deserialize data for type " << type_name << " : json deserialization failed."); + return false; } - else if (eprosima::fastdds::dds::xtypes::TK_NONE != topic.type_identifiers.type_identifier2()._d()) + + // Use XCDR1 for backwards compatibility (e.g. ROS 2 distributions prior to Kilted) + fastdds::dds::DynamicPubSubType pubsub_type (dyn_type); + uint32_t payload_size = pubsub_type.calculate_serialized_size(&dyn_data, + fastdds::dds::DataRepresentationId::XCDR_DATA_REPRESENTATION); + + if (!payload_pool_->get_payload(payload_size, payload)) { - type_id = topic.type_identifiers.type_identifier2(); + EPROSIMA_LOG_ERROR(DDSENABLER_CB_HANDLER, + "Failed to deserialize data for type " << type_name << " : get_payload failed."); + return false; } - else + + if (!pubsub_type.serialize(&dyn_data, payload, fastdds::dds::DataRepresentationId::XCDR_DATA_REPRESENTATION)) { - // NO TYPE_IDENTIFIERS - EPROSIMA_LOG_WARNING(DDSENABLER_CB_HANDLER, - "Received Schema for type " << topic.type_name << " with no TypeIdentifier."); - return; + EPROSIMA_LOG_ERROR(DDSENABLER_CB_HANDLER, + "Failed to deserialize data for type " << type_name << " : payload serialization failed."); + return false; } - auto it = schemas_.find(type_id); + return true; +} + +void CBHandler::add_schema_nts_( + const fastdds::dds::DynamicType::_ref_type& dyn_type, + const fastdds::dds::xtypes::TypeIdentifier& type_id, + bool write_schema) +{ + assert(nullptr != dyn_type); + + const std::string& type_name = dyn_type->get_name().to_string(); + + // Check if it exists already + auto it = schemas_.find(type_name); if (it != schemas_.end()) { - dyn_type = it->second; - // Schema available -> write - write_sample(msg, dyn_type); + return; } - else + schemas_[type_name] = {type_id, dyn_type}; + + // Add to schemas map + EPROSIMA_LOG_INFO(DDSENABLER_CB_HANDLER, + "Adding schema with name " << type_name << "."); + + if (write_schema) { - EPROSIMA_LOG_WARNING(DDSENABLER_CB_HANDLER, - "Schema for type " << topic.type_name << " not available."); + write_schema_nts_(dyn_type, type_id); } +} +bool CBHandler::add_schema_nts_( + const fastdds::dds::xtypes::TypeIdentifier& type_id, + const fastdds::dds::xtypes::TypeObject& type_obj, + bool write_schema) +{ + // Create a DynamicType from TypeObject + fastdds::dds::DynamicType::_ref_type dyn_type = + fastdds::dds::DynamicTypeBuilderFactory::get_instance()->create_type_w_type_object(type_obj) + ->build(); + if (!dyn_type) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_HANDLER, + "Failed to create Dynamic Type from TypeObject."); + return false; + } + + add_schema_nts_(dyn_type, type_id, write_schema); + return true; } -void CBHandler::write_sample( +void CBHandler::write_schema_nts_( + const fastdds::dds::DynamicType::_ref_type& dyn_type, + const fastdds::dds::xtypes::TypeIdentifier& type_id) +{ + cb_writer_->write_schema(dyn_type, type_id); +} + +void CBHandler::write_topic_nts_( + const DdsTopic& topic) +{ + cb_writer_->write_topic(topic); +} + +void CBHandler::write_sample_nts_( const CBMessage& msg, const fastdds::dds::DynamicType::_ref_type& dyn_type) { cb_writer_->write_data(msg, dyn_type); } +bool CBHandler::register_type_nts_( + const std::string& type_name, + const unsigned char* serialized_type, + uint32_t serialized_type_size, + fastdds::dds::xtypes::TypeIdentifier& type_identifier, + fastdds::dds::xtypes::TypeObject& type_object) +{ + DynamicTypesCollection dynamic_types; + if (!serialization::deserialize_dynamic_types(serialized_type, serialized_type_size, dynamic_types)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_HANDLER, + "Failed to deserialize dynamic types collection."); + return false; + } + + std::string _type_name; + fastdds::dds::xtypes::TypeIdentifier _type_identifier; + fastdds::dds::xtypes::TypeObject _type_object; + + // Deserialize and register all dependencies and main type (last one in collection) + for (DynamicType& dynamic_type : dynamic_types.dynamic_types()) + { + if (!serialization::deserialize_dynamic_type(dynamic_type, _type_name, _type_identifier, _type_object)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_HANDLER, + "Failed to deserialize " << dynamic_type.type_name() << " DynamicType."); + return false; + } + + // Create a TypeIdentifierPair to use in register_type_identifier + fastdds::dds::xtypes::TypeIdentifierPair type_identifiers; + type_identifiers.type_identifier1(_type_identifier); + + // Register in factory + if (fastdds::dds::RETCODE_OK != + fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().register_type_object( + _type_object, type_identifiers)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_HANDLER, + "Failed to register " << dynamic_type.type_name() << " DynamicType."); + return false; + } + } + + if (_type_name != type_name) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_HANDLER, + "Unexpected dynamic types collection format: " << type_name << " expected to be last item, found " << _type_name << + " instead."); + return false; + } + + // Assign type identifier and object after all types have been registered + type_identifier = _type_identifier; + type_object = _type_object; + + return true; +} + } /* namespace participants */ } /* namespace ddsenabler */ } /* namespace eprosima */ diff --git a/ddsenabler_participants/src/cpp/CBWriter.cpp b/ddsenabler_participants/src/cpp/CBWriter.cpp index 256c3a27..5f4c6ab2 100644 --- a/ddsenabler_participants/src/cpp/CBWriter.cpp +++ b/ddsenabler_participants/src/cpp/CBWriter.cpp @@ -18,11 +18,14 @@ #include -#include - -#include #include +#include #include +#include +#include + +#include +#include #include @@ -30,20 +33,107 @@ namespace eprosima { namespace ddsenabler { namespace participants { +using namespace eprosima::ddsenabler::participants::serialization; +using namespace eprosima::ddspipe::core::types; + +void CBWriter::write_schema( + const fastdds::dds::DynamicType::_ref_type& dyn_type, + const fastdds::dds::xtypes::TypeIdentifier& type_id) +{ + assert(nullptr != dyn_type); + + const std::string& type_name = dyn_type->get_name().to_string(); + + // Schema has not been registered + EPROSIMA_LOG_INFO(DDSENABLER_CB_WRITER, + "Writing schema: " << type_name << "."); + + std::stringstream ss_idl; + auto ret = fastdds::dds::idl_serialize(dyn_type, ss_idl); + if (ret != fastdds::dds::RETCODE_OK) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_WRITER, + "Failed to serialize DynamicType to idl for type with name: " << type_name); + return; + } + + DynamicTypesCollection types_collection; + if (!serialize_dynamic_type(type_name, type_id, types_collection)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_WRITER, + "Failed to serialize dynamic types collection: " << type_name); + return; + } + + std::unique_ptr types_collection_payload = serialize_dynamic_types( + types_collection); + if (nullptr == types_collection_payload) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_WRITER, + "Failed to serialize dynamic types collection: " << type_name); + return; + } + + std::stringstream ss_data_holder; + ss_data_holder << std::setw(4); + if (fastdds::dds::RETCODE_OK != + fastdds::dds::json_serialize(fastdds::dds::DynamicDataFactory::get_instance()->create_data(dyn_type), + fastdds::dds::DynamicDataJsonFormat::EPROSIMA, ss_data_holder)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_WRITER, + "Not able to generate data placeholder for type " << type_name << "."); + return; + } + + // Notify type reception + if (type_notification_callback_) + { + type_notification_callback_( + type_name.c_str(), + ss_idl.str().c_str(), + types_collection_payload->data, + types_collection_payload->length, + ss_data_holder.str().c_str() + ); + } +} + +void CBWriter::write_topic( + const DdsTopic& topic) +{ + EPROSIMA_LOG_INFO(DDSENABLER_CB_WRITER, + "Writting topic: " << topic.topic_name() << "."); + + // Notify topic reception + if (topic_notification_callback_) + { + std::string serialized_qos = serialize_qos(topic.topic_qos); + topic_notification_callback_( + topic.topic_name().c_str(), + topic.type_name.c_str(), + serialized_qos.c_str() + ); + } +} void CBWriter::write_data( const CBMessage& msg, const fastdds::dds::DynamicType::_ref_type& dyn_type) { - std::lock_guard lock(mutex_); - - write_schema(msg, dyn_type); + assert(nullptr != dyn_type); EPROSIMA_LOG_INFO(DDSENABLER_CB_WRITER, "Writing message from topic: " << msg.topic.topic_name() << "."); - // Get the data as JSON - fastdds::dds::DynamicData::_ref_type dyn_data = get_dynamic_data(msg, dyn_type); + // Get the dynamic data to be serialized into JSON + fastdds::dds::DynamicData::_ref_type dyn_data = get_dynamic_data_(msg, dyn_type); + + if (nullptr == dyn_data) + { + EPROSIMA_LOG_ERROR(DDSENABLER_CB_WRITER, + "Not able to get DynamicData from topic " << msg.topic.topic_name() << "."); + return; + } std::stringstream ss_dyn_data; ss_dyn_data << std::setw(4); @@ -55,28 +145,33 @@ void CBWriter::write_data( return; } - // Create the base JSON structure - nlohmann::ordered_json json_output; - - std::stringstream ss_source_guid_prefix; - ss_source_guid_prefix << msg.source_guid.guid_prefix(); - json_output["id"] = ss_source_guid_prefix.str(); - json_output["type"] = "fastdds"; - json_output[msg.topic.topic_name()] = { - {"type", msg.topic.type_name}, - {"data", nlohmann::json::object()} - }; - - std::stringstream ss_instanceHandle; - ss_instanceHandle << msg.instanceHandle; - nlohmann::ordered_json parsed_dyn_data = nlohmann::json::parse(ss_dyn_data.str()); - json_output[msg.topic.topic_name()]["data"][ss_instanceHandle.str()] = parsed_dyn_data; - - //STORE DATA - if (data_callback_) + // Fill JSON object with the data + nlohmann::json json_output; + { + // Set id to be the source guid prefix + std::stringstream ss_source_guid_prefix; + ss_source_guid_prefix << msg.source_guid.guid_prefix(); + json_output["id"] = ss_source_guid_prefix.str(); + + // Set type to be fastdds + json_output["type"] = "fastdds"; + + // Insert type and data (to be filled below) with topic name as key + json_output[msg.topic.topic_name()] = { + {"type", msg.topic.type_name}, + {"data", nlohmann::json::object()} + }; + + // Insert data with instance handle as key + std::stringstream ss_instanceHandle; + ss_instanceHandle << msg.instanceHandle; + json_output[msg.topic.topic_name()]["data"][ss_instanceHandle.str()] = nlohmann::json::parse(ss_dyn_data.str()); + } + + // Notify data reception + if (data_notification_callback_) { - data_callback_( - msg.topic.type_name.c_str(), + data_notification_callback_( msg.topic.topic_name().c_str(), json_output.dump(4).c_str(), msg.publish_time.to_ns() @@ -84,66 +179,43 @@ void CBWriter::write_data( } } -void CBWriter::write_schema( +fastdds::dds::DynamicData::_ref_type CBWriter::get_dynamic_data_( const CBMessage& msg, - const fastdds::dds::DynamicType::_ref_type& dyn_type) + const fastdds::dds::DynamicType::_ref_type& dyn_type) noexcept { - const std::string topic_name = msg.topic.topic_name(); - const std::string type_name = msg.topic.type_name; - const fastdds::dds::xtypes::TypeIdentifier type_id = msg.topic.type_identifiers.type_identifier1(); + // TODO fast this should not be done, but dyn types API is like it is. + auto& data_no_const = const_cast(msg.payload); - auto it = stored_schemas_.find(topic_name); - if (it == stored_schemas_.end()) - { - //Schema has not been registered - EPROSIMA_LOG_INFO(DDSENABLER_CB_WRITER, - "Writing schema: " << type_name << " on topic: " << topic_name << "."); - - std::stringstream ss_idl; - auto ret = fastdds::dds::idl_serialize(dyn_type, ss_idl); - if (ret != fastdds::dds::RETCODE_OK) - { - EPROSIMA_LOG_ERROR(DDSENABLER_CB_WRITER, - "Failed to serialize DynamicType to idl for type with name: " << type_name); - return; - } - - //Add the schema and topic to stored_schemas_ - stored_schemas_[topic_name] = type_id; - - //STORE SCHEMA - if (type_callback_) - { - type_callback_( - type_name.c_str(), - topic_name.c_str(), - ss_idl.str().c_str() - ); - } - } - else + // Create a DynamicData object using the DynamicType + fastdds::dds::DynamicData::_ref_type dyn_data( + fastdds::dds::DynamicDataFactory::get_instance()->create_data(dyn_type)); + + // Deserialize data into the DynamicData object + if (!(get_pubsub_type_(dyn_type).deserialize(data_no_const, &dyn_data))) { - //Schema has been registered - EPROSIMA_LOG_INFO(DDSENABLER_CB_WRITER, - "Schema: " + type_name + " already registered for topic: " + topic_name + "."); + EPROSIMA_LOG_ERROR(DDSENABLER_CB_WRITER, + "Failed to deserialize data for topic: " << msg.topic.topic_name()); + return nullptr; } + + return dyn_data; } -fastdds::dds::DynamicData::_ref_type CBWriter::get_dynamic_data( - const CBMessage& msg, +fastdds::dds::DynamicPubSubType CBWriter::get_pubsub_type_( const fastdds::dds::DynamicType::_ref_type& dyn_type) noexcept { - // TODO fast this should not be done, but dyn types API is like it is. - auto& data_no_const = const_cast(msg.payload); + // Check if we already have this pubsub type + auto it = dynamic_pubsub_types_.find(dyn_type); + if (it != dynamic_pubsub_types_.end()) + { + return it->second; + } - // Create PubSub Type + // Create a new pubsub type fastdds::dds::DynamicPubSubType pubsub_type(dyn_type); - fastdds::dds::DynamicData::_ref_type dyn_data( - fastdds::dds::DynamicDataFactory::get_instance()->create_data(dyn_type)); + dynamic_pubsub_types_[dyn_type] = pubsub_type; - pubsub_type.deserialize(data_no_const, &dyn_data); - - return dyn_data; + return pubsub_type; } } /* namespace participants */ diff --git a/ddsenabler_participants/src/cpp/DdsParticipant.cpp b/ddsenabler_participants/src/cpp/DdsParticipant.cpp new file mode 100644 index 00000000..3a166c62 --- /dev/null +++ b/ddsenabler_participants/src/cpp/DdsParticipant.cpp @@ -0,0 +1,53 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file DdsParticipant.cpp + */ + +#include +#include +#include + +#include + +namespace eprosima { +namespace ddsenabler { +namespace participants { + +using namespace eprosima::ddspipe::core; +using namespace eprosima::ddspipe::core::types; +using namespace eprosima::ddspipe::participants; + +DdsParticipant::DdsParticipant( + std::shared_ptr participant_configuration, + std::shared_ptr payload_pool, + std::shared_ptr discovery_database) + : DynTypesParticipant(participant_configuration, payload_pool, discovery_database) +{ +} + +std::shared_ptr DdsParticipant::create_writer( + const ITopic& topic) +{ + if (is_type_object_topic(topic)) + { + return std::make_shared(); + } + return rtps::SimpleParticipant::create_writer(topic); +} + +} /* namespace participants */ +} /* namespace ddsenabler */ +} /* namespace eprosima */ diff --git a/ddsenabler_participants/src/cpp/EnablerParticipant.cpp b/ddsenabler_participants/src/cpp/EnablerParticipant.cpp new file mode 100644 index 00000000..0bb1cca2 --- /dev/null +++ b/ddsenabler_participants/src/cpp/EnablerParticipant.cpp @@ -0,0 +1,202 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file EnablerParticipant.cpp + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +namespace eprosima { +namespace ddsenabler { +namespace participants { + +using namespace eprosima::ddspipe::core; +using namespace eprosima::ddspipe::core::types; +using namespace eprosima::ddspipe::participants; + +EnablerParticipant::EnablerParticipant( + std::shared_ptr participant_configuration, + std::shared_ptr payload_pool, + std::shared_ptr discovery_database, + std::shared_ptr schema_handler) + : ddspipe::participants::SchemaParticipant(participant_configuration, payload_pool, discovery_database, + schema_handler) +{ +} + +std::shared_ptr EnablerParticipant::create_reader( + const ITopic& topic) +{ + if (is_type_object_topic(topic)) + { + return std::make_shared(); + } + + std::shared_ptr reader; + { + std::lock_guard lck(mtx_); + reader = std::make_shared(id()); + auto dds_topic = dynamic_cast(topic); + readers_[dds_topic] = reader; + // Only notify the discovery of topics that do not originate from a topic query callback + if (dds_topic.topic_discoverer() != this->id()) + { + std::static_pointer_cast(schema_handler_)->add_topic(dds_topic); + } + } + cv_.notify_all(); + return reader; +} + +bool EnablerParticipant::publish( + const std::string& topic_name, + const std::string& json) +{ + if (topic_name.empty()) + { + EPROSIMA_LOG_ERROR(DDSENABLER_ENABLER_PARTICIPANT, + "Failed to publish data: topic name is empty."); + return false; + } + + std::unique_lock lck(mtx_); + + std::string type_name; + auto reader = lookup_reader_nts_(topic_name, type_name); + + if (nullptr == reader) + { + if (!topic_query_callback_) + { + EPROSIMA_LOG_ERROR(DDSENABLER_ENABLER_PARTICIPANT, + "Failed to publish data in topic " << topic_name << + " : topic is unknown and topic query callback not set."); + return false; + } + + std::string serialized_qos; + if (!topic_query_callback_(topic_name.c_str(), type_name, serialized_qos)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_ENABLER_PARTICIPANT, + "Failed to publish data in topic " << topic_name << " : topic query callback failed."); + return false; + } + + // Deserialize QoS if provided by the user (otherwise use default one) + TopicQoS qos; + if (!serialized_qos.empty()) + { + try + { + qos = serialization::deserialize_qos(serialized_qos); + } + catch (const std::exception& e) + { + EPROSIMA_LOG_ERROR(DDSENABLER_ENABLER_PARTICIPANT, + "Failed to deserialize QoS for topic " << topic_name << ": " << e.what()); + return false; + } + } + + fastdds::dds::xtypes::TypeIdentifier type_identifier; + if (!std::static_pointer_cast(schema_handler_)->get_type_identifier(type_name, type_identifier)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_ENABLER_PARTICIPANT, + "Failed to publish data in topic " << topic_name << " : type identifier not found."); + return false; + } + + DdsTopic topic; + topic.m_topic_name = topic_name; + topic.type_name = type_name; + topic.topic_qos = qos; + topic.type_identifiers.type_identifier1(type_identifier); + this->discovery_database_->add_endpoint(rtps::CommonParticipant::simulate_endpoint(topic, this->id())); + + // Wait for reader to be created from discovery thread + // NOTE: Set a timeout to avoid a deadlock in case the reader is never created for some reason (e.g. the topic + // is blocked or the underlying DDS Pipe object is disabled/destroyed before the reader is created). + if (!cv_.wait_for(lck, std::chrono::seconds(5), [&] + { + return nullptr != (reader = lookup_reader_nts_(topic_name)); + })) + { + EPROSIMA_LOG_ERROR(DDSENABLER_ENABLER_PARTICIPANT, + "Failed to create internal reader for topic " << topic_name << + " , please verify that the topic is allowed."); + return false; + } + + // (Optionally) wait for writer created in DDS participant to match with external readers, to avoid losing this + // message when not using transient durability + std::this_thread::sleep_for(std::chrono::milliseconds(std::static_pointer_cast( + configuration_)->initial_publish_wait)); + } + + auto data = std::make_unique(); + + Payload payload; + if (!std::static_pointer_cast(schema_handler_)->get_serialized_data(type_name, json, payload)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_ENABLER_PARTICIPANT, + "Failed to publish data in topic " << topic_name << " : data serialization failed."); + return false; + } + + if (!payload_pool_->get_payload(payload, data->payload)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_ENABLER_PARTICIPANT, + "Failed to publish data in topic " << topic_name << " : get_payload failed."); + return false; + } + + reader->simulate_data_reception(std::move(data)); + return true; +} + +std::shared_ptr EnablerParticipant::lookup_reader_nts_( + const std::string& topic_name, + std::string& type_name) const +{ + for (const auto& reader : readers_) + { + if (reader.first.m_topic_name == topic_name) + { + type_name = reader.first.type_name; + return reader.second; + } + } + return nullptr; +} + +std::shared_ptr EnablerParticipant::lookup_reader_nts_( + const std::string& topic_name) const +{ + std::string _; + return lookup_reader_nts_(topic_name, _); +} + +} /* namespace participants */ +} /* namespace ddsenabler */ +} /* namespace eprosima */ diff --git a/ddsenabler_participants/src/cpp/serialization.cpp b/ddsenabler_participants/src/cpp/serialization.cpp new file mode 100644 index 00000000..b6848c91 --- /dev/null +++ b/ddsenabler_participants/src/cpp/serialization.cpp @@ -0,0 +1,541 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file serialization.cpp + */ + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace eprosima { +namespace ddsenabler { +namespace participants { +namespace serialization { + +using namespace eprosima::ddspipe::core::types; +using namespace eprosima::fastdds::dds::xtypes; + +/////////////////////// +// QoS serialization // +/////////////////////// + +std::string serialize_qos( + const TopicQoS& qos) +{ + YAML::Node qos_yaml; + + // Reliability tag + YAML::Node reliability_tag = qos_yaml[QOS_SERIALIZATION_RELIABILITY]; + if (qos.is_reliable()) + { + reliability_tag = true; + } + else + { + reliability_tag = false; + } + + // Durability tag + YAML::Node durability_tag = qos_yaml[QOS_SERIALIZATION_DURABILITY]; + if (qos.is_transient_local()) + { + durability_tag = true; + } + else + { + durability_tag = false; + } + + // Ownership tag + YAML::Node ownership_tag = qos_yaml[QOS_SERIALIZATION_OWNERSHIP]; + if (qos.has_ownership()) + { + ownership_tag = true; + } + else + { + ownership_tag = false; + } + + // Keyed tag + YAML::Node keyed_tag = qos_yaml[QOS_SERIALIZATION_KEYED]; + if (qos.keyed) + { + keyed_tag = true; + } + else + { + keyed_tag = false; + } + + return YAML::Dump(qos_yaml); +} + +TopicQoS deserialize_qos( + const std::string& qos_str) +{ + TopicQoS qos{}; + + YAML::Node qos_yaml = YAML::Load(qos_str); + bool reliable = qos_yaml[QOS_SERIALIZATION_RELIABILITY].as(); + bool transient_local = qos_yaml[QOS_SERIALIZATION_DURABILITY].as(); + bool exclusive_ownership = qos_yaml[QOS_SERIALIZATION_OWNERSHIP].as(); + bool keyed = qos_yaml[QOS_SERIALIZATION_KEYED].as(); + + // Parse reliability + if (reliable) + { + qos.reliability_qos = ReliabilityKind::RELIABLE; + } + else + { + qos.reliability_qos = ReliabilityKind::BEST_EFFORT; + } + + // Parse durability + if (transient_local) + { + qos.durability_qos = DurabilityKind::TRANSIENT_LOCAL; + } + else + { + qos.durability_qos = DurabilityKind::VOLATILE; + } + + // Parse ownership + if (exclusive_ownership) + { + qos.ownership_qos = OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS; + } + else + { + qos.ownership_qos = OwnershipQosPolicyKind::SHARED_OWNERSHIP_QOS; + } + + // Parse keyed + qos.keyed = keyed; + + return qos; +} + +////////////////////////// +// XTypes serialization // +////////////////////////// + +template +std::string serialize_type_data( + const DynamicTypeData& type_data); + +template +DynamicTypeData deserialize_type_data( + const std::string& typedata_str); + +std::string serialize_type_identifier( + const TypeIdentifier& type_identifier); + +TypeIdentifier deserialize_type_identifier( + const std::string& typeid_str); + +std::string serialize_type_object( + const TypeObject& type_object); + +TypeObject deserialize_type_object( + const std::string& typeobj_str); + +bool serialize_dynamic_type( + const std::string& type_name, + const TypeIdentifier& type_identifier, + DynamicTypesCollection& dynamic_types) +{ + TypeIdentifierPair type_identifiers; + + // NOTE: type_identifier is assumed to be complete + type_identifiers.type_identifier1(type_identifier); + + TypeInformation type_info; + if (fastdds::dds::RETCODE_OK != + fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_information( + type_identifiers, + type_info, + true)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_SERIALIZATION, + "Error getting TypeInformation for type " << type_name); + return false; + } + + std::string dependency_name; + unsigned int dependency_index = 0; + const auto type_dependencies = type_info.complete().dependent_typeids(); + for (auto dependency : type_dependencies) + { + TypeIdentifier dependency_type_identifier; + dependency_type_identifier = dependency.type_id(); + + TypeObject dependency_type_object; + if (fastdds::dds::RETCODE_OK != + fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_object( + dependency_type_identifier, + dependency_type_object)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_SERIALIZATION, + "Error getting TypeObject of dependency " << "for type " << type_name); + return false; + } + + dependency_name = type_name + "_" + std::to_string(dependency_index); + + // Store dependency in dynamic_types collection + serialize_dynamic_type(dependency_type_identifier, dependency_type_object, dependency_name, dynamic_types); + + // Increment suffix counter + dependency_index++; + } + + TypeObject type_object; + if (fastdds::dds::RETCODE_OK != + fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_object( + type_identifier, + type_object)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_SERIALIZATION, "Error getting TypeObject for type " << type_name); + return false; + } + + // Store dynamic type in dynamic_types collection + return serialize_dynamic_type(type_identifier, type_object, type_name, dynamic_types); +} + +bool serialize_dynamic_type( + const TypeIdentifier& type_identifier, + const TypeObject& type_object, + const std::string& type_name, + DynamicTypesCollection& dynamic_types) +{ + DynamicType dynamic_type; + dynamic_type.type_name(type_name); + + try + { + dynamic_type.type_identifier(utils::base64_encode(serialize_type_identifier(type_identifier))); + dynamic_type.type_object(utils::base64_encode(serialize_type_object(type_object))); + } + catch (const utils::InconsistencyException& e) + { + EPROSIMA_LOG_ERROR(DDSENABLER_SERIALIZATION, "Error serializing DynamicType. Error message:\n " << e.what()); + return false; + } + + dynamic_types.dynamic_types().push_back(dynamic_type); + + return true; + +} + +bool deserialize_dynamic_type( + const DynamicType& dynamic_type, + std::string& type_name, + TypeIdentifier& type_identifier, + TypeObject& type_object) +{ + std::string typeid_str = utils::base64_decode(dynamic_type.type_identifier()); + std::string typeobj_str = utils::base64_decode(dynamic_type.type_object()); + + try + { + // Deserialize type identifer and object strings + type_identifier = deserialize_type_identifier(typeid_str); + type_object = deserialize_type_object(typeobj_str); + } + catch (const utils::InconsistencyException& e) + { + EPROSIMA_LOG_ERROR(DDSENABLER_SERIALIZATION, + "Failed to deserialize " << dynamic_type.type_name() << " DynamicType: " << e.what()); + return false; + } + + type_name = dynamic_type.type_name(); + return true; +} + +template +std::string serialize_type_data( + const DynamicTypeData& type_data) +{ + // Reserve payload and create buffer + fastcdr::CdrSizeCalculator calculator(fastcdr::CdrVersion::XCDRv2); + size_t current_alignment {0}; + size_t size = calculator.calculate_serialized_size(type_data, current_alignment) + + fastdds::rtps::SerializedPayload_t::representation_header_size; + + fastdds::rtps::SerializedPayload_t payload(static_cast(size)); + fastcdr::FastBuffer fastbuffer((char*) payload.data, payload.max_size); + + // Create CDR serializer + fastcdr::Cdr ser(fastbuffer, fastcdr::Cdr::DEFAULT_ENDIAN, + fastcdr::CdrVersion::XCDRv2); + + payload.encapsulation = ser.endianness() == fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + + // Serialize + fastcdr::serialize(ser, type_data); + payload.length = (uint32_t)ser.get_serialized_data_length(); + size = (ser.get_serialized_data_length() + 3) & ~3; + + // Create CDR message with payload + std::unique_ptr cdr_message = std::make_unique(payload); + + // Add data + if (!(cdr_message && (cdr_message->pos + payload.length <= cdr_message->max_size)) || + (payload.length > 0 && !payload.data)) + { + if (!cdr_message) + { + throw utils::InconsistencyException( + "Error adding data -> cdr_message is null."); + } + else if (cdr_message->pos + payload.length > cdr_message->max_size) + { + throw utils::InconsistencyException( + "Error adding data -> not enough space in cdr_message buffer."); + } + else if (payload.length > 0 && !payload.data) + { + throw utils::InconsistencyException( + "Error adding data -> payload length is greater than 0, but payload data is null."); + } + } + + memcpy(&cdr_message->buffer[cdr_message->pos], payload.data, payload.length); + cdr_message->pos += payload.length; + cdr_message->length += payload.length; + + fastdds::rtps::octet value = 0; + for (uint32_t count = payload.length; count < size; ++count) + { + const uint32_t size_octet = sizeof(value); + if (!(cdr_message && (cdr_message->pos + size_octet <= cdr_message->max_size))) + { + throw utils::InconsistencyException( + "Not enough space in cdr_message buffer."); + } + for (uint32_t i = 0; i < size_octet; i++) + { + cdr_message->buffer[cdr_message->pos + i] = *((fastdds::rtps::octet*)&value + size_octet - 1 - i); + } + cdr_message->pos += size_octet; + cdr_message->length += size_octet; + } + + // Copy buffer to string + std::string typedata_str(reinterpret_cast(cdr_message->buffer), size); + + return typedata_str; +} + +template +DynamicTypeData deserialize_type_data( + const std::string& typedata_str) +{ + // Create CDR message from string + // NOTE: Use 0 length to avoid allocation + fastdds::rtps::CDRMessage_t* cdr_message = new fastdds::rtps::CDRMessage_t(0); + cdr_message->buffer = (unsigned char*)reinterpret_cast(typedata_str.c_str()); + cdr_message->length = typedata_str.length(); +#if __BIG_ENDIAN__ + cdr_message->msg_endian = fastdds::rtps::BIGEND; +#else + cdr_message->msg_endian = fastdds::rtps::LITTLEEND; +#endif // if __BIG_ENDIAN__ + + // Reserve payload and create buffer + const auto parameter_length = cdr_message->length; + fastdds::rtps::SerializedPayload_t payload(parameter_length); + fastcdr::FastBuffer fastbuffer((char*)payload.data, parameter_length); + + // Check cdr message is valid + if (!cdr_message) + { + throw utils::InconsistencyException( + "Error reading data -> cdr_message is null."); + } + + // Check enough space in buffer + if (!(cdr_message->length >= cdr_message->pos + parameter_length)) + { + throw utils::InconsistencyException( + "Error reading data -> not enough space in cdr_message buffer."); + } + + // Check length is consistent + if (!(parameter_length > 0)) + { + throw utils::InconsistencyException( + "Error reading data -> payload length is greater than 0."); + } + + // Check payload is valid + if (!payload.data) + { + throw utils::InconsistencyException( + "Error reading data -> payload data is null."); + } + + // Copy data + memcpy(payload.data, &cdr_message->buffer[cdr_message->pos], parameter_length); + cdr_message->pos += parameter_length; + + // Create CDR deserializer + fastcdr::Cdr deser(fastbuffer, fastcdr::Cdr::DEFAULT_ENDIAN, fastcdr::CdrVersion::XCDRv2); + payload.encapsulation = deser.endianness() == fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + + // Deserialize + DynamicTypeData type_data; + fastcdr::deserialize(deser, type_data); + + // Delete CDR message + // NOTE: set wraps attribute to avoid double free (buffer released by string on destruction) + cdr_message->wraps = true; + delete cdr_message; + + return type_data; +} + +std::string serialize_type_identifier( + const TypeIdentifier& type_identifier) +{ + std::string typeid_string; + try + { + typeid_string = serialize_type_data(type_identifier); + } + catch (const utils::InconsistencyException& e) + { + throw utils::InconsistencyException(std::string("Failed to serialize TypeIdentifier: ") + e.what()); + } + + return typeid_string; +} + +TypeIdentifier deserialize_type_identifier( + const std::string& typeid_str) +{ + TypeIdentifier type_id; + try + { + type_id = deserialize_type_data(typeid_str); + } + catch (const utils::InconsistencyException& e) + { + throw utils::InconsistencyException(std::string("Failed to deserialize TypeIdentifier: ") + e.what()); + } + + return type_id; +} + +std::string serialize_type_object( + const TypeObject& type_object) +{ + std::string typeobj_string; + try + { + typeobj_string = serialize_type_data(type_object); + } + catch (const utils::InconsistencyException& e) + { + throw utils::InconsistencyException(std::string("Failed to serialize TypeObject: ") + e.what()); + } + + return typeobj_string; +} + +TypeObject deserialize_type_object( + const std::string& typeobj_str) +{ + TypeObject type_obj; + try + { + type_obj = deserialize_type_data(typeobj_str); + } + catch (const utils::InconsistencyException& e) + { + throw utils::InconsistencyException(std::string("Failed to deserialize TypeObject: ") + e.what()); + } + + return type_obj; +} + +std::unique_ptr serialize_dynamic_types( + const DynamicTypesCollection& dynamic_types) +{ + // Serialize dynamic types collection using CDR + fastdds::dds::TypeSupport type_support(new DynamicTypesCollectionPubSubType()); + auto serialized_payload = std::make_unique( + type_support.calculate_serialized_size(&dynamic_types, fastdds::dds::DEFAULT_DATA_REPRESENTATION)); + if (!type_support.serialize(&dynamic_types, *serialized_payload, fastdds::dds::DEFAULT_DATA_REPRESENTATION)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_SERIALIZATION, + "Failed to serialize dynamic types collection."); + return nullptr; + } + + return serialized_payload; +} + +bool deserialize_dynamic_types( + const unsigned char* dynamic_types_payload, + uint32_t dynamic_types_payload_size, + DynamicTypesCollection& dynamic_types) +{ + fastdds::dds::TypeSupport type_support(new DynamicTypesCollectionPubSubType()); + fastdds::rtps::SerializedPayload_t serialized_payload = fastdds::rtps::SerializedPayload_t( + dynamic_types_payload_size); + serialized_payload.length = dynamic_types_payload_size; + std::memcpy( + serialized_payload.data, + dynamic_types_payload, + dynamic_types_payload_size); + + if (!type_support.deserialize(serialized_payload, &dynamic_types)) + { + EPROSIMA_LOG_ERROR(DDSENABLER_SERIALIZATION, + "Failed to deserialize dynamic types collection."); + return false; + } + + return true; +} + +} /* namespace serialization */ +} /* namespace participants */ +} /* namespace ddsenabler */ +} /* namespace eprosima */ diff --git a/ddsenabler_participants/src/cpp/types/dynamic_types_collection/DynamicTypesCollectionCdrAux.hpp b/ddsenabler_participants/src/cpp/types/dynamic_types_collection/DynamicTypesCollectionCdrAux.hpp new file mode 100644 index 00000000..2310cf91 --- /dev/null +++ b/ddsenabler_participants/src/cpp/types/dynamic_types_collection/DynamicTypesCollectionCdrAux.hpp @@ -0,0 +1,53 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DynamicTypesCollectionCdrAux.hpp + * This source file contains some definitions of CDR related functions. + * + * This file was generated by the tool fastddsgen. + */ + +#ifndef FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTIONCDRAUX_HPP +#define FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTIONCDRAUX_HPP + +#include + +constexpr uint32_t eprosima_ddsenabler_participants_DynamicType_max_cdr_typesize {784UL}; +constexpr uint32_t eprosima_ddsenabler_participants_DynamicType_max_key_cdr_typesize {0UL}; + +constexpr uint32_t eprosima_ddsenabler_participants_DynamicTypesCollection_max_cdr_typesize {12UL}; +constexpr uint32_t eprosima_ddsenabler_participants_DynamicTypesCollection_max_key_cdr_typesize {0UL}; + + +namespace eprosima { +namespace fastcdr { + +class Cdr; +class CdrSizeCalculator; + +eProsima_user_DllExport void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const eprosima::ddsenabler::participants::DynamicType& data); + +eProsima_user_DllExport void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const eprosima::ddsenabler::participants::DynamicTypesCollection& data); + + +} // namespace fastcdr +} // namespace eprosima + +#endif // FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTIONCDRAUX_HPP + diff --git a/ddsenabler_participants/src/cpp/types/dynamic_types_collection/DynamicTypesCollectionCdrAux.ipp b/ddsenabler_participants/src/cpp/types/dynamic_types_collection/DynamicTypesCollectionCdrAux.ipp new file mode 100644 index 00000000..e86fbd57 --- /dev/null +++ b/ddsenabler_participants/src/cpp/types/dynamic_types_collection/DynamicTypesCollectionCdrAux.ipp @@ -0,0 +1,234 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DynamicTypesCollectionCdrAux.ipp + * This source file contains some declarations of CDR related functions. + * + * This file was generated by the tool fastddsgen. + */ + +#ifndef FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTIONCDRAUX_IPP +#define FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTIONCDRAUX_IPP + +#include "DynamicTypesCollectionCdrAux.hpp" + +#include +#include + + +#include +using namespace eprosima::fastcdr::exception; + +namespace eprosima { +namespace fastcdr { + +template<> +eProsima_user_DllExport size_t calculate_serialized_size( + eprosima::fastcdr::CdrSizeCalculator& calculator, + const eprosima::ddsenabler::participants::DynamicType& data, + size_t& current_alignment) +{ + using namespace eprosima::ddsenabler::participants; + + static_cast(data); + + eprosima::fastcdr::EncodingAlgorithmFlag previous_encoding = calculator.get_encoding(); + size_t calculated_size {calculator.begin_calculate_type_serialized_size( + eprosima::fastcdr::CdrVersion::XCDRv2 == calculator.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + current_alignment)}; + + + calculated_size += calculator.calculate_member_serialized_size(eprosima::fastcdr::MemberId(0), + data.type_name(), current_alignment); + + calculated_size += calculator.calculate_member_serialized_size(eprosima::fastcdr::MemberId(1), + data.type_identifier(), current_alignment); + + calculated_size += calculator.calculate_member_serialized_size(eprosima::fastcdr::MemberId(2), + data.type_object(), current_alignment); + + + calculated_size += calculator.end_calculate_type_serialized_size(previous_encoding, current_alignment); + + return calculated_size; +} + +template<> +eProsima_user_DllExport void serialize( + eprosima::fastcdr::Cdr& scdr, + const eprosima::ddsenabler::participants::DynamicType& data) +{ + using namespace eprosima::ddsenabler::participants; + + eprosima::fastcdr::Cdr::state current_state(scdr); + scdr.begin_serialize_type(current_state, + eprosima::fastcdr::CdrVersion::XCDRv2 == scdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR); + + scdr + << eprosima::fastcdr::MemberId(0) << data.type_name() + << eprosima::fastcdr::MemberId(1) << data.type_identifier() + << eprosima::fastcdr::MemberId(2) << data.type_object() +; + scdr.end_serialize_type(current_state); +} + +template<> +eProsima_user_DllExport void deserialize( + eprosima::fastcdr::Cdr& cdr, + eprosima::ddsenabler::participants::DynamicType& data) +{ + using namespace eprosima::ddsenabler::participants; + + cdr.deserialize_type(eprosima::fastcdr::CdrVersion::XCDRv2 == cdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + [&data](eprosima::fastcdr::Cdr& dcdr, const eprosima::fastcdr::MemberId& mid) -> bool + { + bool ret_value = true; + switch (mid.id) + { + case 0: + dcdr >> data.type_name(); + break; + + case 1: + dcdr >> data.type_identifier(); + break; + + case 2: + dcdr >> data.type_object(); + break; + + default: + ret_value = false; + break; + } + return ret_value; + }); +} + +void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const eprosima::ddsenabler::participants::DynamicType& data) +{ + using namespace eprosima::ddsenabler::participants; + + static_cast(scdr); + static_cast(data); + scdr << data.type_name(); + + scdr << data.type_identifier(); + + scdr << data.type_object(); + +} + + +template<> +eProsima_user_DllExport size_t calculate_serialized_size( + eprosima::fastcdr::CdrSizeCalculator& calculator, + const eprosima::ddsenabler::participants::DynamicTypesCollection& data, + size_t& current_alignment) +{ + using namespace eprosima::ddsenabler::participants; + + static_cast(data); + + eprosima::fastcdr::EncodingAlgorithmFlag previous_encoding = calculator.get_encoding(); + size_t calculated_size {calculator.begin_calculate_type_serialized_size( + eprosima::fastcdr::CdrVersion::XCDRv2 == calculator.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + current_alignment)}; + + + calculated_size += calculator.calculate_member_serialized_size(eprosima::fastcdr::MemberId(0), + data.dynamic_types(), current_alignment); + + + calculated_size += calculator.end_calculate_type_serialized_size(previous_encoding, current_alignment); + + return calculated_size; +} + +template<> +eProsima_user_DllExport void serialize( + eprosima::fastcdr::Cdr& scdr, + const eprosima::ddsenabler::participants::DynamicTypesCollection& data) +{ + using namespace eprosima::ddsenabler::participants; + + eprosima::fastcdr::Cdr::state current_state(scdr); + scdr.begin_serialize_type(current_state, + eprosima::fastcdr::CdrVersion::XCDRv2 == scdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR); + + scdr + << eprosima::fastcdr::MemberId(0) << data.dynamic_types() +; + scdr.end_serialize_type(current_state); +} + +template<> +eProsima_user_DllExport void deserialize( + eprosima::fastcdr::Cdr& cdr, + eprosima::ddsenabler::participants::DynamicTypesCollection& data) +{ + using namespace eprosima::ddsenabler::participants; + + cdr.deserialize_type(eprosima::fastcdr::CdrVersion::XCDRv2 == cdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + [&data](eprosima::fastcdr::Cdr& dcdr, const eprosima::fastcdr::MemberId& mid) -> bool + { + bool ret_value = true; + switch (mid.id) + { + case 0: + dcdr >> data.dynamic_types(); + break; + + default: + ret_value = false; + break; + } + return ret_value; + }); +} + +void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const eprosima::ddsenabler::participants::DynamicTypesCollection& data) +{ + using namespace eprosima::ddsenabler::participants; + + static_cast(scdr); + static_cast(data); + scdr << data.dynamic_types(); + +} + + + +} // namespace fastcdr +} // namespace eprosima + +#endif // FAST_DDS_GENERATED__EPROSIMA_DDSENABLER_PARTICIPANTS_DYNAMICTYPESCOLLECTIONCDRAUX_IPP + diff --git a/ddsenabler_participants/src/cpp/types/dynamic_types_collection/DynamicTypesCollectionPubSubTypes.cxx b/ddsenabler_participants/src/cpp/types/dynamic_types_collection/DynamicTypesCollectionPubSubTypes.cxx new file mode 100644 index 00000000..67b19fdc --- /dev/null +++ b/ddsenabler_participants/src/cpp/types/dynamic_types_collection/DynamicTypesCollectionPubSubTypes.cxx @@ -0,0 +1,409 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DynamicTypesCollectionPubSubTypes.cpp + * This header file contains the implementation of the serialization functions. + * + * This file was generated by the tool fastddsgen. + */ + +#include + +#include +#include + +#include "DynamicTypesCollectionCdrAux.hpp" +#include + +using SerializedPayload_t = eprosima::fastdds::rtps::SerializedPayload_t; +using InstanceHandle_t = eprosima::fastdds::rtps::InstanceHandle_t; +using DataRepresentationId_t = eprosima::fastdds::dds::DataRepresentationId_t; + +namespace eprosima { + namespace ddsenabler { + namespace participants { + DynamicTypePubSubType::DynamicTypePubSubType() + { + set_name("eprosima::ddsenabler::participants::DynamicType"); + uint32_t type_size = eprosima_ddsenabler_participants_DynamicType_max_cdr_typesize; + type_size += static_cast(eprosima::fastcdr::Cdr::alignment(type_size, 4)); /* possible submessage alignment */ + max_serialized_type_size = type_size + 4; /*encapsulation*/ + is_compute_key_provided = false; + uint32_t key_length = eprosima_ddsenabler_participants_DynamicType_max_key_cdr_typesize > 16 ? eprosima_ddsenabler_participants_DynamicType_max_key_cdr_typesize : 16; + key_buffer_ = reinterpret_cast(malloc(key_length)); + memset(key_buffer_, 0, key_length); + } + + DynamicTypePubSubType::~DynamicTypePubSubType() + { + if (key_buffer_ != nullptr) + { + free(key_buffer_); + } + } + + bool DynamicTypePubSubType::serialize( + const void* const data, + SerializedPayload_t& payload, + DataRepresentationId_t data_representation) + { + const DynamicType* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload.data), payload.max_size); + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN, + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 : eprosima::fastcdr::CdrVersion::XCDRv2); + payload.encapsulation = ser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + ser.set_encoding_flag( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR : + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2); + + try + { + // Serialize encapsulation + ser.serialize_encapsulation(); + // Serialize the object. + ser << *p_type; + ser.set_dds_cdr_options({0,0}); + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + // Get the serialized length + payload.length = static_cast(ser.get_serialized_data_length()); + return true; + } + + bool DynamicTypePubSubType::deserialize( + SerializedPayload_t& payload, + void* data) + { + try + { + // Convert DATA to pointer of your type + DynamicType* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload.data), payload.length); + + // Object that deserializes the data. + eprosima::fastcdr::Cdr deser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN); + + // Deserialize encapsulation. + deser.read_encapsulation(); + payload.encapsulation = deser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + + // Deserialize the object. + deser >> *p_type; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + return true; + } + + uint32_t DynamicTypePubSubType::calculate_serialized_size( + const void* const data, + DataRepresentationId_t data_representation) + { + try + { + eprosima::fastcdr::CdrSizeCalculator calculator( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 :eprosima::fastcdr::CdrVersion::XCDRv2); + size_t current_alignment {0}; + return static_cast(calculator.calculate_serialized_size( + *static_cast(data), current_alignment)) + + 4u /*encapsulation*/; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return 0; + } + } + + void* DynamicTypePubSubType::create_data() + { + return reinterpret_cast(new DynamicType()); + } + + void DynamicTypePubSubType::delete_data( + void* data) + { + delete(reinterpret_cast(data)); + } + + bool DynamicTypePubSubType::compute_key( + SerializedPayload_t& payload, + InstanceHandle_t& handle, + bool force_md5) + { + if (!is_compute_key_provided) + { + return false; + } + + DynamicType data; + if (deserialize(payload, static_cast(&data))) + { + return compute_key(static_cast(&data), handle, force_md5); + } + + return false; + } + + bool DynamicTypePubSubType::compute_key( + const void* const data, + InstanceHandle_t& handle, + bool force_md5) + { + if (!is_compute_key_provided) + { + return false; + } + + const DynamicType* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(key_buffer_), + eprosima_ddsenabler_participants_DynamicType_max_key_cdr_typesize); + + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::BIG_ENDIANNESS, eprosima::fastcdr::CdrVersion::XCDRv2); + ser.set_encoding_flag(eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR2); + eprosima::fastcdr::serialize_key(ser, *p_type); + if (force_md5 || eprosima_ddsenabler_participants_DynamicType_max_key_cdr_typesize > 16) + { + md5_.init(); + md5_.update(key_buffer_, static_cast(ser.get_serialized_data_length())); + md5_.finalize(); + for (uint8_t i = 0; i < 16; ++i) + { + handle.value[i] = md5_.digest[i]; + } + } + else + { + for (uint8_t i = 0; i < 16; ++i) + { + handle.value[i] = key_buffer_[i]; + } + } + return true; + } + + void DynamicTypePubSubType::register_type_object_representation() + { + register_DynamicType_type_identifier(type_identifiers_); + } + + DynamicTypesCollectionPubSubType::DynamicTypesCollectionPubSubType() + { + set_name("eprosima::ddsenabler::participants::DynamicTypesCollection"); + uint32_t type_size = eprosima_ddsenabler_participants_DynamicTypesCollection_max_cdr_typesize; + type_size += static_cast(eprosima::fastcdr::Cdr::alignment(type_size, 4)); /* possible submessage alignment */ + max_serialized_type_size = type_size + 4; /*encapsulation*/ + is_compute_key_provided = false; + uint32_t key_length = eprosima_ddsenabler_participants_DynamicTypesCollection_max_key_cdr_typesize > 16 ? eprosima_ddsenabler_participants_DynamicTypesCollection_max_key_cdr_typesize : 16; + key_buffer_ = reinterpret_cast(malloc(key_length)); + memset(key_buffer_, 0, key_length); + } + + DynamicTypesCollectionPubSubType::~DynamicTypesCollectionPubSubType() + { + if (key_buffer_ != nullptr) + { + free(key_buffer_); + } + } + + bool DynamicTypesCollectionPubSubType::serialize( + const void* const data, + SerializedPayload_t& payload, + DataRepresentationId_t data_representation) + { + const DynamicTypesCollection* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload.data), payload.max_size); + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN, + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 : eprosima::fastcdr::CdrVersion::XCDRv2); + payload.encapsulation = ser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + ser.set_encoding_flag( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR : + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2); + + try + { + // Serialize encapsulation + ser.serialize_encapsulation(); + // Serialize the object. + ser << *p_type; + ser.set_dds_cdr_options({0,0}); + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + // Get the serialized length + payload.length = static_cast(ser.get_serialized_data_length()); + return true; + } + + bool DynamicTypesCollectionPubSubType::deserialize( + SerializedPayload_t& payload, + void* data) + { + try + { + // Convert DATA to pointer of your type + DynamicTypesCollection* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload.data), payload.length); + + // Object that deserializes the data. + eprosima::fastcdr::Cdr deser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN); + + // Deserialize encapsulation. + deser.read_encapsulation(); + payload.encapsulation = deser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + + // Deserialize the object. + deser >> *p_type; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + return true; + } + + uint32_t DynamicTypesCollectionPubSubType::calculate_serialized_size( + const void* const data, + DataRepresentationId_t data_representation) + { + try + { + eprosima::fastcdr::CdrSizeCalculator calculator( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 :eprosima::fastcdr::CdrVersion::XCDRv2); + size_t current_alignment {0}; + return static_cast(calculator.calculate_serialized_size( + *static_cast(data), current_alignment)) + + 4u /*encapsulation*/; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return 0; + } + } + + void* DynamicTypesCollectionPubSubType::create_data() + { + return reinterpret_cast(new DynamicTypesCollection()); + } + + void DynamicTypesCollectionPubSubType::delete_data( + void* data) + { + delete(reinterpret_cast(data)); + } + + bool DynamicTypesCollectionPubSubType::compute_key( + SerializedPayload_t& payload, + InstanceHandle_t& handle, + bool force_md5) + { + if (!is_compute_key_provided) + { + return false; + } + + DynamicTypesCollection data; + if (deserialize(payload, static_cast(&data))) + { + return compute_key(static_cast(&data), handle, force_md5); + } + + return false; + } + + bool DynamicTypesCollectionPubSubType::compute_key( + const void* const data, + InstanceHandle_t& handle, + bool force_md5) + { + if (!is_compute_key_provided) + { + return false; + } + + const DynamicTypesCollection* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(key_buffer_), + eprosima_ddsenabler_participants_DynamicTypesCollection_max_key_cdr_typesize); + + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::BIG_ENDIANNESS, eprosima::fastcdr::CdrVersion::XCDRv2); + ser.set_encoding_flag(eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR2); + eprosima::fastcdr::serialize_key(ser, *p_type); + if (force_md5 || eprosima_ddsenabler_participants_DynamicTypesCollection_max_key_cdr_typesize > 16) + { + md5_.init(); + md5_.update(key_buffer_, static_cast(ser.get_serialized_data_length())); + md5_.finalize(); + for (uint8_t i = 0; i < 16; ++i) + { + handle.value[i] = md5_.digest[i]; + } + } + else + { + for (uint8_t i = 0; i < 16; ++i) + { + handle.value[i] = key_buffer_[i]; + } + } + return true; + } + + void DynamicTypesCollectionPubSubType::register_type_object_representation() + { + register_DynamicTypesCollection_type_identifier(type_identifiers_); + } + + } // namespace participants + + } // namespace ddsenabler + +} // namespace eprosima + + +// Include auxiliary functions like for serializing/deserializing. +#include "DynamicTypesCollectionCdrAux.ipp" diff --git a/ddsenabler_participants/src/cpp/types/dynamic_types_collection/DynamicTypesCollectionTypeObjectSupport.cxx b/ddsenabler_participants/src/cpp/types/dynamic_types_collection/DynamicTypesCollectionTypeObjectSupport.cxx new file mode 100644 index 00000000..4fb5c82e --- /dev/null +++ b/ddsenabler_participants/src/cpp/types/dynamic_types_collection/DynamicTypesCollectionTypeObjectSupport.cxx @@ -0,0 +1,282 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DynamicTypesCollectionTypeObjectSupport.cxx + * Source file containing the implementation to register the TypeObject representation of the described types in the IDL file + * + * This file was generated by the tool fastddsgen. + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +using namespace eprosima::fastdds::dds::xtypes; + +namespace eprosima { +namespace ddsenabler { +namespace participants { +// TypeIdentifier is returned by reference: dependent structures/unions are registered in this same method +void register_DynamicType_type_identifier( + TypeIdentifierPair& type_ids_DynamicType) +{ + + ReturnCode_t return_code_DynamicType {eprosima::fastdds::dds::RETCODE_OK}; + return_code_DynamicType = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "eprosima::ddsenabler::participants::DynamicType", type_ids_DynamicType); + if (eprosima::fastdds::dds::RETCODE_OK != return_code_DynamicType) + { + StructTypeFlag struct_flags_DynamicType = TypeObjectUtils::build_struct_type_flag(eprosima::fastdds::dds::xtypes::ExtensibilityKind::APPENDABLE, + false, false); + QualifiedTypeName type_name_DynamicType = "eprosima::ddsenabler::participants::DynamicType"; + eprosima::fastcdr::optional type_ann_builtin_DynamicType; + eprosima::fastcdr::optional ann_custom_DynamicType; + CompleteTypeDetail detail_DynamicType = TypeObjectUtils::build_complete_type_detail(type_ann_builtin_DynamicType, ann_custom_DynamicType, type_name_DynamicType.to_string()); + CompleteStructHeader header_DynamicType; + header_DynamicType = TypeObjectUtils::build_complete_struct_header(TypeIdentifier(), detail_DynamicType); + CompleteStructMemberSeq member_seq_DynamicType; + { + TypeIdentifierPair type_ids_type_name; + ReturnCode_t return_code_type_name {eprosima::fastdds::dds::RETCODE_OK}; + return_code_type_name = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "anonymous_string_unbounded", type_ids_type_name); + + if (eprosima::fastdds::dds::RETCODE_OK != return_code_type_name) + { + { + SBound bound = 0; + StringSTypeDefn string_sdefn = TypeObjectUtils::build_string_s_type_defn(bound); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_s_string_type_identifier(string_sdefn, + "anonymous_string_unbounded", type_ids_type_name)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "anonymous_string_unbounded already registered in TypeObjectRegistry for a different type."); + } + } + } + StructMemberFlag member_flags_type_name = TypeObjectUtils::build_struct_member_flag(eprosima::fastdds::dds::xtypes::TryConstructFailAction::DISCARD, + false, false, false, false); + MemberId member_id_type_name = 0x00000000; + bool common_type_name_ec {false}; + CommonStructMember common_type_name {TypeObjectUtils::build_common_struct_member(member_id_type_name, member_flags_type_name, TypeObjectUtils::retrieve_complete_type_identifier(type_ids_type_name, common_type_name_ec))}; + if (!common_type_name_ec) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, "Structure type_name member TypeIdentifier inconsistent."); + return; + } + MemberName name_type_name = "type_name"; + eprosima::fastcdr::optional member_ann_builtin_type_name; + ann_custom_DynamicType.reset(); + CompleteMemberDetail detail_type_name = TypeObjectUtils::build_complete_member_detail(name_type_name, member_ann_builtin_type_name, ann_custom_DynamicType); + CompleteStructMember member_type_name = TypeObjectUtils::build_complete_struct_member(common_type_name, detail_type_name); + TypeObjectUtils::add_complete_struct_member(member_seq_DynamicType, member_type_name); + } + { + TypeIdentifierPair type_ids_type_identifier; + ReturnCode_t return_code_type_identifier {eprosima::fastdds::dds::RETCODE_OK}; + return_code_type_identifier = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "anonymous_string_unbounded", type_ids_type_identifier); + + if (eprosima::fastdds::dds::RETCODE_OK != return_code_type_identifier) + { + { + SBound bound = 0; + StringSTypeDefn string_sdefn = TypeObjectUtils::build_string_s_type_defn(bound); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_s_string_type_identifier(string_sdefn, + "anonymous_string_unbounded", type_ids_type_identifier)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "anonymous_string_unbounded already registered in TypeObjectRegistry for a different type."); + } + } + } + StructMemberFlag member_flags_type_identifier = TypeObjectUtils::build_struct_member_flag(eprosima::fastdds::dds::xtypes::TryConstructFailAction::DISCARD, + false, false, false, false); + MemberId member_id_type_identifier = 0x00000001; + bool common_type_identifier_ec {false}; + CommonStructMember common_type_identifier {TypeObjectUtils::build_common_struct_member(member_id_type_identifier, member_flags_type_identifier, TypeObjectUtils::retrieve_complete_type_identifier(type_ids_type_identifier, common_type_identifier_ec))}; + if (!common_type_identifier_ec) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, "Structure type_identifier member TypeIdentifier inconsistent."); + return; + } + MemberName name_type_identifier = "type_identifier"; + eprosima::fastcdr::optional member_ann_builtin_type_identifier; + ann_custom_DynamicType.reset(); + CompleteMemberDetail detail_type_identifier = TypeObjectUtils::build_complete_member_detail(name_type_identifier, member_ann_builtin_type_identifier, ann_custom_DynamicType); + CompleteStructMember member_type_identifier = TypeObjectUtils::build_complete_struct_member(common_type_identifier, detail_type_identifier); + TypeObjectUtils::add_complete_struct_member(member_seq_DynamicType, member_type_identifier); + } + { + TypeIdentifierPair type_ids_type_object; + ReturnCode_t return_code_type_object {eprosima::fastdds::dds::RETCODE_OK}; + return_code_type_object = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "anonymous_string_unbounded", type_ids_type_object); + + if (eprosima::fastdds::dds::RETCODE_OK != return_code_type_object) + { + { + SBound bound = 0; + StringSTypeDefn string_sdefn = TypeObjectUtils::build_string_s_type_defn(bound); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_s_string_type_identifier(string_sdefn, + "anonymous_string_unbounded", type_ids_type_object)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "anonymous_string_unbounded already registered in TypeObjectRegistry for a different type."); + } + } + } + StructMemberFlag member_flags_type_object = TypeObjectUtils::build_struct_member_flag(eprosima::fastdds::dds::xtypes::TryConstructFailAction::DISCARD, + false, false, false, false); + MemberId member_id_type_object = 0x00000002; + bool common_type_object_ec {false}; + CommonStructMember common_type_object {TypeObjectUtils::build_common_struct_member(member_id_type_object, member_flags_type_object, TypeObjectUtils::retrieve_complete_type_identifier(type_ids_type_object, common_type_object_ec))}; + if (!common_type_object_ec) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, "Structure type_object member TypeIdentifier inconsistent."); + return; + } + MemberName name_type_object = "type_object"; + eprosima::fastcdr::optional member_ann_builtin_type_object; + ann_custom_DynamicType.reset(); + CompleteMemberDetail detail_type_object = TypeObjectUtils::build_complete_member_detail(name_type_object, member_ann_builtin_type_object, ann_custom_DynamicType); + CompleteStructMember member_type_object = TypeObjectUtils::build_complete_struct_member(common_type_object, detail_type_object); + TypeObjectUtils::add_complete_struct_member(member_seq_DynamicType, member_type_object); + } + CompleteStructType struct_type_DynamicType = TypeObjectUtils::build_complete_struct_type(struct_flags_DynamicType, header_DynamicType, member_seq_DynamicType); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_struct_type_object(struct_type_DynamicType, type_name_DynamicType.to_string(), type_ids_DynamicType)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "eprosima::ddsenabler::participants::DynamicType already registered in TypeObjectRegistry for a different type."); + } + } +} +// TypeIdentifier is returned by reference: dependent structures/unions are registered in this same method +void register_DynamicTypesCollection_type_identifier( + TypeIdentifierPair& type_ids_DynamicTypesCollection) +{ + + ReturnCode_t return_code_DynamicTypesCollection {eprosima::fastdds::dds::RETCODE_OK}; + return_code_DynamicTypesCollection = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "eprosima::ddsenabler::participants::DynamicTypesCollection", type_ids_DynamicTypesCollection); + if (eprosima::fastdds::dds::RETCODE_OK != return_code_DynamicTypesCollection) + { + StructTypeFlag struct_flags_DynamicTypesCollection = TypeObjectUtils::build_struct_type_flag(eprosima::fastdds::dds::xtypes::ExtensibilityKind::APPENDABLE, + false, false); + QualifiedTypeName type_name_DynamicTypesCollection = "eprosima::ddsenabler::participants::DynamicTypesCollection"; + eprosima::fastcdr::optional type_ann_builtin_DynamicTypesCollection; + eprosima::fastcdr::optional ann_custom_DynamicTypesCollection; + CompleteTypeDetail detail_DynamicTypesCollection = TypeObjectUtils::build_complete_type_detail(type_ann_builtin_DynamicTypesCollection, ann_custom_DynamicTypesCollection, type_name_DynamicTypesCollection.to_string()); + CompleteStructHeader header_DynamicTypesCollection; + header_DynamicTypesCollection = TypeObjectUtils::build_complete_struct_header(TypeIdentifier(), detail_DynamicTypesCollection); + CompleteStructMemberSeq member_seq_DynamicTypesCollection; + { + TypeIdentifierPair type_ids_dynamic_types; + ReturnCode_t return_code_dynamic_types {eprosima::fastdds::dds::RETCODE_OK}; + return_code_dynamic_types = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded", type_ids_dynamic_types); + + if (eprosima::fastdds::dds::RETCODE_OK != return_code_dynamic_types) + { + return_code_dynamic_types = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "eprosima::ddsenabler::participants::DynamicType", type_ids_dynamic_types); + + if (eprosima::fastdds::dds::RETCODE_OK != return_code_dynamic_types) + { + eprosima::ddsenabler::participants::register_DynamicType_type_identifier(type_ids_dynamic_types); + } + bool element_identifier_anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded_ec {false}; + TypeIdentifier* element_identifier_anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded {new TypeIdentifier(TypeObjectUtils::retrieve_complete_type_identifier(type_ids_dynamic_types, element_identifier_anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded_ec))}; + if (!element_identifier_anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded_ec) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, "Sequence element TypeIdentifier inconsistent."); + return; + } + EquivalenceKind equiv_kind_anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded = EK_COMPLETE; + if (TK_NONE == type_ids_dynamic_types.type_identifier2()._d()) + { + equiv_kind_anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded = EK_BOTH; + } + CollectionElementFlag element_flags_anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded = 0; + PlainCollectionHeader header_anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded = TypeObjectUtils::build_plain_collection_header(equiv_kind_anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded, element_flags_anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded); + { + SBound bound = 0; + PlainSequenceSElemDefn seq_sdefn = TypeObjectUtils::build_plain_sequence_s_elem_defn(header_anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded, bound, + eprosima::fastcdr::external(element_identifier_anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded)); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_s_sequence_type_identifier(seq_sdefn, "anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded", type_ids_dynamic_types)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "anonymous_sequence_eprosima_ddsenabler_participants_DynamicType_unbounded already registered in TypeObjectRegistry for a different type."); + } + } + } + StructMemberFlag member_flags_dynamic_types = TypeObjectUtils::build_struct_member_flag(eprosima::fastdds::dds::xtypes::TryConstructFailAction::DISCARD, + false, false, false, false); + MemberId member_id_dynamic_types = 0x00000000; + bool common_dynamic_types_ec {false}; + CommonStructMember common_dynamic_types {TypeObjectUtils::build_common_struct_member(member_id_dynamic_types, member_flags_dynamic_types, TypeObjectUtils::retrieve_complete_type_identifier(type_ids_dynamic_types, common_dynamic_types_ec))}; + if (!common_dynamic_types_ec) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, "Structure dynamic_types member TypeIdentifier inconsistent."); + return; + } + MemberName name_dynamic_types = "dynamic_types"; + eprosima::fastcdr::optional member_ann_builtin_dynamic_types; + ann_custom_DynamicTypesCollection.reset(); + CompleteMemberDetail detail_dynamic_types = TypeObjectUtils::build_complete_member_detail(name_dynamic_types, member_ann_builtin_dynamic_types, ann_custom_DynamicTypesCollection); + CompleteStructMember member_dynamic_types = TypeObjectUtils::build_complete_struct_member(common_dynamic_types, detail_dynamic_types); + TypeObjectUtils::add_complete_struct_member(member_seq_DynamicTypesCollection, member_dynamic_types); + } + CompleteStructType struct_type_DynamicTypesCollection = TypeObjectUtils::build_complete_struct_type(struct_flags_DynamicTypesCollection, header_DynamicTypesCollection, member_seq_DynamicTypesCollection); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_struct_type_object(struct_type_DynamicTypesCollection, type_name_DynamicTypesCollection.to_string(), type_ids_DynamicTypesCollection)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "eprosima::ddsenabler::participants::DynamicTypesCollection already registered in TypeObjectRegistry for a different type."); + } + } +} + +} // namespace participants + +} // namespace ddsenabler + +} // namespace eprosima + diff --git a/ddsenabler_participants/test/CMakeLists.txt b/ddsenabler_participants/test/CMakeLists.txt index c3a720a7..598a9322 100644 --- a/ddsenabler_participants/test/CMakeLists.txt +++ b/ddsenabler_participants/test/CMakeLists.txt @@ -20,14 +20,16 @@ set(TEST_NAME DdsEnablerParticipantsTest) set(TEST_SOURCES ${PROJECT_SOURCE_DIR}/test/DdsEnablerParticipantsTest.cpp + ${PROJECT_SOURCE_DIR}/test/types/DDSEnablerTestTypesPubSubTypes.cxx + ${PROJECT_SOURCE_DIR}/test/types/DDSEnablerTestTypesTypeObjectSupport.cxx ) set(TEST_LIST ddsenabler_participants_cb_handler_creation ddsenabler_participants_add_new_schemas - ddsenabler_participants_add_same_type_id_schema - ddsenabler_participants_add_same_type_name_schema + ddsenabler_participants_add_same_type_schema ddsenabler_participants_add_data_with_schema + ddsenabler_participants_add_data_without_schema ddsenabler_participants_write_schema_first_time ddsenabler_participants_write_schema_repeated ) diff --git a/ddsenabler_participants/test/DdsEnablerParticipantsTest.cpp b/ddsenabler_participants/test/DdsEnablerParticipantsTest.cpp index c6a630b7..b2204c95 100644 --- a/ddsenabler_participants/test/DdsEnablerParticipantsTest.cpp +++ b/ddsenabler_participants/test/DdsEnablerParticipantsTest.cpp @@ -16,6 +16,9 @@ #include #include +#include +#include +#include #include #include #include @@ -33,23 +36,12 @@ #include #include +#include "types/DDSEnablerTestTypesPubSubTypes.hpp" + using namespace eprosima; using namespace eprosima::fastdds::dds; using namespace eprosima::ddsenabler; -DynamicType::_ref_type create_schema( - ddspipe::core::types::DdsTopic& topic) -{ - DynamicTypeBuilderFactory::_ref_type factory {DynamicTypeBuilderFactory::get_instance()}; - - TypeDescriptor::_ref_type type_descriptor {traits::make_shared()}; - type_descriptor->kind(TK_STRUCTURE); - type_descriptor->name(topic.type_name); - DynamicTypeBuilder::_ref_type type_builder {factory->create_type(type_descriptor)}; - - return type_builder->build(); -} - class CBWriterTest : public participants::CBWriter { public: @@ -60,21 +52,188 @@ class CBWriterTest : public participants::CBWriter // Expose protected methods using CBWriter::write_data; using CBWriter::write_schema; - using CBWriter::stored_schemas_; }; class CBHandlerTest : public participants::CBHandler { public: - // Inherit the constructor from CBHandler - using participants::CBHandler::CBHandler; + CBHandlerTest( + const participants::CBHandlerConfiguration& config, + const std::shared_ptr& payload_pool) + : participants::CBHandler(config, payload_pool) + { + current_test_instance_ = this; + + cb_writer_ = std::make_unique(); + + // Set the callbacks + set_data_notification_callback(test_data_notification_callback); + set_type_notification_callback(test_type_notification_callback); + set_topic_notification_callback(test_topic_notification_callback); + set_type_query_callback(test_type_query_callback); + } // Expose protected members using participants::CBHandler::schemas_; using participants::CBHandler::cb_writer_; + using participants::CBHandler::unique_sequence_number_; + + // eprosima::ddsenabler::participants::DdsTypeQuery type_query; + static bool test_type_query_callback( + const char* type_name, + std::unique_ptr& serialized_type_internal, + uint32_t& serialized_type_internal_size) + { + if (current_test_instance_ == nullptr) + { + return false; + } + + current_test_instance_->type_query_called++; + return true; + } + + // eprosima::ddsenabler::participants::DdsDataNotification data_notification; + static void test_data_notification_callback( + const char* topic_name, + const char* json, + int64_t publish_time) + { + if (current_test_instance_ == nullptr) + { + return; + } + + current_test_instance_->data_called_++; + } + + // eprosima::ddsenabler::participants::DdsTypeNotification type_notification; + static void test_type_notification_callback( + const char* type_name, + const char* serialized_type, + const unsigned char* serialized_type_internal, + uint32_t serialized_type_internal_size, + const char* data_placeholder) + { + if (current_test_instance_ == nullptr) + { + return; + } + + current_test_instance_->type_called_++; + } + + // eprosima::ddsenabler::participants::DdsTopicNotification topic_notification; + static void test_topic_notification_callback( + const char* topic_name, + const char* type_name, + const char* serialized_qos) + { + if (current_test_instance_ == nullptr) + { + return; + } + + current_test_instance_->topic_called_++; + } + + uint32_t type_query_called = 0; + uint32_t data_called_ = 0; + uint32_t type_called_ = 0; + uint32_t topic_called_ = 0; + + + // Pointer to the current test instance (for use in the static callback) + static CBHandlerTest* current_test_instance_; }; +CBHandlerTest* CBHandlerTest::current_test_instance_ = nullptr; + +void get_dynamic_type( + int num_type, + DynamicType::_ref_type& dynamic_type, + xtypes::TypeIdentifier& type_identifier, + ddspipe::core::types::DdsTopic& pipe_topic) +{ + std::shared_ptr type_support; + switch (num_type) + { + case 3: + { + type_support.reset(new DDSEnablerTestType3PubSubType()); + break; + } + case 2: + { + type_support.reset(new DDSEnablerTestType2PubSubType()); + break; + } + case 1: + default: + { + type_support.reset(new DDSEnablerTestType1PubSubType()); + break; + } + } + type_support->register_type_object_representation(); + auto type_id_pair = type_support->type_identifiers(); + + type_identifier = + (fastdds::dds::xtypes::EK_COMPLETE == + type_id_pair.type_identifier1()._d()) ? type_id_pair.type_identifier1() : type_id_pair.type_identifier2(); + + xtypes::TypeObject type_obj; + ASSERT_EQ(RETCODE_OK, + DomainParticipantFactory::get_instance()->type_object_registry().get_type_object(type_identifier, + type_obj)); + dynamic_type = DynamicTypeBuilderFactory::get_instance()->create_type_w_type_object(type_obj)->build(); + + std::ostringstream topic_name; + topic_name << type_support->get_name() << "_topic_name_" << std::to_string(num_type); + pipe_topic.m_topic_name = topic_name.str(); + pipe_topic.type_name = type_support->get_name(); + pipe_topic.type_identifiers = type_id_pair; +} + +void get_dynamic_type( + int num_type, + DynamicType::_ref_type& dynamic_type, + xtypes::TypeIdentifier& type_identifier) +{ + ddspipe::core::types::DdsTopic _; + get_dynamic_type(num_type, dynamic_type, type_identifier, _); +} + +void get_data_payload( + int num_type, + eprosima::ddspipe::core::types::Payload& payload) +{ + std::shared_ptr type_support; + switch (num_type) + { + case 3: + { + type_support.reset(new DDSEnablerTestType3PubSubType()); + break; + } + case 2: + { + type_support.reset(new DDSEnablerTestType2PubSubType()); + break; + } + case 1: + default: + { + type_support.reset(new DDSEnablerTestType1PubSubType()); + break; + } + } + void* data = type_support->create_data(); + ASSERT_TRUE(type_support->serialize(data, payload, DataRepresentationId::XCDR2_DATA_REPRESENTATION)); + type_support->delete_data(data); +} + TEST(DdsEnablerParticipantsTest, ddsenabler_participants_cb_handler_creation) { // Create Payload Pool @@ -103,49 +262,32 @@ TEST(DdsEnablerParticipantsTest, ddsenabler_participants_add_new_schemas) auto cb_handler_ = std::make_shared(handler_config, payload_pool_); ASSERT_NE(cb_handler_, nullptr); - // Replace CBWriter with test version - std::unique_ptr cb_writer_test = std::make_unique(); - ASSERT_NE(cb_writer_test, nullptr); - cb_handler_->cb_writer_ = std::move(cb_writer_test); - - ddspipe::core::types::DdsTopic topic; - topic.m_topic_name = "topic1"; - topic.type_name = "type1"; + // Add a new schema xtypes::TypeIdentifier type_id; - xtypes::EquivalenceHash hash = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - type_id.equivalence_hash(hash); - topic.type_identifiers.type_identifier1(type_id); - DynamicType::_ref_type dynamic_type; - dynamic_type = create_schema(topic); - ASSERT_NE(dynamic_type, nullptr); + get_dynamic_type(1, dynamic_type, type_id); ASSERT_TRUE(cb_handler_->schemas_.empty()); ASSERT_EQ(cb_handler_->schemas_.size(), 0); cb_handler_->add_schema(dynamic_type, type_id); ASSERT_FALSE(cb_handler_->schemas_.empty()); ASSERT_EQ(cb_handler_->schemas_.size(), 1); + ASSERT_EQ(cb_handler_->type_called_, 1); - ddspipe::core::types::DdsTopic topic2; - topic2.m_topic_name = "topic2"; - topic2.type_name = "type2"; + // Add another schema for a different type xtypes::TypeIdentifier type_id2; - xtypes::EquivalenceHash hash2 = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; - type_id2.equivalence_hash(hash2); - topic2.type_identifiers.type_identifier1(type_id2); - DynamicType::_ref_type dynamic_type2; - dynamic_type2 = create_schema(topic2); - ASSERT_NE(dynamic_type2, nullptr); + get_dynamic_type(2, dynamic_type2, type_id2); ASSERT_FALSE(cb_handler_->schemas_.empty()); ASSERT_EQ(cb_handler_->schemas_.size(), 1); cb_handler_->add_schema(dynamic_type2, type_id2); ASSERT_FALSE(cb_handler_->schemas_.empty()); ASSERT_EQ(cb_handler_->schemas_.size(), 2); + ASSERT_EQ(cb_handler_->type_called_, 2); } -TEST(DdsEnablerParticipantsTest, ddsenabler_participants_add_same_type_id_schema) +TEST(DdsEnablerParticipantsTest, ddsenabler_participants_add_same_type_schema) { // Create Payload Pool auto payload_pool_ = std::make_shared(); @@ -158,48 +300,32 @@ TEST(DdsEnablerParticipantsTest, ddsenabler_participants_add_same_type_id_schema auto cb_handler_ = std::make_shared(handler_config, payload_pool_); ASSERT_NE(cb_handler_, nullptr); - // Replace CBWriter with test version - std::unique_ptr cb_writer_test = std::make_unique(); - ASSERT_NE(cb_writer_test, nullptr); - cb_handler_->cb_writer_ = std::move(cb_writer_test); - - ddspipe::core::types::DdsTopic topic; - topic.m_topic_name = "topic1"; - topic.type_name = "type1"; + // Add a new schema xtypes::TypeIdentifier type_id; - xtypes::EquivalenceHash hash = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - type_id.equivalence_hash(hash); - topic.type_identifiers.type_identifier1(type_id); - DynamicType::_ref_type dynamic_type; - dynamic_type = create_schema(topic); - ASSERT_NE(dynamic_type, nullptr); + get_dynamic_type(1, dynamic_type, type_id); ASSERT_TRUE(cb_handler_->schemas_.empty()); ASSERT_EQ(cb_handler_->schemas_.size(), 0); cb_handler_->add_schema(dynamic_type, type_id); ASSERT_FALSE(cb_handler_->schemas_.empty()); ASSERT_EQ(cb_handler_->schemas_.size(), 1); + ASSERT_EQ(cb_handler_->type_called_, 1); - ddspipe::core::types::DdsTopic topic2; - topic2.m_topic_name = "topic2"; - topic2.type_name = "type2"; + // Add the same schema again xtypes::TypeIdentifier type_id2; - type_id2.equivalence_hash(hash); - topic2.type_identifiers.type_identifier1(type_id2); - DynamicType::_ref_type dynamic_type2; - dynamic_type2 = create_schema(topic2); - ASSERT_NE(dynamic_type2, nullptr); + get_dynamic_type(1, dynamic_type2, type_id2); ASSERT_FALSE(cb_handler_->schemas_.empty()); ASSERT_EQ(cb_handler_->schemas_.size(), 1); cb_handler_->add_schema(dynamic_type2, type_id2); ASSERT_FALSE(cb_handler_->schemas_.empty()); ASSERT_EQ(cb_handler_->schemas_.size(), 1); + ASSERT_EQ(cb_handler_->type_called_, 1); } -TEST(DdsEnablerParticipantsTest, ddsenabler_participants_add_same_type_name_schema) +TEST(DdsEnablerParticipantsTest, ddsenabler_participants_add_data_with_schema) { // Create Payload Pool auto payload_pool_ = std::make_shared(); @@ -212,49 +338,31 @@ TEST(DdsEnablerParticipantsTest, ddsenabler_participants_add_same_type_name_sche auto cb_handler_ = std::make_shared(handler_config, payload_pool_); ASSERT_NE(cb_handler_, nullptr); - // Replace CBWriter with test version - std::unique_ptr cb_writer_test = std::make_unique(); - ASSERT_NE(cb_writer_test, nullptr); - cb_handler_->cb_writer_ = std::move(cb_writer_test); - - ddspipe::core::types::DdsTopic topic; - topic.m_topic_name = "topic1"; - topic.type_name = "type1"; - xtypes::TypeIdentifier type_id; - xtypes::EquivalenceHash hash = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - type_id.equivalence_hash(hash); - topic.type_identifiers.type_identifier1(type_id); - + xtypes::TypeIdentifier type_identifier; DynamicType::_ref_type dynamic_type; - dynamic_type = create_schema(topic); - ASSERT_NE(dynamic_type, nullptr); + ddspipe::core::types::DdsTopic pipe_topic; + get_dynamic_type(1, dynamic_type, type_identifier, pipe_topic); ASSERT_TRUE(cb_handler_->schemas_.empty()); ASSERT_EQ(cb_handler_->schemas_.size(), 0); - cb_handler_->add_schema(dynamic_type, type_id); + cb_handler_->add_schema(dynamic_type, type_identifier); ASSERT_FALSE(cb_handler_->schemas_.empty()); ASSERT_EQ(cb_handler_->schemas_.size(), 1); + ASSERT_EQ(cb_handler_->type_called_, 1); - ddspipe::core::types::DdsTopic topic2; - topic2.m_topic_name = "topic2"; - topic2.type_name = "type1"; - xtypes::TypeIdentifier type_id2; - xtypes::EquivalenceHash hash2 = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; - type_id2.equivalence_hash(hash2); - topic2.type_identifiers.type_identifier1(type_id2); + auto data = std::make_unique(); - DynamicType::_ref_type dynamic_type2; - dynamic_type2 = create_schema(topic2); - ASSERT_NE(dynamic_type2, nullptr); + payload_pool_->get_payload(1000, data->payload); + data->payload_owner = payload_pool_.get(); + get_data_payload(1, data->payload); - ASSERT_FALSE(cb_handler_->schemas_.empty()); - ASSERT_EQ(cb_handler_->schemas_.size(), 1); - cb_handler_->add_schema(dynamic_type2, type_id2); - ASSERT_FALSE(cb_handler_->schemas_.empty()); - ASSERT_EQ(cb_handler_->schemas_.size(), 2); + ASSERT_NO_THROW(cb_handler_->add_data(pipe_topic, *data)); + // If the data has been added, the sequence number should be 1 + ASSERT_TRUE(cb_handler_->unique_sequence_number_ == 1); + ASSERT_EQ(cb_handler_->data_called_, 1); } -TEST(DdsEnablerParticipantsTest, ddsenabler_participants_add_data_with_schema) +TEST(DdsEnablerParticipantsTest, ddsenabler_participants_add_data_without_schema) { // Create Payload Pool auto payload_pool_ = std::make_shared(); @@ -267,49 +375,21 @@ TEST(DdsEnablerParticipantsTest, ddsenabler_participants_add_data_with_schema) auto cb_handler_ = std::make_shared(handler_config, payload_pool_); ASSERT_NE(cb_handler_, nullptr); - // Replace CBWriter with test version - std::unique_ptr cb_writer_test = std::make_unique(); - ASSERT_NE(cb_writer_test, nullptr); - cb_handler_->cb_writer_ = std::move(cb_writer_test); - - ddspipe::core::types::DdsTopic topic; - topic.m_topic_name = "topic1"; - topic.type_name = "type1"; xtypes::TypeIdentifier type_id; - xtypes::EquivalenceHash hash = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - type_id.equivalence_hash(hash); - topic.type_identifiers.type_identifier1(type_id); - DynamicType::_ref_type dynamic_type; - dynamic_type = create_schema(topic); - ASSERT_NE(dynamic_type, nullptr); - - ASSERT_TRUE(cb_handler_->schemas_.empty()); - ASSERT_EQ(cb_handler_->schemas_.size(), 0); - cb_handler_->add_schema(dynamic_type, type_id); - ASSERT_FALSE(cb_handler_->schemas_.empty()); - ASSERT_EQ(cb_handler_->schemas_.size(), 1); + ddspipe::core::types::DdsTopic pipe_topic; + get_dynamic_type(1, dynamic_type, type_id, pipe_topic); auto data = std::make_unique(); - eprosima::ddspipe::core::types::Payload payload; - - std::string content = - "{\n" - " \"color\": \"RED\",\n" - " \"shapesize\": 30,\n" - " \"x\": 198,\n" - " \"y\": 189\n" - "}"; - - payload.length = static_cast(content.length()); - payload.max_size = static_cast(content.length()); - payload.data = (unsigned char*)reinterpret_cast(content.data()); - - payload_pool_->get_payload(payload, data->payload); - payload.data = nullptr; // Set to nullptr after copy to avoid free on destruction + + payload_pool_->get_payload(1000, data->payload); data->payload_owner = payload_pool_.get(); + get_data_payload(1, data->payload); - ASSERT_NO_THROW(cb_handler_->add_data(topic, *data)); + ASSERT_NO_THROW(cb_handler_->add_data(pipe_topic, *data)); + // As there is no schema associated, the sequence number should still be 0 + ASSERT_TRUE(cb_handler_->unique_sequence_number_ == 0); + ASSERT_EQ(cb_handler_->data_called_, 0); } TEST(DdsEnablerParticipantsTest, ddsenabler_participants_write_schema_first_time) @@ -318,158 +398,66 @@ TEST(DdsEnablerParticipantsTest, ddsenabler_participants_write_schema_first_time auto payload_pool_ = std::make_shared(); ASSERT_NE(payload_pool_, nullptr); - std::unique_ptr cb_writer_test = std::make_unique(); - ASSERT_NE(cb_writer_test, nullptr); + // Create CB Handler configuration + participants::CBHandlerConfiguration handler_config; - ddspipe::core::types::DdsTopic topic; - topic.m_topic_name = "topic1"; - topic.type_name = "type1"; - xtypes::TypeIdentifier type_id; - xtypes::EquivalenceHash hash = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - type_id.equivalence_hash(hash); - topic.type_identifiers.type_identifier1(type_id); + // Create CB Handler + auto cb_handler_ = std::make_shared(handler_config, payload_pool_); + ASSERT_NE(cb_handler_, nullptr); + xtypes::TypeIdentifier type_id; DynamicType::_ref_type dynamic_type; - dynamic_type = create_schema(topic); - ASSERT_NE(dynamic_type, nullptr); + ddspipe::core::types::DdsTopic pipe_topic; + get_dynamic_type(1, dynamic_type, type_id, pipe_topic); auto data = std::make_unique(); - eprosima::ddspipe::core::types::Payload payload; - - std::string content = - "{\n" - " \"color\": \"RED\",\n" - " \"shapesize\": 30,\n" - " \"x\": 198,\n" - " \"y\": 189\n" - "}"; - - payload.length = static_cast(content.length()); - payload.max_size = static_cast(content.length()); - payload.data = (unsigned char*)reinterpret_cast(content.data()); - - payload_pool_->get_payload(payload, data->payload); - payload.data = nullptr; // Set to nullptr after copy to avoid free on destruction + + payload_pool_->get_payload(1000, data->payload); data->payload_owner = payload_pool_.get(); + get_data_payload(1, data->payload); participants::CBMessage msg; msg.sequence_number = 1; msg.publish_time = data->source_timestamp; - msg.topic = topic; + msg.topic = pipe_topic; msg.instanceHandle = data->instanceHandle; msg.source_guid = data->source_guid; payload_pool_->get_payload(data->payload, msg.payload); msg.payload_owner = payload_pool_.get(); - ASSERT_TRUE(cb_writer_test->stored_schemas_.empty()); - ASSERT_EQ(cb_writer_test->stored_schemas_.size(), 0); - cb_writer_test->write_schema(msg, dynamic_type); - ASSERT_FALSE(cb_writer_test->stored_schemas_.empty()); - ASSERT_EQ(cb_writer_test->stored_schemas_.size(), 1); + cb_handler_->cb_writer_->write_data(msg, dynamic_type); + // The data will be successfully written as the dynamic type exists and we are bypassing the handler schema check + ASSERT_EQ(cb_handler_->data_called_, 1); - ddspipe::core::types::DdsTopic topic2; - topic2.m_topic_name = "topic2"; - topic2.type_name = "type2"; xtypes::TypeIdentifier type_id2; - xtypes::EquivalenceHash hash2 = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; - type_id2.equivalence_hash(hash2); - topic2.type_identifiers.type_identifier1(type_id2); - DynamicType::_ref_type dynamic_type2; - dynamic_type2 = create_schema(topic2); - ASSERT_NE(dynamic_type2, nullptr); + ddspipe::core::types::DdsTopic pipe_topic2; + get_dynamic_type(2, dynamic_type2, type_id2, pipe_topic2); auto data2 = std::make_unique(); - eprosima::ddspipe::core::types::Payload payload2; - payload2.length = static_cast(content.length()); - payload2.max_size = static_cast(content.length()); - payload2.data = (unsigned char*)reinterpret_cast(content.data()); - - payload_pool_->get_payload(payload2, data2->payload); - payload2.data = nullptr; // Set to nullptr after copy to avoid free on destruction + payload_pool_->get_payload(1000, data2->payload); data2->payload_owner = payload_pool_.get(); + get_data_payload(2, data2->payload); participants::CBMessage msg2; msg2.sequence_number = 1; msg2.publish_time = data2->source_timestamp; - msg2.topic = topic2; + msg2.topic = pipe_topic2; msg2.instanceHandle = data2->instanceHandle; msg2.source_guid = data2->source_guid; payload_pool_->get_payload(data2->payload, msg2.payload); msg2.payload_owner = payload_pool_.get(); - ASSERT_FALSE(cb_writer_test->stored_schemas_.empty()); - ASSERT_EQ(cb_writer_test->stored_schemas_.size(), 1); - cb_writer_test->write_schema(msg2, dynamic_type2); - ASSERT_FALSE(cb_writer_test->stored_schemas_.empty()); - ASSERT_EQ(cb_writer_test->stored_schemas_.size(), 2); -} - -TEST(DdsEnablerParticipantsTest, ddsenabler_participants_write_schema_repeated) -{ - // Create Payload Pool - auto payload_pool_ = std::make_shared(); - ASSERT_NE(payload_pool_, nullptr); - - std::unique_ptr cb_writer_test = std::make_unique(); - ASSERT_NE(cb_writer_test, nullptr); - - ddspipe::core::types::DdsTopic topic; - topic.m_topic_name = "topic1"; - topic.type_name = "type1"; - xtypes::TypeIdentifier type_id; - xtypes::EquivalenceHash hash = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - type_id.equivalence_hash(hash); - topic.type_identifiers.type_identifier1(type_id); - - DynamicType::_ref_type dynamic_type; - dynamic_type = create_schema(topic); - ASSERT_NE(dynamic_type, nullptr); - - auto data = std::make_unique(); - eprosima::ddspipe::core::types::Payload payload; - - std::string content = - "{\n" - " \"color\": \"RED\",\n" - " \"shapesize\": 30,\n" - " \"x\": 198,\n" - " \"y\": 189\n" - "}"; - - payload.length = static_cast(content.length()); - payload.max_size = static_cast(content.length()); - payload.data = (unsigned char*)reinterpret_cast(content.data()); - - payload_pool_->get_payload(payload, data->payload); - payload.data = nullptr; // Set to nullptr after copy to avoid free on destruction - data->payload_owner = payload_pool_.get(); - - participants::CBMessage msg; - msg.sequence_number = 1; - msg.publish_time = data->source_timestamp; - msg.topic = topic; - msg.instanceHandle = data->instanceHandle; - msg.source_guid = data->source_guid; - payload_pool_->get_payload(data->payload, msg.payload); - msg.payload_owner = payload_pool_.get(); - - ASSERT_TRUE(cb_writer_test->stored_schemas_.empty()); - ASSERT_EQ(cb_writer_test->stored_schemas_.size(), 0); - cb_writer_test->write_schema(msg, dynamic_type); - ASSERT_FALSE(cb_writer_test->stored_schemas_.empty()); - ASSERT_EQ(cb_writer_test->stored_schemas_.size(), 1); - - cb_writer_test->write_schema(msg, dynamic_type); - ASSERT_FALSE(cb_writer_test->stored_schemas_.empty()); - ASSERT_EQ(cb_writer_test->stored_schemas_.size(), 1); + cb_handler_->cb_writer_->write_data(msg2, dynamic_type2); + ASSERT_EQ(cb_handler_->data_called_, 2); } int main( int argc, char** argv) { + eprosima::fastdds::dds::Log::SetVerbosity(Log::Kind::Warning); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/ddsenabler_participants/test/types/DDSEnablerTestTypes.hpp b/ddsenabler_participants/test/types/DDSEnablerTestTypes.hpp new file mode 100644 index 00000000..840fc12b --- /dev/null +++ b/ddsenabler_participants/test/types/DDSEnablerTestTypes.hpp @@ -0,0 +1,580 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DDSEnablerTestTypes.hpp + * This header file contains the declaration of the described types in the IDL file. + * + * This file was generated by the tool fastddsgen. + */ + +#ifndef FAST_DDS_GENERATED__DDSENABLERTESTTYPES_HPP +#define FAST_DDS_GENERATED__DDSENABLERTESTTYPES_HPP + +#include +#include +#include +#include +#include + +#if defined(_WIN32) +#if defined(EPROSIMA_USER_DLL_EXPORT) +#define eProsima_user_DllExport __declspec( dllexport ) +#else +#define eProsima_user_DllExport +#endif // EPROSIMA_USER_DLL_EXPORT +#else +#define eProsima_user_DllExport +#endif // _WIN32 + +#if defined(_WIN32) +#if defined(EPROSIMA_USER_DLL_EXPORT) +#if defined(DDSENABLERTESTTYPES_SOURCE) +#define DDSENABLERTESTTYPES_DllAPI __declspec( dllexport ) +#else +#define DDSENABLERTESTTYPES_DllAPI __declspec( dllimport ) +#endif // DDSENABLERTESTTYPES_SOURCE +#else +#define DDSENABLERTESTTYPES_DllAPI +#endif // EPROSIMA_USER_DLL_EXPORT +#else +#define DDSENABLERTESTTYPES_DllAPI +#endif // _WIN32 + +/*! + * @brief This class represents the structure DDSEnablerTestType1 defined by the user in the IDL file. + * @ingroup DDSEnablerTestTypes + */ +class DDSEnablerTestType1 +{ +public: + + /*! + * @brief Default constructor. + */ + eProsima_user_DllExport DDSEnablerTestType1() + { + } + + /*! + * @brief Default destructor. + */ + eProsima_user_DllExport ~DDSEnablerTestType1() + { + } + + /*! + * @brief Copy constructor. + * @param x Reference to the object DDSEnablerTestType1 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType1( + const DDSEnablerTestType1& x) + { + m_value = x.m_value; + + } + + /*! + * @brief Move constructor. + * @param x Reference to the object DDSEnablerTestType1 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType1( + DDSEnablerTestType1&& x) noexcept + { + m_value = x.m_value; + } + + /*! + * @brief Copy assignment. + * @param x Reference to the object DDSEnablerTestType1 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType1& operator =( + const DDSEnablerTestType1& x) + { + + m_value = x.m_value; + + return *this; + } + + /*! + * @brief Move assignment. + * @param x Reference to the object DDSEnablerTestType1 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType1& operator =( + DDSEnablerTestType1&& x) noexcept + { + + m_value = x.m_value; + return *this; + } + + /*! + * @brief Comparison operator. + * @param x DDSEnablerTestType1 object to compare. + */ + eProsima_user_DllExport bool operator ==( + const DDSEnablerTestType1& x) const + { + return (m_value == x.m_value); + } + + /*! + * @brief Comparison operator. + * @param x DDSEnablerTestType1 object to compare. + */ + eProsima_user_DllExport bool operator !=( + const DDSEnablerTestType1& x) const + { + return !(*this == x); + } + + /*! + * @brief This function sets a value in member value + * @param _value New value for member value + */ + eProsima_user_DllExport void value( + int16_t _value) + { + m_value = _value; + } + + /*! + * @brief This function returns the value of member value + * @return Value of member value + */ + eProsima_user_DllExport int16_t value() const + { + return m_value; + } + + /*! + * @brief This function returns a reference to member value + * @return Reference to member value + */ + eProsima_user_DllExport int16_t& value() + { + return m_value; + } + + + +private: + + int16_t m_value{0}; + +}; +/*! + * @brief This class represents the structure DDSEnablerTestType2 defined by the user in the IDL file. + * @ingroup DDSEnablerTestTypes + */ +class DDSEnablerTestType2 +{ +public: + + /*! + * @brief Default constructor. + */ + eProsima_user_DllExport DDSEnablerTestType2() + { + } + + /*! + * @brief Default destructor. + */ + eProsima_user_DllExport ~DDSEnablerTestType2() + { + } + + /*! + * @brief Copy constructor. + * @param x Reference to the object DDSEnablerTestType2 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType2( + const DDSEnablerTestType2& x) + { + m_value = x.m_value; + + } + + /*! + * @brief Move constructor. + * @param x Reference to the object DDSEnablerTestType2 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType2( + DDSEnablerTestType2&& x) noexcept + { + m_value = std::move(x.m_value); + } + + /*! + * @brief Copy assignment. + * @param x Reference to the object DDSEnablerTestType2 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType2& operator =( + const DDSEnablerTestType2& x) + { + + m_value = x.m_value; + + return *this; + } + + /*! + * @brief Move assignment. + * @param x Reference to the object DDSEnablerTestType2 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType2& operator =( + DDSEnablerTestType2&& x) noexcept + { + + m_value = std::move(x.m_value); + return *this; + } + + /*! + * @brief Comparison operator. + * @param x DDSEnablerTestType2 object to compare. + */ + eProsima_user_DllExport bool operator ==( + const DDSEnablerTestType2& x) const + { + return (m_value == x.m_value); + } + + /*! + * @brief Comparison operator. + * @param x DDSEnablerTestType2 object to compare. + */ + eProsima_user_DllExport bool operator !=( + const DDSEnablerTestType2& x) const + { + return !(*this == x); + } + + /*! + * @brief This function copies the value in member value + * @param _value New value to be copied in member value + */ + eProsima_user_DllExport void value( + const std::string& _value) + { + m_value = _value; + } + + /*! + * @brief This function moves the value in member value + * @param _value New value to be moved in member value + */ + eProsima_user_DllExport void value( + std::string&& _value) + { + m_value = std::move(_value); + } + + /*! + * @brief This function returns a constant reference to member value + * @return Constant reference to member value + */ + eProsima_user_DllExport const std::string& value() const + { + return m_value; + } + + /*! + * @brief This function returns a reference to member value + * @return Reference to member value + */ + eProsima_user_DllExport std::string& value() + { + return m_value; + } + + + +private: + + std::string m_value; + +}; +/*! + * @brief This class represents the structure DDSEnablerTestType3 defined by the user in the IDL file. + * @ingroup DDSEnablerTestTypes + */ +class DDSEnablerTestType3 +{ +public: + + /*! + * @brief Default constructor. + */ + eProsima_user_DllExport DDSEnablerTestType3() + { + } + + /*! + * @brief Default destructor. + */ + eProsima_user_DllExport ~DDSEnablerTestType3() + { + } + + /*! + * @brief Copy constructor. + * @param x Reference to the object DDSEnablerTestType3 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType3( + const DDSEnablerTestType3& x) + { + m_value = x.m_value; + + } + + /*! + * @brief Move constructor. + * @param x Reference to the object DDSEnablerTestType3 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType3( + DDSEnablerTestType3&& x) noexcept + { + m_value = std::move(x.m_value); + } + + /*! + * @brief Copy assignment. + * @param x Reference to the object DDSEnablerTestType3 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType3& operator =( + const DDSEnablerTestType3& x) + { + + m_value = x.m_value; + + return *this; + } + + /*! + * @brief Move assignment. + * @param x Reference to the object DDSEnablerTestType3 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType3& operator =( + DDSEnablerTestType3&& x) noexcept + { + + m_value = std::move(x.m_value); + return *this; + } + + /*! + * @brief Comparison operator. + * @param x DDSEnablerTestType3 object to compare. + */ + eProsima_user_DllExport bool operator ==( + const DDSEnablerTestType3& x) const + { + return (m_value == x.m_value); + } + + /*! + * @brief Comparison operator. + * @param x DDSEnablerTestType3 object to compare. + */ + eProsima_user_DllExport bool operator !=( + const DDSEnablerTestType3& x) const + { + return !(*this == x); + } + + /*! + * @brief This function copies the value in member value + * @param _value New value to be copied in member value + */ + eProsima_user_DllExport void value( + const std::array& _value) + { + m_value = _value; + } + + /*! + * @brief This function moves the value in member value + * @param _value New value to be moved in member value + */ + eProsima_user_DllExport void value( + std::array&& _value) + { + m_value = std::move(_value); + } + + /*! + * @brief This function returns a constant reference to member value + * @return Constant reference to member value + */ + eProsima_user_DllExport const std::array& value() const + { + return m_value; + } + + /*! + * @brief This function returns a reference to member value + * @return Reference to member value + */ + eProsima_user_DllExport std::array& value() + { + return m_value; + } + + + +private: + + std::array m_value{0}; + +}; +/*! + * @brief This class represents the structure DDSEnablerTestType4 defined by the user in the IDL file. + * @ingroup DDSEnablerTestTypes + */ +class DDSEnablerTestType4 +{ +public: + + /*! + * @brief Default constructor. + */ + eProsima_user_DllExport DDSEnablerTestType4() + { + } + + /*! + * @brief Default destructor. + */ + eProsima_user_DllExport ~DDSEnablerTestType4() + { + } + + /*! + * @brief Copy constructor. + * @param x Reference to the object DDSEnablerTestType4 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType4( + const DDSEnablerTestType4& x) + { + m_value = x.m_value; + + } + + /*! + * @brief Move constructor. + * @param x Reference to the object DDSEnablerTestType4 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType4( + DDSEnablerTestType4&& x) noexcept + { + m_value = std::move(x.m_value); + } + + /*! + * @brief Copy assignment. + * @param x Reference to the object DDSEnablerTestType4 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType4& operator =( + const DDSEnablerTestType4& x) + { + + m_value = x.m_value; + + return *this; + } + + /*! + * @brief Move assignment. + * @param x Reference to the object DDSEnablerTestType4 that will be copied. + */ + eProsima_user_DllExport DDSEnablerTestType4& operator =( + DDSEnablerTestType4&& x) noexcept + { + + m_value = std::move(x.m_value); + return *this; + } + + /*! + * @brief Comparison operator. + * @param x DDSEnablerTestType4 object to compare. + */ + eProsima_user_DllExport bool operator ==( + const DDSEnablerTestType4& x) const + { + return (m_value == x.m_value); + } + + /*! + * @brief Comparison operator. + * @param x DDSEnablerTestType4 object to compare. + */ + eProsima_user_DllExport bool operator !=( + const DDSEnablerTestType4& x) const + { + return !(*this == x); + } + + /*! + * @brief This function copies the value in member value + * @param _value New value to be copied in member value + */ + eProsima_user_DllExport void value( + const DDSEnablerTestType1& _value) + { + m_value = _value; + } + + /*! + * @brief This function moves the value in member value + * @param _value New value to be moved in member value + */ + eProsima_user_DllExport void value( + DDSEnablerTestType1&& _value) + { + m_value = std::move(_value); + } + + /*! + * @brief This function returns a constant reference to member value + * @return Constant reference to member value + */ + eProsima_user_DllExport const DDSEnablerTestType1& value() const + { + return m_value; + } + + /*! + * @brief This function returns a reference to member value + * @return Reference to member value + */ + eProsima_user_DllExport DDSEnablerTestType1& value() + { + return m_value; + } + + + +private: + + DDSEnablerTestType1 m_value; + +}; + +#endif // _FAST_DDS_GENERATED_DDSENABLERTESTTYPES_HPP_ + + diff --git a/ddsenabler_participants/test/types/DDSEnablerTestTypes.idl b/ddsenabler_participants/test/types/DDSEnablerTestTypes.idl new file mode 100644 index 00000000..ec4db993 --- /dev/null +++ b/ddsenabler_participants/test/types/DDSEnablerTestTypes.idl @@ -0,0 +1,19 @@ +struct DDSEnablerTestType1 +{ + short value; +}; + +struct DDSEnablerTestType2 +{ + string value; +}; + +struct DDSEnablerTestType3 +{ + long value[10]; +}; + +struct DDSEnablerTestType4 +{ + DDSEnablerTestType1 value; +}; diff --git a/ddsenabler_participants/test/types/DDSEnablerTestTypesCdrAux.hpp b/ddsenabler_participants/test/types/DDSEnablerTestTypesCdrAux.hpp new file mode 100644 index 00000000..e46c7a78 --- /dev/null +++ b/ddsenabler_participants/test/types/DDSEnablerTestTypesCdrAux.hpp @@ -0,0 +1,67 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DDSEnablerTestTypesCdrAux.hpp + * This source file contains some definitions of CDR related functions. + * + * This file was generated by the tool fastddsgen. + */ + +#ifndef FAST_DDS_GENERATED__DDSENABLERTESTTYPESCDRAUX_HPP +#define FAST_DDS_GENERATED__DDSENABLERTESTTYPESCDRAUX_HPP + +#include "DDSEnablerTestTypes.hpp" + +constexpr uint32_t DDSEnablerTestType2_max_cdr_typesize {264UL}; +constexpr uint32_t DDSEnablerTestType2_max_key_cdr_typesize {0UL}; + +constexpr uint32_t DDSEnablerTestType3_max_cdr_typesize {44UL}; +constexpr uint32_t DDSEnablerTestType3_max_key_cdr_typesize {0UL}; + +constexpr uint32_t DDSEnablerTestType1_max_cdr_typesize {6UL}; +constexpr uint32_t DDSEnablerTestType1_max_key_cdr_typesize {0UL}; + +constexpr uint32_t DDSEnablerTestType4_max_cdr_typesize {10UL}; +constexpr uint32_t DDSEnablerTestType4_max_key_cdr_typesize {0UL}; + + +namespace eprosima { +namespace fastcdr { + +class Cdr; +class CdrSizeCalculator; + +eProsima_user_DllExport void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const DDSEnablerTestType1& data); + +eProsima_user_DllExport void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const DDSEnablerTestType2& data); + +eProsima_user_DllExport void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const DDSEnablerTestType3& data); + +eProsima_user_DllExport void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const DDSEnablerTestType4& data); + + +} // namespace fastcdr +} // namespace eprosima + +#endif // FAST_DDS_GENERATED__DDSENABLERTESTTYPESCDRAUX_HPP + diff --git a/ddsenabler_participants/test/types/DDSEnablerTestTypesCdrAux.ipp b/ddsenabler_participants/test/types/DDSEnablerTestTypesCdrAux.ipp new file mode 100644 index 00000000..848c0afe --- /dev/null +++ b/ddsenabler_participants/test/types/DDSEnablerTestTypesCdrAux.ipp @@ -0,0 +1,362 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DDSEnablerTestTypesCdrAux.ipp + * This source file contains some declarations of CDR related functions. + * + * This file was generated by the tool fastddsgen. + */ + +#ifndef FAST_DDS_GENERATED__DDSENABLERTESTTYPESCDRAUX_IPP +#define FAST_DDS_GENERATED__DDSENABLERTESTTYPESCDRAUX_IPP + +#include "DDSEnablerTestTypesCdrAux.hpp" + +#include +#include + + +#include +using namespace eprosima::fastcdr::exception; + +namespace eprosima { +namespace fastcdr { + +template<> +eProsima_user_DllExport size_t calculate_serialized_size( + eprosima::fastcdr::CdrSizeCalculator& calculator, + const DDSEnablerTestType1& data, + size_t& current_alignment) +{ + static_cast(data); + + eprosima::fastcdr::EncodingAlgorithmFlag previous_encoding = calculator.get_encoding(); + size_t calculated_size {calculator.begin_calculate_type_serialized_size( + eprosima::fastcdr::CdrVersion::XCDRv2 == calculator.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + current_alignment)}; + + + calculated_size += calculator.calculate_member_serialized_size(eprosima::fastcdr::MemberId(0), + data.value(), current_alignment); + + + calculated_size += calculator.end_calculate_type_serialized_size(previous_encoding, current_alignment); + + return calculated_size; +} + +template<> +eProsima_user_DllExport void serialize( + eprosima::fastcdr::Cdr& scdr, + const DDSEnablerTestType1& data) +{ + eprosima::fastcdr::Cdr::state current_state(scdr); + scdr.begin_serialize_type(current_state, + eprosima::fastcdr::CdrVersion::XCDRv2 == scdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR); + + scdr + << eprosima::fastcdr::MemberId(0) << data.value() +; + scdr.end_serialize_type(current_state); +} + +template<> +eProsima_user_DllExport void deserialize( + eprosima::fastcdr::Cdr& cdr, + DDSEnablerTestType1& data) +{ + cdr.deserialize_type(eprosima::fastcdr::CdrVersion::XCDRv2 == cdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + [&data](eprosima::fastcdr::Cdr& dcdr, const eprosima::fastcdr::MemberId& mid) -> bool + { + bool ret_value = true; + switch (mid.id) + { + case 0: + dcdr >> data.value(); + break; + + default: + ret_value = false; + break; + } + return ret_value; + }); +} + +void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const DDSEnablerTestType1& data) +{ + + static_cast(scdr); + static_cast(data); + scdr << data.value(); + +} + + +template<> +eProsima_user_DllExport size_t calculate_serialized_size( + eprosima::fastcdr::CdrSizeCalculator& calculator, + const DDSEnablerTestType2& data, + size_t& current_alignment) +{ + static_cast(data); + + eprosima::fastcdr::EncodingAlgorithmFlag previous_encoding = calculator.get_encoding(); + size_t calculated_size {calculator.begin_calculate_type_serialized_size( + eprosima::fastcdr::CdrVersion::XCDRv2 == calculator.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + current_alignment)}; + + + calculated_size += calculator.calculate_member_serialized_size(eprosima::fastcdr::MemberId(0), + data.value(), current_alignment); + + + calculated_size += calculator.end_calculate_type_serialized_size(previous_encoding, current_alignment); + + return calculated_size; +} + +template<> +eProsima_user_DllExport void serialize( + eprosima::fastcdr::Cdr& scdr, + const DDSEnablerTestType2& data) +{ + eprosima::fastcdr::Cdr::state current_state(scdr); + scdr.begin_serialize_type(current_state, + eprosima::fastcdr::CdrVersion::XCDRv2 == scdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR); + + scdr + << eprosima::fastcdr::MemberId(0) << data.value() +; + scdr.end_serialize_type(current_state); +} + +template<> +eProsima_user_DllExport void deserialize( + eprosima::fastcdr::Cdr& cdr, + DDSEnablerTestType2& data) +{ + cdr.deserialize_type(eprosima::fastcdr::CdrVersion::XCDRv2 == cdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + [&data](eprosima::fastcdr::Cdr& dcdr, const eprosima::fastcdr::MemberId& mid) -> bool + { + bool ret_value = true; + switch (mid.id) + { + case 0: + dcdr >> data.value(); + break; + + default: + ret_value = false; + break; + } + return ret_value; + }); +} + +void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const DDSEnablerTestType2& data) +{ + + static_cast(scdr); + static_cast(data); + scdr << data.value(); + +} + + +template<> +eProsima_user_DllExport size_t calculate_serialized_size( + eprosima::fastcdr::CdrSizeCalculator& calculator, + const DDSEnablerTestType3& data, + size_t& current_alignment) +{ + static_cast(data); + + eprosima::fastcdr::EncodingAlgorithmFlag previous_encoding = calculator.get_encoding(); + size_t calculated_size {calculator.begin_calculate_type_serialized_size( + eprosima::fastcdr::CdrVersion::XCDRv2 == calculator.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + current_alignment)}; + + + calculated_size += calculator.calculate_member_serialized_size(eprosima::fastcdr::MemberId(0), + data.value(), current_alignment); + + + calculated_size += calculator.end_calculate_type_serialized_size(previous_encoding, current_alignment); + + return calculated_size; +} + +template<> +eProsima_user_DllExport void serialize( + eprosima::fastcdr::Cdr& scdr, + const DDSEnablerTestType3& data) +{ + eprosima::fastcdr::Cdr::state current_state(scdr); + scdr.begin_serialize_type(current_state, + eprosima::fastcdr::CdrVersion::XCDRv2 == scdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR); + + scdr + << eprosima::fastcdr::MemberId(0) << data.value() +; + scdr.end_serialize_type(current_state); +} + +template<> +eProsima_user_DllExport void deserialize( + eprosima::fastcdr::Cdr& cdr, + DDSEnablerTestType3& data) +{ + cdr.deserialize_type(eprosima::fastcdr::CdrVersion::XCDRv2 == cdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + [&data](eprosima::fastcdr::Cdr& dcdr, const eprosima::fastcdr::MemberId& mid) -> bool + { + bool ret_value = true; + switch (mid.id) + { + case 0: + dcdr >> data.value(); + break; + + default: + ret_value = false; + break; + } + return ret_value; + }); +} + +void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const DDSEnablerTestType3& data) +{ + + static_cast(scdr); + static_cast(data); + scdr << data.value(); + +} + + +template<> +eProsima_user_DllExport size_t calculate_serialized_size( + eprosima::fastcdr::CdrSizeCalculator& calculator, + const DDSEnablerTestType4& data, + size_t& current_alignment) +{ + static_cast(data); + + eprosima::fastcdr::EncodingAlgorithmFlag previous_encoding = calculator.get_encoding(); + size_t calculated_size {calculator.begin_calculate_type_serialized_size( + eprosima::fastcdr::CdrVersion::XCDRv2 == calculator.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + current_alignment)}; + + + calculated_size += calculator.calculate_member_serialized_size(eprosima::fastcdr::MemberId(0), + data.value(), current_alignment); + + + calculated_size += calculator.end_calculate_type_serialized_size(previous_encoding, current_alignment); + + return calculated_size; +} + +template<> +eProsima_user_DllExport void serialize( + eprosima::fastcdr::Cdr& scdr, + const DDSEnablerTestType4& data) +{ + eprosima::fastcdr::Cdr::state current_state(scdr); + scdr.begin_serialize_type(current_state, + eprosima::fastcdr::CdrVersion::XCDRv2 == scdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR); + + scdr + << eprosima::fastcdr::MemberId(0) << data.value() +; + scdr.end_serialize_type(current_state); +} + +template<> +eProsima_user_DllExport void deserialize( + eprosima::fastcdr::Cdr& cdr, + DDSEnablerTestType4& data) +{ + cdr.deserialize_type(eprosima::fastcdr::CdrVersion::XCDRv2 == cdr.get_cdr_version() ? + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR, + [&data](eprosima::fastcdr::Cdr& dcdr, const eprosima::fastcdr::MemberId& mid) -> bool + { + bool ret_value = true; + switch (mid.id) + { + case 0: + dcdr >> data.value(); + break; + + default: + ret_value = false; + break; + } + return ret_value; + }); +} + +void serialize_key( + eprosima::fastcdr::Cdr& scdr, + const DDSEnablerTestType4& data) +{ + extern void serialize_key( + Cdr& scdr, + const DDSEnablerTestType1& data); + + + static_cast(scdr); + static_cast(data); + serialize_key(scdr, data.value()); + +} + + + +} // namespace fastcdr +} // namespace eprosima + +#endif // FAST_DDS_GENERATED__DDSENABLERTESTTYPESCDRAUX_IPP + diff --git a/ddsenabler_participants/test/types/DDSEnablerTestTypesPubSubTypes.cxx b/ddsenabler_participants/test/types/DDSEnablerTestTypesPubSubTypes.cxx new file mode 100644 index 00000000..047f5f9d --- /dev/null +++ b/ddsenabler_participants/test/types/DDSEnablerTestTypesPubSubTypes.cxx @@ -0,0 +1,760 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DDSEnablerTestTypesPubSubTypes.cpp + * This header file contains the implementation of the serialization functions. + * + * This file was generated by the tool fastddsgen. + */ + +#include "DDSEnablerTestTypesPubSubTypes.hpp" + +#include +#include + +#include "DDSEnablerTestTypesCdrAux.hpp" +#include "DDSEnablerTestTypesTypeObjectSupport.hpp" + +using SerializedPayload_t = eprosima::fastdds::rtps::SerializedPayload_t; +using InstanceHandle_t = eprosima::fastdds::rtps::InstanceHandle_t; +using DataRepresentationId_t = eprosima::fastdds::dds::DataRepresentationId_t; + +DDSEnablerTestType1PubSubType::DDSEnablerTestType1PubSubType() +{ + set_name("DDSEnablerTestType1"); + uint32_t type_size = DDSEnablerTestType1_max_cdr_typesize; + type_size += static_cast(eprosima::fastcdr::Cdr::alignment(type_size, 4)); /* possible submessage alignment */ + max_serialized_type_size = type_size + 4; /*encapsulation*/ + is_compute_key_provided = false; + uint32_t key_length = DDSEnablerTestType1_max_key_cdr_typesize > 16 ? DDSEnablerTestType1_max_key_cdr_typesize : 16; + key_buffer_ = reinterpret_cast(malloc(key_length)); + memset(key_buffer_, 0, key_length); +} + +DDSEnablerTestType1PubSubType::~DDSEnablerTestType1PubSubType() +{ + if (key_buffer_ != nullptr) + { + free(key_buffer_); + } +} + +bool DDSEnablerTestType1PubSubType::serialize( + const void* const data, + SerializedPayload_t& payload, + DataRepresentationId_t data_representation) +{ + const DDSEnablerTestType1* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload.data), payload.max_size); + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN, + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 : eprosima::fastcdr::CdrVersion::XCDRv2); + payload.encapsulation = ser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + ser.set_encoding_flag( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR : + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2); + + try + { + // Serialize encapsulation + ser.serialize_encapsulation(); + // Serialize the object. + ser << *p_type; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + // Get the serialized length + payload.length = static_cast(ser.get_serialized_data_length()); + return true; +} + +bool DDSEnablerTestType1PubSubType::deserialize( + SerializedPayload_t& payload, + void* data) +{ + try + { + // Convert DATA to pointer of your type + DDSEnablerTestType1* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload.data), payload.length); + + // Object that deserializes the data. + eprosima::fastcdr::Cdr deser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN); + + // Deserialize encapsulation. + deser.read_encapsulation(); + payload.encapsulation = deser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + + // Deserialize the object. + deser >> *p_type; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + return true; +} + +uint32_t DDSEnablerTestType1PubSubType::calculate_serialized_size( + const void* const data, + DataRepresentationId_t data_representation) +{ + try + { + eprosima::fastcdr::CdrSizeCalculator calculator( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 :eprosima::fastcdr::CdrVersion::XCDRv2); + size_t current_alignment {0}; + return static_cast(calculator.calculate_serialized_size( + *static_cast(data), current_alignment)) + + 4u /*encapsulation*/; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return 0; + } +} + +void* DDSEnablerTestType1PubSubType::create_data() +{ + return reinterpret_cast(new DDSEnablerTestType1()); +} + +void DDSEnablerTestType1PubSubType::delete_data( + void* data) +{ + delete(reinterpret_cast(data)); +} + +bool DDSEnablerTestType1PubSubType::compute_key( + SerializedPayload_t& payload, + InstanceHandle_t& handle, + bool force_md5) +{ + if (!is_compute_key_provided) + { + return false; + } + + DDSEnablerTestType1 data; + if (deserialize(payload, static_cast(&data))) + { + return compute_key(static_cast(&data), handle, force_md5); + } + + return false; +} + +bool DDSEnablerTestType1PubSubType::compute_key( + const void* const data, + InstanceHandle_t& handle, + bool force_md5) +{ + if (!is_compute_key_provided) + { + return false; + } + + const DDSEnablerTestType1* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(key_buffer_), + DDSEnablerTestType1_max_key_cdr_typesize); + + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::BIG_ENDIANNESS, eprosima::fastcdr::CdrVersion::XCDRv2); + ser.set_encoding_flag(eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR2); + eprosima::fastcdr::serialize_key(ser, *p_type); + if (force_md5 || DDSEnablerTestType1_max_key_cdr_typesize > 16) + { + md5_.init(); + md5_.update(key_buffer_, static_cast(ser.get_serialized_data_length())); + md5_.finalize(); + for (uint8_t i = 0; i < 16; ++i) + { + handle.value[i] = md5_.digest[i]; + } + } + else + { + for (uint8_t i = 0; i < 16; ++i) + { + handle.value[i] = key_buffer_[i]; + } + } + return true; +} + +void DDSEnablerTestType1PubSubType::register_type_object_representation() +{ + register_DDSEnablerTestType1_type_identifier(type_identifiers_); +} + +DDSEnablerTestType2PubSubType::DDSEnablerTestType2PubSubType() +{ + set_name("DDSEnablerTestType2"); + uint32_t type_size = DDSEnablerTestType2_max_cdr_typesize; + type_size += static_cast(eprosima::fastcdr::Cdr::alignment(type_size, 4)); /* possible submessage alignment */ + max_serialized_type_size = type_size + 4; /*encapsulation*/ + is_compute_key_provided = false; + uint32_t key_length = DDSEnablerTestType2_max_key_cdr_typesize > 16 ? DDSEnablerTestType2_max_key_cdr_typesize : 16; + key_buffer_ = reinterpret_cast(malloc(key_length)); + memset(key_buffer_, 0, key_length); +} + +DDSEnablerTestType2PubSubType::~DDSEnablerTestType2PubSubType() +{ + if (key_buffer_ != nullptr) + { + free(key_buffer_); + } +} + +bool DDSEnablerTestType2PubSubType::serialize( + const void* const data, + SerializedPayload_t& payload, + DataRepresentationId_t data_representation) +{ + const DDSEnablerTestType2* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload.data), payload.max_size); + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN, + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 : eprosima::fastcdr::CdrVersion::XCDRv2); + payload.encapsulation = ser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + ser.set_encoding_flag( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR : + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2); + + try + { + // Serialize encapsulation + ser.serialize_encapsulation(); + // Serialize the object. + ser << *p_type; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + // Get the serialized length + payload.length = static_cast(ser.get_serialized_data_length()); + return true; +} + +bool DDSEnablerTestType2PubSubType::deserialize( + SerializedPayload_t& payload, + void* data) +{ + try + { + // Convert DATA to pointer of your type + DDSEnablerTestType2* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload.data), payload.length); + + // Object that deserializes the data. + eprosima::fastcdr::Cdr deser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN); + + // Deserialize encapsulation. + deser.read_encapsulation(); + payload.encapsulation = deser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + + // Deserialize the object. + deser >> *p_type; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + return true; +} + +uint32_t DDSEnablerTestType2PubSubType::calculate_serialized_size( + const void* const data, + DataRepresentationId_t data_representation) +{ + try + { + eprosima::fastcdr::CdrSizeCalculator calculator( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 :eprosima::fastcdr::CdrVersion::XCDRv2); + size_t current_alignment {0}; + return static_cast(calculator.calculate_serialized_size( + *static_cast(data), current_alignment)) + + 4u /*encapsulation*/; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return 0; + } +} + +void* DDSEnablerTestType2PubSubType::create_data() +{ + return reinterpret_cast(new DDSEnablerTestType2()); +} + +void DDSEnablerTestType2PubSubType::delete_data( + void* data) +{ + delete(reinterpret_cast(data)); +} + +bool DDSEnablerTestType2PubSubType::compute_key( + SerializedPayload_t& payload, + InstanceHandle_t& handle, + bool force_md5) +{ + if (!is_compute_key_provided) + { + return false; + } + + DDSEnablerTestType2 data; + if (deserialize(payload, static_cast(&data))) + { + return compute_key(static_cast(&data), handle, force_md5); + } + + return false; +} + +bool DDSEnablerTestType2PubSubType::compute_key( + const void* const data, + InstanceHandle_t& handle, + bool force_md5) +{ + if (!is_compute_key_provided) + { + return false; + } + + const DDSEnablerTestType2* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(key_buffer_), + DDSEnablerTestType2_max_key_cdr_typesize); + + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::BIG_ENDIANNESS, eprosima::fastcdr::CdrVersion::XCDRv2); + ser.set_encoding_flag(eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR2); + eprosima::fastcdr::serialize_key(ser, *p_type); + if (force_md5 || DDSEnablerTestType2_max_key_cdr_typesize > 16) + { + md5_.init(); + md5_.update(key_buffer_, static_cast(ser.get_serialized_data_length())); + md5_.finalize(); + for (uint8_t i = 0; i < 16; ++i) + { + handle.value[i] = md5_.digest[i]; + } + } + else + { + for (uint8_t i = 0; i < 16; ++i) + { + handle.value[i] = key_buffer_[i]; + } + } + return true; +} + +void DDSEnablerTestType2PubSubType::register_type_object_representation() +{ + register_DDSEnablerTestType2_type_identifier(type_identifiers_); +} + +DDSEnablerTestType3PubSubType::DDSEnablerTestType3PubSubType() +{ + set_name("DDSEnablerTestType3"); + uint32_t type_size = DDSEnablerTestType3_max_cdr_typesize; + type_size += static_cast(eprosima::fastcdr::Cdr::alignment(type_size, 4)); /* possible submessage alignment */ + max_serialized_type_size = type_size + 4; /*encapsulation*/ + is_compute_key_provided = false; + uint32_t key_length = DDSEnablerTestType3_max_key_cdr_typesize > 16 ? DDSEnablerTestType3_max_key_cdr_typesize : 16; + key_buffer_ = reinterpret_cast(malloc(key_length)); + memset(key_buffer_, 0, key_length); +} + +DDSEnablerTestType3PubSubType::~DDSEnablerTestType3PubSubType() +{ + if (key_buffer_ != nullptr) + { + free(key_buffer_); + } +} + +bool DDSEnablerTestType3PubSubType::serialize( + const void* const data, + SerializedPayload_t& payload, + DataRepresentationId_t data_representation) +{ + const DDSEnablerTestType3* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload.data), payload.max_size); + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN, + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 : eprosima::fastcdr::CdrVersion::XCDRv2); + payload.encapsulation = ser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + ser.set_encoding_flag( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR : + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2); + + try + { + // Serialize encapsulation + ser.serialize_encapsulation(); + // Serialize the object. + ser << *p_type; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + // Get the serialized length + payload.length = static_cast(ser.get_serialized_data_length()); + return true; +} + +bool DDSEnablerTestType3PubSubType::deserialize( + SerializedPayload_t& payload, + void* data) +{ + try + { + // Convert DATA to pointer of your type + DDSEnablerTestType3* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload.data), payload.length); + + // Object that deserializes the data. + eprosima::fastcdr::Cdr deser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN); + + // Deserialize encapsulation. + deser.read_encapsulation(); + payload.encapsulation = deser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + + // Deserialize the object. + deser >> *p_type; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + return true; +} + +uint32_t DDSEnablerTestType3PubSubType::calculate_serialized_size( + const void* const data, + DataRepresentationId_t data_representation) +{ + try + { + eprosima::fastcdr::CdrSizeCalculator calculator( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 :eprosima::fastcdr::CdrVersion::XCDRv2); + size_t current_alignment {0}; + return static_cast(calculator.calculate_serialized_size( + *static_cast(data), current_alignment)) + + 4u /*encapsulation*/; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return 0; + } +} + +void* DDSEnablerTestType3PubSubType::create_data() +{ + return reinterpret_cast(new DDSEnablerTestType3()); +} + +void DDSEnablerTestType3PubSubType::delete_data( + void* data) +{ + delete(reinterpret_cast(data)); +} + +bool DDSEnablerTestType3PubSubType::compute_key( + SerializedPayload_t& payload, + InstanceHandle_t& handle, + bool force_md5) +{ + if (!is_compute_key_provided) + { + return false; + } + + DDSEnablerTestType3 data; + if (deserialize(payload, static_cast(&data))) + { + return compute_key(static_cast(&data), handle, force_md5); + } + + return false; +} + +bool DDSEnablerTestType3PubSubType::compute_key( + const void* const data, + InstanceHandle_t& handle, + bool force_md5) +{ + if (!is_compute_key_provided) + { + return false; + } + + const DDSEnablerTestType3* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(key_buffer_), + DDSEnablerTestType3_max_key_cdr_typesize); + + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::BIG_ENDIANNESS, eprosima::fastcdr::CdrVersion::XCDRv2); + ser.set_encoding_flag(eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR2); + eprosima::fastcdr::serialize_key(ser, *p_type); + if (force_md5 || DDSEnablerTestType3_max_key_cdr_typesize > 16) + { + md5_.init(); + md5_.update(key_buffer_, static_cast(ser.get_serialized_data_length())); + md5_.finalize(); + for (uint8_t i = 0; i < 16; ++i) + { + handle.value[i] = md5_.digest[i]; + } + } + else + { + for (uint8_t i = 0; i < 16; ++i) + { + handle.value[i] = key_buffer_[i]; + } + } + return true; +} + +void DDSEnablerTestType3PubSubType::register_type_object_representation() +{ + register_DDSEnablerTestType3_type_identifier(type_identifiers_); +} + +DDSEnablerTestType4PubSubType::DDSEnablerTestType4PubSubType() +{ + set_name("DDSEnablerTestType4"); + uint32_t type_size = DDSEnablerTestType4_max_cdr_typesize; + type_size += static_cast(eprosima::fastcdr::Cdr::alignment(type_size, 4)); /* possible submessage alignment */ + max_serialized_type_size = type_size + 4; /*encapsulation*/ + is_compute_key_provided = false; + uint32_t key_length = DDSEnablerTestType4_max_key_cdr_typesize > 16 ? DDSEnablerTestType4_max_key_cdr_typesize : 16; + key_buffer_ = reinterpret_cast(malloc(key_length)); + memset(key_buffer_, 0, key_length); +} + +DDSEnablerTestType4PubSubType::~DDSEnablerTestType4PubSubType() +{ + if (key_buffer_ != nullptr) + { + free(key_buffer_); + } +} + +bool DDSEnablerTestType4PubSubType::serialize( + const void* const data, + SerializedPayload_t& payload, + DataRepresentationId_t data_representation) +{ + const DDSEnablerTestType4* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload.data), payload.max_size); + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN, + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 : eprosima::fastcdr::CdrVersion::XCDRv2); + payload.encapsulation = ser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + ser.set_encoding_flag( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR : + eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2); + + try + { + // Serialize encapsulation + ser.serialize_encapsulation(); + // Serialize the object. + ser << *p_type; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + // Get the serialized length + payload.length = static_cast(ser.get_serialized_data_length()); + return true; +} + +bool DDSEnablerTestType4PubSubType::deserialize( + SerializedPayload_t& payload, + void* data) +{ + try + { + // Convert DATA to pointer of your type + DDSEnablerTestType4* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload.data), payload.length); + + // Object that deserializes the data. + eprosima::fastcdr::Cdr deser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN); + + // Deserialize encapsulation. + deser.read_encapsulation(); + payload.encapsulation = deser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + + // Deserialize the object. + deser >> *p_type; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return false; + } + + return true; +} + +uint32_t DDSEnablerTestType4PubSubType::calculate_serialized_size( + const void* const data, + DataRepresentationId_t data_representation) +{ + try + { + eprosima::fastcdr::CdrSizeCalculator calculator( + data_representation == DataRepresentationId_t::XCDR_DATA_REPRESENTATION ? + eprosima::fastcdr::CdrVersion::XCDRv1 :eprosima::fastcdr::CdrVersion::XCDRv2); + size_t current_alignment {0}; + return static_cast(calculator.calculate_serialized_size( + *static_cast(data), current_alignment)) + + 4u /*encapsulation*/; + } + catch (eprosima::fastcdr::exception::Exception& /*exception*/) + { + return 0; + } +} + +void* DDSEnablerTestType4PubSubType::create_data() +{ + return reinterpret_cast(new DDSEnablerTestType4()); +} + +void DDSEnablerTestType4PubSubType::delete_data( + void* data) +{ + delete(reinterpret_cast(data)); +} + +bool DDSEnablerTestType4PubSubType::compute_key( + SerializedPayload_t& payload, + InstanceHandle_t& handle, + bool force_md5) +{ + if (!is_compute_key_provided) + { + return false; + } + + DDSEnablerTestType4 data; + if (deserialize(payload, static_cast(&data))) + { + return compute_key(static_cast(&data), handle, force_md5); + } + + return false; +} + +bool DDSEnablerTestType4PubSubType::compute_key( + const void* const data, + InstanceHandle_t& handle, + bool force_md5) +{ + if (!is_compute_key_provided) + { + return false; + } + + const DDSEnablerTestType4* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(key_buffer_), + DDSEnablerTestType4_max_key_cdr_typesize); + + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::BIG_ENDIANNESS, eprosima::fastcdr::CdrVersion::XCDRv2); + ser.set_encoding_flag(eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR2); + eprosima::fastcdr::serialize_key(ser, *p_type); + if (force_md5 || DDSEnablerTestType4_max_key_cdr_typesize > 16) + { + md5_.init(); + md5_.update(key_buffer_, static_cast(ser.get_serialized_data_length())); + md5_.finalize(); + for (uint8_t i = 0; i < 16; ++i) + { + handle.value[i] = md5_.digest[i]; + } + } + else + { + for (uint8_t i = 0; i < 16; ++i) + { + handle.value[i] = key_buffer_[i]; + } + } + return true; +} + +void DDSEnablerTestType4PubSubType::register_type_object_representation() +{ + register_DDSEnablerTestType4_type_identifier(type_identifiers_); +} + + +// Include auxiliary functions like for serializing/deserializing. +#include "DDSEnablerTestTypesCdrAux.ipp" diff --git a/ddsenabler_participants/test/types/DDSEnablerTestTypesPubSubTypes.hpp b/ddsenabler_participants/test/types/DDSEnablerTestTypesPubSubTypes.hpp new file mode 100644 index 00000000..c05373e7 --- /dev/null +++ b/ddsenabler_participants/test/types/DDSEnablerTestTypesPubSubTypes.hpp @@ -0,0 +1,366 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DDSEnablerTestTypesPubSubTypes.hpp + * This header file contains the declaration of the serialization functions. + * + * This file was generated by the tool fastddsgen. + */ + + +#ifndef FAST_DDS_GENERATED__DDSENABLERTESTTYPES_PUBSUBTYPES_HPP +#define FAST_DDS_GENERATED__DDSENABLERTESTTYPES_PUBSUBTYPES_HPP + +#include +#include +#include +#include +#include + +#include "DDSEnablerTestTypes.hpp" + + +#if !defined(FASTDDS_GEN_API_VER) || (FASTDDS_GEN_API_VER != 3) +#error \ + Generated DDSEnablerTestTypes is not compatible with current installed Fast DDS. Please, regenerate it with fastddsgen. +#endif // FASTDDS_GEN_API_VER + + +/*! + * @brief This class represents the TopicDataType of the type DDSEnablerTestType1 defined by the user in the IDL file. + * @ingroup DDSEnablerTestTypes + */ +class DDSEnablerTestType1PubSubType : public eprosima::fastdds::dds::TopicDataType +{ +public: + + typedef DDSEnablerTestType1 type; + + eProsima_user_DllExport DDSEnablerTestType1PubSubType(); + + eProsima_user_DllExport ~DDSEnablerTestType1PubSubType() override; + + eProsima_user_DllExport bool serialize( + const void* const data, + eprosima::fastdds::rtps::SerializedPayload_t& payload, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool deserialize( + eprosima::fastdds::rtps::SerializedPayload_t& payload, + void* data) override; + + eProsima_user_DllExport uint32_t calculate_serialized_size( + const void* const data, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool compute_key( + eprosima::fastdds::rtps::SerializedPayload_t& payload, + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport bool compute_key( + const void* const data, + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport void* create_data() override; + + eProsima_user_DllExport void delete_data( + void* data) override; + + //Register TypeObject representation in Fast DDS TypeObjectRegistry + eProsima_user_DllExport void register_type_object_representation() override; + +#ifdef TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + eProsima_user_DllExport inline bool is_bounded() const override + { + return true; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + +#ifdef TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + + eProsima_user_DllExport inline bool is_plain( + eprosima::fastdds::dds::DataRepresentationId_t data_representation) const override + { + static_cast(data_representation); + return false; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + +#ifdef TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + eProsima_user_DllExport inline bool construct_sample( + void* memory) const override + { + static_cast(memory); + return false; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + +private: + + eprosima::fastdds::MD5 md5_; + unsigned char* key_buffer_; + +}; + +/*! + * @brief This class represents the TopicDataType of the type DDSEnablerTestType2 defined by the user in the IDL file. + * @ingroup DDSEnablerTestTypes + */ +class DDSEnablerTestType2PubSubType : public eprosima::fastdds::dds::TopicDataType +{ +public: + + typedef DDSEnablerTestType2 type; + + eProsima_user_DllExport DDSEnablerTestType2PubSubType(); + + eProsima_user_DllExport ~DDSEnablerTestType2PubSubType() override; + + eProsima_user_DllExport bool serialize( + const void* const data, + eprosima::fastdds::rtps::SerializedPayload_t& payload, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool deserialize( + eprosima::fastdds::rtps::SerializedPayload_t& payload, + void* data) override; + + eProsima_user_DllExport uint32_t calculate_serialized_size( + const void* const data, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool compute_key( + eprosima::fastdds::rtps::SerializedPayload_t& payload, + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport bool compute_key( + const void* const data, + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport void* create_data() override; + + eProsima_user_DllExport void delete_data( + void* data) override; + + //Register TypeObject representation in Fast DDS TypeObjectRegistry + eProsima_user_DllExport void register_type_object_representation() override; + +#ifdef TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + eProsima_user_DllExport inline bool is_bounded() const override + { + return false; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + +#ifdef TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + + eProsima_user_DllExport inline bool is_plain( + eprosima::fastdds::dds::DataRepresentationId_t data_representation) const override + { + static_cast(data_representation); + return false; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + +#ifdef TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + eProsima_user_DllExport inline bool construct_sample( + void* memory) const override + { + static_cast(memory); + return false; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + +private: + + eprosima::fastdds::MD5 md5_; + unsigned char* key_buffer_; + +}; + +/*! + * @brief This class represents the TopicDataType of the type DDSEnablerTestType3 defined by the user in the IDL file. + * @ingroup DDSEnablerTestTypes + */ +class DDSEnablerTestType3PubSubType : public eprosima::fastdds::dds::TopicDataType +{ +public: + + typedef DDSEnablerTestType3 type; + + eProsima_user_DllExport DDSEnablerTestType3PubSubType(); + + eProsima_user_DllExport ~DDSEnablerTestType3PubSubType() override; + + eProsima_user_DllExport bool serialize( + const void* const data, + eprosima::fastdds::rtps::SerializedPayload_t& payload, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool deserialize( + eprosima::fastdds::rtps::SerializedPayload_t& payload, + void* data) override; + + eProsima_user_DllExport uint32_t calculate_serialized_size( + const void* const data, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool compute_key( + eprosima::fastdds::rtps::SerializedPayload_t& payload, + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport bool compute_key( + const void* const data, + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport void* create_data() override; + + eProsima_user_DllExport void delete_data( + void* data) override; + + //Register TypeObject representation in Fast DDS TypeObjectRegistry + eProsima_user_DllExport void register_type_object_representation() override; + +#ifdef TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + eProsima_user_DllExport inline bool is_bounded() const override + { + return true; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + +#ifdef TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + + eProsima_user_DllExport inline bool is_plain( + eprosima::fastdds::dds::DataRepresentationId_t data_representation) const override + { + static_cast(data_representation); + return false; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + +#ifdef TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + eProsima_user_DllExport inline bool construct_sample( + void* memory) const override + { + static_cast(memory); + return false; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + +private: + + eprosima::fastdds::MD5 md5_; + unsigned char* key_buffer_; + +}; + +/*! + * @brief This class represents the TopicDataType of the type DDSEnablerTestType4 defined by the user in the IDL file. + * @ingroup DDSEnablerTestTypes + */ +class DDSEnablerTestType4PubSubType : public eprosima::fastdds::dds::TopicDataType +{ +public: + + typedef DDSEnablerTestType4 type; + + eProsima_user_DllExport DDSEnablerTestType4PubSubType(); + + eProsima_user_DllExport ~DDSEnablerTestType4PubSubType() override; + + eProsima_user_DllExport bool serialize( + const void* const data, + eprosima::fastdds::rtps::SerializedPayload_t& payload, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool deserialize( + eprosima::fastdds::rtps::SerializedPayload_t& payload, + void* data) override; + + eProsima_user_DllExport uint32_t calculate_serialized_size( + const void* const data, + eprosima::fastdds::dds::DataRepresentationId_t data_representation) override; + + eProsima_user_DllExport bool compute_key( + eprosima::fastdds::rtps::SerializedPayload_t& payload, + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport bool compute_key( + const void* const data, + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport void* create_data() override; + + eProsima_user_DllExport void delete_data( + void* data) override; + + //Register TypeObject representation in Fast DDS TypeObjectRegistry + eProsima_user_DllExport void register_type_object_representation() override; + +#ifdef TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + eProsima_user_DllExport inline bool is_bounded() const override + { + return true; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + +#ifdef TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + + eProsima_user_DllExport inline bool is_plain( + eprosima::fastdds::dds::DataRepresentationId_t data_representation) const override + { + static_cast(data_representation); + return false; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + +#ifdef TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + eProsima_user_DllExport inline bool construct_sample( + void* memory) const override + { + static_cast(memory); + return false; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + +private: + + eprosima::fastdds::MD5 md5_; + unsigned char* key_buffer_; + +}; + +#endif // FAST_DDS_GENERATED__DDSENABLERTESTTYPES_PUBSUBTYPES_HPP + diff --git a/ddsenabler_participants/test/types/DDSEnablerTestTypesTypeObjectSupport.cxx b/ddsenabler_participants/test/types/DDSEnablerTestTypesTypeObjectSupport.cxx new file mode 100644 index 00000000..fc805396 --- /dev/null +++ b/ddsenabler_participants/test/types/DDSEnablerTestTypesTypeObjectSupport.cxx @@ -0,0 +1,317 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DDSEnablerTestTypesTypeObjectSupport.cxx + * Source file containing the implementation to register the TypeObject representation of the described types in the IDL file + * + * This file was generated by the tool fastddsgen. + */ + +#include "DDSEnablerTestTypesTypeObjectSupport.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DDSEnablerTestTypes.hpp" + + +using namespace eprosima::fastdds::dds::xtypes; + +// TypeIdentifier is returned by reference: dependent structures/unions are registered in this same method +void register_DDSEnablerTestType1_type_identifier( + TypeIdentifierPair& type_ids_DDSEnablerTestType1) +{ + + ReturnCode_t return_code_DDSEnablerTestType1 {eprosima::fastdds::dds::RETCODE_OK}; + return_code_DDSEnablerTestType1 = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "DDSEnablerTestType1", type_ids_DDSEnablerTestType1); + if (eprosima::fastdds::dds::RETCODE_OK != return_code_DDSEnablerTestType1) + { + StructTypeFlag struct_flags_DDSEnablerTestType1 = TypeObjectUtils::build_struct_type_flag(eprosima::fastdds::dds::xtypes::ExtensibilityKind::APPENDABLE, + false, false); + QualifiedTypeName type_name_DDSEnablerTestType1 = "DDSEnablerTestType1"; + eprosima::fastcdr::optional type_ann_builtin_DDSEnablerTestType1; + eprosima::fastcdr::optional ann_custom_DDSEnablerTestType1; + CompleteTypeDetail detail_DDSEnablerTestType1 = TypeObjectUtils::build_complete_type_detail(type_ann_builtin_DDSEnablerTestType1, ann_custom_DDSEnablerTestType1, type_name_DDSEnablerTestType1.to_string()); + CompleteStructHeader header_DDSEnablerTestType1; + header_DDSEnablerTestType1 = TypeObjectUtils::build_complete_struct_header(TypeIdentifier(), detail_DDSEnablerTestType1); + CompleteStructMemberSeq member_seq_DDSEnablerTestType1; + { + TypeIdentifierPair type_ids_value; + ReturnCode_t return_code_value {eprosima::fastdds::dds::RETCODE_OK}; + return_code_value = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "_int16_t", type_ids_value); + + if (eprosima::fastdds::dds::RETCODE_OK != return_code_value) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "value Structure member TypeIdentifier unknown to TypeObjectRegistry."); + return; + } + StructMemberFlag member_flags_value = TypeObjectUtils::build_struct_member_flag(eprosima::fastdds::dds::xtypes::TryConstructFailAction::DISCARD, + false, false, false, false); + MemberId member_id_value = 0x00000000; + bool common_value_ec {false}; + CommonStructMember common_value {TypeObjectUtils::build_common_struct_member(member_id_value, member_flags_value, TypeObjectUtils::retrieve_complete_type_identifier(type_ids_value, common_value_ec))}; + if (!common_value_ec) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, "Structure value member TypeIdentifier inconsistent."); + return; + } + MemberName name_value = "value"; + eprosima::fastcdr::optional member_ann_builtin_value; + ann_custom_DDSEnablerTestType1.reset(); + CompleteMemberDetail detail_value = TypeObjectUtils::build_complete_member_detail(name_value, member_ann_builtin_value, ann_custom_DDSEnablerTestType1); + CompleteStructMember member_value = TypeObjectUtils::build_complete_struct_member(common_value, detail_value); + TypeObjectUtils::add_complete_struct_member(member_seq_DDSEnablerTestType1, member_value); + } + CompleteStructType struct_type_DDSEnablerTestType1 = TypeObjectUtils::build_complete_struct_type(struct_flags_DDSEnablerTestType1, header_DDSEnablerTestType1, member_seq_DDSEnablerTestType1); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_struct_type_object(struct_type_DDSEnablerTestType1, type_name_DDSEnablerTestType1.to_string(), type_ids_DDSEnablerTestType1)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "DDSEnablerTestType1 already registered in TypeObjectRegistry for a different type."); + } + } +} +// TypeIdentifier is returned by reference: dependent structures/unions are registered in this same method +void register_DDSEnablerTestType2_type_identifier( + TypeIdentifierPair& type_ids_DDSEnablerTestType2) +{ + + ReturnCode_t return_code_DDSEnablerTestType2 {eprosima::fastdds::dds::RETCODE_OK}; + return_code_DDSEnablerTestType2 = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "DDSEnablerTestType2", type_ids_DDSEnablerTestType2); + if (eprosima::fastdds::dds::RETCODE_OK != return_code_DDSEnablerTestType2) + { + StructTypeFlag struct_flags_DDSEnablerTestType2 = TypeObjectUtils::build_struct_type_flag(eprosima::fastdds::dds::xtypes::ExtensibilityKind::APPENDABLE, + false, false); + QualifiedTypeName type_name_DDSEnablerTestType2 = "DDSEnablerTestType2"; + eprosima::fastcdr::optional type_ann_builtin_DDSEnablerTestType2; + eprosima::fastcdr::optional ann_custom_DDSEnablerTestType2; + CompleteTypeDetail detail_DDSEnablerTestType2 = TypeObjectUtils::build_complete_type_detail(type_ann_builtin_DDSEnablerTestType2, ann_custom_DDSEnablerTestType2, type_name_DDSEnablerTestType2.to_string()); + CompleteStructHeader header_DDSEnablerTestType2; + header_DDSEnablerTestType2 = TypeObjectUtils::build_complete_struct_header(TypeIdentifier(), detail_DDSEnablerTestType2); + CompleteStructMemberSeq member_seq_DDSEnablerTestType2; + { + TypeIdentifierPair type_ids_value; + ReturnCode_t return_code_value {eprosima::fastdds::dds::RETCODE_OK}; + return_code_value = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "anonymous_string_unbounded", type_ids_value); + + if (eprosima::fastdds::dds::RETCODE_OK != return_code_value) + { + { + SBound bound = 0; + StringSTypeDefn string_sdefn = TypeObjectUtils::build_string_s_type_defn(bound); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_s_string_type_identifier(string_sdefn, + "anonymous_string_unbounded", type_ids_value)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "anonymous_string_unbounded already registered in TypeObjectRegistry for a different type."); + } + } + } + StructMemberFlag member_flags_value = TypeObjectUtils::build_struct_member_flag(eprosima::fastdds::dds::xtypes::TryConstructFailAction::DISCARD, + false, false, false, false); + MemberId member_id_value = 0x00000000; + bool common_value_ec {false}; + CommonStructMember common_value {TypeObjectUtils::build_common_struct_member(member_id_value, member_flags_value, TypeObjectUtils::retrieve_complete_type_identifier(type_ids_value, common_value_ec))}; + if (!common_value_ec) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, "Structure value member TypeIdentifier inconsistent."); + return; + } + MemberName name_value = "value"; + eprosima::fastcdr::optional member_ann_builtin_value; + ann_custom_DDSEnablerTestType2.reset(); + CompleteMemberDetail detail_value = TypeObjectUtils::build_complete_member_detail(name_value, member_ann_builtin_value, ann_custom_DDSEnablerTestType2); + CompleteStructMember member_value = TypeObjectUtils::build_complete_struct_member(common_value, detail_value); + TypeObjectUtils::add_complete_struct_member(member_seq_DDSEnablerTestType2, member_value); + } + CompleteStructType struct_type_DDSEnablerTestType2 = TypeObjectUtils::build_complete_struct_type(struct_flags_DDSEnablerTestType2, header_DDSEnablerTestType2, member_seq_DDSEnablerTestType2); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_struct_type_object(struct_type_DDSEnablerTestType2, type_name_DDSEnablerTestType2.to_string(), type_ids_DDSEnablerTestType2)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "DDSEnablerTestType2 already registered in TypeObjectRegistry for a different type."); + } + } +} +// TypeIdentifier is returned by reference: dependent structures/unions are registered in this same method +void register_DDSEnablerTestType3_type_identifier( + TypeIdentifierPair& type_ids_DDSEnablerTestType3) +{ + + ReturnCode_t return_code_DDSEnablerTestType3 {eprosima::fastdds::dds::RETCODE_OK}; + return_code_DDSEnablerTestType3 = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "DDSEnablerTestType3", type_ids_DDSEnablerTestType3); + if (eprosima::fastdds::dds::RETCODE_OK != return_code_DDSEnablerTestType3) + { + StructTypeFlag struct_flags_DDSEnablerTestType3 = TypeObjectUtils::build_struct_type_flag(eprosima::fastdds::dds::xtypes::ExtensibilityKind::APPENDABLE, + false, false); + QualifiedTypeName type_name_DDSEnablerTestType3 = "DDSEnablerTestType3"; + eprosima::fastcdr::optional type_ann_builtin_DDSEnablerTestType3; + eprosima::fastcdr::optional ann_custom_DDSEnablerTestType3; + CompleteTypeDetail detail_DDSEnablerTestType3 = TypeObjectUtils::build_complete_type_detail(type_ann_builtin_DDSEnablerTestType3, ann_custom_DDSEnablerTestType3, type_name_DDSEnablerTestType3.to_string()); + CompleteStructHeader header_DDSEnablerTestType3; + header_DDSEnablerTestType3 = TypeObjectUtils::build_complete_struct_header(TypeIdentifier(), detail_DDSEnablerTestType3); + CompleteStructMemberSeq member_seq_DDSEnablerTestType3; + { + TypeIdentifierPair type_ids_value; + ReturnCode_t return_code_value {eprosima::fastdds::dds::RETCODE_OK}; + return_code_value = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "anonymous_array_int32_t_10", type_ids_value); + + if (eprosima::fastdds::dds::RETCODE_OK != return_code_value) + { + return_code_value = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "_int32_t", type_ids_value); + + if (eprosima::fastdds::dds::RETCODE_OK != return_code_value) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "Array element TypeIdentifier unknown to TypeObjectRegistry."); + return; + } + bool element_identifier_anonymous_array_int32_t_10_ec {false}; + TypeIdentifier* element_identifier_anonymous_array_int32_t_10 {new TypeIdentifier(TypeObjectUtils::retrieve_complete_type_identifier(type_ids_value, element_identifier_anonymous_array_int32_t_10_ec))}; + if (!element_identifier_anonymous_array_int32_t_10_ec) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, "Array element TypeIdentifier inconsistent."); + return; + } + EquivalenceKind equiv_kind_anonymous_array_int32_t_10 = EK_COMPLETE; + if (TK_NONE == type_ids_value.type_identifier2()._d()) + { + equiv_kind_anonymous_array_int32_t_10 = EK_BOTH; + } + CollectionElementFlag element_flags_anonymous_array_int32_t_10 = 0; + PlainCollectionHeader header_anonymous_array_int32_t_10 = TypeObjectUtils::build_plain_collection_header(equiv_kind_anonymous_array_int32_t_10, element_flags_anonymous_array_int32_t_10); + { + SBoundSeq array_bound_seq; + TypeObjectUtils::add_array_dimension(array_bound_seq, static_cast(10)); + + PlainArraySElemDefn array_sdefn = TypeObjectUtils::build_plain_array_s_elem_defn(header_anonymous_array_int32_t_10, array_bound_seq, + eprosima::fastcdr::external(element_identifier_anonymous_array_int32_t_10)); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_s_array_type_identifier(array_sdefn, "anonymous_array_int32_t_10", type_ids_value)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "anonymous_array_int32_t_10 already registered in TypeObjectRegistry for a different type."); + } + } + } + StructMemberFlag member_flags_value = TypeObjectUtils::build_struct_member_flag(eprosima::fastdds::dds::xtypes::TryConstructFailAction::DISCARD, + false, false, false, false); + MemberId member_id_value = 0x00000000; + bool common_value_ec {false}; + CommonStructMember common_value {TypeObjectUtils::build_common_struct_member(member_id_value, member_flags_value, TypeObjectUtils::retrieve_complete_type_identifier(type_ids_value, common_value_ec))}; + if (!common_value_ec) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, "Structure value member TypeIdentifier inconsistent."); + return; + } + MemberName name_value = "value"; + eprosima::fastcdr::optional member_ann_builtin_value; + ann_custom_DDSEnablerTestType3.reset(); + CompleteMemberDetail detail_value = TypeObjectUtils::build_complete_member_detail(name_value, member_ann_builtin_value, ann_custom_DDSEnablerTestType3); + CompleteStructMember member_value = TypeObjectUtils::build_complete_struct_member(common_value, detail_value); + TypeObjectUtils::add_complete_struct_member(member_seq_DDSEnablerTestType3, member_value); + } + CompleteStructType struct_type_DDSEnablerTestType3 = TypeObjectUtils::build_complete_struct_type(struct_flags_DDSEnablerTestType3, header_DDSEnablerTestType3, member_seq_DDSEnablerTestType3); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_struct_type_object(struct_type_DDSEnablerTestType3, type_name_DDSEnablerTestType3.to_string(), type_ids_DDSEnablerTestType3)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "DDSEnablerTestType3 already registered in TypeObjectRegistry for a different type."); + } + } +} +// TypeIdentifier is returned by reference: dependent structures/unions are registered in this same method +void register_DDSEnablerTestType4_type_identifier( + TypeIdentifierPair& type_ids_DDSEnablerTestType4) +{ + + ReturnCode_t return_code_DDSEnablerTestType4 {eprosima::fastdds::dds::RETCODE_OK}; + return_code_DDSEnablerTestType4 = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "DDSEnablerTestType4", type_ids_DDSEnablerTestType4); + if (eprosima::fastdds::dds::RETCODE_OK != return_code_DDSEnablerTestType4) + { + StructTypeFlag struct_flags_DDSEnablerTestType4 = TypeObjectUtils::build_struct_type_flag(eprosima::fastdds::dds::xtypes::ExtensibilityKind::APPENDABLE, + false, false); + QualifiedTypeName type_name_DDSEnablerTestType4 = "DDSEnablerTestType4"; + eprosima::fastcdr::optional type_ann_builtin_DDSEnablerTestType4; + eprosima::fastcdr::optional ann_custom_DDSEnablerTestType4; + CompleteTypeDetail detail_DDSEnablerTestType4 = TypeObjectUtils::build_complete_type_detail(type_ann_builtin_DDSEnablerTestType4, ann_custom_DDSEnablerTestType4, type_name_DDSEnablerTestType4.to_string()); + CompleteStructHeader header_DDSEnablerTestType4; + header_DDSEnablerTestType4 = TypeObjectUtils::build_complete_struct_header(TypeIdentifier(), detail_DDSEnablerTestType4); + CompleteStructMemberSeq member_seq_DDSEnablerTestType4; + { + TypeIdentifierPair type_ids_value; + ReturnCode_t return_code_value {eprosima::fastdds::dds::RETCODE_OK}; + return_code_value = + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->type_object_registry().get_type_identifiers( + "DDSEnablerTestType1", type_ids_value); + + if (eprosima::fastdds::dds::RETCODE_OK != return_code_value) + { + ::register_DDSEnablerTestType1_type_identifier(type_ids_value); + } + StructMemberFlag member_flags_value = TypeObjectUtils::build_struct_member_flag(eprosima::fastdds::dds::xtypes::TryConstructFailAction::DISCARD, + false, false, false, false); + MemberId member_id_value = 0x00000000; + bool common_value_ec {false}; + CommonStructMember common_value {TypeObjectUtils::build_common_struct_member(member_id_value, member_flags_value, TypeObjectUtils::retrieve_complete_type_identifier(type_ids_value, common_value_ec))}; + if (!common_value_ec) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, "Structure value member TypeIdentifier inconsistent."); + return; + } + MemberName name_value = "value"; + eprosima::fastcdr::optional member_ann_builtin_value; + ann_custom_DDSEnablerTestType4.reset(); + CompleteMemberDetail detail_value = TypeObjectUtils::build_complete_member_detail(name_value, member_ann_builtin_value, ann_custom_DDSEnablerTestType4); + CompleteStructMember member_value = TypeObjectUtils::build_complete_struct_member(common_value, detail_value); + TypeObjectUtils::add_complete_struct_member(member_seq_DDSEnablerTestType4, member_value); + } + CompleteStructType struct_type_DDSEnablerTestType4 = TypeObjectUtils::build_complete_struct_type(struct_flags_DDSEnablerTestType4, header_DDSEnablerTestType4, member_seq_DDSEnablerTestType4); + if (eprosima::fastdds::dds::RETCODE_BAD_PARAMETER == + TypeObjectUtils::build_and_register_struct_type_object(struct_type_DDSEnablerTestType4, type_name_DDSEnablerTestType4.to_string(), type_ids_DDSEnablerTestType4)) + { + EPROSIMA_LOG_ERROR(XTYPES_TYPE_REPRESENTATION, + "DDSEnablerTestType4 already registered in TypeObjectRegistry for a different type."); + } + } +} + diff --git a/ddsenabler_participants/test/types/DDSEnablerTestTypesTypeObjectSupport.hpp b/ddsenabler_participants/test/types/DDSEnablerTestTypesTypeObjectSupport.hpp new file mode 100644 index 00000000..e93f69f2 --- /dev/null +++ b/ddsenabler_participants/test/types/DDSEnablerTestTypesTypeObjectSupport.hpp @@ -0,0 +1,92 @@ +// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*! + * @file DDSEnablerTestTypesTypeObjectSupport.hpp + * Header file containing the API required to register the TypeObject representation of the described types in the IDL file + * + * This file was generated by the tool fastddsgen. + */ + +#ifndef FAST_DDS_GENERATED__DDSENABLERTESTTYPES_TYPE_OBJECT_SUPPORT_HPP +#define FAST_DDS_GENERATED__DDSENABLERTESTTYPES_TYPE_OBJECT_SUPPORT_HPP + +#include + + +#if defined(_WIN32) +#if defined(EPROSIMA_USER_DLL_EXPORT) +#define eProsima_user_DllExport __declspec( dllexport ) +#else +#define eProsima_user_DllExport +#endif // EPROSIMA_USER_DLL_EXPORT +#else +#define eProsima_user_DllExport +#endif // _WIN32 + +#ifndef DOXYGEN_SHOULD_SKIP_THIS_PUBLIC + +/** + * @brief Register DDSEnablerTestType1 related TypeIdentifier. + * Fully-descriptive TypeIdentifiers are directly registered. + * Hash TypeIdentifiers require to fill the TypeObject information and hash it, consequently, the TypeObject is + * indirectly registered as well. + * + * @param[out] TypeIdentifier of the registered type. + * The returned TypeIdentifier corresponds to the complete TypeIdentifier in case of hashed TypeIdentifiers. + * Invalid TypeIdentifier is returned in case of error. + */ +eProsima_user_DllExport void register_DDSEnablerTestType1_type_identifier( + eprosima::fastdds::dds::xtypes::TypeIdentifierPair& type_ids); +/** + * @brief Register DDSEnablerTestType2 related TypeIdentifier. + * Fully-descriptive TypeIdentifiers are directly registered. + * Hash TypeIdentifiers require to fill the TypeObject information and hash it, consequently, the TypeObject is + * indirectly registered as well. + * + * @param[out] TypeIdentifier of the registered type. + * The returned TypeIdentifier corresponds to the complete TypeIdentifier in case of hashed TypeIdentifiers. + * Invalid TypeIdentifier is returned in case of error. + */ +eProsima_user_DllExport void register_DDSEnablerTestType2_type_identifier( + eprosima::fastdds::dds::xtypes::TypeIdentifierPair& type_ids); +/** + * @brief Register DDSEnablerTestType3 related TypeIdentifier. + * Fully-descriptive TypeIdentifiers are directly registered. + * Hash TypeIdentifiers require to fill the TypeObject information and hash it, consequently, the TypeObject is + * indirectly registered as well. + * + * @param[out] TypeIdentifier of the registered type. + * The returned TypeIdentifier corresponds to the complete TypeIdentifier in case of hashed TypeIdentifiers. + * Invalid TypeIdentifier is returned in case of error. + */ +eProsima_user_DllExport void register_DDSEnablerTestType3_type_identifier( + eprosima::fastdds::dds::xtypes::TypeIdentifierPair& type_ids); +/** + * @brief Register DDSEnablerTestType4 related TypeIdentifier. + * Fully-descriptive TypeIdentifiers are directly registered. + * Hash TypeIdentifiers require to fill the TypeObject information and hash it, consequently, the TypeObject is + * indirectly registered as well. + * + * @param[out] TypeIdentifier of the registered type. + * The returned TypeIdentifier corresponds to the complete TypeIdentifier in case of hashed TypeIdentifiers. + * Invalid TypeIdentifier is returned in case of error. + */ +eProsima_user_DllExport void register_DDSEnablerTestType4_type_identifier( + eprosima::fastdds::dds::xtypes::TypeIdentifierPair& type_ids); + + +#endif // DOXYGEN_SHOULD_SKIP_THIS_PUBLIC + +#endif // FAST_DDS_GENERATED__DDSENABLERTESTTYPES_TYPE_OBJECT_SUPPORT_HPP diff --git a/ddsenabler_test/compose/CMakeLists.txt b/ddsenabler_test/compose/CMakeLists.txt index 9f319434..f855833b 100644 --- a/ddsenabler_test/compose/CMakeLists.txt +++ b/ddsenabler_test/compose/CMakeLists.txt @@ -14,8 +14,10 @@ # Name of files to test set(TESTS - topics_yaml - topics_json + publish/discovered_type + publish/requested_type + reception/topics_json + reception/topics_yaml ) file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test_cases DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/ddsenabler_test/compose/scripts/execute_and_validate_listener.py b/ddsenabler_test/compose/scripts/execute_and_validate_listener.py index bcc7f24c..5a628bf6 100644 --- a/ddsenabler_test/compose/scripts/execute_and_validate_listener.py +++ b/ddsenabler_test/compose/scripts/execute_and_validate_listener.py @@ -35,6 +35,12 @@ def parse_options(): description=(DESCRIPTION), usage=(USAGE) ) + parser.add_argument( + '-s', + '--samples', + type=int, + help='Samples to receive.' + ) parser.add_argument( '-t', '--timeout', @@ -72,7 +78,7 @@ def _listener_command(args): """ command = [ 'python3', - '/opt/ros/humble/lib/demo_nodes_py/listener'] + '/opt/ros/jazzy/lib/demo_nodes_py/listener'] return command @@ -112,6 +118,31 @@ def _listener_validate_duplicates(stdout_parsed, stderr_parsed): return ret +def _listener_validate( + stdout_parsed, + stderr_parsed, + samples, + duplicates_allow): + + # Check default validator + ret_code = validation.validate_default(stdout_parsed, stderr_parsed) + + if duplicates_allow != -1: + duplicated_n = len(validation.find_duplicates(stdout_parsed)) + if duplicated_n > duplicates_allow: + log.logger.error( + f'{duplicated_n} duplicated messages found. ' + f'Maximum allowed {duplicates_allow}.') + return validation.ReturnCode.NOT_VALID_MESSAGES + + if samples is not None and len(stdout_parsed) != samples: + log.logger.error(f'Number of messages received: {len(stdout_parsed)}. ' + f'Expected {samples}') + return validation.ReturnCode.NOT_VALID_MESSAGES + + return ret_code + + if __name__ == '__main__': # Parse arguments @@ -124,11 +155,13 @@ def _listener_validate_duplicates(stdout_parsed, stderr_parsed): # Prepare command command = _listener_command(args) - _listener_validate_function = None - if args.allow_duplicates: - _listener_validate_function = _listener_validate_duplicates - else: - _listener_validate_function = validation.validate_default + validate_func = (lambda stdout_parsed, stderr_parsed: ( + _listener_validate( + stdout_parsed=stdout_parsed, + stderr_parsed=stderr_parsed, + samples=args.samples, + duplicates_allow=args.allow_duplicates + ))) # Run command and validate ret_code = validation.run_and_validate( @@ -136,9 +169,9 @@ def _listener_validate_duplicates(stdout_parsed, stderr_parsed): timeout=args.timeout, delay=args.delay, parse_output_function=_listener_parse_output, - validate_output_function=_listener_validate_function, + validate_output_function=validate_func, timeout_as_error=False) - print(f'listener validator exited with code {ret_code}') + log.logger.info(f'listener validator exited with code {ret_code}') exit(ret_code.value) diff --git a/ddsenabler_test/compose/scripts/execute_and_validate_subscriber.py b/ddsenabler_test/compose/scripts/execute_and_validate_subscriber.py index e549fd3f..aac603b1 100644 --- a/ddsenabler_test/compose/scripts/execute_and_validate_subscriber.py +++ b/ddsenabler_test/compose/scripts/execute_and_validate_subscriber.py @@ -176,7 +176,7 @@ def _subscriber_validate( ret_code = validation.validate_default(stdout_parsed['messages'], stderr_parsed) if duplicates_allow != -1: - duplicated_n = len(find_duplicates(stdout_parsed['messages'])) + duplicated_n = len(validation.find_duplicates(stdout_parsed['messages'])) if duplicated_n > duplicates_allow: log.logger.error( f'{duplicated_n} duplicated messages found. ' @@ -208,31 +208,6 @@ def _subscriber_validate( return ret_code -def find_duplicates(data): - """ - Find duplicates in a list os strings. - - :param data: List of strings - :return: List of tuples with the index of the duplicated strings - """ - # TODO: add more logic so duplicated allow are only first messages - duplicates = [] - lines_seen = {} - - for idx, line in enumerate(data): - if line not in lines_seen: - lines_seen[line] = idx - else: - duplicates.append((lines_seen[line], idx)) - - if duplicates: - log.logger.info('Found duplicated messages') - else: - log.logger.debug('None duplicated messages found') - - return duplicates - - def check_transient(data): """ Check that messages go from 0 to N without gaps. diff --git a/ddsenabler_test/compose/scripts/execute_and_validate_talker.py b/ddsenabler_test/compose/scripts/execute_and_validate_talker.py index e635f295..7ef698af 100644 --- a/ddsenabler_test/compose/scripts/execute_and_validate_talker.py +++ b/ddsenabler_test/compose/scripts/execute_and_validate_talker.py @@ -67,7 +67,7 @@ def _talker_command(args): """ command = [ 'python3', - '/opt/ros/humble/lib/demo_nodes_py/talker'] + '/opt/ros/jazzy/lib/demo_nodes_py/talker'] return command diff --git a/ddsenabler_test/compose/test_cases/publish/discovered_type/compose.yml b/ddsenabler_test/compose/test_cases/publish/discovered_type/compose.yml new file mode 100644 index 00000000..4e6a437f --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/discovered_type/compose.yml @@ -0,0 +1,40 @@ +# Test description: +# expected_types = 1 +# expected_topics = 1 +# timeout = 5 +# config_file_path_: allowed only /chatter topic +# This test case checks the DDS Enabler is able to publish data in a topic that has previously been discovered. +# The DDS Enabler is created after the listener, and before the first message is published an active wait of 2 +# seconds is introduced to let the enabler receive the topic and type information from the listener. +# It is checked that the listener receives all messages (guaranteed by reliable reliability QoS, which is ROS 2 default). + +services: + + # ENABLER + ddsenabler: + image: ${DDSENABLER_COMPOSE_TEST_DOCKER_IMAGE} + container_name: ddsenabler + depends_on: + - listener # Ensure listener is ready before ddsenabler starts so it can discover the type + networks: + - std_net + volumes: + - ./config.yml:/config/config.yml + - ./samples:/samples + command: ./build/ddsenabler/examples/ddsenabler_example --config /config/config.yml --timeout 5 --expected-types 1 --expected-topics 1 --publish-path /samples --publish-topic rt/chatter --publish-period 200 --publish-initial-wait 2000 + + listener: + image: ${DDSENABLER_COMPOSE_TEST_ROS2_DOCKER_IMAGE} + container_name: listener + networks: + - std_net + environment: + - ROS_DOMAIN_ID=33 + volumes: + - ../../../scripts:/scripts + command: python3 /scripts/execute_and_validate_listener.py --timeout 5 --samples 5 + +networks: + std_net: + default: + driver: none diff --git a/ddsenabler_test/compose/test_cases/publish/discovered_type/config.yml b/ddsenabler_test/compose/test_cases/publish/discovered_type/config.yml new file mode 100644 index 00000000..29663de6 --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/discovered_type/config.yml @@ -0,0 +1,5 @@ +dds: + domain: 33 + + allowlist: + - name: "rt/chatter" diff --git a/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/1 b/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/1 new file mode 100644 index 00000000..2f813e6c --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/1 @@ -0,0 +1,3 @@ +{ + "data": "Hello World: 1" +} diff --git a/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/2 b/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/2 new file mode 100644 index 00000000..35641d7f --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/2 @@ -0,0 +1,3 @@ +{ + "data": "Hello World: 2" +} diff --git a/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/3 b/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/3 new file mode 100644 index 00000000..cae03a51 --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/3 @@ -0,0 +1,3 @@ +{ + "data": "Hello World: 3" +} diff --git a/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/4 b/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/4 new file mode 100644 index 00000000..112b310d --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/4 @@ -0,0 +1,3 @@ +{ + "data": "Hello World: 4" +} diff --git a/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/5 b/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/5 new file mode 100644 index 00000000..5c53f169 --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/discovered_type/samples/5 @@ -0,0 +1,3 @@ +{ + "data": "Hello World: 5" +} diff --git a/ddsenabler_test/compose/test_cases/publish/requested_type/compose.yml b/ddsenabler_test/compose/test_cases/publish/requested_type/compose.yml new file mode 100644 index 00000000..ef716078 --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/requested_type/compose.yml @@ -0,0 +1,35 @@ +# Test description: +# This test case checks the DDS Enabler is able to publish data in an unknown topic. +# The topic and type information is requested to the user through callbacks. +# The subscriber is created after the DDS Enabler has published all data. +# It is checked that the subscriber receives all messages (guaranteed by reliable reliability and transient local durability QoS). + +services: + + # ENABLER + ddsenabler: + image: ${DDSENABLER_COMPOSE_TEST_DOCKER_IMAGE} + container_name: ddsenabler + networks: + - std_net + volumes: + - ./config.yml:/config/config.yml + - ./samples:/samples + - ./persistence:/persistence + command: ./build/ddsenabler/examples/ddsenabler_example --config /config/config.yml --timeout 5 --publish-path /samples --publish-topic test_topic --publish-period 200 --persistence-path /persistence + + subscriber: + image: ${DDSENABLER_COMPOSE_TEST_DOCKER_IMAGE} + container_name: subscriber + depends_on: + - ddsenabler + networks: + - std_net + volumes: + - ../../../scripts:/scripts + command: sh -c "sleep 1 && python3 /scripts/execute_and_validate_subscriber.py --exe build/fastdds_configuration_example/configuration --samples 5 --timeout 4 --args '--samples 5 --domain 33 --name test_topic --reliable --transient-local --keep-all'" + +networks: + std_net: + default: + driver: none diff --git a/ddsenabler_test/compose/test_cases/publish/requested_type/config.yml b/ddsenabler_test/compose/test_cases/publish/requested_type/config.yml new file mode 100644 index 00000000..f21cb3c3 --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/requested_type/config.yml @@ -0,0 +1,9 @@ +dds: + domain: 33 + + topics: + - name: "test_topic" + type: "Configuration" + qos: + reliability: true + durability: true diff --git a/ddsenabler_test/compose/test_cases/publish/requested_type/persistence/topics/test_topic.bin b/ddsenabler_test/compose/test_cases/publish/requested_type/persistence/topics/test_topic.bin new file mode 100644 index 00000000..b8a97d01 Binary files /dev/null and b/ddsenabler_test/compose/test_cases/publish/requested_type/persistence/topics/test_topic.bin differ diff --git a/ddsenabler_test/compose/test_cases/publish/requested_type/persistence/types/Configuration.bin b/ddsenabler_test/compose/test_cases/publish/requested_type/persistence/types/Configuration.bin new file mode 100644 index 00000000..b289339d Binary files /dev/null and b/ddsenabler_test/compose/test_cases/publish/requested_type/persistence/types/Configuration.bin differ diff --git a/ddsenabler_test/compose/test_cases/publish/requested_type/samples/1 b/ddsenabler_test/compose/test_cases/publish/requested_type/samples/1 new file mode 100644 index 00000000..82d441ea --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/requested_type/samples/1 @@ -0,0 +1,37 @@ +{ + "data": [ + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170 + ], + "index": 1, + "message": [ + "C", + "o", + "n", + "f", + "i", + "g", + "u", + "r", + "a", + "t", + "i", + "o", + "n", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000" + ] +} diff --git a/ddsenabler_test/compose/test_cases/publish/requested_type/samples/2 b/ddsenabler_test/compose/test_cases/publish/requested_type/samples/2 new file mode 100644 index 00000000..9ec200cc --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/requested_type/samples/2 @@ -0,0 +1,37 @@ +{ + "data": [ + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170 + ], + "index": 2, + "message": [ + "C", + "o", + "n", + "f", + "i", + "g", + "u", + "r", + "a", + "t", + "i", + "o", + "n", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000" + ] +} diff --git a/ddsenabler_test/compose/test_cases/publish/requested_type/samples/3 b/ddsenabler_test/compose/test_cases/publish/requested_type/samples/3 new file mode 100644 index 00000000..f03f9120 --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/requested_type/samples/3 @@ -0,0 +1,37 @@ +{ + "data": [ + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170 + ], + "index": 3, + "message": [ + "C", + "o", + "n", + "f", + "i", + "g", + "u", + "r", + "a", + "t", + "i", + "o", + "n", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000" + ] +} diff --git a/ddsenabler_test/compose/test_cases/publish/requested_type/samples/4 b/ddsenabler_test/compose/test_cases/publish/requested_type/samples/4 new file mode 100644 index 00000000..b18ff443 --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/requested_type/samples/4 @@ -0,0 +1,37 @@ +{ + "data": [ + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170 + ], + "index": 4, + "message": [ + "C", + "o", + "n", + "f", + "i", + "g", + "u", + "r", + "a", + "t", + "i", + "o", + "n", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000" + ] +} diff --git a/ddsenabler_test/compose/test_cases/publish/requested_type/samples/5 b/ddsenabler_test/compose/test_cases/publish/requested_type/samples/5 new file mode 100644 index 00000000..417e5157 --- /dev/null +++ b/ddsenabler_test/compose/test_cases/publish/requested_type/samples/5 @@ -0,0 +1,37 @@ +{ + "data": [ + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170, + 170 + ], + "index": 5, + "message": [ + "C", + "o", + "n", + "f", + "i", + "g", + "u", + "r", + "a", + "t", + "i", + "o", + "n", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000", + "\u0000" + ] +} diff --git a/ddsenabler_test/compose/test_cases/reception/topics_json/compose.yml b/ddsenabler_test/compose/test_cases/reception/topics_json/compose.yml new file mode 100644 index 00000000..4d80171b --- /dev/null +++ b/ddsenabler_test/compose/test_cases/reception/topics_json/compose.yml @@ -0,0 +1,39 @@ +# Test description: +# expected_types = 1 +# expected_topics = 1 +# expected_data = 1 +# timeout = 6 +# config_file_path_: allowed only /chatter topic +# This test case checks the DDS Enabler, configured with a JSON file, receives only the chatter topic. +# The chatter topic is published ROS2 domain 1 with 1 Hz rate. +# It is checked that at least 3 messages are received in at most 6 seconds. + +services: + + # ENABLER + ddsenabler: + image: ${DDSENABLER_COMPOSE_TEST_DOCKER_IMAGE} + container_name: ddsenabler + networks: + - std_net + volumes: + - ./config.json:/config/config.json + command: ./build/ddsenabler/examples/ddsenabler_example --config /config/config.json --expected-types 1 --expected-topics 1 --expected-data 3 --timeout 6 + + talker: + image: ${DDSENABLER_COMPOSE_TEST_ROS2_DOCKER_IMAGE} + container_name: talker + depends_on: + - ddsenabler + networks: + - std_net + environment: + - ROS_DOMAIN_ID=1 + volumes: + - ../../../scripts:/scripts + command: python3 /scripts/execute_and_validate_talker.py --timeout 6 --delay 1 + +networks: + std_net: + default: + driver: none diff --git a/ddsenabler_test/compose/test_cases/topics_json/config.json b/ddsenabler_test/compose/test_cases/reception/topics_json/config.json similarity index 92% rename from ddsenabler_test/compose/test_cases/topics_json/config.json rename to ddsenabler_test/compose/test_cases/reception/topics_json/config.json index 0214a830..7637a2fa 100644 --- a/ddsenabler_test/compose/test_cases/topics_json/config.json +++ b/ddsenabler_test/compose/test_cases/reception/topics_json/config.json @@ -18,7 +18,9 @@ } ] }, - "ddsenabler": null, + "ddsenabler": { + "initial-publish-wait": 500 + }, "specs": { "threads": 12, "logging": { diff --git a/ddsenabler_test/compose/test_cases/reception/topics_yaml/compose.yml b/ddsenabler_test/compose/test_cases/reception/topics_yaml/compose.yml new file mode 100644 index 00000000..fb0739e0 --- /dev/null +++ b/ddsenabler_test/compose/test_cases/reception/topics_yaml/compose.yml @@ -0,0 +1,39 @@ +# Test description: +# expected_types = 1 +# expected_topics = 1 +# expected_data = 1 +# timeout = 6 +# config_file_path_: allowed only /chatter topic +# This test case checks the DDS Enabler, configured with a YAML file, receives only the chatter topic. +# The chatter topic is published ROS2 domain 2 with 1 Hz rate. +# It is checked that at least 3 messages are received in at most 6 seconds. + +services: + + # ENABLER + ddsenabler: + image: ${DDSENABLER_COMPOSE_TEST_DOCKER_IMAGE} + container_name: ddsenabler + networks: + - std_net + volumes: + - ./config.yml:/config/config.yml + command: ./build/ddsenabler/examples/ddsenabler_example --config /config/config.yml --expected-types 1 --expected-topics 1 --expected-data 3 --timeout 6 + + talker: + image: ${DDSENABLER_COMPOSE_TEST_ROS2_DOCKER_IMAGE} + container_name: talker + depends_on: + - ddsenabler + networks: + - std_net + environment: + - ROS_DOMAIN_ID=2 + volumes: + - ../../../scripts:/scripts + command: python3 /scripts/execute_and_validate_talker.py --timeout 6 --delay 1 + +networks: + std_net: + default: + driver: none diff --git a/ddsenabler_test/compose/test_cases/topics_yaml/config.yml b/ddsenabler_test/compose/test_cases/reception/topics_yaml/config.yml similarity index 100% rename from ddsenabler_test/compose/test_cases/topics_yaml/config.yml rename to ddsenabler_test/compose/test_cases/reception/topics_yaml/config.yml diff --git a/ddsenabler_test/compose/test_cases/topics_json/compose.yml b/ddsenabler_test/compose/test_cases/topics_json/compose.yml deleted file mode 100644 index 0c757ee2..00000000 --- a/ddsenabler_test/compose/test_cases/topics_json/compose.yml +++ /dev/null @@ -1,37 +0,0 @@ -# Test description: -# expected_types_ = 1 -# expected_data_ = 1 -# timeout_seconds = 10 -# config_file_path_: allowed only /chatter topic -# This test case checks the DDS Enabler receives only the chatter topic -# which publishes only 1 msg in ROS2 domain 1. - -services: - - # ENABLER - ddsenabler: - image: ${DDSENABLER_COMPOSE_TEST_DOCKER_IMAGE} - container_name: ddsenabler - networks: - - std_net - volumes: - - ./config.json:/config/config.json - command: ./build/ddsenabler/examples/ddsenabler_example 1 1 10 /config/config.json - - talker: - image: ${DDSENABLER_COMPOSE_TEST_ROS2_DOCKER_IMAGE} - container_name: talker - depends_on: - - ddsenabler - networks: - - std_net - environment: - - ROS_DOMAIN_ID=1 - volumes: - - ../../scripts:/scripts - command: ros2 topic pub /chatter std_msgs/msg/String "{}" --once --spin-time 3 - -networks: - std_net: - default: - driver: none diff --git a/ddsenabler_test/compose/test_cases/topics_yaml/compose.yml b/ddsenabler_test/compose/test_cases/topics_yaml/compose.yml deleted file mode 100644 index 4db0aeed..00000000 --- a/ddsenabler_test/compose/test_cases/topics_yaml/compose.yml +++ /dev/null @@ -1,37 +0,0 @@ -# Test description: -# expected_types_ = 1 -# expected_data_ = 1 -# timeout_seconds = 10 -# config_file_path_: allowed only /chatter topic -# This test case checks the DDS Enabler receives only the chatter topic -# which publishes only 1 msg in ROS2 domain 0. - -services: - - # ENABLER - ddsenabler: - image: ${DDSENABLER_COMPOSE_TEST_DOCKER_IMAGE} - container_name: ddsenabler - networks: - - std_net - volumes: - - ./config.yml:/config/config.yml - command: ./build/ddsenabler/examples/ddsenabler_example 1 1 10 /config/config.yml - - talker: - image: ${DDSENABLER_COMPOSE_TEST_ROS2_DOCKER_IMAGE} - container_name: talker - depends_on: - - ddsenabler - networks: - - std_net - environment: - - ROS_DOMAIN_ID=2 - volumes: - - ../../scripts:/scripts - command: ros2 topic pub /chatter std_msgs/msg/String "{}" --once --spin-time 3 - -networks: - std_net: - default: - driver: none diff --git a/ddsenabler_test/package.xml b/ddsenabler_test/package.xml index d64b3671..14cba5ac 100644 --- a/ddsenabler_test/package.xml +++ b/ddsenabler_test/package.xml @@ -4,7 +4,7 @@ ddsenabler_test 0.1.0 - *eprosima DDS Enabler* main C++ package. + *eprosima DDS Enabler* system tests package. Raul Sánchez-Mateos Eugenio Collado diff --git a/ddsenabler_yaml/README.md b/ddsenabler_yaml/README.md deleted file mode 100644 index 266dc745..00000000 --- a/ddsenabler_yaml/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# eProsima DDS Enabler Yaml Module - -This library implements the required functions to translate a DDS Enabler configuration written in *yaml* -format into C++ source code. -It is powered by `yaml-cpp` library. - -It provides methods: - -- to create every type of object from a *yaml* node, -- to read a *yaml* file, and -- to interact with a *yaml* object using `YAML::Node` class from `yaml-cpp`. - ---- - -## Example of usage - -```cpp -// LOAD DDS ENABLER CONFIGURATION FROM FILE -eprosima::ddsenabler::yaml::EnablerConfiguration configuration("configuration.yaml"); - -``` - ---- - -## Dependencies - -* `yaml-cpp` -* `cpp_utils` -* `ddspipe_core` -* `ddspipe_participants` -* `ddspipe_yaml` -* `ddsenabler_participants` - ---- - -## How to use it in your project - -Just import library `ddsenabler_yaml` into your CMake project. - -```cmake -find_package(ddsenabler_yaml) -target_link_libraries(${LIBRARY_TARGET_NAME} ddsenabler_yaml) -``` diff --git a/ddsenabler_yaml/include/ddsenabler_yaml/EnablerConfiguration.hpp b/ddsenabler_yaml/include/ddsenabler_yaml/EnablerConfiguration.hpp index 000df681..769837c6 100644 --- a/ddsenabler_yaml/include/ddsenabler_yaml/EnablerConfiguration.hpp +++ b/ddsenabler_yaml/include/ddsenabler_yaml/EnablerConfiguration.hpp @@ -27,9 +27,10 @@ #include #include -#include #include +#include + #include #include @@ -67,7 +68,7 @@ class EnablerConfiguration // Participants configurations std::shared_ptr simple_configuration; - std::shared_ptr enabler_configuration; + std::shared_ptr enabler_configuration; unsigned int n_threads = DEFAULT_N_THREADS; @@ -75,25 +76,25 @@ class EnablerConfiguration protected: - void load_ddsenabler_configuration( + void load_ddsenabler_configuration_( const Yaml& yml); - void load_enabler_configuration( + void load_enabler_configuration_( const Yaml& yml, const ddspipe::yaml::YamlReaderVersion& version); - void load_specs_configuration( + void load_specs_configuration_( const Yaml& yml, const ddspipe::yaml::YamlReaderVersion& version); - void load_dds_configuration( + void load_dds_configuration_( const Yaml& yml, const ddspipe::yaml::YamlReaderVersion& version); - void load_ddsenabler_configuration_from_yaml_file( + void load_ddsenabler_configuration_from_yaml_file_( const std::string& file_path); - void load_ddsenabler_configuration_from_json_file( + void load_ddsenabler_configuration_from_json_file_( const std::string& file_path); }; diff --git a/ddsenabler_yaml/include/ddsenabler_yaml/yaml_configuration_tags.hpp b/ddsenabler_yaml/include/ddsenabler_yaml/yaml_configuration_tags.hpp index b3d43c4c..33cc85ef 100644 --- a/ddsenabler_yaml/include/ddsenabler_yaml/yaml_configuration_tags.hpp +++ b/ddsenabler_yaml/include/ddsenabler_yaml/yaml_configuration_tags.hpp @@ -27,6 +27,7 @@ namespace yaml { constexpr const char* ENABLER_DDS_TAG("dds"); constexpr const char* ENABLER_ENABLER_TAG("ddsenabler"); +constexpr const char* ENABLER_INITIAL_PUBLISH_WAIT_TAG("initial-publish-wait"); } /* namespace yaml */ } /* namespace ddsenabler */ diff --git a/ddsenabler_yaml/src/cpp/EnablerConfiguration.cpp b/ddsenabler_yaml/src/cpp/EnablerConfiguration.cpp index 11daf37a..bbd5d3f9 100644 --- a/ddsenabler_yaml/src/cpp/EnablerConfiguration.cpp +++ b/ddsenabler_yaml/src/cpp/EnablerConfiguration.cpp @@ -35,6 +35,7 @@ #include #include + #include namespace eprosima { @@ -115,7 +116,7 @@ YAML::Node convert_json_to_yaml( else { // Fallback for any other types (like null) - yaml_node[element.key()] = ""; + // Skip element to avoid exception when parsing YAML (YamlReader::is_tag_present expects non-null value) } } } @@ -128,8 +129,9 @@ EnablerConfiguration::EnablerConfiguration( { if (is_json(file_path)) { - load_ddsenabler_configuration_from_json_file(file_path); - } else + load_ddsenabler_configuration_from_json_file_(file_path); + } + else { if (file_path.size() >= 5 && (file_path.substr(file_path.size() - 5) == ".json" || @@ -138,14 +140,14 @@ EnablerConfiguration::EnablerConfiguration( EPROSIMA_LOG_WARNING(DDSENABLER_YAML, "Failed to parse JSON configuration, treating as YAML."); } - load_ddsenabler_configuration_from_yaml_file(file_path); + load_ddsenabler_configuration_from_yaml_file_(file_path); } } EnablerConfiguration::EnablerConfiguration( const Yaml& yml) { - load_ddsenabler_configuration(yml); + load_ddsenabler_configuration_(yml); } bool EnablerConfiguration::is_valid( @@ -154,7 +156,7 @@ bool EnablerConfiguration::is_valid( return true; } -void EnablerConfiguration::load_ddsenabler_configuration( +void EnablerConfiguration::load_ddsenabler_configuration_( const Yaml& yml) { try @@ -170,24 +172,19 @@ void EnablerConfiguration::load_ddsenabler_configuration( simple_configuration = std::make_shared(); simple_configuration->id = "SimpleEnablerParticipant"; simple_configuration->app_id = "DDS_ENABLER"; - simple_configuration->app_metadata = ""; - simple_configuration->is_repeater = false; ///// // Create Enabler Participant Configuration - enabler_configuration = std::make_shared(); + enabler_configuration = std::make_shared(); enabler_configuration->id = "EnablerEnablerParticipant"; enabler_configuration->app_id = "DDS_ENABLER"; - // TODO: fill metadata field once its content has been defined. - enabler_configuration->app_metadata = ""; - enabler_configuration->is_repeater = false; ///// // Get optional Enabler configuration options if (YamlReader::is_tag_present(yml, ENABLER_ENABLER_TAG)) { auto enabler_yml = YamlReader::get_value_in_tag(yml, ENABLER_ENABLER_TAG); - load_enabler_configuration(enabler_yml, version); + load_enabler_configuration_(enabler_yml, version); } ///// @@ -196,7 +193,7 @@ void EnablerConfiguration::load_ddsenabler_configuration( if (YamlReader::is_tag_present(yml, SPECS_TAG)) { auto specs_yml = YamlReader::get_value_in_tag(yml, SPECS_TAG); - load_specs_configuration(specs_yml, version); + load_specs_configuration_(specs_yml, version); } ///// @@ -204,7 +201,7 @@ void EnablerConfiguration::load_ddsenabler_configuration( if (YamlReader::is_tag_present(yml, ENABLER_DDS_TAG)) { auto dds_yml = YamlReader::get_value_in_tag(yml, ENABLER_DDS_TAG); - load_dds_configuration(dds_yml, version); + load_dds_configuration_(dds_yml, version); } // Block ROS 2 services (RPC) topics @@ -224,10 +221,13 @@ void EnablerConfiguration::load_ddsenabler_configuration( ddspipe_configuration.blocklist.insert( utils::Heritable::make_heritable(rpc_response_topic)); - ddspipe_configuration.init_enabled = true; + // Enable manually after all callbacks are set to avoid missing notifications + ddspipe_configuration.init_enabled = false; - // Only trigger the DdsPipe's callbacks when discovering or removing writers - ddspipe_configuration.discovery_trigger = DiscoveryTrigger::WRITER; + // Trigger discovery also with readers in order to enable the publish feature in their associated topics + // NOTE: discovering a reader is not a requirement for the publish feature, as the related type and topic can be + // requested to the user if the corresponding callbacks are set. + ddspipe_configuration.discovery_trigger = DiscoveryTrigger::ANY; } catch (const std::exception& e) { @@ -237,14 +237,19 @@ void EnablerConfiguration::load_ddsenabler_configuration( } -void EnablerConfiguration::load_enabler_configuration( +void EnablerConfiguration::load_enabler_configuration_( const Yaml& yml, const YamlReaderVersion& version) { - //Nothing to configure yet + // Get initial publish wait + if (YamlReader::is_tag_present(yml, ENABLER_INITIAL_PUBLISH_WAIT_TAG)) + { + enabler_configuration->initial_publish_wait = YamlReader::get_nonnegative_int(yml, + ENABLER_INITIAL_PUBLISH_WAIT_TAG); + } } -void EnablerConfiguration::load_specs_configuration( +void EnablerConfiguration::load_specs_configuration_( const Yaml& yml, const YamlReaderVersion& version) { @@ -263,7 +268,7 @@ void EnablerConfiguration::load_specs_configuration( } } -void EnablerConfiguration::load_dds_configuration( +void EnablerConfiguration::load_dds_configuration_( const Yaml& yml, const YamlReaderVersion& version) { @@ -336,7 +341,7 @@ void EnablerConfiguration::load_dds_configuration( } } -void EnablerConfiguration::load_ddsenabler_configuration_from_yaml_file( +void EnablerConfiguration::load_ddsenabler_configuration_from_yaml_file_( const std::string& file_path) { Yaml yml; @@ -359,10 +364,10 @@ void EnablerConfiguration::load_ddsenabler_configuration_from_yaml_file( EPROSIMA_LOG_WARNING(DDSENABLER_YAML, "No configuration file specified, using default values."); } - EnablerConfiguration::load_ddsenabler_configuration(yml); + EnablerConfiguration::load_ddsenabler_configuration_(yml); } -void EnablerConfiguration::load_ddsenabler_configuration_from_json_file( +void EnablerConfiguration::load_ddsenabler_configuration_from_json_file_( const std::string& file_path) { Yaml yml; @@ -375,7 +380,7 @@ void EnablerConfiguration::load_ddsenabler_configuration_from_json_file( if (!file.is_open()) { throw eprosima::utils::ConfigurationException( - utils::Formatter() << "Could not open JSON file"); + utils::Formatter() << "Could not open JSON file"); } // Parse the JSON file @@ -396,22 +401,22 @@ void EnablerConfiguration::load_ddsenabler_configuration_from_json_file( else { throw eprosima::utils::ConfigurationException( - utils::Formatter() << - "\"ddsmodule\" not found or is not an object within \"dds\" in the JSON file"); + utils::Formatter() << + "\"ddsmodule\" not found or is not an object within \"dds\" in the JSON file"); } } else { throw eprosima::utils::ConfigurationException( - utils::Formatter() << "\"dds\" not found or is not an object in the JSON file"); + utils::Formatter() << "\"dds\" not found or is not an object in the JSON file"); } } catch (const std::exception& e) { throw eprosima::utils::ConfigurationException( - utils::Formatter() << "Error loading DDS Enabler configuration from file: <" << file_path << - "> :\n " << e.what()); + utils::Formatter() << "Error loading DDS Enabler configuration from file: <" << file_path << + "> :\n " << e.what()); } } else @@ -419,7 +424,7 @@ void EnablerConfiguration::load_ddsenabler_configuration_from_json_file( EPROSIMA_LOG_WARNING(DDSENABLER_YAML, "No configuration file specified, using default values."); } - EnablerConfiguration::load_ddsenabler_configuration(yml); + EnablerConfiguration::load_ddsenabler_configuration_(yml); } } /* namespace yaml */ diff --git a/ddsenabler_yaml/test/DdsEnablerYamlTest.cpp b/ddsenabler_yaml/test/DdsEnablerYamlTest.cpp index bfec170e..d8cd522a 100644 --- a/ddsenabler_yaml/test/DdsEnablerYamlTest.cpp +++ b/ddsenabler_yaml/test/DdsEnablerYamlTest.cpp @@ -29,9 +29,10 @@ TEST(DdsEnablerYamlTest, get_ddsenabler_correct_configuration_yaml) const char* yml_str = R"( dds: - domain: 0 + domain: 4 ddsenabler: + initial-publish-wait: 500 specs: threads: 12 @@ -51,6 +52,9 @@ TEST(DdsEnablerYamlTest, get_ddsenabler_correct_configuration_yaml) utils::Formatter error_msg; ASSERT_TRUE(configuration.is_valid(error_msg)); + + ASSERT_EQ(configuration.simple_configuration->domain.domain_id, 4); + ASSERT_EQ(configuration.enabler_configuration->initial_publish_wait, 500); ASSERT_EQ(configuration.n_threads, 12); ASSERT_TRUE(configuration.ddspipe_configuration.log_configuration.is_valid(error_msg)); @@ -112,6 +116,9 @@ TEST(DdsEnablerYamlTest, get_ddsenabler_default_values_configuration_yaml) utils::Formatter error_msg; ASSERT_TRUE(configuration.is_valid(error_msg)); + + ASSERT_EQ(configuration.simple_configuration->domain.domain_id, 0); + ASSERT_EQ(configuration.enabler_configuration->initial_publish_wait, 0); ASSERT_EQ(configuration.n_threads, DEFAULT_N_THREADS); } @@ -125,7 +132,7 @@ TEST(DdsEnablerYamlTest, get_ddsenabler_incorrect_path_configuration_json) TEST(DdsEnablerYamlTest, get_ddsenabler_correct_configuration_json) { const char* path_str = "./resources/correct_config.json"; - + ASSERT_TRUE(std::filesystem::exists(path_str)); EnablerConfiguration configuration(path_str); @@ -133,6 +140,9 @@ TEST(DdsEnablerYamlTest, get_ddsenabler_correct_configuration_json) utils::Formatter error_msg; ASSERT_TRUE(configuration.is_valid(error_msg)); + + ASSERT_EQ(configuration.simple_configuration->domain.domain_id, 4); + ASSERT_EQ(configuration.enabler_configuration->initial_publish_wait, 500); ASSERT_EQ(configuration.n_threads, 12); ASSERT_TRUE(configuration.ddspipe_configuration.log_configuration.is_valid(error_msg)); @@ -148,7 +158,7 @@ TEST(DdsEnablerYamlTest, get_ddsenabler_correct_configuration_json) TEST(DdsEnablerYamlTest, get_ddsenabler_incorrect_n_threads_configuration_json) { const char* path_str = "./resources/incorrect_threads_config.json"; - + ASSERT_TRUE(std::filesystem::exists(path_str)); EXPECT_THROW({EnablerConfiguration configuration(path_str);}, std::exception); @@ -165,6 +175,9 @@ TEST(DdsEnablerYamlTest, get_ddsenabler_default_values_configuration_json) utils::Formatter error_msg; ASSERT_TRUE(configuration.is_valid(error_msg)); + + ASSERT_EQ(configuration.simple_configuration->domain.domain_id, 0); + ASSERT_EQ(configuration.enabler_configuration->initial_publish_wait, 0); ASSERT_EQ(configuration.n_threads, DEFAULT_N_THREADS); } @@ -178,7 +191,7 @@ TEST(DdsEnablerYamlTest, get_ddsenabler_incorrect_path_configuration_yaml) TEST(DdsEnablerYamlTest, get_ddsenabler_full_configuration_json) { const char* path_str = "./resources/correct_config.json"; - + ASSERT_TRUE(std::filesystem::exists(path_str)); EnablerConfiguration configuration(path_str); @@ -186,6 +199,9 @@ TEST(DdsEnablerYamlTest, get_ddsenabler_full_configuration_json) utils::Formatter error_msg; ASSERT_TRUE(configuration.is_valid(error_msg)); + + ASSERT_EQ(configuration.simple_configuration->domain.domain_id, 4); + ASSERT_EQ(configuration.enabler_configuration->initial_publish_wait, 500); ASSERT_EQ(configuration.n_threads, 12); } diff --git a/ddsenabler_yaml/test/resources/correct_config.json b/ddsenabler_yaml/test/resources/correct_config.json index 97c51b1d..ac20b8db 100644 --- a/ddsenabler_yaml/test/resources/correct_config.json +++ b/ddsenabler_yaml/test/resources/correct_config.json @@ -2,9 +2,11 @@ "dds": { "ddsmodule": { "dds": { - "domain": 0 + "domain": 4 + }, + "ddsenabler": { + "initial-publish-wait": 500 }, - "ddsenabler": null, "specs": { "threads": 12, "logging": { diff --git a/ddsenabler_yaml/test/resources/full_config.json b/ddsenabler_yaml/test/resources/full_config.json index 3be31cdc..71e64565 100644 --- a/ddsenabler_yaml/test/resources/full_config.json +++ b/ddsenabler_yaml/test/resources/full_config.json @@ -2,7 +2,7 @@ "dds": { "ddsmodule": { "dds": { - "domain": 0, + "domain": 4, "allowlist": [ { "name": "*" @@ -23,7 +23,9 @@ } ] }, - "ddsenabler": null, + "ddsenabler": { + "initial-publish-wait": 500 + }, "specs": { "threads": 12, "logging": { diff --git a/docs/context_broker_interface.rst b/docs/context_broker_interface.rst index d274c2b7..6927b921 100644 --- a/docs/context_broker_interface.rst +++ b/docs/context_broker_interface.rst @@ -15,7 +15,7 @@ during the initialization process of the ``DDS Enabler`` by using the ``init_dds int init_dds_enabler( const char* ddsEnablerConfigFile, - participants::DdsNotification data_callback, + participants::DdsDataNotification data_callback, participants::DdsTypeNotification type_callback, participants::DdsLogFunc log_callback); @@ -50,6 +50,8 @@ This callback is invoked by the ``CBHandler`` through the ``CBWriter`` class. const char* topicName, const char* serializedType); +.. TODO: update with topic notification, topic request and type request callbacks + Log callback ============ The Log Callback is responsible for relaying all relevant logging information from the Fast DDS ecosystem to the