From d58d92fa541766f2101ea6180d8255ba5c5fa94d Mon Sep 17 00:00:00 2001 From: lulivi Date: Fri, 4 Nov 2022 18:14:16 +0100 Subject: [PATCH] Fix #551 Adds C++98 example --- examples/connext_dds/CMakeLists.txt | 1 + .../build_systems/cmake/c++98/CMakeLists.txt | 111 +++++++++ .../build_systems/cmake/c++98/HelloWorld.idl | 15 ++ .../cmake/c++98/HelloWorld_publisher.cxx | 183 +++++++++++++++ .../cmake/c++98/HelloWorld_subscriber.cxx | 218 ++++++++++++++++++ .../build_systems/cmake/c++98/README.md | 124 ++++++++++ .../cmake/c++98/USER_QOS_PROFILES.xml | 93 ++++++++ .../build_systems/cmake/c++98/application.h | 128 ++++++++++ .../build_systems/cmake/c/CMakeLists.txt | 6 +- 9 files changed, 876 insertions(+), 3 deletions(-) create mode 100644 examples/connext_dds/build_systems/cmake/c++98/CMakeLists.txt create mode 100644 examples/connext_dds/build_systems/cmake/c++98/HelloWorld.idl create mode 100644 examples/connext_dds/build_systems/cmake/c++98/HelloWorld_publisher.cxx create mode 100644 examples/connext_dds/build_systems/cmake/c++98/HelloWorld_subscriber.cxx create mode 100644 examples/connext_dds/build_systems/cmake/c++98/README.md create mode 100644 examples/connext_dds/build_systems/cmake/c++98/USER_QOS_PROFILES.xml create mode 100644 examples/connext_dds/build_systems/cmake/c++98/application.h diff --git a/examples/connext_dds/CMakeLists.txt b/examples/connext_dds/CMakeLists.txt index f049f964f..86fada5ee 100644 --- a/examples/connext_dds/CMakeLists.txt +++ b/examples/connext_dds/CMakeLists.txt @@ -59,6 +59,7 @@ if(NOT DEFINED CONNEXTDDS_CONNEXT_DDS_EXAMPLES) "asynchronous_publication" "asyncwaitset" "batching" + "build_systems/cmake" "builtin_qos_profiles" "builtin_topics" "coherent_presentation" diff --git a/examples/connext_dds/build_systems/cmake/c++98/CMakeLists.txt b/examples/connext_dds/build_systems/cmake/c++98/CMakeLists.txt new file mode 100644 index 000000000..28fcaa0ff --- /dev/null +++ b/examples/connext_dds/build_systems/cmake/c++98/CMakeLists.txt @@ -0,0 +1,111 @@ +# (c) 2019 Copyright, Real-Time Innovations, Inc. All rights reserved. +# No duplications, whole or partial, manual or electronic, may be made +# without express written permission. Any such copies, or revisions thereof, +# must display this notice unaltered. +# This code contains trade secrets of Real-Time Innovations, Inc. + +cmake_minimum_required(VERSION 3.11) +project(rtiexamples-hello-world) + +# Add the folder where the FindRTIConnextDDS.cmake file is placed to the +# CMAKE_MODULE_PATH variable +list(APPEND CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../resources/cmake/Modules" +) +include(ConnextDdsConfigureCmakeUtils) +connextdds_configure_cmake_utils() + +# Find the ConnextDDS libraries. This will look fo the core and API libraries +# only +find_package(RTIConnextDDS + "7.0.0" + REQUIRED + COMPONENTS + core +) + +# Run Codegen to generate the source code files for the types +include(ConnextDdsCodegen) +connextdds_rtiddsgen_run( + IDL_FILE + "${CMAKE_CURRENT_SOURCE_DIR}/HelloWorld.idl" + OUTPUT_DIRECTORY + "${CMAKE_CURRENT_BINARY_DIR}/src" + LANG C++98 +) + +add_custom_target(codegen_sources + DEPENDS + ${HelloWorld_CXX98_SOURCES} +) + +# Create the target for the publisher executable +add_executable(HelloWorld_publisher + "${CMAKE_CURRENT_SOURCE_DIR}/HelloWorld_publisher.cxx" + ${HelloWorld_CXX98_SOURCES} +) + +# Link against the ConnextDDS libraries +target_link_libraries( + HelloWorld_publisher + PRIVATE + RTIConnextDDS::cpp_api +) + +# Include the folder with the type header files +target_include_directories(HelloWorld_publisher + PRIVATE + "${CMAKE_CURRENT_BINARY_DIR}/src" +) + +# Create the target for the subscriber executable +add_executable(HelloWorld_subscriber + "${CMAKE_CURRENT_SOURCE_DIR}/HelloWorld_subscriber.cxx" + ${HelloWorld_CXX98_SOURCES} +) + +# Link against the ConnextDDS libraries +target_link_libraries( + HelloWorld_subscriber + PRIVATE + RTIConnextDDS::cpp_api +) +# Include the folder with the type header files +target_include_directories(HelloWorld_subscriber + PRIVATE + "${CMAKE_CURRENT_BINARY_DIR}/src" +) + + +# Copy the USER_QOS_PROFILES.xml +add_custom_target(copy_qos + DEPENDS + "${CMAKE_CURRENT_BINARY_DIR}/USER_QOS_PROFILES.xml" +) + +add_custom_command( + OUTPUT + "${CMAKE_CURRENT_BINARY_DIR}/USER_QOS_PROFILES.xml" + COMMAND + ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_CURRENT_SOURCE_DIR}/USER_QOS_PROFILES.xml" + "${CMAKE_CURRENT_BINARY_DIR}" + COMMENT "Copying USER_QOS_PROFILES.xml" + DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/USER_QOS_PROFILES.xml" + VERBATIM +) + +# Copy the USER_QOS_PROFILES.XML when the publisher is built and ensure +# Codegen is called +add_dependencies(HelloWorld_publisher + copy_qos + codegen_sources +) + +# Copy the USER_QOS_PROFILES.XML when the subscriber is built and ensure +# Codegen is called +add_dependencies(HelloWorld_subscriber + copy_qos + codegen_sources +) diff --git a/examples/connext_dds/build_systems/cmake/c++98/HelloWorld.idl b/examples/connext_dds/build_systems/cmake/c++98/HelloWorld.idl new file mode 100644 index 000000000..0c5211a2c --- /dev/null +++ b/examples/connext_dds/build_systems/cmake/c++98/HelloWorld.idl @@ -0,0 +1,15 @@ +/* + * (c) 2019 Copyright, Real-Time Innovations, Inc. All rights reserved. + * + * RTI grants Licensee a license to use, modify, compile, and create derivative + * works of the Software. Licensee has the right to distribute object form + * only for use with RTI products. The Software is provided "as is", with no + * warranty of any type, including any warranty for fitness for any purpose. + * RTI is under no obligation to maintain or support the Software. RTI shall + * not be liable for any incidental or consequential damages arising out of the + * use or inability to use the software. + */ + +struct HelloWorld { + char a; +}; diff --git a/examples/connext_dds/build_systems/cmake/c++98/HelloWorld_publisher.cxx b/examples/connext_dds/build_systems/cmake/c++98/HelloWorld_publisher.cxx new file mode 100644 index 000000000..92ba30557 --- /dev/null +++ b/examples/connext_dds/build_systems/cmake/c++98/HelloWorld_publisher.cxx @@ -0,0 +1,183 @@ +/* +* (c) Copyright, Real-Time Innovations, 2020. All rights reserved. +* RTI grants Licensee a license to use, modify, compile, and create derivative +* works of the software solely for use with RTI Connext DDS. Licensee may +* redistribute copies of the software provided that all such copies are subject +* to this license. The software is provided "as is", with no warranty of any +* type, including any warranty for fitness for any purpose. RTI is under no +* obligation to maintain or support the software. RTI shall not be liable for +* any incidental or consequential damages arising out of the use or inability +* to use the software. +*/ + +#include +#include +#include + +#include "HelloWorld.h" +#include "HelloWorldSupport.h" +#include "ndds/ndds_cpp.h" +#include "application.h" + +using namespace application; + +static int shutdown_participant( + DDSDomainParticipant *participant, + const char *shutdown_message, + int status); + +int run_publisher_application(unsigned int domain_id, unsigned int sample_count) +{ + // Start communicating in a domain, usually one participant per application + DDSDomainParticipant *participant = + DDSTheParticipantFactory->create_participant( + domain_id, + DDS_PARTICIPANT_QOS_DEFAULT, + NULL /* listener */, + DDS_STATUS_MASK_NONE); + if (participant == NULL) { + return shutdown_participant(participant, "create_participant error", EXIT_FAILURE); + } + + // A Publisher allows an application to create one or more DataWriters + DDSPublisher *publisher = participant->create_publisher( + DDS_PUBLISHER_QOS_DEFAULT, + NULL /* listener */, + DDS_STATUS_MASK_NONE); + if (publisher == NULL) { + return shutdown_participant(participant, "create_publisher error", EXIT_FAILURE); + } + + // Register the datatype to use when creating the Topic + const char *type_name = HelloWorldTypeSupport::get_type_name(); + DDS_ReturnCode_t retcode = + HelloWorldTypeSupport::register_type(participant, type_name); + if (retcode != DDS_RETCODE_OK) { + return shutdown_participant(participant, "register_type error", EXIT_FAILURE); + } + + // Create a Topic with a name and a datatype + DDSTopic *topic = participant->create_topic( + "Example HelloWorld", + type_name, + DDS_TOPIC_QOS_DEFAULT, + NULL /* listener */, + DDS_STATUS_MASK_NONE); + if (topic == NULL) { + return shutdown_participant(participant, "create_topic error", EXIT_FAILURE); + } + + // This DataWriter writes data on "Example HelloWorld" Topic + DDSDataWriter *untyped_writer = publisher->create_datawriter( + topic, + DDS_DATAWRITER_QOS_DEFAULT, + NULL /* listener */, + DDS_STATUS_MASK_NONE); + if (untyped_writer == NULL) { + return shutdown_participant(participant, "create_datawriter error", EXIT_FAILURE); + } + + // Narrow casts from an untyped DataWriter to a writer of your type + HelloWorldDataWriter *typed_writer = + HelloWorldDataWriter::narrow(untyped_writer); + if (typed_writer == NULL) { + return shutdown_participant(participant, "DataWriter narrow error", EXIT_FAILURE); + } + + // Create data for writing, allocating all members + HelloWorld *data = HelloWorldTypeSupport::create_data(); + if (data == NULL) { + return shutdown_participant( + participant, + "HelloWorldTypeSupport::create_data error", + EXIT_FAILURE); + } + + // Main loop, write data + for (unsigned int samples_written = 0; + !shutdown_requested && samples_written < sample_count; + ++samples_written) { + + // Modify the data to be written here + + std::cout << "Writing HelloWorld, count " << samples_written + << std::endl; + retcode = typed_writer->write(*data, DDS_HANDLE_NIL); + if (retcode != DDS_RETCODE_OK) { + std::cerr << "write error " << retcode << std::endl; + } + + // Send once every second + DDS_Duration_t send_period = { 1, 0 }; + NDDSUtility::sleep(send_period); + } + + // Delete previously allocated HelloWorld, including all contained elements + retcode = HelloWorldTypeSupport::delete_data(data); + if (retcode != DDS_RETCODE_OK) { + std::cerr << "HelloWorldTypeSupport::delete_data error " << retcode + << std::endl; + } + + // Delete all entities (DataWriter, Topic, Publisher, DomainParticipant) + return shutdown_participant(participant, "Shutting down", EXIT_SUCCESS); +} + +// Delete all entities +static int shutdown_participant( + DDSDomainParticipant *participant, + const char *shutdown_message, + int status) +{ + DDS_ReturnCode_t retcode; + + std::cout << shutdown_message << std::endl; + + if (participant != NULL) { + // Cleanup everything created by this Participant + retcode = participant->delete_contained_entities(); + if (retcode != DDS_RETCODE_OK) { + std::cerr << "delete_contained_entities error " << retcode + << std::endl; + status = EXIT_FAILURE; + } + + retcode = DDSTheParticipantFactory->delete_participant(participant); + if (retcode != DDS_RETCODE_OK) { + std::cerr << "delete_participant error " << retcode << std::endl; + status = EXIT_FAILURE; + } + } + + return status; +} + +int main(int argc, char *argv[]) +{ + + // Parse arguments and handle control-C + ApplicationArguments arguments; + parse_arguments(arguments, argc, argv); + if (arguments.parse_result == PARSE_RETURN_EXIT) { + return EXIT_SUCCESS; + } else if (arguments.parse_result == PARSE_RETURN_FAILURE) { + return EXIT_FAILURE; + } + setup_signal_handlers(); + + // Sets Connext verbosity to help debugging + NDDSConfigLogger::get_instance()->set_verbosity(arguments.verbosity); + + int status = run_publisher_application(arguments.domain_id, arguments.sample_count); + + // Releases the memory used by the participant factory. Optional at + // application exit + DDS_ReturnCode_t retcode = DDSDomainParticipantFactory::finalize_instance(); + if (retcode != DDS_RETCODE_OK) { + std::cerr << "finalize_instance error " << retcode << std::endl; + status = EXIT_FAILURE; + } + + return status; +} + diff --git a/examples/connext_dds/build_systems/cmake/c++98/HelloWorld_subscriber.cxx b/examples/connext_dds/build_systems/cmake/c++98/HelloWorld_subscriber.cxx new file mode 100644 index 000000000..cb5c950b6 --- /dev/null +++ b/examples/connext_dds/build_systems/cmake/c++98/HelloWorld_subscriber.cxx @@ -0,0 +1,218 @@ +/* +* (c) Copyright, Real-Time Innovations, 2020. All rights reserved. +* RTI grants Licensee a license to use, modify, compile, and create derivative +* works of the software solely for use with RTI Connext DDS. Licensee may +* redistribute copies of the software provided that all such copies are subject +* to this license. The software is provided "as is", with no warranty of any +* type, including any warranty for fitness for any purpose. RTI is under no +* obligation to maintain or support the software. RTI shall not be liable for +* any incidental or consequential damages arising out of the use or inability +* to use the software. +*/ + +#include +#include +#include + +#include "HelloWorld.h" +#include "HelloWorldSupport.h" +#include "ndds/ndds_cpp.h" +#include "application.h" + +using namespace application; + +static int shutdown_participant( + DDSDomainParticipant *participant, + const char *shutdown_message, + int status); + +// Process data. Returns number of samples processed. +unsigned int process_data(HelloWorldDataReader *typed_reader) +{ + HelloWorldSeq data_seq; // Sequence of received data + DDS_SampleInfoSeq info_seq; // Metadata associated with samples in data_seq + unsigned int samples_read = 0; + + // Take available data from DataReader's queue + typed_reader->take( + data_seq, + info_seq, + DDS_LENGTH_UNLIMITED, + DDS_ANY_SAMPLE_STATE, + DDS_ANY_VIEW_STATE, + DDS_ANY_INSTANCE_STATE); + + // Iterate over all available data + for (int i = 0; i < data_seq.length(); ++i) { + // Check if a sample is an instance lifecycle event + if (info_seq[i].valid_data) { + // Print data + std::cout << "Received data" << std::endl; + HelloWorldTypeSupport::print_data(&data_seq[i]); + samples_read++; + } else { // This is an instance lifecycle event with no data payload. + std::cout << "Received instance state notification" << std::endl; + } + } + // Data loaned from Connext for performance. Return loan when done. + DDS_ReturnCode_t retcode = typed_reader->return_loan(data_seq, info_seq); + if (retcode != DDS_RETCODE_OK) { + std::cerr << "return loan error " << retcode << std::endl; + } + + return samples_read; +} + +int run_subscriber_application(unsigned int domain_id, unsigned int sample_count) +{ + // Start communicating in a domain, usually one participant per application + DDSDomainParticipant *participant = + DDSTheParticipantFactory->create_participant( + domain_id, + DDS_PARTICIPANT_QOS_DEFAULT, + NULL /* listener */, + DDS_STATUS_MASK_NONE); + if (participant == NULL) { + return shutdown_participant(participant, "create_participant error", EXIT_FAILURE); + } + + // A Subscriber allows an application to create one or more DataReaders + DDSSubscriber *subscriber = participant->create_subscriber( + DDS_SUBSCRIBER_QOS_DEFAULT, + NULL /* listener */, + DDS_STATUS_MASK_NONE); + if (subscriber == NULL) { + return shutdown_participant(participant, "create_subscriber error", EXIT_FAILURE); + } + + // Register the datatype to use when creating the Topic + const char *type_name = HelloWorldTypeSupport::get_type_name(); + DDS_ReturnCode_t retcode = + HelloWorldTypeSupport::register_type(participant, type_name); + if (retcode != DDS_RETCODE_OK) { + return shutdown_participant(participant, "register_type error", EXIT_FAILURE); + } + + // Create a Topic with a name and a datatype + DDSTopic *topic = participant->create_topic( + "Example HelloWorld", + type_name, + DDS_TOPIC_QOS_DEFAULT, + NULL /* listener */, + DDS_STATUS_MASK_NONE); + if (topic == NULL) { + return shutdown_participant(participant, "create_topic error", EXIT_FAILURE); + } + + // This DataReader reads data on "Example HelloWorld" Topic + DDSDataReader *untyped_reader = subscriber->create_datareader( + topic, + DDS_DATAREADER_QOS_DEFAULT, + NULL, + DDS_STATUS_MASK_NONE); + if (untyped_reader == NULL) { + return shutdown_participant(participant, "create_datareader error", EXIT_FAILURE); + } + + // Narrow casts from a untyped DataReader to a reader of your type + HelloWorldDataReader *typed_reader = + HelloWorldDataReader::narrow(untyped_reader); + if (typed_reader == NULL) { + return shutdown_participant(participant, "DataReader narrow error", EXIT_FAILURE); + } + + // Create ReadCondition that triggers when unread data in reader's queue + DDSReadCondition *read_condition = typed_reader->create_readcondition( + DDS_NOT_READ_SAMPLE_STATE, + DDS_ANY_VIEW_STATE, + DDS_ANY_INSTANCE_STATE); + if (read_condition == NULL) { + return shutdown_participant(participant, "create_readcondition error", EXIT_FAILURE); + } + + // WaitSet will be woken when the attached condition is triggered + DDSWaitSet waitset; + retcode = waitset.attach_condition(read_condition); + if (retcode != DDS_RETCODE_OK) { + return shutdown_participant(participant, "attach_condition error", EXIT_FAILURE); + } + + // Main loop. Wait for data to arrive, and process when it arrives + unsigned int samples_read = 0; + while (!shutdown_requested && samples_read < sample_count) { + DDSConditionSeq active_conditions_seq; + + // Wait for data and report if it does not arrive in 1 second + DDS_Duration_t wait_timeout = { 1, 0 }; + retcode = waitset.wait(active_conditions_seq, wait_timeout); + + if (retcode == DDS_RETCODE_OK) { + // If the read condition is triggered, process data + samples_read += process_data(typed_reader); + } else { + if (retcode == DDS_RETCODE_TIMEOUT) { + std::cout << "No data after 1 second" << std::endl; + } + } + } + + // Cleanup + return shutdown_participant(participant, "Shutting down", 0); +} + +// Delete all entities +static int shutdown_participant( + DDSDomainParticipant *participant, + const char *shutdown_message, + int status) +{ + DDS_ReturnCode_t retcode; + + std::cout << shutdown_message << std::endl; + + if (participant != NULL) { + // Cleanup everything created by this Participant + retcode = participant->delete_contained_entities(); + if (retcode != DDS_RETCODE_OK) { + std::cerr << "delete_contained_entities error" << retcode + << std::endl; + status = EXIT_FAILURE; + } + + retcode = DDSTheParticipantFactory->delete_participant(participant); + if (retcode != DDS_RETCODE_OK) { + std::cerr << "delete_participant error" << retcode << std::endl; + status = EXIT_FAILURE; + } + } + return status; +} + +int main(int argc, char *argv[]) +{ + + // Parse arguments and handle control-C + ApplicationArguments arguments; + parse_arguments(arguments, argc, argv); + if (arguments.parse_result == PARSE_RETURN_EXIT) { + return EXIT_SUCCESS; + } else if (arguments.parse_result == PARSE_RETURN_FAILURE) { + return EXIT_FAILURE; + } + setup_signal_handlers(); + + // Sets Connext verbosity to help debugging + NDDSConfigLogger::get_instance()->set_verbosity(arguments.verbosity); + + int status = run_subscriber_application(arguments.domain_id, arguments.sample_count); + + // Releases the memory used by the participant factory. Optional at + // application exit + DDS_ReturnCode_t retcode = DDSDomainParticipantFactory::finalize_instance(); + if (retcode != DDS_RETCODE_OK) { + std::cerr << "finalize_instance error" << retcode << std::endl; + status = EXIT_FAILURE; + } + + return status; +} diff --git a/examples/connext_dds/build_systems/cmake/c++98/README.md b/examples/connext_dds/build_systems/cmake/c++98/README.md new file mode 100644 index 000000000..f0d820317 --- /dev/null +++ b/examples/connext_dds/build_systems/cmake/c++98/README.md @@ -0,0 +1,124 @@ +# ConnextDDS C example with CMake + +This example show how to create a "`hello world`" application written in C and +how to build it using [CMake](https://cmake.org/). + +The CMakeList.txt file is self documented to allow you to understand how the +publisher and subscriber build is performed. + +## Building the Example :wrench: + +To build this example, first run CMake to generate the corresponding build +files. We recommend you use a separate directory to store all the generated +files (e.g., ./build). + +```sh +mkdir build +cd build +cmake .. +``` + +Once you have run CMake, you will find a number of new files in your build +directory (the list of generated files will depend on the specific CMake +Generator). To build the example, run CMake as follows: + +```sh +cmake --build . +``` + +**Note**: if you are using a multi-configuration generator, such as Visual +Studio solutions, you can specify the configuration mode to build as follows: + +```sh +cmake --build . --config Release|Debug +``` + +Alternatively, you can use directly the generated infrastructure (e.g., +Makefiles or Visual Studio Solutions) to build the example. If you generated +Makefiles in the configuration process, run make to build the example. Likewise, +if you generated a Visual Studio solution, open the solution and follow the +regular build process. + +## Running the Example + +After building the example, two applications will be generated in the binary +directory, to run them, you can run the following commands: + +```sh +HelloWorld_publisher +HelloWorld_subscriber +``` + +## Customizing the Build + +### Configuring Build Type and Generator + +By default, CMake will generate build files using the most common generator for +your host platform (e.g., Makefiles on Unix-like systems and Visual Studio +solution on Windows), \. You can use the following CMake variables to modify the +default behavior: + +- `-DCMAKE_BUILD_TYPE` -- specifies the build mode. Valid values are Release + and Debug. See the [CMake documentation for more details. + (Optional)](https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html) + +- `-DBUILD_SHARED_LIBS` -- specifies the link mode. Valid values are ON for + dynamic linking and OFF for static linking. See [CMake documentation for + more details. + (Optional)](https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html) + +- `-G` -- CMake generator. The generator is the native build system to use + build the source code. All the valid values are described described in the + CMake documentation [CMake Generators + Section.](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html) + +For example, to build a example in Debug/Static mode run CMake as follows: + +```sh +cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON .. -G "Visual Studio 15 2017" -A x64 +``` + +### Configuring Connext DDS Installation Path and Architecture + +The CMake build infrastructure will try to guess the location of your Connext +DDS installation and the Connext DDS architecture based on the default settings +for your host platform.If you installed Connext DDS in a custom location, you +can use the CONNEXTDDS_DIR variable to indicate the path to your RTI Connext DDS +installation folder. For example: + +```sh +cmake -DCONNEXTDDS_DIR=/home/rti/rti_connext_dds-x.y.z .. +``` + +Also, If you installed libraries for multiple target architecture on your system +(i.e., you installed more than one target rtipkg), you can use the +CONNEXTDDS_ARCH variable to indicate the architecture of the specific libraries +you want to link against. For example: + +```sh +cmake -DCONNEXTDDS_ARCH=x64Linux3gcc5.4.0 .. +``` + +### CMake Build Infrastructure + +The CMakeListst.txt script that builds this example uses a generic CMake +function called connextdds_add_example that defines all the necessary constructs +to: + +1. Run RTI Code Generator to generate the serialization/deserialization code + for the types defined in the IDL file associated with the example. + +2. Build the corresponding Publisher and Subscriber applications. + +3. Copy the USER_QOS_PROFILES.xml file into the directory where the publisher + and subscriber executables are generated. + +You will find the definition of connextdds_add_example, along with detailed +documentation, in +[resources/cmake/ConnextDdsAddExample.cmake](../../../../resources/cmake/ConnextDdsAddExample.cmake). + +For a more comprehensive example on how to build an RTI Connext DDS application +using CMake, please refer to the +[hello_world](../../../connext_dds/build_systems/cmake/) example, which includes +a comprehensive CMakeLists.txt script with all the steps and instructions +described in detail. diff --git a/examples/connext_dds/build_systems/cmake/c++98/USER_QOS_PROFILES.xml b/examples/connext_dds/build_systems/cmake/c++98/USER_QOS_PROFILES.xml new file mode 100644 index 000000000..59e867683 --- /dev/null +++ b/examples/connext_dds/build_systems/cmake/c++98/USER_QOS_PROFILES.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + HelloWorldDataWriter + + + + + + + HelloWorldDataReader + + + + + + HelloWorldParticipant + HelloWorldParticipantRole + + + + + + + diff --git a/examples/connext_dds/build_systems/cmake/c++98/application.h b/examples/connext_dds/build_systems/cmake/c++98/application.h new file mode 100644 index 000000000..22cb1de83 --- /dev/null +++ b/examples/connext_dds/build_systems/cmake/c++98/application.h @@ -0,0 +1,128 @@ +/* +* (c) Copyright, Real-Time Innovations, 2020. All rights reserved. +* RTI grants Licensee a license to use, modify, compile, and create derivative +* works of the software solely for use with RTI Connext DDS. Licensee may +* redistribute copies of the software provided that all such copies are subject +* to this license. The software is provided "as is", with no warranty of any +* type, including any warranty for fitness for any purpose. RTI is under no +* obligation to maintain or support the software. RTI shall not be liable for +* any incidental or consequential damages arising out of the use or inability +* to use the software. +*/ + +#ifndef APPLICATION_H +#define APPLICATION_H + +#include +#include +#include + +namespace application { + + // Catch control-C and tell application to shut down + bool shutdown_requested = false; + + inline void stop_handler(int) + { + shutdown_requested = true; + std::cout << "preparing to shut down..." << std::endl; + } + + inline void setup_signal_handlers() + { + signal(SIGINT, stop_handler); + signal(SIGTERM, stop_handler); + } + + enum ParseReturn { PARSE_RETURN_OK, PARSE_RETURN_FAILURE, PARSE_RETURN_EXIT }; + + struct ApplicationArguments { + ParseReturn parse_result; + unsigned int domain_id; + unsigned int sample_count; + NDDS_Config_LogVerbosity verbosity; + }; + + inline void set_verbosity( + ApplicationArguments& arguments, + int verbosity) + { + switch (verbosity) { + case 0: + arguments.verbosity = NDDS_CONFIG_LOG_VERBOSITY_SILENT; + break; + case 1: + arguments.verbosity = NDDS_CONFIG_LOG_VERBOSITY_ERROR; + break; + case 2: + arguments.verbosity = NDDS_CONFIG_LOG_VERBOSITY_WARNING; + break; + case 3: + arguments.verbosity = NDDS_CONFIG_LOG_VERBOSITY_STATUS_ALL; + break; + default: + arguments.verbosity = NDDS_CONFIG_LOG_VERBOSITY_ERROR; + break; + } + } + + // Parses application arguments for example. Returns whether to exit. + inline void parse_arguments( + ApplicationArguments& arguments, + int argc, + char *argv[]) + { + int arg_processing = 1; + bool show_usage = false; + arguments.domain_id = 0; + arguments.sample_count = INT_MAX; + arguments.verbosity = NDDS_CONFIG_LOG_VERBOSITY_ERROR; + arguments.parse_result = PARSE_RETURN_OK; + + while (arg_processing < argc) { + if ((argc > arg_processing + 1) + && (strcmp(argv[arg_processing], "-d") == 0 + || strcmp(argv[arg_processing], "--domain") == 0)) { + arguments.domain_id = atoi(argv[arg_processing + 1]); + arg_processing += 2; + } else if ((argc > arg_processing + 1) + && (strcmp(argv[arg_processing], "-s") == 0 + || strcmp(argv[arg_processing], "--sample-count") == 0)) { + arguments.sample_count = atoi(argv[arg_processing + 1]); + arg_processing += 2; + } else if ((argc > arg_processing + 1) + && (strcmp(argv[arg_processing], "-v") == 0 + || strcmp(argv[arg_processing], "--verbosity") == 0)) { + set_verbosity(arguments, atoi(argv[arg_processing + 1])); + arg_processing += 2; + } else if (strcmp(argv[arg_processing], "-h") == 0 + || strcmp(argv[arg_processing], "--help") == 0) { + std::cout << "Example application." << std::endl; + show_usage = true; + arguments.parse_result = PARSE_RETURN_EXIT; + break; + } else { + std::cout << "Bad parameter." << std::endl; + show_usage = true; + arguments.parse_result = PARSE_RETURN_FAILURE; + break; + } + } + if (show_usage) { + std::cout << "Usage:\n"\ + " -d, --domain Domain ID this application will\n" \ + " subscribe in. \n" + " Default: 0\n"\ + " -s, --sample_count Number of samples to receive before\n"\ + " cleanly shutting down. \n" + " Default: infinite\n" + " -v, --verbosity How much debugging output to show.\n"\ + " Range: 0-3 \n" + " Default: 1" + << std::endl; + } + } + +} // namespace application + +#endif // APPLICATION_H diff --git a/examples/connext_dds/build_systems/cmake/c/CMakeLists.txt b/examples/connext_dds/build_systems/cmake/c/CMakeLists.txt index f2dc26ef4..4534857a7 100644 --- a/examples/connext_dds/build_systems/cmake/c/CMakeLists.txt +++ b/examples/connext_dds/build_systems/cmake/c/CMakeLists.txt @@ -36,13 +36,13 @@ connextdds_rtiddsgen_run( add_custom_target(codegen_sources DEPENDS - ${HelloWorld_C_GENERATED_SOURCES} + ${HelloWorld_C_SOURCES} ) # Create the target for the publisher executable add_executable(HelloWorld_publisher "${CMAKE_CURRENT_SOURCE_DIR}/HelloWorld_publisher.c" - ${HelloWorld_C_GENERATED_SOURCES} + ${HelloWorld_C_SOURCES} ) # Link against the ConnextDDS libraries @@ -61,7 +61,7 @@ target_include_directories(HelloWorld_publisher # Create the target for the subscriber executable add_executable(HelloWorld_subscriber "${CMAKE_CURRENT_SOURCE_DIR}/HelloWorld_subscriber.c" - ${HelloWorld_C_GENERATED_SOURCES} + ${HelloWorld_C_SOURCES} ) # Link against the ConnextDDS libraries