diff --git a/examples/C++/DDS/CMakeLists.txt b/examples/C++/DDS/CMakeLists.txt index 53ccd3c48eb..0614c6b0fb9 100644 --- a/examples/C++/DDS/CMakeLists.txt +++ b/examples/C++/DDS/CMakeLists.txt @@ -18,6 +18,7 @@ add_subdirectory(BasicConfigurationExample) add_subdirectory(Benchmark) add_subdirectory(ClientServerTest) add_subdirectory(Configurability) +add_subdirectory(ContentFilteredTopicExample) add_subdirectory(CustomListenerExample) add_subdirectory(DeadlineQoSExample) add_subdirectory(DisablePositiveACKs) diff --git a/examples/C++/DDS/ContentFilteredTopicExample/CMakeLists.txt b/examples/C++/DDS/ContentFilteredTopicExample/CMakeLists.txt new file mode 100644 index 00000000000..1ea5c1f73cb --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/CMakeLists.txt @@ -0,0 +1,47 @@ +# Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.16.3) + +project("ContentFilterTopic" VERSION 1 LANGUAGES CXX) + +# Find requirements +if(NOT fastcdr_FOUND) + find_package(fastcdr REQUIRED) +endif() + +if(NOT fastrtps_FOUND) + find_package(fastrtps REQUIRED) +endif() + +message(STATUS "Configuring ContentFilterTopic examples...") + +set(CFT_COMMON_SOURCES + ContentFilteredTopicExample_main.cpp + ContentFilteredTopicExamplePublisher.cpp + ContentFilteredTopicExampleSubscriber.cpp + HelloWorld.cxx + HelloWorldPubSubTypes.cxx + HelloWorldTypeObject.cxx + ) + +add_executable(DDSContentFilteredTopicExample ${CFT_COMMON_SOURCES}) +target_compile_definitions(DDSContentFilteredTopicExample PRIVATE + $<$>,$>:__DEBUG> + $<$:__INTERNALDEBUG> # Internal debug activated. +) +target_compile_features(DDSContentFilteredTopicExample PRIVATE cxx_std_11) +target_link_libraries(DDSContentFilteredTopicExample fastrtps fastcdr fastdds::optionparser) +install(TARGETS DDSContentFilteredTopicExample + RUNTIME DESTINATION examples/C++/DDS/ContentFilteredTopicExample/${BIN_INSTALL_DIR}) diff --git a/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExamplePublisher.cpp b/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExamplePublisher.cpp new file mode 100644 index 00000000000..431d8764161 --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExamplePublisher.cpp @@ -0,0 +1,183 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file ContentFilteredTopicExamplePublisher.cpp + * + */ + +#include "ContentFilteredTopicExamplePublisher.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace eprosima::fastdds::dds; + +bool ContentFilteredTopicExamplePublisher::init() +{ + // Initialize internal variables + matched_ = 0; + + // Initialize data sample + hello_.index(0); + hello_.message("HelloWorld"); + + // Set DomainParticipant name + DomainParticipantQos pqos; + pqos.name("Participant_pub"); + // Create DomainParticipant in domain 0 + participant_ = DomainParticipantFactory::get_instance()->create_participant(0, pqos); + if (nullptr == participant_) + { + return false; + } + + // Register the type + type_.register_type(participant_); + + // Create the Publisher + publisher_ = participant_->create_publisher(PUBLISHER_QOS_DEFAULT, nullptr); + if (nullptr == publisher_) + { + return false; + } + + // Create the Topic + topic_ = participant_->create_topic("HelloWorldTopic", type_->getName(), TOPIC_QOS_DEFAULT); + if (nullptr == topic_) + { + return false; + } + + // Create the DataWriter + writer_ = publisher_->create_datawriter(topic_, DATAWRITER_QOS_DEFAULT, this); + if (nullptr == writer_) + { + return false; + } + return true; +} + +ContentFilteredTopicExamplePublisher::~ContentFilteredTopicExamplePublisher() +{ + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); + // Delete DomainParticipant + DomainParticipantFactory::get_instance()->delete_participant(participant_); +} + +void ContentFilteredTopicExamplePublisher::on_publication_matched( + DataWriter*, + const PublicationMatchedStatus& info) +{ + // New remote DataReader discovered + if (info.current_count_change == 1) + { + matched_ = info.current_count; + first_connected_ = true; + std::cout << "Publisher matched." << std::endl; + } + // New remote DataReader undiscovered + else if (info.current_count_change == -1) + { + matched_ = info.current_count; + std::cout << "Publisher unmatched." << std::endl; + } + // Non-valid option + else + { + std::cout << info.current_count_change + << " is not a valid value for PublicationMatchedStatus current count change" << std::endl; + } +} + +void ContentFilteredTopicExamplePublisher::runThread( + uint32_t samples, + uint32_t sleep) +{ + // Publish samples continously until stopped by the user + 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)); + } + } + // Publish given number of samples + 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 ContentFilteredTopicExamplePublisher::run( + uint32_t samples, + uint32_t sleep) +{ + // Spawn publisher application thread + stop_ = false; + std::thread thread(&ContentFilteredTopicExamplePublisher::runThread, this, samples, sleep); + // Thread runs indefinitely until stopped by the user + if (samples == 0) + { + std::cout << "Publisher running. Please press enter to stop the Publisher at any time." << std::endl; + std::cin.ignore(); + stop_ = true; + } + // Thread runs only for the given samples + else + { + std::cout << "Publisher running " << samples << " samples." << std::endl; + } + thread.join(); +} + +bool ContentFilteredTopicExamplePublisher::publish( + bool wait_for_listener) +{ + // Wait until there is a matched DataReader, unless wait_for_listener flag is set to false + if (first_connected_ || !wait_for_listener || matched_ > 0) + { + // Update sample + hello_.index(hello_.index() + 1); + // Write sample + writer_->write(&hello_); + return true; + } + return false; +} diff --git a/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExamplePublisher.hpp b/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExamplePublisher.hpp new file mode 100644 index 00000000000..ff076dbb364 --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExamplePublisher.hpp @@ -0,0 +1,99 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file ContentFilteredTopicExamplePublisher.hpp + * + */ + +#ifndef _CONTENTFILTEREDTOPICEXAMPLEPUBLISHER_H_ +#define _CONTENTFILTEREDTOPICEXAMPLEPUBLISHER_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "HelloWorldPubSubTypes.h" + +//! Publisher application class +class ContentFilteredTopicExamplePublisher : public eprosima::fastdds::dds::DataWriterListener +{ +public: + + //! Constructor + ContentFilteredTopicExamplePublisher() = default; + + //! Destructor + virtual ~ContentFilteredTopicExamplePublisher(); + + //! Initialize + bool init(); + + //! Publish a sample + bool publish( + bool wait_for_listener = true); + + //! Run for the given number of samples (0 => infinite samples) + void run( + uint32_t number, + uint32_t sleep); + +private: + + //! Data type + HelloWorld hello_; + + //! DDS DomainParticipant pointer + eprosima::fastdds::dds::DomainParticipant* participant_ = nullptr; + + //! DDS Publisher pointer + eprosima::fastdds::dds::Publisher* publisher_ = nullptr; + + //! DDS Topic pointer + eprosima::fastdds::dds::Topic* topic_ = nullptr; + + //! DDS DataWriter pointer + eprosima::fastdds::dds::DataWriter* writer_ = nullptr; + + //! DDS TypeSupport pointer + eprosima::fastdds::dds::TypeSupport type_ = eprosima::fastdds::dds::TypeSupport(new HelloWorldPubSubType()); + + //! Flag to terminate application + std::atomic stop_; + + //! Number of DataReaders matched with the publisher application + std::atomic matched_; + + //! Flag set once the first subscriber is discovered and matched + std::atomic first_connected_; + + //! Discovery callback specialization when the DataWriter received discovery information from a remote DataReader + void on_publication_matched( + eprosima::fastdds::dds::DataWriter* writer, + const eprosima::fastdds::dds::PublicationMatchedStatus& info) override; + + //! Publisher application thread + void runThread( + uint32_t number, + uint32_t sleep); + +}; + +#endif // _CONTENTFILTEREDTOPICEXAMPLEPUBLISHER_H_ diff --git a/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExampleSubscriber.cpp b/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExampleSubscriber.cpp new file mode 100644 index 00000000000..d94053f5f83 --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExampleSubscriber.cpp @@ -0,0 +1,173 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file ContentFilteredTopicExampleSubscriber.cpp + * + */ + +#include "ContentFilteredTopicExampleSubscriber.hpp" + +#include +#include +#include +#include +#include +#include +#include + +using namespace eprosima::fastdds::dds; + +bool ContentFilteredTopicExampleSubscriber::init( + bool custom_filter) +{ + // Initialize internal variables + matched_ = 0; + + // Set DomainParticipant name + DomainParticipantQos pqos; + pqos.name("Participant_sub"); + // Create DomainParticipant + participant_ = DomainParticipantFactory::get_instance()->create_participant(0, pqos); + if (nullptr == participant_) + { + return false; + } + + // If using the custom filter + if (custom_filter) + { + // Register the filter factory + if (ReturnCode_t::RETCODE_OK != + participant_->register_content_filter_factory("MY_CUSTOM_FILTER", &filter_factory)) + { + return false; + } + } + + // Register the type + type_.register_type(participant_); + + // Create the Subscriber + subscriber_ = participant_->create_subscriber(SUBSCRIBER_QOS_DEFAULT, nullptr); + if (nullptr == subscriber_) + { + return false; + } + + // Create the Topic + topic_ = participant_->create_topic("HelloWorldTopic", type_->getName(), TOPIC_QOS_DEFAULT); + if (nullptr == topic_) + { + return false; + } + + // Create the ContentFilteredTopic + std::string expression; + std::vector parameters; + if (custom_filter) + { + // Custom filter: reject samples where index > parameters[0] and index < parameters[1]. + // Custom filter does not use expression. However, an empty expression disables filtering, so some expression + // must be set. + expression = " "; + parameters.push_back("3"); + parameters.push_back("5"); + filter_topic_ = + participant_->create_contentfilteredtopic("HelloWorldFilteredTopic1", topic_, expression, parameters, + "MY_CUSTOM_FILTER"); + } + else + { + // Default filter: accept samples meeting the given expression: index between the two given parameters + expression = "index between %0 and %1"; + parameters.push_back("5"); + parameters.push_back("9"); + filter_topic_ = + participant_->create_contentfilteredtopic("HelloWorldFilteredTopic1", topic_, expression, parameters); + } + if (nullptr == filter_topic_) + { + return false; + } + + // Create the DataReader + DataReaderQos rqos = DATAREADER_QOS_DEFAULT; + // In order to receive all samples, DataReader is configured as RELIABLE and TRANSIENT_LOCAL (ensure reception even + // if DataReader matching is after DataWriter one) + rqos.reliability().kind = RELIABLE_RELIABILITY_QOS; + rqos.durability().kind = TRANSIENT_LOCAL_DURABILITY_QOS; + reader_ = subscriber_->create_datareader(filter_topic_, rqos, this); + if (nullptr == reader_) + { + return false; + } + return true; +} + +ContentFilteredTopicExampleSubscriber::~ContentFilteredTopicExampleSubscriber() +{ + // Delete DDS entities contained within the DomainParticipant + participant_->delete_contained_entities(); + // Delete DomainParticipant + DomainParticipantFactory::get_instance()->delete_participant(participant_); +} + +void ContentFilteredTopicExampleSubscriber::on_subscription_matched( + DataReader*, + const SubscriptionMatchedStatus& info) +{ + // New remote DataWriter discovered + if (info.current_count_change == 1) + { + matched_ = info.current_count; + std::cout << "Subscriber matched." << std::endl; + } + // New remote DataWriter undiscovered + else if (info.current_count_change == -1) + { + matched_ = info.current_count; + std::cout << "Subscriber unmatched." << std::endl; + } + // Non-valid option + else + { + std::cout << info.current_count_change + << " is not a valid value for SubscriptionMatchedStatus current count change" << std::endl; + } +} + +void ContentFilteredTopicExampleSubscriber::on_data_available( + DataReader* reader) +{ + SampleInfo info; + // Take next sample from DataReader's history + if (ReturnCode_t::RETCODE_OK == reader->take_next_sample(&hello_, &info)) + { + // Some samples only update the instance state. Only if it is a valid sample (with data) + if (ALIVE_INSTANCE_STATE == info.instance_state) + { + samples_++; + // Print structure data + std::cout << "Message " << hello_.message() << " " << hello_.index() << " RECEIVED" << std::endl; + } + } +} + +void ContentFilteredTopicExampleSubscriber::run() +{ + // Subscriber application thread running until stopped by the user + std::cout << "Subscriber running. Please press enter to stop the Subscriber" << std::endl; + std::cin.ignore(); +} diff --git a/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExampleSubscriber.hpp b/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExampleSubscriber.hpp new file mode 100644 index 00000000000..1876fe94296 --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExampleSubscriber.hpp @@ -0,0 +1,106 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file ContentFilteredTopicExampleSubscriber.hpp + * + */ + +#ifndef _CONTENTFILTEREDTOPICEXAMPLESUBSCRIBER_HPP_ +#define _CONTENTFILTEREDTOPICEXAMPLESUBSCRIBER_HPP_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "HelloWorldPubSubTypes.h" +#include "MyCustomFilterFactory.hpp" + +// Subscriber application class +class ContentFilteredTopicExampleSubscriber : public eprosima::fastdds::dds::DataReaderListener +{ +public: + + //! Constructor + ContentFilteredTopicExampleSubscriber() = default; + + //! Destructor + virtual ~ContentFilteredTopicExampleSubscriber(); + + /** + * @brief Initialize the subscriber + * + * @param custom_filter Whether the default SQL filter or the custom defined filter is used. + * By default the SQL filter is used. + * @return true if correctly initialized. + * @return false otherwise. + */ + bool init( + bool custom_filter = false); + + //! Run the subscriber application + void run(); + +private: + + //! DDS DomainParticipant pointer + eprosima::fastdds::dds::DomainParticipant* participant_ = nullptr; + + //! DDS Subscriber pointer + eprosima::fastdds::dds::Subscriber* subscriber_ = nullptr; + + //! DDS Topic pointer + eprosima::fastdds::dds::Topic* topic_ = nullptr; + + //! DDS ContentFilteredTopic pointer + eprosima::fastdds::dds::ContentFilteredTopic* filter_topic_ = nullptr; + + //! DDS DataReader pointer + eprosima::fastdds::dds::DataReader* reader_ = nullptr; + + //! DDS TypeSupport pointer + eprosima::fastdds::dds::TypeSupport type_ = eprosima::fastdds::dds::TypeSupport(new HelloWorldPubSubType()); + + //! Custom filter factory + MyCustomFilterFactory filter_factory; + + //! Data type + HelloWorld hello_; + + //! Number of DataWriters matched with the subscriber application + std::atomic matched_; + + //! Number of received samples + uint32_t samples_ = 0; + + //! Callback specialization when data is notified to the DataReader + void on_data_available( + eprosima::fastdds::dds::DataReader* reader) override; + + //! Discovery callback specialization when the DataReader receives discovery information from a remote DataWriter + void on_subscription_matched( + eprosima::fastdds::dds::DataReader* reader, + const eprosima::fastdds::dds::SubscriptionMatchedStatus& info) override; + +}; + +#endif // _CONTENTFILTEREDTOPICEXAMPLESUBSCRIBER_HPP_ diff --git a/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExample_main.cpp b/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExample_main.cpp new file mode 100644 index 00000000000..06881a6775d --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/ContentFilteredTopicExample_main.cpp @@ -0,0 +1,243 @@ +// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file CustomFilter_main.cpp + * + */ + +#include + +#include +#include + +#include "ContentFilteredTopicExamplePublisher.hpp" +#include "ContentFilteredTopicExampleSubscriber.hpp" + +using eprosima::fastdds::dds::Log; +namespace option = eprosima::option; + +// Argument checkers +struct Arg : public option::Arg +{ + // Auxiliary method for printing errors while checking arguments + 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); + } + + // Argument checker for numeric options + static option::ArgStatus Numeric( + const option::Option& option, + bool msg) + { + char* endptr = 0; + if (nullptr != option.arg) + { + 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; + } + + // Argument checker for string options + static option::ArgStatus String( + const option::Option& option, + bool msg) + { + if (nullptr != option.arg) + { + return option::ARG_OK; + } + if (msg) + { + print_error("Option '", option, "' requires a string argument\n"); + } + return option::ARG_ILLEGAL; + } + +}; + +// Possible options +enum optionIndex +{ + UNKNOWN_OPTION, + HELP, + PUBLISHER, + SUBSCRIBER, + SAMPLES, + INTERVAL, + FILTER +}; + +// Usage description +const option::Descriptor usage[] = { + { UNKNOWN_OPTION, 0, "", "", Arg::None, + "Usage: ContentFilteredTopicExample [--publisher|--subscriber] [OPTIONS]\n\nGeneral options:" }, + { HELP, 0, "h", "help", Arg::None, " -h\t--help\tProduce help message." }, + { PUBLISHER, 0, "", "publisher", Arg::None, "\t--publisher\tLaunch publisher application." }, + { SUBSCRIBER, 0, "", "subscriber", Arg::None, "\t--subscriber\tLaunch subscriber application." }, + + { UNKNOWN_OPTION, 0, "", "", Arg::None, "\nPublisher options:" }, + { SAMPLES, 0, "s", "samples", Arg::Numeric, + " -s \t--samples=\tNumber of samples (Default: 0 => infinite samples)." }, + { INTERVAL, 0, "i", "interval", Arg::Numeric, + " -i \t--interval=\tTime between samples in milliseconds (Default: 100 ms)." }, + + { UNKNOWN_OPTION, 0, "", "", Arg::None, "\nSubscriber options:" }, + { FILTER, 0, "f", "filter", Arg::String, + " -f \t--filter=\tKind of Content Filter to use (Default: DDS SQL default filter" + }, + + { 0, 0, 0, 0, 0, 0 } +}; + +int main( + int argc, + char** argv) +{ + // Parse arguments using optionparser + // skip program name argv[0] if present (optionparser limitation) + argc -= (argc > 0); + argv += (argc > 0); + option::Stats stats(usage, argc, argv); + std::vector options(stats.options_max); + std::vector buffer(stats.buffer_max); + option::Parser parse(usage, argc, argv, &options[0], &buffer[0]); + if (parse.error()) + { + return 1; + } + + // If help option selected, print usage description and exit + if (options[HELP]) + { + option::printUsage(fwrite, stdout, usage); + return 0; + } + // If option is not recognized, print usage description and exit with error code + else if (options[UNKNOWN_OPTION]) + { + std::cerr << "ERROR: " << options[UNKNOWN_OPTION].name << " is not a valid argument." << std::endl; + option::printUsage(fwrite, stdout, usage); + return 1; + } + + // Initialize variables with default values + int type = 1; + int count = 0; + int sleep = 100; + bool custom_filter = false; + // If both publisher and subscriber options are selected, print usage description and exit with error code + if (options[PUBLISHER] && options[SUBSCRIBER]) + { + std::cerr << "ERROR: select either '--publisher' or '--subscriber' option" << std::endl; + option::printUsage(fwrite, stdout, usage); + return 1; + } + // Publisher option selected + else if (options[PUBLISHER]) + { + // If any subscriber option is selected, print usage description and exit with error code + if (options[FILTER]) + { + std::cerr << "ERROR: option filter is a subscriber option" << std::endl; + option::printUsage(fwrite, stdout, usage); + return 1; + } + // If any optional publisher option is selected, set the corresponding value + if (options[SAMPLES]) + { + count = strtol(options[SAMPLES].arg, nullptr, 10); + } + if (options[INTERVAL]) + { + sleep = strtol(options[INTERVAL].arg, nullptr, 10); + } + } + // Subscriber option selected + else if (options[SUBSCRIBER]) + { + type = 2; + // If any publisher option is selected, print usage description and exit with error code + if (options[SAMPLES] || options[INTERVAL]) + { + std::cerr << "ERROR: options samples and interval are publisher options" << std::endl; + option::printUsage(fwrite, stdout, usage); + return 1; + } + // If any optional subscriber option is selected, set the corresponding value + if (options[FILTER]) + { + if (0 == strcmp(options[FILTER].arg, "custom")) + { + custom_filter = true; + } + // If filter option does not have one of the expected values, print usage description and exit with error + // code + else if (0 != strcmp(options[FILTER].arg, "default")) + { + std::cerr << "ERROR: filter option should be either 'custom' or 'default'" << std::endl; + option::printUsage(fwrite, stdout, usage); + return 1; + } + } + } + // If no publisher or subscriber option has been selected, print usage description and exit with error code + else + { + std::cerr << "ERROR: select either '--publisher' or '--subscriber' option" << std::endl; + option::printUsage(fwrite, stdout, usage); + return 1; + } + + switch (type) + { + case 1: + { + // Initialize and run publisher application + ContentFilteredTopicExamplePublisher mypub; + if (mypub.init()) + { + mypub.run(static_cast(count), static_cast(sleep)); + } + break; + } + case 2: + { + // Initialize and run subscriber application + ContentFilteredTopicExampleSubscriber mysub; + if (mysub.init(custom_filter)) + { + mysub.run(); + } + break; + } + } + // Flush Fast DDS Log before closing application + Log::Reset(); + return 0; +} diff --git a/examples/C++/DDS/ContentFilteredTopicExample/HelloWorld.cxx b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorld.cxx new file mode 100644 index 00000000000..7cdda355f4f --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorld.cxx @@ -0,0 +1,239 @@ +// 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 HelloWorld.cpp + * This source file contains the definition of the described types in the IDL file. + * + * This file was generated by the tool gen. + */ + +#ifdef _WIN32 +// Remove linker warning LNK4221 on Visual Studio +namespace { +char dummy; +} // namespace +#endif // _WIN32 + +#include "HelloWorld.h" +#include "HelloWorldTypeObject.h" +#include + +#include +using namespace eprosima::fastcdr::exception; + +#include + +HelloWorld::HelloWorld() +{ + // m_index com.eprosima.idl.parser.typecode.PrimitiveTypeCode@1f36e637 + m_index = 0; + // m_message com.eprosima.idl.parser.typecode.StringTypeCode@578486a3 + m_message =""; + + // Just to register all known types + registerHelloWorldTypes(); +} + +HelloWorld::~HelloWorld() +{ + + +} + +HelloWorld::HelloWorld( + const HelloWorld& x) +{ + m_index = x.m_index; + m_message = x.m_message; +} + +HelloWorld::HelloWorld( + HelloWorld&& x) +{ + m_index = x.m_index; + m_message = std::move(x.m_message); +} + +HelloWorld& HelloWorld::operator =( + const HelloWorld& x) +{ + + m_index = x.m_index; + m_message = x.m_message; + + return *this; +} + +HelloWorld& HelloWorld::operator =( + HelloWorld&& x) +{ + + m_index = x.m_index; + m_message = std::move(x.m_message); + + return *this; +} + +bool HelloWorld::operator ==( + const HelloWorld& x) const +{ + + return (m_index == x.m_index && m_message == x.m_message); +} + +bool HelloWorld::operator !=( + const HelloWorld& x) const +{ + return !(*this == x); +} + +size_t HelloWorld::getMaxCdrSerializedSize( + size_t current_alignment) +{ + size_t initial_alignment = current_alignment; + + + current_alignment += 4 + eprosima::fastcdr::Cdr::alignment(current_alignment, 4); + + + current_alignment += 4 + eprosima::fastcdr::Cdr::alignment(current_alignment, 4) + 255 + 1; + + + return current_alignment - initial_alignment; +} + +size_t HelloWorld::getCdrSerializedSize( + const HelloWorld& data, + size_t current_alignment) +{ + (void)data; + size_t initial_alignment = current_alignment; + + + current_alignment += 4 + eprosima::fastcdr::Cdr::alignment(current_alignment, 4); + + + current_alignment += 4 + eprosima::fastcdr::Cdr::alignment(current_alignment, 4) + data.message().size() + 1; + + + return current_alignment - initial_alignment; +} + +void HelloWorld::serialize( + eprosima::fastcdr::Cdr& scdr) const +{ + + scdr << m_index; + scdr << m_message; + +} + +void HelloWorld::deserialize( + eprosima::fastcdr::Cdr& dcdr) +{ + + dcdr >> m_index; + dcdr >> m_message; +} + +/*! + * @brief This function sets a value in member index + * @param _index New value for member index + */ +void HelloWorld::index( + uint32_t _index) +{ + m_index = _index; +} + +/*! + * @brief This function returns the value of member index + * @return Value of member index + */ +uint32_t HelloWorld::index() const +{ + return m_index; +} + +/*! + * @brief This function returns a reference to member index + * @return Reference to member index + */ +uint32_t& HelloWorld::index() +{ + return m_index; +} + +/*! + * @brief This function copies the value in member message + * @param _message New value to be copied in member message + */ +void HelloWorld::message( + const std::string& _message) +{ + m_message = _message; +} + +/*! + * @brief This function moves the value in member message + * @param _message New value to be moved in member message + */ +void HelloWorld::message( + std::string&& _message) +{ + m_message = std::move(_message); +} + +/*! + * @brief This function returns a constant reference to member message + * @return Constant reference to member message + */ +const std::string& HelloWorld::message() const +{ + return m_message; +} + +/*! + * @brief This function returns a reference to member message + * @return Reference to member message + */ +std::string& HelloWorld::message() +{ + return m_message; +} + +size_t HelloWorld::getKeyMaxCdrSerializedSize( + size_t current_alignment) +{ + size_t current_align = current_alignment; + + + + + + return current_align; +} + +bool HelloWorld::isKeyDefined() +{ + return false; +} + +void HelloWorld::serializeKey( + eprosima::fastcdr::Cdr& scdr) const +{ + (void) scdr; + +} diff --git a/examples/C++/DDS/ContentFilteredTopicExample/HelloWorld.h b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorld.h new file mode 100644 index 00000000000..ca96c339a28 --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorld.h @@ -0,0 +1,232 @@ +// 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 HelloWorld.h + * This header file contains the declaration of the described types in the IDL file. + * + * This file was generated by the tool gen. + */ + +#ifndef _FAST_DDS_GENERATED_HELLOWORLD_H_ +#define _FAST_DDS_GENERATED_HELLOWORLD_H_ + + +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) +#if defined(EPROSIMA_USER_DLL_EXPORT) +#define eProsima_user_DllExport __declspec( dllexport ) +#else +#define eProsima_user_DllExport +#endif // EPROSIMA_USER_DLL_EXPORT +#else +#define eProsima_user_DllExport +#endif // _WIN32 + +#if defined(_WIN32) +#if defined(EPROSIMA_USER_DLL_EXPORT) +#if defined(HelloWorld_SOURCE) +#define HelloWorld_DllAPI __declspec( dllexport ) +#else +#define HelloWorld_DllAPI __declspec( dllimport ) +#endif // HelloWorld_SOURCE +#else +#define HelloWorld_DllAPI +#endif // EPROSIMA_USER_DLL_EXPORT +#else +#define HelloWorld_DllAPI +#endif // _WIN32 + +namespace eprosima { +namespace fastcdr { +class Cdr; +} // namespace fastcdr +} // namespace eprosima + + +/*! + * @brief This class represents the structure HelloWorld defined by the user in the IDL file. + * @ingroup HELLOWORLD + */ +class HelloWorld +{ +public: + + /*! + * @brief Default constructor. + */ + eProsima_user_DllExport HelloWorld(); + + /*! + * @brief Default destructor. + */ + eProsima_user_DllExport ~HelloWorld(); + + /*! + * @brief Copy constructor. + * @param x Reference to the object HelloWorld that will be copied. + */ + eProsima_user_DllExport HelloWorld( + const HelloWorld& x); + + /*! + * @brief Move constructor. + * @param x Reference to the object HelloWorld that will be copied. + */ + eProsima_user_DllExport HelloWorld( + HelloWorld&& x); + + /*! + * @brief Copy assignment. + * @param x Reference to the object HelloWorld that will be copied. + */ + eProsima_user_DllExport HelloWorld& operator =( + const HelloWorld& x); + + /*! + * @brief Move assignment. + * @param x Reference to the object HelloWorld that will be copied. + */ + eProsima_user_DllExport HelloWorld& operator =( + HelloWorld&& x); + + /*! + * @brief Comparison operator. + * @param x HelloWorld object to compare. + */ + eProsima_user_DllExport bool operator ==( + const HelloWorld& x) const; + + /*! + * @brief Comparison operator. + * @param x HelloWorld object to compare. + */ + eProsima_user_DllExport bool operator !=( + const HelloWorld& x) const; + + /*! + * @brief This function sets a value in member index + * @param _index New value for member index + */ + eProsima_user_DllExport void index( + uint32_t _index); + + /*! + * @brief This function returns the value of member index + * @return Value of member index + */ + eProsima_user_DllExport uint32_t index() const; + + /*! + * @brief This function returns a reference to member index + * @return Reference to member index + */ + eProsima_user_DllExport uint32_t& index(); + + /*! + * @brief This function copies the value in member message + * @param _message New value to be copied in member message + */ + eProsima_user_DllExport void message( + const std::string& _message); + + /*! + * @brief This function moves the value in member message + * @param _message New value to be moved in member message + */ + eProsima_user_DllExport void message( + std::string&& _message); + + /*! + * @brief This function returns a constant reference to member message + * @return Constant reference to member message + */ + eProsima_user_DllExport const std::string& message() const; + + /*! + * @brief This function returns a reference to member message + * @return Reference to member message + */ + eProsima_user_DllExport std::string& message(); + + /*! + * @brief This function returns the maximum serialized size of an object + * depending on the buffer alignment. + * @param current_alignment Buffer alignment. + * @return Maximum serialized size. + */ + eProsima_user_DllExport static size_t getMaxCdrSerializedSize( + size_t current_alignment = 0); + + /*! + * @brief This function returns the serialized size of a data depending on the buffer alignment. + * @param data Data which is calculated its serialized size. + * @param current_alignment Buffer alignment. + * @return Serialized size. + */ + eProsima_user_DllExport static size_t getCdrSerializedSize( + const HelloWorld& data, + size_t current_alignment = 0); + + + /*! + * @brief This function serializes an object using CDR serialization. + * @param cdr CDR serialization object. + */ + eProsima_user_DllExport void serialize( + eprosima::fastcdr::Cdr& cdr) const; + + /*! + * @brief This function deserializes an object using CDR serialization. + * @param cdr CDR serialization object. + */ + eProsima_user_DllExport void deserialize( + eprosima::fastcdr::Cdr& cdr); + + + + /*! + * @brief This function returns the maximum serialized size of the Key of an object + * depending on the buffer alignment. + * @param current_alignment Buffer alignment. + * @return Maximum serialized size. + */ + eProsima_user_DllExport static size_t getKeyMaxCdrSerializedSize( + size_t current_alignment = 0); + + /*! + * @brief This function tells you if the Key has been defined for this type + */ + eProsima_user_DllExport static bool isKeyDefined(); + + /*! + * @brief This function serializes the key members of an object using CDR serialization. + * @param cdr CDR serialization object. + */ + eProsima_user_DllExport void serializeKey( + eprosima::fastcdr::Cdr& cdr) const; + +private: + + uint32_t m_index; + std::string m_message; +}; + +#endif // _FAST_DDS_GENERATED_HELLOWORLD_H_ \ No newline at end of file diff --git a/examples/C++/DDS/ContentFilteredTopicExample/HelloWorld.idl b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorld.idl new file mode 100644 index 00000000000..0fd2c355aee --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorld.idl @@ -0,0 +1,5 @@ +struct HelloWorld +{ + unsigned long index; + string message; +}; diff --git a/examples/C++/DDS/ContentFilteredTopicExample/HelloWorldPubSubTypes.cxx b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorldPubSubTypes.cxx new file mode 100644 index 00000000000..0741f6fded3 --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorldPubSubTypes.cxx @@ -0,0 +1,170 @@ +// 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 HelloWorldPubSubTypes.cpp + * This header file contains the implementation of the serialization functions. + * + * This file was generated by the tool fastcdrgen. + */ + + +#include +#include + +#include "HelloWorldPubSubTypes.h" + +using SerializedPayload_t = eprosima::fastrtps::rtps::SerializedPayload_t; +using InstanceHandle_t = eprosima::fastrtps::rtps::InstanceHandle_t; + +HelloWorldPubSubType::HelloWorldPubSubType() +{ + setName("HelloWorld"); + auto type_size = HelloWorld::getMaxCdrSerializedSize(); + type_size += eprosima::fastcdr::Cdr::alignment(type_size, 4); /* possible submessage alignment */ + m_typeSize = static_cast(type_size) + 4; /*encapsulation*/ + m_isGetKeyDefined = HelloWorld::isKeyDefined(); + size_t keyLength = HelloWorld::getKeyMaxCdrSerializedSize() > 16 ? + HelloWorld::getKeyMaxCdrSerializedSize() : 16; + m_keyBuffer = reinterpret_cast(malloc(keyLength)); + memset(m_keyBuffer, 0, keyLength); +} + +HelloWorldPubSubType::~HelloWorldPubSubType() +{ + if (m_keyBuffer != nullptr) + { + free(m_keyBuffer); + } +} + +bool HelloWorldPubSubType::serialize( + void* data, + SerializedPayload_t* payload) +{ + HelloWorld* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload->data), payload->max_size); + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN, eprosima::fastcdr::Cdr::DDS_CDR); + payload->encapsulation = ser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + // Serialize encapsulation + ser.serialize_encapsulation(); + + try + { + // Serialize the object. + p_type->serialize(ser); + } + catch (eprosima::fastcdr::exception::NotEnoughMemoryException& /*exception*/) + { + return false; + } + + // Get the serialized length + payload->length = static_cast(ser.getSerializedDataLength()); + return true; +} + +bool HelloWorldPubSubType::deserialize( + SerializedPayload_t* payload, + void* data) +{ + try + { + //Convert DATA to pointer of your type + HelloWorld* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload->data), payload->length); + + // Object that deserializes the data. + eprosima::fastcdr::Cdr deser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN, eprosima::fastcdr::Cdr::DDS_CDR); + + // Deserialize encapsulation. + deser.read_encapsulation(); + payload->encapsulation = deser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE; + + // Deserialize the object. + p_type->deserialize(deser); + } + catch (eprosima::fastcdr::exception::NotEnoughMemoryException& /*exception*/) + { + return false; + } + + return true; +} + +std::function HelloWorldPubSubType::getSerializedSizeProvider( + void* data) +{ + return [data]() -> uint32_t + { + return static_cast(type::getCdrSerializedSize(*static_cast(data))) + + 4u /*encapsulation*/; + }; +} + +void* HelloWorldPubSubType::createData() +{ + return reinterpret_cast(new HelloWorld()); +} + +void HelloWorldPubSubType::deleteData( + void* data) +{ + delete(reinterpret_cast(data)); +} + +bool HelloWorldPubSubType::getKey( + void* data, + InstanceHandle_t* handle, + bool force_md5) +{ + if (!m_isGetKeyDefined) + { + return false; + } + + HelloWorld* p_type = static_cast(data); + + // Object that manages the raw buffer. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(m_keyBuffer), + HelloWorld::getKeyMaxCdrSerializedSize()); + + // Object that serializes the data. + eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::BIG_ENDIANNESS); + p_type->serializeKey(ser); + if (force_md5 || HelloWorld::getKeyMaxCdrSerializedSize() > 16) + { + m_md5.init(); + m_md5.update(m_keyBuffer, static_cast(ser.getSerializedDataLength())); + m_md5.finalize(); + for (uint8_t i = 0; i < 16; ++i) + { + handle->value[i] = m_md5.digest[i]; + } + } + else + { + for (uint8_t i = 0; i < 16; ++i) + { + handle->value[i] = m_keyBuffer[i]; + } + } + return true; +} + diff --git a/examples/C++/DDS/ContentFilteredTopicExample/HelloWorldPubSubTypes.h b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorldPubSubTypes.h new file mode 100644 index 00000000000..8b2348be67c --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorldPubSubTypes.h @@ -0,0 +1,101 @@ +// 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 HelloWorldPubSubTypes.h + * This header file contains the declaration of the serialization functions. + * + * This file was generated by the tool fastcdrgen. + */ + + +#ifndef _FAST_DDS_GENERATED_HELLOWORLD_PUBSUBTYPES_H_ +#define _FAST_DDS_GENERATED_HELLOWORLD_PUBSUBTYPES_H_ + +#include +#include + +#include "HelloWorld.h" + +#if !defined(GEN_API_VER) || (GEN_API_VER != 1) +#error \ + Generated HelloWorld is not compatible with current installed Fast DDS. Please, regenerate it with fastddsgen. +#endif // GEN_API_VER + +/*! + * @brief This class represents the TopicDataType of the type HelloWorld defined by the user in the IDL file. + * @ingroup HELLOWORLD + */ +class HelloWorldPubSubType : public eprosima::fastdds::dds::TopicDataType +{ +public: + + typedef HelloWorld type; + + eProsima_user_DllExport HelloWorldPubSubType(); + + eProsima_user_DllExport virtual ~HelloWorldPubSubType(); + + eProsima_user_DllExport virtual bool serialize( + void* data, + eprosima::fastrtps::rtps::SerializedPayload_t* payload) override; + + eProsima_user_DllExport virtual bool deserialize( + eprosima::fastrtps::rtps::SerializedPayload_t* payload, + void* data) override; + + eProsima_user_DllExport virtual std::function getSerializedSizeProvider( + void* data) override; + + eProsima_user_DllExport virtual bool getKey( + void* data, + eprosima::fastrtps::rtps::InstanceHandle_t* ihandle, + bool force_md5 = false) override; + + eProsima_user_DllExport virtual void* createData() override; + + eProsima_user_DllExport virtual void deleteData( + void* data) override; + +#ifdef TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + eProsima_user_DllExport inline bool is_bounded() const override + { + return false; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_IS_BOUNDED + +#ifdef TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + eProsima_user_DllExport inline bool is_plain() const override + { + return false; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_IS_PLAIN + +#ifdef TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + eProsima_user_DllExport inline bool construct_sample( + void* memory) const override + { + (void)memory; + return false; + } + +#endif // TOPIC_DATA_TYPE_API_HAS_CONSTRUCT_SAMPLE + + MD5 m_md5; + unsigned char* m_keyBuffer; +}; + +#endif // _FAST_DDS_GENERATED_HELLOWORLD_PUBSUBTYPES_H_ \ No newline at end of file diff --git a/examples/C++/DDS/ContentFilteredTopicExample/HelloWorldTypeObject.cxx b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorldTypeObject.cxx new file mode 100644 index 00000000000..e4cd82ed3ba --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorldTypeObject.cxx @@ -0,0 +1,248 @@ +// 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 HelloWorldTypeObject.cpp + * This source file contains the definition of the described types in the IDL file. + * + * This file was generated by the tool gen. + */ + +#ifdef _WIN32 +// Remove linker warning LNK4221 on Visual Studio +namespace { char dummy; } +#endif + +#include "HelloWorld.h" +#include "HelloWorldTypeObject.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace eprosima::fastrtps::rtps; + +void registerHelloWorldTypes() +{ + TypeObjectFactory *factory = TypeObjectFactory::get_instance(); + factory->add_type_object("HelloWorld", GetHelloWorldIdentifier(true), + GetHelloWorldObject(true)); + factory->add_type_object("HelloWorld", GetHelloWorldIdentifier(false), + GetHelloWorldObject(false)); + +} + +const TypeIdentifier* GetHelloWorldIdentifier(bool complete) +{ + const TypeIdentifier * c_identifier = TypeObjectFactory::get_instance()->get_type_identifier("HelloWorld", complete); + if (c_identifier != nullptr && (!complete || c_identifier->_d() == EK_COMPLETE)) + { + return c_identifier; + } + + GetHelloWorldObject(complete); // Generated inside + return TypeObjectFactory::get_instance()->get_type_identifier("HelloWorld", complete); +} + +const TypeObject* GetHelloWorldObject(bool complete) +{ + const TypeObject* c_type_object = TypeObjectFactory::get_instance()->get_type_object("HelloWorld", complete); + if (c_type_object != nullptr) + { + return c_type_object; + } + else if (complete) + { + return GetCompleteHelloWorldObject(); + } + //else + return GetMinimalHelloWorldObject(); +} + +const TypeObject* GetMinimalHelloWorldObject() +{ + const TypeObject* c_type_object = TypeObjectFactory::get_instance()->get_type_object("HelloWorld", false); + if (c_type_object != nullptr) + { + return c_type_object; + } + + TypeObject *type_object = new TypeObject(); + type_object->_d(EK_MINIMAL); + type_object->minimal()._d(TK_STRUCTURE); + + type_object->minimal().struct_type().struct_flags().IS_FINAL(false); + type_object->minimal().struct_type().struct_flags().IS_APPENDABLE(false); + type_object->minimal().struct_type().struct_flags().IS_MUTABLE(false); + type_object->minimal().struct_type().struct_flags().IS_NESTED(false); + type_object->minimal().struct_type().struct_flags().IS_AUTOID_HASH(false); // Unsupported + + MemberId memberId = 0; + MinimalStructMember mst_index; + mst_index.common().member_id(memberId++); + mst_index.common().member_flags().TRY_CONSTRUCT1(false); // Unsupported + mst_index.common().member_flags().TRY_CONSTRUCT2(false); // Unsupported + mst_index.common().member_flags().IS_EXTERNAL(false); // Unsupported + mst_index.common().member_flags().IS_OPTIONAL(false); + mst_index.common().member_flags().IS_MUST_UNDERSTAND(false); + mst_index.common().member_flags().IS_KEY(false); + mst_index.common().member_flags().IS_DEFAULT(false); // Doesn't apply + mst_index.common().member_type_id(*TypeObjectFactory::get_instance()->get_type_identifier("uint32_t", false)); + + MD5 index_hash("index"); + for(int i = 0; i < 4; ++i) + { + mst_index.detail().name_hash()[i] = index_hash.digest[i]; + } + type_object->minimal().struct_type().member_seq().emplace_back(mst_index); + + MinimalStructMember mst_message; + mst_message.common().member_id(memberId++); + mst_message.common().member_flags().TRY_CONSTRUCT1(false); // Unsupported + mst_message.common().member_flags().TRY_CONSTRUCT2(false); // Unsupported + mst_message.common().member_flags().IS_EXTERNAL(false); // Unsupported + mst_message.common().member_flags().IS_OPTIONAL(false); + mst_message.common().member_flags().IS_MUST_UNDERSTAND(false); + mst_message.common().member_flags().IS_KEY(false); + mst_message.common().member_flags().IS_DEFAULT(false); // Doesn't apply + mst_message.common().member_type_id(*TypeObjectFactory::get_instance()->get_string_identifier(255, false)); + + + MD5 message_hash("message"); + for(int i = 0; i < 4; ++i) + { + mst_message.detail().name_hash()[i] = message_hash.digest[i]; + } + type_object->minimal().struct_type().member_seq().emplace_back(mst_message); + + + // Header + // TODO Inheritance + //type_object->minimal().struct_type().header().base_type()._d(EK_MINIMAL); + //type_object->minimal().struct_type().header().base_type().equivalence_hash()[0..13]; + + TypeIdentifier identifier; + identifier._d(EK_MINIMAL); + + SerializedPayload_t payload(static_cast( + MinimalStructType::getCdrSerializedSize(type_object->minimal().struct_type()) + 4)); + eprosima::fastcdr::FastBuffer fastbuffer((char*) payload.data, payload.max_size); + // Fixed endian (Page 221, EquivalenceHash definition of Extensible and Dynamic Topic Types for DDS document) + eprosima::fastcdr::Cdr ser( + fastbuffer, eprosima::fastcdr::Cdr::LITTLE_ENDIANNESS, + eprosima::fastcdr::Cdr::DDS_CDR); // Object that serializes the data. + payload.encapsulation = CDR_LE; + + type_object->serialize(ser); + payload.length = (uint32_t)ser.getSerializedDataLength(); //Get the serialized length + MD5 objectHash; + objectHash.update((char*)payload.data, payload.length); + objectHash.finalize(); + for(int i = 0; i < 14; ++i) + { + identifier.equivalence_hash()[i] = objectHash.digest[i]; + } + + TypeObjectFactory::get_instance()->add_type_object("HelloWorld", &identifier, type_object); + delete type_object; + return TypeObjectFactory::get_instance()->get_type_object("HelloWorld", false); +} + +const TypeObject* GetCompleteHelloWorldObject() +{ + const TypeObject* c_type_object = TypeObjectFactory::get_instance()->get_type_object("HelloWorld", true); + if (c_type_object != nullptr && c_type_object->_d() == EK_COMPLETE) + { + return c_type_object; + } + + TypeObject *type_object = new TypeObject(); + type_object->_d(EK_COMPLETE); + type_object->complete()._d(TK_STRUCTURE); + + type_object->complete().struct_type().struct_flags().IS_FINAL(false); + type_object->complete().struct_type().struct_flags().IS_APPENDABLE(false); + type_object->complete().struct_type().struct_flags().IS_MUTABLE(false); + type_object->complete().struct_type().struct_flags().IS_NESTED(false); + type_object->complete().struct_type().struct_flags().IS_AUTOID_HASH(false); // Unsupported + + MemberId memberId = 0; + CompleteStructMember cst_index; + cst_index.common().member_id(memberId++); + cst_index.common().member_flags().TRY_CONSTRUCT1(false); // Unsupported + cst_index.common().member_flags().TRY_CONSTRUCT2(false); // Unsupported + cst_index.common().member_flags().IS_EXTERNAL(false); // Unsupported + cst_index.common().member_flags().IS_OPTIONAL(false); + cst_index.common().member_flags().IS_MUST_UNDERSTAND(false); + cst_index.common().member_flags().IS_KEY(false); + cst_index.common().member_flags().IS_DEFAULT(false); // Doesn't apply + cst_index.common().member_type_id(*TypeObjectFactory::get_instance()->get_type_identifier("uint32_t", false)); + + cst_index.detail().name("index"); + + type_object->complete().struct_type().member_seq().emplace_back(cst_index); + + CompleteStructMember cst_message; + cst_message.common().member_id(memberId++); + cst_message.common().member_flags().TRY_CONSTRUCT1(false); // Unsupported + cst_message.common().member_flags().TRY_CONSTRUCT2(false); // Unsupported + cst_message.common().member_flags().IS_EXTERNAL(false); // Unsupported + cst_message.common().member_flags().IS_OPTIONAL(false); + cst_message.common().member_flags().IS_MUST_UNDERSTAND(false); + cst_message.common().member_flags().IS_KEY(false); + cst_message.common().member_flags().IS_DEFAULT(false); // Doesn't apply + cst_message.common().member_type_id(*TypeObjectFactory::get_instance()->get_string_identifier(255, false)); + + + cst_message.detail().name("message"); + + type_object->complete().struct_type().member_seq().emplace_back(cst_message); + + + // Header + type_object->complete().struct_type().header().detail().type_name("HelloWorld"); + // TODO inheritance + + + TypeIdentifier identifier; + identifier._d(EK_COMPLETE); + + SerializedPayload_t payload(static_cast( + CompleteStructType::getCdrSerializedSize(type_object->complete().struct_type()) + 4)); + eprosima::fastcdr::FastBuffer fastbuffer((char*) payload.data, payload.max_size); + // Fixed endian (Page 221, EquivalenceHash definition of Extensible and Dynamic Topic Types for DDS document) + eprosima::fastcdr::Cdr ser( + fastbuffer, eprosima::fastcdr::Cdr::LITTLE_ENDIANNESS, + eprosima::fastcdr::Cdr::DDS_CDR); // Object that serializes the data. + payload.encapsulation = CDR_LE; + + type_object->serialize(ser); + payload.length = (uint32_t)ser.getSerializedDataLength(); //Get the serialized length + MD5 objectHash; + objectHash.update((char*)payload.data, payload.length); + objectHash.finalize(); + for(int i = 0; i < 14; ++i) + { + identifier.equivalence_hash()[i] = objectHash.digest[i]; + } + + TypeObjectFactory::get_instance()->add_type_object("HelloWorld", &identifier, type_object); + delete type_object; + return TypeObjectFactory::get_instance()->get_type_object("HelloWorld", true); +} diff --git a/examples/C++/DDS/ContentFilteredTopicExample/HelloWorldTypeObject.h b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorldTypeObject.h new file mode 100644 index 00000000000..d6b4fbe75c1 --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/HelloWorldTypeObject.h @@ -0,0 +1,63 @@ +// 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 HelloWorldTypeObject.h + * This header file contains the declaration of the described types in the IDL file. + * + * This file was generated by the tool gen. + */ + +#ifndef _FAST_DDS_GENERATED_HELLOWORLD_TYPE_OBJECT_H_ +#define _FAST_DDS_GENERATED_HELLOWORLD_TYPE_OBJECT_H_ + + +#include +#include + +#if defined(_WIN32) +#if defined(EPROSIMA_USER_DLL_EXPORT) +#define eProsima_user_DllExport __declspec( dllexport ) +#else +#define eProsima_user_DllExport +#endif +#else +#define eProsima_user_DllExport +#endif + +#if defined(_WIN32) +#if defined(EPROSIMA_USER_DLL_EXPORT) +#if defined(HelloWorld_SOURCE) +#define HelloWorld_DllAPI __declspec( dllexport ) +#else +#define HelloWorld_DllAPI __declspec( dllimport ) +#endif // HelloWorld_SOURCE +#else +#define HelloWorld_DllAPI +#endif +#else +#define HelloWorld_DllAPI +#endif // _WIN32 + +using namespace eprosima::fastrtps::types; + +eProsima_user_DllExport void registerHelloWorldTypes(); + +eProsima_user_DllExport const TypeIdentifier* GetHelloWorldIdentifier(bool complete = false); +eProsima_user_DllExport const TypeObject* GetHelloWorldObject(bool complete = false); +eProsima_user_DllExport const TypeObject* GetMinimalHelloWorldObject(); +eProsima_user_DllExport const TypeObject* GetCompleteHelloWorldObject(); + + +#endif // _FAST_DDS_GENERATED_HELLOWORLD_TYPE_OBJECT_H_ \ No newline at end of file diff --git a/examples/C++/DDS/ContentFilteredTopicExample/MyCustomFilter.hpp b/examples/C++/DDS/ContentFilteredTopicExample/MyCustomFilter.hpp new file mode 100644 index 00000000000..d2fbd366585 --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/MyCustomFilter.hpp @@ -0,0 +1,79 @@ +#ifndef _CONTENTFILTEREDTOPICEXAMPLE_MYCUSTOMFILTER_HPP_ +#define _CONTENTFILTEREDTOPICEXAMPLE_MYCUSTOMFILTER_HPP_ + +#include +#include + +//! Custom filter class +//! It requieres two parameters 'low_mark_' and 'high_mark_'. +//! Filter samples which index is lower than 'low_mark_' and higher than 'high_mark_'. +class MyCustomFilter : public eprosima::fastdds::dds::IContentFilter +{ +public: + + /** + * @brief Construct a new MyCustomFilter object + * + * @param low_mark + * @param high_mark + */ + MyCustomFilter( + int low_mark, + int high_mark) + : low_mark_(low_mark) + , high_mark_(high_mark) + { + } + + //! Destructor + virtual ~MyCustomFilter() = default; + + /** + * @brief Evaluate filter discriminating whether the sample is relevant or not, i.e. whether it meets the filtering + * criteria + * + * @param payload Serialized sample + * @return true if sample meets filter requirements. false otherwise. + */ + bool evaluate( + const SerializedPayload& payload, + const FilterSampleInfo& /*sample_info*/, + const GUID_t& /*reader_guid*/) const override + { + // Deserialize the `index` field from the serialized sample. + eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast(payload.data), payload.length); + eprosima::fastcdr::Cdr deser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN, + eprosima::fastcdr::Cdr::DDS_CDR); + // Deserialize encapsulation. + deser.read_encapsulation(); + uint32_t index = 0; + + // Deserialize `index` field. + try + { + deser >> index; + } + catch (eprosima::fastcdr::exception::NotEnoughMemoryException& /*exception*/) + { + return false; + } + + // Custom filter: reject samples where index > low_mark_ and index < high_mark_. + if (index < low_mark_ || index > high_mark_) + { + return true; + } + + return false; + } + +private: + + //! Low mark: lower threshold below which the samples are relevant + uint32_t low_mark_ = 0; + //! High mark: upper threshold over which the samples are relevant + uint32_t high_mark_ = 0; + +}; + +#endif // _CONTENTFILTEREDTOPICEXAMPLE_MYCUSTOMFILTER_HPP_ diff --git a/examples/C++/DDS/ContentFilteredTopicExample/MyCustomFilterFactory.hpp b/examples/C++/DDS/ContentFilteredTopicExample/MyCustomFilterFactory.hpp new file mode 100644 index 00000000000..deb86feca93 --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/MyCustomFilterFactory.hpp @@ -0,0 +1,91 @@ +#ifndef _CONTENTFILTEREDTOPICEXAMPLE_MYCUSTOMFILTERFACTORY_HPP_ +#define _CONTENTFILTEREDTOPICEXAMPLE_MYCUSTOMFILTERFACTORY_HPP_ + +#include +#include +#include + +#include "MyCustomFilter.hpp" + +//! Custom filter factory +class MyCustomFilterFactory : public eprosima::fastdds::dds::IContentFilterFactory +{ +public: + + /** + * @brief Create a ContentFilteredTopic using this factory. + * Updating the filter implies deleting the previous one and creating a new one using the new given + * parameters. + * + * @param filter_class_name Custom filter name + * @param type_name Data type name + * @param filter_parameters Parameters required by the filter + * @param filter_instance Instance of the filter to be evaluated + * + * @return eprosima::fastrtps::types::ReturnCode_t::RETCODE_BAD_PARAMETER if the requirements for creating the + * ContentFilteredTopic using this factory are not met + * eprosima::fastrtps::types::ReturnCode_t::RETCODE_OK if the ContentFilteredTopic is correctly created + */ + eprosima::fastrtps::types::ReturnCode_t create_content_filter( + const char* filter_class_name, // My custom filter class name is 'MY_CUSTOM_FILTER'. + const char* type_name, // This custom filter only supports one type: 'HelloWorld'. + const eprosima::fastdds::dds::TopicDataType* /*data_type*/, // Not used in this implementation. + const char* /*filter_expression*/, // This Custom Filter doesn't implement a filter expression. + const ParameterSeq& filter_parameters, // Always need two parameters to be set: low_mark and high_mark. + eprosima::fastdds::dds::IContentFilter*& filter_instance) override + { + // Check the ContentFilteredTopic should be created by this factory. + if (0 != strcmp(filter_class_name, "MY_CUSTOM_FILTER") || + // Check the ContentFilteredTopic is created for the unique type this Custom Filter supports. + 0 != strcmp(type_name, "HelloWorld") || + // Check that the two mandatory filter parameters were set. + 2 != filter_parameters.length()) + { + return ReturnCode_t::RETCODE_BAD_PARAMETER; + } + + // If there is an update, delete previous instance. + if (nullptr != filter_instance) + { + delete(dynamic_cast(filter_instance)); + } + + // Instantiation of the Custom Filter. + filter_instance = new MyCustomFilter(std::stoi(filter_parameters[0]), std::stoi(filter_parameters[1])); + + return ReturnCode_t::RETCODE_OK; + } + + /** + * @brief Delete a ContentFilteredTopic created by this factory + * + * @param filter_class_name Custom filter name + * @param filter_instance Instance of the filter to be deleted. + * After returning, the passed pointer becomes invalid. + * @return eprosima::fastrtps::types::ReturnCode_t::RETCODE_BAD_PARAMETER if the instance was created with another + * factory + * eprosima::fastrtps::types::ReturnCode_t::RETCODE_OK if correctly deleted + */ + eprosima::fastrtps::types::ReturnCode_t delete_content_filter( + const char* filter_class_name, + eprosima::fastdds::dds::IContentFilter* filter_instance) override + { + // Check the ContentFilteredTopic should be created by this factory. + if (0 != strcmp(filter_class_name, "MY_CUSTOM_FILTER") || + // Check the filter instance is valid + nullptr != filter_instance) + { + return ReturnCode_t::RETCODE_BAD_PARAMETER; + } + + // Deletion of the Custom Filter. + if (nullptr != filter_instance) + { + delete(dynamic_cast(filter_instance)); + } + + return ReturnCode_t::RETCODE_OK; + } + +}; +#endif // _CONTENTFILTEREDTOPICEXAMPLE_MYCUSTOMFILTERFACTORY_HPP_ diff --git a/examples/C++/DDS/ContentFilteredTopicExample/README.md b/examples/C++/DDS/ContentFilteredTopicExample/README.md new file mode 100644 index 00000000000..d60e9ece821 --- /dev/null +++ b/examples/C++/DDS/ContentFilteredTopicExample/README.md @@ -0,0 +1,34 @@ +# Content Filtered Topic Example + +This example extends the HelloWorld example to show how to use Content Filtered Topics. +It does so by including two different Filter Factories: on the one hand, the default SQL filter; on the other hand, a custom filter defined in the example. + +## Execution instructions (Linux platform) + +To launch this example, open three different terminals: + +In the first one, launch the Subscriber using the default SQL filter: + +``` +./DDSContentFilteredTopicExample --subscriber +``` + +In the second one, launch the Subscriber using the custom filter: + +``` +./DDSContentFilteredTopicExample --subscriber -f custom +``` + +Finally, in the third terminal launch the Publisher: + +``` +./DDSContentFilteredTopicExample --publisher +``` + +The Subscriber with the default filter should received only the samples between indexes 5 and 9, while the Subscriber with the custom filter should received samples which index is lower than 3 or greater than 5. + +In order to know further possible arguments please run: + +``` +./DDSContentFilteredTopicExample --help +```