diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index d63b96f986c..1a1b3e7497d 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -15,3 +15,4 @@ set(fastdds_FOUND TRUE) add_subdirectory(cpp/dds) add_subdirectory(cpp/rtps) +add_subdirectory(cpp/configuration) diff --git a/examples/cpp/configuration/Application.cpp b/examples/cpp/configuration/Application.cpp new file mode 100644 index 00000000000..2c0e8c94575 --- /dev/null +++ b/examples/cpp/configuration/Application.cpp @@ -0,0 +1,57 @@ +// 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 Application.cpp + * + */ + +#include "Application.hpp" + +#include "CLIParser.hpp" +#include "PublisherApp.hpp" +#include "SubscriberApp.hpp" + +using namespace eprosima::fastdds::dds; + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace configuration { + +//! Factory method to create a publisher or subscriber +std::shared_ptr Application::make_app( + const CLIParser::configuration_config& config) +{ + std::shared_ptr entity; + switch (config.entity) + { + case CLIParser::EntityKind::PUBLISHER: + entity = std::make_shared(config.pub_config); + break; + case CLIParser::EntityKind::SUBSCRIBER: + entity = std::make_shared(config.sub_config); + break; + case CLIParser::EntityKind::UNDEFINED: + default: + throw std::runtime_error("Entity initialization failed"); + break; + } + return entity; +} + +} // namespace configuration +} // namespace examples +} // namespace fastdds +} // namespace eprosima diff --git a/examples/cpp/configuration/Application.hpp b/examples/cpp/configuration/Application.hpp new file mode 100644 index 00000000000..c35f8b8f1e9 --- /dev/null +++ b/examples/cpp/configuration/Application.hpp @@ -0,0 +1,52 @@ +// 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 Application.hpp + * + */ + +#ifndef _FASTDDS_CONFIGURATION_APPLICATION_HPP_ +#define _FASTDDS_CONFIGURATION_APPLICATION_HPP_ + +#include + +#include "CLIParser.hpp" + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace configuration { + +class Application +{ +public: + + //! Run application + virtual void run() = 0; + + //! Trigger the end of execution + virtual void stop() = 0; + + //! Factory method to create applications based on configuration + static std::shared_ptr make_app( + const CLIParser::configuration_config& config); +}; + +} // namespace configuration +} // namespace examples +} // namespace fastdds +} // namespace eprosima + +#endif /* _FASTDDS_CONFIGURATION_APPLICATION_HPP_ */ diff --git a/examples/cpp/configuration/CLIParser.hpp b/examples/cpp/configuration/CLIParser.hpp new file mode 100644 index 00000000000..ec4e349d487 --- /dev/null +++ b/examples/cpp/configuration/CLIParser.hpp @@ -0,0 +1,959 @@ + +// 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. + +#include +#include +#include +#include + +#include +#include +#include + +#ifndef _FASTDDS_CONFIGURATION_CLI_PARSER_HPP_ +#define _FASTDDS_CONFIGURATION_CLI_PARSER_HPP_ + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace configuration { + +using namespace eprosima::fastdds::dds; +using Log; + +class CLIParser +{ +public: + + CLIParser() = delete; + + enum class EntityKind : uint8_t + { + PUBLISHER, + SUBSCRIBER, + UNDEFINED + }; + +private: + + struct entity_config + { + uint16_t samples = 0; + uint32_t domain = 0; + eprosima::fastdds::rtps::BuiltinTransports transport = eprosima::fastdds::rtps::BuiltinTransports::DEFAULT; + uint8_t ttl = 1; + std::string topic_name = "configuration_topic"; + std::string profile_participant = ""; + ReliabilityQosPolicyKind reliability = ReliabilityQosPolicyKind::BEST_EFFORT_RELIABILITY_QOS; + DurabilityQosPolicyKind durability = DurabilityQosPolicyKind::VOLATILE_DURABILITY_QOS; + HistoryQosPolicyKind history_kind = HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS; + int32_t history_depth = 1; + uint32_t deadline = 100; + uint32_t lifespan = 100; + LivelinessQosPolicyKind liveliness = LivelinessQosPolicyKind::AUTOMATIC_LIVELINESS_QOS; + uint32_t liveliness_lease = 200; + uint32_t liveliness_assert = 100; + OwnershipQosPolicyKind ownership = OwnershipQosPolicyKind::SHARED_OWNERSHIP_QOS; + std::string partitions = ""; + }; + +public: + + struct publisher_config : public entity_config + { + uint16_t wait = 0; + uint32_t msg_size = 10; + uint32_t interval = 100; + bool disable_positive_ack = false; + uint32_t ack_keep_duration = 100; + uint32_t strength = 0; + std::string profile_writer = ""; + PublishModeQosPolicyKind publish_mode = PublishModeQosPolicyKind::SYNCHRONOUS_PUBLISH_MODE; + }; + + struct subscriber_config : public entity_config + { + std::string profile_reader = ""; + }; + + struct configuration_config + { + CLIParser::EntityKind entity = CLIParser::EntityKind::UNDEFINED; + publisher_config pub_config; + subscriber_config sub_config; + }; + + static void print_help( + uint8_t return_code) + { + std::cout << "Usage: configuration [options]" << std::endl; + std::cout << "" << std::endl; + std::cout << "Entities:" << std::endl; + std::cout << " publisher Run a publisher entity" << std::endl; + std::cout << " subscriber Run a subscriber entity" << std::endl; + std::cout << "" << std::endl; + std::cout << "Common options:" << std::endl; + std::cout << " -h, --help Print this help message" << std::endl; + std::cout << " -d , --domain Domain ID number [0 <= <= 232]" << std::endl; + std::cout << " (Default: 0)" << std::endl; + std::cout << " -t , --transport Select builtin transport :" << std::endl; + std::cout << " · DEFAULT: SHM & UDPv4 (SHM prior UDP)" << std::endl; + std::cout << " · SHM: Shared Memory Transport only" << std::endl; + std::cout << " · UDPv4: UDP over IPv4 only" << std::endl; + std::cout << " · LARGE_DATA: Large data mode" << std::endl; + std::cout << " (refer to Fast DDS documentation)" << std::endl; + std::cout << " (Default: DEFAULT)" << std::endl; + std::cout << " --ttl Number of multicast discovery Time To Live" << std::endl; + std::cout << " hops [1 <= <= 255]" << std::endl; + std::cout << " (Default: 1)" << std::endl; + std::cout << " -n , --name Custom topic name" << std::endl; + std::cout << " (Default: configuration_topic)" << std::endl; + std::cout << " -s , --samples Number of samples to send or receive" << std::endl; + std::cout << " [0 <= <= 65535]" << std::endl; + std::cout << " (Default: 0 [unlimited])" << std::endl; + std::cout << " --profile-participant Profile name from already exported" << std::endl; + std::cout << " XML file to configure DomainParticipant" << std::endl; + std::cout << " --profile-reader Profile name from already exported" << std::endl; + std::cout << " XML file to configure DataReader" << std::endl; + std::cout << " --profile-writer Profile name from already exported" << std::endl; + std::cout << " XML file to configure DataWriter" << std::endl; + std::cout << " -r, --reliable Set Reliability QoS as reliable" << std::endl; + std::cout << " (Default: best effort)" << std::endl; + std::cout << " --transient-local Set Durability QoS as transient local" << std::endl; + std::cout << " (Default: volatile)" << std::endl; + std::cout << " -k, --keep-all Set History QoS as keep all" << std::endl; + std::cout << " --keep-last Set History QoS as keep last " << std::endl; + std::cout << " [1 <= <= 2147483647]" << std::endl; + std::cout << " (Default: keep last 1)" << std::endl; + std::cout << " --deadline Set deadline period in milliseconds" << std::endl; + std::cout << " [1 <= <= 4294967]" << std::endl; + std::cout << " (Default: 100)" << std::endl; + std::cout << " --lifespan Set Lifespan QoS as milliseconds" << std::endl; + std::cout << " [1 <= <= 4294967]" << std::endl; + std::cout << " (Default: 100)" << std::endl; + std::cout << " --liveliness Set liveliness lease duration in " << std::endl; + std::cout << " milliseconds" << std::endl; + std::cout << " [1 <= <= 4294967]" << std::endl; + std::cout << " (Default: 200)" << std::endl; + std::cout << " --liveliness-kind Set liveliness kind:" << std::endl; + std::cout << " · AUTOMATIC" << std::endl; + std::cout << " · MANUAL_BY_PARTICIPANT" << std::endl; + std::cout << " · MANUAL_BY_TOPIC" << std::endl; + std::cout << " (Default: AUTOMATIC)" << std::endl; + std::cout << " --liveliness-assert Set liveliness assert period in " << std::endl; + std::cout << " milliseconds" << std::endl; + std::cout << " [1 <= <= 4294967]" << std::endl; + std::cout << " (Default: 100)" << std::endl; + std::cout << " -o, --ownership Use Topic with exclusive ownership." << std::endl; + std::cout << " (Default: shared ownership)" << std::endl; + std::cout << " -p , --partition Partitions to match, separated by ';'" << std::endl; + std::cout << " Single or double quotes required for" << std::endl; + std::cout << " multiple partitions. No partitions used if" << std::endl; + std::cout << " empty string ('') provided" << std::endl; + std::cout << " (Default: '')" << std::endl; + std::cout << "" << std::endl; + std::cout << "Publisher options:" << std::endl; + std::cout << " -w , --wait Number of matched subscribers required to" << std::endl; + std::cout << " start publishing" << std::endl; + std::cout << " [0 <= <= 4294967]" << std::endl; + std::cout << " (Default: 0 [does not wait])" << std::endl; + std::cout << " -m , --msg-size Size in bytes of the data to be sent" << std::endl; + std::cout << " (Default: 10)" << std::endl; + std::cout << " -i , --interval Time between samples in milliseconds" << std::endl; + std::cout << " [1 <= <= 4294967]" << std::endl; + std::cout << " (Default: 100)" << std::endl; + std::cout << " -a, --async Asynchronous publish mode" << std::endl; + std::cout << " (Default: synchronous)" << std::endl; + std::cout << " --disable-positive-ack Disables positive acks" << std::endl; + std::cout << " --ack-keep-duration Set acknowledgment keep duration in" << std::endl; + std::cout << " milliseconds (DisablePositiveAckQoS)" << std::endl; + std::cout << " [1 <= <= 4294967]" << std::endl; + std::cout << " (Default: 100)" << std::endl; + std::cout << " --strength Set as publisher ownership strength." << std::endl; + std::cout << " This flag forces the exclusive ownership" << std::endl; + std::cout << " configuration in the publisher ('-o' flag)" << std::endl; + std::cout << " [0 <= <= 4294967295]" << std::endl; + std::cout << " (Default: 0 [unused, shared ownership])" << std::endl; + std::exit(return_code); + } + + static configuration_config parse_cli_options( + int argc, + char* argv[]) + { + configuration_config config; + + std::string first_argument = argv[1]; + + if (first_argument == "publisher" ) + { + config.entity = CLIParser::EntityKind::PUBLISHER; + } + else if ( first_argument == "subscriber") + { + config.entity = CLIParser::EntityKind::SUBSCRIBER; + } + else if (first_argument == "-h" || first_argument == "--help") + { + print_help(EXIT_SUCCESS); + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing entity argument " + first_argument); + print_help(EXIT_FAILURE); + } + + // max value allowed taking into account that the input is receiving millisecond values + uint32_t max_duration = floor(std::numeric_limits::max() * 1e-3); // = 4294967 + + for (int i = 2; i < argc; ++i) + { + std::string arg = argv[i]; + + if (arg == "-h" || arg == "--help") + { + print_help(EXIT_SUCCESS); + } + else if (arg == "-d" || arg == "--domain") + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < 0 || input > 232) + { + throw std::out_of_range("domain argument " + std::string( + argv[i]) + " out of range [0, 232]."); + } + else + { + config.pub_config.domain = static_cast(input); + config.sub_config.domain = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid domain argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing domain argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-t" || arg == "--transport") + { + if (++i < argc) + { + std::string transport = argv[i]; + if (transport == "DEFAULT") + { + config.pub_config.transport = eprosima::fastdds::rtps::BuiltinTransports::DEFAULT; + config.sub_config.transport = eprosima::fastdds::rtps::BuiltinTransports::DEFAULT; + } + else if (transport == "SHM") + { + config.pub_config.transport = eprosima::fastdds::rtps::BuiltinTransports::SHM; + config.sub_config.transport = eprosima::fastdds::rtps::BuiltinTransports::SHM; + } + else if (transport == "UDPv4") + { + config.pub_config.transport = eprosima::fastdds::rtps::BuiltinTransports::UDPv4; + config.sub_config.transport = eprosima::fastdds::rtps::BuiltinTransports::UDPv4; + } + else if (transport == "LARGE_DATA") + { + config.pub_config.transport = eprosima::fastdds::rtps::BuiltinTransports::LARGE_DATA; + config.sub_config.transport = eprosima::fastdds::rtps::BuiltinTransports::LARGE_DATA; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing transport argument"); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing transport argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "--ttl") + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < 0 || input > 232) + { + throw std::out_of_range("domain argument " + std::string( + argv[i]) + " out of range [0, 232]."); + } + else + { + config.pub_config.ttl = static_cast(input); + config.sub_config.ttl = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid domain argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing ttl argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-n" || arg == "--name") + { + if (++i < argc) + { + config.pub_config.topic_name = argv[i]; + config.sub_config.topic_name = argv[i]; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing name argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-s" || arg == "--samples") + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < std::numeric_limits::min() || + input > std::numeric_limits::max()) + { + throw std::out_of_range("sample argument " + std::string( + argv[i]) + " out of range [0, 65535]."); + } + else + { + config.pub_config.samples = static_cast(input); + config.sub_config.samples = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid sample argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing samples argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "--profile-participant") + { + if (++i < argc) + { + config.pub_config.profile_participant = argv[i]; + config.sub_config.profile_participant = argv[i]; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing profile-participant argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "--profile-reader") + { + if (config.entity == CLIParser::EntityKind::SUBSCRIBER) + { + if (++i < argc) + { + config.sub_config.profile_reader = argv[i]; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing profile-reader argument"); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "profile-reader argument is only valid for subscriber entity"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "--profile-writer") + { + if (config.entity == CLIParser::EntityKind::PUBLISHER) + { + if (++i < argc) + { + config.pub_config.profile_writer = argv[i]; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing profile-writer argument"); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "profile-writer argument is only valid for publisher entity"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-r" || arg == "--reliable") + { + config.pub_config.reliability = ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS; + config.sub_config.reliability = ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS; + } + else if (arg == "--transient-local") + { + config.pub_config.durability = DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS; + config.sub_config.durability = DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS; + + } + else if (arg == "-k" || arg == "--keep-all") + { + config.pub_config.history_kind = HistoryQosPolicyKind::KEEP_ALL_HISTORY_QOS; + config.sub_config.history_kind = HistoryQosPolicyKind::KEEP_ALL_HISTORY_QOS; + config.pub_config.history_depth = -1; + config.sub_config.history_depth = -1; + } + else if (arg == "--keep-last") + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < 1 || input > std::numeric_limits::max()) + { + throw std::out_of_range("keep-last depth argument " + std::string( + argv[i]) + " out of range [1, 2147483647]."); + } + else + { + config.pub_config.history_depth = static_cast(input); + config.sub_config.history_depth = static_cast(input); + config.pub_config.history_kind = HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS; + config.sub_config.history_kind = HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS; + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid keep-last argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing keep-last argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "--deadline") + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < 1 || input > max_duration) + { + throw std::out_of_range("deadline argument " + std::string( + argv[i]) + " out of range [1, " + std::to_string( + max_duration) + "]."); + } + else + { + config.pub_config.deadline = static_cast(input); + config.sub_config.deadline = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid deadline argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing deadline argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "--disable-positive-ack") + { + if (config.entity == CLIParser::EntityKind::PUBLISHER) + { + config.pub_config.disable_positive_ack = true; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, + "disable-positive-ack argument is only valid for publisher entity"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "--lifespan") + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < 1 || input > max_duration) + { + throw std::out_of_range("lifespan argument " + std::string( + argv[i]) + " out of range [1, " + std::to_string( + max_duration) + "]."); + } + else + { + config.pub_config.lifespan = static_cast(input); + config.sub_config.lifespan = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid lifespan argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing lifespan argument"); + } + } + else if (arg == "--liveliness") + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < 1 || input > max_duration) + { + throw std::out_of_range("liveliness argument " + std::string( + argv[i]) + " out of range [1, " + std::to_string( + max_duration) + "]."); + } + else + { + config.pub_config.liveliness_lease = static_cast(input); + config.sub_config.liveliness_lease = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid liveliness argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing liveliness argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "--liveliness-kind") + { + if (++i < argc) + { + std::string kind = argv[i]; + if (kind == "AUTOMATIC") + { + config.pub_config.liveliness = LivelinessQosPolicyKind::AUTOMATIC_LIVELINESS_QOS; + config.sub_config.liveliness = LivelinessQosPolicyKind::AUTOMATIC_LIVELINESS_QOS; + } + else if (kind == "MANUAL_BY_PARTICIPANT") + { + config.pub_config.liveliness = LivelinessQosPolicyKind::MANUAL_BY_PARTICIPANT_LIVELINESS_QOS; + config.sub_config.liveliness = LivelinessQosPolicyKind::MANUAL_BY_PARTICIPANT_LIVELINESS_QOS; + } + else if (kind == "MANUAL_BY_TOPIC") + { + config.pub_config.liveliness = LivelinessQosPolicyKind::MANUAL_BY_TOPIC_LIVELINESS_QOS; + config.sub_config.liveliness = LivelinessQosPolicyKind::MANUAL_BY_TOPIC_LIVELINESS_QOS; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing liveliness-kind argument"); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing liveliness-kind argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "--liveliness-assert") + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < 1 || input > max_duration) + { + throw std::out_of_range("liveliness-assert argument " + std::string( + argv[i]) + " out of range [1, " + std::to_string( + max_duration) + "]."); + } + else + { + config.pub_config.liveliness_assert = static_cast(input); + config.sub_config.liveliness_assert = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid liveliness-assert argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing liveliness-assert argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-o" || arg == "--ownership") + { + config.pub_config.ownership = OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS; + config.sub_config.ownership = OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS; + } + else if (arg == "--partition") + { + if (++i < argc) + { + config.pub_config.partitions = argv[i]; + config.sub_config.partitions = argv[i]; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing partition argument"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-w" || arg == "--wait") + { + if (config.entity == CLIParser::EntityKind::PUBLISHER) + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < 1 || input > max_duration) + { + throw std::out_of_range("wait argument " + std::string( + argv[i]) + " out of range [1, " + std::to_string( + max_duration) + "]."); + } + else + { + config.pub_config.wait = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid wait argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing wait argument"); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "wait argument is only valid for publisher entity"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-m" || arg == "--msg-size") + { + if (config.entity == CLIParser::EntityKind::PUBLISHER) + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < 1 || input > std::numeric_limits::max()) + { + throw std::out_of_range("strength argument " + std::string( + argv[i]) + " out of range [1, " + + std::to_string(std::numeric_limits::max()) + "]."); + } + else + { + config.pub_config.ownership = OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS; + config.pub_config.strength = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid strength argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing msg-size argument"); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "msg-size argument is only valid for publisher entity"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-i" || arg == "--interval") + { + if (config.entity == CLIParser::EntityKind::PUBLISHER) + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < 1 || input > max_duration) + { + throw std::out_of_range("interval argument " + std::string( + argv[i]) + " out of range [1, " + std::to_string( + max_duration) + "]."); + } + else + { + config.pub_config.interval = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid interval argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing interval argument"); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "interval argument is only valid for publisher entity"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-a" || arg == "--async") + { + if (config.entity == CLIParser::EntityKind::PUBLISHER) + { + config.pub_config.publish_mode = PublishModeQosPolicyKind::ASYNCHRONOUS_PUBLISH_MODE; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "async argument is only valid for publisher entity"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "--ack-keep-duration") + { + if (config.entity == CLIParser::EntityKind::PUBLISHER) + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < 1 || input > max_duration) + { + throw std::out_of_range("ack-keep-duration argument " + std::string( + argv[i]) + " out of range [1, " + std::to_string( + max_duration) + "]."); + } + else + { + config.pub_config.ack_keep_duration = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid ack-keep-duration argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing ack-keep-duration argument"); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, + "ack-keep-duration argument is only valid for publisher entity"); + print_help(EXIT_FAILURE); + } + } + else if (arg == "--strength") + { + if (config.entity == CLIParser::EntityKind::PUBLISHER) + { + if (++i < argc) + { + try + { + int input = std::stoi(argv[i]); + if (input < std::numeric_limits::min() || + input > std::numeric_limits::max()) + { + throw std::out_of_range("strength argument " + std::string( + argv[i]) + " out of range [0, " + + std::to_string(std::numeric_limits::max()) + "]."); + } + else + { + config.pub_config.ownership = OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS; + config.pub_config.strength = static_cast(input); + } + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid strength argument " + std::string( + argv[i]) + ": " + std::string(e.what())); + print_help(EXIT_FAILURE); + } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, std::string(e.what())); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing strength argument"); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "strength argument is only valid for publisher entity"); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing argument: " + arg); + print_help(EXIT_FAILURE); + } + } + return config; + } + +}; + +} // namespace configuration +} // namespace examples +} // namespace fastdds +} // namespace eprosima + +#endif // _FASTDDS_CONFIGURATION_CLI_PARSER_HPP_ diff --git a/examples/cpp/dds/AdvancedConfigurationExample/CMakeLists.txt b/examples/cpp/configuration/CMakeLists.txt similarity index 53% rename from examples/cpp/dds/AdvancedConfigurationExample/CMakeLists.txt rename to examples/cpp/configuration/CMakeLists.txt index 16a28f79266..1195677b615 100644 --- a/examples/cpp/dds/AdvancedConfigurationExample/CMakeLists.txt +++ b/examples/cpp/configuration/CMakeLists.txt @@ -14,7 +14,7 @@ cmake_minimum_required(VERSION 3.20) -project(AdvancedConfigurationExample VERSION 1 LANGUAGES CXX) +project(fastdds_configuration_example VERSION 1 LANGUAGES CXX) # Find requirements if(NOT fastcdr_FOUND) @@ -35,19 +35,32 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") endif() endif() -message(STATUS "Configuring AdvancedConfiguration example...") -file(GLOB ADVANCED_CONFIG_EXAMPLE_SOURCES_CXX "*.cxx") -file(GLOB ADVANCED_CONFIG_EXAMPLE_SOURCES_CPP "*.cpp") +message(STATUS "Configuring configuration example...") +file(GLOB CONFIGURATION_SOURCES_CXX "*.cxx") +file(GLOB CONFIGURATION_SOURCES_CPP "*.cpp") -add_executable(${PROJECT_NAME} ${ADVANCED_CONFIG_EXAMPLE_SOURCES_CXX} ${ADVANCED_CONFIG_EXAMPLE_SOURCES_CPP}) -target_compile_definitions(${PROJECT_NAME} PRIVATE +add_executable(configuration ${CONFIGURATION_SOURCES_CXX} ${CONFIGURATION_SOURCES_CPP}) +target_compile_definitions(configuration PRIVATE $<$>,$>:__DEBUG> $<$:__INTERNALDEBUG> # Internal debug activated. $<$:SHM_TRANSPORT_BUILTIN> # Enable SHM as built-in transport ) -target_link_libraries(${PROJECT_NAME} fastdds fastcdr fastdds::optionparser) -install(TARGETS ${PROJECT_NAME} - RUNTIME DESTINATION examples/cpp/dds/${PROJECT_NAME}/${BIN_INSTALL_DIR}) +target_link_libraries(configuration fastdds fastcdr) +install(TARGETS configuration + RUNTIME DESTINATION ${DATA_INSTALL_DIR}/fastdds/examples/cpp/configuration/${BIN_INSTALL_DIR}) -file(COPY shm_off.xml DESTINATION ${PROJECT_BINARY_DIR}) +# Copy the XML files over to the build directory +file(GLOB_RECURSE XML_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.xml) +# for each xml file detected +foreach(XML_FILE_COMPLETE_PATH ${XML_FILES}) + # obtain the file name + get_filename_component(XML_FILE ${XML_FILE_COMPLETE_PATH} NAME_WE) + # copy the file from src to build folders + configure_file( + ${XML_FILE_COMPLETE_PATH} # from full src path + ${CMAKE_CURRENT_BINARY_DIR}/${XML_FILE}.xml # to relative build path + COPYONLY) + install(FILES ${XML_FILE_COMPLETE_PATH} + DESTINATION ${DATA_INSTALL_DIR}/fastdds/examples/cpp/configuration/${BIN_INSTALL_DIR}) +endforeach() diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfiguration.cxx b/examples/cpp/configuration/Configuration.cxx similarity index 72% rename from examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfiguration.cxx rename to examples/cpp/configuration/Configuration.cxx index f423c3c9cc9..36fc456e834 100644 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfiguration.cxx +++ b/examples/cpp/configuration/Configuration.cxx @@ -13,7 +13,7 @@ // limitations under the License. /*! - * @file AdvancedConfiguration.cpp + * @file Configuration.cpp * This source file contains the implementation of the described types in the IDL file. * * This file was generated by the tool fastddsgen. @@ -26,9 +26,7 @@ char dummy; } // namespace #endif // _WIN32 -#include "AdvancedConfiguration.h" - -#if FASTCDR_VERSION_MAJOR > 1 +#include "Configuration.h" #include @@ -43,32 +41,32 @@ using namespace eprosima::fastcdr::exception; -AdvancedConfiguration::AdvancedConfiguration() +Configuration::Configuration() { } -AdvancedConfiguration::~AdvancedConfiguration() +Configuration::~Configuration() { } -AdvancedConfiguration::AdvancedConfiguration( - const AdvancedConfiguration& x) +Configuration::Configuration( + const Configuration& x) { m_index = x.m_index; m_message = x.m_message; m_data = x.m_data; } -AdvancedConfiguration::AdvancedConfiguration( - AdvancedConfiguration&& x) noexcept +Configuration::Configuration( + Configuration&& x) noexcept { m_index = x.m_index; m_message = std::move(x.m_message); m_data = std::move(x.m_data); } -AdvancedConfiguration& AdvancedConfiguration::operator =( - const AdvancedConfiguration& x) +Configuration& Configuration::operator =( + const Configuration& x) { m_index = x.m_index; @@ -77,8 +75,8 @@ AdvancedConfiguration& AdvancedConfiguration::operator =( return *this; } -AdvancedConfiguration& AdvancedConfiguration::operator =( - AdvancedConfiguration&& x) noexcept +Configuration& Configuration::operator =( + Configuration&& x) noexcept { m_index = x.m_index; @@ -87,16 +85,16 @@ AdvancedConfiguration& AdvancedConfiguration::operator =( return *this; } -bool AdvancedConfiguration::operator ==( - const AdvancedConfiguration& x) const +bool Configuration::operator ==( + const Configuration& x) const { return (m_index == x.m_index && m_message == x.m_message && m_data == x.m_data); } -bool AdvancedConfiguration::operator !=( - const AdvancedConfiguration& x) const +bool Configuration::operator !=( + const Configuration& x) const { return !(*this == x); } @@ -105,7 +103,7 @@ bool AdvancedConfiguration::operator !=( * @brief This function sets a value in member index * @param _index New value for member index */ -void AdvancedConfiguration::index( +void Configuration::index( uint32_t _index) { m_index = _index; @@ -115,7 +113,7 @@ void AdvancedConfiguration::index( * @brief This function returns the value of member index * @return Value of member index */ -uint32_t AdvancedConfiguration::index() const +uint32_t Configuration::index() const { return m_index; } @@ -124,7 +122,7 @@ uint32_t AdvancedConfiguration::index() const * @brief This function returns a reference to member index * @return Reference to member index */ -uint32_t& AdvancedConfiguration::index() +uint32_t& Configuration::index() { return m_index; } @@ -134,7 +132,7 @@ uint32_t& AdvancedConfiguration::index() * @brief This function copies the value in member message * @param _message New value to be copied in member message */ -void AdvancedConfiguration::message( +void Configuration::message( const std::array& _message) { m_message = _message; @@ -144,7 +142,7 @@ void AdvancedConfiguration::message( * @brief This function moves the value in member message * @param _message New value to be moved in member message */ -void AdvancedConfiguration::message( +void Configuration::message( std::array&& _message) { m_message = std::move(_message); @@ -154,7 +152,7 @@ void AdvancedConfiguration::message( * @brief This function returns a constant reference to member message * @return Constant reference to member message */ -const std::array& AdvancedConfiguration::message() const +const std::array& Configuration::message() const { return m_message; } @@ -163,7 +161,7 @@ const std::array& AdvancedConfiguration::message() const * @brief This function returns a reference to member message * @return Reference to member message */ -std::array& AdvancedConfiguration::message() +std::array& Configuration::message() { return m_message; } @@ -173,7 +171,7 @@ std::array& AdvancedConfiguration::message() * @brief This function copies the value in member data * @param _data New value to be copied in member data */ -void AdvancedConfiguration::data( +void Configuration::data( const std::vector& _data) { m_data = _data; @@ -183,7 +181,7 @@ void AdvancedConfiguration::data( * @brief This function moves the value in member data * @param _data New value to be moved in member data */ -void AdvancedConfiguration::data( +void Configuration::data( std::vector&& _data) { m_data = std::move(_data); @@ -193,7 +191,7 @@ void AdvancedConfiguration::data( * @brief This function returns a constant reference to member data * @return Constant reference to member data */ -const std::vector& AdvancedConfiguration::data() const +const std::vector& Configuration::data() const { return m_data; } @@ -202,13 +200,12 @@ const std::vector& AdvancedConfiguration::data() const * @brief This function returns a reference to member data * @return Reference to member data */ -std::vector& AdvancedConfiguration::data() +std::vector& Configuration::data() { return m_data; } // Include auxiliary functions like for serializing/deserializing. -#include "AdvancedConfigurationCdrAux.ipp" +#include "ConfigurationCdrAux.ipp" -#endif // FASTCDR_VERSION_MAJOR > 1 diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfiguration.h b/examples/cpp/configuration/Configuration.h similarity index 70% rename from examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfiguration.h rename to examples/cpp/configuration/Configuration.h index 18c1255a55c..1e9f52ecd3e 100644 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfiguration.h +++ b/examples/cpp/configuration/Configuration.h @@ -13,19 +13,14 @@ // limitations under the License. /*! - * @file AdvancedConfiguration.h + * @file Configuration.h * This header file contains the declaration of the described types in the IDL file. * * This file was generated by the tool fastddsgen. */ -#include -#include "AdvancedConfigurationv1.h" - -#if FASTCDR_VERSION_MAJOR > 1 - -#ifndef _FAST_DDS_GENERATED_ADVANCEDCONFIGURATION_H_ -#define _FAST_DDS_GENERATED_ADVANCEDCONFIGURATION_H_ +#ifndef _FAST_DDS_GENERATED_CONFIGURATION_H_ +#define _FAST_DDS_GENERATED_CONFIGURATION_H_ #include #include @@ -34,6 +29,7 @@ #include #include +#include #include #include @@ -51,16 +47,16 @@ #if defined(_WIN32) #if defined(EPROSIMA_USER_DLL_EXPORT) -#if defined(ADVANCEDCONFIGURATION_SOURCE) -#define ADVANCEDCONFIGURATION_DllAPI __declspec( dllexport ) +#if defined(CONFIGURATION_SOURCE) +#define CONFIGURATION_DllAPI __declspec( dllexport ) #else -#define ADVANCEDCONFIGURATION_DllAPI __declspec( dllimport ) -#endif // ADVANCEDCONFIGURATION_SOURCE +#define CONFIGURATION_DllAPI __declspec( dllimport ) +#endif // CONFIGURATION_SOURCE #else -#define ADVANCEDCONFIGURATION_DllAPI +#define CONFIGURATION_DllAPI #endif // EPROSIMA_USER_DLL_EXPORT #else -#define ADVANCEDCONFIGURATION_DllAPI +#define CONFIGURATION_DllAPI #endif // _WIN32 namespace eprosima { @@ -77,64 +73,64 @@ class CdrSizeCalculator; /*! - * @brief This class represents the structure AdvancedConfiguration defined by the user in the IDL file. - * @ingroup AdvancedConfiguration + * @brief This class represents the structure Configuration defined by the user in the IDL file. + * @ingroup Configuration */ -class AdvancedConfiguration +class Configuration { public: /*! * @brief Default constructor. */ - eProsima_user_DllExport AdvancedConfiguration(); + eProsima_user_DllExport Configuration(); /*! * @brief Default destructor. */ - eProsima_user_DllExport ~AdvancedConfiguration(); + eProsima_user_DllExport ~Configuration(); /*! * @brief Copy constructor. - * @param x Reference to the object AdvancedConfiguration that will be copied. + * @param x Reference to the object Configuration that will be copied. */ - eProsima_user_DllExport AdvancedConfiguration( - const AdvancedConfiguration& x); + eProsima_user_DllExport Configuration( + const Configuration& x); /*! * @brief Move constructor. - * @param x Reference to the object AdvancedConfiguration that will be copied. + * @param x Reference to the object Configuration that will be copied. */ - eProsima_user_DllExport AdvancedConfiguration( - AdvancedConfiguration&& x) noexcept; + eProsima_user_DllExport Configuration( + Configuration&& x) noexcept; /*! * @brief Copy assignment. - * @param x Reference to the object AdvancedConfiguration that will be copied. + * @param x Reference to the object Configuration that will be copied. */ - eProsima_user_DllExport AdvancedConfiguration& operator =( - const AdvancedConfiguration& x); + eProsima_user_DllExport Configuration& operator =( + const Configuration& x); /*! * @brief Move assignment. - * @param x Reference to the object AdvancedConfiguration that will be copied. + * @param x Reference to the object Configuration that will be copied. */ - eProsima_user_DllExport AdvancedConfiguration& operator =( - AdvancedConfiguration&& x) noexcept; + eProsima_user_DllExport Configuration& operator =( + Configuration&& x) noexcept; /*! * @brief Comparison operator. - * @param x AdvancedConfiguration object to compare. + * @param x Configuration object to compare. */ eProsima_user_DllExport bool operator ==( - const AdvancedConfiguration& x) const; + const Configuration& x) const; /*! * @brief Comparison operator. - * @param x AdvancedConfiguration object to compare. + * @param x Configuration object to compare. */ eProsima_user_DllExport bool operator !=( - const AdvancedConfiguration& x) const; + const Configuration& x) const; /*! * @brief This function sets a value in member index @@ -217,8 +213,7 @@ class AdvancedConfiguration }; -#endif // _FAST_DDS_GENERATED_ADVANCEDCONFIGURATION_H_ +#endif // _FAST_DDS_GENERATED_CONFIGURATION_H_ -#endif // FASTCDR_VERSION_MAJOR > 1 diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfiguration.idl b/examples/cpp/configuration/Configuration.idl similarity index 58% rename from examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfiguration.idl rename to examples/cpp/configuration/Configuration.idl index 3887de51ac8..063cd25a3f8 100644 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfiguration.idl +++ b/examples/cpp/configuration/Configuration.idl @@ -1,4 +1,5 @@ -struct AdvancedConfiguration +@extensibility(APPENDABLE) +struct Configuration { unsigned long index; char message[20]; diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationCdrAux.hpp b/examples/cpp/configuration/ConfigurationCdrAux.hpp similarity index 69% rename from examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationCdrAux.hpp rename to examples/cpp/configuration/ConfigurationCdrAux.hpp index a99d903b31f..bcfbe3d07a0 100644 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationCdrAux.hpp +++ b/examples/cpp/configuration/ConfigurationCdrAux.hpp @@ -13,19 +13,19 @@ // limitations under the License. /*! - * @file AdvancedConfigurationCdrAux.hpp + * @file ConfigurationCdrAux.hpp * This source file contains some definitions of CDR related functions. * * This file was generated by the tool fastddsgen. */ -#ifndef _FAST_DDS_GENERATED_ADVANCEDCONFIGURATIONCDRAUX_HPP_ -#define _FAST_DDS_GENERATED_ADVANCEDCONFIGURATIONCDRAUX_HPP_ +#ifndef _FAST_DDS_GENERATED_CONFIGURATIONCDRAUX_HPP_ +#define _FAST_DDS_GENERATED_CONFIGURATIONCDRAUX_HPP_ -#include "AdvancedConfiguration.h" +#include "Configuration.h" -constexpr uint32_t AdvancedConfiguration_max_cdr_typesize {132UL}; -constexpr uint32_t AdvancedConfiguration_max_key_cdr_typesize {0UL}; +constexpr uint32_t Configuration_max_cdr_typesize {132UL}; +constexpr uint32_t Configuration_max_key_cdr_typesize {0UL}; namespace eprosima { @@ -40,11 +40,11 @@ class CdrSizeCalculator; eProsima_user_DllExport void serialize_key( eprosima::fastcdr::Cdr& scdr, - const AdvancedConfiguration& data); + const Configuration& data); } // namespace fastcdr } // namespace eprosima -#endif // _FAST_DDS_GENERATED_ADVANCEDCONFIGURATIONCDRAUX_HPP_ +#endif // _FAST_DDS_GENERATED_CONFIGURATIONCDRAUX_HPP_ diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationCdrAux.ipp b/examples/cpp/configuration/ConfigurationCdrAux.ipp similarity index 90% rename from examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationCdrAux.ipp rename to examples/cpp/configuration/ConfigurationCdrAux.ipp index 61815b63fe3..47030904ded 100644 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationCdrAux.ipp +++ b/examples/cpp/configuration/ConfigurationCdrAux.ipp @@ -13,16 +13,16 @@ // limitations under the License. /*! - * @file AdvancedConfigurationCdrAux.ipp + * @file ConfigurationCdrAux.ipp * This source file contains some declarations of CDR related functions. * * This file was generated by the tool fastddsgen. */ -#ifndef _FAST_DDS_GENERATED_ADVANCEDCONFIGURATIONCDRAUX_IPP_ -#define _FAST_DDS_GENERATED_ADVANCEDCONFIGURATIONCDRAUX_IPP_ +#ifndef _FAST_DDS_GENERATED_CONFIGURATIONCDRAUX_IPP_ +#define _FAST_DDS_GENERATED_CONFIGURATIONCDRAUX_IPP_ -#include "AdvancedConfigurationCdrAux.hpp" +#include "ConfigurationCdrAux.hpp" #include #include @@ -41,7 +41,7 @@ namespace fastcdr { template<> eProsima_user_DllExport size_t calculate_serialized_size( eprosima::fastcdr::CdrSizeCalculator& calculator, - const AdvancedConfiguration& data, + const Configuration& data, size_t& current_alignment) { static_cast(data); @@ -72,7 +72,7 @@ eProsima_user_DllExport size_t calculate_serialized_size( template<> eProsima_user_DllExport void serialize( eprosima::fastcdr::Cdr& scdr, - const AdvancedConfiguration& data) + const Configuration& data) { eprosima::fastcdr::Cdr::state current_state(scdr); scdr.begin_serialize_type(current_state, @@ -91,7 +91,7 @@ eProsima_user_DllExport void serialize( template<> eProsima_user_DllExport void deserialize( eprosima::fastcdr::Cdr& cdr, - AdvancedConfiguration& data) + Configuration& data) { cdr.deserialize_type(eprosima::fastcdr::CdrVersion::XCDRv2 == cdr.get_cdr_version() ? eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 : @@ -123,7 +123,7 @@ eProsima_user_DllExport void deserialize( void serialize_key( eprosima::fastcdr::Cdr& scdr, - const AdvancedConfiguration& data) + const Configuration& data) { static_cast(scdr); static_cast(data); @@ -134,5 +134,5 @@ void serialize_key( } // namespace fastcdr } // namespace eprosima -#endif // _FAST_DDS_GENERATED_ADVANCEDCONFIGURATIONCDRAUX_IPP_ +#endif // _FAST_DDS_GENERATED_CONFIGURATIONCDRAUX_IPP_ diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationPubSubTypes.cxx b/examples/cpp/configuration/ConfigurationPubSubTypes.cxx similarity index 80% rename from examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationPubSubTypes.cxx rename to examples/cpp/configuration/ConfigurationPubSubTypes.cxx index fc1cdd916e3..00f7a4db9b9 100644 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationPubSubTypes.cxx +++ b/examples/cpp/configuration/ConfigurationPubSubTypes.cxx @@ -13,7 +13,7 @@ // limitations under the License. /*! - * @file AdvancedConfigurationPubSubTypes.cpp + * @file ConfigurationPubSubTypes.cpp * This header file contains the implementation of the serialization functions. * * This file was generated by the tool fastddsgen. @@ -22,8 +22,8 @@ #include -#include "AdvancedConfigurationPubSubTypes.h" -#include "AdvancedConfigurationCdrAux.hpp" +#include "ConfigurationPubSubTypes.h" +#include "ConfigurationCdrAux.hpp" using SerializedPayload_t = eprosima::fastrtps::rtps::SerializedPayload_t; using InstanceHandle_t = eprosima::fastrtps::rtps::InstanceHandle_t; @@ -33,24 +33,24 @@ using DataRepresentationId_t = eprosima::fastdds::dds::DataRepresentationId_t; -AdvancedConfigurationPubSubType::AdvancedConfigurationPubSubType() +ConfigurationPubSubType::ConfigurationPubSubType() { - setName("AdvancedConfiguration"); + setName("Configuration"); uint32_t type_size = #if FASTCDR_VERSION_MAJOR == 1 - static_cast(AdvancedConfiguration::getMaxCdrSerializedSize()); + static_cast(Configuration::getMaxCdrSerializedSize()); #else - AdvancedConfiguration_max_cdr_typesize; + Configuration_max_cdr_typesize; #endif type_size += static_cast(eprosima::fastcdr::Cdr::alignment(type_size, 4)); /* possible submessage alignment */ m_typeSize = type_size + 4; /*encapsulation*/ m_isGetKeyDefined = false; - uint32_t keyLength = AdvancedConfiguration_max_key_cdr_typesize > 16 ? AdvancedConfiguration_max_key_cdr_typesize : 16; + uint32_t keyLength = Configuration_max_key_cdr_typesize > 16 ? Configuration_max_key_cdr_typesize : 16; m_keyBuffer = reinterpret_cast(malloc(keyLength)); memset(m_keyBuffer, 0, keyLength); } -AdvancedConfigurationPubSubType::~AdvancedConfigurationPubSubType() +ConfigurationPubSubType::~ConfigurationPubSubType() { if (m_keyBuffer != nullptr) { @@ -58,12 +58,12 @@ AdvancedConfigurationPubSubType::~AdvancedConfigurationPubSubType() } } -bool AdvancedConfigurationPubSubType::serialize( +bool ConfigurationPubSubType::serialize( void* data, SerializedPayload_t* payload, DataRepresentationId_t data_representation) { - AdvancedConfiguration* p_type = static_cast(data); + Configuration* p_type = static_cast(data); // Object that manages the raw buffer. eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload->data), payload->max_size); @@ -100,14 +100,14 @@ bool AdvancedConfigurationPubSubType::serialize( return true; } -bool AdvancedConfigurationPubSubType::deserialize( +bool ConfigurationPubSubType::deserialize( SerializedPayload_t* payload, void* data) { try { // Convert DATA to pointer of your type - AdvancedConfiguration* p_type = static_cast(data); + Configuration* p_type = static_cast(data); // Object that manages the raw buffer. eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload->data), payload->length); @@ -134,7 +134,7 @@ bool AdvancedConfigurationPubSubType::deserialize( return true; } -std::function AdvancedConfigurationPubSubType::getSerializedSizeProvider( +std::function ConfigurationPubSubType::getSerializedSizeProvider( void* data, DataRepresentationId_t data_representation) { @@ -142,7 +142,7 @@ std::function AdvancedConfigurationPubSubType::getSerializedSizeProv { #if FASTCDR_VERSION_MAJOR == 1 static_cast(data_representation); - return static_cast(type::getCdrSerializedSize(*static_cast(data))) + + return static_cast(type::getCdrSerializedSize(*static_cast(data))) + 4u /*encapsulation*/; #else try @@ -152,7 +152,7 @@ std::function AdvancedConfigurationPubSubType::getSerializedSizeProv 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)) + + *static_cast(data), current_alignment)) + 4u /*encapsulation*/; } catch (eprosima::fastcdr::exception::Exception& /*exception*/) @@ -163,18 +163,18 @@ std::function AdvancedConfigurationPubSubType::getSerializedSizeProv }; } -void* AdvancedConfigurationPubSubType::createData() +void* ConfigurationPubSubType::createData() { - return reinterpret_cast(new AdvancedConfiguration()); + return reinterpret_cast(new Configuration()); } -void AdvancedConfigurationPubSubType::deleteData( +void ConfigurationPubSubType::deleteData( void* data) { - delete(reinterpret_cast(data)); + delete(reinterpret_cast(data)); } -bool AdvancedConfigurationPubSubType::getKey( +bool ConfigurationPubSubType::getKey( void* data, InstanceHandle_t* handle, bool force_md5) @@ -184,11 +184,11 @@ bool AdvancedConfigurationPubSubType::getKey( return false; } - AdvancedConfiguration* p_type = static_cast(data); + Configuration* p_type = static_cast(data); // Object that manages the raw buffer. eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(m_keyBuffer), - AdvancedConfiguration_max_key_cdr_typesize); + Configuration_max_key_cdr_typesize); // Object that serializes the data. eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::BIG_ENDIANNESS, eprosima::fastcdr::CdrVersion::XCDRv1); @@ -197,7 +197,7 @@ bool AdvancedConfigurationPubSubType::getKey( #else eprosima::fastcdr::serialize_key(ser, *p_type); #endif // FASTCDR_VERSION_MAJOR == 1 - if (force_md5 || AdvancedConfiguration_max_key_cdr_typesize > 16) + if (force_md5 || Configuration_max_key_cdr_typesize > 16) { m_md5.init(); #if FASTCDR_VERSION_MAJOR == 1 diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationPubSubTypes.h b/examples/cpp/configuration/ConfigurationPubSubTypes.h similarity index 80% rename from examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationPubSubTypes.h rename to examples/cpp/configuration/ConfigurationPubSubTypes.h index 7c513bc156c..57524f1a0ec 100644 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationPubSubTypes.h +++ b/examples/cpp/configuration/ConfigurationPubSubTypes.h @@ -13,15 +13,15 @@ // limitations under the License. /*! - * @file AdvancedConfigurationPubSubTypes.h + * @file ConfigurationPubSubTypes.h * This header file contains the declaration of the serialization functions. * * This file was generated by the tool fastddsgen. */ -#ifndef _FAST_DDS_GENERATED_ADVANCEDCONFIGURATION_PUBSUBTYPES_H_ -#define _FAST_DDS_GENERATED_ADVANCEDCONFIGURATION_PUBSUBTYPES_H_ +#ifndef _FAST_DDS_GENERATED_CONFIGURATION_PUBSUBTYPES_H_ +#define _FAST_DDS_GENERATED_CONFIGURATION_PUBSUBTYPES_H_ #include #include @@ -29,12 +29,12 @@ #include #include -#include "AdvancedConfiguration.h" +#include "Configuration.h" #if !defined(GEN_API_VER) || (GEN_API_VER != 2) #error \ - Generated AdvancedConfiguration is not compatible with current installed Fast DDS. Please, regenerate it with fastddsgen. + Generated Configuration is not compatible with current installed Fast DDS. Please, regenerate it with fastddsgen. #endif // GEN_API_VER @@ -43,18 +43,18 @@ /*! - * @brief This class represents the TopicDataType of the type AdvancedConfiguration defined by the user in the IDL file. - * @ingroup AdvancedConfiguration + * @brief This class represents the TopicDataType of the type Configuration defined by the user in the IDL file. + * @ingroup Configuration */ -class AdvancedConfigurationPubSubType : public eprosima::fastdds::dds::TopicDataType +class ConfigurationPubSubType : public eprosima::fastdds::dds::TopicDataType { public: - typedef AdvancedConfiguration type; + typedef Configuration type; - eProsima_user_DllExport AdvancedConfigurationPubSubType(); + eProsima_user_DllExport ConfigurationPubSubType(); - eProsima_user_DllExport ~AdvancedConfigurationPubSubType() override; + eProsima_user_DllExport ~ConfigurationPubSubType() override; eProsima_user_DllExport bool serialize( void* data, @@ -130,5 +130,5 @@ class AdvancedConfigurationPubSubType : public eprosima::fastdds::dds::TopicData }; -#endif // _FAST_DDS_GENERATED_ADVANCEDCONFIGURATION_PUBSUBTYPES_H_ +#endif // _FAST_DDS_GENERATED_CONFIGURATION_PUBSUBTYPES_H_ diff --git a/examples/cpp/configuration/PublisherApp.cpp b/examples/cpp/configuration/PublisherApp.cpp new file mode 100644 index 00000000000..dde19fc55f6 --- /dev/null +++ b/examples/cpp/configuration/PublisherApp.cpp @@ -0,0 +1,249 @@ +// 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 PublisherApp.cpp + * + */ + +#include "PublisherApp.hpp" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace eprosima::fastdds::dds; +using namespace eprosima::fastdds::rtps; + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace configuration { + +PublisherApp::PublisherApp( + const CLIParser::publisher_config& config) + : participant_(nullptr) + , publisher_(nullptr) + , topic_(nullptr) + , writer_(nullptr) + , type_(new ConfigurationPubSubType()) + , matched_(0) + , period_ms_(config.interval) + , samples_(config.samples) + , stop_(false) + , wait_(config.wait) +{ + // Set up the data type with initial values + configuration_.index(0); + memcpy(configuration_.message().data(), "Configuration", strlen("Configuration") + 1); + configuration_.data(std::vector(config.msg_size, 0xAA)); + + // Create the participant + DomainParticipantQos pqos = PARTICIPANT_QOS_DEFAULT; + pqos.name("Configuration_pub_participant"); + auto factory = DomainParticipantFactory::get_instance(); + if (config.profile_participant.empty()) + { + // Include Participant QoS + pqos.setup_transports(config.transport); + for (auto& transportDescriptor : pqos.transport().user_transports) + { + SocketTransportDescriptor* pT = dynamic_cast(transportDescriptor.get()); + if (pT) + { + pT->TTL = config.ttl; + } + } + participant_ = factory->create_participant(config.domain, pqos); + } + else + { + participant_ = factory->create_participant_with_profile(config.profile_participant); + } + if (participant_ == nullptr) + { + throw std::runtime_error("Participant initialization failed"); + } + + // Register the type + type_.register_type(participant_); + + // Create the publisher + PublisherQos pub_qos = PUBLISHER_QOS_DEFAULT; + participant_->get_default_publisher_qos(pub_qos); + if (!config.partitions.empty()) + { + std::stringstream partitions(config.partitions); + std::string partition; + while (std::getline(partitions, partition, ';')) + { + pub_qos.partition().push_back(partition.c_str()); + } + } + publisher_ = participant_->create_publisher(pub_qos, nullptr, StatusMask::none()); + if (publisher_ == nullptr) + { + throw std::runtime_error("Publisher initialization failed"); + } + + // Create the topic + TopicQos topic_qos = TOPIC_QOS_DEFAULT; + participant_->get_default_topic_qos(topic_qos); + topic_ = participant_->create_topic(config.topic_name, type_.get_type_name(), topic_qos); + if (topic_ == nullptr) + { + throw std::runtime_error("Topic initialization failed"); + } + + // Create the data writer + if (config.profile_writer.empty()) + { + DataWriterQos writer_qos = DATAWRITER_QOS_DEFAULT; + publisher_->get_default_datawriter_qos(writer_qos); + writer_qos.publish_mode().kind = config.publish_mode; + writer_qos.reliability().kind = config.reliability; + writer_qos.durability().kind = config.durability; + writer_qos.history().kind = config.history_kind; + writer_qos.history().depth = config.history_depth; + writer_qos.ownership().kind = config.ownership; + if (config.strength > 0 + && config.ownership != OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS) + { + throw std::runtime_error( + "DataWriter initialization failed: ownership strength is only valid with exclusive ownership"); + } + writer_qos.ownership_strength().value = config.strength; + writer_qos.deadline().period = eprosima::fastrtps::Duration_t(config.deadline * 1e-3); + writer_qos.reliable_writer_qos().disable_positive_acks.enabled = config.disable_positive_ack; + writer_qos.reliable_writer_qos().disable_positive_acks.duration = eprosima::fastrtps::Duration_t( + config.ack_keep_duration * 1e-3); + writer_qos.lifespan().duration = eprosima::fastrtps::Duration_t(config.lifespan * 1e-3); + writer_qos.liveliness().kind = config.liveliness; + writer_qos.liveliness().lease_duration = eprosima::fastrtps::Duration_t( + config.liveliness_lease * 1e-3); + writer_qos.liveliness().announcement_period = eprosima::fastrtps::Duration_t( + config.liveliness_assert * 1e-3); + writer_ = publisher_->create_datawriter(topic_, writer_qos, this, StatusMask::all()); + } + else + { + writer_ = publisher_->create_datawriter_with_profile(topic_, config.profile_writer, this, StatusMask::all()); + } + if (writer_ == nullptr) + { + throw std::runtime_error("DataWriter initialization failed"); + } +} + +PublisherApp::~PublisherApp() +{ + if (nullptr != participant_) + { + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); + + // Delete DomainParticipant + DomainParticipantFactory::get_instance()->delete_participant(participant_); + } +} + +void PublisherApp::on_publication_matched( + eprosima::fastdds::dds::DataWriter* /*writer*/, + const PublicationMatchedStatus& info) +{ + if (info.current_count_change == 1) + { + matched_ = info.current_count; + std::cout << "Publisher matched." << std::endl; + if (matched_ >= static_cast(wait_)) + { + cv_.notify_one(); + } + } + else if (info.current_count_change == -1) + { + matched_ = info.current_count; + std::cout << "Publisher unmatched." << std::endl; + } + else + { + std::cout << info.current_count_change + << " is not a valid value for PublicationMatchedStatus current count change" << std::endl; + } +} + +void PublisherApp::run() +{ + while (!is_stopped() && ((samples_ == 0) || (configuration_.index() < samples_))) + { + if (publish()) + { + std::cout << "Sample: '" << configuration_.message().data() << "' with index: '" + << configuration_.index() << "' (" << static_cast(configuration_.data().size()) + << " Bytes) SENT" << std::endl; + } + // Wait for period or stop event + std::unique_lock terminate_lock(mutex_); + terminate_cv_.wait_for(terminate_lock, std::chrono::milliseconds(period_ms_), [&]() + { + return is_stopped(); + }); + } +} + +bool PublisherApp::publish() +{ + bool ret = false; + // Wait for the data endpoints discovery + std::unique_lock matched_lock(mutex_); + cv_.wait(matched_lock, [&]() + { + // at least one has been discovered + return ((matched_ > 0) || is_stopped()); + }); + if (!is_stopped()) + { + configuration_.index(configuration_.index() + 1); + ret = writer_->write(&configuration_); + } + return ret; +} + +bool PublisherApp::is_stopped() +{ + return stop_.load(); +} + +void PublisherApp::stop() +{ + stop_.store(true); + cv_.notify_one(); +} + +} // namespace configuration +} // namespace examples +} // namespace fastdds +} // namespace eprosima diff --git a/examples/cpp/configuration/PublisherApp.hpp b/examples/cpp/configuration/PublisherApp.hpp new file mode 100644 index 00000000000..1f4551a9e98 --- /dev/null +++ b/examples/cpp/configuration/PublisherApp.hpp @@ -0,0 +1,101 @@ +// 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 PublisherApp.hpp + * + */ + +#ifndef _FASTDDS_CONFIGURATION_PUBLISHER_APP_HPP_ +#define _FASTDDS_CONFIGURATION_PUBLISHER_APP_HPP_ + + +#include + +#include +#include +#include + +#include "Application.hpp" +#include "CLIParser.hpp" +#include "ConfigurationPubSubTypes.h" + +using namespace eprosima::fastdds::dds; + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace configuration { + +class PublisherApp : public Application, public DataWriterListener +{ +public: + + PublisherApp( + const CLIParser::publisher_config& config); + + ~PublisherApp(); + + //! Publisher matched method + void on_publication_matched( + DataWriter* writer, + const PublicationMatchedStatus& info) override; + + //! Run publisher + void run() override; + + //! Trigger the end of execution + void stop() override; + +private: + + //! Return the current state of execution + bool is_stopped(); + + //! Publish a sample + bool publish(); + + Configuration configuration_; + + DomainParticipant* participant_; + + Publisher* publisher_; + + Topic* topic_; + + DataWriter* writer_; + + TypeSupport type_; + + std::condition_variable cv_; + + int16_t matched_; + + std::mutex mutex_; + + uint16_t period_ms_; + + uint16_t samples_; + + std::atomic stop_; + + int16_t wait_; +}; + +} // namespace configuration +} // namespace examples +} // namespace fastdds +} // namespace eprosima + +#endif /* _FASTDDS_CONFIGURATION_PUBLISHER_APP_HPP_ */ diff --git a/examples/cpp/configuration/README.md b/examples/cpp/configuration/README.md new file mode 100644 index 00000000000..bf02665a26e --- /dev/null +++ b/examples/cpp/configuration/README.md @@ -0,0 +1,114 @@ +# Configuration example + +The *eProsima Fast DDS configuration* example is an application intended to be a DDS deployment configuration playground. + +This example is part of the suite of examples designed by eProsima that aims to illustrate the features and possible configurations of DDS deployments through *eProsima Fast DDS*. + +In this case, the *configuration* example allows a long list of configurable options to show how the DDS entities behave under different configurations, and includes a set of meta-examples to illustrate those behaviors. +e simplest deployment of a Fast DDS publisher and subscriber. + +* [Description of the example](#description-of-the-example) +* [Run the example](#run-the-example) +* TODO list meta-examples +* [XML Configuration](#xml-configuration) + +## Description of the example + +TODO (this is pasted from previous readme) + +This example extends the configuration options of a trivial HelloWorld by letting the user specify properties of entities such as durability, reliability or specify the transport protocol to be used, among other possibilities. +This could be useful, for example, to quickly test whether two endpoints are compatible and hence would match. +Additionally, the message type includes a data sequence which size can be set by the user, allowing to send large data between endpoints. +Note: Due to the nature of the data type (not bounded), this example will not use data sharing. + +## Run the example + +To launch this example, two different terminals are required. One of them will run the publisher example application, and the other will run the subscriber application. + +### Configuration publisher + +* Ubuntu ( / MacOS ) + + ```shell + user@machine:example_path$ ./configuration publisher + Publisher running. Please press Ctrl+C to stop the Publisher at any time. + ``` + +* Windows + + ```powershell + example_path> configuration.exe publisher + Publisher running. Please press Ctrl+C to stop the Publisher at any time. + ``` + +### Configuration subscriber + +* Ubuntu ( / MacOS ) + + ```shell + user@machine:example_path$ ./configuration subscriber + Subscriber running. Please press Ctrl+C to stop the Subscriber at any time. + ``` + +* Windows + + ```powershell + example_path> configuration.exe subscriber + Subscriber running. Please press Ctrl+C to stop the Subscriber at any time. + ``` + +All the example available flags can be queried running the executable with the ``-h`` or ``--help`` flag. + +### Expected output + +Regardless of which application is run first, since the publisher will not start sending data until a subscriber is discovered, the expected output both for publishers and subscribers is a first displayed message acknowledging the match, followed by the amount of samples sent or received until Ctrl+C is pressed. + +### Configuration publisher + +```shell +Publisher running. Please press Ctrl+C to stop the Publisher at any time. +Publisher matched. +Sample: 'Configuration' with index: '1' (10 Bytes) SENT +Sample: 'Configuration' with index: '2' (10 Bytes) SENT +Sample: 'Configuration' with index: '3' (10 Bytes) SENT +... +``` + +### Configuration subscriber + +```shell +Subscriber running. Please press Ctrl+C to stop the Subscriber at any time. +Subscriber matched. +Sample: 'Configuration' with index: '1' (10 Bytes) RECEIVED +Sample: 'Configuration' with index: '2' (10 Bytes) RECEIVED +Sample: 'Configuration' with index: '3' (10 Bytes) RECEIVED +... +``` + +When Ctrl+C is pressed to stop one of the applications, the other one will show the unmatched status, displaying an informative message, and it will stop sending / receiving messages. The following is a possible output of the publisher application when stopping the subscriber app. + +```shell +Sample: 'Configuration' with index: '8' (10 Bytes) SENT +Sample: 'Configuration' with index: '9' (10 Bytes) SENT +Sample: 'Configuration' with index: '10' (10 Bytes) SENT +Sample: 'Configuration' with index: '11' (10 Bytes) SENT +Publisher unmatched. +``` + +## TODO list meta-examples + + +## XML Configuration + +TODO refactor this (from previous readme) + +Using argument `--xml-profile ` will configure the internal DomainParticipant using the profile name loaded from an XML file. +To load XML files check [Fast DDS documentation](https://fast-dds.docs.eprosima.com/en/latest/fastdds/xml_configuration/xml_configuration.html). +Loading example XML configuration [file](shm_off.xml) and calling this example with `--xml-profile no_shm_participant_profile` will disable Shared Memory Transport for the internal DomainParticipant created. + +This code presents how to run a publisher with this example without Shared Memory: + +```sh +# From AdvancedConfigurationExample installation dir +FASTDDS_DEFAULT_PROFILES_FILE=shm_off.xml ./AdvancedConfigurationExample publisher --xml-profile no_shm_participant_profile +``` diff --git a/examples/cpp/configuration/SubscriberApp.cpp b/examples/cpp/configuration/SubscriberApp.cpp new file mode 100644 index 00000000000..7d27d89c1e4 --- /dev/null +++ b/examples/cpp/configuration/SubscriberApp.cpp @@ -0,0 +1,216 @@ +// 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 SubscriberApp.cpp + * + */ + +#include "SubscriberApp.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Application.hpp" +#include "CLIParser.hpp" +#include "ConfigurationPubSubTypes.h" + +using namespace eprosima::fastdds::dds; +using namespace eprosima::fastdds::rtps; + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace configuration { + +SubscriberApp::SubscriberApp( + const CLIParser::subscriber_config& config) + : participant_(nullptr) + , subscriber_(nullptr) + , topic_(nullptr) + , reader_(nullptr) + , type_(new ConfigurationPubSubType()) + , received_samples_(0) + , samples_(config.samples) +{ + // Create the participant + DomainParticipantQos pqos = PARTICIPANT_QOS_DEFAULT; + pqos.name("Configuration_sub_participant"); + auto factory = DomainParticipantFactory::get_instance(); + if (config.profile_participant.empty()) + { + // Include Participant QoS + pqos.setup_transports(config.transport); + for (auto& transportDescriptor : pqos.transport().user_transports) + { + SocketTransportDescriptor* pT = dynamic_cast(transportDescriptor.get()); + if (pT) + { + pT->TTL = config.ttl; + } + } + participant_ = factory->create_participant(config.domain, pqos); + } + else + { + participant_ = factory->create_participant_with_profile(config.profile_participant); + } + if (participant_ == nullptr) + { + throw std::runtime_error("Participant initialization failed"); + } + + // Register the type + type_.register_type(participant_); + + // Create the subscriber + SubscriberQos sub_qos = SUBSCRIBER_QOS_DEFAULT; + participant_->get_default_subscriber_qos(sub_qos); + if (!config.partitions.empty()) + { + std::stringstream partitions(config.partitions); + std::string partition; + while (std::getline(partitions, partition, ';')) + { + sub_qos.partition().push_back(partition.c_str()); + } + } + subscriber_ = participant_->create_subscriber(sub_qos, nullptr, StatusMask::none()); + if (subscriber_ == nullptr) + { + throw std::runtime_error("Subscriber initialization failed"); + } + + // Create the topic + TopicQos topic_qos = TOPIC_QOS_DEFAULT; + participant_->get_default_topic_qos(topic_qos); + topic_ = participant_->create_topic(config.topic_name, type_.get_type_name(), topic_qos); + if (topic_ == nullptr) + { + throw std::runtime_error("Topic initialization failed"); + } + + // Create the data reader + if (config.profile_reader.empty()) + { + DataReaderQos reader_qos = DATAREADER_QOS_DEFAULT; + subscriber_->get_default_datareader_qos(reader_qos); + reader_qos.reliability().kind = config.reliability; + reader_qos.durability().kind = config.durability; + reader_qos.history().kind = config.history_kind; + reader_qos.history().depth = config.history_depth; + reader_qos.ownership().kind = config.ownership; + reader_qos.deadline().period = eprosima::fastrtps::Duration_t(config.deadline * 1e-3); + reader_qos.lifespan().duration = eprosima::fastrtps::Duration_t(config.lifespan * 1e-3); + reader_qos.liveliness().kind = config.liveliness; + reader_qos.liveliness().lease_duration = eprosima::fastrtps::Duration_t( + config.liveliness_lease * 1e-3); + reader_qos.liveliness().announcement_period = eprosima::fastrtps::Duration_t( + config.liveliness_assert * 1e-3); + reader_ = subscriber_->create_datareader(topic_, reader_qos, this, StatusMask::all()); + } + else + { + reader_ = subscriber_->create_datareader_with_profile(topic_, config.profile_reader, this, StatusMask::all()); + } + if (reader_ == nullptr) + { + throw std::runtime_error("DataReader initialization failed"); + } +} + +SubscriberApp::~SubscriberApp() +{ + if (nullptr != participant_) + { + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); + + // Delete DomainParticipant + DomainParticipantFactory::get_instance()->delete_participant(participant_); + } +} + +void SubscriberApp::on_subscription_matched( + DataReader* /*reader*/, + const SubscriptionMatchedStatus& info) +{ + if (info.current_count_change == 1) + { + std::cout << "Subscriber matched." << std::endl; + } + else if (info.current_count_change == -1) + { + std::cout << "Subscriber unmatched." << std::endl; + } + else + { + std::cout << info.current_count_change + << " is not a valid value for SubscriptionMatchedStatus current count change" << std::endl; + } +} + +void SubscriberApp::on_data_available( + DataReader* reader) +{ + SampleInfo info; + if ((!is_stopped()) && (ReturnCode_t::RETCODE_OK == reader->take_next_sample(&configuration_, &info))) + { + if ((info.instance_state == ALIVE_INSTANCE_STATE) && info.valid_data) + { + received_samples_++; + std::cout << "Sample: '" << configuration_.message().data() << "' with index: '" << + configuration_.index() << "' (" << static_cast(configuration_.data().size()) << + " Bytes) RECEIVED" << std::endl; + if ((samples_ > 0) && (received_samples_ >= samples_)) + { + stop(); + } + } + } +} + +void SubscriberApp::run() +{ + std::unique_lock lock_(mutex_); + cv_.wait(lock_, [&] + { + return is_stopped(); + }); +} + +bool SubscriberApp::is_stopped() +{ + return stop_.load(); +} + +void SubscriberApp::stop() +{ + stop_.store(true); + cv_.notify_all(); +} + +} // namespace configuration +} // namespace examples +} // namespace fastdds +} // namespace eprosima diff --git a/examples/cpp/configuration/SubscriberApp.hpp b/examples/cpp/configuration/SubscriberApp.hpp new file mode 100644 index 00000000000..cfa89b52ebf --- /dev/null +++ b/examples/cpp/configuration/SubscriberApp.hpp @@ -0,0 +1,97 @@ +// 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 SubscriberApp.h + * + */ + +#ifndef _FASTDDS_CONFIGURATION_SUBSCRIBER_APP_HPP_ +#define _FASTDDS_CONFIGURATION_SUBSCRIBER_APP_HPP_ + +#include +#include +#include + +#include + +#include "Application.hpp" +#include "CLIParser.hpp" +#include "ConfigurationPubSubTypes.h" + +using namespace eprosima::fastdds::dds; + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace configuration { + +class SubscriberApp : public Application, public DataReaderListener +{ +public: + + SubscriberApp( + const CLIParser::subscriber_config& config); + + virtual ~SubscriberApp(); + + //! Subscription callback + void on_data_available( + DataReader* reader) override; + + //! Subscriber matched method + void on_subscription_matched( + DataReader* reader, + const SubscriptionMatchedStatus& info) override; + + //! Run the subscriber + void run() override; + + //! Trigger the end of execution + void stop() override; + +private: + + //! Return the current state of execution + bool is_stopped(); + + Configuration configuration_; + + DomainParticipant* participant_; + + Subscriber* subscriber_; + + Topic* topic_; + + DataReader* reader_; + + TypeSupport type_; + + static std::condition_variable cv_; + + static std::mutex mutex_; + + uint32_t received_samples_; + + uint32_t samples_; + + static std::atomic stop_; +}; + +} // namespace configuration +} // namespace examples +} // namespace fastdds +} // namespace eprosima + +#endif /* _FASTDDS_CONFIGURATION_SUBSCRIBER_APP_HPP_ */ diff --git a/examples/cpp/configuration/configuration_profile.xml b/examples/cpp/configuration/configuration_profile.xml new file mode 100644 index 00000000000..929f0ce0d7c --- /dev/null +++ b/examples/cpp/configuration/configuration_profile.xml @@ -0,0 +1,96 @@ + + + + 0 + + configuration_participant + + + + + + TRANSIENT_LOCAL + + + RELIABLE + + + + + KEEP_LAST + 100 + + + 100 + 1 + 100 + + + + + + + + VOLATILE + + + BEST_EFFORT + + + + + KEEP_LAST + 1 + + + 1 + 1 + 1 + + + + + + + + TRANSIENT_LOCAL + + + RELIABLE + + + + + KEEP_LAST + 100 + + + 100 + 1 + 100 + + + + + + + + VOLATILE + + + BEST_EFFORT + + + + + KEEP_LAST + 1 + + + 1 + 1 + 1 + + + + diff --git a/examples/cpp/configuration/main.cpp b/examples/cpp/configuration/main.cpp new file mode 100644 index 00000000000..e13a59194d3 --- /dev/null +++ b/examples/cpp/configuration/main.cpp @@ -0,0 +1,103 @@ +// 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 main.cpp + * + */ + +#include +#include +#include + +#include +#include + +#include "Application.hpp" +#include "CLIParser.hpp" + +using eprosima::fastdds::dds::Log; + +using namespace eprosima::fastdds::examples::configuration; + +std::function stop_app_handler; +void signal_handler( + int signum) +{ + stop_app_handler(signum); +} + +int main( + int argc, + char** argv) +{ + auto ret = EXIT_SUCCESS; + CLIParser::configuration_config config = CLIParser::parse_cli_options(argc, argv); + uint16_t samples = 0; + switch (config.entity) + { + case CLIParser::EntityKind::PUBLISHER: + samples = config.pub_config.samples; + break; + case CLIParser::EntityKind::SUBSCRIBER: + samples = config.sub_config.samples; + break; + default: + break; + } + + std::string app_name = CLIParser::parse_entity_kind(config.entity); + std::shared_ptr app; + + try + { + app = Application::make_app(config); + } + catch (const std::runtime_error& e) + { + EPROSIMA_LOG_ERROR(app_name, e.what()); + ret = EXIT_FAILURE; + } + + std::thread thread(&Application::run, app); + + if (samples == 0) + { + std::cout << app_name << " running. Please press Ctrl+C to stop the " + << app_name << " at any time." << std::endl; + } + else + { + std::cout << app_name << " running for " << samples << " samples. Please press Ctrl+C to stop the " + << app_name << " at any time." << std::endl; + } + + stop_app_handler = [&](int signum) + { + std::cout << "\n" << CLIParser::parse_signal(signum) << " received, stopping " << app_name + << " execution." << std::endl; + app->stop(); + }; + + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); +#ifndef _WIN32 + signal(SIGQUIT, signal_handler); + signal(SIGHUP, signal_handler); +#endif // _WIN32 + + thread.join(); + Log::Reset(); + return ret; +} diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationPublisher.cpp b/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationPublisher.cpp deleted file mode 100644 index 63420653ed1..00000000000 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationPublisher.cpp +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright 2022 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 AdvancedConfigurationPublisher.cpp - * - */ - -#include "AdvancedConfigurationPublisher.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace eprosima::fastdds::dds; -using namespace eprosima::fastdds::rtps; - -std::atomic HelloWorldPublisher::stop_(false); -std::mutex HelloWorldPublisher::PubListener::wait_matched_cv_mtx_; -std::condition_variable HelloWorldPublisher::PubListener::wait_matched_cv_; - -HelloWorldPublisher::HelloWorldPublisher() - : participant_(nullptr) - , publisher_(nullptr) - , topic_(nullptr) - , writer_(nullptr) - , type_(new AdvancedConfigurationPubSubType()) -{ -} - -bool HelloWorldPublisher::is_stopped() -{ - return stop_; -} - -void HelloWorldPublisher::stop() -{ - stop_ = true; - PubListener::awake(); -} - -bool HelloWorldPublisher::init( - const std::string& topic_name, - uint32_t domain, - uint32_t num_wait_matched, - bool async, - TransportType transport, - bool reliable, - bool transient, - int hops, - const std::string& partitions, - bool use_ownership, - unsigned int ownership_strength, - int data_size, - const std::string& profile) -{ - - hello_.index(0); - memcpy(hello_.message().data(), "HelloWorld ", strlen("HelloWorld") + 1); - hello_.data(std::vector(data_size, 0xAA)); - - DomainParticipantQos pqos; - pqos.name("Participant_pub"); - listener_.set_num_wait_matched(num_wait_matched); - - if (profile.empty()) - { - // TRANSPORT CONFIG - // If it is set, not use default and set the transport - if (transport != DEFAULT || hops > 0 ) - { - pqos.transport().use_builtin_transports = false; - - switch ( transport ) - { - case SHM: - { - auto shm_transport = std::make_shared(); - pqos.transport().user_transports.push_back(shm_transport); - } - break; - case UDPv4: - { - auto udp_transport = std::make_shared(); - pqos.transport().user_transports.push_back(udp_transport); - } - break; - case UDPv6: - { - auto udp_transport = std::make_shared(); - pqos.transport().user_transports.push_back(udp_transport); - } - break; - case DEFAULT: - default: - { - // mimick default transport selection - auto udp_transport = std::make_shared(); - pqos.transport().user_transports.push_back(udp_transport); -#ifdef SHM_TRANSPORT_BUILTIN - auto shm_transport = std::make_shared(); - pqos.transport().user_transports.push_back(shm_transport); -#endif // SHM_TRANSPORT_BUILTIN - } - } - - if ( hops > 0 ) - { - for (auto& transportDescriptor : pqos.transport().user_transports) - { - SocketTransportDescriptor* pT = dynamic_cast(transportDescriptor.get()); - if (pT) - { - pT->TTL = (uint8_t)std::min(hops, 255); - } - } - } - } - - // CREATE THE PARTICIPANT - participant_ = DomainParticipantFactory::get_instance()->create_participant(domain, pqos); - } - else - { - // Create participant from xml profile - participant_ = DomainParticipantFactory::get_instance()->create_participant_with_profile(profile); - } - - if (participant_ == nullptr) - { - return false; - } - - // REGISTER THE TYPE - type_.register_type(participant_); - - // CREATE THE PUBLISHER - PublisherQos pbqos; - - if (!partitions.empty()) - { - // Divide in partitions by ; - std::stringstream spartitions(partitions); - std::string partition_cut; - while (std::getline(spartitions, partition_cut, ';')) - { - pbqos.partition().push_back(partition_cut.c_str()); - } - } - - // Create publisher - publisher_ = participant_->create_publisher(pbqos, nullptr); - - if (publisher_ == nullptr) - { - return false; - } - - // CREATE THE TOPIC - topic_ = participant_->create_topic(topic_name, type_.get_type_name(), TOPIC_QOS_DEFAULT); - - if (topic_ == nullptr) - { - return false; - } - - // CREATE THE WRITER - DataWriterQos wqos = DATAWRITER_QOS_DEFAULT; - - // Data sharing set in endpoint. If it is not default, set it to off - if (transport != DEFAULT) - { - wqos.data_sharing().off(); - } - else - { - wqos.data_sharing().automatic(); // default - } - - if (async) - { - wqos.publish_mode().kind = ASYNCHRONOUS_PUBLISH_MODE; - } - else - { - wqos.publish_mode().kind = SYNCHRONOUS_PUBLISH_MODE; // default - } - - if (reliable) - { - wqos.reliability().kind = RELIABLE_RELIABILITY_QOS; - wqos.history().kind = KEEP_ALL_HISTORY_QOS; - } - else - { - wqos.reliability().kind = BEST_EFFORT_RELIABILITY_QOS; // default in this example (although default value for - // writters' qos actually is RELIABLE) - } - - if (transient) - { - wqos.durability().kind = TRANSIENT_LOCAL_DURABILITY_QOS; - wqos.history().kind = KEEP_ALL_HISTORY_QOS; // store previously sent samples so they can be resent to newly - // matched DataReaders - } - else - { - wqos.durability().kind = VOLATILE_DURABILITY_QOS; // default in this example (although default value for - // writters' qos actually is TRANSIENT_LOCAL) - } - - // Set ownership - if (use_ownership) - { - wqos.ownership().kind = OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS; - wqos.ownership_strength().value = ownership_strength; - } - - writer_ = publisher_->create_datawriter(topic_, wqos, &listener_); - - if (writer_ == nullptr) - { - return false; - } - - std::cout << "Publisher Participant created with DataWriter Guid [ " << writer_->guid() << " ]." << std::endl; - return true; -} - -HelloWorldPublisher::~HelloWorldPublisher() -{ - if (participant_ != nullptr) - { - if (publisher_ != nullptr) - { - if (writer_ != nullptr) - { - publisher_->delete_datawriter(writer_); - } - participant_->delete_publisher(publisher_); - } - if (topic_ != nullptr) - { - participant_->delete_topic(topic_); - } - DomainParticipantFactory::get_instance()->delete_participant(participant_); - } -} - -void HelloWorldPublisher::PubListener::on_publication_matched( - eprosima::fastdds::dds::DataWriter*, - const eprosima::fastdds::dds::PublicationMatchedStatus& info) -{ - if (info.current_count_change == 1) - { - matched_ = info.current_count; - std::cout << "Publisher matched [ " << iHandle2GUID(info.last_subscription_handle) << " ]." << std::endl; - if (enough_matched()) - { - awake(); - } - } - else if (info.current_count_change == -1) - { - matched_ = info.current_count; - std::cout << "Publisher unmatched [ " << iHandle2GUID(info.last_subscription_handle) << " ]." << std::endl; - } - else - { - std::cout << info.current_count_change - << " is not a valid value for PublicationMatchedStatus current count change" << std::endl; - } -} - -void HelloWorldPublisher::PubListener::set_num_wait_matched( - uint32_t num_wait_matched) -{ - num_wait_matched_ = num_wait_matched; -} - -bool HelloWorldPublisher::PubListener::enough_matched() -{ - return matched_ >= num_wait_matched_; -} - -void HelloWorldPublisher::PubListener::wait() -{ - std::unique_lock lck(wait_matched_cv_mtx_); - wait_matched_cv_.wait(lck, [this] - { - return enough_matched() || is_stopped(); - }); -} - -void HelloWorldPublisher::PubListener::awake() -{ - wait_matched_cv_.notify_all(); -} - -void HelloWorldPublisher::runThread( - uint32_t samples, - uint32_t sleep) -{ - while (!is_stopped() && (samples == 0 || hello_.index() < samples)) - { - if (listener_.enough_matched()) - { - publish(); - std::cout << "Sample sent: " << hello_.message().data() << " " << hello_.index() << - " (" << static_cast(hello_.data().size()) << " Bytes)" - << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); - } - else - { - listener_.wait(); - } - } -} - -void HelloWorldPublisher::run( - uint32_t samples, - uint32_t sleep) -{ - stop_ = false; - std::thread thread(&HelloWorldPublisher::runThread, this, samples, sleep); - if (samples == 0) - { - std::cout << "Publisher running. Please press CTRL+C to stop the Publisher at any time." << std::endl; - } - else - { - std::cout << "Publisher running " << samples << - " samples. Please press CTRL+C to stop the Publisher at any time." << std::endl; - } - signal(SIGINT, [](int signum) - { - std::cout << "SIGINT received, stopping Publisher execution." << std::endl; - static_cast(signum); HelloWorldPublisher::stop(); - }); - thread.join(); -} - -void HelloWorldPublisher::publish() -{ - hello_.index(hello_.index() + 1); - writer_->write(&hello_); -} diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationPublisher.h b/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationPublisher.h deleted file mode 100644 index 96ad39d641f..00000000000 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationPublisher.h +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2022 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 AdvancedConfigurationPublisher.h - * - */ - -#ifndef _EPROSIMA_FASTDDS_EXAMPLES_CPP_DDS_ADVANCEDCONFIGURATIONEXAMPLE_ADVANCEDCONFIGURATIONPUBLISHER_H_ -#define _EPROSIMA_FASTDDS_EXAMPLES_CPP_DDS_ADVANCEDCONFIGURATIONEXAMPLE_ADVANCEDCONFIGURATIONPUBLISHER_H_ - -#include -#include -#include - -#include -#include -#include - -#include "AdvancedConfigurationPubSubTypes.h" -#include "types.hpp" - -/** - * Class used to group into a single working unit a Publisher with a DataWriter, its listener, and a TypeSupport member - * corresponding to the HelloWorld datatype - */ -class HelloWorldPublisher -{ -public: - - HelloWorldPublisher(); - - virtual ~HelloWorldPublisher(); - - //! Initialize the publisher - bool init( - const std::string& topic_name, - uint32_t domain, - uint32_t num_wait_matched, - bool async, - TransportType transport, - bool reliable, - bool transient, - int hops, - const std::string& partitions, - bool use_ownership, - unsigned int ownership_strength, - int data_size, - const std::string& profile); - - //! Publish a sample - void publish(); - - //! Run for number samples, publish every sleep seconds - void run( - uint32_t number, - uint32_t sleep); - - //! Return the current state of execution - static bool is_stopped(); - - //! Trigger the end of execution - static void stop(); - -private: - - AdvancedConfiguration hello_; - - eprosima::fastdds::dds::DomainParticipant* participant_; - - eprosima::fastdds::dds::Publisher* publisher_; - - eprosima::fastdds::dds::Topic* topic_; - - eprosima::fastdds::dds::DataWriter* writer_; - - eprosima::fastdds::dds::TypeSupport type_; - - /** - * Class handling discovery events and dataflow - */ - class PubListener : public eprosima::fastdds::dds::DataWriterListener - { - public: - - PubListener() - : matched_(0) - , num_wait_matched_(0) - { - } - - ~PubListener() override - { - } - - //! Callback executed when a DataReader is matched or unmatched - void on_publication_matched( - eprosima::fastdds::dds::DataWriter* writer, - const eprosima::fastdds::dds::PublicationMatchedStatus& info) override; - - //! Set the number of matched DataReaders required for publishing - void set_num_wait_matched( - uint32_t num_wait_matched); - - //! Return true if there are at least num_wait_matched_ matched DataReaders - bool enough_matched(); - - //! Block the thread until enough DataReaders are matched - void wait(); - - //! Unblock the thread so publication of samples begins/resumes - static void awake(); - - private: - - //! Number of DataReaders matched to the associated DataWriter - std::atomic matched_; - - //! Number of matched DataReaders required for publishing - uint32_t num_wait_matched_; - - //! Protects wait_matched condition variable - static std::mutex wait_matched_cv_mtx_; - - //! Waits until enough DataReaders are matched - static std::condition_variable wait_matched_cv_; - } - listener_; - - //! Run thread for number samples, publish every sleep seconds - void runThread( - uint32_t number, - uint32_t sleep); - - //! Member used for control flow purposes - static std::atomic stop_; -}; - - - -#endif /* _EPROSIMA_FASTDDS_EXAMPLES_CPP_DDS_ADVANCEDCONFIGURATIONEXAMPLE_ADVANCEDCONFIGURATIONPUBLISHER_H_ */ diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationSubscriber.cpp b/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationSubscriber.cpp deleted file mode 100644 index 8323c5b9874..00000000000 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationSubscriber.cpp +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright 2022 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 AdvancedConfigurationSubscriber.cpp - * - */ - -#include "AdvancedConfigurationSubscriber.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace eprosima::fastdds::dds; -using namespace eprosima::fastdds::rtps; - -std::atomic HelloWorldSubscriber::stop_(false); -std::mutex HelloWorldSubscriber::terminate_cv_mtx_; -std::condition_variable HelloWorldSubscriber::terminate_cv_; - -HelloWorldSubscriber::HelloWorldSubscriber() - : participant_(nullptr) - , subscriber_(nullptr) - , topic_(nullptr) - , reader_(nullptr) - , type_(new AdvancedConfigurationPubSubType()) -{ -} - -bool HelloWorldSubscriber::is_stopped() -{ - return stop_; -} - -void HelloWorldSubscriber::stop() -{ - stop_ = true; - terminate_cv_.notify_all(); -} - -bool HelloWorldSubscriber::init( - const std::string& topic_name, - uint32_t max_messages, - uint32_t domain, - TransportType transport, - bool reliable, - bool transient, - int hops, - const std::string& partitions, - bool use_ownership, - const std::string& profile) -{ - DomainParticipantQos pqos; - pqos.name("Participant_sub"); - - if (profile.empty()) - { - // TRANSPORT CONFIG - // If it is set, not use default and set the transport - if (transport != DEFAULT || hops > 0 ) - { - pqos.transport().use_builtin_transports = false; - - switch ( transport ) - { - case SHM: - { - auto shm_transport = std::make_shared(); - pqos.transport().user_transports.push_back(shm_transport); - } - break; - case UDPv4: - { - auto udp_transport = std::make_shared(); - pqos.transport().user_transports.push_back(udp_transport); - } - break; - case UDPv6: - { - auto udp_transport = std::make_shared(); - pqos.transport().user_transports.push_back(udp_transport); - } - break; - case DEFAULT: - default: - { - // mimick default transport selection - auto udp_transport = std::make_shared(); - pqos.transport().user_transports.push_back(udp_transport); - #ifdef SHM_TRANSPORT_BUILTIN - auto shm_transport = std::make_shared(); - pqos.transport().user_transports.push_back(shm_transport); - #endif // SHM_TRANSPORT_BUILTIN - } - } - - if ( hops > 0 ) - { - for (auto& transportDescriptor : pqos.transport().user_transports) - { - SocketTransportDescriptor* pT = dynamic_cast(transportDescriptor.get()); - if (pT) - { - pT->TTL = (uint8_t)std::min(hops, 255); - } - } - } - } - - // CREATE THE PARTICIPANT - participant_ = DomainParticipantFactory::get_instance()->create_participant(domain, pqos); - } - else - { - // Create participant from xml profile - participant_ = DomainParticipantFactory::get_instance()->create_participant_with_profile(profile); - } - - if (participant_ == nullptr) - { - return false; - } - - // REGISTER THE TYPE - type_.register_type(participant_); - - // CREATE THE SUBSCRIBER - SubscriberQos sqos; - - if (!partitions.empty()) - { - // Divide in partitions by ; - std::stringstream spartitions(partitions); - std::string partition_cut; - while (std::getline(spartitions, partition_cut, ';')) - { - sqos.partition().push_back(partition_cut.c_str()); - } - } - - subscriber_ = participant_->create_subscriber(sqos, nullptr); - - if (subscriber_ == nullptr) - { - return false; - } - - // CREATE THE TOPIC - topic_ = participant_->create_topic( - topic_name, - "AdvancedConfiguration", - TOPIC_QOS_DEFAULT); - - if (topic_ == nullptr) - { - return false; - } - - // CREATE THE READER - if (max_messages > 0) - { - listener_.set_max_messages(max_messages); - } - DataReaderQos rqos = DATAREADER_QOS_DEFAULT; - - // Data sharing set in endpoint. If it is not default, set it to off - if (transport != DEFAULT) - { - rqos.data_sharing().off(); - } - else - { - rqos.data_sharing().automatic(); // default - } - - if (reliable) - { - rqos.reliability().kind = RELIABLE_RELIABILITY_QOS; - rqos.history().kind = KEEP_ALL_HISTORY_QOS; - } - else - { - rqos.reliability().kind = BEST_EFFORT_RELIABILITY_QOS; // default - } - - if (transient) - { - rqos.durability().kind = TRANSIENT_LOCAL_DURABILITY_QOS; - } - else - { - rqos.durability().kind = VOLATILE_DURABILITY_QOS; // default - } - - // Set ownership - if (use_ownership) - { - rqos.ownership().kind = OwnershipQosPolicyKind::EXCLUSIVE_OWNERSHIP_QOS; - } - - reader_ = subscriber_->create_datareader(topic_, rqos, &listener_); - - if (reader_ == nullptr) - { - return false; - } - - std::cout << "Subscriber Participant created with DataReader Guid [ " << reader_->guid() << " ]." << std::endl; - - return true; -} - -HelloWorldSubscriber::~HelloWorldSubscriber() -{ - if (participant_ != nullptr) - { - if (subscriber_ != nullptr) - { - if (reader_ != nullptr) - { - subscriber_->delete_datareader(reader_); - } - participant_->delete_subscriber(subscriber_); - } - if (topic_ != nullptr) - { - participant_->delete_topic(topic_); - } - DomainParticipantFactory::get_instance()->delete_participant(participant_); - } -} - -void HelloWorldSubscriber::SubListener::set_max_messages( - uint32_t max_messages) -{ - max_messages_ = max_messages; -} - -void HelloWorldSubscriber::SubListener::on_subscription_matched( - DataReader*, - const SubscriptionMatchedStatus& info) -{ - if (info.current_count_change == 1) - { - matched_ = info.current_count; - std::cout << "Subscriber matched [ " << iHandle2GUID(info.last_publication_handle) << " ]." << std::endl; - } - else if (info.current_count_change == -1) - { - matched_ = info.current_count; - std::cout << "Subscriber unmatched [ " << iHandle2GUID(info.last_publication_handle) << " ]." << std::endl; - } - else - { - std::cout << info.current_count_change - << " is not a valid value for SubscriptionMatchedStatus current count change" << std::endl; - } -} - -void HelloWorldSubscriber::SubListener::on_data_available( - DataReader* reader) -{ - SampleInfo info; - while ((reader->take_next_sample(&hello_, &info) == ReturnCode_t::RETCODE_OK) && !is_stopped()) - { - if (info.instance_state == ALIVE_INSTANCE_STATE) - { - samples_++; - // Print your structure data here. - std::cout << "Sample received: " << hello_.message().data() << " " << hello_.index() << - " (" << static_cast(hello_.data().size()) << " Bytes)" << std::endl; - - if (max_messages_ > 0 && (samples_ >= max_messages_)) - { - stop(); - } - } - } -} - -void HelloWorldSubscriber::run( - uint32_t samples) -{ - stop_ = false; - if (samples > 0) - { - std::cout << "Subscriber running until " << samples << - " samples have been received. Please press CTRL+C to stop the Subscriber at any time." << std::endl; - } - else - { - std::cout << "Subscriber running. Please press CTRL+C to stop the Subscriber." << std::endl; - } - signal(SIGINT, [](int signum) - { - std::cout << "SIGINT received, stopping Subscriber execution." << std::endl; - static_cast(signum); HelloWorldSubscriber::stop(); - }); - std::unique_lock lck(terminate_cv_mtx_); - terminate_cv_.wait(lck, [] - { - return is_stopped(); - }); -} diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationSubscriber.h b/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationSubscriber.h deleted file mode 100644 index b3c550aa33a..00000000000 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationSubscriber.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2022 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 AdvancedConfigurationSubscriber.h - * - */ - -#ifndef _EPROSIMA_FASTDDS_EXAMPLES_CPP_DDS_ADVANCEDCONFIGURATIONEXAMPLE_ADVANCEDCONFIGURATIONSUBSCRIBER_H_ -#define _EPROSIMA_FASTDDS_EXAMPLES_CPP_DDS_ADVANCEDCONFIGURATIONEXAMPLE_ADVANCEDCONFIGURATIONSUBSCRIBER_H_ - -#include -#include -#include - -#include -#include -#include - -#include "AdvancedConfigurationPubSubTypes.h" -#include "types.hpp" - -/** - * Class used to group into a single working unit a Subscriber with a DataReader, its listener, and a TypeSupport member - * corresponding to the HelloWorld datatype - */ -class HelloWorldSubscriber -{ -public: - - HelloWorldSubscriber(); - - virtual ~HelloWorldSubscriber(); - - //! Initialize the subscriber - bool init( - const std::string& topic_name, - uint32_t max_messages, - uint32_t domain, - TransportType transport, - bool reliable, - bool transient, - int hops, - const std::string& partitions, - bool use_ownership, - const std::string& profile); - - //! RUN the subscriber until number samples are received - void run( - uint32_t number); - - //! Return the current state of execution - static bool is_stopped(); - - //! Trigger the end of execution - static void stop(); - -private: - - eprosima::fastdds::dds::DomainParticipant* participant_; - - eprosima::fastdds::dds::Subscriber* subscriber_; - - eprosima::fastdds::dds::Topic* topic_; - - eprosima::fastdds::dds::DataReader* reader_; - - eprosima::fastdds::dds::TypeSupport type_; - - /** - * Class handling discovery and dataflow events - */ - class SubListener : public eprosima::fastdds::dds::DataReaderListener - { - public: - - SubListener() - : matched_(0) - , samples_(0) - , max_messages_(0) - { - } - - ~SubListener() override - { - } - - //! Set the maximum number of messages to receive before exiting - void set_max_messages( - uint32_t max_messages); - - //! Callback executed when a new sample is received - void on_data_available( - eprosima::fastdds::dds::DataReader* reader) override; - - //! Callback executed when a DataWriter is matched or unmatched - void on_subscription_matched( - eprosima::fastdds::dds::DataReader* reader, - const eprosima::fastdds::dds::SubscriptionMatchedStatus& info) override; - - private: - - AdvancedConfiguration hello_; - - //! Number of DataWriters matched to the associated DataReader - int matched_; - - //! Number of samples received - uint32_t samples_; - - //! Number of messages to be received before triggering termination of execution - uint32_t max_messages_; - } - listener_; - - //! Member used for control flow purposes - static std::atomic stop_; - - //! Protects terminate condition variable - static std::mutex terminate_cv_mtx_; - - //! Waits during execution until SIGINT or max_messages_ samples are received - static std::condition_variable terminate_cv_; -}; - -#endif /* _EPROSIMA_FASTDDS_EXAMPLES_CPP_DDS_ADVANCEDCONFIGURATIONEXAMPLE_ADVANCEDCONFIGURATIONSUBSCRIBER_H_ */ diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfiguration_main.cpp b/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfiguration_main.cpp deleted file mode 100644 index dc54bf7893c..00000000000 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfiguration_main.cpp +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2022 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 AdvancedConfiguration_main.cpp - * - */ - -#include - -#include "arg_configuration.h" -#include "AdvancedConfigurationPublisher.h" -#include "AdvancedConfigurationSubscriber.h" -#include "types.hpp" - -enum EntityType -{ - PUBLISHER, - SUBSCRIBER -}; - -int main( - int argc, - char** argv) -{ - int columns; - -#if defined(_WIN32) - char* buf = nullptr; - size_t sz = 0; - if (_dupenv_s(&buf, &sz, "COLUMNS") == 0 && buf != nullptr) - { - columns = strtol(buf, nullptr, 10); - free(buf); - } - else - { - columns = 80; - } -#else - columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 80; -#endif // if defined(_WIN32) - - EntityType type = PUBLISHER; - std::string topic_name = "AdvancedConfigurationTopic"; - int count = 0; - long sleep = 100; - int num_wait_matched = 0; - int domain = 0; - bool async = false; - TransportType transport = DEFAULT; - int hops = -1; - bool reliable = false; - bool transient = false; // transient local - std::string partitions = ""; - bool use_ownership = false; - unsigned int ownership_strength = 0; - int data_size = 10; - std::string participant_profile = ""; - // - argc -= (argc > 0); - argv += (argc > 0); // skip program name argv[0] if present - option::Stats stats(true, usage, argc, argv); - std::vector options(stats.options_max); - std::vector buffer(stats.buffer_max); - option::Parser parse(true, usage, argc, argv, &options[0], &buffer[0]); - - if (parse.error()) - { - option::printUsage(fwrite, stdout, usage, columns); - return 1; - } - - if (options[optionIndex::HELP]) - { - option::printUsage(fwrite, stdout, usage, columns); - return 0; - } - - // Decide between publisher or subscriber - try - { - if (parse.nonOptionsCount() != 1) - { - throw 1; - } - - const char* type_name = parse.nonOption(0); - - // make sure is the first option - if (parse.optionsCount() && type_name >= buffer[0].name) - { - throw 1; - } - - if (strcmp(type_name, "publisher") == 0) - { - type = PUBLISHER; - } - else if (strcmp(type_name, "subscriber") == 0) - { - type = SUBSCRIBER; - } - else - { - throw 1; - } - } - catch (int error) - { - std::cerr << "ERROR: first argument must be followed by - or -- options" << std::endl; - option::printUsage(fwrite, stdout, usage, columns); - return error; - } - - for (int i = 0; i < parse.optionsCount(); ++i) - { - option::Option& opt = buffer[i]; - switch (opt.index()) - { - case optionIndex::HELP: - // not possible, because handled further above and exits the program - break; - - case optionIndex::TOPIC: - topic_name = std::string(opt.arg); - break; - - case optionIndex::DOMAIN_ID: - domain = strtol(opt.arg, nullptr, 10); - break; - - case optionIndex::SAMPLES: - count = strtol(opt.arg, nullptr, 10); - break; - - case optionIndex::INTERVAL: - if (type == PUBLISHER) - { - sleep = strtol(opt.arg, nullptr, 10); - } - else - { - print_warning("publisher", opt.name); - } - break; - - case optionIndex::WAIT: - if (type == PUBLISHER) - { - num_wait_matched = strtol(opt.arg, nullptr, 10); - } - else - { - print_warning("publisher", opt.name); - } - break; - - case optionIndex::ASYNC: - if (type == PUBLISHER) - { - async = true; - } - else - { - print_warning("publisher", opt.name); - } - break; - - case optionIndex::TRANSPORT: - if (strcmp(opt.arg, "shm") == 0) - { - transport = SHM; - } - else if (strcmp(opt.arg, "udp") == 0 || (strcmp(opt.arg, "udpv4") == 0)) - { - transport = UDPv4; - } - else if (strcmp(opt.arg, "udpv6") == 0) - { - transport = UDPv6; - } - break; - - case optionIndex::RELIABLE: - reliable = true; - break; - - case optionIndex::TRANSIENT_LOCAL: - transient = true; - break; - - case optionIndex::TTL: - hops = strtol(opt.arg, nullptr, 10); - break; - - case optionIndex::PARTITIONS: - partitions = std::string(opt.arg); - break; - - case optionIndex::OWNERSHIP: - use_ownership = true; - break; - - case optionIndex::OWNERSHIP_STRENGTH: - if (type == PUBLISHER) - { - use_ownership = true; - ownership_strength = strtol(opt.arg, nullptr, 10); - } - else - { - print_warning("publisher", opt.name); - } - break; - - case optionIndex::DATA_SIZE: - data_size = strtol(opt.arg, nullptr, 10); - break; - - case optionIndex::PROFILE: - participant_profile = std::string(opt.arg); - break; - - case optionIndex::UNKNOWN_OPT: - std::cerr << "ERROR: " << opt.name << " is not a valid argument." << std::endl; - option::printUsage(fwrite, stdout, usage, columns); - return 1; - break; - } - } - if (transient && !reliable) - { - std::cerr << "WARNING: --transient will take no effect since not reliable." << std::endl; - } - - if (transport == SHM && hops > 0 ) - { - std::cerr << "WARNING: --ttl will take no effect since not using UDP transport." << std::endl; - } - - switch (type) - { - case PUBLISHER: - { - HelloWorldPublisher mypub; - - if (mypub.init(topic_name, static_cast(domain), static_cast(num_wait_matched), async, - transport, reliable, transient, hops, partitions, use_ownership, ownership_strength, data_size, - participant_profile)) - { - mypub.run(static_cast(count), static_cast(sleep)); - } - break; - } - case SUBSCRIBER: - { - HelloWorldSubscriber mysub; - if (mysub.init(topic_name, static_cast(count), static_cast(domain), transport, - reliable, transient, hops, partitions, use_ownership, participant_profile)) - { - mysub.run(static_cast(count)); - } - break; - } - } - return 0; -} diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationv1.cxx b/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationv1.cxx deleted file mode 100644 index 2e28c5a0822..00000000000 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationv1.cxx +++ /dev/null @@ -1,361 +0,0 @@ -// 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 AdvancedConfiguration.cpp - * This source file contains the implementation of the described types in the IDL file. - * - * This file was generated by the tool fastddsgen. - */ - -#ifdef _WIN32 -// Remove linker warning LNK4221 on Visual Studio -namespace { -char dummy; -} // namespace -#endif // _WIN32 - -#include "AdvancedConfiguration.h" - -#if FASTCDR_VERSION_MAJOR == 1 - -#include - - -#include -using namespace eprosima::fastcdr::exception; - -#include - -namespace helper { namespace internal { - -enum class Size { - UInt8, - UInt16, - UInt32, - UInt64, -}; - -constexpr Size get_size(int s) { - return (s <= 8 ) ? Size::UInt8: - (s <= 16) ? Size::UInt16: - (s <= 32) ? Size::UInt32: Size::UInt64; -} - -template -struct FindTypeH; - -template<> -struct FindTypeH { - using type = std::uint8_t; -}; - -template<> -struct FindTypeH { - using type = std::uint16_t; -}; - -template<> -struct FindTypeH { - using type = std::uint32_t; -}; - -template<> -struct FindTypeH { - using type = std::uint64_t; -}; -} - -template -struct FindType { - using type = typename internal::FindTypeH::type; -}; -} - -#define AdvancedConfiguration_max_cdr_typesize 132ULL; - - - - - - -AdvancedConfiguration::AdvancedConfiguration() -{ - // unsigned long m_index - m_index = 0; - // char m_message - memset(&m_message, 0, ((20)) * 1); - // sequence m_data - - -} - -AdvancedConfiguration::~AdvancedConfiguration() -{ -} - -AdvancedConfiguration::AdvancedConfiguration( - const AdvancedConfiguration& x) -{ - m_index = x.m_index; - - - m_message = x.m_message; - - - m_data = x.m_data; - -} - -AdvancedConfiguration::AdvancedConfiguration( - AdvancedConfiguration&& x) noexcept -{ - m_index = x.m_index; - - - m_message = std::move(x.m_message); - - - m_data = std::move(x.m_data); - -} - -AdvancedConfiguration& AdvancedConfiguration::operator =( - const AdvancedConfiguration& x) -{ - m_index = x.m_index; - - - m_message = x.m_message; - - - m_data = x.m_data; - - return *this; -} - -AdvancedConfiguration& AdvancedConfiguration::operator =( - AdvancedConfiguration&& x) noexcept -{ - m_index = x.m_index; - - - m_message = std::move(x.m_message); - - - m_data = std::move(x.m_data); - - return *this; -} - -bool AdvancedConfiguration::operator ==( - const AdvancedConfiguration& x) const -{ - return (m_index == x.m_index && - m_message == x.m_message && - m_data == x.m_data); -} - -bool AdvancedConfiguration::operator !=( - const AdvancedConfiguration& x) const -{ - return !(*this == x); -} - -size_t AdvancedConfiguration::getMaxCdrSerializedSize( - size_t current_alignment) -{ - static_cast(current_alignment); - return AdvancedConfiguration_max_cdr_typesize; -} - -size_t AdvancedConfiguration::getCdrSerializedSize( - const AdvancedConfiguration& data, - size_t current_alignment) -{ - (void)data; - size_t initial_alignment = current_alignment; - - current_alignment += 4 + eprosima::fastcdr::Cdr::alignment(current_alignment, 4); - - - current_alignment += (((20)) * 1) + eprosima::fastcdr::Cdr::alignment(current_alignment, 1); - - - - current_alignment += 4 + eprosima::fastcdr::Cdr::alignment(current_alignment, 4); - - if (data.data().size() > 0) - { - current_alignment += (data.data().size() * 1) + eprosima::fastcdr::Cdr::alignment(current_alignment, 1); - } - - - - - return current_alignment - initial_alignment; -} - - -void AdvancedConfiguration::serialize( - eprosima::fastcdr::Cdr& scdr) const -{ - scdr << m_index; - - scdr << m_message; - - - scdr << m_data; - - -} - -void AdvancedConfiguration::deserialize( - eprosima::fastcdr::Cdr& dcdr) -{ - dcdr >> m_index; - - - - dcdr >> m_message; - - - - dcdr >> m_data; - - -} - - -bool AdvancedConfiguration::isKeyDefined() -{ - return false; -} - -void AdvancedConfiguration::serializeKey( - eprosima::fastcdr::Cdr& scdr) const -{ - (void) scdr; -} - -/*! - * @brief This function sets a value in member index - * @param _index New value for member index - */ -void AdvancedConfiguration::index( - uint32_t _index) -{ - m_index = _index; -} - -/*! - * @brief This function returns the value of member index - * @return Value of member index - */ -uint32_t AdvancedConfiguration::index() const -{ - return m_index; -} - -/*! - * @brief This function returns a reference to member index - * @return Reference to member index - */ -uint32_t& AdvancedConfiguration::index() -{ - return m_index; -} - - -/*! - * @brief This function copies the value in member message - * @param _message New value to be copied in member message - */ -void AdvancedConfiguration::message( - const std::array& _message) -{ - m_message = _message; -} - -/*! - * @brief This function moves the value in member message - * @param _message New value to be moved in member message - */ -void AdvancedConfiguration::message( - std::array&& _message) -{ - m_message = std::move(_message); -} - -/*! - * @brief This function returns a constant reference to member message - * @return Constant reference to member message - */ -const std::array& AdvancedConfiguration::message() const -{ - return m_message; -} - -/*! - * @brief This function returns a reference to member message - * @return Reference to member message - */ -std::array& AdvancedConfiguration::message() -{ - return m_message; -} - - -/*! - * @brief This function copies the value in member data - * @param _data New value to be copied in member data - */ -void AdvancedConfiguration::data( - const std::vector& _data) -{ - m_data = _data; -} - -/*! - * @brief This function moves the value in member data - * @param _data New value to be moved in member data - */ -void AdvancedConfiguration::data( - std::vector&& _data) -{ - m_data = std::move(_data); -} - -/*! - * @brief This function returns a constant reference to member data - * @return Constant reference to member data - */ -const std::vector& AdvancedConfiguration::data() const -{ - return m_data; -} - -/*! - * @brief This function returns a reference to member data - * @return Reference to member data - */ -std::vector& AdvancedConfiguration::data() -{ - return m_data; -} - - - - -#endif // FASTCDR_VERSION_MAJOR == 1 diff --git a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationv1.h b/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationv1.h deleted file mode 100644 index da5d202a47d..00000000000 --- a/examples/cpp/dds/AdvancedConfigurationExample/AdvancedConfigurationv1.h +++ /dev/null @@ -1,271 +0,0 @@ -// 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 AdvancedConfiguration.h - * This header file contains the declaration of the described types in the IDL file. - * - * This file was generated by the tool fastddsgen. - */ - -#include - -#if FASTCDR_VERSION_MAJOR == 1 - -#ifndef _FAST_DDS_GENERATED_ADVANCEDCONFIGURATION_H_ -#define _FAST_DDS_GENERATED_ADVANCEDCONFIGURATION_H_ - -#include -#include -#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(ADVANCEDCONFIGURATION_SOURCE) -#define ADVANCEDCONFIGURATION_DllAPI __declspec( dllexport ) -#else -#define ADVANCEDCONFIGURATION_DllAPI __declspec( dllimport ) -#endif // ADVANCEDCONFIGURATION_SOURCE -#else -#define ADVANCEDCONFIGURATION_DllAPI -#endif // EPROSIMA_USER_DLL_EXPORT -#else -#define ADVANCEDCONFIGURATION_DllAPI -#endif // _WIN32 - -namespace eprosima { -namespace fastcdr { -class Cdr; -} // namespace fastcdr -} // namespace eprosima - - - - - - - -/*! - * @brief This class represents the structure AdvancedConfiguration defined by the user in the IDL file. - * @ingroup AdvancedConfiguration - */ -class AdvancedConfiguration -{ -public: - - /*! - * @brief Default constructor. - */ - eProsima_user_DllExport AdvancedConfiguration(); - - /*! - * @brief Default destructor. - */ - eProsima_user_DllExport ~AdvancedConfiguration(); - - /*! - * @brief Copy constructor. - * @param x Reference to the object AdvancedConfiguration that will be copied. - */ - eProsima_user_DllExport AdvancedConfiguration( - const AdvancedConfiguration& x); - - /*! - * @brief Move constructor. - * @param x Reference to the object AdvancedConfiguration that will be copied. - */ - eProsima_user_DllExport AdvancedConfiguration( - AdvancedConfiguration&& x) noexcept; - - /*! - * @brief Copy assignment. - * @param x Reference to the object AdvancedConfiguration that will be copied. - */ - eProsima_user_DllExport AdvancedConfiguration& operator =( - const AdvancedConfiguration& x); - - /*! - * @brief Move assignment. - * @param x Reference to the object AdvancedConfiguration that will be copied. - */ - eProsima_user_DllExport AdvancedConfiguration& operator =( - AdvancedConfiguration&& x) noexcept; - - /*! - * @brief Comparison operator. - * @param x AdvancedConfiguration object to compare. - */ - eProsima_user_DllExport bool operator ==( - const AdvancedConfiguration& x) const; - - /*! - * @brief Comparison operator. - * @param x AdvancedConfiguration object to compare. - */ - eProsima_user_DllExport bool operator !=( - const AdvancedConfiguration& x) const; - - /*! - * @brief This function sets a value in member index - * @param _index New value for member index - */ - eProsima_user_DllExport void index( - uint32_t _index); - - /*! - * @brief This function returns the value of member index - * @return Value of member index - */ - eProsima_user_DllExport uint32_t index() const; - - /*! - * @brief This function returns a reference to member index - * @return Reference to member index - */ - eProsima_user_DllExport uint32_t& index(); - - - /*! - * @brief This function copies the value in member message - * @param _message New value to be copied in member message - */ - eProsima_user_DllExport void message( - const std::array& _message); - - /*! - * @brief This function moves the value in member message - * @param _message New value to be moved in member message - */ - eProsima_user_DllExport void message( - std::array&& _message); - - /*! - * @brief This function returns a constant reference to member message - * @return Constant reference to member message - */ - eProsima_user_DllExport const std::array& message() const; - - /*! - * @brief This function returns a reference to member message - * @return Reference to member message - */ - eProsima_user_DllExport std::array& message(); - - - /*! - * @brief This function copies the value in member data - * @param _data New value to be copied in member data - */ - eProsima_user_DllExport void data( - const std::vector& _data); - - /*! - * @brief This function moves the value in member data - * @param _data New value to be moved in member data - */ - eProsima_user_DllExport void data( - std::vector&& _data); - - /*! - * @brief This function returns a constant reference to member data - * @return Constant reference to member data - */ - eProsima_user_DllExport const std::vector& data() const; - - /*! - * @brief This function returns a reference to member data - * @return Reference to member data - */ - eProsima_user_DllExport std::vector& data(); - - - /*! - * @brief This function returns the maximum serialized size of an object - * depending on the buffer alignment. - * @param current_alignment Buffer alignment. - * @return Maximum serialized size. - */ - eProsima_user_DllExport static size_t getMaxCdrSerializedSize( - size_t current_alignment = 0); - - /*! - * @brief This function returns the serialized size of a data depending on the buffer alignment. - * @param data Data which is calculated its serialized size. - * @param current_alignment Buffer alignment. - * @return Serialized size. - */ - eProsima_user_DllExport static size_t getCdrSerializedSize( - const AdvancedConfiguration& data, - size_t current_alignment = 0); - - - - /*! - * @brief This function serializes an object using CDR serialization. - * @param cdr CDR serialization object. - */ - eProsima_user_DllExport void serialize( - eprosima::fastcdr::Cdr& cdr) const; - - /*! - * @brief This function deserializes an object using CDR serialization. - * @param cdr CDR serialization object. - */ - eProsima_user_DllExport void deserialize( - eprosima::fastcdr::Cdr& cdr); - - - - - /*! - * @brief This function tells you if the Key has been defined for this type - */ - eProsima_user_DllExport static bool isKeyDefined(); - - /*! - * @brief This function serializes the key members of an object using CDR serialization. - * @param cdr CDR serialization object. - */ - eProsima_user_DllExport void serializeKey( - eprosima::fastcdr::Cdr& cdr) const; - -private: - - uint32_t m_index; - std::array m_message; - std::vector m_data; - -}; - - -#endif // _FAST_DDS_GENERATED_ADVANCEDCONFIGURATION_H_ - - - -#endif // FASTCDR_VERSION_MAJOR == 1 diff --git a/examples/cpp/dds/AdvancedConfigurationExample/README.md b/examples/cpp/dds/AdvancedConfigurationExample/README.md deleted file mode 100644 index c31397f38f9..00000000000 --- a/examples/cpp/dds/AdvancedConfigurationExample/README.md +++ /dev/null @@ -1,104 +0,0 @@ -# Advanced Configuration Example - -This example extends the configuration options of a trivial HelloWorld by letting the user specify properties of -entities such as durability, reliability or specify the transport protocol to be used, among other possibilities. This -could be useful, for example, to quickly test whether two endpoints are compatible and hence would match. -Additionally, the message type includes a data sequence which size can be set by the user, allowing to send large data between endpoints. -Note: Due to the nature of the data type (not bounded), this example will not use data sharing. - -## Execution instructions - -To launch this test open two different consoles: - -In the first one launch: ./AdvancedConfigurationExample publisher (or AdvancedConfigurationExample.exe publisher on windows). -In the second one: ./AdvancedConfigurationExample subscriber (or AdvancedConfigurationExample.exe subscriber on windows). - -## Arguments - -First argument is `publisher` or `subscriber` and then the rest of arguments are read unordered - -```sh -Usage: AdvancedConfigurationExample - -General options: - -h --help - Produce help message. - -Publisher options: - -t --topic= - Topic name (Default: AdvancedConfigurationTopic). - -d --domain= - DDS domain ID (Default: 0). - -w --wait= - Number of matched subscribers required to publish (Default: - 0 => does not wait). - -m --msg-size= - Size in bytes of the data to send (Default 10). - -s --samples= - Number of samples to send (Default: 0 => infinite samples). - -i --interval= - Time between samples in milliseconds (Default: 100). - -a --async - Asynchronous publish mode (synchronous by default). - --transport= - Use only shared-memory, UDPv4, or UDPv6 transport.If not - set, use Fast DDS default transports (depending on the - scenario it will use the most efficient one: data-sharing - delivery mechanism > shared-memory > UDP). - -o --ownership - Use Topic with EXCLUSIVE_OWNERSHIP (SHARED_OWNERSHIP by - default). - --strength= - Set this Publisher strength. Set Topic with - EXCLUSIVE_OWNERSHIP. Default: 0 - -Subscriber options: - -t --topic= - Topic name (Default: AdvancedConfigurationTopic). - -d --domain= - DDS domain ID (Default: 0). - -s --samples= - Number of samples to wait for (Default: 0 => infinite - samples). - --transport= - Use only shared-memory, UDPv4, or UDPv6 transport.If not - set, use Fast DDS default transports (depending on the - scenario it will use the most efficient one: data-sharing - delivery mechanism > shared-memory > UDP). - -o --ownership - Use Topic with EXCLUSIVE_OWNERSHIP (SHARED_OWNERSHIP by - default). - -QoS options: - -r --reliable - Set reliability to reliable (best-effort by default). - --transient - Set durability to transient local (volatile by default, - ineffective when not reliable). - -p --partitions= - Partitions to match separated by ';'. Single or double - quotes required with multiple partitions. With empty string - ('') no partitions used. (Default: ''). - -x --xml-profile - Profile name to configure DomainParticipant. - -Discovery options: - --ttl - Set multicast discovery Time To Live on IPv4 or Hop Limit - for IPv6. If not set, uses Fast DDS default (1 hop). - Increase it to avoid discovery issues on scenarios with - several routers. Maximum: 255. -``` - -### XML Configuration - -Using argument `--xml-profile ` will configure the internal DomainParticipant using the profile name loaded from an XML file. -To load XML files check [Fast DDS documentation](https://fast-dds.docs.eprosima.com/en/latest/fastdds/xml_configuration/xml_configuration.html). -Loading example XML configuration [file](shm_off.xml) and calling this example with `--xml-profile no_shm_participant_profile` will disable Shared Memory Transport for the internal DomainParticipant created. - -This code presents how to run a publisher with this example without Shared Memory: - -```sh -# From AdvancedConfigurationExample installation dir -FASTDDS_DEFAULT_PROFILES_FILE=shm_off.xml ./AdvancedConfigurationExample publisher --xml-profile no_shm_participant_profile -``` diff --git a/examples/cpp/dds/AdvancedConfigurationExample/arg_configuration.h b/examples/cpp/dds/AdvancedConfigurationExample/arg_configuration.h deleted file mode 100644 index 997360b7e9c..00000000000 --- a/examples/cpp/dds/AdvancedConfigurationExample/arg_configuration.h +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2022 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 arg_configuration.h - * - */ - -#ifndef _EPROSIMA_FASTDDS_EXAMPLES_CPP_DDS_ADVANCEDCONFIGURATIONEXAMPLE_ARG_CONFIGURATION_H_ -#define _EPROSIMA_FASTDDS_EXAMPLES_CPP_DDS_ADVANCEDCONFIGURATIONEXAMPLE_ARG_CONFIGURATION_H_ - -#include -#include -#include -#include - -#include - -namespace option = eprosima::option; - -struct Arg : public option::Arg -{ - static void print_error( - const char* msg1, - const option::Option& opt, - const char* msg2) - { - fprintf(stderr, "%s", msg1); - fwrite(opt.name, opt.namelen, 1, stderr); - fprintf(stderr, "%s", msg2); - } - - static option::ArgStatus Unknown( - const option::Option& option, - bool msg) - { - if (msg) - { - print_error("Unknown option '", option, "'\n"); - } - return option::ARG_ILLEGAL; - } - - static option::ArgStatus Required( - const option::Option& option, - bool msg) - { - if (option.arg != 0 && option.arg[0] != 0) - { - return option::ARG_OK; - } - - if (msg) - { - print_error("Option '", option, "' requires an argument\n"); - } - return option::ARG_ILLEGAL; - } - - static option::ArgStatus Numeric( - const option::Option& option, - bool msg) - { - char* endptr = 0; - if ( option.arg != nullptr ) - { - strtol(option.arg, &endptr, 10); - if (endptr != option.arg && *endptr == 0) - { - return option::ARG_OK; - } - } - - if (msg) - { - print_error("Option '", option, "' requires a numeric argument\n"); - } - return option::ARG_ILLEGAL; - } - - template::max()> - static option::ArgStatus NumericRange( - const option::Option& option, - bool msg) - { - static_assert(min <= max, "NumericRange: invalid range provided."); - - char* endptr = 0; - if ( option.arg != nullptr ) - { - long value = strtol(option.arg, &endptr, 10); - if ( endptr != option.arg && *endptr == 0 && - value >= min && value <= max) - { - return option::ARG_OK; - } - } - - if (msg) - { - std::ostringstream os; - os << "' requires a numeric argument in range [" - << min << ", " << max << "]" << std::endl; - print_error("Option '", option, os.str().c_str()); - } - - return option::ARG_ILLEGAL; - } - - static option::ArgStatus String( - const option::Option& option, - bool msg) - { - if (option.arg != 0) - { - return option::ARG_OK; - } - if (msg) - { - print_error("Option '", option, "' requires a string argument\n"); - } - return option::ARG_ILLEGAL; - } - - static option::ArgStatus Transport( - const option::Option& option, - bool msg) - { - if (option.arg != 0) - { - std::string transport = std::string(option.arg); - if (transport != "shm" && transport != "udp" && transport != "udpv4" && transport != "udpv6") - { - if (msg) - { - print_error("Option '", option, "' only accepts values\n"); - } - return option::ARG_ILLEGAL; - } - return option::ARG_OK; - } - if (msg) - { - print_error("Option '", option, "' requires a string argument\n"); - } - return option::ARG_ILLEGAL; - } - -}; - -enum optionIndex -{ - UNKNOWN_OPT, - HELP, - TOPIC, - WAIT, - SAMPLES, - INTERVAL, - ASYNC, - DOMAIN_ID, - TRANSPORT, - RELIABLE, - TRANSIENT_LOCAL, - TTL, - PARTITIONS, - OWNERSHIP_STRENGTH, - OWNERSHIP, - DATA_SIZE, - PROFILE, -}; - -const option::Descriptor usage[] = { - { UNKNOWN_OPT, 0, "", "", Arg::None, - "Usage: AdvancedConfigurationExample \n\nGeneral options:" }, - { HELP, 0, "h", "help", Arg::None, " -h \t--help \tProduce help message." }, - - { UNKNOWN_OPT, 0, "", "", Arg::None, "\nPublisher options:"}, - { TOPIC, 0, "t", "topic", Arg::String, - " -t \t--topic= \tTopic name (Default: AdvancedConfigurationTopic)." }, - { DOMAIN_ID, 0, "d", "domain", Arg::NumericRange<0, 230>, - " -d \t--domain= \tDDS domain ID (Default: 0)." }, - { WAIT, 0, "w", "wait", Arg::NumericRange<>, - " -w \t--wait= \tNumber of matched subscribers required to publish" - " (Default: 0 => does not wait)." }, - { DATA_SIZE, 0, "m", "msg-size", Arg::String, - " -m \t--msg-size=\tSize in bytes of the data to send (Default 10)."}, - { SAMPLES, 0, "s", "samples", Arg::NumericRange<>, - " -s \t--samples= \tNumber of samples to send (Default: 0 => infinite samples)." }, - { INTERVAL, 0, "i", "interval", Arg::NumericRange<>, - " -i \t--interval= \tTime between samples in milliseconds (Default: 100)." }, - { ASYNC, 0, "a", "async", Arg::None, - " -a \t--async \tAsynchronous publish mode (synchronous by default)." }, - { TRANSPORT, 0, "", "transport", Arg::Transport, - " \t--transport= \tUse only shared-memory, UDPv4, or UDPv6 transport." - "If not set, use Fast DDS default transports (depending on the scenario it will use the most efficient one:" - " data-sharing delivery mechanism > shared-memory > UDP)." }, - { OWNERSHIP, 0, "o", "ownership", Arg::None, - " -o \t--ownership \tUse Topic with EXCLUSIVE_OWNERSHIP (SHARED_OWNERSHIP by default)."}, - { OWNERSHIP_STRENGTH, 0, "", "strength", Arg::NumericRange<>, - " \t--strength= \tSet this Publisher strength. Set Topic with EXCLUSIVE_OWNERSHIP. Default: 0"}, - - { UNKNOWN_OPT, 0, "", "", Arg::None, "\nSubscriber options:"}, - { TOPIC, 0, "t", "topic", Arg::String, - " -t \t--topic= \tTopic name (Default: AdvancedConfigurationTopic)." }, - { DOMAIN_ID, 0, "d", "domain", Arg::NumericRange<0, 230>, - " -d \t--domain= \tDDS domain ID (Default: 0)." }, - { SAMPLES, 0, "s", "samples", Arg::NumericRange<>, - " -s \t--samples= \tNumber of samples to wait for (Default: 0 => infinite samples)." }, - { TRANSPORT, 0, "", "transport", Arg::Transport, - " \t--transport= \tUse only shared-memory, UDPv4, or UDPv6 transport." - "If not set, use Fast DDS default transports (depending on the scenario it will use the most efficient one:" - " data-sharing delivery mechanism > shared-memory > UDP)." }, - { OWNERSHIP, 0, "o", "ownership", Arg::None, - " -o \t--ownership \tUse Topic with EXCLUSIVE_OWNERSHIP (SHARED_OWNERSHIP by default)."}, - - { UNKNOWN_OPT, 0, "", "", Arg::None, "\nQoS options:"}, - { RELIABLE, 0, "r", "reliable", Arg::None, - " -r \t--reliable \tSet reliability to reliable (best-effort by default)." }, - { TRANSIENT_LOCAL, 0, "", "transient", Arg::None, - " \t--transient \tSet durability to transient local (volatile by default, ineffective when not reliable)." }, - { PARTITIONS, 0, "p", "partitions", Arg::String, - " -p \t--partitions= \tPartitions to match separated by ';'." - " Single or double quotes required with multiple partitions." - " With empty string ('') no partitions used. (Default: '')." }, - { PROFILE, 0, "x", "xml-profile", Arg::String, - " -x \t--xml-profile \tProfile name to configure DomainParticipant."}, - - { UNKNOWN_OPT, 0, "", "", Arg::None, "\nDiscovery options:"}, - { TTL, 0, "", "ttl", Arg::NumericRange<1, 255>, - "\t--ttl \tSet multicast discovery Time To Live on IPv4 or Hop Limit for IPv6." - " If not set, uses Fast DDS default (1 hop). Increase it to avoid discovery issues" - " on scenarios with several routers. Maximum: 255."}, - - { 0, 0, 0, 0, 0, 0 } -}; - -void print_warning( - std::string type, - const char* opt) -{ - std::cerr << "WARNING: " << opt << " is a " << type << " option, ignoring argument." << std::endl; -} - -#endif /* _EPROSIMA_FASTDDS_EXAMPLES_CPP_DDS_ADVANCEDCONFIGURATIONEXAMPLE_ARG_CONFIGURATION_H_ */ diff --git a/examples/cpp/dds/AdvancedConfigurationExample/shm_off.xml b/examples/cpp/dds/AdvancedConfigurationExample/shm_off.xml deleted file mode 100644 index 50d23e0c3ca..00000000000 --- a/examples/cpp/dds/AdvancedConfigurationExample/shm_off.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - custom_udpv4_transport - UDPv4 - - - - - false - - custom_udpv4_transport - - - - - diff --git a/examples/cpp/dds/AdvancedConfigurationExample/types.hpp b/examples/cpp/dds/AdvancedConfigurationExample/types.hpp deleted file mode 100644 index b323d8e094c..00000000000 --- a/examples/cpp/dds/AdvancedConfigurationExample/types.hpp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2022 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 AdvancedConfigurationPublisher.h - * - */ - -#ifndef _EPROSIMA_FASTDDS_EXAMPLES_CPP_DDS_ADVANCEDCONFIGURATIONEXAMPLE_TYPES_HPP_ -#define _EPROSIMA_FASTDDS_EXAMPLES_CPP_DDS_ADVANCEDCONFIGURATIONEXAMPLE_TYPES_HPP_ - -enum TransportType -{ - DEFAULT, - SHM, - UDPv4, - UDPv6, -}; - -#endif /* _EPROSIMA_FASTDDS_EXAMPLES_CPP_DDS_ADVANCEDCONFIGURATIONEXAMPLE_TYPES_HPP_ */ diff --git a/examples/cpp/dds/CMakeLists.txt b/examples/cpp/dds/CMakeLists.txt index 421eb164dcb..7e5b3da1897 100644 --- a/examples/cpp/dds/CMakeLists.txt +++ b/examples/cpp/dds/CMakeLists.txt @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -add_subdirectory(AdvancedConfigurationExample) add_subdirectory(BasicConfigurationExample) add_subdirectory(Configurability) add_subdirectory(ContentFilteredTopicExample) diff --git a/test/examples/basic_configuration.compose.yml b/test/examples/basic_configuration.compose.yml deleted file mode 100644 index b6ca5c1d4c8..00000000000 --- a/test/examples/basic_configuration.compose.yml +++ /dev/null @@ -1,25 +0,0 @@ -# FASTDDS_TODO_BEFORE(3, 0, "This compose file should be used for the future configuration example"); -version: "3" - -services: - publisher: - image: @DOCKER_IMAGE_NAME@ - volumes: - - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ - - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ - environment: - # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows - LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@ - EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/dds/BasicConfigurationExample - command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/BasicConfigurationExample@FILE_EXTENSION@ publisher --wait 2 --samples 10 --interval 10 --reliable --transient & $${EXAMPLE_DIR}/BasicConfigurationExample@FILE_EXTENSION@ subscriber --samples 10 --reliable --transient" - - subscriber: - image: @DOCKER_IMAGE_NAME@ - volumes: - - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ - - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ - environment: - # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows - LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@ - EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/dds/BasicConfigurationExample@FILE_EXTENSION@ - command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/BasicConfigurationExample@FILE_EXTENSION@ subscriber --samples 10 --reliable --transient" diff --git a/test/examples/configuration.compose.yml b/test/examples/configuration.compose.yml new file mode 100644 index 00000000000..c39d042cbcc --- /dev/null +++ b/test/examples/configuration.compose.yml @@ -0,0 +1,30 @@ +# FASTDDS_TODO_BEFORE(3, 0, "This compose file should be used for the future configuration example"); +version: "3" + +services: + subscriber: + image: @DOCKER_IMAGE_NAME@ + volumes: + - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ + - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + environment: + # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@ + EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/configuration + FASTDDS_DEFAULT_PROFILES_FILE: @PROJECT_BINARY_DIR@/examples/cpp/configuration/configuration_profile.xml + SUBSCRIBER_ADDITIONAL_ARGUMENTS: ${SUB_ARGS} + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/configuration@FILE_EXTENSION@ subscriber $${SUBSCRIBER_ADDITIONAL_ARGUMENTS}" + + publisher-subscriber: + image: @DOCKER_IMAGE_NAME@ + volumes: + - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ + - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + environment: + # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@ + EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/configuration + FASTDDS_DEFAULT_PROFILES_FILE: @PROJECT_BINARY_DIR@/examples/cpp/configuration/configuration_profile.xml + PUBLISHER_ADDITIONAL_ARGUMENTS: ${PUB_ARGS} + SUBSCRIBER_ADDITIONAL_ARGUMENTS: ${SUB_ARGS} + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/configuration@FILE_EXTENSION@ subscriber $${SUBSCRIBER_ADDITIONAL_ARGUMENTS} & $${EXAMPLE_DIR}/configuration@FILE_EXTENSION@ publisher $${PUBLISHER_ADDITIONAL_ARGUMENTS}" diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index d7d500f88ef..f4bf8e2a0c4 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -1,14 +1,35 @@ -""".""" + import subprocess +import pytest +config_test_cases = [ + ('', ''), # Default configuration + ('--profile-participant configuration_participant_profile', '--profile-participant configuration_participant_profile'), + ('--profile-writer configuration_writer_profile', '--profile-reader configuration_reader_profile' ), + ('--profile-writer best_effort_writer_profile', '--profile-reader best_effort_reader_profile'), + ('--transport DEFAULT', '--transport DEFAULT'), + ('--transport DEFAULT', '--transport UDPv4'), + ('--transport UDPv4', '--transport UDPv4'), + ('--transport LARGE_DATA', '--transport LARGE_DATA'), + # TODO test deadline QoS + # TODO test lifespan QoS + # TODO test liveliness QoS + # TODO test ownership QoS + # TODO test disable positive acks QoS + # TODO test partitions QoS +] -def test_basic_configuration(): +@pytest.mark.parametrize("pub_args, sub_args", config_test_cases) +def test_configuration(pub_args, sub_args): """.""" ret = False out = '' + pub_requirements = '--reliable --transient-local --keep-last 10 --samples 10 --wait 2' + sub_requirements = '--reliable --transient-local --keep-last 10 --samples 10' + + command_prerequisites = 'PUB_ARGS="' + pub_requirements + ' ' + pub_args + '" SUB_ARGS="' + sub_requirements + ' ' + sub_args + '" ' try: - out = subprocess.check_output( - '@DOCKER_EXECUTABLE@ compose -f basic_configuration.compose.yml up', + out = subprocess.check_output(command_prerequisites + '@DOCKER_EXECUTABLE@ compose -f configuration.compose.yml up', stderr=subprocess.STDOUT, shell=True, timeout=30 @@ -28,6 +49,7 @@ def test_basic_configuration(): if sent * 2 == received: ret = True else: + print ('ERROR: sent: ' + str(sent) + ', but received: ' + str(received) + '(expected: ' + str(sent * 2) + ')') raise subprocess.CalledProcessError(1, '') except subprocess.CalledProcessError: @@ -35,5 +57,6 @@ def test_basic_configuration(): print(l) except subprocess.TimeoutExpired: print('TIMEOUT') + print(out) assert(ret)