From 8dc98fd209f44717faf20e2387356717d5b67d3d Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 6 Mar 2024 15:51:03 +0100 Subject: [PATCH 01/42] Refs #20543: Refactor HelloWorld example Signed-off-by: JesusPoderoso --- examples/CMakeLists.txt | 1 + examples/cpp/dds/CMakeLists.txt | 1 - .../HelloWorldExample/HelloWorldPublisher.cpp | 224 ------------- .../HelloWorldExample/HelloWorldPublisher.h | 97 ------ .../HelloWorldExample/HelloWorldSubscriber.h | 91 ----- .../dds/HelloWorldExample/HelloWorld_main.cpp | 316 ------------------ examples/cpp/dds/HelloWorldExample/README.txt | 36 -- .../CMakeLists.txt | 18 +- .../hello_world/DEFAULT_FASTDDS_PROFILES.xml | 0 .../HelloWorld.hpp | 0 .../HelloWorld.idl | 1 + .../HelloWorldCdrAux.hpp | 0 .../HelloWorldCdrAux.ipp | 0 .../HelloWorldPubSubTypes.cxx | 0 .../HelloWorldPubSubTypes.h | 0 .../cpp/hello_world/HelloWorldPublisher.cpp | 151 +++++++++ .../cpp/hello_world/HelloWorldPublisher.h | 71 ++++ .../HelloWorldSubscriber.cpp | 105 ++---- .../cpp/hello_world/HelloWorldSubscriber.h | 66 ++++ .../HelloWorldSubscriberWaitset.cpp | 172 ++++++++++ .../hello_world/HelloWorldSubscriberWaitset.h | 67 ++++ .../HelloWorldTypeObjectSupport.cxx | 9 +- .../HelloWorldTypeObjectSupport.hpp | 0 examples/cpp/hello_world/HelloWorld_main.cpp | 91 +++++ examples/cpp/hello_world/README.md | 176 ++++++++++ examples/cpp/hello_world/cli_options.hpp | 75 +++++ 26 files changed, 917 insertions(+), 851 deletions(-) delete mode 100644 examples/cpp/dds/HelloWorldExample/HelloWorldPublisher.cpp delete mode 100644 examples/cpp/dds/HelloWorldExample/HelloWorldPublisher.h delete mode 100644 examples/cpp/dds/HelloWorldExample/HelloWorldSubscriber.h delete mode 100644 examples/cpp/dds/HelloWorldExample/HelloWorld_main.cpp delete mode 100644 examples/cpp/dds/HelloWorldExample/README.txt rename examples/cpp/{dds/HelloWorldExample => hello_world}/CMakeLists.txt (67%) create mode 100644 examples/cpp/hello_world/DEFAULT_FASTDDS_PROFILES.xml rename examples/cpp/{dds/HelloWorldExample => hello_world}/HelloWorld.hpp (100%) rename examples/cpp/{dds/HelloWorldExample => hello_world}/HelloWorld.idl (69%) rename examples/cpp/{dds/HelloWorldExample => hello_world}/HelloWorldCdrAux.hpp (100%) rename examples/cpp/{dds/HelloWorldExample => hello_world}/HelloWorldCdrAux.ipp (100%) rename examples/cpp/{dds/HelloWorldExample => hello_world}/HelloWorldPubSubTypes.cxx (100%) rename examples/cpp/{dds/HelloWorldExample => hello_world}/HelloWorldPubSubTypes.h (100%) create mode 100644 examples/cpp/hello_world/HelloWorldPublisher.cpp create mode 100644 examples/cpp/hello_world/HelloWorldPublisher.h rename examples/cpp/{dds/HelloWorldExample => hello_world}/HelloWorldSubscriber.cpp (58%) create mode 100644 examples/cpp/hello_world/HelloWorldSubscriber.h create mode 100644 examples/cpp/hello_world/HelloWorldSubscriberWaitset.cpp create mode 100644 examples/cpp/hello_world/HelloWorldSubscriberWaitset.h rename examples/cpp/{dds/HelloWorldExample => hello_world}/HelloWorldTypeObjectSupport.cxx (98%) rename examples/cpp/{dds/HelloWorldExample => hello_world}/HelloWorldTypeObjectSupport.hpp (100%) create mode 100644 examples/cpp/hello_world/HelloWorld_main.cpp create mode 100644 examples/cpp/hello_world/README.md create mode 100644 examples/cpp/hello_world/cli_options.hpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index d63b96f986c..d41f21bdcab 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/hello_world) diff --git a/examples/cpp/dds/CMakeLists.txt b/examples/cpp/dds/CMakeLists.txt index 0ade7a00048..ac08a223219 100644 --- a/examples/cpp/dds/CMakeLists.txt +++ b/examples/cpp/dds/CMakeLists.txt @@ -24,7 +24,6 @@ add_subdirectory(DiscoveryServerExample) add_subdirectory(DynamicHelloWorldExample) add_subdirectory(Filtering) add_subdirectory(FlowControlExample) -add_subdirectory(HelloWorldExample) add_subdirectory(HelloWorldExampleDataSharing) add_subdirectory(HelloWorldExampleSharedMem) add_subdirectory(HelloWorldExampleTCP) diff --git a/examples/cpp/dds/HelloWorldExample/HelloWorldPublisher.cpp b/examples/cpp/dds/HelloWorldExample/HelloWorldPublisher.cpp deleted file mode 100644 index 1a2bdfce472..00000000000 --- a/examples/cpp/dds/HelloWorldExample/HelloWorldPublisher.cpp +++ /dev/null @@ -1,224 +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 HelloWorldPublisher.cpp - * - */ - -#include "HelloWorldPublisher.h" - -#include - -#include -#include -#include -#include -#include - -using namespace eprosima::fastdds::dds; - -HelloWorldPublisher::HelloWorldPublisher() - : participant_(nullptr) - , publisher_(nullptr) - , topic_(nullptr) - , writer_(nullptr) - , type_(new HelloWorldPubSubType()) -{ -} - -bool HelloWorldPublisher::init( - bool use_env) -{ - hello_.index(0); - hello_.message("HelloWorld"); - DomainParticipantQos pqos = PARTICIPANT_QOS_DEFAULT; - pqos.name("Participant_pub"); - auto factory = DomainParticipantFactory::get_instance(); - - if (use_env) - { - factory->load_profiles(); - factory->get_default_participant_qos(pqos); - } - - participant_ = factory->create_participant(0, pqos); - - if (participant_ == nullptr) - { - return false; - } - - //REGISTER THE TYPE - type_.register_type(participant_); - - //CREATE THE PUBLISHER - PublisherQos pubqos = PUBLISHER_QOS_DEFAULT; - - if (use_env) - { - participant_->get_default_publisher_qos(pubqos); - } - - publisher_ = participant_->create_publisher( - pubqos, - nullptr); - - if (publisher_ == nullptr) - { - return false; - } - - //CREATE THE TOPIC - TopicQos tqos = TOPIC_QOS_DEFAULT; - - if (use_env) - { - participant_->get_default_topic_qos(tqos); - } - - topic_ = participant_->create_topic( - "HelloWorldTopic", - "HelloWorld", - tqos); - - if (topic_ == nullptr) - { - return false; - } - - // CREATE THE WRITER - DataWriterQos wqos = DATAWRITER_QOS_DEFAULT; - - if (use_env) - { - publisher_->get_default_datawriter_qos(wqos); - } - - writer_ = publisher_->create_datawriter( - topic_, - wqos, - &listener_); - - if (writer_ == nullptr) - { - return false; - } - - return true; -} - -HelloWorldPublisher::~HelloWorldPublisher() -{ - if (writer_ != nullptr) - { - publisher_->delete_datawriter(writer_); - } - if (publisher_ != nullptr) - { - 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.total_count; - firstConnected_ = true; - std::cout << "Publisher matched." << std::endl; - } - else if (info.current_count_change == -1) - { - matched_ = info.total_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 HelloWorldPublisher::runThread( - uint32_t samples, - uint32_t sleep) -{ - if (samples == 0) - { - while (!stop_) - { - if (publish(false)) - { - std::cout << "Message: " << hello_.message() << " with index: " << hello_.index() - << " SENT" << std::endl; - } - std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); - } - } - else - { - for (uint32_t i = 0; i < samples; ++i) - { - if (!publish()) - { - --i; - } - else - { - std::cout << "Message: " << hello_.message() << " with index: " << hello_.index() - << " SENT" << std::endl; - } - std::this_thread::sleep_for(std::chrono::milliseconds(sleep)); - } - } -} - -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 enter to stop the Publisher at any time." << std::endl; - std::cin.ignore(); - stop_ = true; - } - else - { - std::cout << "Publisher running " << samples << " samples." << std::endl; - } - thread.join(); -} - -bool HelloWorldPublisher::publish( - bool waitForListener) -{ - if (listener_.firstConnected_ || !waitForListener || listener_.matched_ > 0) - { - hello_.index(hello_.index() + 1); - writer_->write(&hello_); - return true; - } - return false; -} diff --git a/examples/cpp/dds/HelloWorldExample/HelloWorldPublisher.h b/examples/cpp/dds/HelloWorldExample/HelloWorldPublisher.h deleted file mode 100644 index b764dfc67f6..00000000000 --- a/examples/cpp/dds/HelloWorldExample/HelloWorldPublisher.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2019 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 HelloWorldPublisher.h - * - */ - -#ifndef HELLOWORLDPUBLISHER_H_ -#define HELLOWORLDPUBLISHER_H_ - -#include "HelloWorldPubSubTypes.h" - -#include -#include -#include - -class HelloWorldPublisher -{ -public: - - HelloWorldPublisher(); - - virtual ~HelloWorldPublisher(); - - //!Initialize - bool init( - bool use_env); - - //!Publish a sample - bool publish( - bool waitForListener = true); - - //!Run for number samples - void run( - uint32_t number, - uint32_t sleep); - -private: - - HelloWorld hello_; - - eprosima::fastdds::dds::DomainParticipant* participant_; - - eprosima::fastdds::dds::Publisher* publisher_; - - eprosima::fastdds::dds::Topic* topic_; - - eprosima::fastdds::dds::DataWriter* writer_; - - bool stop_; - - class PubListener : public eprosima::fastdds::dds::DataWriterListener - { - public: - - PubListener() - : matched_(0) - , firstConnected_(false) - { - } - - ~PubListener() override - { - } - - void on_publication_matched( - eprosima::fastdds::dds::DataWriter* writer, - const eprosima::fastdds::dds::PublicationMatchedStatus& info) override; - - int matched_; - - bool firstConnected_; - } - listener_; - - void runThread( - uint32_t number, - uint32_t sleep); - - eprosima::fastdds::dds::TypeSupport type_; -}; - - - -#endif /* HELLOWORLDPUBLISHER_H_ */ diff --git a/examples/cpp/dds/HelloWorldExample/HelloWorldSubscriber.h b/examples/cpp/dds/HelloWorldExample/HelloWorldSubscriber.h deleted file mode 100644 index 227198cf191..00000000000 --- a/examples/cpp/dds/HelloWorldExample/HelloWorldSubscriber.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2019 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 HelloWorldSubscriber.h - * - */ - -#ifndef HELLOWORLDSUBSCRIBER_H_ -#define HELLOWORLDSUBSCRIBER_H_ - -#include -#include -#include -#include - -#include "HelloWorldPubSubTypes.h" - -class HelloWorldSubscriber -{ -public: - - HelloWorldSubscriber(); - - virtual ~HelloWorldSubscriber(); - - //!Initialize the subscriber - bool init( - bool use_env); - - //!RUN the subscriber - void run(); - - //!Run the subscriber until number samples have been received. - void run( - uint32_t number); - -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 SubListener : public eprosima::fastdds::dds::DataReaderListener - { - public: - - SubListener() - : matched_(0) - , samples_(0) - { - } - - ~SubListener() override - { - } - - void on_data_available( - eprosima::fastdds::dds::DataReader* reader) override; - - void on_subscription_matched( - eprosima::fastdds::dds::DataReader* reader, - const eprosima::fastdds::dds::SubscriptionMatchedStatus& info) override; - - HelloWorld hello_; - - int matched_; - - uint32_t samples_; - } - listener_; -}; - -#endif /* HELLOWORLDSUBSCRIBER_H_ */ diff --git a/examples/cpp/dds/HelloWorldExample/HelloWorld_main.cpp b/examples/cpp/dds/HelloWorldExample/HelloWorld_main.cpp deleted file mode 100644 index 7a6fb595f09..00000000000 --- a/examples/cpp/dds/HelloWorldExample/HelloWorld_main.cpp +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2019 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 HelloWorld_main.cpp - * - */ - -#include -#include - -#include -#include -#include - -#include "HelloWorldPublisher.h" -#include "HelloWorldSubscriber.h" - -using eprosima::fastdds::dds::Log; - -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 an argument\n"); - } - return option::ARG_ILLEGAL; - } - -}; - -enum optionIndex -{ - UNKNOWN_OPT, - HELP, - SAMPLES, - INTERVAL, - ENVIRONMENT -}; - -const option::Descriptor usage[] = { - { UNKNOWN_OPT, 0, "", "", Arg::None, - "Usage: HelloWorldExample \n\nGeneral options:" }, - { HELP, 0, "h", "help", Arg::None, " -h \t--help \tProduce help message." }, - { UNKNOWN_OPT, 0, "", "", Arg::None, "\nPublisher options:"}, - { SAMPLES, 0, "s", "samples", Arg::NumericRange<>, - " -s , \t--samples= \tNumber of samples (0, default, infinite)." }, - { INTERVAL, 0, "i", "interval", Arg::NumericRange<>, - " -i , \t--interval= \tTime between samples in milliseconds (Default: 100)." }, - { ENVIRONMENT, 0, "e", "env", Arg::None, " -e \t--env \tLoad QoS from environment." }, - { 0, 0, 0, 0, 0, 0 } -}; - -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) - - std::cout << "Starting " << std::endl; - - int type = 1; - uint32_t count = 10; - uint32_t sleep = 100; - bool use_environment_qos = false; - - 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]); - - try - { - if (parse.error()) - { - throw 1; - } - - if (options[HELP] || options[UNKNOWN_OPT]) - { - throw 1; - } - - // For backward compatibility count and sleep may be given positionally - if (parse.nonOptionsCount() > 3 || parse.nonOptionsCount() == 0) - { - throw 2; - } - - // Decide between publisher or subscriber - const char* type_name = parse.nonOption(0); - - // make sure is the first option. - // type_name and buffer[0].name reference the original command line char array - // type_name must precede any other arguments in the array. - // Note buffer[0].arg may be null for non-valued options and is not reliable for - // testing purposes. - if (parse.optionsCount() && type_name >= buffer[0].name) - { - throw 2; - } - - if (strcmp(type_name, "publisher") == 0) - { - type = 1; - } - else if (strcmp(type_name, "subscriber") == 0) - { - type = 2; - } - else - { - throw 2; - } - } - catch (int error) - { - if ( error == 2 ) - { - std::cerr << "ERROR: first argument must be followed by - or -- options" - << std::endl; - } - option::printUsage(fwrite, stdout, usage, columns); - return error; - } - - // Decide between the old and new syntax - if (parse.nonOptionsCount() > 1) - { - // old syntax, only affects publishers - // old and new syntax cannot be mixed - if (type != 1 || parse.optionsCount() > 0) - { - option::printUsage(fwrite, stdout, usage, columns); - return 1; - } - - count = atoi(parse.nonOption(1)); - - if (parse.nonOptionsCount() == 3) - { - sleep = atoi(parse.nonOption(2)); - } - } - else - { - // new syntax - option::Option* opt = options[SAMPLES]; - if (opt) - { - count = strtol(opt->arg, nullptr, 10); - } - - opt = options[INTERVAL]; - if (opt) - { - sleep = strtol(opt->arg, nullptr, 10); - } - - opt = options[ENVIRONMENT]; - if (opt) - { - use_environment_qos = true; - } - } - - switch (type) - { - case 1: - { - HelloWorldPublisher mypub; - if (mypub.init(use_environment_qos)) - { - mypub.run(count, sleep); - } - break; - } - case 2: - { - HelloWorldSubscriber mysub; - if (mysub.init(use_environment_qos)) - { - mysub.run(); - } - break; - } - } - Log::Reset(); - return 0; -} diff --git a/examples/cpp/dds/HelloWorldExample/README.txt b/examples/cpp/dds/HelloWorldExample/README.txt deleted file mode 100644 index 6e02448ed83..00000000000 --- a/examples/cpp/dds/HelloWorldExample/README.txt +++ /dev/null @@ -1,36 +0,0 @@ -To launch this test open two different consoles: - -In the first one launch: ./DDSHelloWorldExample publisher (or DDSHelloWorldExample.exe publisher on windows). -In the second one: ./DDSHelloWorldExample subscriber (or DDSHelloWorldExample.exe subscriber on windows). - -In order to use xml profiles (--env or shorcut -e cli flags): - - reference the xml profiles file setting the environment variable FASTDDS_DEFAULT_PROFILES_FILE to its path. - - name it DEFAULT_FASTDDS_PROFILES.xml and make sure the file is besides the DDSHelloWorldExample binary. -The profile loaded will be the mark as default one with the corresponding attribute. For example: - - - - - - Profiles example name - - - - - - BEST_EFFORT - - - - - - - KEEP_LAST - 5 - - - - - -will create a participant called "Example dummy name" and modify the endpoint set up. -Note the "profile_name" attribute is mandatory. diff --git a/examples/cpp/dds/HelloWorldExample/CMakeLists.txt b/examples/cpp/hello_world/CMakeLists.txt similarity index 67% rename from examples/cpp/dds/HelloWorldExample/CMakeLists.txt rename to examples/cpp/hello_world/CMakeLists.txt index 87fbf8dc2b4..5eb2f7680eb 100644 --- a/examples/cpp/dds/HelloWorldExample/CMakeLists.txt +++ b/examples/cpp/hello_world/CMakeLists.txt @@ -14,7 +14,7 @@ cmake_minimum_required(VERSION 3.20) -project(DDSHelloWorldExample VERSION 1 LANGUAGES CXX) +project(hello_world VERSION 1 LANGUAGES CXX) # Find requirements if(NOT fastcdr_FOUND) @@ -34,15 +34,15 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") endif() endif() -message(STATUS "Configuring HelloWorld example...") -file(GLOB DDS_HELLOWORLD_EXAMPLE_SOURCES_CXX "*.cxx") -file(GLOB DDS_HELLOWORLD_EXAMPLE_SOURCES_CPP "*.cpp") +message(STATUS "Configuring hello world example...") +file(GLOB HELLO_WORLD_SOURCES_CXX "*.cxx") +file(GLOB HELLO_WORLD_SOURCES_CPP "*.cpp") -add_executable(DDSHelloWorldExample ${DDS_HELLOWORLD_EXAMPLE_SOURCES_CXX} ${DDS_HELLOWORLD_EXAMPLE_SOURCES_CPP}) -target_compile_definitions(DDSHelloWorldExample PRIVATE +add_executable(hello_world ${HELLO_WORLD_SOURCES_CXX} ${HELLO_WORLD_SOURCES_CPP}) +target_compile_definitions(hello_world PRIVATE $<$>,$>:__DEBUG> $<$:__INTERNALDEBUG> # Internal debug activated. ) -target_link_libraries(DDSHelloWorldExample fastdds fastcdr fastdds::optionparser) -install(TARGETS DDSHelloWorldExample - RUNTIME DESTINATION examples/cpp/dds/HelloWorldExample/${BIN_INSTALL_DIR}) +target_link_libraries(hello_world fastdds fastcdr) +install(TARGETS hello_world + RUNTIME DESTINATION examples/cpp/hello_world/${BIN_INSTALL_DIR}) diff --git a/examples/cpp/hello_world/DEFAULT_FASTDDS_PROFILES.xml b/examples/cpp/hello_world/DEFAULT_FASTDDS_PROFILES.xml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/cpp/dds/HelloWorldExample/HelloWorld.hpp b/examples/cpp/hello_world/HelloWorld.hpp similarity index 100% rename from examples/cpp/dds/HelloWorldExample/HelloWorld.hpp rename to examples/cpp/hello_world/HelloWorld.hpp diff --git a/examples/cpp/dds/HelloWorldExample/HelloWorld.idl b/examples/cpp/hello_world/HelloWorld.idl similarity index 69% rename from examples/cpp/dds/HelloWorldExample/HelloWorld.idl rename to examples/cpp/hello_world/HelloWorld.idl index 0fd2c355aee..192f8f9d487 100644 --- a/examples/cpp/dds/HelloWorldExample/HelloWorld.idl +++ b/examples/cpp/hello_world/HelloWorld.idl @@ -1,3 +1,4 @@ +@extensibility(APPENDABLE) struct HelloWorld { unsigned long index; diff --git a/examples/cpp/dds/HelloWorldExample/HelloWorldCdrAux.hpp b/examples/cpp/hello_world/HelloWorldCdrAux.hpp similarity index 100% rename from examples/cpp/dds/HelloWorldExample/HelloWorldCdrAux.hpp rename to examples/cpp/hello_world/HelloWorldCdrAux.hpp diff --git a/examples/cpp/dds/HelloWorldExample/HelloWorldCdrAux.ipp b/examples/cpp/hello_world/HelloWorldCdrAux.ipp similarity index 100% rename from examples/cpp/dds/HelloWorldExample/HelloWorldCdrAux.ipp rename to examples/cpp/hello_world/HelloWorldCdrAux.ipp diff --git a/examples/cpp/dds/HelloWorldExample/HelloWorldPubSubTypes.cxx b/examples/cpp/hello_world/HelloWorldPubSubTypes.cxx similarity index 100% rename from examples/cpp/dds/HelloWorldExample/HelloWorldPubSubTypes.cxx rename to examples/cpp/hello_world/HelloWorldPubSubTypes.cxx diff --git a/examples/cpp/dds/HelloWorldExample/HelloWorldPubSubTypes.h b/examples/cpp/hello_world/HelloWorldPubSubTypes.h similarity index 100% rename from examples/cpp/dds/HelloWorldExample/HelloWorldPubSubTypes.h rename to examples/cpp/hello_world/HelloWorldPubSubTypes.h diff --git a/examples/cpp/hello_world/HelloWorldPublisher.cpp b/examples/cpp/hello_world/HelloWorldPublisher.cpp new file mode 100644 index 00000000000..945be6ebea4 --- /dev/null +++ b/examples/cpp/hello_world/HelloWorldPublisher.cpp @@ -0,0 +1,151 @@ +// 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 HelloWorldPublisher.cpp + * + */ + +#include "HelloWorldPublisher.h" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace eprosima::fastdds::dds; + +HelloWorldPublisher::HelloWorldPublisher() + : participant_(nullptr) + , publisher_(nullptr) + , topic_(nullptr) + , writer_(nullptr) + , type_(new HelloWorldPubSubType()) + , stop_(false) +{ + // Set up the data type with initial values + hello_.index(0); + hello_.message("Hello world"); + + // Create the participant + auto factory = DomainParticipantFactory::get_instance(); + participant_ = factory->create_participant_with_default_profile(); + 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); + publisher_ = participant_->create_publisher(pub_qos, nullptr); + 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("Hello_world_topic", "HelloWorld", topic_qos); + if (topic_ == nullptr) + { + throw std::runtime_error("Topic initialization failed"); + } + + // Create the data writer + DataWriterQos writer_qos = DATAWRITER_QOS_DEFAULT; + publisher_->get_default_datawriter_qos(writer_qos); + writer_ = publisher_->create_datawriter(topic_, writer_qos, this); + if (writer_ == nullptr) + { + throw std::runtime_error("DataWriter initialization failed"); + } +} + +HelloWorldPublisher::~HelloWorldPublisher() +{ + if (writer_ != nullptr) + { + publisher_->delete_datawriter(writer_); + } + if (publisher_ != nullptr) + { + participant_->delete_publisher(publisher_); + } + if (topic_ != nullptr) + { + participant_->delete_topic(topic_); + } + DomainParticipantFactory::get_instance()->delete_participant(participant_); +} + +void HelloWorldPublisher::on_publication_matched( + DataWriter*, + const PublicationMatchedStatus& info) +{ + if (info.current_count_change == 1) + { + matched_ = info.total_count; + std::cout << "Publisher matched." << std::endl; + } + else if (info.current_count_change == -1) + { + matched_ = info.total_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 HelloWorldPublisher::run() +{ + std::thread pub_thread([&] + { + while (!stop_.load()) + { + if (publish()) + { + std::cout << "Message: '" << hello_.message() << "' with index: '" << hello_.index() + << "' SENT" << std::endl; + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + }); + std::cout << "Publisher running. Please press enter to stop the Publisher at any time." << std::endl; + std::cin.ignore(); + stop_.store(true); + pub_thread.join(); +} + +bool HelloWorldPublisher::publish() +{ + if (matched_ > 0) + { + hello_.index(hello_.index() + 1); + writer_->write(&hello_); + return true; + } + return false; +} diff --git a/examples/cpp/hello_world/HelloWorldPublisher.h b/examples/cpp/hello_world/HelloWorldPublisher.h new file mode 100644 index 00000000000..57fd6790d48 --- /dev/null +++ b/examples/cpp/hello_world/HelloWorldPublisher.h @@ -0,0 +1,71 @@ +// Copyright 2019 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 hello_world_publisher.h + * + */ + +#ifndef HELLO_WORLD_PUBLISHER_H_ +#define HELLO_WORLD_PUBLISHER_H_ + +#include +#include +#include + +#include "HelloWorldPubSubTypes.h" + +using namespace eprosima::fastdds::dds; + +class HelloWorldPublisher : public DataWriterListener +{ +public: + + HelloWorldPublisher(); + + ~HelloWorldPublisher() override; + + //! Publisher matched method + void on_publication_matched( + DataWriter* writer, + const PublicationMatchedStatus& info) override; + + //! Publish a sample + bool publish(); + + //! Run publisher + void run(); + +private: + + HelloWorld hello_; + + DomainParticipant* participant_; + + Publisher* publisher_; + + Topic* topic_; + + DataWriter* writer_; + + TypeSupport type_; + + std::atomic stop_; + + int16_t matched_; +}; + + + +#endif /* HELLO_WORLD_PUBLISHER_H_ */ diff --git a/examples/cpp/dds/HelloWorldExample/HelloWorldSubscriber.cpp b/examples/cpp/hello_world/HelloWorldSubscriber.cpp similarity index 58% rename from examples/cpp/dds/HelloWorldExample/HelloWorldSubscriber.cpp rename to examples/cpp/hello_world/HelloWorldSubscriber.cpp index 680194c85b8..5894d864b54 100644 --- a/examples/cpp/dds/HelloWorldExample/HelloWorldSubscriber.cpp +++ b/examples/cpp/hello_world/HelloWorldSubscriber.cpp @@ -19,12 +19,14 @@ #include "HelloWorldSubscriber.h" -#include +#include #include +#include #include #include #include +#include #include #include @@ -37,81 +39,44 @@ HelloWorldSubscriber::HelloWorldSubscriber() , reader_(nullptr) , type_(new HelloWorldPubSubType()) { -} - -bool HelloWorldSubscriber::init( - bool use_env) -{ - DomainParticipantQos pqos = PARTICIPANT_QOS_DEFAULT; - pqos.name("Participant_sub"); + // Create the participant auto factory = DomainParticipantFactory::get_instance(); - - if (use_env) - { - factory->load_profiles(); - factory->get_default_participant_qos(pqos); - } - - participant_ = factory->create_participant(0, pqos); - + participant_ = factory->create_participant_with_default_profile(); if (participant_ == nullptr) { - return false; + throw std::runtime_error("Participant initialization failed"); } - //REGISTER THE TYPE + // Register the type type_.register_type(participant_); - //CREATE THE SUBSCRIBER - SubscriberQos sqos = SUBSCRIBER_QOS_DEFAULT; - - if (use_env) - { - participant_->get_default_subscriber_qos(sqos); - } - - subscriber_ = participant_->create_subscriber(sqos, nullptr); - + // Create the subscriber + SubscriberQos sub_qos = SUBSCRIBER_QOS_DEFAULT; + participant_->get_default_subscriber_qos(sub_qos); + subscriber_ = participant_->create_subscriber(sub_qos, nullptr); if (subscriber_ == nullptr) { - return false; + throw std::runtime_error("Subscriber initialization failed"); } - //CREATE THE TOPIC - TopicQos tqos = TOPIC_QOS_DEFAULT; - - if (use_env) - { - participant_->get_default_topic_qos(tqos); - } - - topic_ = participant_->create_topic( - "HelloWorldTopic", - "HelloWorld", - tqos); - + // Create the topic + TopicQos topic_qos = TOPIC_QOS_DEFAULT; + participant_->get_default_topic_qos(topic_qos); + topic_ = participant_->create_topic("Hello_world_topic", "HelloWorld", topic_qos); if (topic_ == nullptr) { - return false; - } - - // CREATE THE READER - DataReaderQos rqos = DATAREADER_QOS_DEFAULT; - rqos.reliability().kind = RELIABLE_RELIABILITY_QOS; - - if (use_env) - { - subscriber_->get_default_datareader_qos(rqos); + throw std::runtime_error("Topic initialization failed"); } - reader_ = subscriber_->create_datareader(topic_, rqos, &listener_); - + // Create the reader + DataReaderQos reader_qos = DATAREADER_QOS_DEFAULT; + reader_qos.reliability().kind = RELIABLE_RELIABILITY_QOS; + subscriber_->get_default_datareader_qos(reader_qos); + reader_ = subscriber_->create_datareader(topic_, reader_qos, this); if (reader_ == nullptr) { - return false; + throw std::runtime_error("DataReader initialization failed"); } - - return true; } HelloWorldSubscriber::~HelloWorldSubscriber() @@ -131,18 +96,16 @@ HelloWorldSubscriber::~HelloWorldSubscriber() DomainParticipantFactory::get_instance()->delete_participant(participant_); } -void HelloWorldSubscriber::SubListener::on_subscription_matched( +void HelloWorldSubscriber::on_subscription_matched( DataReader*, const SubscriptionMatchedStatus& info) { if (info.current_count_change == 1) { - matched_ = info.total_count; std::cout << "Subscriber matched." << std::endl; } else if (info.current_count_change == -1) { - matched_ = info.total_count; std::cout << "Subscriber unmatched." << std::endl; } else @@ -152,7 +115,7 @@ void HelloWorldSubscriber::SubListener::on_subscription_matched( } } -void HelloWorldSubscriber::SubListener::on_data_available( +void HelloWorldSubscriber::on_data_available( DataReader* reader) { SampleInfo info; @@ -160,25 +123,15 @@ void HelloWorldSubscriber::SubListener::on_data_available( { if (info.instance_state == ALIVE_INSTANCE_STATE) { - samples_++; - // Print your structure data here. - std::cout << "Message " << hello_.message() << " " << hello_.index() << " RECEIVED" << std::endl; + // Print Hello world message data + std::cout << "Message: '" << hello_.message() << "' with index: '" << hello_.index() + << "' RECEIVED" << std::endl; } } } void HelloWorldSubscriber::run() { - std::cout << "Subscriber running. Please press enter to stop the Subscriber" << std::endl; + std::cout << "Subscriber running. Please press enter to stop the Subscriber at any time." << std::endl; std::cin.ignore(); } - -void HelloWorldSubscriber::run( - uint32_t number) -{ - std::cout << "Subscriber running until " << number << "samples have been received" << std::endl; - while (number > listener_.samples_) - { - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - } -} diff --git a/examples/cpp/hello_world/HelloWorldSubscriber.h b/examples/cpp/hello_world/HelloWorldSubscriber.h new file mode 100644 index 00000000000..bb127ea6bd4 --- /dev/null +++ b/examples/cpp/hello_world/HelloWorldSubscriber.h @@ -0,0 +1,66 @@ +// Copyright 2019 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 HelloWorldSubscriber.h + * + */ + +#ifndef HELLO_WORLD_SUBSCRIBER_H_ +#define HELLO_WORLD_SUBSCRIBER_H_ + +#include +#include +#include + +#include "HelloWorldPubSubTypes.h" + +using namespace eprosima::fastdds::dds; + +class HelloWorldSubscriber : public DataReaderListener +{ +public: + + HelloWorldSubscriber(); + + virtual ~HelloWorldSubscriber(); + + //! Subscription callback + void on_data_available( + DataReader* reader) override; + + //! Subscriber matched method + void on_subscription_matched( + DataReader* reader, + const SubscriptionMatchedStatus& info) override; + + //! Run subscriber + void run(); + +private: + + HelloWorld hello_; + + DomainParticipant* participant_; + + Subscriber* subscriber_; + + Topic* topic_; + + DataReader* reader_; + + TypeSupport type_; +}; + +#endif /* HELLO_WORLD_SUBSCRIBER_H_ */ diff --git a/examples/cpp/hello_world/HelloWorldSubscriberWaitset.cpp b/examples/cpp/hello_world/HelloWorldSubscriberWaitset.cpp new file mode 100644 index 00000000000..770191e1b31 --- /dev/null +++ b/examples/cpp/hello_world/HelloWorldSubscriberWaitset.cpp @@ -0,0 +1,172 @@ +// 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 HelloWorldSubscriberWaitset.cpp + * + */ + +#include "HelloWorldSubscriberWaitset.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace eprosima::fastdds::dds; + +HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset() + : participant_(nullptr) + , subscriber_(nullptr) + , topic_(nullptr) + , reader_(nullptr) + , type_(new HelloWorldPubSubType()) +{ + stop_.store(false); + + // Create the participant + auto factory = DomainParticipantFactory::get_instance(); + participant_ = factory->create_participant_with_default_profile(); + 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); + subscriber_ = participant_->create_subscriber(sub_qos, nullptr); + 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("Hello_world_topic", "HelloWorld", topic_qos); + if (topic_ == nullptr) + { + throw std::runtime_error("Topic initialization failed"); + } + + // Create the reader + DataReaderQos reader_qos = DATAREADER_QOS_DEFAULT; + reader_qos.reliability().kind = RELIABLE_RELIABILITY_QOS; + subscriber_->get_default_datareader_qos(reader_qos); + reader_ = subscriber_->create_datareader(topic_, reader_qos); + if (reader_ == nullptr) + { + throw std::runtime_error("DataReader initialization failed"); + } + + // Prepare a wait-set + wait_set_.attach_condition(reader_->get_statuscondition()); + wait_set_.attach_condition(terminate_condition_); +} + +HelloWorldSubscriberWaitset::~HelloWorldSubscriberWaitset() +{ + wait_set_.detach_condition(reader_->get_statuscondition()); + if (reader_ != nullptr) + { + subscriber_->delete_datareader(reader_); + } + if (topic_ != nullptr) + { + participant_->delete_topic(topic_); + } + if (subscriber_ != nullptr) + { + participant_->delete_subscriber(subscriber_); + } + DomainParticipantFactory::get_instance()->delete_participant(participant_); +} + +void HelloWorldSubscriberWaitset::run() +{ + std::thread sub_thread([&] + { + while (!stop_.load()) + { + ConditionSeq triggered_conditions; + ReturnCode_t ret_code = wait_set_.wait(triggered_conditions, eprosima::fastrtps::c_TimeInfinite); + if (ReturnCode_t::RETCODE_OK != ret_code) + { + EPROSIMA_LOG_ERROR(SUBSCRIBER_WAITSET, "Error waiting for conditions"); + continue; + } + for (Condition* cond : triggered_conditions) + { + StatusCondition* status_cond = dynamic_cast(cond); + if (nullptr != status_cond) + { + Entity* entity = status_cond->get_entity(); + StatusMask changed_statuses = entity->get_status_changes(); + if (changed_statuses.is_active(StatusMask::subscription_matched())) + { + SubscriptionMatchedStatus status_; + reader_->get_subscription_matched_status(status_); + if (status_.current_count_change == 1) + { + std::cout << "Waitset Subscriber matched." << std::endl; + } + else if (status_.current_count_change == -1) + { + std::cout << "Waitset Subscriber unmatched." << std::endl; + } + else + { + std::cout << status_.current_count_change << + " is not a valid value for SubscriptionMatchedStatus current count change" << + std::endl; + } + } + if (changed_statuses.is_active(StatusMask::data_available())) + { + SampleInfo info; + while ((reader_->take_next_sample(&hello_, + &info) == ReturnCode_t::RETCODE_OK) && !stop_.load()) + { + if (info.instance_state == ALIVE_INSTANCE_STATE) + { + // Print Hello world message data + std::cout << "Message: '" << hello_.message() << "' with index: '" + << hello_.index() << "' RECEIVED" << std::endl; + } + } + } + } + } + } + }); + std::cout << "Waitset Subscriber running. Please press enter to stop the Waitset Subscriber at any time." + << std::endl; + std::cin.ignore(); + terminate_condition_.set_trigger_value(true); + stop_.store(true); + sub_thread.join(); +} diff --git a/examples/cpp/hello_world/HelloWorldSubscriberWaitset.h b/examples/cpp/hello_world/HelloWorldSubscriberWaitset.h new file mode 100644 index 00000000000..d81aa8bb250 --- /dev/null +++ b/examples/cpp/hello_world/HelloWorldSubscriberWaitset.h @@ -0,0 +1,67 @@ +// 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 HelloWorldSubscriberWaitset.h + * + */ + +#ifndef HELLO_WORLD_SUBSCRIBER_WAITSET_H_ +#define HELLO_WORLD_SUBSCRIBER_WAITSET_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "HelloWorldPubSubTypes.h" + +using namespace eprosima::fastdds::dds; + +class HelloWorldSubscriberWaitset +{ +public: + + HelloWorldSubscriberWaitset(); + + virtual ~HelloWorldSubscriberWaitset(); + + //! Run subscriber + void run(); + +private: + + HelloWorld hello_; + + DomainParticipant* participant_; + + Subscriber* subscriber_; + + Topic* topic_; + + DataReader* reader_; + + TypeSupport type_; + + WaitSet wait_set_; + + GuardCondition terminate_condition_; + + std::atomic stop_; +}; + +#endif /* HELLO_WORLD_SUBSCRIBER_WAITSET_H_ */ diff --git a/examples/cpp/dds/HelloWorldExample/HelloWorldTypeObjectSupport.cxx b/examples/cpp/hello_world/HelloWorldTypeObjectSupport.cxx similarity index 98% rename from examples/cpp/dds/HelloWorldExample/HelloWorldTypeObjectSupport.cxx rename to examples/cpp/hello_world/HelloWorldTypeObjectSupport.cxx index fe783982b0f..fedf539c3fd 100644 --- a/examples/cpp/dds/HelloWorldExample/HelloWorldTypeObjectSupport.cxx +++ b/examples/cpp/hello_world/HelloWorldTypeObjectSupport.cxx @@ -54,13 +54,20 @@ void register_HelloWorld_type_identifier( TypeIdentifier& type_id) { { - StructTypeFlag struct_flags_HelloWorld = TypeObjectUtils::build_struct_type_flag(eprosima::fastdds::dds::xtypes::ExtensibilityKind::NOT_APPLIED, + StructTypeFlag struct_flags_HelloWorld = TypeObjectUtils::build_struct_type_flag(eprosima::fastdds::dds::xtypes::ExtensibilityKind::APPENDABLE, false, false); ReturnCode_t return_code_HelloWorld; TypeIdentifierPair type_ids_HelloWorld; QualifiedTypeName type_name_HelloWorld = "HelloWorld"; eprosima::fastcdr::optional type_ann_builtin_HelloWorld; eprosima::fastcdr::optional ann_custom_HelloWorld; + AppliedAnnotationSeq tmp_ann_custom_HelloWorld; + eprosima::fastcdr::optional verbatim_HelloWorld; + if (!tmp_ann_custom_HelloWorld.empty()) + { + ann_custom_HelloWorld = tmp_ann_custom_HelloWorld; + } + CompleteTypeDetail detail_HelloWorld = TypeObjectUtils::build_complete_type_detail(type_ann_builtin_HelloWorld, ann_custom_HelloWorld, type_name_HelloWorld.to_string()); CompleteStructHeader header_HelloWorld; header_HelloWorld = TypeObjectUtils::build_complete_struct_header(TypeIdentifier(), detail_HelloWorld); diff --git a/examples/cpp/dds/HelloWorldExample/HelloWorldTypeObjectSupport.hpp b/examples/cpp/hello_world/HelloWorldTypeObjectSupport.hpp similarity index 100% rename from examples/cpp/dds/HelloWorldExample/HelloWorldTypeObjectSupport.hpp rename to examples/cpp/hello_world/HelloWorldTypeObjectSupport.hpp diff --git a/examples/cpp/hello_world/HelloWorld_main.cpp b/examples/cpp/hello_world/HelloWorld_main.cpp new file mode 100644 index 00000000000..89e0bf9d760 --- /dev/null +++ b/examples/cpp/hello_world/HelloWorld_main.cpp @@ -0,0 +1,91 @@ +// Copyright 2019 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 HelloWorld_main.cpp + * + */ + +#include + +#include +#include + +#include "cli_options.hpp" +#include "HelloWorldPublisher.h" +#include "HelloWorldSubscriber.h" +#include "HelloWorldSubscriberWaitset.h" + +using eprosima::fastdds::dds::Log; + +int main( + int argc, + char** argv) +{ + auto ret = EXIT_SUCCESS; + hello_world_config config = parse_cli_options(argc, argv); + + if (config.entity == "publisher") + { + try + { + HelloWorldPublisher hello_world_publisher; + hello_world_publisher.run(); + } + catch (const std::runtime_error& e) + { + EPROSIMA_LOG_ERROR(PUBLISHER, e.what()); + ret = EXIT_FAILURE; + } + } + else if (config.entity == "subscriber") + { + if (config.sub_config.use_waitset) + { + try + { + HelloWorldSubscriberWaitset hello_world_subscriber_waitset; + hello_world_subscriber_waitset.run(); + } + catch (const std::runtime_error& e) + { + EPROSIMA_LOG_ERROR(SUBSCRIBER, e.what()); + ret = EXIT_FAILURE; + } + } + else + { + try + { + HelloWorldSubscriber hello_world_subscriber; + hello_world_subscriber.run(); + } + catch (const std::runtime_error& e) + { + EPROSIMA_LOG_ERROR(SUBSCRIBER_WAITSET, e.what()); + ret = EXIT_FAILURE; + } + } + } + // example should never reach this point + else + { + std::cerr << "Error: unknown entity " << config.entity << "\n"; + print_help(); + ret = EXIT_FAILURE; + } + + Log::Reset(); + return ret; +} diff --git a/examples/cpp/hello_world/README.md b/examples/cpp/hello_world/README.md new file mode 100644 index 00000000000..19b8352c84f --- /dev/null +++ b/examples/cpp/hello_world/README.md @@ -0,0 +1,176 @@ +# Hello world example + +The *eProsima Fast DDS hello world* example is a simple application intended to demonstrate a basic DDS deployment. + +## Introduction + +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 *hello world* example describes the simplest deployment of a Fast DDS publisher and subscriber. + +## Example in deep + +TODO: talk about entities creation, and XML profile from environment. + +The *hello world* example, together with the remain examples, would include a listening callback on the subscriber side. The subscriber will manage the new available data in the same thread as the main subscriber application. +For simplicity, the ``HelloWorldSubscriber`` implements it own callback. + +Furthermore, this particular example includes a wait-set implementation. In contrast to implementing a listening callback, the wait-set is a mechanism where a dedicated thread waits until a status condition occurs. In that moment, that status condition triggering event would be evaluated to determine witch actions should be taken against it. + +For this example, both listening callback and wait-set implementation would run the same code and generate the same output for both triggering events: subscription matching and new data available. + +## Run the example + +To launch this test open two different consoles. One of them will run the publisher side of the example, and the other would run the subscriber side. + +### Hello world publisher + +#### Ubuntu ( / MacOS ) + +```shell +user@machine:example_path$ ./hello_world publisher +Publisher running. Please press enter to stop the Publisher at any time. +``` + +#### Windows + +```powershell +example_path> hello_world.exe publisher +Publisher running. Please press enter to stop the Publisher at any time. +``` + +### Hello world subscriber + +#### Ubuntu ( / MacOS ) + +```shell +user@machine:example_path$ ./hello_world subscriber +Subscriber running. Please press enter to stop the Subscriber at any time. +``` + +#### Windows + +```powershell +example_path> hello_world.exe subscriber +Subscriber running. Please press enter to stop the Subscriber at any time. +``` + +## Expected output + +It does not matter which entity is launched first, because the publisher has a condition to wait until the first match to start sending hello world samples. +The expected output on both cases is a first displayed message acknowledging they have matched, followed by the amount of samples sent or received until user press ENTER. + +### Hello world publisher + +```shell +Publisher running. Please press enter to stop the Publisher at any time. +Publisher matched. +Message: 'Hello world' with index: '1' SENT +Message: 'Hello world' with index: '2' SENT +Message: 'Hello world' with index: '3' SENT +... +``` + +### Hello world subscriber + +```shell +Subscriber running. Please press enter to stop the Subscriber at any time. +Subscriber matched. +Message: 'Hello world' with index: '1' RECEIVED +Message: 'Hello world' with index: '2' RECEIVED +Message: 'Hello world' with index: '3' RECEIVED +... +``` + +When pressed ENTER to stop one of the applications, the other will detect the unmatched status, and will display an informative message. +This output example represents stopping the subscriber application. + +### Hello world publisher + +```shell +... +Message: 'Hello world' with index: '9' SENT +Message: 'Hello world' with index: '10' SENT +Message: 'Hello world' with index: '11' SENT +Publisher unmatched. +Message: 'Hello world' with index: '12' SENT +Message: 'Hello world' with index: '13' SENT +... +``` + +### Hello world subscriber + +```shell +... +Message: 'Hello world' with index: '9' RECEIVED +Message: 'Hello world' with index: '10' RECEIVED +Message: 'Hello world' with index: '11' RECEIVED +user@machine:example_path$ | +``` + +Stopping the subscriber application does not make the publisher stop sending data. But in the opposite case, stopping the publisher application will make subscriber stop receiving data. + +### Hello world publisher + +```shell +... +Message: 'Hello world' with index: '9' SENT +Message: 'Hello world' with index: '10' SENT +Message: 'Hello world' with index: '11' SENT +user@machine:example_path$ | +``` + +### Hello world subscriber + +```shell +... +Message: 'Hello world' with index: '9' RECEIVED +Message: 'Hello world' with index: '10' RECEIVED +Message: 'Hello world' with index: '11' RECEIVED +Subscriber unmatched. +``` + +## Advanced configuration + +### Wait-set subscriber + +As described in the *[example in deep](#example-in-deep)* section, the *hello world* example has two listening implementations. Launching the subscriber example with the flag ``-w`` or ``--waitset`` will use the wait-set approach instead of the listening callback. + +#### Ubuntu ( / MacOS ) + +```shell +user@machine:example_path$ ./hello_world subscriber --waitset +``` + +#### Windows + +```powershell +example_path> hello_world.exe subscriber --waitset +``` + +The expected output is exactly the same as the described in the *[previous](#expected-output)* section. + + +All the example available flags can be queried running the executable with the ``-h`` or ``--help`` flag. + +### XML profile playground + +The *eProsima Fast DDS* entities can be configured through an XML profile from the environment by adding a reference the XML profiles file setting the environment variable ``FASTDDS_DEFAULT_PROFILES_FILE`` to its path. + +#### Ubuntu ( / MacOS ) + +```shell +user@machine:example_path$ export FASTDDS_DEFAULT_PROFILES_FILE=example_path +``` + +#### Windows + +```powershell +example_path> set FASTDDS_DEFAULT_PROFILES_FILE=example_path +``` + +Other alternative is naming the XML profiles file as DEFAULT_FASTDDS_PROFILES.xml and make sure the file is besides the ``hello_world`` executable. + +The following list contains a set of XML profiles files with certain QoS: + +TODO: do the XMLs and the list diff --git a/examples/cpp/hello_world/cli_options.hpp b/examples/cpp/hello_world/cli_options.hpp new file mode 100644 index 00000000000..260e3bf5a0e --- /dev/null +++ b/examples/cpp/hello_world/cli_options.hpp @@ -0,0 +1,75 @@ +#include + +struct subscriber_config +{ + bool use_waitset; +}; + +struct hello_world_config +{ + std::string entity; + subscriber_config sub_config; +}; + + +void print_help() +{ + std::cout << "Usage: hello_world [entity] [options]\n" + << "Entities: Mandatory field\n" + << " publisher\n" + << " subscriber\n" + << "Options: Optional fields:\n" + << " -w, --waitset Use waitset read condition (subscriber only)\n" + << " -h, --help Print this help message\n"; +} + +hello_world_config parse_cli_options ( + int argc, + char* argv[]) +{ + hello_world_config config; + config.entity = ""; + config.sub_config.use_waitset = false; + + for (int i = 1; i < argc; ++i) + { + std::string arg = argv[i]; + if (arg == "-h" || arg == "--help") + { + print_help(); + exit(EXIT_SUCCESS); + } + else if (arg == "publisher" || arg == "subscriber") + { + config.entity = arg; + } + else if (arg == "-w" || arg == "--waitset") + { + if (config.entity == "subscriber") + { + config.sub_config.use_waitset = true; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSE, "waitset can only be used with the subscriber entity"); + print_help(); + exit(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSE, "unknown option " + arg); + print_help(); + exit(EXIT_FAILURE); + } + } + + if (config.entity == "") + { + EPROSIMA_LOG_ERROR(CLI_PARSE, "entity not specified"); + print_help(); + exit(EXIT_FAILURE); + } + + return config; +} From fcbd19fc490c75c6214a9929bb5d2c612987cd79 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 11 Mar 2024 09:45:55 +0100 Subject: [PATCH 02/42] Refs #20543: Include XML profiles Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CMakeLists.txt | 16 +++++ .../hello_world/DEFAULT_FASTDDS_PROFILES.xml | 0 .../HelloWorld_controller_profile.xml | 53 +++++++++++++++++ .../hello_world/HelloWorld_event_profile.xml | 58 +++++++++++++++++++ .../HelloWorld_multimedia_profile.xml | 43 ++++++++++++++ examples/cpp/hello_world/README.md | 24 ++++++-- 6 files changed, 190 insertions(+), 4 deletions(-) delete mode 100644 examples/cpp/hello_world/DEFAULT_FASTDDS_PROFILES.xml create mode 100644 examples/cpp/hello_world/HelloWorld_controller_profile.xml create mode 100644 examples/cpp/hello_world/HelloWorld_event_profile.xml create mode 100644 examples/cpp/hello_world/HelloWorld_multimedia_profile.xml diff --git a/examples/cpp/hello_world/CMakeLists.txt b/examples/cpp/hello_world/CMakeLists.txt index 5eb2f7680eb..be3fe6cd13e 100644 --- a/examples/cpp/hello_world/CMakeLists.txt +++ b/examples/cpp/hello_world/CMakeLists.txt @@ -46,3 +46,19 @@ target_compile_definitions(hello_world PRIVATE target_link_libraries(hello_world fastdds fastcdr) install(TARGETS hello_world RUNTIME DESTINATION examples/cpp/hello_world/${BIN_INSTALL_DIR}) + +install(TARGETS hello_world + RUNTIME DESTINATION examples/cpp/hello_world/${BIN_INSTALL_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) +endforeach() diff --git a/examples/cpp/hello_world/DEFAULT_FASTDDS_PROFILES.xml b/examples/cpp/hello_world/DEFAULT_FASTDDS_PROFILES.xml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/examples/cpp/hello_world/HelloWorld_controller_profile.xml b/examples/cpp/hello_world/HelloWorld_controller_profile.xml new file mode 100644 index 00000000000..931cd893d25 --- /dev/null +++ b/examples/cpp/hello_world/HelloWorld_controller_profile.xml @@ -0,0 +1,53 @@ + + + + 0 + + hello_world_controllers_participant + UDPv4 + + + + + + TRANSIENT_LOCAL + + + RELIABLE + + + + + KEEP_LAST + 100 + + + 100 + 1 + 100 + + + + + + + + TRANSIENT_LOCAL + + + RELIABLE + + + + + KEEP_LAST + 100 + + + 100 + 1 + 100 + + + + diff --git a/examples/cpp/hello_world/HelloWorld_event_profile.xml b/examples/cpp/hello_world/HelloWorld_event_profile.xml new file mode 100644 index 00000000000..c1592676659 --- /dev/null +++ b/examples/cpp/hello_world/HelloWorld_event_profile.xml @@ -0,0 +1,58 @@ + + + + 0 + + hello_world_events_participant + UDPv4 + + + + + + VOLATILE + + + RELIABLE + + + + + KEEP_LAST + 10 + + + 10 + 1 + 10 + + + + + 10000000 + + + + + + + + VOLATILE + + + RELIABLE + + + + + KEEP_LAST + 10 + + + 10 + 1 + 10 + + + + diff --git a/examples/cpp/hello_world/HelloWorld_multimedia_profile.xml b/examples/cpp/hello_world/HelloWorld_multimedia_profile.xml new file mode 100644 index 00000000000..8c96e4a7a19 --- /dev/null +++ b/examples/cpp/hello_world/HelloWorld_multimedia_profile.xml @@ -0,0 +1,43 @@ + + + + 0 + + hello_world_multimedia_participant + UDPv4 + + + + + + VOLATILE + + + BEST_EFFORT + + + + + KEEP_LAST + 1 + + + + + + + + VOLATILE + + + BEST_EFFORT + + + + + KEEP_LAST + 1 + + + + diff --git a/examples/cpp/hello_world/README.md b/examples/cpp/hello_world/README.md index 19b8352c84f..439e501f7e4 100644 --- a/examples/cpp/hello_world/README.md +++ b/examples/cpp/hello_world/README.md @@ -160,17 +160,33 @@ The *eProsima Fast DDS* entities can be configured through an XML profile from t #### Ubuntu ( / MacOS ) ```shell -user@machine:example_path$ export FASTDDS_DEFAULT_PROFILES_FILE=example_path +user@machine:example_path$ export FASTDDS_DEFAULT_PROFILES_FILE=example_profile.xml ``` #### Windows ```powershell -example_path> set FASTDDS_DEFAULT_PROFILES_FILE=example_path +example_path> set FASTDDS_DEFAULT_PROFILES_FILE=example_profile.xml ``` Other alternative is naming the XML profiles file as DEFAULT_FASTDDS_PROFILES.xml and make sure the file is besides the ``hello_world`` executable. -The following list contains a set of XML profiles files with certain QoS: +The following list contains a set of given XML profiles files with certain QoS: -TODO: do the XMLs and the list +- **Multimedia feed** (HelloWorld_multimedia_profile.xml): Audio and Video transmission have a common characteristic: having a stable, high data-rate feed is more important than having a 100% lossless transmission. For that reason, this scenario is characterized by the following QoS configuration: + - Best-effort reliability: a fast transmission is required, so if a sample is lost, it can be recovered via error-correcting algorithms. + - Volatile durability: while data from the past is not crucial, the transmission of data from the present is. + - Keep-last history with low depth: once displayed or recorded on the receiving application, data is not needed in the History. + +- **Periodic controllers:** (HelloWorld_controller_profile.xml): in this scenario, it is recreated a scenario where periodic sensor data in a distributed network is sent to a single main computer, which makes decisions based on the data. The recommended configuration for this scenario would be: + + - Reliable reliability: samples cannot be lost. Furthermore, since reliable more ensures data delivery, it allows detecting hardware problems when a sensor does not publish data. + - Transient local durability: sensor losing connection temporarily needs tp retrieve all samples, so any sample lost is avoided. + - Keep-last history with high depth: having access to past samples is required in order to be able to compute delta values. + +- **Event-based transmission** (HelloWorld_event_profile.xml): scenarios when data transmission is required only under certain circumstances, e.g. an image from a surveillance camera that has detected any movement, it is important that all data reaches its destination. In those cases, the most appropriate configuration would be: + + - Reliable reliability: all samples must reach their destination. + - Volatile durability: since corrective actions are taken as events come, past triggers have no use. + - Keep-last history with low depth: no past alarm information is necessary for present-time transmissions. + - Reduced heartbeat period: dictates system response velocity when a sample is lost. A lower heartbeat period equals fast response on data delivery. From 61e12c4c00e7286f3716263b9c98c50435691bd3 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 11 Mar 2024 10:07:02 +0100 Subject: [PATCH 03/42] Refs #20543: Include example in test automotation Signed-off-by: JesusPoderoso --- test/examples/hello_world.compose.yml | 27 ++++++++++++++++++ test/examples/test_examples.py | 40 +++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 test/examples/hello_world.compose.yml diff --git a/test/examples/hello_world.compose.yml b/test/examples/hello_world.compose.yml new file mode 100644 index 00000000000..a5a3c70bb2e --- /dev/null +++ b/test/examples/hello_world.compose.yml @@ -0,0 +1,27 @@ +# 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/hello_world + FASTDDS_DEFAULT_PROFILES_FILE: $${EXAMPLE_DIR}/hello_world/HelloWorld_controller_profile.xml + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ publisher & $${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber --waitset" + + 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/hello_world@FILE_EXTENSION@ + FASTDDS_DEFAULT_PROFILES_FILE: $${EXAMPLE_DIR}/hello_world/HelloWorld_controller_profile.xml + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber" diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index d7d500f88ef..9408ae1549b 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -25,6 +25,46 @@ def test_basic_configuration(): received += 1 continue + print(line) + + if sent * 2 == received: + ret = True + else: + raise subprocess.CalledProcessError(1, '') + + except subprocess.CalledProcessError: + for l in out: + print(l) + except subprocess.TimeoutExpired: + print('TIMEOUT') + + assert(ret) + +def test_hello_world(): + """.""" + ret = False + out = '' + try: + out = subprocess.check_output( + '@DOCKER_EXECUTABLE@ compose -f hello_world.compose.yml up', + stderr=subprocess.STDOUT, + shell=True, + timeout=10 + ).decode().split('\n') + + sent = 0 + received = 0 + for line in out: + if 'SENT' in line: + sent += 1 + continue + + if 'RECEIVED' in line: + received += 1 + continue + + print(line) + if sent * 2 == received: ret = True else: From e3ca55ac4e17744c67024ffb1a2b2d6ccb507e4c Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 11 Mar 2024 10:24:04 +0100 Subject: [PATCH 04/42] Refs #20543: Improve README.md Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/cpp/hello_world/README.md b/examples/cpp/hello_world/README.md index 439e501f7e4..06113a008ec 100644 --- a/examples/cpp/hello_world/README.md +++ b/examples/cpp/hello_world/README.md @@ -10,7 +10,10 @@ In this case, the *hello world* example describes the simplest deployment of a F ## Example in deep -TODO: talk about entities creation, and XML profile from environment. +Each entity of the example (publisher and subscriber) creates different nested DDS entities: domain participant, publisher & dataWriter, and subscriber & dataReader, respectively. +In both cases, the three DDS entities (domain participant, publisher/subscriber and dataWriter/dataReader) load their default configuration from the environment. +If the environment does not specify the expected configuration, they take the default configuration per entity. +For further information regarding the configuration environment, please refer to the *[XML profile playground](#xml-profile-playground)* subsection in the *[advanced configuration](#advanced-configuration)* section. The *hello world* example, together with the remain examples, would include a listening callback on the subscriber side. The subscriber will manage the new available data in the same thread as the main subscriber application. For simplicity, the ``HelloWorldSubscriber`` implements it own callback. @@ -169,7 +172,7 @@ user@machine:example_path$ export FASTDDS_DEFAULT_PROFILES_FILE=example_profile. example_path> set FASTDDS_DEFAULT_PROFILES_FILE=example_profile.xml ``` -Other alternative is naming the XML profiles file as DEFAULT_FASTDDS_PROFILES.xml and make sure the file is besides the ``hello_world`` executable. +Other alternative is naming the XML profiles file as ``DEFAULT_FASTDDS_PROFILES.xml`` and make sure the file is besides the ``hello_world`` executable. The following list contains a set of given XML profiles files with certain QoS: @@ -190,3 +193,6 @@ The following list contains a set of given XML profiles files with certain QoS: - Volatile durability: since corrective actions are taken as events come, past triggers have no use. - Keep-last history with low depth: no past alarm information is necessary for present-time transmissions. - Reduced heartbeat period: dictates system response velocity when a sample is lost. A lower heartbeat period equals fast response on data delivery. + +Applying each different configuration to the entities would change the sample management behavior, among other configurations, but in any case these configurations would affect in the behavior of the *hello_world* example. +The expected output would be exactly the same as launching it with no environment configuration. From d499d5e175bdd6d563cb289c415ed7498f8460d8 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 11 Mar 2024 11:05:40 +0100 Subject: [PATCH 05/42] Refs #20543: Update example test to fail if no communication stablished Signed-off-by: JesusPoderoso --- test/examples/test_examples.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index 9408ae1549b..8834c97d1ca 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -27,7 +27,7 @@ def test_basic_configuration(): print(line) - if sent * 2 == received: + if sent != 0 and received != 0 and sent * 2 == received: ret = True else: raise subprocess.CalledProcessError(1, '') @@ -65,7 +65,7 @@ def test_hello_world(): print(line) - if sent * 2 == received: + if sent != 0 and received != 0 and sent * 2 == received: ret = True else: raise subprocess.CalledProcessError(1, '') From d1cb6d0b9a62c73ade4dc43dbc27c40f237c9116 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 11 Mar 2024 16:25:27 +0100 Subject: [PATCH 06/42] Refs #20543: Adjust example to run test Signed-off-by: JesusPoderoso --- .../cpp/hello_world/HelloWorldPublisher.cpp | 25 +++++++-- .../cpp/hello_world/HelloWorldPublisher.h | 9 +++- .../cpp/hello_world/HelloWorldSubscriber.cpp | 32 +++++++++-- .../cpp/hello_world/HelloWorldSubscriber.h | 13 +++++ .../HelloWorldSubscriberWaitset.cpp | 25 +++++++-- .../hello_world/HelloWorldSubscriberWaitset.h | 9 +++- examples/cpp/hello_world/README.md | 16 +++--- test/examples/hello_world.compose.yml | 6 ++- test/examples/test_examples.py | 54 +++++++++---------- 9 files changed, 133 insertions(+), 56 deletions(-) diff --git a/examples/cpp/hello_world/HelloWorldPublisher.cpp b/examples/cpp/hello_world/HelloWorldPublisher.cpp index 945be6ebea4..19eeefae6be 100644 --- a/examples/cpp/hello_world/HelloWorldPublisher.cpp +++ b/examples/cpp/hello_world/HelloWorldPublisher.cpp @@ -19,6 +19,7 @@ #include "HelloWorldPublisher.h" +#include #include #include @@ -30,13 +31,14 @@ using namespace eprosima::fastdds::dds; +std::atomic HelloWorldPublisher::stop_(false); + HelloWorldPublisher::HelloWorldPublisher() : participant_(nullptr) , publisher_(nullptr) , topic_(nullptr) , writer_(nullptr) , type_(new HelloWorldPubSubType()) - , stop_(false) { // Set up the data type with initial values hello_.index(0); @@ -123,7 +125,7 @@ void HelloWorldPublisher::run() { std::thread pub_thread([&] { - while (!stop_.load()) + while (!is_stopped()) { if (publish()) { @@ -133,9 +135,12 @@ void HelloWorldPublisher::run() std::this_thread::sleep_for(std::chrono::milliseconds(100)); } }); - std::cout << "Publisher running. Please press enter to stop the Publisher at any time." << std::endl; - std::cin.ignore(); - stop_.store(true); + std::cout << "Publisher running. 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(); + }); pub_thread.join(); } @@ -149,3 +154,13 @@ bool HelloWorldPublisher::publish() } return false; } + +bool HelloWorldPublisher::is_stopped() +{ + return stop_; +} + +void HelloWorldPublisher::stop() +{ + stop_ = true; +} diff --git a/examples/cpp/hello_world/HelloWorldPublisher.h b/examples/cpp/hello_world/HelloWorldPublisher.h index 57fd6790d48..2ed4351c42b 100644 --- a/examples/cpp/hello_world/HelloWorldPublisher.h +++ b/examples/cpp/hello_world/HelloWorldPublisher.h @@ -13,7 +13,7 @@ // limitations under the License. /** - * @file hello_world_publisher.h + * @file HelloWorldPublisher.h * */ @@ -47,6 +47,11 @@ class HelloWorldPublisher : public DataWriterListener //! Run publisher void run(); + //! Return the current state of execution + static bool is_stopped(); + + //! Trigger the end of execution + static void stop(); private: HelloWorld hello_; @@ -61,7 +66,7 @@ class HelloWorldPublisher : public DataWriterListener TypeSupport type_; - std::atomic stop_; + static std::atomic stop_; int16_t matched_; }; diff --git a/examples/cpp/hello_world/HelloWorldSubscriber.cpp b/examples/cpp/hello_world/HelloWorldSubscriber.cpp index 5894d864b54..258a74e7298 100644 --- a/examples/cpp/hello_world/HelloWorldSubscriber.cpp +++ b/examples/cpp/hello_world/HelloWorldSubscriber.cpp @@ -19,6 +19,8 @@ #include "HelloWorldSubscriber.h" +#include +#include #include #include @@ -32,6 +34,10 @@ using namespace eprosima::fastdds::dds; +std::atomic HelloWorldSubscriber::stop_(false); +std::mutex HelloWorldSubscriber::terminate_cv_mtx_; +std::condition_variable HelloWorldSubscriber::terminate_cv_; + HelloWorldSubscriber::HelloWorldSubscriber() : participant_(nullptr) , subscriber_(nullptr) @@ -119,7 +125,7 @@ void HelloWorldSubscriber::on_data_available( DataReader* reader) { SampleInfo info; - if (reader->take_next_sample(&hello_, &info) == RETCODE_OK) + if (reader->take_next_sample(&hello_, &info) == RETCODE_OK && !is_stopped()) { if (info.instance_state == ALIVE_INSTANCE_STATE) { @@ -132,6 +138,26 @@ void HelloWorldSubscriber::on_data_available( void HelloWorldSubscriber::run() { - std::cout << "Subscriber running. Please press enter to stop the Subscriber at any time." << std::endl; - std::cin.ignore(); + std::cout << "Subscriber running. Please press Ctrl+C to stop the Subscriber at any time." << 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(); + }); +} + +bool HelloWorldSubscriber::is_stopped() +{ + return stop_; +} + +void HelloWorldSubscriber::stop() +{ + stop_ = true; + terminate_cv_.notify_all(); } diff --git a/examples/cpp/hello_world/HelloWorldSubscriber.h b/examples/cpp/hello_world/HelloWorldSubscriber.h index bb127ea6bd4..d35e981b8f3 100644 --- a/examples/cpp/hello_world/HelloWorldSubscriber.h +++ b/examples/cpp/hello_world/HelloWorldSubscriber.h @@ -20,6 +20,8 @@ #ifndef HELLO_WORLD_SUBSCRIBER_H_ #define HELLO_WORLD_SUBSCRIBER_H_ +#include + #include #include #include @@ -48,6 +50,11 @@ class HelloWorldSubscriber : public DataReaderListener //! Run subscriber void run(); + //! Return the current state of execution + static bool is_stopped(); + + //! Trigger the end of execution + static void stop(); private: HelloWorld hello_; @@ -61,6 +68,12 @@ class HelloWorldSubscriber : public DataReaderListener DataReader* reader_; TypeSupport type_; + + static std::atomic stop_; + + static std::mutex terminate_cv_mtx_; + + static std::condition_variable terminate_cv_; }; #endif /* HELLO_WORLD_SUBSCRIBER_H_ */ diff --git a/examples/cpp/hello_world/HelloWorldSubscriberWaitset.cpp b/examples/cpp/hello_world/HelloWorldSubscriberWaitset.cpp index 770191e1b31..d3e4b7fffff 100644 --- a/examples/cpp/hello_world/HelloWorldSubscriberWaitset.cpp +++ b/examples/cpp/hello_world/HelloWorldSubscriberWaitset.cpp @@ -20,6 +20,7 @@ #include "HelloWorldSubscriberWaitset.h" #include +#include #include #include @@ -35,6 +36,9 @@ using namespace eprosima::fastdds::dds; +std::atomic HelloWorldSubscriberWaitset::stop_(false); +GuardCondition HelloWorldSubscriberWaitset::terminate_condition_; + HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset() : participant_(nullptr) , subscriber_(nullptr) @@ -163,10 +167,23 @@ void HelloWorldSubscriberWaitset::run() } } }); - std::cout << "Waitset Subscriber running. Please press enter to stop the Waitset Subscriber at any time." + std::cout << "Waitset Subscriber running. Please press Ctrl+C to stop the Waitset Subscriber at any time." << std::endl; - std::cin.ignore(); - terminate_condition_.set_trigger_value(true); - stop_.store(true); + signal(SIGINT, [](int signum) + { + std::cout << "SIGINT received, stopping Waitset Subscriber execution." << std::endl; + static_cast(signum); HelloWorldSubscriberWaitset::stop(); + }); sub_thread.join(); } + +bool HelloWorldSubscriberWaitset::is_stopped() +{ + return stop_; +} + +void HelloWorldSubscriberWaitset::stop() +{ + stop_ = true; + terminate_condition_.set_trigger_value(true); +} diff --git a/examples/cpp/hello_world/HelloWorldSubscriberWaitset.h b/examples/cpp/hello_world/HelloWorldSubscriberWaitset.h index d81aa8bb250..b9695073ade 100644 --- a/examples/cpp/hello_world/HelloWorldSubscriberWaitset.h +++ b/examples/cpp/hello_world/HelloWorldSubscriberWaitset.h @@ -43,6 +43,11 @@ class HelloWorldSubscriberWaitset //! Run subscriber void run(); + //! Return the current state of execution + static bool is_stopped(); + + //! Trigger the end of execution + static void stop(); private: HelloWorld hello_; @@ -59,9 +64,9 @@ class HelloWorldSubscriberWaitset WaitSet wait_set_; - GuardCondition terminate_condition_; + static std::atomic stop_; - std::atomic stop_; + static GuardCondition terminate_condition_; }; #endif /* HELLO_WORLD_SUBSCRIBER_WAITSET_H_ */ diff --git a/examples/cpp/hello_world/README.md b/examples/cpp/hello_world/README.md index 06113a008ec..72ebe1785c0 100644 --- a/examples/cpp/hello_world/README.md +++ b/examples/cpp/hello_world/README.md @@ -32,14 +32,14 @@ To launch this test open two different consoles. One of them will run the publis ```shell user@machine:example_path$ ./hello_world publisher -Publisher running. Please press enter to stop the Publisher at any time. +Publisher running. Please press Ctrl+C to stop the Publisher at any time. ``` #### Windows ```powershell example_path> hello_world.exe publisher -Publisher running. Please press enter to stop the Publisher at any time. +Publisher running. Please press Ctrl+C to stop the Publisher at any time. ``` ### Hello world subscriber @@ -48,25 +48,25 @@ Publisher running. Please press enter to stop the Publisher at any time. ```shell user@machine:example_path$ ./hello_world subscriber -Subscriber running. Please press enter to stop the Subscriber at any time. +Subscriber running. Please press Ctrl+C to stop the Subscriber at any time. ``` #### Windows ```powershell example_path> hello_world.exe subscriber -Subscriber running. Please press enter to stop the Subscriber at any time. +Subscriber running. Please press Ctrl+C to stop the Subscriber at any time. ``` ## Expected output It does not matter which entity is launched first, because the publisher has a condition to wait until the first match to start sending hello world samples. -The expected output on both cases is a first displayed message acknowledging they have matched, followed by the amount of samples sent or received until user press ENTER. +The expected output on both cases is a first displayed message acknowledging they have matched, followed by the amount of samples sent or received until user press Ctrl+C. ### Hello world publisher ```shell -Publisher running. Please press enter to stop the Publisher at any time. +Publisher running. Please press Ctrl+C to stop the Publisher at any time. Publisher matched. Message: 'Hello world' with index: '1' SENT Message: 'Hello world' with index: '2' SENT @@ -77,7 +77,7 @@ Message: 'Hello world' with index: '3' SENT ### Hello world subscriber ```shell -Subscriber running. Please press enter to stop the Subscriber at any time. +Subscriber running. Please press Ctrl+C to stop the Subscriber at any time. Subscriber matched. Message: 'Hello world' with index: '1' RECEIVED Message: 'Hello world' with index: '2' RECEIVED @@ -85,7 +85,7 @@ Message: 'Hello world' with index: '3' RECEIVED ... ``` -When pressed ENTER to stop one of the applications, the other will detect the unmatched status, and will display an informative message. +When pressed Ctrl+C to stop one of the applications, the other will detect the unmatched status, and will display an informative message. This output example represents stopping the subscriber application. ### Hello world publisher diff --git a/test/examples/hello_world.compose.yml b/test/examples/hello_world.compose.yml index a5a3c70bb2e..a52b74727e1 100644 --- a/test/examples/hello_world.compose.yml +++ b/test/examples/hello_world.compose.yml @@ -7,11 +7,12 @@ services: volumes: - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + - @PROJECT_BINARY_DIR@/examples/cpp/hello_world/HelloWorld_controller_profile.xml:@PROJECT_BINARY_DIR@/examples/cpp/hello_world/HelloWorld_controller_profile.xml 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/hello_world - FASTDDS_DEFAULT_PROFILES_FILE: $${EXAMPLE_DIR}/hello_world/HelloWorld_controller_profile.xml + FASTDDS_DEFAULT_PROFILES_FILE: @PROJECT_BINARY_DIR@/examples/cpp/hello_world/HelloWorld_controller_profile.xml command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ publisher & $${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber --waitset" subscriber: @@ -19,9 +20,10 @@ services: volumes: - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + - @PROJECT_BINARY_DIR@/examples/cpp/hello_world/HelloWorld_controller_profile.xml:@PROJECT_BINARY_DIR@/examples/cpp/hello_world/HelloWorld_controller_profile.xml 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/hello_world@FILE_EXTENSION@ - FASTDDS_DEFAULT_PROFILES_FILE: $${EXAMPLE_DIR}/hello_world/HelloWorld_controller_profile.xml + FASTDDS_DEFAULT_PROFILES_FILE: @PROJECT_BINARY_DIR@/examples/cpp/hello_world/HelloWorld_controller_profile.xml command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber" diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index 8834c97d1ca..d6fc93974e9 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -1,6 +1,8 @@ """.""" +import os +import signal import subprocess - +from subprocess import Popen, PIPE, TimeoutExpired def test_basic_configuration(): """.""" @@ -25,8 +27,6 @@ def test_basic_configuration(): received += 1 continue - print(line) - if sent != 0 and received != 0 and sent * 2 == received: ret = True else: @@ -44,36 +44,30 @@ def test_hello_world(): """.""" ret = False out = '' - try: - out = subprocess.check_output( - '@DOCKER_EXECUTABLE@ compose -f hello_world.compose.yml up', - stderr=subprocess.STDOUT, - shell=True, - timeout=10 - ).decode().split('\n') - - sent = 0 - received = 0 - for line in out: - if 'SENT' in line: - sent += 1 - continue + with Popen('@DOCKER_EXECUTABLE@ compose -f hello_world.compose.yml up', + shell=True, + stdout=PIPE, + preexec_fn=os.setsid) as process: + try: + out = process.communicate(timeout=3)[0].decode().split('\n') + except TimeoutExpired: + os.killpg(process.pid, signal.SIGINT) + out = process.communicate()[0].decode().split('\n') + sent = 0 + received = 0 + for line in out: + if 'SENT' in line: + sent += 1 + continue - if 'RECEIVED' in line: - received += 1 - continue + if 'RECEIVED' in line: + received += 1 + continue - print(line) - - if sent != 0 and received != 0 and sent * 2 == received: - ret = True - else: - raise subprocess.CalledProcessError(1, '') - - except subprocess.CalledProcessError: + if sent != 0 and received != 0 and sent * 2 == received: + ret = True + else: for l in out: print(l) - except subprocess.TimeoutExpired: - print('TIMEOUT') assert(ret) From 4eb84211ba799bbd87644feeddbfe9ba502346b4 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 11 Mar 2024 16:38:21 +0100 Subject: [PATCH 07/42] Refs #20543: Please linters Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/HelloWorldPublisher.h | 1 + examples/cpp/hello_world/HelloWorldSubscriber.h | 1 + examples/cpp/hello_world/HelloWorldSubscriberWaitset.h | 1 + 3 files changed, 3 insertions(+) diff --git a/examples/cpp/hello_world/HelloWorldPublisher.h b/examples/cpp/hello_world/HelloWorldPublisher.h index 2ed4351c42b..accbacde3e4 100644 --- a/examples/cpp/hello_world/HelloWorldPublisher.h +++ b/examples/cpp/hello_world/HelloWorldPublisher.h @@ -52,6 +52,7 @@ class HelloWorldPublisher : public DataWriterListener //! Trigger the end of execution static void stop(); + private: HelloWorld hello_; diff --git a/examples/cpp/hello_world/HelloWorldSubscriber.h b/examples/cpp/hello_world/HelloWorldSubscriber.h index d35e981b8f3..9cdbe42c0bb 100644 --- a/examples/cpp/hello_world/HelloWorldSubscriber.h +++ b/examples/cpp/hello_world/HelloWorldSubscriber.h @@ -55,6 +55,7 @@ class HelloWorldSubscriber : public DataReaderListener //! Trigger the end of execution static void stop(); + private: HelloWorld hello_; diff --git a/examples/cpp/hello_world/HelloWorldSubscriberWaitset.h b/examples/cpp/hello_world/HelloWorldSubscriberWaitset.h index b9695073ade..559b88b61f0 100644 --- a/examples/cpp/hello_world/HelloWorldSubscriberWaitset.h +++ b/examples/cpp/hello_world/HelloWorldSubscriberWaitset.h @@ -48,6 +48,7 @@ class HelloWorldSubscriberWaitset //! Trigger the end of execution static void stop(); + private: HelloWorld hello_; From 498ea0d5e70da4c5d23ce315d9e2ccecb46e4847 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 12 Mar 2024 12:18:02 +0100 Subject: [PATCH 08/42] Refs #20543: Apply rev suggestions Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CMakeLists.txt | 2 +- .../hello_world/HelloWorld_event_profile.xml | 58 -------------- examples/cpp/hello_world/HelloWorld_main.cpp | 13 ++-- .../HelloWorld_multimedia_profile.xml | 43 ----------- ...{HelloWorldPublisher.cpp => Publisher.cpp} | 75 +++++++++++-------- .../{HelloWorldPublisher.h => Publisher.hpp} | 24 ++++-- examples/cpp/hello_world/README.md | 32 +++----- ...elloWorldSubscriber.cpp => Subscriber.cpp} | 61 ++++++++------- ...{HelloWorldSubscriber.h => Subscriber.hpp} | 18 ++--- ...riberWaitset.cpp => SubscriberWaitset.cpp} | 66 ++++++++-------- ...scriberWaitset.h => SubscriberWaitset.hpp} | 8 +- examples/cpp/hello_world/cli_options.hpp | 47 ++++++++---- ...er_profile.xml => hello_world_profile.xml} | 9 +-- test/examples/hello_world.compose.yml | 20 ++--- 14 files changed, 204 insertions(+), 272 deletions(-) delete mode 100644 examples/cpp/hello_world/HelloWorld_event_profile.xml delete mode 100644 examples/cpp/hello_world/HelloWorld_multimedia_profile.xml rename examples/cpp/hello_world/{HelloWorldPublisher.cpp => Publisher.cpp} (69%) rename examples/cpp/hello_world/{HelloWorldPublisher.h => Publisher.hpp} (79%) rename examples/cpp/hello_world/{HelloWorldSubscriber.cpp => Subscriber.cpp} (72%) rename examples/cpp/hello_world/{HelloWorldSubscriber.h => Subscriber.hpp} (86%) rename examples/cpp/hello_world/{HelloWorldSubscriberWaitset.cpp => SubscriberWaitset.cpp} (79%) rename examples/cpp/hello_world/{HelloWorldSubscriberWaitset.h => SubscriberWaitset.hpp} (89%) rename examples/cpp/hello_world/{HelloWorld_controller_profile.xml => hello_world_profile.xml} (77%) diff --git a/examples/cpp/hello_world/CMakeLists.txt b/examples/cpp/hello_world/CMakeLists.txt index be3fe6cd13e..b3ff2a83e72 100644 --- a/examples/cpp/hello_world/CMakeLists.txt +++ b/examples/cpp/hello_world/CMakeLists.txt @@ -14,7 +14,7 @@ cmake_minimum_required(VERSION 3.20) -project(hello_world VERSION 1 LANGUAGES CXX) +project(fastdds_hello_world_example VERSION 1 LANGUAGES CXX) # Find requirements if(NOT fastcdr_FOUND) diff --git a/examples/cpp/hello_world/HelloWorld_event_profile.xml b/examples/cpp/hello_world/HelloWorld_event_profile.xml deleted file mode 100644 index c1592676659..00000000000 --- a/examples/cpp/hello_world/HelloWorld_event_profile.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - 0 - - hello_world_events_participant - UDPv4 - - - - - - VOLATILE - - - RELIABLE - - - - - KEEP_LAST - 10 - - - 10 - 1 - 10 - - - - - 10000000 - - - - - - - - VOLATILE - - - RELIABLE - - - - - KEEP_LAST - 10 - - - 10 - 1 - 10 - - - - diff --git a/examples/cpp/hello_world/HelloWorld_main.cpp b/examples/cpp/hello_world/HelloWorld_main.cpp index 89e0bf9d760..77870d6539d 100644 --- a/examples/cpp/hello_world/HelloWorld_main.cpp +++ b/examples/cpp/hello_world/HelloWorld_main.cpp @@ -1,4 +1,4 @@ -// Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// 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. @@ -23,9 +23,9 @@ #include #include "cli_options.hpp" -#include "HelloWorldPublisher.h" -#include "HelloWorldSubscriber.h" -#include "HelloWorldSubscriberWaitset.h" +#include "Publisher.hpp" +#include "Subscriber.hpp" +#include "SubscriberWaitset.hpp" using eprosima::fastdds::dds::Log; @@ -81,9 +81,8 @@ int main( // example should never reach this point else { - std::cerr << "Error: unknown entity " << config.entity << "\n"; - print_help(); - ret = EXIT_FAILURE; + EPROSIMA_LOG_ERROR(CLI_PARSE, "unknown entity " + config.entity); + print_help(EXIT_FAILURE); } Log::Reset(); diff --git a/examples/cpp/hello_world/HelloWorld_multimedia_profile.xml b/examples/cpp/hello_world/HelloWorld_multimedia_profile.xml deleted file mode 100644 index 8c96e4a7a19..00000000000 --- a/examples/cpp/hello_world/HelloWorld_multimedia_profile.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - 0 - - hello_world_multimedia_participant - UDPv4 - - - - - - VOLATILE - - - BEST_EFFORT - - - - - KEEP_LAST - 1 - - - - - - - - VOLATILE - - - BEST_EFFORT - - - - - KEEP_LAST - 1 - - - - diff --git a/examples/cpp/hello_world/HelloWorldPublisher.cpp b/examples/cpp/hello_world/Publisher.cpp similarity index 69% rename from examples/cpp/hello_world/HelloWorldPublisher.cpp rename to examples/cpp/hello_world/Publisher.cpp index 19eeefae6be..308fc7c4610 100644 --- a/examples/cpp/hello_world/HelloWorldPublisher.cpp +++ b/examples/cpp/hello_world/Publisher.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// 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. @@ -13,12 +13,13 @@ // limitations under the License. /** - * @file HelloWorldPublisher.cpp + * @file Publisher.cpp * */ -#include "HelloWorldPublisher.h" +#include "Publisher.hpp" +#include #include #include #include @@ -58,7 +59,7 @@ HelloWorldPublisher::HelloWorldPublisher() // Create the publisher PublisherQos pub_qos = PUBLISHER_QOS_DEFAULT; participant_->get_default_publisher_qos(pub_qos); - publisher_ = participant_->create_publisher(pub_qos, nullptr); + publisher_ = participant_->create_publisher(pub_qos); if (publisher_ == nullptr) { throw std::runtime_error("Publisher initialization failed"); @@ -67,7 +68,7 @@ HelloWorldPublisher::HelloWorldPublisher() // Create the topic TopicQos topic_qos = TOPIC_QOS_DEFAULT; participant_->get_default_topic_qos(topic_qos); - topic_ = participant_->create_topic("Hello_world_topic", "HelloWorld", topic_qos); + topic_ = participant_->create_topic("hello_world_topic", type_.get_type_name(), topic_qos); if (topic_ == nullptr) { throw std::runtime_error("Topic initialization failed"); @@ -85,29 +86,22 @@ HelloWorldPublisher::HelloWorldPublisher() HelloWorldPublisher::~HelloWorldPublisher() { - if (writer_ != nullptr) - { - publisher_->delete_datawriter(writer_); - } - if (publisher_ != nullptr) - { - participant_->delete_publisher(publisher_); - } - if (topic_ != nullptr) - { - participant_->delete_topic(topic_); - } + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); + + // Delete DomainParticipant DomainParticipantFactory::get_instance()->delete_participant(participant_); } void HelloWorldPublisher::on_publication_matched( - DataWriter*, + DataWriter* /*writer*/, const PublicationMatchedStatus& info) { if (info.current_count_change == 1) { matched_ = info.total_count; std::cout << "Publisher matched." << std::endl; + matched_cv_.notify_one(); } else if (info.current_count_change == -1) { @@ -132,35 +126,54 @@ void HelloWorldPublisher::run() std::cout << "Message: '" << hello_.message() << "' with index: '" << hello_.index() << "' SENT" << std::endl; } - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::sleep_for(std::chrono::milliseconds(period_)); } }); std::cout << "Publisher running. Please press Ctrl+C to stop the Publisher at any time." << std::endl; - signal(SIGINT, [](int signum) + signal(SIGINT, [](int /*signum*/) + { + std::cout << "\nSIGINT received, stopping Publisher execution." << std::endl; + HelloWorldPublisher::stop(); + }); + signal(SIGTERM, [](int /*signum*/) { - std::cout << "SIGINT received, stopping Publisher execution." << std::endl; - static_cast(signum); HelloWorldPublisher::stop(); + std::cout << "\nSIGTERM received, stopping Publisher execution." << std::endl; + HelloWorldPublisher::stop(); }); +#ifndef _WIN32 + signal(SIGQUIT, [](int /*signum*/) + { + std::cout << "\nSIGQUIT received, stopping Publisher execution." << std::endl; + HelloWorldPublisher::stop(); + }); + signal(SIGHUP, [](int /*signum*/) + { + std::cout << "\nSIGHUP received, stopping Publisher execution." << std::endl; + HelloWorldPublisher::stop(); + }); +#endif // _WIN32 pub_thread.join(); } bool HelloWorldPublisher::publish() { - if (matched_ > 0) - { - hello_.index(hello_.index() + 1); - writer_->write(&hello_); - return true; - } - return false; + // Wait for the data endpoints discovery + std::unique_lock matched_lock(mutex_); + matched_cv_.wait(matched_lock, [&]() + { + // at least one has been discovered + return matched_ > 0; + }); + hello_.index(hello_.index() + 1); + return writer_->write(&hello_); } bool HelloWorldPublisher::is_stopped() { - return stop_; + return stop_.load(); } void HelloWorldPublisher::stop() { - stop_ = true; + stop_.store(true); } diff --git a/examples/cpp/hello_world/HelloWorldPublisher.h b/examples/cpp/hello_world/Publisher.hpp similarity index 79% rename from examples/cpp/hello_world/HelloWorldPublisher.h rename to examples/cpp/hello_world/Publisher.hpp index accbacde3e4..529eee83e9d 100644 --- a/examples/cpp/hello_world/HelloWorldPublisher.h +++ b/examples/cpp/hello_world/Publisher.hpp @@ -1,4 +1,4 @@ -// Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// 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. @@ -13,12 +13,14 @@ // limitations under the License. /** - * @file HelloWorldPublisher.h + * @file Publisher.hpp * */ -#ifndef HELLO_WORLD_PUBLISHER_H_ -#define HELLO_WORLD_PUBLISHER_H_ +#ifndef _FASTDDS_HELLO_WORLD_PUBLISHER_HPP_ +#define _FASTDDS_HELLO_WORLD_PUBLISHER_HPP_ + +#include #include #include @@ -47,14 +49,14 @@ class HelloWorldPublisher : public DataWriterListener //! Run publisher void run(); - //! Return the current state of execution - static bool is_stopped(); - //! Trigger the end of execution static void stop(); private: + //! Return the current state of execution + bool is_stopped(); + HelloWorld hello_; DomainParticipant* participant_; @@ -70,8 +72,14 @@ class HelloWorldPublisher : public DataWriterListener static std::atomic stop_; int16_t matched_; + + std::mutex mutex_; + + std::condition_variable matched_cv_; + + const uint8_t period_ = 100; // in ms }; -#endif /* HELLO_WORLD_PUBLISHER_H_ */ +#endif /* _FASTDDS_HELLO_WORLD_PUBLISHER_HPP_ */ diff --git a/examples/cpp/hello_world/README.md b/examples/cpp/hello_world/README.md index 72ebe1785c0..0b26060c244 100644 --- a/examples/cpp/hello_world/README.md +++ b/examples/cpp/hello_world/README.md @@ -163,36 +163,22 @@ The *eProsima Fast DDS* entities can be configured through an XML profile from t #### Ubuntu ( / MacOS ) ```shell -user@machine:example_path$ export FASTDDS_DEFAULT_PROFILES_FILE=example_profile.xml +user@machine:example_path$ export FASTDDS_DEFAULT_PROFILES_FILE=hello_world_profile.xml ``` #### Windows ```powershell -example_path> set FASTDDS_DEFAULT_PROFILES_FILE=example_profile.xml +example_path> set FASTDDS_DEFAULT_PROFILES_FILE=hello_world_profile.xml ``` -Other alternative is naming the XML profiles file as ``DEFAULT_FASTDDS_PROFILES.xml`` and make sure the file is besides the ``hello_world`` executable. +The example contains a XML profiles files with certain QoS: -The following list contains a set of given XML profiles files with certain QoS: +- Reliable reliability: avoid sample loss. +- Transient local durability: enable late-join-participants to receive previous samples if connection was lost. +- Keep-last history with high depth: ensure certain amount of previous samples for late-joiners. -- **Multimedia feed** (HelloWorld_multimedia_profile.xml): Audio and Video transmission have a common characteristic: having a stable, high data-rate feed is more important than having a 100% lossless transmission. For that reason, this scenario is characterized by the following QoS configuration: - - Best-effort reliability: a fast transmission is required, so if a sample is lost, it can be recovered via error-correcting algorithms. - - Volatile durability: while data from the past is not crucial, the transmission of data from the present is. - - Keep-last history with low depth: once displayed or recorded on the receiving application, data is not needed in the History. - -- **Periodic controllers:** (HelloWorld_controller_profile.xml): in this scenario, it is recreated a scenario where periodic sensor data in a distributed network is sent to a single main computer, which makes decisions based on the data. The recommended configuration for this scenario would be: - - - Reliable reliability: samples cannot be lost. Furthermore, since reliable more ensures data delivery, it allows detecting hardware problems when a sensor does not publish data. - - Transient local durability: sensor losing connection temporarily needs tp retrieve all samples, so any sample lost is avoided. - - Keep-last history with high depth: having access to past samples is required in order to be able to compute delta values. - -- **Event-based transmission** (HelloWorld_event_profile.xml): scenarios when data transmission is required only under certain circumstances, e.g. an image from a surveillance camera that has detected any movement, it is important that all data reaches its destination. In those cases, the most appropriate configuration would be: - - - Reliable reliability: all samples must reach their destination. - - Volatile durability: since corrective actions are taken as events come, past triggers have no use. - - Keep-last history with low depth: no past alarm information is necessary for present-time transmissions. - - Reduced heartbeat period: dictates system response velocity when a sample is lost. A lower heartbeat period equals fast response on data delivery. - -Applying each different configuration to the entities would change the sample management behavior, among other configurations, but in any case these configurations would affect in the behavior of the *hello_world* example. +Applying different configurations to the entities would change the sample management behavior, among other configurations, but in any case these configurations would affect in the behavior of the *hello_world* example. The expected output would be exactly the same as launching it with no environment configuration. + +Try your own XML profile to see how your configuration affects the *hello world* example communication. diff --git a/examples/cpp/hello_world/HelloWorldSubscriber.cpp b/examples/cpp/hello_world/Subscriber.cpp similarity index 72% rename from examples/cpp/hello_world/HelloWorldSubscriber.cpp rename to examples/cpp/hello_world/Subscriber.cpp index 258a74e7298..748dfb354f5 100644 --- a/examples/cpp/hello_world/HelloWorldSubscriber.cpp +++ b/examples/cpp/hello_world/Subscriber.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// 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. @@ -13,11 +13,11 @@ // limitations under the License. /** - * @file HelloWorldSubscriber.cpp + * @file Subscriber.cpp * */ -#include "HelloWorldSubscriber.h" +#include "Subscriber.hpp" #include #include @@ -35,7 +35,6 @@ using namespace eprosima::fastdds::dds; std::atomic HelloWorldSubscriber::stop_(false); -std::mutex HelloWorldSubscriber::terminate_cv_mtx_; std::condition_variable HelloWorldSubscriber::terminate_cv_; HelloWorldSubscriber::HelloWorldSubscriber() @@ -59,7 +58,7 @@ HelloWorldSubscriber::HelloWorldSubscriber() // Create the subscriber SubscriberQos sub_qos = SUBSCRIBER_QOS_DEFAULT; participant_->get_default_subscriber_qos(sub_qos); - subscriber_ = participant_->create_subscriber(sub_qos, nullptr); + subscriber_ = participant_->create_subscriber(sub_qos); if (subscriber_ == nullptr) { throw std::runtime_error("Subscriber initialization failed"); @@ -68,7 +67,7 @@ HelloWorldSubscriber::HelloWorldSubscriber() // Create the topic TopicQos topic_qos = TOPIC_QOS_DEFAULT; participant_->get_default_topic_qos(topic_qos); - topic_ = participant_->create_topic("Hello_world_topic", "HelloWorld", topic_qos); + topic_ = participant_->create_topic("hello_world_topic", type_.get_type_name(), topic_qos); if (topic_ == nullptr) { throw std::runtime_error("Topic initialization failed"); @@ -76,7 +75,6 @@ HelloWorldSubscriber::HelloWorldSubscriber() // Create the reader DataReaderQos reader_qos = DATAREADER_QOS_DEFAULT; - reader_qos.reliability().kind = RELIABLE_RELIABILITY_QOS; subscriber_->get_default_datareader_qos(reader_qos); reader_ = subscriber_->create_datareader(topic_, reader_qos, this); if (reader_ == nullptr) @@ -87,23 +85,15 @@ HelloWorldSubscriber::HelloWorldSubscriber() HelloWorldSubscriber::~HelloWorldSubscriber() { - if (reader_ != nullptr) - { - subscriber_->delete_datareader(reader_); - } - if (topic_ != nullptr) - { - participant_->delete_topic(topic_); - } - if (subscriber_ != nullptr) - { - participant_->delete_subscriber(subscriber_); - } + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); + + // Delete DomainParticipant DomainParticipantFactory::get_instance()->delete_participant(participant_); } void HelloWorldSubscriber::on_subscription_matched( - DataReader*, + DataReader* /*reader*/, const SubscriptionMatchedStatus& info) { if (info.current_count_change == 1) @@ -125,9 +115,9 @@ void HelloWorldSubscriber::on_data_available( DataReader* reader) { SampleInfo info; - if (reader->take_next_sample(&hello_, &info) == RETCODE_OK && !is_stopped()) + if ((!is_stopped()) && (RETCODE_OK == reader->take_next_sample(&hello_, &info))) { - if (info.instance_state == ALIVE_INSTANCE_STATE) + if (info.instance_state == ALIVE_INSTANCE_STATE && info.valid_data) { // Print Hello world message data std::cout << "Message: '" << hello_.message() << "' with index: '" << hello_.index() @@ -139,11 +129,28 @@ void HelloWorldSubscriber::on_data_available( void HelloWorldSubscriber::run() { std::cout << "Subscriber running. Please press Ctrl+C to stop the Subscriber at any time." << std::endl; - signal(SIGINT, [](int signum) + signal(SIGINT, [](int /*signum*/) + { + std::cout << "\nSIGINT received, stopping Subscriber execution." << std::endl; + HelloWorldSubscriber::stop(); + }); + signal(SIGTERM, [](int /*signum*/) + { + std::cout << "\nSIGTERM received, stopping Subscriber execution." << std::endl; + HelloWorldSubscriber::stop(); + }); +#ifndef _WIN32 + signal(SIGQUIT, [](int /*signum*/) + { + std::cout << "\nSIGQUIT received, stopping Subscriber execution." << std::endl; + HelloWorldSubscriber::stop(); + }); + signal(SIGHUP, [](int /*signum*/) { - std::cout << "SIGINT received, stopping Subscriber execution." << std::endl; - static_cast(signum); HelloWorldSubscriber::stop(); + std::cout << "\nSIGHUP received, stopping Subscriber execution." << std::endl; + HelloWorldSubscriber::stop(); }); +#endif // _WIN32 std::unique_lock lck(terminate_cv_mtx_); terminate_cv_.wait(lck, [] { @@ -153,11 +160,11 @@ void HelloWorldSubscriber::run() bool HelloWorldSubscriber::is_stopped() { - return stop_; + return stop_.load(); } void HelloWorldSubscriber::stop() { - stop_ = true; + stop_.store(true); terminate_cv_.notify_all(); } diff --git a/examples/cpp/hello_world/HelloWorldSubscriber.h b/examples/cpp/hello_world/Subscriber.hpp similarity index 86% rename from examples/cpp/hello_world/HelloWorldSubscriber.h rename to examples/cpp/hello_world/Subscriber.hpp index 9cdbe42c0bb..2f1e0e4c565 100644 --- a/examples/cpp/hello_world/HelloWorldSubscriber.h +++ b/examples/cpp/hello_world/Subscriber.hpp @@ -1,4 +1,4 @@ -// Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// 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. @@ -13,12 +13,12 @@ // limitations under the License. /** - * @file HelloWorldSubscriber.h + * @file Subscriber.hpp * */ -#ifndef HELLO_WORLD_SUBSCRIBER_H_ -#define HELLO_WORLD_SUBSCRIBER_H_ +#ifndef _FASTDDS_HELLO_WORLD_SUBSCRIBER_HPP_ +#define _FASTDDS_HELLO_WORLD_SUBSCRIBER_HPP_ #include @@ -50,14 +50,14 @@ class HelloWorldSubscriber : public DataReaderListener //! Run subscriber void run(); - //! Return the current state of execution - static bool is_stopped(); - //! Trigger the end of execution static void stop(); private: + //! Return the current state of execution + static bool is_stopped(); + HelloWorld hello_; DomainParticipant* participant_; @@ -72,9 +72,9 @@ class HelloWorldSubscriber : public DataReaderListener static std::atomic stop_; - static std::mutex terminate_cv_mtx_; + mutable std::mutex terminate_cv_mtx_; static std::condition_variable terminate_cv_; }; -#endif /* HELLO_WORLD_SUBSCRIBER_H_ */ +#endif /* _FASTDDS_HELLO_WORLD_SUBSCRIBER_HPP_ */ diff --git a/examples/cpp/hello_world/HelloWorldSubscriberWaitset.cpp b/examples/cpp/hello_world/SubscriberWaitset.cpp similarity index 79% rename from examples/cpp/hello_world/HelloWorldSubscriberWaitset.cpp rename to examples/cpp/hello_world/SubscriberWaitset.cpp index d3e4b7fffff..9dbc38b9e53 100644 --- a/examples/cpp/hello_world/HelloWorldSubscriberWaitset.cpp +++ b/examples/cpp/hello_world/SubscriberWaitset.cpp @@ -1,4 +1,4 @@ -// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// 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. @@ -13,11 +13,11 @@ // limitations under the License. /** - * @file HelloWorldSubscriberWaitset.cpp + * @file SubscriberWaitset.cpp * */ -#include "HelloWorldSubscriberWaitset.h" +#include "SubscriberWaitset.hpp" #include #include @@ -46,8 +46,6 @@ HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset() , reader_(nullptr) , type_(new HelloWorldPubSubType()) { - stop_.store(false); - // Create the participant auto factory = DomainParticipantFactory::get_instance(); participant_ = factory->create_participant_with_default_profile(); @@ -62,7 +60,7 @@ HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset() // Create the subscriber SubscriberQos sub_qos = SUBSCRIBER_QOS_DEFAULT; participant_->get_default_subscriber_qos(sub_qos); - subscriber_ = participant_->create_subscriber(sub_qos, nullptr); + subscriber_ = participant_->create_subscriber(sub_qos); if (subscriber_ == nullptr) { throw std::runtime_error("Subscriber initialization failed"); @@ -71,7 +69,7 @@ HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset() // Create the topic TopicQos topic_qos = TOPIC_QOS_DEFAULT; participant_->get_default_topic_qos(topic_qos); - topic_ = participant_->create_topic("Hello_world_topic", "HelloWorld", topic_qos); + topic_ = participant_->create_topic("hello_world_topic", type_.get_type_name(), topic_qos); if (topic_ == nullptr) { throw std::runtime_error("Topic initialization failed"); @@ -79,7 +77,6 @@ HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset() // Create the reader DataReaderQos reader_qos = DATAREADER_QOS_DEFAULT; - reader_qos.reliability().kind = RELIABLE_RELIABILITY_QOS; subscriber_->get_default_datareader_qos(reader_qos); reader_ = subscriber_->create_datareader(topic_, reader_qos); if (reader_ == nullptr) @@ -94,19 +91,10 @@ HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset() HelloWorldSubscriberWaitset::~HelloWorldSubscriberWaitset() { - wait_set_.detach_condition(reader_->get_statuscondition()); - if (reader_ != nullptr) - { - subscriber_->delete_datareader(reader_); - } - if (topic_ != nullptr) - { - participant_->delete_topic(topic_); - } - if (subscriber_ != nullptr) - { - participant_->delete_subscriber(subscriber_); - } + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); + + // Delete DomainParticipant DomainParticipantFactory::get_instance()->delete_participant(participant_); } @@ -114,7 +102,7 @@ void HelloWorldSubscriberWaitset::run() { std::thread sub_thread([&] { - while (!stop_.load()) + while (!is_stopped()) { ConditionSeq triggered_conditions; ReturnCode_t ret_code = wait_set_.wait(triggered_conditions, eprosima::fastrtps::c_TimeInfinite); @@ -152,10 +140,10 @@ void HelloWorldSubscriberWaitset::run() if (changed_statuses.is_active(StatusMask::data_available())) { SampleInfo info; - while ((reader_->take_next_sample(&hello_, - &info) == ReturnCode_t::RETCODE_OK) && !stop_.load()) + while ((!is_stopped()) && + (ReturnCode_t::RETCODE_OK == reader_->take_next_sample(&hello_, &info))) { - if (info.instance_state == ALIVE_INSTANCE_STATE) + if (info.instance_state == ALIVE_INSTANCE_STATE && info.valid_data) { // Print Hello world message data std::cout << "Message: '" << hello_.message() << "' with index: '" @@ -167,23 +155,41 @@ void HelloWorldSubscriberWaitset::run() } } }); + std::cout << "Waitset Subscriber running. Please press Ctrl+C to stop the Waitset Subscriber at any time." << std::endl; - signal(SIGINT, [](int signum) + signal(SIGINT, [](int /*signum*/) + { + std::cout << "\nSIGINT received, stopping Waitset Subscriber execution." << std::endl; + HelloWorldSubscriberWaitset::stop(); + }); + signal(SIGTERM, [](int /*signum*/) + { + std::cout << "\nSIGTERM received, stopping Waitset Subscriber execution." << std::endl; + HelloWorldSubscriberWaitset::stop(); + }); +#ifndef _WIN32 + signal(SIGQUIT, [](int /*signum*/) + { + std::cout << "\nSIGQUIT received, stopping Waitset Subscriber execution." << std::endl; + HelloWorldSubscriberWaitset::stop(); + }); + signal(SIGHUP, [](int /*signum*/) { - std::cout << "SIGINT received, stopping Waitset Subscriber execution." << std::endl; - static_cast(signum); HelloWorldSubscriberWaitset::stop(); + std::cout << "\nSIGHUP received, stopping Waitset Subscriber execution." << std::endl; + HelloWorldSubscriberWaitset::stop(); }); +#endif // _WIN32 sub_thread.join(); } bool HelloWorldSubscriberWaitset::is_stopped() { - return stop_; + return stop_.load(); } void HelloWorldSubscriberWaitset::stop() { - stop_ = true; + stop_.store(true); terminate_condition_.set_trigger_value(true); } diff --git a/examples/cpp/hello_world/HelloWorldSubscriberWaitset.h b/examples/cpp/hello_world/SubscriberWaitset.hpp similarity index 89% rename from examples/cpp/hello_world/HelloWorldSubscriberWaitset.h rename to examples/cpp/hello_world/SubscriberWaitset.hpp index 559b88b61f0..14d064d0ade 100644 --- a/examples/cpp/hello_world/HelloWorldSubscriberWaitset.h +++ b/examples/cpp/hello_world/SubscriberWaitset.hpp @@ -13,12 +13,12 @@ // limitations under the License. /** - * @file HelloWorldSubscriberWaitset.h + * @file SubscriberWaitset.hpp * */ -#ifndef HELLO_WORLD_SUBSCRIBER_WAITSET_H_ -#define HELLO_WORLD_SUBSCRIBER_WAITSET_H_ +#ifndef _FASTDDS_HELLO_WORLD_SUBSCRIBER_WAITSET_HPP_ +#define _FASTDDS_HELLO_WORLD_SUBSCRIBER_WAITSET_HPP_ #include #include @@ -70,4 +70,4 @@ class HelloWorldSubscriberWaitset static GuardCondition terminate_condition_; }; -#endif /* HELLO_WORLD_SUBSCRIBER_WAITSET_H_ */ +#endif /* _FASTDDS_HELLO_WORLD_SUBSCRIBER_WAITSET_HPP_ */ diff --git a/examples/cpp/hello_world/cli_options.hpp b/examples/cpp/hello_world/cli_options.hpp index 260e3bf5a0e..5236ed3ffad 100644 --- a/examples/cpp/hello_world/cli_options.hpp +++ b/examples/cpp/hello_world/cli_options.hpp @@ -1,3 +1,18 @@ +// 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 struct subscriber_config @@ -12,15 +27,19 @@ struct hello_world_config }; -void print_help() +void print_help( + uint8_t return_code) { - std::cout << "Usage: hello_world [entity] [options]\n" - << "Entities: Mandatory field\n" - << " publisher\n" - << " subscriber\n" - << "Options: Optional fields:\n" - << " -w, --waitset Use waitset read condition (subscriber only)\n" - << " -h, --help Print this help message\n"; + std::cout << "Usage: hello_world [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 << "Common options:" << std::endl; + std::cout << " -h, --help Print this help message" << std::endl; + std::cout << "Subscriber options:" << std::endl; + std::cout << " -w, --waitset Use waitset read condition" << std::endl; + std::exit(return_code); } hello_world_config parse_cli_options ( @@ -36,8 +55,7 @@ hello_world_config parse_cli_options ( std::string arg = argv[i]; if (arg == "-h" || arg == "--help") { - print_help(); - exit(EXIT_SUCCESS); + print_help(EXIT_SUCCESS); } else if (arg == "publisher" || arg == "subscriber") { @@ -52,23 +70,20 @@ hello_world_config parse_cli_options ( else { EPROSIMA_LOG_ERROR(CLI_PARSE, "waitset can only be used with the subscriber entity"); - print_help(); - exit(EXIT_FAILURE); + print_help(EXIT_FAILURE); } } else { EPROSIMA_LOG_ERROR(CLI_PARSE, "unknown option " + arg); - print_help(); - exit(EXIT_FAILURE); + print_help(EXIT_FAILURE); } } if (config.entity == "") { EPROSIMA_LOG_ERROR(CLI_PARSE, "entity not specified"); - print_help(); - exit(EXIT_FAILURE); + print_help(EXIT_FAILURE); } return config; diff --git a/examples/cpp/hello_world/HelloWorld_controller_profile.xml b/examples/cpp/hello_world/hello_world_profile.xml similarity index 77% rename from examples/cpp/hello_world/HelloWorld_controller_profile.xml rename to examples/cpp/hello_world/hello_world_profile.xml index 931cd893d25..1cc694fd28b 100644 --- a/examples/cpp/hello_world/HelloWorld_controller_profile.xml +++ b/examples/cpp/hello_world/hello_world_profile.xml @@ -1,13 +1,12 @@ - + 0 - hello_world_controllers_participant - UDPv4 + hello_world_participant - + TRANSIENT_LOCAL @@ -29,7 +28,7 @@ - + TRANSIENT_LOCAL diff --git a/test/examples/hello_world.compose.yml b/test/examples/hello_world.compose.yml index a52b74727e1..587db20ad03 100644 --- a/test/examples/hello_world.compose.yml +++ b/test/examples/hello_world.compose.yml @@ -2,28 +2,28 @@ version: "3" services: - publisher: + waitset-subscriber: image: @DOCKER_IMAGE_NAME@ volumes: - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ - - @PROJECT_BINARY_DIR@/examples/cpp/hello_world/HelloWorld_controller_profile.xml:@PROJECT_BINARY_DIR@/examples/cpp/hello_world/HelloWorld_controller_profile.xml 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/hello_world - FASTDDS_DEFAULT_PROFILES_FILE: @PROJECT_BINARY_DIR@/examples/cpp/hello_world/HelloWorld_controller_profile.xml - command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ publisher & $${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber --waitset" + EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/hello_world@FILE_EXTENSION@ + FASTDDS_DEFAULT_PROFILES_FILE: @PROJECT_BINARY_DIR@/examples/cpp/hello_world/hello_world_profile.xml + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber --waitset" - subscriber: + subscriber-publisher: image: @DOCKER_IMAGE_NAME@ volumes: - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ - - @PROJECT_BINARY_DIR@/examples/cpp/hello_world/HelloWorld_controller_profile.xml:@PROJECT_BINARY_DIR@/examples/cpp/hello_world/HelloWorld_controller_profile.xml 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/hello_world@FILE_EXTENSION@ - FASTDDS_DEFAULT_PROFILES_FILE: @PROJECT_BINARY_DIR@/examples/cpp/hello_world/HelloWorld_controller_profile.xml - command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber" + EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/hello_world + FASTDDS_DEFAULT_PROFILES_FILE: @PROJECT_BINARY_DIR@/examples/cpp/hello_world/hello_world_profile.xml + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber & $${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ publisher" + depends_on: + - waitset-subscriber From e0caef8d00be8807fbcb6f4d11994408a57128f3 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 12 Mar 2024 17:13:20 +0100 Subject: [PATCH 09/42] Refs #20543: Add explicit status mask arguments Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/Publisher.cpp | 6 +++--- examples/cpp/hello_world/Subscriber.cpp | 6 +++--- examples/cpp/hello_world/SubscriberWaitset.cpp | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/cpp/hello_world/Publisher.cpp b/examples/cpp/hello_world/Publisher.cpp index 308fc7c4610..bee64531215 100644 --- a/examples/cpp/hello_world/Publisher.cpp +++ b/examples/cpp/hello_world/Publisher.cpp @@ -47,7 +47,7 @@ HelloWorldPublisher::HelloWorldPublisher() // Create the participant auto factory = DomainParticipantFactory::get_instance(); - participant_ = factory->create_participant_with_default_profile(); + participant_ = factory->create_participant_with_default_profile(nullptr, StatusMask::none()); if (participant_ == nullptr) { throw std::runtime_error("Participant initialization failed"); @@ -59,7 +59,7 @@ HelloWorldPublisher::HelloWorldPublisher() // Create the publisher PublisherQos pub_qos = PUBLISHER_QOS_DEFAULT; participant_->get_default_publisher_qos(pub_qos); - publisher_ = participant_->create_publisher(pub_qos); + publisher_ = participant_->create_publisher(pub_qos, nullptr, StatusMask::none()); if (publisher_ == nullptr) { throw std::runtime_error("Publisher initialization failed"); @@ -77,7 +77,7 @@ HelloWorldPublisher::HelloWorldPublisher() // Create the data writer DataWriterQos writer_qos = DATAWRITER_QOS_DEFAULT; publisher_->get_default_datawriter_qos(writer_qos); - writer_ = publisher_->create_datawriter(topic_, writer_qos, this); + writer_ = publisher_->create_datawriter(topic_, writer_qos, this, StatusMask::all()); if (writer_ == nullptr) { throw std::runtime_error("DataWriter initialization failed"); diff --git a/examples/cpp/hello_world/Subscriber.cpp b/examples/cpp/hello_world/Subscriber.cpp index 748dfb354f5..28d002e265e 100644 --- a/examples/cpp/hello_world/Subscriber.cpp +++ b/examples/cpp/hello_world/Subscriber.cpp @@ -46,7 +46,7 @@ HelloWorldSubscriber::HelloWorldSubscriber() { // Create the participant auto factory = DomainParticipantFactory::get_instance(); - participant_ = factory->create_participant_with_default_profile(); + participant_ = factory->create_participant_with_default_profile(nullptr, StatusMask::none()); if (participant_ == nullptr) { throw std::runtime_error("Participant initialization failed"); @@ -58,7 +58,7 @@ HelloWorldSubscriber::HelloWorldSubscriber() // Create the subscriber SubscriberQos sub_qos = SUBSCRIBER_QOS_DEFAULT; participant_->get_default_subscriber_qos(sub_qos); - subscriber_ = participant_->create_subscriber(sub_qos); + subscriber_ = participant_->create_subscriber(sub_qos, nullptr, StatusMask::none()); if (subscriber_ == nullptr) { throw std::runtime_error("Subscriber initialization failed"); @@ -76,7 +76,7 @@ HelloWorldSubscriber::HelloWorldSubscriber() // Create the reader DataReaderQos reader_qos = DATAREADER_QOS_DEFAULT; subscriber_->get_default_datareader_qos(reader_qos); - reader_ = subscriber_->create_datareader(topic_, reader_qos, this); + reader_ = subscriber_->create_datareader(topic_, reader_qos, this, StatusMask::all()); if (reader_ == nullptr) { throw std::runtime_error("DataReader initialization failed"); diff --git a/examples/cpp/hello_world/SubscriberWaitset.cpp b/examples/cpp/hello_world/SubscriberWaitset.cpp index 9dbc38b9e53..2239a2d8c78 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.cpp +++ b/examples/cpp/hello_world/SubscriberWaitset.cpp @@ -48,7 +48,7 @@ HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset() { // Create the participant auto factory = DomainParticipantFactory::get_instance(); - participant_ = factory->create_participant_with_default_profile(); + participant_ = factory->create_participant_with_default_profile(nullptr, StatusMask::none()); if (participant_ == nullptr) { throw std::runtime_error("Participant initialization failed"); @@ -60,7 +60,7 @@ HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset() // Create the subscriber SubscriberQos sub_qos = SUBSCRIBER_QOS_DEFAULT; participant_->get_default_subscriber_qos(sub_qos); - subscriber_ = participant_->create_subscriber(sub_qos); + subscriber_ = participant_->create_subscriber(sub_qos, nullptr, StatusMask::none()); if (subscriber_ == nullptr) { throw std::runtime_error("Subscriber initialization failed"); @@ -78,7 +78,7 @@ HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset() // Create the reader DataReaderQos reader_qos = DATAREADER_QOS_DEFAULT; subscriber_->get_default_datareader_qos(reader_qos); - reader_ = subscriber_->create_datareader(topic_, reader_qos); + reader_ = subscriber_->create_datareader(topic_, reader_qos, nullptr, StatusMask::all()); if (reader_ == nullptr) { throw std::runtime_error("DataReader initialization failed"); From e561a720eb5c68ae7f3f39dc9d8cb73c42dad765 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 13 Mar 2024 08:30:45 +0100 Subject: [PATCH 10/42] Refs #20543: Include sample CLI argument Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/HelloWorld_main.cpp | 10 +- examples/cpp/hello_world/Publisher.cpp | 31 +++- examples/cpp/hello_world/Publisher.hpp | 8 +- examples/cpp/hello_world/Subscriber.cpp | 23 ++- examples/cpp/hello_world/Subscriber.hpp | 8 +- .../cpp/hello_world/SubscriberWaitset.cpp | 24 ++- .../cpp/hello_world/SubscriberWaitset.hpp | 8 +- examples/cpp/hello_world/cli_options.hpp | 139 +++++++++++------- test/examples/hello_world.compose.yml | 4 +- test/examples/test_examples.py | 49 +++--- 10 files changed, 206 insertions(+), 98 deletions(-) diff --git a/examples/cpp/hello_world/HelloWorld_main.cpp b/examples/cpp/hello_world/HelloWorld_main.cpp index 77870d6539d..4be8ad2f496 100644 --- a/examples/cpp/hello_world/HelloWorld_main.cpp +++ b/examples/cpp/hello_world/HelloWorld_main.cpp @@ -34,13 +34,13 @@ int main( char** argv) { auto ret = EXIT_SUCCESS; - hello_world_config config = parse_cli_options(argc, argv); + CLIParser::hello_world_config config = CLIParser::parse_cli_options(argc, argv); if (config.entity == "publisher") { try { - HelloWorldPublisher hello_world_publisher; + HelloWorldPublisher hello_world_publisher(config); hello_world_publisher.run(); } catch (const std::runtime_error& e) @@ -55,7 +55,7 @@ int main( { try { - HelloWorldSubscriberWaitset hello_world_subscriber_waitset; + HelloWorldSubscriberWaitset hello_world_subscriber_waitset(config); hello_world_subscriber_waitset.run(); } catch (const std::runtime_error& e) @@ -68,7 +68,7 @@ int main( { try { - HelloWorldSubscriber hello_world_subscriber; + HelloWorldSubscriber hello_world_subscriber(config); hello_world_subscriber.run(); } catch (const std::runtime_error& e) @@ -82,7 +82,7 @@ int main( else { EPROSIMA_LOG_ERROR(CLI_PARSE, "unknown entity " + config.entity); - print_help(EXIT_FAILURE); + CLIParser::print_help(EXIT_FAILURE); } Log::Reset(); diff --git a/examples/cpp/hello_world/Publisher.cpp b/examples/cpp/hello_world/Publisher.cpp index bee64531215..cdfcdd5ae35 100644 --- a/examples/cpp/hello_world/Publisher.cpp +++ b/examples/cpp/hello_world/Publisher.cpp @@ -33,8 +33,10 @@ using namespace eprosima::fastdds::dds; std::atomic HelloWorldPublisher::stop_(false); +std::condition_variable HelloWorldPublisher::matched_cv_; -HelloWorldPublisher::HelloWorldPublisher() +HelloWorldPublisher::HelloWorldPublisher( + const CLIParser::hello_world_config& config) : participant_(nullptr) , publisher_(nullptr) , topic_(nullptr) @@ -44,6 +46,10 @@ HelloWorldPublisher::HelloWorldPublisher() // Set up the data type with initial values hello_.index(0); hello_.message("Hello world"); + matched_ = 0; + + // Get CLI options + samples_ = config.samples; // Create the participant auto factory = DomainParticipantFactory::get_instance(); @@ -119,7 +125,7 @@ void HelloWorldPublisher::run() { std::thread pub_thread([&] { - while (!is_stopped()) + while (!is_stopped() && (samples_ == 0 || hello_.index() < samples_)) { if (publish()) { @@ -129,7 +135,15 @@ void HelloWorldPublisher::run() std::this_thread::sleep_for(std::chrono::milliseconds(period_)); } }); - std::cout << "Publisher running. Please press Ctrl+C to stop the Publisher at any time." << std::endl; + 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 << "\nSIGINT received, stopping Publisher execution." << std::endl; @@ -162,10 +176,14 @@ bool HelloWorldPublisher::publish() matched_cv_.wait(matched_lock, [&]() { // at least one has been discovered - return matched_ > 0; + return matched_ > 0 || is_stopped(); }); - hello_.index(hello_.index() + 1); - return writer_->write(&hello_); + if (!is_stopped()) + { + hello_.index(hello_.index() + 1); + return writer_->write(&hello_); + } + return false; } bool HelloWorldPublisher::is_stopped() @@ -176,4 +194,5 @@ bool HelloWorldPublisher::is_stopped() void HelloWorldPublisher::stop() { stop_.store(true); + matched_cv_.notify_one(); } diff --git a/examples/cpp/hello_world/Publisher.hpp b/examples/cpp/hello_world/Publisher.hpp index 529eee83e9d..c3c252abb6e 100644 --- a/examples/cpp/hello_world/Publisher.hpp +++ b/examples/cpp/hello_world/Publisher.hpp @@ -26,6 +26,7 @@ #include #include +#include "cli_options.hpp" #include "HelloWorldPubSubTypes.h" using namespace eprosima::fastdds::dds; @@ -34,7 +35,8 @@ class HelloWorldPublisher : public DataWriterListener { public: - HelloWorldPublisher(); + HelloWorldPublisher( + const CLIParser::hello_world_config& config); ~HelloWorldPublisher() override; @@ -73,9 +75,11 @@ class HelloWorldPublisher : public DataWriterListener int16_t matched_; + uint16_t samples_; + std::mutex mutex_; - std::condition_variable matched_cv_; + static std::condition_variable matched_cv_; const uint8_t period_ = 100; // in ms }; diff --git a/examples/cpp/hello_world/Subscriber.cpp b/examples/cpp/hello_world/Subscriber.cpp index 28d002e265e..25ff2359097 100644 --- a/examples/cpp/hello_world/Subscriber.cpp +++ b/examples/cpp/hello_world/Subscriber.cpp @@ -37,13 +37,18 @@ using namespace eprosima::fastdds::dds; std::atomic HelloWorldSubscriber::stop_(false); std::condition_variable HelloWorldSubscriber::terminate_cv_; -HelloWorldSubscriber::HelloWorldSubscriber() +HelloWorldSubscriber::HelloWorldSubscriber( + const CLIParser::hello_world_config& config) : participant_(nullptr) , subscriber_(nullptr) , topic_(nullptr) , reader_(nullptr) , type_(new HelloWorldPubSubType()) { + // Get CLI options + samples_ = config.samples; + received_samples_ = 0; + // Create the participant auto factory = DomainParticipantFactory::get_instance(); participant_ = factory->create_participant_with_default_profile(nullptr, StatusMask::none()); @@ -119,16 +124,30 @@ void HelloWorldSubscriber::on_data_available( { if (info.instance_state == ALIVE_INSTANCE_STATE && info.valid_data) { + received_samples_++; // Print Hello world message data std::cout << "Message: '" << hello_.message() << "' with index: '" << hello_.index() << "' RECEIVED" << std::endl; + if (samples_ > 0 && (received_samples_ >= samples_)) + { + stop(); + } } } } void HelloWorldSubscriber::run() { - std::cout << "Subscriber running. Please press Ctrl+C to stop the Subscriber at any time." << std::endl; + if (samples_ == 0) + { + std::cout << "Subscriber running. Please press Ctrl+C to stop the Subscriber at any time." << std::endl; + } + else + { + std::cout << "Subscriber running until " << samples_ << + " samples have been received. Please press Ctrl+C to stop the Subscriber at any time." << std::endl; + } + signal(SIGINT, [](int /*signum*/) { std::cout << "\nSIGINT received, stopping Subscriber execution." << std::endl; diff --git a/examples/cpp/hello_world/Subscriber.hpp b/examples/cpp/hello_world/Subscriber.hpp index 2f1e0e4c565..fa3ab6a30a4 100644 --- a/examples/cpp/hello_world/Subscriber.hpp +++ b/examples/cpp/hello_world/Subscriber.hpp @@ -26,6 +26,7 @@ #include #include +#include "cli_options.hpp" #include "HelloWorldPubSubTypes.h" using namespace eprosima::fastdds::dds; @@ -34,7 +35,8 @@ class HelloWorldSubscriber : public DataReaderListener { public: - HelloWorldSubscriber(); + HelloWorldSubscriber( + const CLIParser::hello_world_config& config); virtual ~HelloWorldSubscriber(); @@ -70,6 +72,10 @@ class HelloWorldSubscriber : public DataReaderListener TypeSupport type_; + uint16_t samples_; + + uint16_t received_samples_; + static std::atomic stop_; mutable std::mutex terminate_cv_mtx_; diff --git a/examples/cpp/hello_world/SubscriberWaitset.cpp b/examples/cpp/hello_world/SubscriberWaitset.cpp index 2239a2d8c78..c588edbacb9 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.cpp +++ b/examples/cpp/hello_world/SubscriberWaitset.cpp @@ -39,13 +39,18 @@ using namespace eprosima::fastdds::dds; std::atomic HelloWorldSubscriberWaitset::stop_(false); GuardCondition HelloWorldSubscriberWaitset::terminate_condition_; -HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset() +HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset( + const CLIParser::hello_world_config& config) : participant_(nullptr) , subscriber_(nullptr) , topic_(nullptr) , reader_(nullptr) , type_(new HelloWorldPubSubType()) { + // Get CLI options + samples_ = config.samples; + received_samples_ = 0; + // Create the participant auto factory = DomainParticipantFactory::get_instance(); participant_ = factory->create_participant_with_default_profile(nullptr, StatusMask::none()); @@ -145,9 +150,14 @@ void HelloWorldSubscriberWaitset::run() { if (info.instance_state == ALIVE_INSTANCE_STATE && info.valid_data) { + received_samples_++; // Print Hello world message data std::cout << "Message: '" << hello_.message() << "' with index: '" << hello_.index() << "' RECEIVED" << std::endl; + if (samples_ > 0 && (received_samples_ >= samples_)) + { + stop(); + } } } } @@ -156,8 +166,16 @@ void HelloWorldSubscriberWaitset::run() } }); - std::cout << "Waitset Subscriber running. Please press Ctrl+C to stop the Waitset Subscriber at any time." - << std::endl; + if (samples_ == 0) + { + std::cout << "Waitset Subscriber running. Please press Ctrl+C to stop the Waitset Subscriber at any time." + << std::endl; + } + else + { + std::cout << "Waitset Subscriber running until " << samples_ << + " samples have been received. Please press Ctrl+C to stop the Waitset Subscriber at any time." << std::endl; + } signal(SIGINT, [](int /*signum*/) { std::cout << "\nSIGINT received, stopping Waitset Subscriber execution." << std::endl; diff --git a/examples/cpp/hello_world/SubscriberWaitset.hpp b/examples/cpp/hello_world/SubscriberWaitset.hpp index 14d064d0ade..60959f618de 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.hpp +++ b/examples/cpp/hello_world/SubscriberWaitset.hpp @@ -28,6 +28,7 @@ #include #include +#include "cli_options.hpp" #include "HelloWorldPubSubTypes.h" using namespace eprosima::fastdds::dds; @@ -36,7 +37,8 @@ class HelloWorldSubscriberWaitset { public: - HelloWorldSubscriberWaitset(); + HelloWorldSubscriberWaitset( + const CLIParser::hello_world_config& config); virtual ~HelloWorldSubscriberWaitset(); @@ -65,6 +67,10 @@ class HelloWorldSubscriberWaitset WaitSet wait_set_; + uint16_t samples_; + + uint16_t received_samples_; + static std::atomic stop_; static GuardCondition terminate_condition_; diff --git a/examples/cpp/hello_world/cli_options.hpp b/examples/cpp/hello_world/cli_options.hpp index 5236ed3ffad..1c70f397589 100644 --- a/examples/cpp/hello_world/cli_options.hpp +++ b/examples/cpp/hello_world/cli_options.hpp @@ -15,76 +15,111 @@ #include #include -struct subscriber_config -{ - bool use_waitset; -}; +#ifndef _FASTDDS_HELLO_WORLD_CLI_PARSER_HPP_ +#define _FASTDDS_HELLO_WORLD_CLI_PARSER_HPP_ -struct hello_world_config +class CLIParser { - std::string entity; - subscriber_config sub_config; -}; +public: + CLIParser() = delete; -void print_help( - uint8_t return_code) -{ - std::cout << "Usage: hello_world [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 << "Common options:" << std::endl; - std::cout << " -h, --help Print this help message" << std::endl; - std::cout << "Subscriber options:" << std::endl; - std::cout << " -w, --waitset Use waitset read condition" << std::endl; - std::exit(return_code); -} + struct subscriber_config + { + bool use_waitset; + }; -hello_world_config parse_cli_options ( - int argc, - char* argv[]) -{ - hello_world_config config; - config.entity = ""; - config.sub_config.use_waitset = false; + struct hello_world_config + { + std::string entity; + uint16_t samples; + subscriber_config sub_config; + }; - for (int i = 1; i < argc; ++i) + static void print_help( + uint8_t return_code) { - std::string arg = argv[i]; - if (arg == "-h" || arg == "--help") - { - print_help(EXIT_SUCCESS); - } - else if (arg == "publisher" || arg == "subscriber") - { - config.entity = arg; - } - else if (arg == "-w" || arg == "--waitset") + std::cout << "Usage: hello_world [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 << "Common options:" << std::endl; + std::cout << " -h, --help Print this help message" << std::endl; + std::cout << " -s, --samples Amount of samples to be sent or" << std::endl; + std::cout << " received (default: 0 [unlimited])" << std::endl; + std::cout << "Subscriber options:" << std::endl; + std::cout << " -w, --waitset Use waitset read condition" << std::endl; + std::exit(return_code); + } + + static hello_world_config parse_cli_options( + int argc, + char* argv[]) + { + hello_world_config config; + config.entity = ""; + config.samples = 0; + config.sub_config.use_waitset = false; + + for (int i = 1; i < argc; ++i) { - if (config.entity == "subscriber") + std::string arg = argv[i]; + if (arg == "-h" || arg == "--help") + { + print_help(EXIT_SUCCESS); + } + else if (arg == "publisher" || arg == "subscriber") + { + config.entity = arg; + } + else if (arg == "-s" || arg == "--samples") { - config.sub_config.use_waitset = true; + if (i + 1 < argc) + { + try + { + config.samples = std::stoi(argv[++i]); + } + catch (const std::invalid_argument& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSE, "invalid sample argument for " + arg); + print_help(EXIT_FAILURE); + } + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSE, "missing argument for " + arg); + print_help(EXIT_FAILURE); + } + } + else if (arg == "-w" || arg == "--waitset") + { + if (config.entity == "subscriber") + { + config.sub_config.use_waitset = true; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSE, "waitset can only be used with the subscriber entity"); + print_help(EXIT_FAILURE); + } } else { - EPROSIMA_LOG_ERROR(CLI_PARSE, "waitset can only be used with the subscriber entity"); + EPROSIMA_LOG_ERROR(CLI_PARSE, "unknown option " + arg); print_help(EXIT_FAILURE); } } - else + + if (config.entity == "") { - EPROSIMA_LOG_ERROR(CLI_PARSE, "unknown option " + arg); + EPROSIMA_LOG_ERROR(CLI_PARSE, "entity not specified"); print_help(EXIT_FAILURE); } - } - if (config.entity == "") - { - EPROSIMA_LOG_ERROR(CLI_PARSE, "entity not specified"); - print_help(EXIT_FAILURE); + return config; } +}; - return config; -} +#endif // _FASTDDS_HELLO_WORLD_CLI_PARSER_HPP_ diff --git a/test/examples/hello_world.compose.yml b/test/examples/hello_world.compose.yml index 587db20ad03..e2ad7390b7d 100644 --- a/test/examples/hello_world.compose.yml +++ b/test/examples/hello_world.compose.yml @@ -12,7 +12,7 @@ services: LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@ EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/hello_world@FILE_EXTENSION@ FASTDDS_DEFAULT_PROFILES_FILE: @PROJECT_BINARY_DIR@/examples/cpp/hello_world/hello_world_profile.xml - command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber --waitset" + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber --waitset --samples 10" subscriber-publisher: image: @DOCKER_IMAGE_NAME@ @@ -24,6 +24,6 @@ services: LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@ EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/hello_world FASTDDS_DEFAULT_PROFILES_FILE: @PROJECT_BINARY_DIR@/examples/cpp/hello_world/hello_world_profile.xml - command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber & $${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ publisher" + command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber --samples 10 & $${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ publisher --samples 10" depends_on: - waitset-subscriber diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index d6fc93974e9..a1e89044349 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -1,8 +1,5 @@ """.""" -import os -import signal import subprocess -from subprocess import Popen, PIPE, TimeoutExpired def test_basic_configuration(): """.""" @@ -44,30 +41,34 @@ def test_hello_world(): """.""" ret = False out = '' - with Popen('@DOCKER_EXECUTABLE@ compose -f hello_world.compose.yml up', - shell=True, - stdout=PIPE, - preexec_fn=os.setsid) as process: - try: - out = process.communicate(timeout=3)[0].decode().split('\n') - except TimeoutExpired: - os.killpg(process.pid, signal.SIGINT) - out = process.communicate()[0].decode().split('\n') - sent = 0 - received = 0 - for line in out: - if 'SENT' in line: - sent += 1 - continue + try: + out = subprocess.check_output( + '@DOCKER_EXECUTABLE@ compose -f hello_world.compose.yml up', + stderr=subprocess.STDOUT, + shell=True, + timeout=30 + ).decode().split('\n') + + sent = 0 + received = 0 + for line in out: + if 'SENT' in line: + sent += 1 + continue + + if 'RECEIVED' in line: + received += 1 + continue - if 'RECEIVED' in line: - received += 1 - continue + if sent != 0 and received != 0 and sent * 2 == received: + ret = True + else: + raise subprocess.CalledProcessError(1, '') - if sent != 0 and received != 0 and sent * 2 == received: - ret = True - else: + except subprocess.CalledProcessError: for l in out: print(l) + except subprocess.TimeoutExpired: + print('TIMEOUT') assert(ret) From 7fee335c96a574d3ee274cd1f5b0d7a83ac5552d Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 13 Mar 2024 10:32:45 +0100 Subject: [PATCH 11/42] Refs #20543: Simplify publish return Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/Publisher.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/cpp/hello_world/Publisher.cpp b/examples/cpp/hello_world/Publisher.cpp index cdfcdd5ae35..a765420dfc1 100644 --- a/examples/cpp/hello_world/Publisher.cpp +++ b/examples/cpp/hello_world/Publisher.cpp @@ -171,6 +171,7 @@ void HelloWorldPublisher::run() bool HelloWorldPublisher::publish() { + bool ret = false; // Wait for the data endpoints discovery std::unique_lock matched_lock(mutex_); matched_cv_.wait(matched_lock, [&]() @@ -181,9 +182,9 @@ bool HelloWorldPublisher::publish() if (!is_stopped()) { hello_.index(hello_.index() + 1); - return writer_->write(&hello_); + ret = writer_->write(&hello_); } - return false; + return ret; } bool HelloWorldPublisher::is_stopped() From aa1f902bd24fdb9f07b2dcf4147aa537615bae75 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 13 Mar 2024 10:35:03 +0100 Subject: [PATCH 12/42] Refs #20543: Please uncrustify Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/cli_options.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/cpp/hello_world/cli_options.hpp b/examples/cpp/hello_world/cli_options.hpp index 1c70f397589..52ec469fd1a 100644 --- a/examples/cpp/hello_world/cli_options.hpp +++ b/examples/cpp/hello_world/cli_options.hpp @@ -120,6 +120,7 @@ class CLIParser return config; } + }; #endif // _FASTDDS_HELLO_WORLD_CLI_PARSER_HPP_ From 0e602dc4499a4f5f95c06e7eddec40ae3e588362 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 13 Mar 2024 10:47:37 +0100 Subject: [PATCH 13/42] Refs #20543: Add missing SHM build def and remove duplicated install Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/cpp/hello_world/CMakeLists.txt b/examples/cpp/hello_world/CMakeLists.txt index b3ff2a83e72..15bdfdc6eec 100644 --- a/examples/cpp/hello_world/CMakeLists.txt +++ b/examples/cpp/hello_world/CMakeLists.txt @@ -42,14 +42,12 @@ add_executable(hello_world ${HELLO_WORLD_SOURCES_CXX} ${HELLO_WORLD_SOURCES_CPP} target_compile_definitions(hello_world PRIVATE $<$>,$>:__DEBUG> $<$:__INTERNALDEBUG> # Internal debug activated. + $<$:SHM_TRANSPORT_BUILTIN> # Enable SHM as built-in transport ) target_link_libraries(hello_world fastdds fastcdr) install(TARGETS hello_world RUNTIME DESTINATION examples/cpp/hello_world/${BIN_INSTALL_DIR}) -install(TARGETS hello_world - RUNTIME DESTINATION examples/cpp/hello_world/${BIN_INSTALL_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 From 3626f11278c7faefd49fd3d278fe29de6252afeb Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 13 Mar 2024 11:08:33 +0100 Subject: [PATCH 14/42] Refs #20543: Set sample as pub / sub option Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/HelloWorld_main.cpp | 6 ++--- examples/cpp/hello_world/Publisher.cpp | 2 +- examples/cpp/hello_world/Publisher.hpp | 2 +- examples/cpp/hello_world/Subscriber.cpp | 2 +- examples/cpp/hello_world/Subscriber.hpp | 2 +- .../cpp/hello_world/SubscriberWaitset.cpp | 2 +- .../cpp/hello_world/SubscriberWaitset.hpp | 2 +- examples/cpp/hello_world/cli_options.hpp | 27 ++++++++++++++++--- 8 files changed, 33 insertions(+), 12 deletions(-) diff --git a/examples/cpp/hello_world/HelloWorld_main.cpp b/examples/cpp/hello_world/HelloWorld_main.cpp index 4be8ad2f496..e58dbcceef8 100644 --- a/examples/cpp/hello_world/HelloWorld_main.cpp +++ b/examples/cpp/hello_world/HelloWorld_main.cpp @@ -40,7 +40,7 @@ int main( { try { - HelloWorldPublisher hello_world_publisher(config); + HelloWorldPublisher hello_world_publisher(config.pub_config); hello_world_publisher.run(); } catch (const std::runtime_error& e) @@ -55,7 +55,7 @@ int main( { try { - HelloWorldSubscriberWaitset hello_world_subscriber_waitset(config); + HelloWorldSubscriberWaitset hello_world_subscriber_waitset(config.sub_config); hello_world_subscriber_waitset.run(); } catch (const std::runtime_error& e) @@ -68,7 +68,7 @@ int main( { try { - HelloWorldSubscriber hello_world_subscriber(config); + HelloWorldSubscriber hello_world_subscriber(config.sub_config); hello_world_subscriber.run(); } catch (const std::runtime_error& e) diff --git a/examples/cpp/hello_world/Publisher.cpp b/examples/cpp/hello_world/Publisher.cpp index a765420dfc1..28ccccb29c6 100644 --- a/examples/cpp/hello_world/Publisher.cpp +++ b/examples/cpp/hello_world/Publisher.cpp @@ -36,7 +36,7 @@ std::atomic HelloWorldPublisher::stop_(false); std::condition_variable HelloWorldPublisher::matched_cv_; HelloWorldPublisher::HelloWorldPublisher( - const CLIParser::hello_world_config& config) + const CLIParser::publisher_config& config) : participant_(nullptr) , publisher_(nullptr) , topic_(nullptr) diff --git a/examples/cpp/hello_world/Publisher.hpp b/examples/cpp/hello_world/Publisher.hpp index c3c252abb6e..58a2abdc8a9 100644 --- a/examples/cpp/hello_world/Publisher.hpp +++ b/examples/cpp/hello_world/Publisher.hpp @@ -36,7 +36,7 @@ class HelloWorldPublisher : public DataWriterListener public: HelloWorldPublisher( - const CLIParser::hello_world_config& config); + const CLIParser::publisher_config& config); ~HelloWorldPublisher() override; diff --git a/examples/cpp/hello_world/Subscriber.cpp b/examples/cpp/hello_world/Subscriber.cpp index 25ff2359097..d53eeb512ef 100644 --- a/examples/cpp/hello_world/Subscriber.cpp +++ b/examples/cpp/hello_world/Subscriber.cpp @@ -38,7 +38,7 @@ std::atomic HelloWorldSubscriber::stop_(false); std::condition_variable HelloWorldSubscriber::terminate_cv_; HelloWorldSubscriber::HelloWorldSubscriber( - const CLIParser::hello_world_config& config) + const CLIParser::subscriber_config& config) : participant_(nullptr) , subscriber_(nullptr) , topic_(nullptr) diff --git a/examples/cpp/hello_world/Subscriber.hpp b/examples/cpp/hello_world/Subscriber.hpp index fa3ab6a30a4..33e9337aa6c 100644 --- a/examples/cpp/hello_world/Subscriber.hpp +++ b/examples/cpp/hello_world/Subscriber.hpp @@ -36,7 +36,7 @@ class HelloWorldSubscriber : public DataReaderListener public: HelloWorldSubscriber( - const CLIParser::hello_world_config& config); + const CLIParser::subscriber_config& config); virtual ~HelloWorldSubscriber(); diff --git a/examples/cpp/hello_world/SubscriberWaitset.cpp b/examples/cpp/hello_world/SubscriberWaitset.cpp index c588edbacb9..4c3bc6cf42e 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.cpp +++ b/examples/cpp/hello_world/SubscriberWaitset.cpp @@ -40,7 +40,7 @@ std::atomic HelloWorldSubscriberWaitset::stop_(false); GuardCondition HelloWorldSubscriberWaitset::terminate_condition_; HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset( - const CLIParser::hello_world_config& config) + const CLIParser::subscriber_config& config) : participant_(nullptr) , subscriber_(nullptr) , topic_(nullptr) diff --git a/examples/cpp/hello_world/SubscriberWaitset.hpp b/examples/cpp/hello_world/SubscriberWaitset.hpp index 60959f618de..ea08b0d67ed 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.hpp +++ b/examples/cpp/hello_world/SubscriberWaitset.hpp @@ -38,7 +38,7 @@ class HelloWorldSubscriberWaitset public: HelloWorldSubscriberWaitset( - const CLIParser::hello_world_config& config); + const CLIParser::subscriber_config& config); virtual ~HelloWorldSubscriberWaitset(); diff --git a/examples/cpp/hello_world/cli_options.hpp b/examples/cpp/hello_world/cli_options.hpp index 52ec469fd1a..8ef530c87c0 100644 --- a/examples/cpp/hello_world/cli_options.hpp +++ b/examples/cpp/hello_world/cli_options.hpp @@ -24,15 +24,21 @@ class CLIParser CLIParser() = delete; + struct publisher_config + { + uint16_t samples; + }; + struct subscriber_config { bool use_waitset; + uint16_t samples; }; struct hello_world_config { std::string entity; - uint16_t samples; + publisher_config pub_config; subscriber_config sub_config; }; @@ -59,7 +65,8 @@ class CLIParser { hello_world_config config; config.entity = ""; - config.samples = 0; + config.pub_config.samples = 0; + config.sub_config.samples = 0; config.sub_config.use_waitset = false; for (int i = 1; i < argc; ++i) @@ -79,7 +86,21 @@ class CLIParser { try { - config.samples = std::stoi(argv[++i]); + uint16_t samples = std::stoi(argv[++i]); + if (config.entity == "publisher") + { + config.pub_config.samples = samples; + } + else if (config.entity == "subscriber") + { + config.sub_config.samples = samples; + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSE, "entity not specified for --sample argument"); + print_help(EXIT_FAILURE); + + } } catch (const std::invalid_argument& e) { From 15ac5f8484f2515bfe273bb8c99033e39e54b3e4 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 13 Mar 2024 11:16:48 +0100 Subject: [PATCH 15/42] Refs #20543: Rename cli_options.hpp to CLIParser.hpp Signed-off-by: JesusPoderoso --- .../{cli_options.hpp => CLIParser.hpp} | 16 ++++++++++------ examples/cpp/hello_world/HelloWorld_main.cpp | 4 ++-- examples/cpp/hello_world/Publisher.hpp | 2 +- examples/cpp/hello_world/Subscriber.hpp | 2 +- examples/cpp/hello_world/SubscriberWaitset.hpp | 2 +- 5 files changed, 15 insertions(+), 11 deletions(-) rename examples/cpp/hello_world/{cli_options.hpp => CLIParser.hpp} (88%) diff --git a/examples/cpp/hello_world/cli_options.hpp b/examples/cpp/hello_world/CLIParser.hpp similarity index 88% rename from examples/cpp/hello_world/cli_options.hpp rename to examples/cpp/hello_world/CLIParser.hpp index 8ef530c87c0..f6d43df690f 100644 --- a/examples/cpp/hello_world/cli_options.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -15,9 +15,13 @@ #include #include +#include + #ifndef _FASTDDS_HELLO_WORLD_CLI_PARSER_HPP_ #define _FASTDDS_HELLO_WORLD_CLI_PARSER_HPP_ +using eprosima::fastdds::dds::Log; + class CLIParser { public: @@ -97,20 +101,20 @@ class CLIParser } else { - EPROSIMA_LOG_ERROR(CLI_PARSE, "entity not specified for --sample argument"); + EPROSIMA_LOG_ERROR(CLI_PARSER, "entity not specified for --sample argument"); print_help(EXIT_FAILURE); } } catch (const std::invalid_argument& e) { - EPROSIMA_LOG_ERROR(CLI_PARSE, "invalid sample argument for " + arg); + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid sample argument for " + arg); print_help(EXIT_FAILURE); } } else { - EPROSIMA_LOG_ERROR(CLI_PARSE, "missing argument for " + arg); + EPROSIMA_LOG_ERROR(CLI_PARSER, "missing argument for " + arg); print_help(EXIT_FAILURE); } } @@ -122,20 +126,20 @@ class CLIParser } else { - EPROSIMA_LOG_ERROR(CLI_PARSE, "waitset can only be used with the subscriber entity"); + EPROSIMA_LOG_ERROR(CLI_PARSER, "waitset can only be used with the subscriber entity"); print_help(EXIT_FAILURE); } } else { - EPROSIMA_LOG_ERROR(CLI_PARSE, "unknown option " + arg); + EPROSIMA_LOG_ERROR(CLI_PARSER, "unknown option " + arg); print_help(EXIT_FAILURE); } } if (config.entity == "") { - EPROSIMA_LOG_ERROR(CLI_PARSE, "entity not specified"); + EPROSIMA_LOG_ERROR(CLI_PARSER, "entity not specified"); print_help(EXIT_FAILURE); } diff --git a/examples/cpp/hello_world/HelloWorld_main.cpp b/examples/cpp/hello_world/HelloWorld_main.cpp index e58dbcceef8..706b543758a 100644 --- a/examples/cpp/hello_world/HelloWorld_main.cpp +++ b/examples/cpp/hello_world/HelloWorld_main.cpp @@ -22,7 +22,7 @@ #include #include -#include "cli_options.hpp" +#include "CLIParser.hpp" #include "Publisher.hpp" #include "Subscriber.hpp" #include "SubscriberWaitset.hpp" @@ -81,7 +81,7 @@ int main( // example should never reach this point else { - EPROSIMA_LOG_ERROR(CLI_PARSE, "unknown entity " + config.entity); + EPROSIMA_LOG_ERROR(CLI_PARSER, "unknown entity " + config.entity); CLIParser::print_help(EXIT_FAILURE); } diff --git a/examples/cpp/hello_world/Publisher.hpp b/examples/cpp/hello_world/Publisher.hpp index 58a2abdc8a9..5489662cea2 100644 --- a/examples/cpp/hello_world/Publisher.hpp +++ b/examples/cpp/hello_world/Publisher.hpp @@ -26,7 +26,7 @@ #include #include -#include "cli_options.hpp" +#include "CLIParser.hpp" #include "HelloWorldPubSubTypes.h" using namespace eprosima::fastdds::dds; diff --git a/examples/cpp/hello_world/Subscriber.hpp b/examples/cpp/hello_world/Subscriber.hpp index 33e9337aa6c..b5cb36b38f7 100644 --- a/examples/cpp/hello_world/Subscriber.hpp +++ b/examples/cpp/hello_world/Subscriber.hpp @@ -26,7 +26,7 @@ #include #include -#include "cli_options.hpp" +#include "CLIParser.hpp" #include "HelloWorldPubSubTypes.h" using namespace eprosima::fastdds::dds; diff --git a/examples/cpp/hello_world/SubscriberWaitset.hpp b/examples/cpp/hello_world/SubscriberWaitset.hpp index ea08b0d67ed..13f843b53ed 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.hpp +++ b/examples/cpp/hello_world/SubscriberWaitset.hpp @@ -28,7 +28,7 @@ #include #include -#include "cli_options.hpp" +#include "CLIParser.hpp" #include "HelloWorldPubSubTypes.h" using namespace eprosima::fastdds::dds; From 5c0b65eae60c15866cf73d2dd909bc98042f629f Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 13 Mar 2024 11:45:26 +0100 Subject: [PATCH 16/42] Refs #20543: Improve usage message Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CLIParser.hpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/cpp/hello_world/CLIParser.hpp b/examples/cpp/hello_world/CLIParser.hpp index f6d43df690f..c742337c4bf 100644 --- a/examples/cpp/hello_world/CLIParser.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -49,17 +49,17 @@ class CLIParser static void print_help( uint8_t return_code) { - std::cout << "Usage: hello_world [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 << "Common options:" << std::endl; - std::cout << " -h, --help Print this help message" << std::endl; - std::cout << " -s, --samples Amount of samples to be sent or" << std::endl; - std::cout << " received (default: 0 [unlimited])" << std::endl; - std::cout << "Subscriber options:" << std::endl; - std::cout << " -w, --waitset Use waitset read condition" << std::endl; + std::cout << "Usage: hello_world [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 << "Common options:" << std::endl; + std::cout << " -h, --help Print this help message" << std::endl; + std::cout << " -s , --samples Number of samples to send or receive" << std::endl; + std::cout << " (Default: 0 [unlimited])" << std::endl; + std::cout << "Subscriber options:" << std::endl; + std::cout << " -w, --waitset Use waitset read condition" << std::endl; std::exit(return_code); } From b7899237658f9587ff5f63195dbc7c240180ce6f Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 14 Mar 2024 10:53:41 +0100 Subject: [PATCH 17/42] Refs #20543: Apply rev suggestions (2) Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CLIParser.hpp | 55 +++++++++++-------- examples/cpp/hello_world/CMakeLists.txt | 2 +- examples/cpp/hello_world/HelloWorld_main.cpp | 7 ++- examples/cpp/hello_world/Publisher.cpp | 28 +++++----- examples/cpp/hello_world/Publisher.hpp | 11 ++-- examples/cpp/hello_world/Subscriber.cpp | 24 ++++---- examples/cpp/hello_world/Subscriber.hpp | 3 +- .../cpp/hello_world/SubscriberWaitset.cpp | 24 ++++---- .../cpp/hello_world/SubscriberWaitset.hpp | 9 +-- test/examples/test_examples.py | 4 ++ 10 files changed, 95 insertions(+), 72 deletions(-) diff --git a/examples/cpp/hello_world/CLIParser.hpp b/examples/cpp/hello_world/CLIParser.hpp index c742337c4bf..231cd14b86b 100644 --- a/examples/cpp/hello_world/CLIParser.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -30,18 +30,17 @@ class CLIParser struct publisher_config { - uint16_t samples; + uint16_t samples = 0; }; - struct subscriber_config + struct subscriber_config : public publisher_config { - bool use_waitset; - uint16_t samples; + bool use_waitset = false; }; struct hello_world_config { - std::string entity; + std::string entity = ""; publisher_config pub_config; subscriber_config sub_config; }; @@ -54,9 +53,10 @@ class CLIParser 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 << " -s , --samples Number of samples to send or receive" << std::endl; + std::cout << " -s , --samples Number of samples to send or receive" << std::endl; std::cout << " (Default: 0 [unlimited])" << std::endl; std::cout << "Subscriber options:" << std::endl; std::cout << " -w, --waitset Use waitset read condition" << std::endl; @@ -68,21 +68,32 @@ class CLIParser char* argv[]) { hello_world_config config; - config.entity = ""; - config.pub_config.samples = 0; - config.sub_config.samples = 0; - config.sub_config.use_waitset = false; - for (int i = 1; i < argc; ++i) + std::string first_argument = argv[1]; + + if (first_argument == "publisher" || first_argument == "subscriber") { - std::string arg = argv[i]; - if (arg == "-h" || arg == "--help") + config.entity = first_argument; + } + else + { + if (first_argument == "-h" || first_argument == "--help") { print_help(EXIT_SUCCESS); } - else if (arg == "publisher" || arg == "subscriber") + else { - config.entity = arg; + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing entity argument"); + print_help(EXIT_FAILURE); + } + } + + for (int i = 2; i < argc; ++i) + { + std::string arg = argv[i]; + if (arg == "-h" || arg == "--help") + { + print_help(EXIT_SUCCESS); } else if (arg == "-s" || arg == "--samples") { @@ -90,7 +101,7 @@ class CLIParser { try { - uint16_t samples = std::stoi(argv[++i]); + uint16_t samples = static_cast(std::stoi(argv[++i])); if (config.entity == "publisher") { config.pub_config.samples = samples; @@ -111,6 +122,11 @@ class CLIParser EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid sample argument for " + arg); print_help(EXIT_FAILURE); } + catch (const std::out_of_range& e) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "sample argument out of range for " + arg); + print_help(EXIT_FAILURE); + } } else { @@ -137,15 +153,8 @@ class CLIParser } } - if (config.entity == "") - { - EPROSIMA_LOG_ERROR(CLI_PARSER, "entity not specified"); - print_help(EXIT_FAILURE); - } - return config; } - }; #endif // _FASTDDS_HELLO_WORLD_CLI_PARSER_HPP_ diff --git a/examples/cpp/hello_world/CMakeLists.txt b/examples/cpp/hello_world/CMakeLists.txt index 15bdfdc6eec..33b21dad5a1 100644 --- a/examples/cpp/hello_world/CMakeLists.txt +++ b/examples/cpp/hello_world/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# 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. diff --git a/examples/cpp/hello_world/HelloWorld_main.cpp b/examples/cpp/hello_world/HelloWorld_main.cpp index 706b543758a..46f69b0e0bb 100644 --- a/examples/cpp/hello_world/HelloWorld_main.cpp +++ b/examples/cpp/hello_world/HelloWorld_main.cpp @@ -34,13 +34,14 @@ int main( char** argv) { auto ret = EXIT_SUCCESS; + const std::string topic_name = "hello_world_topic"; CLIParser::hello_world_config config = CLIParser::parse_cli_options(argc, argv); if (config.entity == "publisher") { try { - HelloWorldPublisher hello_world_publisher(config.pub_config); + HelloWorldPublisher hello_world_publisher(config.pub_config, topic_name); hello_world_publisher.run(); } catch (const std::runtime_error& e) @@ -55,7 +56,7 @@ int main( { try { - HelloWorldSubscriberWaitset hello_world_subscriber_waitset(config.sub_config); + HelloWorldSubscriberWaitset hello_world_subscriber_waitset(config.sub_config, topic_name); hello_world_subscriber_waitset.run(); } catch (const std::runtime_error& e) @@ -68,7 +69,7 @@ int main( { try { - HelloWorldSubscriber hello_world_subscriber(config.sub_config); + HelloWorldSubscriber hello_world_subscriber(config.sub_config, topic_name); hello_world_subscriber.run(); } catch (const std::runtime_error& e) diff --git a/examples/cpp/hello_world/Publisher.cpp b/examples/cpp/hello_world/Publisher.cpp index 28ccccb29c6..2f5530220af 100644 --- a/examples/cpp/hello_world/Publisher.cpp +++ b/examples/cpp/hello_world/Publisher.cpp @@ -36,21 +36,20 @@ std::atomic HelloWorldPublisher::stop_(false); std::condition_variable HelloWorldPublisher::matched_cv_; HelloWorldPublisher::HelloWorldPublisher( - const CLIParser::publisher_config& config) + const CLIParser::publisher_config& config, + const std::string& topic_name) : participant_(nullptr) , publisher_(nullptr) , topic_(nullptr) , writer_(nullptr) , type_(new HelloWorldPubSubType()) + , matched_(0) + , samples_ (config.samples) { // Set up the data type with initial values hello_.index(0); hello_.message("Hello world"); - matched_ = 0; - - // Get CLI options - samples_ = config.samples; - + // Create the participant auto factory = DomainParticipantFactory::get_instance(); participant_ = factory->create_participant_with_default_profile(nullptr, StatusMask::none()); @@ -74,7 +73,7 @@ HelloWorldPublisher::HelloWorldPublisher( // Create the topic TopicQos topic_qos = TOPIC_QOS_DEFAULT; participant_->get_default_topic_qos(topic_qos); - topic_ = participant_->create_topic("hello_world_topic", type_.get_type_name(), topic_qos); + topic_ = participant_->create_topic(topic_name, type_.get_type_name(), topic_qos); if (topic_ == nullptr) { throw std::runtime_error("Topic initialization failed"); @@ -92,11 +91,14 @@ HelloWorldPublisher::HelloWorldPublisher( HelloWorldPublisher::~HelloWorldPublisher() { - // Delete DDS entities contained within the DomainParticipant - participant_->delete_contained_entities(); + if (nullptr != participant_) + { + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); - // Delete DomainParticipant - DomainParticipantFactory::get_instance()->delete_participant(participant_); + // Delete DomainParticipant + DomainParticipantFactory::get_instance()->delete_participant(participant_); + } } void HelloWorldPublisher::on_publication_matched( @@ -132,7 +134,7 @@ void HelloWorldPublisher::run() std::cout << "Message: '" << hello_.message() << "' with index: '" << hello_.index() << "' SENT" << std::endl; } - std::this_thread::sleep_for(std::chrono::milliseconds(period_)); + std::this_thread::sleep_for(std::chrono::milliseconds(period_ms_)); } }); if (samples_ == 0) @@ -177,7 +179,7 @@ bool HelloWorldPublisher::publish() matched_cv_.wait(matched_lock, [&]() { // at least one has been discovered - return matched_ > 0 || is_stopped(); + return ((matched_ > 0) || is_stopped()); }); if (!is_stopped()) { diff --git a/examples/cpp/hello_world/Publisher.hpp b/examples/cpp/hello_world/Publisher.hpp index 5489662cea2..090bd7952b4 100644 --- a/examples/cpp/hello_world/Publisher.hpp +++ b/examples/cpp/hello_world/Publisher.hpp @@ -36,7 +36,8 @@ class HelloWorldPublisher : public DataWriterListener public: HelloWorldPublisher( - const CLIParser::publisher_config& config); + const CLIParser::publisher_config& config, + const std::string& topic_name); ~HelloWorldPublisher() override; @@ -45,9 +46,6 @@ class HelloWorldPublisher : public DataWriterListener DataWriter* writer, const PublicationMatchedStatus& info) override; - //! Publish a sample - bool publish(); - //! Run publisher void run(); @@ -56,6 +54,9 @@ class HelloWorldPublisher : public DataWriterListener private: + //! Publish a sample + bool publish(); + //! Return the current state of execution bool is_stopped(); @@ -81,7 +82,7 @@ class HelloWorldPublisher : public DataWriterListener static std::condition_variable matched_cv_; - const uint8_t period_ = 100; // in ms + const uint32_t period_ms_ = 100; // in ms }; diff --git a/examples/cpp/hello_world/Subscriber.cpp b/examples/cpp/hello_world/Subscriber.cpp index d53eeb512ef..3b437607d0c 100644 --- a/examples/cpp/hello_world/Subscriber.cpp +++ b/examples/cpp/hello_world/Subscriber.cpp @@ -38,17 +38,16 @@ std::atomic HelloWorldSubscriber::stop_(false); std::condition_variable HelloWorldSubscriber::terminate_cv_; HelloWorldSubscriber::HelloWorldSubscriber( - const CLIParser::subscriber_config& config) + const CLIParser::subscriber_config& config, + const std::string& topic_name) : participant_(nullptr) , subscriber_(nullptr) , topic_(nullptr) , reader_(nullptr) , type_(new HelloWorldPubSubType()) + , samples_ (config.samples) + , received_samples_(0) { - // Get CLI options - samples_ = config.samples; - received_samples_ = 0; - // Create the participant auto factory = DomainParticipantFactory::get_instance(); participant_ = factory->create_participant_with_default_profile(nullptr, StatusMask::none()); @@ -72,7 +71,7 @@ HelloWorldSubscriber::HelloWorldSubscriber( // Create the topic TopicQos topic_qos = TOPIC_QOS_DEFAULT; participant_->get_default_topic_qos(topic_qos); - topic_ = participant_->create_topic("hello_world_topic", type_.get_type_name(), topic_qos); + topic_ = participant_->create_topic(topic_name, type_.get_type_name(), topic_qos); if (topic_ == nullptr) { throw std::runtime_error("Topic initialization failed"); @@ -90,11 +89,14 @@ HelloWorldSubscriber::HelloWorldSubscriber( HelloWorldSubscriber::~HelloWorldSubscriber() { - // Delete DDS entities contained within the DomainParticipant - participant_->delete_contained_entities(); + if (nullptr != participant_) + { + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); - // Delete DomainParticipant - DomainParticipantFactory::get_instance()->delete_participant(participant_); + // Delete DomainParticipant + DomainParticipantFactory::get_instance()->delete_participant(participant_); + } } void HelloWorldSubscriber::on_subscription_matched( @@ -122,7 +124,7 @@ void HelloWorldSubscriber::on_data_available( SampleInfo info; if ((!is_stopped()) && (RETCODE_OK == reader->take_next_sample(&hello_, &info))) { - if (info.instance_state == ALIVE_INSTANCE_STATE && info.valid_data) + if ((info.instance_state == ALIVE_INSTANCE_STATE) && info.valid_data) { received_samples_++; // Print Hello world message data diff --git a/examples/cpp/hello_world/Subscriber.hpp b/examples/cpp/hello_world/Subscriber.hpp index b5cb36b38f7..2ffdba85820 100644 --- a/examples/cpp/hello_world/Subscriber.hpp +++ b/examples/cpp/hello_world/Subscriber.hpp @@ -36,7 +36,8 @@ class HelloWorldSubscriber : public DataReaderListener public: HelloWorldSubscriber( - const CLIParser::subscriber_config& config); + const CLIParser::subscriber_config& config, + const std::string& topic_name); virtual ~HelloWorldSubscriber(); diff --git a/examples/cpp/hello_world/SubscriberWaitset.cpp b/examples/cpp/hello_world/SubscriberWaitset.cpp index 4c3bc6cf42e..e0ae1bba4a1 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.cpp +++ b/examples/cpp/hello_world/SubscriberWaitset.cpp @@ -40,17 +40,16 @@ std::atomic HelloWorldSubscriberWaitset::stop_(false); GuardCondition HelloWorldSubscriberWaitset::terminate_condition_; HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset( - const CLIParser::subscriber_config& config) + const CLIParser::subscriber_config& config, + const std::string& topic_name) : participant_(nullptr) , subscriber_(nullptr) , topic_(nullptr) , reader_(nullptr) , type_(new HelloWorldPubSubType()) + , samples_ (config.samples) + , received_samples_(0) { - // Get CLI options - samples_ = config.samples; - received_samples_ = 0; - // Create the participant auto factory = DomainParticipantFactory::get_instance(); participant_ = factory->create_participant_with_default_profile(nullptr, StatusMask::none()); @@ -74,7 +73,7 @@ HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset( // Create the topic TopicQos topic_qos = TOPIC_QOS_DEFAULT; participant_->get_default_topic_qos(topic_qos); - topic_ = participant_->create_topic("hello_world_topic", type_.get_type_name(), topic_qos); + topic_ = participant_->create_topic(topic_name, type_.get_type_name(), topic_qos); if (topic_ == nullptr) { throw std::runtime_error("Topic initialization failed"); @@ -96,11 +95,14 @@ HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset( HelloWorldSubscriberWaitset::~HelloWorldSubscriberWaitset() { - // Delete DDS entities contained within the DomainParticipant - participant_->delete_contained_entities(); + if (nullptr != participant_) + { + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); - // Delete DomainParticipant - DomainParticipantFactory::get_instance()->delete_participant(participant_); + // Delete DomainParticipant + DomainParticipantFactory::get_instance()->delete_participant(participant_); + } } void HelloWorldSubscriberWaitset::run() @@ -148,7 +150,7 @@ void HelloWorldSubscriberWaitset::run() while ((!is_stopped()) && (ReturnCode_t::RETCODE_OK == reader_->take_next_sample(&hello_, &info))) { - if (info.instance_state == ALIVE_INSTANCE_STATE && info.valid_data) + if ((info.instance_state == ALIVE_INSTANCE_STATE) && info.valid_data) { received_samples_++; // Print Hello world message data diff --git a/examples/cpp/hello_world/SubscriberWaitset.hpp b/examples/cpp/hello_world/SubscriberWaitset.hpp index 13f843b53ed..87b22ea944a 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.hpp +++ b/examples/cpp/hello_world/SubscriberWaitset.hpp @@ -38,21 +38,22 @@ class HelloWorldSubscriberWaitset public: HelloWorldSubscriberWaitset( - const CLIParser::subscriber_config& config); + const CLIParser::subscriber_config& config, + const std::string& topic_name); virtual ~HelloWorldSubscriberWaitset(); //! Run subscriber void run(); - //! Return the current state of execution - static bool is_stopped(); - //! Trigger the end of execution static void stop(); private: + //! Return the current state of execution + static bool is_stopped(); + HelloWorld hello_; DomainParticipant* participant_; diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index a1e89044349..4d5c11ce1d5 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -27,6 +27,7 @@ def test_basic_configuration(): if sent != 0 and received != 0 and sent * 2 == received: ret = True else: + print ('sent: ' + str(sent) + ' received: ' + str(received)) raise subprocess.CalledProcessError(1, '') except subprocess.CalledProcessError: @@ -34,6 +35,7 @@ def test_basic_configuration(): print(l) except subprocess.TimeoutExpired: print('TIMEOUT') + print(out) assert(ret) @@ -63,6 +65,7 @@ def test_hello_world(): if sent != 0 and received != 0 and sent * 2 == received: ret = True else: + print ('sent: ' + str(sent) + ' received: ' + str(received)) raise subprocess.CalledProcessError(1, '') except subprocess.CalledProcessError: @@ -70,5 +73,6 @@ def test_hello_world(): print(l) except subprocess.TimeoutExpired: print('TIMEOUT') + print(out) assert(ret) From 223cf8cdce095451cc89e968669aeb508c066294 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 14 Mar 2024 16:31:02 +0100 Subject: [PATCH 18/42] Refs #20543: Apply rev suggestions (3) Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CLIParser.hpp | 24 ++- examples/cpp/hello_world/CMakeLists.txt | 2 +- examples/cpp/hello_world/HelloWorld_main.cpp | 177 ++++++++++++++---- examples/cpp/hello_world/Publisher.cpp | 55 +----- examples/cpp/hello_world/Publisher.hpp | 6 +- examples/cpp/hello_world/Subscriber.cpp | 39 +--- examples/cpp/hello_world/Subscriber.hpp | 8 +- .../cpp/hello_world/SubscriberWaitset.cpp | 131 +++++-------- .../cpp/hello_world/SubscriberWaitset.hpp | 8 +- 9 files changed, 232 insertions(+), 218 deletions(-) diff --git a/examples/cpp/hello_world/CLIParser.hpp b/examples/cpp/hello_world/CLIParser.hpp index 231cd14b86b..039e0f35207 100644 --- a/examples/cpp/hello_world/CLIParser.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -28,6 +28,13 @@ class CLIParser CLIParser() = delete; + enum entity_kind + { + PUBLISHER, + SUBSCRIBER, + UNDEFINED + }; + struct publisher_config { uint16_t samples = 0; @@ -40,7 +47,7 @@ class CLIParser struct hello_world_config { - std::string entity = ""; + entity_kind entity = entity_kind::UNDEFINED; publisher_config pub_config; subscriber_config sub_config; }; @@ -71,9 +78,13 @@ class CLIParser std::string first_argument = argv[1]; - if (first_argument == "publisher" || first_argument == "subscriber") + if (first_argument == "publisher" ) { - config.entity = first_argument; + config.entity = entity_kind::PUBLISHER; + } + else if ( first_argument == "subscriber") + { + config.entity = entity_kind::SUBSCRIBER; } else { @@ -102,11 +113,11 @@ class CLIParser try { uint16_t samples = static_cast(std::stoi(argv[++i])); - if (config.entity == "publisher") + if (config.entity == entity_kind::PUBLISHER) { config.pub_config.samples = samples; } - else if (config.entity == "subscriber") + else if (config.entity == entity_kind::SUBSCRIBER) { config.sub_config.samples = samples; } @@ -136,7 +147,7 @@ class CLIParser } else if (arg == "-w" || arg == "--waitset") { - if (config.entity == "subscriber") + if (config.entity == entity_kind::SUBSCRIBER) { config.sub_config.use_waitset = true; } @@ -155,6 +166,7 @@ class CLIParser return config; } + }; #endif // _FASTDDS_HELLO_WORLD_CLI_PARSER_HPP_ diff --git a/examples/cpp/hello_world/CMakeLists.txt b/examples/cpp/hello_world/CMakeLists.txt index 33b21dad5a1..34588413662 100644 --- a/examples/cpp/hello_world/CMakeLists.txt +++ b/examples/cpp/hello_world/CMakeLists.txt @@ -46,7 +46,7 @@ target_compile_definitions(hello_world PRIVATE ) target_link_libraries(hello_world fastdds fastcdr) install(TARGETS hello_world - RUNTIME DESTINATION examples/cpp/hello_world/${BIN_INSTALL_DIR}) + RUNTIME DESTINATION fastdds/examples/cpp/hello_world/${BIN_INSTALL_DIR}) # Copy the XML files over to the build directory file(GLOB_RECURSE XML_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.xml) diff --git a/examples/cpp/hello_world/HelloWorld_main.cpp b/examples/cpp/hello_world/HelloWorld_main.cpp index 46f69b0e0bb..d70ce6d4a52 100644 --- a/examples/cpp/hello_world/HelloWorld_main.cpp +++ b/examples/cpp/hello_world/HelloWorld_main.cpp @@ -17,7 +17,9 @@ * */ +#include #include +#include #include #include @@ -29,61 +31,172 @@ using eprosima::fastdds::dds::Log; +std::function signal_handler; + int main( int argc, char** argv) { auto ret = EXIT_SUCCESS; + HelloWorldPublisher* publisher = nullptr; + HelloWorldSubscriber* subscriber = nullptr; + HelloWorldSubscriberWaitset* subscriber_waitset = nullptr; + std::thread* thread = nullptr; const std::string topic_name = "hello_world_topic"; + std::string entity_name = "undefined"; + uint16_t samples = 0; CLIParser::hello_world_config config = CLIParser::parse_cli_options(argc, argv); - if (config.entity == "publisher") + switch (config.entity) { - try - { - HelloWorldPublisher hello_world_publisher(config.pub_config, topic_name); - hello_world_publisher.run(); - } - catch (const std::runtime_error& e) - { - EPROSIMA_LOG_ERROR(PUBLISHER, e.what()); - ret = EXIT_FAILURE; - } - } - else if (config.entity == "subscriber") - { - if (config.sub_config.use_waitset) - { + case CLIParser::entity_kind::PUBLISHER: + entity_name = "Publisher"; + samples = config.pub_config.samples; try { - HelloWorldSubscriberWaitset hello_world_subscriber_waitset(config.sub_config, topic_name); - hello_world_subscriber_waitset.run(); + publisher = new HelloWorldPublisher(config.pub_config, topic_name); + thread = new std::thread(&HelloWorldPublisher::run, publisher); } catch (const std::runtime_error& e) { - EPROSIMA_LOG_ERROR(SUBSCRIBER, e.what()); + EPROSIMA_LOG_ERROR(PUBLISHER, e.what()); ret = EXIT_FAILURE; } - } - else - { - try + break; + case CLIParser::entity_kind::SUBSCRIBER: + samples = config.sub_config.samples; + if (config.sub_config.use_waitset) { - HelloWorldSubscriber hello_world_subscriber(config.sub_config, topic_name); - hello_world_subscriber.run(); + entity_name = "Waitset Subscriber"; + try + { + subscriber_waitset = new HelloWorldSubscriberWaitset(config.sub_config, topic_name); + thread = new std::thread(&HelloWorldSubscriberWaitset::run, subscriber_waitset); + } + catch (const std::runtime_error& e) + { + EPROSIMA_LOG_ERROR(SUBSCRIBER, e.what()); + ret = EXIT_FAILURE; + } } - catch (const std::runtime_error& e) + else { - EPROSIMA_LOG_ERROR(SUBSCRIBER_WAITSET, e.what()); - ret = EXIT_FAILURE; + entity_name = "Subscriber"; + try + { + subscriber = new HelloWorldSubscriber(config.sub_config, topic_name); + thread = new std::thread(&HelloWorldSubscriber::run, subscriber); + } + catch (const std::runtime_error& e) + { + EPROSIMA_LOG_ERROR(SUBSCRIBER_WAITSET, e.what()); + ret = EXIT_FAILURE; + } } - } + break; + default: + EPROSIMA_LOG_ERROR(CLI_PARSER, "unknown entity"); + CLIParser::print_help(EXIT_FAILURE); + break; + } + + if (samples == 0) + { + std::cout << entity_name << " running. Please press Ctrl+C to stop the " + << entity_name << " at any time." << std::endl; } - // example should never reach this point else { - EPROSIMA_LOG_ERROR(CLI_PARSER, "unknown entity " + config.entity); - CLIParser::print_help(EXIT_FAILURE); + switch (config.entity) + { + case CLIParser::entity_kind::PUBLISHER: + std::cout << entity_name << " running " << samples << " samples. Please press Ctrl+C to stop the " + << entity_name << " at any time." << std::endl; + break; + case CLIParser::entity_kind::SUBSCRIBER: + default: + std::cout << entity_name << " running until " << samples << " samples have been received. Please press " + << "Ctrl+C to stop the " << entity_name << " at any time." << std::endl; + break; + } + } + + signal_handler = [&](std::string signal) + { + std::cout << "\n" << signal << " received, stopping " << entity_name << " execution." << std::endl; + switch (config.entity) + { + case CLIParser::entity_kind::PUBLISHER: + if (nullptr != publisher) + { + publisher->stop(); + } + break; + case CLIParser::entity_kind::SUBSCRIBER: + default: + if (config.sub_config.use_waitset) + { + if (nullptr != subscriber_waitset) + { + subscriber_waitset->stop(); + } + } + else + { + if (nullptr != subscriber) + { + subscriber->stop(); + } + } + break; + } + }; + signal(SIGINT, [](int /*signum*/) + { + signal_handler("SIGINT"); + }); + signal(SIGTERM, [](int /*signum*/) + { + signal_handler("SIGTERM"); + }); +#ifndef _WIN32 + signal(SIGQUIT, [](int /*signum*/) + { + signal_handler("SIGQUIT"); + }); + signal(SIGHUP, [](int /*signum*/) + { + signal_handler("SIGHUP"); + }); +#endif // _WIN32 + + thread->join(); + delete thread; + switch (config.entity) + { + case CLIParser::entity_kind::PUBLISHER: + if (nullptr != publisher) + { + delete publisher; + } + break; + case CLIParser::entity_kind::SUBSCRIBER: + default: + if (config.sub_config.use_waitset) + { + if (nullptr != subscriber_waitset) + { + delete subscriber_waitset; + } + } + else + { + if (nullptr != subscriber) + { + delete subscriber; + } + } + break; } Log::Reset(); diff --git a/examples/cpp/hello_world/Publisher.cpp b/examples/cpp/hello_world/Publisher.cpp index 2f5530220af..8dd8f6b8d0c 100644 --- a/examples/cpp/hello_world/Publisher.cpp +++ b/examples/cpp/hello_world/Publisher.cpp @@ -32,9 +32,6 @@ using namespace eprosima::fastdds::dds; -std::atomic HelloWorldPublisher::stop_(false); -std::condition_variable HelloWorldPublisher::matched_cv_; - HelloWorldPublisher::HelloWorldPublisher( const CLIParser::publisher_config& config, const std::string& topic_name) @@ -43,13 +40,14 @@ HelloWorldPublisher::HelloWorldPublisher( , topic_(nullptr) , writer_(nullptr) , type_(new HelloWorldPubSubType()) + , stop_(false) , matched_(0) , samples_ (config.samples) { // Set up the data type with initial values hello_.index(0); hello_.message("Hello world"); - + // Create the participant auto factory = DomainParticipantFactory::get_instance(); participant_ = factory->create_participant_with_default_profile(nullptr, StatusMask::none()); @@ -125,50 +123,15 @@ void HelloWorldPublisher::on_publication_matched( void HelloWorldPublisher::run() { - std::thread pub_thread([&] - { - while (!is_stopped() && (samples_ == 0 || hello_.index() < samples_)) - { - if (publish()) - { - std::cout << "Message: '" << hello_.message() << "' with index: '" << hello_.index() - << "' SENT" << std::endl; - } - std::this_thread::sleep_for(std::chrono::milliseconds(period_ms_)); - } - }); - if (samples_ == 0) + while (!is_stopped() && (samples_ == 0 || hello_.index() < samples_)) { - std::cout << "Publisher running. Please press Ctrl+C to stop the Publisher at any time." << std::endl; + if (publish()) + { + std::cout << "Message: '" << hello_.message() << "' with index: '" << hello_.index() + << "' SENT" << std::endl; + } + std::this_thread::sleep_for(std::chrono::milliseconds(period_ms_)); } - 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 << "\nSIGINT received, stopping Publisher execution." << std::endl; - HelloWorldPublisher::stop(); - }); - signal(SIGTERM, [](int /*signum*/) - { - std::cout << "\nSIGTERM received, stopping Publisher execution." << std::endl; - HelloWorldPublisher::stop(); - }); -#ifndef _WIN32 - signal(SIGQUIT, [](int /*signum*/) - { - std::cout << "\nSIGQUIT received, stopping Publisher execution." << std::endl; - HelloWorldPublisher::stop(); - }); - signal(SIGHUP, [](int /*signum*/) - { - std::cout << "\nSIGHUP received, stopping Publisher execution." << std::endl; - HelloWorldPublisher::stop(); - }); -#endif // _WIN32 - pub_thread.join(); } bool HelloWorldPublisher::publish() diff --git a/examples/cpp/hello_world/Publisher.hpp b/examples/cpp/hello_world/Publisher.hpp index 090bd7952b4..d19ed7c52d8 100644 --- a/examples/cpp/hello_world/Publisher.hpp +++ b/examples/cpp/hello_world/Publisher.hpp @@ -50,7 +50,7 @@ class HelloWorldPublisher : public DataWriterListener void run(); //! Trigger the end of execution - static void stop(); + void stop(); private: @@ -72,7 +72,7 @@ class HelloWorldPublisher : public DataWriterListener TypeSupport type_; - static std::atomic stop_; + std::atomic stop_; int16_t matched_; @@ -80,7 +80,7 @@ class HelloWorldPublisher : public DataWriterListener std::mutex mutex_; - static std::condition_variable matched_cv_; + std::condition_variable matched_cv_; const uint32_t period_ms_ = 100; // in ms }; diff --git a/examples/cpp/hello_world/Subscriber.cpp b/examples/cpp/hello_world/Subscriber.cpp index 3b437607d0c..591db490e94 100644 --- a/examples/cpp/hello_world/Subscriber.cpp +++ b/examples/cpp/hello_world/Subscriber.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -34,9 +33,6 @@ using namespace eprosima::fastdds::dds; -std::atomic HelloWorldSubscriber::stop_(false); -std::condition_variable HelloWorldSubscriber::terminate_cv_; - HelloWorldSubscriber::HelloWorldSubscriber( const CLIParser::subscriber_config& config, const std::string& topic_name) @@ -47,6 +43,7 @@ HelloWorldSubscriber::HelloWorldSubscriber( , type_(new HelloWorldPubSubType()) , samples_ (config.samples) , received_samples_(0) + , stop_(false) { // Create the participant auto factory = DomainParticipantFactory::get_instance(); @@ -140,40 +137,8 @@ void HelloWorldSubscriber::on_data_available( void HelloWorldSubscriber::run() { - if (samples_ == 0) - { - std::cout << "Subscriber running. Please press Ctrl+C to stop the Subscriber at any time." << std::endl; - } - else - { - std::cout << "Subscriber running until " << samples_ << - " samples have been received. Please press Ctrl+C to stop the Subscriber at any time." << std::endl; - } - - signal(SIGINT, [](int /*signum*/) - { - std::cout << "\nSIGINT received, stopping Subscriber execution." << std::endl; - HelloWorldSubscriber::stop(); - }); - signal(SIGTERM, [](int /*signum*/) - { - std::cout << "\nSIGTERM received, stopping Subscriber execution." << std::endl; - HelloWorldSubscriber::stop(); - }); -#ifndef _WIN32 - signal(SIGQUIT, [](int /*signum*/) - { - std::cout << "\nSIGQUIT received, stopping Subscriber execution." << std::endl; - HelloWorldSubscriber::stop(); - }); - signal(SIGHUP, [](int /*signum*/) - { - std::cout << "\nSIGHUP received, stopping Subscriber execution." << std::endl; - HelloWorldSubscriber::stop(); - }); -#endif // _WIN32 std::unique_lock lck(terminate_cv_mtx_); - terminate_cv_.wait(lck, [] + terminate_cv_.wait(lck, [&] { return is_stopped(); }); diff --git a/examples/cpp/hello_world/Subscriber.hpp b/examples/cpp/hello_world/Subscriber.hpp index 2ffdba85820..14449b72f76 100644 --- a/examples/cpp/hello_world/Subscriber.hpp +++ b/examples/cpp/hello_world/Subscriber.hpp @@ -54,12 +54,12 @@ class HelloWorldSubscriber : public DataReaderListener void run(); //! Trigger the end of execution - static void stop(); + void stop(); private: //! Return the current state of execution - static bool is_stopped(); + bool is_stopped(); HelloWorld hello_; @@ -77,11 +77,11 @@ class HelloWorldSubscriber : public DataReaderListener uint16_t received_samples_; - static std::atomic stop_; + std::atomic stop_; mutable std::mutex terminate_cv_mtx_; - static std::condition_variable terminate_cv_; + std::condition_variable terminate_cv_; }; #endif /* _FASTDDS_HELLO_WORLD_SUBSCRIBER_HPP_ */ diff --git a/examples/cpp/hello_world/SubscriberWaitset.cpp b/examples/cpp/hello_world/SubscriberWaitset.cpp index e0ae1bba4a1..9eedb3d0988 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.cpp +++ b/examples/cpp/hello_world/SubscriberWaitset.cpp @@ -36,9 +36,6 @@ using namespace eprosima::fastdds::dds; -std::atomic HelloWorldSubscriberWaitset::stop_(false); -GuardCondition HelloWorldSubscriberWaitset::terminate_condition_; - HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset( const CLIParser::subscriber_config& config, const std::string& topic_name) @@ -49,6 +46,7 @@ HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset( , type_(new HelloWorldPubSubType()) , samples_ (config.samples) , received_samples_(0) + , stop_(false) { // Create the participant auto factory = DomainParticipantFactory::get_instance(); @@ -107,100 +105,63 @@ HelloWorldSubscriberWaitset::~HelloWorldSubscriberWaitset() void HelloWorldSubscriberWaitset::run() { - std::thread sub_thread([&] + while (!is_stopped()) + { + ConditionSeq triggered_conditions; + ReturnCode_t ret_code = wait_set_.wait(triggered_conditions, eprosima::fastrtps::c_TimeInfinite); + if (ReturnCode_t::RETCODE_OK != ret_code) + { + EPROSIMA_LOG_ERROR(SUBSCRIBER_WAITSET, "Error waiting for conditions"); + continue; + } + for (Condition* cond : triggered_conditions) + { + StatusCondition* status_cond = dynamic_cast(cond); + if (nullptr != status_cond) { - while (!is_stopped()) + Entity* entity = status_cond->get_entity(); + StatusMask changed_statuses = entity->get_status_changes(); + if (changed_statuses.is_active(StatusMask::subscription_matched())) { - ConditionSeq triggered_conditions; - ReturnCode_t ret_code = wait_set_.wait(triggered_conditions, eprosima::fastrtps::c_TimeInfinite); - if (ReturnCode_t::RETCODE_OK != ret_code) + SubscriptionMatchedStatus status_; + reader_->get_subscription_matched_status(status_); + if (status_.current_count_change == 1) { - EPROSIMA_LOG_ERROR(SUBSCRIBER_WAITSET, "Error waiting for conditions"); - continue; + std::cout << "Waitset Subscriber matched." << std::endl; } - for (Condition* cond : triggered_conditions) + else if (status_.current_count_change == -1) { - StatusCondition* status_cond = dynamic_cast(cond); - if (nullptr != status_cond) + std::cout << "Waitset Subscriber unmatched." << std::endl; + } + else + { + std::cout << status_.current_count_change << + " is not a valid value for SubscriptionMatchedStatus current count change" << + std::endl; + } + } + if (changed_statuses.is_active(StatusMask::data_available())) + { + SampleInfo info; + while ((!is_stopped()) && + (ReturnCode_t::RETCODE_OK == reader_->take_next_sample(&hello_, &info))) + { + if ((info.instance_state == ALIVE_INSTANCE_STATE) && info.valid_data) { - Entity* entity = status_cond->get_entity(); - StatusMask changed_statuses = entity->get_status_changes(); - if (changed_statuses.is_active(StatusMask::subscription_matched())) - { - SubscriptionMatchedStatus status_; - reader_->get_subscription_matched_status(status_); - if (status_.current_count_change == 1) - { - std::cout << "Waitset Subscriber matched." << std::endl; - } - else if (status_.current_count_change == -1) - { - std::cout << "Waitset Subscriber unmatched." << std::endl; - } - else - { - std::cout << status_.current_count_change << - " is not a valid value for SubscriptionMatchedStatus current count change" << - std::endl; - } - } - if (changed_statuses.is_active(StatusMask::data_available())) + received_samples_++; + // Print Hello world message data + std::cout << "Message: '" << hello_.message() << "' with index: '" + << hello_.index() << "' RECEIVED" << std::endl; + if (samples_ > 0 && (received_samples_ >= samples_)) { - SampleInfo info; - while ((!is_stopped()) && - (ReturnCode_t::RETCODE_OK == reader_->take_next_sample(&hello_, &info))) - { - if ((info.instance_state == ALIVE_INSTANCE_STATE) && info.valid_data) - { - received_samples_++; - // Print Hello world message data - std::cout << "Message: '" << hello_.message() << "' with index: '" - << hello_.index() << "' RECEIVED" << std::endl; - if (samples_ > 0 && (received_samples_ >= samples_)) - { - stop(); - } - } - } + stop(); } } } } - }); - - if (samples_ == 0) - { - std::cout << "Waitset Subscriber running. Please press Ctrl+C to stop the Waitset Subscriber at any time." - << std::endl; - } - else - { - std::cout << "Waitset Subscriber running until " << samples_ << - " samples have been received. Please press Ctrl+C to stop the Waitset Subscriber at any time." << std::endl; + } + } } - signal(SIGINT, [](int /*signum*/) - { - std::cout << "\nSIGINT received, stopping Waitset Subscriber execution." << std::endl; - HelloWorldSubscriberWaitset::stop(); - }); - signal(SIGTERM, [](int /*signum*/) - { - std::cout << "\nSIGTERM received, stopping Waitset Subscriber execution." << std::endl; - HelloWorldSubscriberWaitset::stop(); - }); -#ifndef _WIN32 - signal(SIGQUIT, [](int /*signum*/) - { - std::cout << "\nSIGQUIT received, stopping Waitset Subscriber execution." << std::endl; - HelloWorldSubscriberWaitset::stop(); - }); - signal(SIGHUP, [](int /*signum*/) - { - std::cout << "\nSIGHUP received, stopping Waitset Subscriber execution." << std::endl; - HelloWorldSubscriberWaitset::stop(); - }); -#endif // _WIN32 - sub_thread.join(); } bool HelloWorldSubscriberWaitset::is_stopped() diff --git a/examples/cpp/hello_world/SubscriberWaitset.hpp b/examples/cpp/hello_world/SubscriberWaitset.hpp index 87b22ea944a..b187b13d5fa 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.hpp +++ b/examples/cpp/hello_world/SubscriberWaitset.hpp @@ -47,12 +47,12 @@ class HelloWorldSubscriberWaitset void run(); //! Trigger the end of execution - static void stop(); + void stop(); private: //! Return the current state of execution - static bool is_stopped(); + bool is_stopped(); HelloWorld hello_; @@ -72,9 +72,9 @@ class HelloWorldSubscriberWaitset uint16_t received_samples_; - static std::atomic stop_; + std::atomic stop_; - static GuardCondition terminate_condition_; + GuardCondition terminate_condition_; }; #endif /* _FASTDDS_HELLO_WORLD_SUBSCRIBER_WAITSET_HPP_ */ From ba30e0ddbbbe65c66798ff490ad92a44f59bd0a8 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 18 Mar 2024 08:23:55 +0100 Subject: [PATCH 19/42] Refs #20543: [ARS] Include namespaces Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CLIParser.hpp | 26 +++++++++++++------ examples/cpp/hello_world/HelloWorld_main.cpp | 21 ++++++++------- examples/cpp/hello_world/Publisher.cpp | 2 +- examples/cpp/hello_world/Publisher.hpp | 2 +- examples/cpp/hello_world/Subscriber.cpp | 2 +- examples/cpp/hello_world/Subscriber.hpp | 2 +- .../cpp/hello_world/SubscriberWaitset.cpp | 2 +- .../cpp/hello_world/SubscriberWaitset.hpp | 2 +- 8 files changed, 35 insertions(+), 24 deletions(-) diff --git a/examples/cpp/hello_world/CLIParser.hpp b/examples/cpp/hello_world/CLIParser.hpp index 039e0f35207..b11e88c53ff 100644 --- a/examples/cpp/hello_world/CLIParser.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -20,7 +20,12 @@ #ifndef _FASTDDS_HELLO_WORLD_CLI_PARSER_HPP_ #define _FASTDDS_HELLO_WORLD_CLI_PARSER_HPP_ -using eprosima::fastdds::dds::Log; +namespace eprosima { +namespace fastdds { +namespace examples { +namespace hello_world { + +using dds::Log; class CLIParser { @@ -28,7 +33,7 @@ class CLIParser CLIParser() = delete; - enum entity_kind + enum EntityKind { PUBLISHER, SUBSCRIBER, @@ -47,7 +52,7 @@ class CLIParser struct hello_world_config { - entity_kind entity = entity_kind::UNDEFINED; + CLIParser::EntityKind entity = CLIParser::EntityKind::UNDEFINED; publisher_config pub_config; subscriber_config sub_config; }; @@ -80,11 +85,11 @@ class CLIParser if (first_argument == "publisher" ) { - config.entity = entity_kind::PUBLISHER; + config.entity = CLIParser::EntityKind::PUBLISHER; } else if ( first_argument == "subscriber") { - config.entity = entity_kind::SUBSCRIBER; + config.entity = CLIParser::EntityKind::SUBSCRIBER; } else { @@ -113,11 +118,11 @@ class CLIParser try { uint16_t samples = static_cast(std::stoi(argv[++i])); - if (config.entity == entity_kind::PUBLISHER) + if (config.entity == CLIParser::EntityKind::PUBLISHER) { config.pub_config.samples = samples; } - else if (config.entity == entity_kind::SUBSCRIBER) + else if (config.entity == CLIParser::EntityKind::SUBSCRIBER) { config.sub_config.samples = samples; } @@ -147,7 +152,7 @@ class CLIParser } else if (arg == "-w" || arg == "--waitset") { - if (config.entity == entity_kind::SUBSCRIBER) + if (config.entity == CLIParser::EntityKind::SUBSCRIBER) { config.sub_config.use_waitset = true; } @@ -169,4 +174,9 @@ class CLIParser }; +} // namespace hello_world +} // namespace examples +} // namespace fastdds +} // namespace eprosima + #endif // _FASTDDS_HELLO_WORLD_CLI_PARSER_HPP_ diff --git a/examples/cpp/hello_world/HelloWorld_main.cpp b/examples/cpp/hello_world/HelloWorld_main.cpp index d70ce6d4a52..08f3220787b 100644 --- a/examples/cpp/hello_world/HelloWorld_main.cpp +++ b/examples/cpp/hello_world/HelloWorld_main.cpp @@ -45,11 +45,12 @@ int main( const std::string topic_name = "hello_world_topic"; std::string entity_name = "undefined"; uint16_t samples = 0; - CLIParser::hello_world_config config = CLIParser::parse_cli_options(argc, argv); + eprosima::fastdds::examples::hello_world::CLIParser::hello_world_config config = + eprosima::fastdds::examples::hello_world::CLIParser::parse_cli_options(argc, argv); switch (config.entity) { - case CLIParser::entity_kind::PUBLISHER: + case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::PUBLISHER: entity_name = "Publisher"; samples = config.pub_config.samples; try @@ -63,7 +64,7 @@ int main( ret = EXIT_FAILURE; } break; - case CLIParser::entity_kind::SUBSCRIBER: + case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::SUBSCRIBER: samples = config.sub_config.samples; if (config.sub_config.use_waitset) { @@ -96,7 +97,7 @@ int main( break; default: EPROSIMA_LOG_ERROR(CLI_PARSER, "unknown entity"); - CLIParser::print_help(EXIT_FAILURE); + eprosima::fastdds::examples::hello_world::CLIParser::print_help(EXIT_FAILURE); break; } @@ -109,11 +110,11 @@ int main( { switch (config.entity) { - case CLIParser::entity_kind::PUBLISHER: + case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::PUBLISHER: std::cout << entity_name << " running " << samples << " samples. Please press Ctrl+C to stop the " << entity_name << " at any time." << std::endl; break; - case CLIParser::entity_kind::SUBSCRIBER: + case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::SUBSCRIBER: default: std::cout << entity_name << " running until " << samples << " samples have been received. Please press " << "Ctrl+C to stop the " << entity_name << " at any time." << std::endl; @@ -126,13 +127,13 @@ int main( std::cout << "\n" << signal << " received, stopping " << entity_name << " execution." << std::endl; switch (config.entity) { - case CLIParser::entity_kind::PUBLISHER: + case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::PUBLISHER: if (nullptr != publisher) { publisher->stop(); } break; - case CLIParser::entity_kind::SUBSCRIBER: + case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::SUBSCRIBER: default: if (config.sub_config.use_waitset) { @@ -174,13 +175,13 @@ int main( delete thread; switch (config.entity) { - case CLIParser::entity_kind::PUBLISHER: + case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::PUBLISHER: if (nullptr != publisher) { delete publisher; } break; - case CLIParser::entity_kind::SUBSCRIBER: + case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::SUBSCRIBER: default: if (config.sub_config.use_waitset) { diff --git a/examples/cpp/hello_world/Publisher.cpp b/examples/cpp/hello_world/Publisher.cpp index 8dd8f6b8d0c..bd885f015ca 100644 --- a/examples/cpp/hello_world/Publisher.cpp +++ b/examples/cpp/hello_world/Publisher.cpp @@ -33,7 +33,7 @@ using namespace eprosima::fastdds::dds; HelloWorldPublisher::HelloWorldPublisher( - const CLIParser::publisher_config& config, + const eprosima::fastdds::examples::hello_world::CLIParser::publisher_config& config, const std::string& topic_name) : participant_(nullptr) , publisher_(nullptr) diff --git a/examples/cpp/hello_world/Publisher.hpp b/examples/cpp/hello_world/Publisher.hpp index d19ed7c52d8..3af6fb40227 100644 --- a/examples/cpp/hello_world/Publisher.hpp +++ b/examples/cpp/hello_world/Publisher.hpp @@ -36,7 +36,7 @@ class HelloWorldPublisher : public DataWriterListener public: HelloWorldPublisher( - const CLIParser::publisher_config& config, + const eprosima::fastdds::examples::hello_world::CLIParser::publisher_config& config, const std::string& topic_name); ~HelloWorldPublisher() override; diff --git a/examples/cpp/hello_world/Subscriber.cpp b/examples/cpp/hello_world/Subscriber.cpp index 591db490e94..b0cd928304b 100644 --- a/examples/cpp/hello_world/Subscriber.cpp +++ b/examples/cpp/hello_world/Subscriber.cpp @@ -34,7 +34,7 @@ using namespace eprosima::fastdds::dds; HelloWorldSubscriber::HelloWorldSubscriber( - const CLIParser::subscriber_config& config, + const eprosima::fastdds::examples::hello_world::CLIParser::subscriber_config& config, const std::string& topic_name) : participant_(nullptr) , subscriber_(nullptr) diff --git a/examples/cpp/hello_world/Subscriber.hpp b/examples/cpp/hello_world/Subscriber.hpp index 14449b72f76..e470bf86965 100644 --- a/examples/cpp/hello_world/Subscriber.hpp +++ b/examples/cpp/hello_world/Subscriber.hpp @@ -36,7 +36,7 @@ class HelloWorldSubscriber : public DataReaderListener public: HelloWorldSubscriber( - const CLIParser::subscriber_config& config, + const eprosima::fastdds::examples::hello_world::CLIParser::subscriber_config& config, const std::string& topic_name); virtual ~HelloWorldSubscriber(); diff --git a/examples/cpp/hello_world/SubscriberWaitset.cpp b/examples/cpp/hello_world/SubscriberWaitset.cpp index 9eedb3d0988..df9f332b958 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.cpp +++ b/examples/cpp/hello_world/SubscriberWaitset.cpp @@ -37,7 +37,7 @@ using namespace eprosima::fastdds::dds; HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset( - const CLIParser::subscriber_config& config, + const eprosima::fastdds::examples::hello_world::CLIParser::subscriber_config& config, const std::string& topic_name) : participant_(nullptr) , subscriber_(nullptr) diff --git a/examples/cpp/hello_world/SubscriberWaitset.hpp b/examples/cpp/hello_world/SubscriberWaitset.hpp index b187b13d5fa..3f5317ef298 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.hpp +++ b/examples/cpp/hello_world/SubscriberWaitset.hpp @@ -38,7 +38,7 @@ class HelloWorldSubscriberWaitset public: HelloWorldSubscriberWaitset( - const CLIParser::subscriber_config& config, + const eprosima::fastdds::examples::hello_world::CLIParser::subscriber_config& config, const std::string& topic_name); virtual ~HelloWorldSubscriberWaitset(); From 1cae90a9e611deeaddab9958384152aa392b047c Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 18 Mar 2024 08:12:53 +0100 Subject: [PATCH 20/42] Refs #20543: [ARS] Fix example installation Signed-off-by: JesusPoderoso Refs #20543: Fix installation path Signed-off-by: JesusPoderoso --- CMakeLists.txt | 4 ++-- examples/cpp/hello_world/CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b8a62e2608..e76f772414b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -571,8 +571,8 @@ option(INSTALL_EXAMPLES "Install example" OFF) if(INSTALL_EXAMPLES) # Install examples install(DIRECTORY ${PROJECT_SOURCE_DIR}/examples/cpp - DESTINATION examples/ - COMPONENT examples + DESTINATION ${DATA_INSTALL_DIR}/fastdds/examples/ + COMPONENT ${DATA_INSTALL_DIR}/fastdds/examples PATTERN "examples/CMakeLists.txt" EXCLUDE ) endif() diff --git a/examples/cpp/hello_world/CMakeLists.txt b/examples/cpp/hello_world/CMakeLists.txt index 34588413662..6fb4663a046 100644 --- a/examples/cpp/hello_world/CMakeLists.txt +++ b/examples/cpp/hello_world/CMakeLists.txt @@ -46,7 +46,7 @@ target_compile_definitions(hello_world PRIVATE ) target_link_libraries(hello_world fastdds fastcdr) install(TARGETS hello_world - RUNTIME DESTINATION fastdds/examples/cpp/hello_world/${BIN_INSTALL_DIR}) + RUNTIME DESTINATION ${DATA_INSTALL_DIR}/fastdds/examples/cpp/hello_world/${BIN_INSTALL_DIR}) # Copy the XML files over to the build directory file(GLOB_RECURSE XML_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.xml) From 79d960f63a16a75340d4495fa732f39e813c56f0 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 19 Mar 2024 10:10:57 +0100 Subject: [PATCH 21/42] Refs #20543: Apply rev suggestions (4) Signed-off-by: JesusPoderoso A Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CLIParser.hpp | 51 ++++++++++++++++---------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/examples/cpp/hello_world/CLIParser.hpp b/examples/cpp/hello_world/CLIParser.hpp index b11e88c53ff..17e397a7a9f 100644 --- a/examples/cpp/hello_world/CLIParser.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -69,6 +69,7 @@ class CLIParser std::cout << "Common options:" << std::endl; std::cout << " -h, --help Print this help message" << 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 << "Subscriber options:" << std::endl; std::cout << " -w, --waitset Use waitset read condition" << std::endl; @@ -81,27 +82,30 @@ class CLIParser { hello_world_config config; + if (argc < 2) + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "missing entity argument"); + print_help(EXIT_FAILURE); + } + std::string first_argument = argv[1]; if (first_argument == "publisher" ) { config.entity = CLIParser::EntityKind::PUBLISHER; } - else if ( first_argument == "subscriber") + else if (first_argument == "subscriber") { config.entity = CLIParser::EntityKind::SUBSCRIBER; } + else if (first_argument == "-h" || first_argument == "--help") + { + print_help(EXIT_SUCCESS); + } else { - if (first_argument == "-h" || first_argument == "--help") - { - print_help(EXIT_SUCCESS); - } - else - { - EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing entity argument"); - print_help(EXIT_FAILURE); - } + EPROSIMA_LOG_ERROR(CLI_PARSER, "parsing entity argument " + first_argument); + print_help(EXIT_FAILURE); } for (int i = 2; i < argc; ++i) @@ -117,20 +121,27 @@ class CLIParser { try { - uint16_t samples = static_cast(std::stoi(argv[++i])); - if (config.entity == CLIParser::EntityKind::PUBLISHER) + int16_t input = static_cast(std::stoi(argv[++i])); + if (input < std::numeric_limits::min() || + input > std::numeric_limits::max()) { - config.pub_config.samples = samples; - } - else if (config.entity == CLIParser::EntityKind::SUBSCRIBER) - { - config.sub_config.samples = samples; + throw std::out_of_range("sample argument out of range"); } else { - EPROSIMA_LOG_ERROR(CLI_PARSER, "entity not specified for --sample argument"); - print_help(EXIT_FAILURE); - + if (config.entity == CLIParser::EntityKind::PUBLISHER) + { + config.pub_config.samples = static_cast(input); + } + else if (config.entity == CLIParser::EntityKind::SUBSCRIBER) + { + config.sub_config.samples = static_cast(input); + } + else + { + EPROSIMA_LOG_ERROR(CLI_PARSER, "entity not specified for --sample argument"); + print_help(EXIT_FAILURE); + } } } catch (const std::invalid_argument& e) From 866f593a02b2ff7b3ba4c7003b65ce69d55e8d67 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 19 Mar 2024 12:08:24 +0100 Subject: [PATCH 22/42] Refs #20543: Apply rev suggestions (5) Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/Publisher.cpp | 15 +++++++++++---- examples/cpp/hello_world/Publisher.hpp | 6 +++++- .../hello_world/{HelloWorld_main.cpp => main.cpp} | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) rename examples/cpp/hello_world/{HelloWorld_main.cpp => main.cpp} (99%) diff --git a/examples/cpp/hello_world/Publisher.cpp b/examples/cpp/hello_world/Publisher.cpp index bd885f015ca..1aeac60b9a8 100644 --- a/examples/cpp/hello_world/Publisher.cpp +++ b/examples/cpp/hello_world/Publisher.cpp @@ -42,7 +42,7 @@ HelloWorldPublisher::HelloWorldPublisher( , type_(new HelloWorldPubSubType()) , stop_(false) , matched_(0) - , samples_ (config.samples) + , samples_(config.samples) { // Set up the data type with initial values hello_.index(0); @@ -123,14 +123,19 @@ void HelloWorldPublisher::on_publication_matched( void HelloWorldPublisher::run() { - while (!is_stopped() && (samples_ == 0 || hello_.index() < samples_)) + while (!is_stopped() && ((samples_ == 0) || (hello_.index() < samples_))) { if (publish()) { std::cout << "Message: '" << hello_.message() << "' with index: '" << hello_.index() << "' SENT" << std::endl; } - std::this_thread::sleep_for(std::chrono::milliseconds(period_ms_)); + // Wait for period or stop event + std::unique_lock terminate_lock(terminate_mutex_); + terminate_cv_.wait_for(terminate_lock, std::chrono::milliseconds(period_ms_), [&]() + { + return is_stopped(); + }); } } @@ -138,12 +143,13 @@ bool HelloWorldPublisher::publish() { bool ret = false; // Wait for the data endpoints discovery - std::unique_lock matched_lock(mutex_); + std::unique_lock matched_lock(matched_mutex_); matched_cv_.wait(matched_lock, [&]() { // at least one has been discovered return ((matched_ > 0) || is_stopped()); }); + if (!is_stopped()) { hello_.index(hello_.index() + 1); @@ -161,4 +167,5 @@ void HelloWorldPublisher::stop() { stop_.store(true); matched_cv_.notify_one(); + terminate_cv_.notify_one(); } diff --git a/examples/cpp/hello_world/Publisher.hpp b/examples/cpp/hello_world/Publisher.hpp index 3af6fb40227..ba4ef5d289b 100644 --- a/examples/cpp/hello_world/Publisher.hpp +++ b/examples/cpp/hello_world/Publisher.hpp @@ -78,10 +78,14 @@ class HelloWorldPublisher : public DataWriterListener uint16_t samples_; - std::mutex mutex_; + std::mutex matched_mutex_; + + std::mutex terminate_mutex_; std::condition_variable matched_cv_; + std::condition_variable terminate_cv_; + const uint32_t period_ms_ = 100; // in ms }; diff --git a/examples/cpp/hello_world/HelloWorld_main.cpp b/examples/cpp/hello_world/main.cpp similarity index 99% rename from examples/cpp/hello_world/HelloWorld_main.cpp rename to examples/cpp/hello_world/main.cpp index 08f3220787b..41f2bd6c79b 100644 --- a/examples/cpp/hello_world/HelloWorld_main.cpp +++ b/examples/cpp/hello_world/main.cpp @@ -13,7 +13,7 @@ // limitations under the License. /** - * @file HelloWorld_main.cpp + * @file main.cpp * */ From 3a15e8f419b1053799848c3f4200c970837758c0 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 19 Mar 2024 14:58:10 +0100 Subject: [PATCH 23/42] Refs #20543: Apply rev suggestions (6) Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CLIParser.hpp | 19 +++++++++++++++ examples/cpp/hello_world/main.cpp | 32 +++++++++++--------------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/examples/cpp/hello_world/CLIParser.hpp b/examples/cpp/hello_world/CLIParser.hpp index 17e397a7a9f..85cde67881f 100644 --- a/examples/cpp/hello_world/CLIParser.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include @@ -183,6 +184,24 @@ class CLIParser return config; } + static std::string parse_signal( + int signum) + { + switch (signum) + { + case SIGINT: + return "SIGINT"; + case SIGTERM: + return "SIGTERM"; + case SIGQUIT: + return "SIGQUIT"; + case SIGHUP: + return "SIGHUP"; + default: + return "UNKNOWN SIGNAL"; + } + } + }; } // namespace hello_world diff --git a/examples/cpp/hello_world/main.cpp b/examples/cpp/hello_world/main.cpp index 41f2bd6c79b..0c37ed24184 100644 --- a/examples/cpp/hello_world/main.cpp +++ b/examples/cpp/hello_world/main.cpp @@ -31,7 +31,12 @@ using eprosima::fastdds::dds::Log; -std::function signal_handler; +std::function stop_app_handler; +void signal_handler( + int signum) +{ + stop_app_handler(signum); +} int main( int argc, @@ -122,9 +127,10 @@ int main( } } - signal_handler = [&](std::string signal) + stop_app_handler = [&](int signum) { - std::cout << "\n" << signal << " received, stopping " << entity_name << " execution." << std::endl; + std::cout << "\n" << eprosima::fastdds::examples::hello_world::CLIParser::parse_signal(signum) << + " received, stopping " << entity_name << " execution." << std::endl; switch (config.entity) { case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::PUBLISHER: @@ -152,23 +158,11 @@ int main( break; } }; - signal(SIGINT, [](int /*signum*/) - { - signal_handler("SIGINT"); - }); - signal(SIGTERM, [](int /*signum*/) - { - signal_handler("SIGTERM"); - }); + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); #ifndef _WIN32 - signal(SIGQUIT, [](int /*signum*/) - { - signal_handler("SIGQUIT"); - }); - signal(SIGHUP, [](int /*signum*/) - { - signal_handler("SIGHUP"); - }); + signal(SIGQUIT, signal_handler); + signal(SIGHUP, signal_handler); #endif // _WIN32 thread->join(); From 99d8c45baf162493985f4352e05d7c4d89114601 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Tue, 19 Mar 2024 17:10:58 +0100 Subject: [PATCH 24/42] Refs #20543: Refactor entities Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/Application.cpp | 83 ++++++++++ examples/cpp/hello_world/Application.hpp | 61 +++++++ examples/cpp/hello_world/CLIParser.hpp | 15 ++ ...bscriber.cpp => ListenerSubscriberApp.cpp} | 37 +++-- ...bscriber.hpp => ListenerSubscriberApp.hpp} | 33 ++-- .../{Publisher.cpp => PublisherApp.cpp} | 35 ++-- .../{Publisher.hpp => PublisherApp.hpp} | 43 +++-- ...erWaitset.cpp => WaitsetSubscriberApp.cpp} | 33 +++- ...erWaitset.hpp => WaitsetSubscriberApp.hpp} | 33 ++-- examples/cpp/hello_world/main.cpp | 156 ++++-------------- test/examples/test_examples.py | 2 +- 11 files changed, 333 insertions(+), 198 deletions(-) create mode 100644 examples/cpp/hello_world/Application.cpp create mode 100644 examples/cpp/hello_world/Application.hpp rename examples/cpp/hello_world/{Subscriber.cpp => ListenerSubscriberApp.cpp} (85%) rename examples/cpp/hello_world/{Subscriber.hpp => ListenerSubscriberApp.hpp} (71%) rename examples/cpp/hello_world/{Publisher.cpp => PublisherApp.cpp} (89%) rename examples/cpp/hello_world/{Publisher.hpp => PublisherApp.hpp} (72%) rename examples/cpp/hello_world/{SubscriberWaitset.cpp => WaitsetSubscriberApp.cpp} (90%) rename examples/cpp/hello_world/{SubscriberWaitset.hpp => WaitsetSubscriberApp.hpp} (70%) diff --git a/examples/cpp/hello_world/Application.cpp b/examples/cpp/hello_world/Application.cpp new file mode 100644 index 00000000000..dd300b9261d --- /dev/null +++ b/examples/cpp/hello_world/Application.cpp @@ -0,0 +1,83 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file Application.cpp + * + */ + +#include "Application.hpp" + +#include "CLIParser.hpp" +#include "ListenerSubscriberApp.hpp" +#include "PublisherApp.hpp" +#include "WaitsetSubscriberApp.hpp" + +using namespace eprosima::fastdds::dds; + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace hello_world { + +Application::Application() +{ +} + +void Application::run() +{ +} + +void Application::stop() +{ +} + +bool Application::is_stopped() +{ + return false; +} + +//! Factory method to create a publisher or subscriber +std::shared_ptr Application::make_app( + const CLIParser::hello_world_config& config, + const std::string& topic_name) +{ + std::shared_ptr entity; + switch (config.entity) + { + case CLIParser::EntityKind::PUBLISHER: + entity = std::make_shared(config.pub_config, topic_name); + break; + case CLIParser::EntityKind::SUBSCRIBER: + if (config.sub_config.use_waitset) + { + entity = std::make_shared(config.sub_config, topic_name); + } + else + { + entity = std::make_shared(config.sub_config, topic_name); + } + break; + case CLIParser::EntityKind::UNDEFINED: + default: + throw std::runtime_error("Entity initialization failed"); + break; + } + return entity; +} + +} // namespace hello_world +} // namespace examples +} // namespace fastdds +} // namespace eprosima diff --git a/examples/cpp/hello_world/Application.hpp b/examples/cpp/hello_world/Application.hpp new file mode 100644 index 00000000000..54d0525103d --- /dev/null +++ b/examples/cpp/hello_world/Application.hpp @@ -0,0 +1,61 @@ +// 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_HELLO_WORLD_APPLICATION_HPP_ +#define _FASTDDS_HELLO_WORLD_APPLICATION_HPP_ + +#include + +#include "CLIParser.hpp" + +namespace eprosima { +namespace fastdds { +namespace examples { +namespace hello_world { + +class Application +{ +public: + + Application(); + + //! Run entity (publisher or subscriber) + virtual void run(); + + //! Trigger the end of execution + virtual void stop(); + + //! Factory method to create a publisher or subscriber + static std::shared_ptr make_app( + const CLIParser::hello_world_config& config, + const std::string& topic_name); + +private: + + //! Return the current state of execution + virtual bool is_stopped(); + +}; + +} // namespace hello_world +} // namespace examples +} // namespace fastdds +} // namespace eprosima + +#endif /* _FASTDDS_HELLO_WORLD_APPLICATION_HPP_ */ diff --git a/examples/cpp/hello_world/CLIParser.hpp b/examples/cpp/hello_world/CLIParser.hpp index 85cde67881f..22634611652 100644 --- a/examples/cpp/hello_world/CLIParser.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -202,6 +202,21 @@ class CLIParser } } + static std::string parse_entity_kind( + EntityKind entity) + { + switch (entity) + { + case EntityKind::PUBLISHER: + return "Publisher"; + case EntityKind::SUBSCRIBER: + return "Subscriber"; + case EntityKind::UNDEFINED: + default: + return "Undefined entity"; + } + } + }; } // namespace hello_world diff --git a/examples/cpp/hello_world/Subscriber.cpp b/examples/cpp/hello_world/ListenerSubscriberApp.cpp similarity index 85% rename from examples/cpp/hello_world/Subscriber.cpp rename to examples/cpp/hello_world/ListenerSubscriberApp.cpp index b0cd928304b..54bf34d9f93 100644 --- a/examples/cpp/hello_world/Subscriber.cpp +++ b/examples/cpp/hello_world/ListenerSubscriberApp.cpp @@ -13,11 +13,11 @@ // limitations under the License. /** - * @file Subscriber.cpp + * @file ListenerSubscriber.cpp * */ -#include "Subscriber.hpp" +#include "ListenerSubscriberApp.hpp" #include #include @@ -31,12 +31,22 @@ #include #include +#include "CLIParser.hpp" +#include "HelloWorldPubSubTypes.h" +#include "Application.hpp" + using namespace eprosima::fastdds::dds; -HelloWorldSubscriber::HelloWorldSubscriber( - const eprosima::fastdds::examples::hello_world::CLIParser::subscriber_config& config, +namespace eprosima { +namespace fastdds { +namespace examples { +namespace hello_world { + +ListenerSubscriberApp::ListenerSubscriberApp( + const CLIParser::subscriber_config& config, const std::string& topic_name) - : participant_(nullptr) + : Application () + , participant_(nullptr) , subscriber_(nullptr) , topic_(nullptr) , reader_(nullptr) @@ -84,7 +94,7 @@ HelloWorldSubscriber::HelloWorldSubscriber( } } -HelloWorldSubscriber::~HelloWorldSubscriber() +ListenerSubscriberApp::~ListenerSubscriberApp() { if (nullptr != participant_) { @@ -96,7 +106,7 @@ HelloWorldSubscriber::~HelloWorldSubscriber() } } -void HelloWorldSubscriber::on_subscription_matched( +void ListenerSubscriberApp::on_subscription_matched( DataReader* /*reader*/, const SubscriptionMatchedStatus& info) { @@ -115,7 +125,7 @@ void HelloWorldSubscriber::on_subscription_matched( } } -void HelloWorldSubscriber::on_data_available( +void ListenerSubscriberApp::on_data_available( DataReader* reader) { SampleInfo info; @@ -135,7 +145,7 @@ void HelloWorldSubscriber::on_data_available( } } -void HelloWorldSubscriber::run() +void ListenerSubscriberApp::run() { std::unique_lock lck(terminate_cv_mtx_); terminate_cv_.wait(lck, [&] @@ -144,13 +154,18 @@ void HelloWorldSubscriber::run() }); } -bool HelloWorldSubscriber::is_stopped() +bool ListenerSubscriberApp::is_stopped() { return stop_.load(); } -void HelloWorldSubscriber::stop() +void ListenerSubscriberApp::stop() { stop_.store(true); terminate_cv_.notify_all(); } + +} // namespace hello_world +} // namespace examples +} // namespace fastdds +} // namespace eprosima diff --git a/examples/cpp/hello_world/Subscriber.hpp b/examples/cpp/hello_world/ListenerSubscriberApp.hpp similarity index 71% rename from examples/cpp/hello_world/Subscriber.hpp rename to examples/cpp/hello_world/ListenerSubscriberApp.hpp index e470bf86965..239c3f79e35 100644 --- a/examples/cpp/hello_world/Subscriber.hpp +++ b/examples/cpp/hello_world/ListenerSubscriberApp.hpp @@ -13,12 +13,12 @@ // limitations under the License. /** - * @file Subscriber.hpp + * @file ListenerSubscriberApp.hpp * */ -#ifndef _FASTDDS_HELLO_WORLD_SUBSCRIBER_HPP_ -#define _FASTDDS_HELLO_WORLD_SUBSCRIBER_HPP_ +#ifndef _FASTDDS_HELLO_WORLD_LISTENER_SUBSCRIBER_APP_HPP_ +#define _FASTDDS_HELLO_WORLD_LISTENER_SUBSCRIBER_APP_HPP_ #include @@ -28,18 +28,24 @@ #include "CLIParser.hpp" #include "HelloWorldPubSubTypes.h" +#include "Application.hpp" using namespace eprosima::fastdds::dds; -class HelloWorldSubscriber : public DataReaderListener +namespace eprosima { +namespace fastdds { +namespace examples { +namespace hello_world { + +class ListenerSubscriberApp : public Application, public DataReaderListener { public: - HelloWorldSubscriber( - const eprosima::fastdds::examples::hello_world::CLIParser::subscriber_config& config, + ListenerSubscriberApp( + const CLIParser::subscriber_config& config, const std::string& topic_name); - virtual ~HelloWorldSubscriber(); + ~ListenerSubscriberApp(); //! Subscription callback void on_data_available( @@ -51,15 +57,15 @@ class HelloWorldSubscriber : public DataReaderListener const SubscriptionMatchedStatus& info) override; //! Run subscriber - void run(); + virtual void run(); //! Trigger the end of execution - void stop(); + virtual void stop(); private: //! Return the current state of execution - bool is_stopped(); + virtual bool is_stopped(); HelloWorld hello_; @@ -84,4 +90,9 @@ class HelloWorldSubscriber : public DataReaderListener std::condition_variable terminate_cv_; }; -#endif /* _FASTDDS_HELLO_WORLD_SUBSCRIBER_HPP_ */ +} // namespace hello_world +} // namespace examples +} // namespace fastdds +} // namespace eprosima + +#endif /* _FASTDDS_HELLO_WORLD_LISTENER_SUBSCRIBER_APP_HPP_ */ diff --git a/examples/cpp/hello_world/Publisher.cpp b/examples/cpp/hello_world/PublisherApp.cpp similarity index 89% rename from examples/cpp/hello_world/Publisher.cpp rename to examples/cpp/hello_world/PublisherApp.cpp index 1aeac60b9a8..19671cb70d9 100644 --- a/examples/cpp/hello_world/Publisher.cpp +++ b/examples/cpp/hello_world/PublisherApp.cpp @@ -13,11 +13,11 @@ // limitations under the License. /** - * @file Publisher.cpp + * @file PublisherApp.cpp * */ -#include "Publisher.hpp" +#include "PublisherApp.hpp" #include #include @@ -32,17 +32,23 @@ using namespace eprosima::fastdds::dds; -HelloWorldPublisher::HelloWorldPublisher( - const eprosima::fastdds::examples::hello_world::CLIParser::publisher_config& config, +namespace eprosima { +namespace fastdds { +namespace examples { +namespace hello_world { + +PublisherApp::PublisherApp( + const CLIParser::publisher_config& config, const std::string& topic_name) - : participant_(nullptr) + : Application() + , participant_(nullptr) , publisher_(nullptr) , topic_(nullptr) , writer_(nullptr) , type_(new HelloWorldPubSubType()) - , stop_(false) , matched_(0) , samples_(config.samples) + , stop_(false) { // Set up the data type with initial values hello_.index(0); @@ -87,7 +93,7 @@ HelloWorldPublisher::HelloWorldPublisher( } } -HelloWorldPublisher::~HelloWorldPublisher() +PublisherApp::~PublisherApp() { if (nullptr != participant_) { @@ -99,7 +105,7 @@ HelloWorldPublisher::~HelloWorldPublisher() } } -void HelloWorldPublisher::on_publication_matched( +void PublisherApp::on_publication_matched( DataWriter* /*writer*/, const PublicationMatchedStatus& info) { @@ -121,7 +127,7 @@ void HelloWorldPublisher::on_publication_matched( } } -void HelloWorldPublisher::run() +void PublisherApp::run() { while (!is_stopped() && ((samples_ == 0) || (hello_.index() < samples_))) { @@ -139,7 +145,7 @@ void HelloWorldPublisher::run() } } -bool HelloWorldPublisher::publish() +bool PublisherApp::publish() { bool ret = false; // Wait for the data endpoints discovery @@ -158,14 +164,19 @@ bool HelloWorldPublisher::publish() return ret; } -bool HelloWorldPublisher::is_stopped() +bool PublisherApp::is_stopped() { return stop_.load(); } -void HelloWorldPublisher::stop() +void PublisherApp::stop() { stop_.store(true); matched_cv_.notify_one(); terminate_cv_.notify_one(); } + +} // namespace hello_world +} // namespace examples +} // namespace fastdds +} // namespace eprosima diff --git a/examples/cpp/hello_world/Publisher.hpp b/examples/cpp/hello_world/PublisherApp.hpp similarity index 72% rename from examples/cpp/hello_world/Publisher.hpp rename to examples/cpp/hello_world/PublisherApp.hpp index ba4ef5d289b..dfde8735490 100644 --- a/examples/cpp/hello_world/Publisher.hpp +++ b/examples/cpp/hello_world/PublisherApp.hpp @@ -13,12 +13,12 @@ // limitations under the License. /** - * @file Publisher.hpp + * @file PublisherApp.hpp * */ -#ifndef _FASTDDS_HELLO_WORLD_PUBLISHER_HPP_ -#define _FASTDDS_HELLO_WORLD_PUBLISHER_HPP_ +#ifndef _FASTDDS_HELLO_WORLD_PUBLISHER_APP_HPP_ +#define _FASTDDS_HELLO_WORLD_PUBLISHER_APP_HPP_ #include @@ -26,20 +26,26 @@ #include #include +#include "Application.hpp" #include "CLIParser.hpp" #include "HelloWorldPubSubTypes.h" using namespace eprosima::fastdds::dds; -class HelloWorldPublisher : public DataWriterListener +namespace eprosima { +namespace fastdds { +namespace examples { +namespace hello_world { + +class PublisherApp : public Application, public DataWriterListener { public: - HelloWorldPublisher( - const eprosima::fastdds::examples::hello_world::CLIParser::publisher_config& config, + PublisherApp( + const CLIParser::publisher_config& config, const std::string& topic_name); - ~HelloWorldPublisher() override; + ~PublisherApp(); //! Publisher matched method void on_publication_matched( @@ -47,19 +53,19 @@ class HelloWorldPublisher : public DataWriterListener const PublicationMatchedStatus& info) override; //! Run publisher - void run(); + void run() override; - //! Trigger the end of execution - void stop(); + //! Stop publisher + void stop() override; private: + //! Return the current state of execution + bool is_stopped() override; + //! Publish a sample bool publish(); - //! Return the current state of execution - bool is_stopped(); - HelloWorld hello_; DomainParticipant* participant_; @@ -72,8 +78,6 @@ class HelloWorldPublisher : public DataWriterListener TypeSupport type_; - std::atomic stop_; - int16_t matched_; uint16_t samples_; @@ -86,9 +90,14 @@ class HelloWorldPublisher : public DataWriterListener std::condition_variable terminate_cv_; + std::atomic stop_; + const uint32_t period_ms_ = 100; // in ms }; +} // namespace hello_world +} // namespace examples +} // namespace fastdds +} // namespace eprosima - -#endif /* _FASTDDS_HELLO_WORLD_PUBLISHER_HPP_ */ +#endif /* _FASTDDS_HELLO_WORLD_PUBLISHER_APP_HPP_ */ diff --git a/examples/cpp/hello_world/SubscriberWaitset.cpp b/examples/cpp/hello_world/WaitsetSubscriberApp.cpp similarity index 90% rename from examples/cpp/hello_world/SubscriberWaitset.cpp rename to examples/cpp/hello_world/WaitsetSubscriberApp.cpp index df9f332b958..0d2648bc625 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.cpp +++ b/examples/cpp/hello_world/WaitsetSubscriberApp.cpp @@ -13,11 +13,11 @@ // limitations under the License. /** - * @file SubscriberWaitset.cpp + * @file WaitsetSubscriberApp.cpp * */ -#include "SubscriberWaitset.hpp" +#include "WaitsetSubscriberApp.hpp" #include #include @@ -34,12 +34,22 @@ #include #include +#include "HelloWorldPubSubTypes.h" +#include "CLIParser.hpp" +#include "Application.hpp" + using namespace eprosima::fastdds::dds; -HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset( - const eprosima::fastdds::examples::hello_world::CLIParser::subscriber_config& config, +namespace eprosima { +namespace fastdds { +namespace examples { +namespace hello_world { + +WaitsetSubscriberApp::WaitsetSubscriberApp( + const CLIParser::subscriber_config& config, const std::string& topic_name) - : participant_(nullptr) + : Application () + , participant_(nullptr) , subscriber_(nullptr) , topic_(nullptr) , reader_(nullptr) @@ -91,7 +101,7 @@ HelloWorldSubscriberWaitset::HelloWorldSubscriberWaitset( wait_set_.attach_condition(terminate_condition_); } -HelloWorldSubscriberWaitset::~HelloWorldSubscriberWaitset() +WaitsetSubscriberApp::~WaitsetSubscriberApp() { if (nullptr != participant_) { @@ -103,7 +113,7 @@ HelloWorldSubscriberWaitset::~HelloWorldSubscriberWaitset() } } -void HelloWorldSubscriberWaitset::run() +void WaitsetSubscriberApp::run() { while (!is_stopped()) { @@ -164,13 +174,18 @@ void HelloWorldSubscriberWaitset::run() } } -bool HelloWorldSubscriberWaitset::is_stopped() +bool WaitsetSubscriberApp::is_stopped() { return stop_.load(); } -void HelloWorldSubscriberWaitset::stop() +void WaitsetSubscriberApp::stop() { stop_.store(true); terminate_condition_.set_trigger_value(true); } + +} // namespace hello_world +} // namespace examples +} // namespace fastdds +} // namespace eprosima diff --git a/examples/cpp/hello_world/SubscriberWaitset.hpp b/examples/cpp/hello_world/WaitsetSubscriberApp.hpp similarity index 70% rename from examples/cpp/hello_world/SubscriberWaitset.hpp rename to examples/cpp/hello_world/WaitsetSubscriberApp.hpp index 3f5317ef298..0c8a4bfcbb8 100644 --- a/examples/cpp/hello_world/SubscriberWaitset.hpp +++ b/examples/cpp/hello_world/WaitsetSubscriberApp.hpp @@ -13,12 +13,12 @@ // limitations under the License. /** - * @file SubscriberWaitset.hpp + * @file WaitsetSubscriberApp.hpp * */ -#ifndef _FASTDDS_HELLO_WORLD_SUBSCRIBER_WAITSET_HPP_ -#define _FASTDDS_HELLO_WORLD_SUBSCRIBER_WAITSET_HPP_ +#ifndef _FASTDDS_HELLO_WORLD_WAITSET_SUBSCRIBER_APP_HPP_ +#define _FASTDDS_HELLO_WORLD_WAITSET_SUBSCRIBER_APP_HPP_ #include #include @@ -30,29 +30,35 @@ #include "CLIParser.hpp" #include "HelloWorldPubSubTypes.h" +#include "Application.hpp" using namespace eprosima::fastdds::dds; -class HelloWorldSubscriberWaitset +namespace eprosima { +namespace fastdds { +namespace examples { +namespace hello_world { + +class WaitsetSubscriberApp : public Application { public: - HelloWorldSubscriberWaitset( - const eprosima::fastdds::examples::hello_world::CLIParser::subscriber_config& config, + WaitsetSubscriberApp( + const CLIParser::subscriber_config& config, const std::string& topic_name); - virtual ~HelloWorldSubscriberWaitset(); + ~WaitsetSubscriberApp(); //! Run subscriber - void run(); + virtual void run(); //! Trigger the end of execution - void stop(); + virtual void stop(); private: //! Return the current state of execution - bool is_stopped(); + virtual bool is_stopped(); HelloWorld hello_; @@ -77,4 +83,9 @@ class HelloWorldSubscriberWaitset GuardCondition terminate_condition_; }; -#endif /* _FASTDDS_HELLO_WORLD_SUBSCRIBER_WAITSET_HPP_ */ +} // namespace hello_world +} // namespace examples +} // namespace fastdds +} // namespace eprosima + +#endif /* _FASTDDS_HELLO_WORLD_WAITSET_SUBSCRIBER_APP_HPP_ */ diff --git a/examples/cpp/hello_world/main.cpp b/examples/cpp/hello_world/main.cpp index 0c37ed24184..f61a7c77f42 100644 --- a/examples/cpp/hello_world/main.cpp +++ b/examples/cpp/hello_world/main.cpp @@ -24,13 +24,13 @@ #include #include +#include "Application.hpp" #include "CLIParser.hpp" -#include "Publisher.hpp" -#include "Subscriber.hpp" -#include "SubscriberWaitset.hpp" using eprosima::fastdds::dds::Log; +using namespace eprosima::fastdds::examples::hello_world; + std::function stop_app_handler; void signal_handler( int signum) @@ -43,121 +43,53 @@ int main( char** argv) { auto ret = EXIT_SUCCESS; - HelloWorldPublisher* publisher = nullptr; - HelloWorldSubscriber* subscriber = nullptr; - HelloWorldSubscriberWaitset* subscriber_waitset = nullptr; - std::thread* thread = nullptr; const std::string topic_name = "hello_world_topic"; - std::string entity_name = "undefined"; - uint16_t samples = 0; - eprosima::fastdds::examples::hello_world::CLIParser::hello_world_config config = - eprosima::fastdds::examples::hello_world::CLIParser::parse_cli_options(argc, argv); + CLIParser::hello_world_config config = CLIParser::parse_cli_options(argc, argv); + uint16_t samples = config.entity == CLIParser::EntityKind::PUBLISHER ? config.pub_config.samples : + config.entity == CLIParser::EntityKind::SUBSCRIBER ? config.sub_config.samples : 0; + std::string app_name = CLIParser::parse_entity_kind(config.entity); + std::shared_ptr app; - switch (config.entity) + try { - case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::PUBLISHER: - entity_name = "Publisher"; - samples = config.pub_config.samples; - try - { - publisher = new HelloWorldPublisher(config.pub_config, topic_name); - thread = new std::thread(&HelloWorldPublisher::run, publisher); - } - catch (const std::runtime_error& e) - { - EPROSIMA_LOG_ERROR(PUBLISHER, e.what()); - ret = EXIT_FAILURE; - } - break; - case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::SUBSCRIBER: - samples = config.sub_config.samples; - if (config.sub_config.use_waitset) - { - entity_name = "Waitset Subscriber"; - try - { - subscriber_waitset = new HelloWorldSubscriberWaitset(config.sub_config, topic_name); - thread = new std::thread(&HelloWorldSubscriberWaitset::run, subscriber_waitset); - } - catch (const std::runtime_error& e) - { - EPROSIMA_LOG_ERROR(SUBSCRIBER, e.what()); - ret = EXIT_FAILURE; - } - } - else - { - entity_name = "Subscriber"; - try - { - subscriber = new HelloWorldSubscriber(config.sub_config, topic_name); - thread = new std::thread(&HelloWorldSubscriber::run, subscriber); - } - catch (const std::runtime_error& e) - { - EPROSIMA_LOG_ERROR(SUBSCRIBER_WAITSET, e.what()); - ret = EXIT_FAILURE; - } - } - break; - default: - EPROSIMA_LOG_ERROR(CLI_PARSER, "unknown entity"); - eprosima::fastdds::examples::hello_world::CLIParser::print_help(EXIT_FAILURE); - break; + app = Application::make_app(config, topic_name); + } + 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 << entity_name << " running. Please press Ctrl+C to stop the " - << entity_name << " at any time." << std::endl; + std::cout << app_name << " running. Please press Ctrl+C to stop the " + << app_name << " at any time." << std::endl; } else { switch (config.entity) { - case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::PUBLISHER: - std::cout << entity_name << " running " << samples << " samples. Please press Ctrl+C to stop the " - << entity_name << " at any time." << std::endl; + case CLIParser::EntityKind::PUBLISHER: + std::cout << app_name << " running " << samples << " samples. Please press Ctrl+C to stop the " + << app_name << " at any time." << std::endl; break; - case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::SUBSCRIBER: + case CLIParser::EntityKind::SUBSCRIBER: default: - std::cout << entity_name << " running until " << samples << " samples have been received. Please press " - << "Ctrl+C to stop the " << entity_name << " at any time." << std::endl; + std::cout << app_name << " running until " << samples << " samples have been received. Please press " + << "Ctrl+C to stop the " << app_name << " at any time." << std::endl; break; } } stop_app_handler = [&](int signum) { - std::cout << "\n" << eprosima::fastdds::examples::hello_world::CLIParser::parse_signal(signum) << - " received, stopping " << entity_name << " execution." << std::endl; - switch (config.entity) - { - case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::PUBLISHER: - if (nullptr != publisher) - { - publisher->stop(); - } - break; - case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::SUBSCRIBER: - default: - if (config.sub_config.use_waitset) - { - if (nullptr != subscriber_waitset) - { - subscriber_waitset->stop(); - } - } - else - { - if (nullptr != subscriber) - { - subscriber->stop(); - } - } - break; - } + 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 @@ -165,35 +97,7 @@ int main( signal(SIGHUP, signal_handler); #endif // _WIN32 - thread->join(); - delete thread; - switch (config.entity) - { - case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::PUBLISHER: - if (nullptr != publisher) - { - delete publisher; - } - break; - case eprosima::fastdds::examples::hello_world::CLIParser::EntityKind::SUBSCRIBER: - default: - if (config.sub_config.use_waitset) - { - if (nullptr != subscriber_waitset) - { - delete subscriber_waitset; - } - } - else - { - if (nullptr != subscriber) - { - delete subscriber; - } - } - break; - } - + thread.join(); Log::Reset(); return ret; } diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index 4d5c11ce1d5..2ec00764b3b 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -27,7 +27,7 @@ def test_basic_configuration(): if sent != 0 and received != 0 and sent * 2 == received: ret = True else: - print ('sent: ' + str(sent) + ' received: ' + str(received)) + print ('ERROR: sent: ' + str(sent) + ', but received: ' + str(received) + '(expected: ' + str(sent * 2) + ')') raise subprocess.CalledProcessError(1, '') except subprocess.CalledProcessError: From 71fdf6d6ef22905c128996062e160b11e21425e9 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 21 Mar 2024 08:00:00 +0100 Subject: [PATCH 25/42] Refs #20543: [ARS] Install XML profile Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/cpp/hello_world/CMakeLists.txt b/examples/cpp/hello_world/CMakeLists.txt index 6fb4663a046..573fd36c4f4 100644 --- a/examples/cpp/hello_world/CMakeLists.txt +++ b/examples/cpp/hello_world/CMakeLists.txt @@ -59,4 +59,6 @@ foreach(XML_FILE_COMPLETE_PATH ${XML_FILES}) ${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/hello_world/${BIN_INSTALL_DIR}) endforeach() From 02e9a0b2eb23cb6f5f9d58c64905ccdd3297d655 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 21 Mar 2024 08:08:19 +0100 Subject: [PATCH 26/42] Refs #20543: [ARS] Set EntityKind as enum class Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CLIParser.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cpp/hello_world/CLIParser.hpp b/examples/cpp/hello_world/CLIParser.hpp index 22634611652..fe1c86453ab 100644 --- a/examples/cpp/hello_world/CLIParser.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -34,7 +34,7 @@ class CLIParser CLIParser() = delete; - enum EntityKind + enum class EntityKind : uint8_t { PUBLISHER, SUBSCRIBER, From 16784704a99812af56357f5115755eefbe63c418 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 21 Mar 2024 08:11:55 +0100 Subject: [PATCH 27/42] Refs #20543: [ARS] Remove ternary operator Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/main.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/examples/cpp/hello_world/main.cpp b/examples/cpp/hello_world/main.cpp index f61a7c77f42..97e20284be3 100644 --- a/examples/cpp/hello_world/main.cpp +++ b/examples/cpp/hello_world/main.cpp @@ -45,8 +45,19 @@ int main( auto ret = EXIT_SUCCESS; const std::string topic_name = "hello_world_topic"; CLIParser::hello_world_config config = CLIParser::parse_cli_options(argc, argv); - uint16_t samples = config.entity == CLIParser::EntityKind::PUBLISHER ? config.pub_config.samples : - config.entity == CLIParser::EntityKind::SUBSCRIBER ? config.sub_config.samples : 0; + 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; From 9699cbaa103295e16dff3b93ca06e013e488b46c Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 21 Mar 2024 08:18:31 +0100 Subject: [PATCH 28/42] Refs #20543: [ARS] Simplify running message Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/main.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/examples/cpp/hello_world/main.cpp b/examples/cpp/hello_world/main.cpp index 97e20284be3..38e4cad888f 100644 --- a/examples/cpp/hello_world/main.cpp +++ b/examples/cpp/hello_world/main.cpp @@ -80,18 +80,8 @@ int main( } else { - switch (config.entity) - { - case CLIParser::EntityKind::PUBLISHER: - std::cout << app_name << " running " << samples << " samples. Please press Ctrl+C to stop the " - << app_name << " at any time." << std::endl; - break; - case CLIParser::EntityKind::SUBSCRIBER: - default: - std::cout << app_name << " running until " << samples << " samples have been received. Please press " - << "Ctrl+C to stop the " << app_name << " at any time." << std::endl; - break; - } + 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) From a32fa5479e3b9ea3c62a6601e164dc1a46dd48af Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 21 Mar 2024 08:19:48 +0100 Subject: [PATCH 29/42] Refs #20543: [ARS] Improve CLI usage message Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CLIParser.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/cpp/hello_world/CLIParser.hpp b/examples/cpp/hello_world/CLIParser.hpp index fe1c86453ab..ad12ba8d80d 100644 --- a/examples/cpp/hello_world/CLIParser.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -70,10 +70,10 @@ class CLIParser std::cout << "Common options:" << std::endl; std::cout << " -h, --help Print this help message" << std::endl; std::cout << " -s , --samples Number of samples to send or receive" << std::endl; - std::cout << " [0 <= <= 65535]" << std::endl; + std::cout << " [0 <= <= 65535]" << std::endl; std::cout << " (Default: 0 [unlimited])" << std::endl; std::cout << "Subscriber options:" << std::endl; - std::cout << " -w, --waitset Use waitset read condition" << std::endl; + std::cout << " -w, --waitset Use waitset & read condition" << std::endl; std::exit(return_code); } From 617a7f339da7f14498c8accdf49bf48d874e3ccc Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 21 Mar 2024 08:22:42 +0100 Subject: [PATCH 30/42] Refs #20543: [ARS] Improve CLI parse Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CLIParser.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/cpp/hello_world/CLIParser.hpp b/examples/cpp/hello_world/CLIParser.hpp index ad12ba8d80d..772fd594b78 100644 --- a/examples/cpp/hello_world/CLIParser.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -122,7 +122,7 @@ class CLIParser { try { - int16_t input = static_cast(std::stoi(argv[++i])); + int input = std::stoi(argv[++i]); if (input < std::numeric_limits::min() || input > std::numeric_limits::max()) { @@ -185,7 +185,7 @@ class CLIParser } static std::string parse_signal( - int signum) + const int& signum) { switch (signum) { @@ -203,7 +203,7 @@ class CLIParser } static std::string parse_entity_kind( - EntityKind entity) + const EntityKind& entity) { switch (entity) { @@ -216,7 +216,6 @@ class CLIParser return "Undefined entity"; } } - }; } // namespace hello_world From 96ff8a233691f5100dfa669b43dcdc79d68a923c Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 21 Mar 2024 08:40:08 +0100 Subject: [PATCH 31/42] Refs #20543: [ARS] Apply remain NITs Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/Application.cpp | 17 ----------------- examples/cpp/hello_world/Application.hpp | 16 ++++------------ examples/cpp/hello_world/CLIParser.hpp | 1 + .../cpp/hello_world/ListenerSubscriberApp.cpp | 6 ++---- .../cpp/hello_world/ListenerSubscriberApp.hpp | 2 +- examples/cpp/hello_world/PublisherApp.cpp | 9 +++------ examples/cpp/hello_world/PublisherApp.hpp | 6 ++---- .../cpp/hello_world/WaitsetSubscriberApp.cpp | 7 ++----- .../cpp/hello_world/WaitsetSubscriberApp.hpp | 2 +- test/examples/test_examples.py | 6 ++++-- 10 files changed, 20 insertions(+), 52 deletions(-) diff --git a/examples/cpp/hello_world/Application.cpp b/examples/cpp/hello_world/Application.cpp index dd300b9261d..fb42f74aafc 100644 --- a/examples/cpp/hello_world/Application.cpp +++ b/examples/cpp/hello_world/Application.cpp @@ -31,23 +31,6 @@ namespace fastdds { namespace examples { namespace hello_world { -Application::Application() -{ -} - -void Application::run() -{ -} - -void Application::stop() -{ -} - -bool Application::is_stopped() -{ - return false; -} - //! Factory method to create a publisher or subscriber std::shared_ptr Application::make_app( const CLIParser::hello_world_config& config, diff --git a/examples/cpp/hello_world/Application.hpp b/examples/cpp/hello_world/Application.hpp index 54d0525103d..1a2a2c70981 100644 --- a/examples/cpp/hello_world/Application.hpp +++ b/examples/cpp/hello_world/Application.hpp @@ -33,24 +33,16 @@ class Application { public: - Application(); - - //! Run entity (publisher or subscriber) - virtual void run(); + //! Run application + virtual void run() = 0; //! Trigger the end of execution - virtual void stop(); + virtual void stop() = 0; - //! Factory method to create a publisher or subscriber + //! Factory method to create applications based on configuration static std::shared_ptr make_app( const CLIParser::hello_world_config& config, const std::string& topic_name); - -private: - - //! Return the current state of execution - virtual bool is_stopped(); - }; } // namespace hello_world diff --git a/examples/cpp/hello_world/CLIParser.hpp b/examples/cpp/hello_world/CLIParser.hpp index 772fd594b78..32005d178b7 100644 --- a/examples/cpp/hello_world/CLIParser.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -216,6 +216,7 @@ class CLIParser return "Undefined entity"; } } + }; } // namespace hello_world diff --git a/examples/cpp/hello_world/ListenerSubscriberApp.cpp b/examples/cpp/hello_world/ListenerSubscriberApp.cpp index 54bf34d9f93..8f889bbcbfb 100644 --- a/examples/cpp/hello_world/ListenerSubscriberApp.cpp +++ b/examples/cpp/hello_world/ListenerSubscriberApp.cpp @@ -20,7 +20,6 @@ #include "ListenerSubscriberApp.hpp" #include -#include #include #include @@ -45,13 +44,12 @@ namespace hello_world { ListenerSubscriberApp::ListenerSubscriberApp( const CLIParser::subscriber_config& config, const std::string& topic_name) - : Application () - , participant_(nullptr) + : participant_(nullptr) , subscriber_(nullptr) , topic_(nullptr) , reader_(nullptr) , type_(new HelloWorldPubSubType()) - , samples_ (config.samples) + , samples_(config.samples) , received_samples_(0) , stop_(false) { diff --git a/examples/cpp/hello_world/ListenerSubscriberApp.hpp b/examples/cpp/hello_world/ListenerSubscriberApp.hpp index 239c3f79e35..cfe3896b3c2 100644 --- a/examples/cpp/hello_world/ListenerSubscriberApp.hpp +++ b/examples/cpp/hello_world/ListenerSubscriberApp.hpp @@ -65,7 +65,7 @@ class ListenerSubscriberApp : public Application, public DataReaderListener private: //! Return the current state of execution - virtual bool is_stopped(); + bool is_stopped(); HelloWorld hello_; diff --git a/examples/cpp/hello_world/PublisherApp.cpp b/examples/cpp/hello_world/PublisherApp.cpp index 19671cb70d9..27cd0671c5b 100644 --- a/examples/cpp/hello_world/PublisherApp.cpp +++ b/examples/cpp/hello_world/PublisherApp.cpp @@ -20,9 +20,7 @@ #include "PublisherApp.hpp" #include -#include #include -#include #include #include @@ -40,8 +38,7 @@ namespace hello_world { PublisherApp::PublisherApp( const CLIParser::publisher_config& config, const std::string& topic_name) - : Application() - , participant_(nullptr) + : participant_(nullptr) , publisher_(nullptr) , topic_(nullptr) , writer_(nullptr) @@ -137,7 +134,7 @@ void PublisherApp::run() << "' SENT" << std::endl; } // Wait for period or stop event - std::unique_lock terminate_lock(terminate_mutex_); + std::unique_lock terminate_lock(mutex_); terminate_cv_.wait_for(terminate_lock, std::chrono::milliseconds(period_ms_), [&]() { return is_stopped(); @@ -149,7 +146,7 @@ bool PublisherApp::publish() { bool ret = false; // Wait for the data endpoints discovery - std::unique_lock matched_lock(matched_mutex_); + std::unique_lock matched_lock(mutex_); matched_cv_.wait(matched_lock, [&]() { // at least one has been discovered diff --git a/examples/cpp/hello_world/PublisherApp.hpp b/examples/cpp/hello_world/PublisherApp.hpp index dfde8735490..f98e8e0b17c 100644 --- a/examples/cpp/hello_world/PublisherApp.hpp +++ b/examples/cpp/hello_world/PublisherApp.hpp @@ -61,7 +61,7 @@ class PublisherApp : public Application, public DataWriterListener private: //! Return the current state of execution - bool is_stopped() override; + bool is_stopped(); //! Publish a sample bool publish(); @@ -82,9 +82,7 @@ class PublisherApp : public Application, public DataWriterListener uint16_t samples_; - std::mutex matched_mutex_; - - std::mutex terminate_mutex_; + std::mutex mutex_; std::condition_variable matched_cv_; diff --git a/examples/cpp/hello_world/WaitsetSubscriberApp.cpp b/examples/cpp/hello_world/WaitsetSubscriberApp.cpp index 0d2648bc625..0d9343ba3e1 100644 --- a/examples/cpp/hello_world/WaitsetSubscriberApp.cpp +++ b/examples/cpp/hello_world/WaitsetSubscriberApp.cpp @@ -20,9 +20,7 @@ #include "WaitsetSubscriberApp.hpp" #include -#include #include -#include #include #include @@ -48,13 +46,12 @@ namespace hello_world { WaitsetSubscriberApp::WaitsetSubscriberApp( const CLIParser::subscriber_config& config, const std::string& topic_name) - : Application () - , participant_(nullptr) + : participant_(nullptr) , subscriber_(nullptr) , topic_(nullptr) , reader_(nullptr) , type_(new HelloWorldPubSubType()) - , samples_ (config.samples) + , samples_(config.samples) , received_samples_(0) , stop_(false) { diff --git a/examples/cpp/hello_world/WaitsetSubscriberApp.hpp b/examples/cpp/hello_world/WaitsetSubscriberApp.hpp index 0c8a4bfcbb8..9b1c0180a87 100644 --- a/examples/cpp/hello_world/WaitsetSubscriberApp.hpp +++ b/examples/cpp/hello_world/WaitsetSubscriberApp.hpp @@ -58,7 +58,7 @@ class WaitsetSubscriberApp : public Application private: //! Return the current state of execution - virtual bool is_stopped(); + bool is_stopped(); HelloWorld hello_; diff --git a/test/examples/test_examples.py b/test/examples/test_examples.py index 2ec00764b3b..6ed4ebbfaca 100644 --- a/test/examples/test_examples.py +++ b/test/examples/test_examples.py @@ -27,7 +27,8 @@ def test_basic_configuration(): if sent != 0 and received != 0 and sent * 2 == received: ret = True else: - print ('ERROR: sent: ' + str(sent) + ', but received: ' + str(received) + '(expected: ' + str(sent * 2) + ')') + print('ERROR: sent: ' + str(sent) + ', but received: ' + str(received) + + ' (expected: ' + str(sent * 2) + ')') raise subprocess.CalledProcessError(1, '') except subprocess.CalledProcessError: @@ -65,7 +66,8 @@ def test_hello_world(): if sent != 0 and received != 0 and sent * 2 == received: ret = True else: - print ('sent: ' + str(sent) + ' received: ' + str(received)) + print('ERROR: sent: ' + str(sent) + ', but received: ' + str(received) + + ' (expected: ' + str(sent * 2) + ')') raise subprocess.CalledProcessError(1, '') except subprocess.CalledProcessError: From 19e557a68b736a2d936460b5f8f95c889b490619 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 21 Mar 2024 12:05:41 +0100 Subject: [PATCH 32/42] Refs #20543: Apply rev suggestions (7) Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/PublisherApp.cpp | 5 ++--- examples/cpp/hello_world/PublisherApp.hpp | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/cpp/hello_world/PublisherApp.cpp b/examples/cpp/hello_world/PublisherApp.cpp index 27cd0671c5b..9b61b59492f 100644 --- a/examples/cpp/hello_world/PublisherApp.cpp +++ b/examples/cpp/hello_world/PublisherApp.cpp @@ -134,8 +134,8 @@ void PublisherApp::run() << "' 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_), [&]() + std::unique_lock matched_lock(mutex_); + matched_cv_.wait_for(matched_lock, std::chrono::milliseconds(period_ms_), [&]() { return is_stopped(); }); @@ -170,7 +170,6 @@ void PublisherApp::stop() { stop_.store(true); matched_cv_.notify_one(); - terminate_cv_.notify_one(); } } // namespace hello_world diff --git a/examples/cpp/hello_world/PublisherApp.hpp b/examples/cpp/hello_world/PublisherApp.hpp index f98e8e0b17c..b39094f93a3 100644 --- a/examples/cpp/hello_world/PublisherApp.hpp +++ b/examples/cpp/hello_world/PublisherApp.hpp @@ -86,8 +86,6 @@ class PublisherApp : public Application, public DataWriterListener std::condition_variable matched_cv_; - std::condition_variable terminate_cv_; - std::atomic stop_; const uint32_t period_ms_ = 100; // in ms From ec3e4429d6e7ce76dc2c052105d5f05421599b33 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 21 Mar 2024 12:09:55 +0100 Subject: [PATCH 33/42] Refs #20543: Apply rev suggestions (8) Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/PublisherApp.cpp | 14 +- examples/cpp/hello_world/PublisherApp.hpp | 2 +- examples/cpp/hello_world/README.md | 174 +++++++++------------- 3 files changed, 79 insertions(+), 111 deletions(-) diff --git a/examples/cpp/hello_world/PublisherApp.cpp b/examples/cpp/hello_world/PublisherApp.cpp index 9b61b59492f..75751ba1f3f 100644 --- a/examples/cpp/hello_world/PublisherApp.cpp +++ b/examples/cpp/hello_world/PublisherApp.cpp @@ -108,13 +108,13 @@ void PublisherApp::on_publication_matched( { if (info.current_count_change == 1) { - matched_ = info.total_count; + matched_ = info.current_count; std::cout << "Publisher matched." << std::endl; - matched_cv_.notify_one(); + cv_.notify_one(); } else if (info.current_count_change == -1) { - matched_ = info.total_count; + matched_ = info.current_count; std::cout << "Publisher unmatched." << std::endl; } else @@ -134,8 +134,8 @@ void PublisherApp::run() << "' SENT" << std::endl; } // Wait for period or stop event - std::unique_lock matched_lock(mutex_); - matched_cv_.wait_for(matched_lock, std::chrono::milliseconds(period_ms_), [&]() + std::unique_lock period_lock(mutex_); + cv_.wait_for(period_lock, std::chrono::milliseconds(period_ms_), [&]() { return is_stopped(); }); @@ -147,7 +147,7 @@ bool PublisherApp::publish() bool ret = false; // Wait for the data endpoints discovery std::unique_lock matched_lock(mutex_); - matched_cv_.wait(matched_lock, [&]() + cv_.wait(matched_lock, [&]() { // at least one has been discovered return ((matched_ > 0) || is_stopped()); @@ -169,7 +169,7 @@ bool PublisherApp::is_stopped() void PublisherApp::stop() { stop_.store(true); - matched_cv_.notify_one(); + cv_.notify_one(); } } // namespace hello_world diff --git a/examples/cpp/hello_world/PublisherApp.hpp b/examples/cpp/hello_world/PublisherApp.hpp index b39094f93a3..0b9c6b7f874 100644 --- a/examples/cpp/hello_world/PublisherApp.hpp +++ b/examples/cpp/hello_world/PublisherApp.hpp @@ -84,7 +84,7 @@ class PublisherApp : public Application, public DataWriterListener std::mutex mutex_; - std::condition_variable matched_cv_; + std::condition_variable cv_; std::atomic stop_; diff --git a/examples/cpp/hello_world/README.md b/examples/cpp/hello_world/README.md index 0b26060c244..08548ddd518 100644 --- a/examples/cpp/hello_world/README.md +++ b/examples/cpp/hello_world/README.md @@ -2,66 +2,76 @@ The *eProsima Fast DDS hello world* example is a simple application intended to demonstrate a basic DDS deployment. -## Introduction - 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 *hello world* example describes the simplest deployment of a Fast DDS publisher and subscriber. -## Example in deep +* [Description of the example](#description-of-the-example) +* [Run the example](#run-the-example) +* [Expected output](#expected-output) +* [Wait-set subscriber](#wait-set-subscriber) +* [XML profile playground](#xml-profile-playground) + +## Description of the example -Each entity of the example (publisher and subscriber) creates different nested DDS entities: domain participant, publisher & dataWriter, and subscriber & dataReader, respectively. -In both cases, the three DDS entities (domain participant, publisher/subscriber and dataWriter/dataReader) load their default configuration from the environment. +Each example application (publisher and subscriber) creates different nested DDS entities: domain participant, publisher, and data writer; and domain participant, subscriber, and data reader, respectively. +In both cases, the three DDS entities (domain participant, publisher/subscriber and data writer/data reader) load their default configuration from the environment. If the environment does not specify the expected configuration, they take the default configuration per entity. -For further information regarding the configuration environment, please refer to the *[XML profile playground](#xml-profile-playground)* subsection in the *[advanced configuration](#advanced-configuration)* section. +For further information regarding the configuration environment, please refer to the *[XML profile playground](#xml-profile-playground)* section. -The *hello world* example, together with the remain examples, would include a listening callback on the subscriber side. The subscriber will manage the new available data in the same thread as the main subscriber application. -For simplicity, the ``HelloWorldSubscriber`` implements it own callback. +This particular example includes two different subscription paradigms: listening callbacks and wait-sets: -Furthermore, this particular example includes a wait-set implementation. In contrast to implementing a listening callback, the wait-set is a mechanism where a dedicated thread waits until a status condition occurs. In that moment, that status condition triggering event would be evaluated to determine witch actions should be taken against it. +* The listening callback mechanism consists on declaring a listener class and attach it to the data reader. +When the data reader is triggered by an event, it runs the listener's method associated to that event, as a callback. + For simplicity, in this example the subscriber class inherits the listener class, and it implements it own callback. -For this example, both listening callback and wait-set implementation would run the same code and generate the same output for both triggering events: subscription matching and new data available. +* The wait-set is a mechanism where a dedicated thread waits until a status condition occurs. +In that moment, that status condition triggering event would be evaluated to determine witch actions should be taken against it. + +For this example, both listening callback and wait-set implementation would run similar code and generate equivalent output for both triggering events: subscription matching and new data available. ## Run the example -To launch this test open two different consoles. One of them will run the publisher side of the example, and the other would run the subscriber side. +To launch this example, two different terminals are required. +One of them will run the publisher example application, and the other would run the subscriber application. ### Hello world publisher -#### Ubuntu ( / MacOS ) +* Ubuntu ( / MacOS ) -```shell -user@machine:example_path$ ./hello_world publisher -Publisher running. Please press Ctrl+C to stop the Publisher at any time. -``` + ```shell + user@machine:example_path$ ./hello_world publisher + Publisher running. Please press Ctrl+C to stop the Publisher at any time. + ``` -#### Windows +* Windows -```powershell -example_path> hello_world.exe publisher -Publisher running. Please press Ctrl+C to stop the Publisher at any time. -``` + ```powershell + example_path> hello_world.exe publisher + Publisher running. Please press Ctrl+C to stop the Publisher at any time. + ``` ### Hello world subscriber -#### Ubuntu ( / MacOS ) +* Ubuntu ( / MacOS ) -```shell -user@machine:example_path$ ./hello_world subscriber -Subscriber running. Please press Ctrl+C to stop the Subscriber at any time. -``` + ```shell + user@machine:example_path$ ./hello_world subscriber + Subscriber running. Please press Ctrl+C to stop the Subscriber at any time. + ``` -#### Windows +* Windows -```powershell -example_path> hello_world.exe subscriber -Subscriber running. Please press Ctrl+C to stop the Subscriber at any time. -``` + ```powershell + example_path> hello_world.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 -It does not matter which entity is launched first, because the publisher has a condition to wait until the first match to start sending hello world samples. -The expected output on both cases is a first displayed message acknowledging they have matched, followed by the amount of samples sent or received until user press Ctrl+C. +Regardless of which application is run first, since the published will not start sending that until a subscriber is discovered, the expected output both for publishers and subscriber is a first displayed message acknowledging the match, followed by the amount of samples sent or received until Ctrl+C is pressed. ### Hello world publisher @@ -85,100 +95,58 @@ Message: 'Hello world' with index: '3' RECEIVED ... ``` -When pressed Ctrl+C to stop one of the applications, the other will detect the unmatched status, and will display an informative message. -This output example represents stopping the subscriber application. - -### Hello world publisher +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 ... +Message: 'Hello world' with index: '8' SENT Message: 'Hello world' with index: '9' SENT Message: 'Hello world' with index: '10' SENT Message: 'Hello world' with index: '11' SENT Publisher unmatched. -Message: 'Hello world' with index: '12' SENT -Message: 'Hello world' with index: '13' SENT -... ``` -### Hello world subscriber +## Wait-set subscriber -```shell -... -Message: 'Hello world' with index: '9' RECEIVED -Message: 'Hello world' with index: '10' RECEIVED -Message: 'Hello world' with index: '11' RECEIVED -user@machine:example_path$ | -``` +As described in the *[Description of the example](#description-of-the-example)* section, the *hello world* example has two listening implementations. Launching the subscriber example with the flag ``-w`` or ``--waitset`` will use the wait-set approach instead of the listening callback. -Stopping the subscriber application does not make the publisher stop sending data. But in the opposite case, stopping the publisher application will make subscriber stop receiving data. +* Ubuntu ( / MacOS ) -### Hello world publisher + ```shell + user@machine:example_path$ ./hello_world subscriber --waitset + ``` -```shell -... -Message: 'Hello world' with index: '9' SENT -Message: 'Hello world' with index: '10' SENT -Message: 'Hello world' with index: '11' SENT -user@machine:example_path$ | -``` +* Windows -### Hello world subscriber - -```shell -... -Message: 'Hello world' with index: '9' RECEIVED -Message: 'Hello world' with index: '10' RECEIVED -Message: 'Hello world' with index: '11' RECEIVED -Subscriber unmatched. -``` - -## Advanced configuration - -### Wait-set subscriber - -As described in the *[example in deep](#example-in-deep)* section, the *hello world* example has two listening implementations. Launching the subscriber example with the flag ``-w`` or ``--waitset`` will use the wait-set approach instead of the listening callback. - -#### Ubuntu ( / MacOS ) - -```shell -user@machine:example_path$ ./hello_world subscriber --waitset -``` - -#### Windows - -```powershell -example_path> hello_world.exe subscriber --waitset -``` + ```powershell + example_path> hello_world.exe subscriber --waitset + ``` The expected output is exactly the same as the described in the *[previous](#expected-output)* section. +## XML profile playground -All the example available flags can be queried running the executable with the ``-h`` or ``--help`` flag. - -### XML profile playground - -The *eProsima Fast DDS* entities can be configured through an XML profile from the environment by adding a reference the XML profiles file setting the environment variable ``FASTDDS_DEFAULT_PROFILES_FILE`` to its path. +The *eProsima Fast DDS* entities can be configured through an XML profile from the environment. +It is performed by setting the environment variable ``FASTDDS_DEFAULT_PROFILES_FILE`` with the path to the XML profiles file: -#### Ubuntu ( / MacOS ) +* Ubuntu ( / MacOS ) -```shell -user@machine:example_path$ export FASTDDS_DEFAULT_PROFILES_FILE=hello_world_profile.xml -``` + ```shell + user@machine:example_path$ export FASTDDS_DEFAULT_PROFILES_FILE=hello_world_profile.xml + ``` -#### Windows +* Windows -```powershell -example_path> set FASTDDS_DEFAULT_PROFILES_FILE=hello_world_profile.xml -``` + ```powershell + example_path> set FASTDDS_DEFAULT_PROFILES_FILE=hello_world_profile.xml + ``` -The example contains a XML profiles files with certain QoS: +The example provides with an XML profiles files with certain QoS: - Reliable reliability: avoid sample loss. -- Transient local durability: enable late-join-participants to receive previous samples if connection was lost. +- Transient local durability: enable late-join subscriber applications to receive previous samples. - Keep-last history with high depth: ensure certain amount of previous samples for late-joiners. -Applying different configurations to the entities would change the sample management behavior, among other configurations, but in any case these configurations would affect in the behavior of the *hello_world* example. -The expected output would be exactly the same as launching it with no environment configuration. - -Try your own XML profile to see how your configuration affects the *hello world* example communication. +Applying different configurations to the entities will change to a greater or lesser extent how the application behaves in relation to sample management. +In any case these settings will affect the behavior of the sample itself: the output of the sample will be the same regardless of the configuration (or lack of configuration) provided by the environment variable. From 6e282fba58bbfc6c12122dfce7470d600964196e Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 21 Mar 2024 15:48:36 +0100 Subject: [PATCH 34/42] Refs #20543: Apply rev suggestions (9) Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/README.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/examples/cpp/hello_world/README.md b/examples/cpp/hello_world/README.md index 08548ddd518..02e90eccacd 100644 --- a/examples/cpp/hello_world/README.md +++ b/examples/cpp/hello_world/README.md @@ -8,7 +8,6 @@ In this case, the *hello world* example describes the simplest deployment of a F * [Description of the example](#description-of-the-example) * [Run the example](#run-the-example) -* [Expected output](#expected-output) * [Wait-set subscriber](#wait-set-subscriber) * [XML profile playground](#xml-profile-playground) @@ -19,21 +18,21 @@ In both cases, the three DDS entities (domain participant, publisher/subscriber If the environment does not specify the expected configuration, they take the default configuration per entity. For further information regarding the configuration environment, please refer to the *[XML profile playground](#xml-profile-playground)* section. -This particular example includes two different subscription paradigms: listening callbacks and wait-sets: +This particular example includes two different subscription paradigms; i.e. listening callbacks and wait-sets: -* The listening callback mechanism consists on declaring a listener class and attach it to the data reader. -When the data reader is triggered by an event, it runs the listener's method associated to that event, as a callback. - For simplicity, in this example the subscriber class inherits the listener class, and it implements it own callback. +* The listening callback mechanism consists on declaring a listener class and attaching it to the data reader. + When the data reader is triggered by an event, it runs the listener's method associated to that event, as a callback. + For simplicity, in this example, the subscriber class inherits from the listener class, overriding the corresponding callback. * The wait-set is a mechanism where a dedicated thread waits until a status condition occurs. -In that moment, that status condition triggering event would be evaluated to determine witch actions should be taken against it. + In that moment, that status condition triggering event would be evaluated to determine witch actions should be taken against it. For this example, both listening callback and wait-set implementation would run similar code and generate equivalent output for both triggering events: subscription matching and new data available. ## Run the example To launch this example, two different terminals are required. -One of them will run the publisher example application, and the other would run the subscriber application. +One of them will run the publisher example application, and the other will run the subscriber application. ### Hello world publisher @@ -69,9 +68,9 @@ One of them will run the publisher example application, and the other would run All the example available flags can be queried running the executable with the ``-h`` or ``--help`` flag. -## Expected output +### Expected output -Regardless of which application is run first, since the published will not start sending that until a subscriber is discovered, the expected output both for publishers and subscriber is a first displayed message acknowledging the match, followed by the amount of samples sent or received until Ctrl+C is pressed. +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. ### Hello world publisher @@ -128,7 +127,7 @@ The expected output is exactly the same as the described in the *[previous](#exp ## XML profile playground The *eProsima Fast DDS* entities can be configured through an XML profile from the environment. -It is performed by setting the environment variable ``FASTDDS_DEFAULT_PROFILES_FILE`` with the path to the XML profiles file: +This is accomplished by setting the environment variable ``FASTDDS_DEFAULT_PROFILES_FILE`` to path to the XML profiles file: * Ubuntu ( / MacOS ) @@ -149,4 +148,4 @@ The example provides with an XML profiles files with certain QoS: - Keep-last history with high depth: ensure certain amount of previous samples for late-joiners. Applying different configurations to the entities will change to a greater or lesser extent how the application behaves in relation to sample management. -In any case these settings will affect the behavior of the sample itself: the output of the sample will be the same regardless of the configuration (or lack of configuration) provided by the environment variable. +Even when these settings affect the behavior of the sample management, the applications' output will be the similar. From cf1dcf89c7b05bb0d72ed5d4047920b49e74f296 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 27 Mar 2024 15:04:27 +0100 Subject: [PATCH 35/42] Refs #20543: Fix listener loop Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/ListenerSubscriberApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cpp/hello_world/ListenerSubscriberApp.cpp b/examples/cpp/hello_world/ListenerSubscriberApp.cpp index 8f889bbcbfb..4e5491ea0d5 100644 --- a/examples/cpp/hello_world/ListenerSubscriberApp.cpp +++ b/examples/cpp/hello_world/ListenerSubscriberApp.cpp @@ -127,7 +127,7 @@ void ListenerSubscriberApp::on_data_available( DataReader* reader) { SampleInfo info; - if ((!is_stopped()) && (RETCODE_OK == reader->take_next_sample(&hello_, &info))) + while ((!is_stopped()) && (RETCODE_OK == reader->take_next_sample(&hello_, &info))) { if ((info.instance_state == ALIVE_INSTANCE_STATE) && info.valid_data) { From 83bd757fb6c699ba4280bd8ffab703e9be0184a2 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 27 Mar 2024 16:03:19 +0100 Subject: [PATCH 36/42] Refs #20543: Add example in versions.md Signed-off-by: JesusPoderoso --- versions.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/versions.md b/versions.md index dd41d9af90c..4b8d004e0b1 100644 --- a/versions.md +++ b/versions.md @@ -30,6 +30,8 @@ Forthcoming * Refactor Dynamic Language Binding API according to OMG XTypes v1.3 specification. * Refactor ReturnCode complying with OMG DDS specification. * Calling `DataReader::return_loan` returns `ReturnCode_t::RETCODE_OK` both for empty sequences and for sequences that were not loaned. +* Refactor examples: + * Hello world example with wait-sets and environment XML profiles. Version 2.14.0 -------------- From 5a723d7b3952fe94ae9152b90d3eb10504a26208 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 27 Mar 2024 17:47:52 +0100 Subject: [PATCH 37/42] Refs #20543: Fix windows and mac errors and warnings Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CLIParser.hpp | 6 ++++-- examples/cpp/hello_world/ListenerSubscriberApp.hpp | 4 ++-- examples/cpp/hello_world/PublisherApp.cpp | 4 ++-- examples/cpp/hello_world/WaitsetSubscriberApp.hpp | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/cpp/hello_world/CLIParser.hpp b/examples/cpp/hello_world/CLIParser.hpp index 32005d178b7..6b6a03d912a 100644 --- a/examples/cpp/hello_world/CLIParser.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -147,12 +147,12 @@ class CLIParser } catch (const std::invalid_argument& e) { - EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid sample argument for " + arg); + EPROSIMA_LOG_ERROR(CLI_PARSER, "invalid sample argument for " + arg + ": " + e.what()); print_help(EXIT_FAILURE); } catch (const std::out_of_range& e) { - EPROSIMA_LOG_ERROR(CLI_PARSER, "sample argument out of range for " + arg); + EPROSIMA_LOG_ERROR(CLI_PARSER, "sample argument out of range for " + arg + ": " + e.what()); print_help(EXIT_FAILURE); } } @@ -193,10 +193,12 @@ class CLIParser return "SIGINT"; case SIGTERM: return "SIGTERM"; +#ifndef _WIN32 case SIGQUIT: return "SIGQUIT"; case SIGHUP: return "SIGHUP"; +#endif // _WIN32 default: return "UNKNOWN SIGNAL"; } diff --git a/examples/cpp/hello_world/ListenerSubscriberApp.hpp b/examples/cpp/hello_world/ListenerSubscriberApp.hpp index cfe3896b3c2..cd22791dec6 100644 --- a/examples/cpp/hello_world/ListenerSubscriberApp.hpp +++ b/examples/cpp/hello_world/ListenerSubscriberApp.hpp @@ -57,10 +57,10 @@ class ListenerSubscriberApp : public Application, public DataReaderListener const SubscriptionMatchedStatus& info) override; //! Run subscriber - virtual void run(); + void run() override; //! Trigger the end of execution - virtual void stop(); + void stop() override; private: diff --git a/examples/cpp/hello_world/PublisherApp.cpp b/examples/cpp/hello_world/PublisherApp.cpp index 75751ba1f3f..b2d804bbcf5 100644 --- a/examples/cpp/hello_world/PublisherApp.cpp +++ b/examples/cpp/hello_world/PublisherApp.cpp @@ -108,13 +108,13 @@ void PublisherApp::on_publication_matched( { if (info.current_count_change == 1) { - matched_ = info.current_count; + matched_ = static_cast(info.current_count); std::cout << "Publisher matched." << std::endl; cv_.notify_one(); } else if (info.current_count_change == -1) { - matched_ = info.current_count; + matched_ = static_cast(info.current_count); std::cout << "Publisher unmatched." << std::endl; } else diff --git a/examples/cpp/hello_world/WaitsetSubscriberApp.hpp b/examples/cpp/hello_world/WaitsetSubscriberApp.hpp index 9b1c0180a87..cb27cc5c016 100644 --- a/examples/cpp/hello_world/WaitsetSubscriberApp.hpp +++ b/examples/cpp/hello_world/WaitsetSubscriberApp.hpp @@ -50,10 +50,10 @@ class WaitsetSubscriberApp : public Application ~WaitsetSubscriberApp(); //! Run subscriber - virtual void run(); + void run() override; //! Trigger the end of execution - virtual void stop(); + void stop() override; private: From 1033d09bfc7528d2741701a88b9fae49a0812308 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 1 Apr 2024 08:24:44 +0200 Subject: [PATCH 38/42] Refs #20543: Fix mac warning Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/Application.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/cpp/hello_world/Application.hpp b/examples/cpp/hello_world/Application.hpp index 1a2a2c70981..9d1f01b214b 100644 --- a/examples/cpp/hello_world/Application.hpp +++ b/examples/cpp/hello_world/Application.hpp @@ -33,6 +33,9 @@ class Application { public: + //! Virtual destructor + virtual ~Application() = default; + //! Run application virtual void run() = 0; From ecd10b68ec5232b8138076432229b8927854c822 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 1 Apr 2024 12:13:01 +0200 Subject: [PATCH 39/42] Refs #20543: Fix example test run without THIRDPARTY flags Signed-off-by: JesusPoderoso --- test/examples/CMakeLists.txt | 9 +++++++++ test/examples/basic_configuration.compose.yml | 6 ++++-- test/examples/hello_world.compose.yml | 6 ++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/test/examples/CMakeLists.txt b/test/examples/CMakeLists.txt index 752b05ef2e9..9e8db93668c 100644 --- a/test/examples/CMakeLists.txt +++ b/test/examples/CMakeLists.txt @@ -25,6 +25,8 @@ endif() set(FILE_EXTENSION "") set(DOCKER_IMAGE_NAME "") set(SHELL_EXECUTABLE "") +set(TINYXML2_LIB_DIR_COMPOSE_VOLUME "") +set(TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH "") # Linux configurations if(UNIX AND NOT(APPLE) AND NOT(QNXNTO) AND NOT(ANDROID)) @@ -56,6 +58,13 @@ else() message(FATAL_ERROR "Unsupported platform") endif() +# Configure TinyXML2 library path if installed in user library path +if(NOT (TINYXML2_FROM_SOURCE OR TINYXML2_FROM_THIRDPARTY)) + get_filename_component(TINYXML2_LIB_DIR ${TINYXML2_LIBRARY} DIRECTORY) + set(TINYXML2_LIB_DIR_COMPOSE_VOLUME "- ${TINYXML2_LIB_DIR}:${TINYXML2_LIB_DIR}") + set(TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH ":${TINYXML2_LIB_DIR}") +endif() + # Find all docker compose yml files for testing file(GLOB files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.yml) diff --git a/test/examples/basic_configuration.compose.yml b/test/examples/basic_configuration.compose.yml index b6ca5c1d4c8..a07ff0196ef 100644 --- a/test/examples/basic_configuration.compose.yml +++ b/test/examples/basic_configuration.compose.yml @@ -7,9 +7,10 @@ services: volumes: - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + @TINYXML2_LIB_DIR_COMPOSE_VOLUME@ environment: # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows - LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@ + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@@TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH@ 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" @@ -18,8 +19,9 @@ services: volumes: - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + @TINYXML2_LIB_DIR_COMPOSE_VOLUME@ environment: # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows - LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@ + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@@TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH@ 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/hello_world.compose.yml b/test/examples/hello_world.compose.yml index e2ad7390b7d..8d03da8134a 100644 --- a/test/examples/hello_world.compose.yml +++ b/test/examples/hello_world.compose.yml @@ -7,9 +7,10 @@ services: volumes: - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + @TINYXML2_LIB_DIR_COMPOSE_VOLUME@ environment: # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows - LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@ + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@@TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH@ EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/hello_world@FILE_EXTENSION@ FASTDDS_DEFAULT_PROFILES_FILE: @PROJECT_BINARY_DIR@/examples/cpp/hello_world/hello_world_profile.xml command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber --waitset --samples 10" @@ -19,9 +20,10 @@ services: volumes: - @PROJECT_BINARY_DIR@:@PROJECT_BINARY_DIR@ - @fastcdr_LIB_DIR@:@fastcdr_LIB_DIR@ + @TINYXML2_LIB_DIR_COMPOSE_VOLUME@ environment: # TODO(eduponz): LD_LIBRARY_PATH is not the correct variable for Windows - LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@ + LD_LIBRARY_PATH: @PROJECT_BINARY_DIR@/src/cpp:@fastcdr_LIB_DIR@@TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH@ EXAMPLE_DIR: @PROJECT_BINARY_DIR@/examples/cpp/hello_world FASTDDS_DEFAULT_PROFILES_FILE: @PROJECT_BINARY_DIR@/examples/cpp/hello_world/hello_world_profile.xml command: @SHELL_EXECUTABLE@ -c "$${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ subscriber --samples 10 & $${EXAMPLE_DIR}/hello_world@FILE_EXTENSION@ publisher --samples 10" From 85eaadf6ddcc04f9d077a8f855e6004e48567d9e Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 1 Apr 2024 15:58:02 +0200 Subject: [PATCH 40/42] Refs #20543: Apply internal review suggestions Signed-off-by: JesusPoderoso --- test/examples/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/examples/CMakeLists.txt b/test/examples/CMakeLists.txt index 9e8db93668c..ffc1e407e2e 100644 --- a/test/examples/CMakeLists.txt +++ b/test/examples/CMakeLists.txt @@ -61,8 +61,8 @@ endif() # Configure TinyXML2 library path if installed in user library path if(NOT (TINYXML2_FROM_SOURCE OR TINYXML2_FROM_THIRDPARTY)) get_filename_component(TINYXML2_LIB_DIR ${TINYXML2_LIBRARY} DIRECTORY) - set(TINYXML2_LIB_DIR_COMPOSE_VOLUME "- ${TINYXML2_LIB_DIR}:${TINYXML2_LIB_DIR}") - set(TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH ":${TINYXML2_LIB_DIR}") + set(TINYXML2_LIB_DIR_COMPOSE_VOLUME "- ${TINYXML2_LIB_DIR}:/usr/local/shared/fastdds:ro") + set(TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH ":/usr/local/shared/fastdds") endif() # Find all docker compose yml files for testing From 4b4bf33607a462ceaf1e52e0ca949aa66acd5693 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Thu, 18 Apr 2024 15:06:23 +0200 Subject: [PATCH 41/42] Refs #20543: Apply configuration example suggestions Signed-off-by: JesusPoderoso --- examples/cpp/hello_world/CLIParser.hpp | 32 +++++++++++ .../cpp/hello_world/WaitsetSubscriberApp.cpp | 4 +- examples/cpp/hello_world/main.cpp | 54 ++++++++++--------- 3 files changed, 63 insertions(+), 27 deletions(-) diff --git a/examples/cpp/hello_world/CLIParser.hpp b/examples/cpp/hello_world/CLIParser.hpp index 6b6a03d912a..8aebfacde8d 100644 --- a/examples/cpp/hello_world/CLIParser.hpp +++ b/examples/cpp/hello_world/CLIParser.hpp @@ -34,6 +34,7 @@ class CLIParser CLIParser() = delete; + //! Entity kind enumeration enum class EntityKind : uint8_t { PUBLISHER, @@ -41,16 +42,19 @@ class CLIParser UNDEFINED }; + //! Publisher configuration structure (shared for both publisher and subscriber applications) struct publisher_config { uint16_t samples = 0; }; + //! Subscriber application configuration structure struct subscriber_config : public publisher_config { bool use_waitset = false; }; + //! Configuration structure for the application struct hello_world_config { CLIParser::EntityKind entity = CLIParser::EntityKind::UNDEFINED; @@ -58,6 +62,13 @@ class CLIParser subscriber_config sub_config; }; + /** + * @brief Print usage help message and exit with the given return code + * + * @param return_code return code to exit with + * + * @warning This method finishes the execution of the program with the input return code + */ static void print_help( uint8_t return_code) { @@ -77,6 +88,15 @@ class CLIParser std::exit(return_code); } + /** + * @brief Parse the command line options and return the configuration_config object + * + * @param argc number of arguments + * @param argv array of arguments + * @return configuration_config object with the parsed options + * + * @warning This method finishes the execution of the program if the input arguments are invalid + */ static hello_world_config parse_cli_options( int argc, char* argv[]) @@ -184,6 +204,12 @@ class CLIParser return config; } + /** + * @brief Parse the signal number into the signal name + * + * @param signum signal number + * @return std::string signal name + */ static std::string parse_signal( const int& signum) { @@ -204,6 +230,12 @@ class CLIParser } } + /** + * @brief Parse the entity kind into std::string + * + * @param entity entity kind + * @return std::string entity kind + */ static std::string parse_entity_kind( const EntityKind& entity) { diff --git a/examples/cpp/hello_world/WaitsetSubscriberApp.cpp b/examples/cpp/hello_world/WaitsetSubscriberApp.cpp index 0d9343ba3e1..ff98788651f 100644 --- a/examples/cpp/hello_world/WaitsetSubscriberApp.cpp +++ b/examples/cpp/hello_world/WaitsetSubscriberApp.cpp @@ -116,7 +116,7 @@ void WaitsetSubscriberApp::run() { ConditionSeq triggered_conditions; ReturnCode_t ret_code = wait_set_.wait(triggered_conditions, eprosima::fastrtps::c_TimeInfinite); - if (ReturnCode_t::RETCODE_OK != ret_code) + if (RETCODE_OK != ret_code) { EPROSIMA_LOG_ERROR(SUBSCRIBER_WAITSET, "Error waiting for conditions"); continue; @@ -151,7 +151,7 @@ void WaitsetSubscriberApp::run() { SampleInfo info; while ((!is_stopped()) && - (ReturnCode_t::RETCODE_OK == reader_->take_next_sample(&hello_, &info))) + (RETCODE_OK == reader_->take_next_sample(&hello_, &info))) { if ((info.instance_state == ALIVE_INSTANCE_STATE) && info.valid_data) { diff --git a/examples/cpp/hello_world/main.cpp b/examples/cpp/hello_world/main.cpp index 38e4cad888f..edfb6ff468e 100644 --- a/examples/cpp/hello_world/main.cpp +++ b/examples/cpp/hello_world/main.cpp @@ -71,34 +71,38 @@ int main( 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 + if (EXIT_FAILURE != ret) { - std::cout << app_name << " running for " << samples << " samples. Please press Ctrl+C to stop the " - << app_name << " at any time." << std::endl; + 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(); } - 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; } From 416fce28b14094f2f76a49acba754ed4379e6604 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 20 May 2024 16:39:02 +0200 Subject: [PATCH 42/42] Refs #20543: Apply rev suggestions Signed-off-by: JesusPoderoso --- test/examples/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/examples/CMakeLists.txt b/test/examples/CMakeLists.txt index ffc1e407e2e..5a3bb0bc5aa 100644 --- a/test/examples/CMakeLists.txt +++ b/test/examples/CMakeLists.txt @@ -61,8 +61,8 @@ endif() # Configure TinyXML2 library path if installed in user library path if(NOT (TINYXML2_FROM_SOURCE OR TINYXML2_FROM_THIRDPARTY)) get_filename_component(TINYXML2_LIB_DIR ${TINYXML2_LIBRARY} DIRECTORY) - set(TINYXML2_LIB_DIR_COMPOSE_VOLUME "- ${TINYXML2_LIB_DIR}:/usr/local/shared/fastdds:ro") - set(TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH ":/usr/local/shared/fastdds") + set(TINYXML2_LIB_DIR_COMPOSE_VOLUME "- ${TINYXML2_LIB_DIR}:${CMAKE_INSTALL_PREFIX}/${DATA_INSTALL_DIR}/fastdds:ro") + set(TINYXML2_LIB_DIR_COMPOSE_LD_LIBRARY_PATH ":${CMAKE_INSTALL_PREFIX}/${DATA_INSTALL_DIR}/fastdds") endif() # Find all docker compose yml files for testing