From 69cf7e31044c62e1601c07e70453dac554aedf94 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Mon, 15 Jul 2024 16:40:15 +0200 Subject: [PATCH 1/3] Refs #21324: Adapt example generation to Fast DDS examples refactor Signed-off-by: JesusPoderoso --- .../java/com/eprosima/fastdds/fastddsgen.java | 44 +++-- .../idl/templates/DDSApplicationHeader.stg | 48 +++++ .../idl/templates/DDSApplicationSource.stg | 47 +++++ .../fastdds/idl/templates/DDSPubSubMain.stg | 111 +++++++---- .../idl/templates/DDSPublisherHeader.stg | 62 +++--- .../idl/templates/DDSPublisherSource.stg | 187 ++++++++++-------- .../idl/templates/DDSSubscriberHeader.stg | 67 ++++--- .../idl/templates/DDSSubscriberSource.stg | 139 +++++++------ 8 files changed, 441 insertions(+), 264 deletions(-) create mode 100644 src/main/java/com/eprosima/fastdds/idl/templates/DDSApplicationHeader.stg create mode 100644 src/main/java/com/eprosima/fastdds/idl/templates/DDSApplicationSource.stg diff --git a/src/main/java/com/eprosima/fastdds/fastddsgen.java b/src/main/java/com/eprosima/fastdds/fastddsgen.java index 40b4c7c4..375c471b 100644 --- a/src/main/java/com/eprosima/fastdds/fastddsgen.java +++ b/src/main/java/com/eprosima/fastdds/fastddsgen.java @@ -787,6 +787,10 @@ private Project parseIDL( if (m_exampleOption != null) { + // Load Application templates + tmanager.addGroup("com/eprosima/fastdds/idl/templates/DDSApplicationHeader.stg"); + tmanager.addGroup("com/eprosima/fastdds/idl/templates/DDSApplicationSource.stg"); + // Load Publisher templates tmanager.addGroup("com/eprosima/fastdds/idl/templates/DDSPublisherHeader.stg"); tmanager.addGroup("com/eprosima/fastdds/idl/templates/DDSPublisherSource.stg"); @@ -795,7 +799,7 @@ private Project parseIDL( tmanager.addGroup("com/eprosima/fastdds/idl/templates/DDSSubscriberHeader.stg"); tmanager.addGroup("com/eprosima/fastdds/idl/templates/DDSSubscriberSource.stg"); - // Load PubSubMain template + // Load main template tmanager.addGroup("com/eprosima/fastdds/idl/templates/DDSPubSubMain.stg"); } @@ -1017,40 +1021,54 @@ private Project parseIDL( if (m_exampleOption != null) { - System.out.println("Generating Publisher files..."); + System.out.println("Generating Application files..."); + if (returnedValue = + Utils.writeFile(output_dir + ctx.getFilename() + "Application.hpp", + maintemplates.getTemplate("com/eprosima/fastdds/idl/templates/DDSApplicationHeader.stg"), m_replace)) + { + if (returnedValue = + Utils.writeFile(output_dir + ctx.getFilename() + "Application.cxx", + maintemplates.getTemplate("com/eprosima/fastdds/idl/templates/DDSApplicationSource.stg"), m_replace)) + { + project.addProjectIncludeFile(relative_dir + ctx.getFilename() + "Application.hpp"); + project.addProjectSrcFile(relative_dir + ctx.getFilename() + "Application.cxx"); + } + } + + System.out.println("Generating PublisherApp files..."); if (returnedValue = - Utils.writeFile(output_dir + ctx.getFilename() + "Publisher.hpp", + Utils.writeFile(output_dir + ctx.getFilename() + "PublisherApp.hpp", maintemplates.getTemplate("com/eprosima/fastdds/idl/templates/DDSPublisherHeader.stg"), m_replace)) { if (returnedValue = - Utils.writeFile(output_dir + ctx.getFilename() + "Publisher.cxx", + Utils.writeFile(output_dir + ctx.getFilename() + "PublisherApp.cxx", maintemplates.getTemplate("com/eprosima/fastdds/idl/templates/DDSPublisherSource.stg"), m_replace)) { - project.addProjectIncludeFile(relative_dir + ctx.getFilename() + "Publisher.hpp"); - project.addProjectSrcFile(relative_dir + ctx.getFilename() + "Publisher.cxx"); + project.addProjectIncludeFile(relative_dir + ctx.getFilename() + "PublisherApp.hpp"); + project.addProjectSrcFile(relative_dir + ctx.getFilename() + "PublisherApp.cxx"); } } - System.out.println("Generating Subscriber files..."); + System.out.println("Generating SubscriberApp files..."); if (returnedValue = - Utils.writeFile(output_dir + ctx.getFilename() + "Subscriber.hpp", + Utils.writeFile(output_dir + ctx.getFilename() + "SubscriberApp.hpp", maintemplates.getTemplate("com/eprosima/fastdds/idl/templates/DDSSubscriberHeader.stg"), m_replace)) { if (returnedValue = - Utils.writeFile(output_dir + ctx.getFilename() + "Subscriber.cxx", + Utils.writeFile(output_dir + ctx.getFilename() + "SubscriberApp.cxx", maintemplates.getTemplate("com/eprosima/fastdds/idl/templates/DDSSubscriberSource.stg"), m_replace)) { - project.addProjectIncludeFile(relative_dir + ctx.getFilename() + "Subscriber.hpp"); - project.addProjectSrcFile(relative_dir + ctx.getFilename() + "Subscriber.cxx"); + project.addProjectIncludeFile(relative_dir + ctx.getFilename() + "SubscriberApp.hpp"); + project.addProjectSrcFile(relative_dir + ctx.getFilename() + "SubscriberApp.cxx"); } } System.out.println("Generating main file..."); if (returnedValue = - Utils.writeFile(output_dir + ctx.getFilename() + "PubSubMain.cxx", + Utils.writeFile(output_dir + ctx.getFilename() + "main.cxx", maintemplates.getTemplate("com/eprosima/fastdds/idl/templates/DDSPubSubMain.stg"), m_replace)) { - project.addProjectSrcFile(relative_dir + ctx.getFilename() + "PubSubMain.cxx"); + project.addProjectSrcFile(relative_dir + ctx.getFilename() + "main.cxx"); } } } diff --git a/src/main/java/com/eprosima/fastdds/idl/templates/DDSApplicationHeader.stg b/src/main/java/com/eprosima/fastdds/idl/templates/DDSApplicationHeader.stg new file mode 100644 index 00000000..50e4e953 --- /dev/null +++ b/src/main/java/com/eprosima/fastdds/idl/templates/DDSApplicationHeader.stg @@ -0,0 +1,48 @@ +// Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +group ProtocolHeader; + +import "eprosima.stg" + +main(ctx, definitions) ::= << +$fileHeader(ctx=ctx, file=[ctx.filename, "Application.hpp"], description=["This header file contains the declaration of the application functions."])$ + +#ifndef FAST_DDS_GENERATED__$ctx.headerGuardName$APPLICATION_HPP +#define FAST_DDS_GENERATED__$ctx.headerGuardName$APPLICATION_HPP + +#include +#include + +class $ctx.filename$Application +{ +public: + + //! Virtual destructor + virtual ~$ctx.filename$Application() = default; + + //! Run application + virtual void run() = 0; + + //! Trigger the end of execution + virtual void stop() = 0; + + //! Factory method to create applications based on configuration + static std::shared_ptr<$ctx.filename$Application> make_app( + const int& domain_id, + const std::string& entity_kind); +}; + +#endif // FAST_DDS_GENERATED__$ctx.headerGuardName$APPLICATION_HPP +>> diff --git a/src/main/java/com/eprosima/fastdds/idl/templates/DDSApplicationSource.stg b/src/main/java/com/eprosima/fastdds/idl/templates/DDSApplicationSource.stg new file mode 100644 index 00000000..0957d63c --- /dev/null +++ b/src/main/java/com/eprosima/fastdds/idl/templates/DDSApplicationSource.stg @@ -0,0 +1,47 @@ +// 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. + +group ProtocolHeader; + +import "eprosima.stg" + +main(ctx, definitions) ::= << +$fileHeader(ctx=ctx, file=[ctx.filename, "Application.cxx"], description=["This file contains the implementation of the application functions."])$ + +#include "$ctx.filename$Application.hpp" + +#include "$ctx.filename$PublisherApp.hpp" +#include "$ctx.filename$SubscriberApp.hpp" + +//! Factory method to create a publisher or subscriber +std::shared_ptr<$ctx.filename$Application> $ctx.filename$Application::make_app( + const int& domain_id, + const std::string& entity_kind) +{ + std::shared_ptr<$ctx.filename$Application> entity; + if (strcmp(entity_kind.c_str(), "publisher") == 0) + { + entity = std::make_shared<$ctx.filename$PublisherApp>(domain_id); + } + else if (strcmp(entity_kind.c_str(), "subscriber") == 0) + { + entity = std::make_shared<$ctx.filename$SubscriberApp>(domain_id); + } + else + { + throw std::runtime_error("Entity initialization failed"); + } + return entity; +} +>> diff --git a/src/main/java/com/eprosima/fastdds/idl/templates/DDSPubSubMain.stg b/src/main/java/com/eprosima/fastdds/idl/templates/DDSPubSubMain.stg index 300f355e..0ad8856a 100644 --- a/src/main/java/com/eprosima/fastdds/idl/templates/DDSPubSubMain.stg +++ b/src/main/java/com/eprosima/fastdds/idl/templates/DDSPubSubMain.stg @@ -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. @@ -17,65 +17,96 @@ group ProtocolHeader; import "eprosima.stg" main(ctx, definitions) ::= << -$fileHeader(ctx=ctx, file=[ctx.filename, "PubSubMain.cpp"], description=["This file acts as a main entry point to the application."])$ +$fileHeader(ctx=ctx, file=[ctx.filename, "main.cxx"], description=["This file acts as a main entry point to the application."])$ +#include +#include +#include +#include -#include "$ctx.filename$Publisher.hpp" -#include "$ctx.filename$Subscriber.hpp" +#include -int main( - int argc, - char** argv) +#include "$ctx.filename$Application.hpp" + +using eprosima::fastdds::dds::Log; + +std::function stop_handler; +void signal_handler( + int signum) { - int type = 0; + stop_handler(signum); +} - if (argc == 2) +std::string parse_signal( + const int& signum) +{ + switch (signum) { - if (strcmp(argv[1], "publisher") == 0) - { - type = 1; - } - else if (strcmp(argv[1], "subscriber") == 0) - { - type = 2; - } + case SIGINT: + return "SIGINT"; + case SIGTERM: + return "SIGTERM"; +#ifndef _WIN32 + case SIGQUIT: + return "SIGQUIT"; + case SIGHUP: + return "SIGHUP"; +#endif // _WIN32 + default: + return "UNKNOWN SIGNAL"; } +} - if (type == 0) +int main( + int argc, + char** argv) +{ + auto ret = EXIT_SUCCESS; + int domain_id = 0; + std::shared_ptr<$ctx.filename$Application> app; + + if (argc != 2 || (strcmp(argv[1], "publisher") != 0 && strcmp(argv[1], "subscriber") != 0)) { std::cout << "Error: Incorrect arguments." << std::endl; std::cout << "Usage: " << std::endl << std::endl; std::cout << argv[0] << " publisher|subscriber" << std::endl << std::endl; - return 0; + ret = EXIT_FAILURE; } - - std::cout << "Starting " << std::endl; - - // Register the type being used - - switch (type) + else { - case 1: + try { - $ctx.filename$Publisher mypub; - if (mypub.init()) - { - mypub.run(); - } - break; + app = $ctx.filename$Application::make_app(domain_id, argv[1]); } - case 2: + catch (const std::runtime_error& e) { - $ctx.filename$Subscriber mysub; - if (mysub.init()) - { - mysub.run(); - } - break; + EPROSIMA_LOG_ERROR(app_name, e.what()); + ret = EXIT_FAILURE; } + + std::thread thread(&$ctx.filename$Application::run, app); + + std::cout << argv[1] << " running. Please press Ctrl+C to stop the " << argv[1] << " at any time." << std::endl; + + stop_handler = [&](int signum) + { + std::cout << "\n" << parse_signal(signum) << " received, stopping " << argv[1] + << " 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(); } - return 0; + Log::Reset(); + return ret; } >> diff --git a/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherHeader.stg b/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherHeader.stg index 80aa42b9..2be2d578 100644 --- a/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherHeader.stg +++ b/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherHeader.stg @@ -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. @@ -17,54 +17,60 @@ group ProtocolHeader; import "eprosima.stg" main(ctx, definitions) ::= << -$fileHeader(ctx=ctx, file=[ctx.filename, "Publisher.hpp"], description=["This header file contains the declaration of the publisher functions."])$ +$fileHeader(ctx=ctx, file=[ctx.filename, "PublisherApp.hpp"], description=["This header file contains the declaration of the publisher functions."])$ +#ifndef FAST_DDS_GENERATED__$ctx.headerGuardName$PUBLISHERAPP_HPP +#define FAST_DDS_GENERATED__$ctx.headerGuardName$PUBLISHERAPP_HPP -#ifndef FAST_DDS_GENERATED__$ctx.headerGuardName$_PUBLISHER_HPP -#define FAST_DDS_GENERATED__$ctx.headerGuardName$_PUBLISHER_HPP +#include #include -#include #include -#include #include -class $ctx.filename$Publisher +#include "$ctx.filename$Application.hpp" + +class $ctx.filename$PublisherApp : public $ctx.filename$Application, + public eprosima::fastdds::dds::DataWriterListener { public: - $ctx.filename$Publisher(); + $ctx.filename$PublisherApp( + const int& domain_id); + + ~$ctx.filename$PublisherApp(); - virtual ~$ctx.filename$Publisher(); + //! Publisher matched method + void on_publication_matched( + eprosima::fastdds::dds::DataWriter* writer, + const eprosima::fastdds::dds::PublicationMatchedStatus& info) override; - bool init(); + //! Run publisher + void run() override; - void run(); + //! Trigger the end of execution + void stop() override; private: + //! Return the current state of execution + bool is_stopped(); + + //! Publish a sample + bool publish(); + eprosima::fastdds::dds::DomainParticipant* participant_; eprosima::fastdds::dds::Publisher* publisher_; eprosima::fastdds::dds::Topic* topic_; eprosima::fastdds::dds::DataWriter* writer_; eprosima::fastdds::dds::TypeSupport type_; - - class PubListener : public eprosima::fastdds::dds::DataWriterListener - { - public: - - PubListener() = default; - - ~PubListener() override = default; - - void on_publication_matched( - eprosima::fastdds::dds::DataWriter* writer, - const eprosima::fastdds::dds::PublicationMatchedStatus& info) override; - - int matched = 0; - } - listener_; + std::condition_variable cv_; + int32_t matched_; + std::mutex mutex_; + const uint32_t period_ms_ = 100; // in ms + uint16_t samples_sent_; + std::atomic stop_; }; -#endif // FAST_DDS_GENERATED__$ctx.headerGuardName$_PUBLISHER_HPP +#endif // FAST_DDS_GENERATED__$ctx.headerGuardName$PUBLISHERAPP_HPP >> diff --git a/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherSource.stg b/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherSource.stg index 6db74e6d..df0814da 100644 --- a/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherSource.stg +++ b/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherSource.stg @@ -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. @@ -17,106 +17,109 @@ group ProtocolHeader; import "eprosima.stg" main(ctx, definitions) ::= << -$fileHeader(ctx=ctx, file=[ctx.filename, "Publisher.cpp"], description=["This file contains the implementation of the publisher functions."])$ +$fileHeader(ctx=ctx, file=[ctx.filename, "PublisherApp.cxx"], description=["This file contains the implementation of the publisher functions."])$ +#include "$ctx.filename$PublisherApp.hpp" -#include "$ctx.filename$Publisher.hpp" -#include "$ctx.filename$PubSubTypes.hpp" +#include +#include +#include +#include #include -#include -#include +#include #include +#include #include +#include -#include -#include +#include "$ctx.filename$PubSubTypes.hpp" using namespace eprosima::fastdds::dds; -$ctx.filename$Publisher::$ctx.filename$Publisher() +$ctx.filename$PublisherApp::$ctx.filename$PublisherApp( + const int& domain_id) : participant_(nullptr) , publisher_(nullptr) , topic_(nullptr) , writer_(nullptr) , type_(new $ctx.m_lastStructureTopicDataTypeName$PubSubType()) + , matched_(0) + , samples_sent_(0) + , stop_(false) { -} - -$ctx.filename$Publisher::~$ctx.filename$Publisher() -{ - 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_); -} - -bool $ctx.filename$Publisher::init() -{ - /* Initialize data_ here */ + // - //CREATE THE PARTICIPANT - DomainParticipantQos pqos; - pqos.name("Participant_pub"); - participant_ = DomainParticipantFactory::get_instance()->create_participant(0, pqos); + // Create the participant + DomainParticipantQos pqos = PARTICIPANT_QOS_DEFAULT; + pqos.name("$ctx.m_lastStructureScopedName$_pub_participant"); + participant_ = DomainParticipantFactory::get_instance()->create_participant( + domain_id, pqos, nullptr, StatusMask::none()); if (participant_ == nullptr) { - return false; + throw std::runtime_error("$ctx.m_lastStructureScopedName$ Participant initialization failed"); } - //REGISTER THE TYPE + // Register the type type_.register_type(participant_); - //CREATE THE PUBLISHER - publisher_ = participant_->create_publisher(PUBLISHER_QOS_DEFAULT, nullptr); + // Create the publisher + PublisherQos pub_qos = PUBLISHER_QOS_DEFAULT; + participant_->get_default_publisher_qos(pub_qos); + publisher_ = participant_->create_publisher(pub_qos, nullptr, StatusMask::none()); if (publisher_ == nullptr) { - return false; + throw std::runtime_error("$ctx.m_lastStructureScopedName$ Publisher initialization failed"); } - //CREATE THE TOPIC - topic_ = participant_->create_topic( - "$ctx.filename$Topic", - type_.get_type_name(), - TOPIC_QOS_DEFAULT); + // Create the topic + TopicQos topic_qos = TOPIC_QOS_DEFAULT; + participant_->get_default_topic_qos(topic_qos); + topic_ = participant_->create_topic("$ctx.filename$Topic", type_.get_type_name(), topic_qos); if (topic_ == nullptr) { - return false; + throw std::runtime_error("$ctx.m_lastStructureScopedName$ Topic initialization failed"); } - // CREATE THE WRITER - writer_ = publisher_->create_datawriter(topic_, DATAWRITER_QOS_DEFAULT, &listener_); + // Create the data writer + DataWriterQos writer_qos = DATAWRITER_QOS_DEFAULT; + publisher_->get_default_datawriter_qos(writer_qos); + writer_qos.reliability().kind = ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS; + writer_qos.durability().kind = DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS; + writer_qos.history().kind = HistoryQosPolicyKind::KEEP_ALL_HISTORY_QOS; + writer_ = publisher_->create_datawriter(topic_, writer_qos, this, StatusMask::all()); if (writer_ == nullptr) { - return false; + throw std::runtime_error("$ctx.m_lastStructureScopedName$ DataWriter initialization failed"); } +} - std::cout << "$ctx.m_lastStructureScopedName$ DataWriter created." << std::endl; - return true; +$ctx.filename$PublisherApp::~$ctx.filename$PublisherApp() +{ + if (nullptr != participant_) + { + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); + + // Delete DomainParticipant + DomainParticipantFactory::get_instance()->delete_participant(participant_); + } } -void $ctx.filename$Publisher::PubListener::on_publication_matched( - eprosima::fastdds::dds::DataWriter*, - const eprosima::fastdds::dds::PublicationMatchedStatus& info) +void $ctx.filename$PublisherApp::on_publication_matched( + DataWriter* /*writer*/, + const PublicationMatchedStatus& info) { if (info.current_count_change == 1) { - matched = info.total_count; - std::cout << "DataWriter matched." << std::endl; + matched_ = info.current_count; + std::cout << "$ctx.m_lastStructureScopedName$ Publisher matched." << std::endl; + cv_.notify_one(); } else if (info.current_count_change == -1) { - matched = info.total_count; - std::cout << "DataWriter unmatched." << std::endl; + matched_ = info.current_count; + std::cout << "$ctx.m_lastStructureScopedName$ Publisher unmatched." << std::endl; } else { @@ -125,40 +128,52 @@ void $ctx.filename$Publisher::PubListener::on_publication_matched( } } -void $ctx.filename$Publisher::run() +void $ctx.filename$PublisherApp::run() { - std::cout << "$ctx.m_lastStructureScopedName$ DataWriter waiting for DataReaders." << std::endl; - while (listener_.matched == 0) + while (!is_stopped()) { - std::this_thread::sleep_for(std::chrono::milliseconds(250)); // Sleep 250 ms + if (publish()) + { + std::cout << "Sample '" << std::to_string(++samples_sent_) << "' SENT" << std::endl; + } + // Wait for period or stop event + std::unique_lock period_lock(mutex_); + cv_.wait_for(period_lock, std::chrono::milliseconds(period_ms_), [&]() + { + return is_stopped(); + }); } +} - // Publication code - - $ctx.m_lastStructureScopedName$ st; - - /* Initialize your structure here */ - int msgsent = 0; - char ch = 'y'; - do +bool $ctx.filename$PublisherApp::publish() +{ + bool ret = false; + // Wait for the data endpoints discovery + std::unique_lock matched_lock(mutex_); + cv_.wait(matched_lock, [&]() + { + // at least one has been discovered + return ((matched_ > 0) || is_stopped()); + }); + + if (!is_stopped()) { - if (ch == 'y') - { - writer_->write(&st); - ++msgsent; - std::cout << "Sending sample, count=" << msgsent << ", send another sample?(y-yes,n-stop): "; - } - else if (ch == 'n') - { - std::cout << "Stopping execution " << std::endl; - break; - } - else - { - std::cout << "Command " << ch << " not recognized, please enter \"y/n\":"; - } - } while (std::cin \>> ch); + /* Initialize your structure here */ + $ctx.m_lastStructureScopedName$ sample_; + ret = (RETCODE_OK == writer_->write(&sample_)); + } + return ret; } +bool $ctx.filename$PublisherApp::is_stopped() +{ + return stop_.load(); +} + +void $ctx.filename$PublisherApp::stop() +{ + stop_.store(true); + cv_.notify_one(); +} >> diff --git a/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberHeader.stg b/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberHeader.stg index f61263d5..4e64e551 100644 --- a/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberHeader.stg +++ b/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberHeader.stg @@ -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. @@ -17,57 +17,60 @@ group ProtocolHeader; import "eprosima.stg" main(ctx, definitions) ::= << -$fileHeader(ctx=ctx, file=[ctx.filename, "Subscriber.hpp"], description=["This header file contains the declaration of the subscriber functions."])$ +$fileHeader(ctx=ctx, file=[ctx.filename, "SubscriberApp.hpp"], description=["This header file contains the declaration of the subscriber functions."])$ +#ifndef FAST_DDS_GENERATED__$ctx.headerGuardName$SUBSCRIBERAPP_HPP +#define FAST_DDS_GENERATED__$ctx.headerGuardName$SUBSCRIBERAPP_HPP -#ifndef FAST_DDS_GENERATED__$ctx.headerGuardName$_SUBSCRIBER_HPP -#define FAST_DDS_GENERATED__$ctx.headerGuardName$_SUBSCRIBER_HPP +#include #include -#include #include -#include +#include -class $ctx.filename$Subscriber +#include "$ctx.filename$.hpp" +#include "$ctx.filename$Application.hpp" + +class $ctx.filename$SubscriberApp : public $ctx.filename$Application, + public eprosima::fastdds::dds::DataReaderListener { public: - $ctx.filename$Subscriber(); + $ctx.filename$SubscriberApp( + const int& domain_id); + + virtual ~$ctx.filename$SubscriberApp(); + + //! Subscription callback + void on_data_available( + eprosima::fastdds::dds::DataReader* reader) override; - virtual ~$ctx.filename$Subscriber(); + //! Subscriber matched method + void on_subscription_matched( + eprosima::fastdds::dds::DataReader* reader, + const eprosima::fastdds::dds::SubscriptionMatchedStatus& info) override; - bool init(); + //! Run subscriber + void run() override; - void run(); + //! Trigger the end of execution + void stop() override; private: + //! Return the current state of execution + bool is_stopped(); + 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() = default; - - ~SubListener() override = default; - - 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; - - int matched = 0; - uint32_t samples = 0; - } - listener_; + uint16_t samples_received_; + std::atomic stop_; + mutable std::mutex terminate_cv_mtx_; + std::condition_variable terminate_cv_; }; -#endif // FAST_DDS_GENERATED__$ctx.headerGuardName$_SUBSCRIBER_HPP +#endif // FAST_DDS_GENERATED__$ctx.headerGuardName$SUBSCRIBERAPP_HPP >> diff --git a/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberSource.stg b/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberSource.stg index bc6b7243..df51bcf5 100644 --- a/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberSource.stg +++ b/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberSource.stg @@ -17,101 +17,102 @@ group ProtocolHeader; import "eprosima.stg" main(ctx, definitions) ::= << -$fileHeader(ctx=ctx, file=[ctx.filename, "Subscriber.cpp"], description=["This file contains the implementation of the subscriber functions."])$ +$fileHeader(ctx=ctx, file=[ctx.filename, "SubscriberApp.cxx"], description=["This file contains the implementation of the subscriber functions."])$ +#include "$ctx.filename$SubscriberApp.hpp" + +#include +#include + +#include #include #include +#include +#include #include #include -#include -#include "$ctx.filename$Subscriber.hpp" #include "$ctx.filename$PubSubTypes.hpp" using namespace eprosima::fastdds::dds; -$ctx.filename$Subscriber::$ctx.filename$Subscriber() +$ctx.filename$SubscriberApp::$ctx.filename$SubscriberApp( + const int& domain_id) : participant_(nullptr) , subscriber_(nullptr) , topic_(nullptr) , reader_(nullptr) , type_(new $ctx.m_lastStructureTopicDataTypeName$PubSubType()) + , samples_received_(0) + , stop_(false) { -} - -$ctx.filename$Subscriber::~$ctx.filename$Subscriber() -{ - 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_); -} - -bool $ctx.filename$Subscriber::init() -{ - //CREATE THE PARTICIPANT - DomainParticipantQos pqos; - pqos.name("Participant_sub"); - participant_ = DomainParticipantFactory::get_instance()->create_participant(0, pqos); + // Create the participant + DomainParticipantQos pqos = PARTICIPANT_QOS_DEFAULT; + pqos.name("$ctx.m_lastStructureScopedName$_sub_participant"); + participant_ = DomainParticipantFactory::get_instance()->create_participant( + domain_id, pqos, nullptr, StatusMask::none()); if (participant_ == nullptr) { - return false; + throw std::runtime_error("$ctx.m_lastStructureScopedName$ Participant initialization failed"); } - //REGISTER THE TYPE + // Register the type type_.register_type(participant_); - //CREATE THE SUBSCRIBER - subscriber_ = participant_->create_subscriber(SUBSCRIBER_QOS_DEFAULT, nullptr); + // Create the subscriber + SubscriberQos sub_qos = SUBSCRIBER_QOS_DEFAULT; + participant_->get_default_subscriber_qos(sub_qos); + subscriber_ = participant_->create_subscriber(sub_qos, nullptr, StatusMask::none()); if (subscriber_ == nullptr) { - return false; + throw std::runtime_error("$ctx.m_lastStructureScopedName$ Subscriber initialization failed"); } - //CREATE THE TOPIC - topic_ = participant_->create_topic( - "$ctx.filename$Topic", - type_.get_type_name(), - TOPIC_QOS_DEFAULT); + // Create the topic + TopicQos topic_qos = TOPIC_QOS_DEFAULT; + participant_->get_default_topic_qos(topic_qos); + topic_ = participant_->create_topic("$ctx.filename$Topic", type_.get_type_name(), topic_qos); if (topic_ == nullptr) { - return false; + throw std::runtime_error("$ctx.m_lastStructureScopedName$ Topic initialization failed"); } - //CREATE THE READER - DataReaderQos rqos = DATAREADER_QOS_DEFAULT; - rqos.reliability().kind = RELIABLE_RELIABILITY_QOS; - reader_ = subscriber_->create_datareader(topic_, rqos, &listener_); + // Create the reader + DataReaderQos reader_qos = DATAREADER_QOS_DEFAULT; + subscriber_->get_default_datareader_qos(reader_qos); + reader_qos.reliability().kind = ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS; + reader_qos.durability().kind = DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS; + reader_qos.history().kind = HistoryQosPolicyKind::KEEP_ALL_HISTORY_QOS; + reader_ = subscriber_->create_datareader(topic_, reader_qos, this, StatusMask::all()); if (reader_ == nullptr) { - return false; + throw std::runtime_error("$ctx.m_lastStructureScopedName$ DataReader initialization failed"); } +} - return true; +$ctx.filename$SubscriberApp::~$ctx.filename$SubscriberApp() +{ + if (nullptr != participant_) + { + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); + + // Delete DomainParticipant + DomainParticipantFactory::get_instance()->delete_participant(participant_); + } } -void $ctx.filename$Subscriber::SubListener::on_subscription_matched( - DataReader*, +void $ctx.filename$SubscriberApp::on_subscription_matched( + DataReader* /*reader*/, const SubscriptionMatchedStatus& info) { if (info.current_count_change == 1) { - matched = info.total_count; - std::cout << "Subscriber matched." << std::endl; + std::cout << "$ctx.m_lastStructureScopedName$ Subscriber matched." << std::endl; } else if (info.current_count_change == -1) { - matched = info.total_count; - std::cout << "Subscriber unmatched." << std::endl; + std::cout << "$ctx.m_lastStructureScopedName$ Subscriber unmatched." << std::endl; } else { @@ -120,29 +121,37 @@ void $ctx.filename$Subscriber::SubListener::on_subscription_matched( } } -void $ctx.filename$Subscriber::SubListener::on_data_available( +void $ctx.filename$SubscriberApp::on_data_available( DataReader* reader) { - // Take data - $ctx.m_lastStructureScopedName$ st; + $ctx.m_lastStructureScopedName$ sample_; SampleInfo info; - - if (reader->take_next_sample(&st, &info) == RETCODE_OK) + while ((!is_stopped()) && (RETCODE_OK == reader->take_next_sample(&sample_, &info))) { - if (info.valid_data) + if ((info.instance_state == ALIVE_INSTANCE_STATE) && info.valid_data) { - // Print your structure data here. - ++samples; - std::cout << "Sample received, count=" << samples << std::endl; + std::cout << "Sample '" << std::to_string(++samples_received_) << "' RECEIVED" << std::endl; } } } -void $ctx.filename$Subscriber::run() +void $ctx.filename$SubscriberApp::run() +{ + std::unique_lock lck(terminate_cv_mtx_); + terminate_cv_.wait(lck, [&] + { + return is_stopped(); + }); +} + +bool $ctx.filename$SubscriberApp::is_stopped() { - std::cout << "Waiting for Data, press Enter to stop the DataReader. " << std::endl; - std::cin.ignore(); - std::cout << "Shutting down the Subscriber." << std::endl; + return stop_.load(); } +void $ctx.filename$SubscriberApp::stop() +{ + stop_.store(true); + terminate_cv_.notify_all(); +} >> From e425fdfc40754ca7d696ab125987098d6abcd4f3 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 17 Jul 2024 13:13:35 +0200 Subject: [PATCH 2/3] Refs #21324: Apply rev suggestions Signed-off-by: JesusPoderoso --- .../idl/templates/DDSPublisherHeader.stg | 2 ++ .../idl/templates/DDSPublisherSource.stg | 21 ++++++++++++------- .../idl/templates/DDSSubscriberHeader.stg | 2 ++ .../idl/templates/DDSSubscriberSource.stg | 11 +++++----- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherHeader.stg b/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherHeader.stg index 2be2d578..9069169b 100644 --- a/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherHeader.stg +++ b/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherHeader.stg @@ -25,6 +25,7 @@ $fileHeader(ctx=ctx, file=[ctx.filename, "PublisherApp.hpp"], description=["Thi #include #include +#include #include #include @@ -59,6 +60,7 @@ private: //! Publish a sample bool publish(); + std::shared_ptr factory_; eprosima::fastdds::dds::DomainParticipant* participant_; eprosima::fastdds::dds::Publisher* publisher_; eprosima::fastdds::dds::Topic* topic_; diff --git a/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherSource.stg b/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherSource.stg index df0814da..3f144f6f 100644 --- a/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherSource.stg +++ b/src/main/java/com/eprosima/fastdds/idl/templates/DDSPublisherSource.stg @@ -39,7 +39,8 @@ using namespace eprosima::fastdds::dds; $ctx.filename$PublisherApp::$ctx.filename$PublisherApp( const int& domain_id) - : participant_(nullptr) + : factory_(nullptr) + , participant_(nullptr) , publisher_(nullptr) , topic_(nullptr) , writer_(nullptr) @@ -53,8 +54,8 @@ $ctx.filename$PublisherApp::$ctx.filename$PublisherApp( // Create the participant DomainParticipantQos pqos = PARTICIPANT_QOS_DEFAULT; pqos.name("$ctx.m_lastStructureScopedName$_pub_participant"); - participant_ = DomainParticipantFactory::get_instance()->create_participant( - domain_id, pqos, nullptr, StatusMask::none()); + factory_ = DomainParticipantFactory::get_shared_instance(); + participant_ = factory_->create_participant(domain_id, pqos, nullptr, StatusMask::none()); if (participant_ == nullptr) { throw std::runtime_error("$ctx.m_lastStructureScopedName$ Participant initialization failed"); @@ -102,7 +103,7 @@ $ctx.filename$PublisherApp::~$ctx.filename$PublisherApp() participant_->delete_contained_entities(); // Delete DomainParticipant - DomainParticipantFactory::get_instance()->delete_participant(participant_); + factory_->delete_participant(participant_); } } @@ -112,13 +113,19 @@ void $ctx.filename$PublisherApp::on_publication_matched( { if (info.current_count_change == 1) { - matched_ = info.current_count; + { + std::lock_guard lock(mutex_); + matched_ = info.current_count; + } std::cout << "$ctx.m_lastStructureScopedName$ Publisher matched." << std::endl; cv_.notify_one(); } else if (info.current_count_change == -1) { - matched_ = info.current_count; + { + std::lock_guard lock(mutex_); + matched_ = info.current_count; + } std::cout << "$ctx.m_lastStructureScopedName$ Publisher unmatched." << std::endl; } else @@ -138,7 +145,7 @@ void $ctx.filename$PublisherApp::run() } // Wait for period or stop event std::unique_lock period_lock(mutex_); - cv_.wait_for(period_lock, std::chrono::milliseconds(period_ms_), [&]() + cv_.wait_for(period_lock, std::chrono::milliseconds(period_ms_), [this]() { return is_stopped(); }); diff --git a/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberHeader.stg b/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberHeader.stg index 4e64e551..16a227d9 100644 --- a/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberHeader.stg +++ b/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberHeader.stg @@ -25,6 +25,7 @@ $fileHeader(ctx=ctx, file=[ctx.filename, "SubscriberApp.hpp"], description=["Th #include #include +#include #include #include @@ -61,6 +62,7 @@ private: //! Return the current state of execution bool is_stopped(); + std::shared_ptr factory_; eprosima::fastdds::dds::DomainParticipant* participant_; eprosima::fastdds::dds::Subscriber* subscriber_; eprosima::fastdds::dds::Topic* topic_; diff --git a/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberSource.stg b/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberSource.stg index df51bcf5..05ec244a 100644 --- a/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberSource.stg +++ b/src/main/java/com/eprosima/fastdds/idl/templates/DDSSubscriberSource.stg @@ -38,7 +38,8 @@ using namespace eprosima::fastdds::dds; $ctx.filename$SubscriberApp::$ctx.filename$SubscriberApp( const int& domain_id) - : participant_(nullptr) + : factory_(nullptr) + , participant_(nullptr) , subscriber_(nullptr) , topic_(nullptr) , reader_(nullptr) @@ -49,8 +50,8 @@ $ctx.filename$SubscriberApp::$ctx.filename$SubscriberApp( // Create the participant DomainParticipantQos pqos = PARTICIPANT_QOS_DEFAULT; pqos.name("$ctx.m_lastStructureScopedName$_sub_participant"); - participant_ = DomainParticipantFactory::get_instance()->create_participant( - domain_id, pqos, nullptr, StatusMask::none()); + factory_ = DomainParticipantFactory::get_shared_instance(); + participant_ = factory_->create_participant(domain_id, pqos, nullptr, StatusMask::none()); if (participant_ == nullptr) { throw std::runtime_error("$ctx.m_lastStructureScopedName$ Participant initialization failed"); @@ -98,7 +99,7 @@ $ctx.filename$SubscriberApp::~$ctx.filename$SubscriberApp() participant_->delete_contained_entities(); // Delete DomainParticipant - DomainParticipantFactory::get_instance()->delete_participant(participant_); + factory_->delete_participant(participant_); } } @@ -138,7 +139,7 @@ void $ctx.filename$SubscriberApp::on_data_available( void $ctx.filename$SubscriberApp::run() { std::unique_lock lck(terminate_cv_mtx_); - terminate_cv_.wait(lck, [&] + terminate_cv_.wait(lck, [this] { return is_stopped(); }); From 6040b4ebddc847e8f87b7ec3a72d0109d3a6d8e7 Mon Sep 17 00:00:00 2001 From: JesusPoderoso Date: Wed, 17 Jul 2024 16:32:29 +0200 Subject: [PATCH 3/3] Refs #21324: Add missing includes to build on windows Signed-off-by: JesusPoderoso --- .../com/eprosima/fastdds/idl/templates/DDSApplicationHeader.stg | 1 + .../java/com/eprosima/fastdds/idl/templates/DDSPubSubMain.stg | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/com/eprosima/fastdds/idl/templates/DDSApplicationHeader.stg b/src/main/java/com/eprosima/fastdds/idl/templates/DDSApplicationHeader.stg index 50e4e953..84479c6c 100644 --- a/src/main/java/com/eprosima/fastdds/idl/templates/DDSApplicationHeader.stg +++ b/src/main/java/com/eprosima/fastdds/idl/templates/DDSApplicationHeader.stg @@ -24,6 +24,7 @@ $fileHeader(ctx=ctx, file=[ctx.filename, "Application.hpp"], description=["This #include #include +#include class $ctx.filename$Application { diff --git a/src/main/java/com/eprosima/fastdds/idl/templates/DDSPubSubMain.stg b/src/main/java/com/eprosima/fastdds/idl/templates/DDSPubSubMain.stg index 0ad8856a..dd3dd356 100644 --- a/src/main/java/com/eprosima/fastdds/idl/templates/DDSPubSubMain.stg +++ b/src/main/java/com/eprosima/fastdds/idl/templates/DDSPubSubMain.stg @@ -20,6 +20,7 @@ main(ctx, definitions) ::= << $fileHeader(ctx=ctx, file=[ctx.filename, "main.cxx"], description=["This file acts as a main entry point to the application."])$ #include +#include #include #include #include