From 07bf0f06ec639d87437d4013d6083fe464ec8fa5 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Fri, 24 Nov 2023 18:28:52 +0100 Subject: [PATCH 1/4] Adding dynamic data enum example --- examples/connext_dds/CMakeLists.txt | 1 + .../dynamic_data_get_enum_value/.gitignore | 4 + .../dynamic_data_get_enum_value/README.md | 26 +++ .../c++11/CMakeLists.txt | 49 ++++++ .../c++11/README.md | 112 +++++++++++++ .../c++11/dynamic_data_enum_example.cxx | 153 ++++++++++++++++++ 6 files changed, 345 insertions(+) create mode 100644 examples/connext_dds/dynamic_data_get_enum_value/.gitignore create mode 100644 examples/connext_dds/dynamic_data_get_enum_value/README.md create mode 100644 examples/connext_dds/dynamic_data_get_enum_value/c++11/CMakeLists.txt create mode 100644 examples/connext_dds/dynamic_data_get_enum_value/c++11/README.md create mode 100644 examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx diff --git a/examples/connext_dds/CMakeLists.txt b/examples/connext_dds/CMakeLists.txt index ac82c71f6..3142cb969 100644 --- a/examples/connext_dds/CMakeLists.txt +++ b/examples/connext_dds/CMakeLists.txt @@ -107,6 +107,7 @@ if(NOT DEFINED CONNEXTDDS_CONNEXT_DDS_EXAMPLES) "compression" "detect_samples_dropped" "dynamic_data_access_union_discriminator" + "dynamic_data_get_enum_value" "dynamic_data_nested_structs" "dynamic_data_request_reply" "dynamic_data_sequences" diff --git a/examples/connext_dds/dynamic_data_get_enum_value/.gitignore b/examples/connext_dds/dynamic_data_get_enum_value/.gitignore new file mode 100644 index 000000000..fe580da99 --- /dev/null +++ b/examples/connext_dds/dynamic_data_get_enum_value/.gitignore @@ -0,0 +1,4 @@ +# This project has a specific makefile / solution +!*.sln +!*.vcxproj +!makefile* diff --git a/examples/connext_dds/dynamic_data_get_enum_value/README.md b/examples/connext_dds/dynamic_data_get_enum_value/README.md new file mode 100644 index 000000000..d3c3b7178 --- /dev/null +++ b/examples/connext_dds/dynamic_data_get_enum_value/README.md @@ -0,0 +1,26 @@ +# Dynamic Data API: access to complex member example + +## Concept + +*Dynamic Data API* allows to create topic samples in a programmatically manner +without defining an IDL in compile time. + +This example shows how to access enum ordinal values by name from a +dynamic data object. + +## Example description + +In this example, we show three different scenarios to get the ordinal value of +an enum member by using `DynamicData` and `DynamicType` elements. + +The first scenario shows how to get the enum member ordinal value from a +`DynamicType`. In this case, you have to specify the enum field name and +the enum element string. In this case, there is a translation from the +`DynamicType` into a `StructType` and then the element into an `EnumType`. + +In the second scenario, a for loop iterates through all elements and check +which one is an `ENUMERATION_TYPE`. Then, if this enum is the type that we are +looking for, then it prints the specified values. + +In the third scenario, the `EnumType` is gotten from the a DynamicData by using +the `member_type` API. diff --git a/examples/connext_dds/dynamic_data_get_enum_value/c++11/CMakeLists.txt b/examples/connext_dds/dynamic_data_get_enum_value/c++11/CMakeLists.txt new file mode 100644 index 000000000..c3d1caaec --- /dev/null +++ b/examples/connext_dds/dynamic_data_get_enum_value/c++11/CMakeLists.txt @@ -0,0 +1,49 @@ +# +# (c) 2018 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. +# +cmake_minimum_required(VERSION 3.11) +project(rtiexamples-dynamic-data-access-enum-discriminator) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +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 for core and API libraries +find_package(RTIConnextDDS + "7.0.0" + REQUIRED + COMPONENTS + core +) + +add_executable(dynamic_data_enum_example_cxx2 + "${CMAKE_CURRENT_SOURCE_DIR}/dynamic_data_enum_example.cxx" +) + +target_link_libraries(dynamic_data_enum_example_cxx2 + PRIVATE + RTIConnextDDS::cpp2_api +) + +set_target_properties(dynamic_data_enum_example_cxx2 + PROPERTIES + OUTPUT_NAME "dynamic_data_enum_example") + +if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND CMAKE_CXX_COMPILER_ID MATCHES "GNU") + set_target_properties(dynamic_data_enum_example_cxx2 + PROPERTIES + LINK_FLAGS -Wl,--no-as-needed) +endif() diff --git a/examples/connext_dds/dynamic_data_get_enum_value/c++11/README.md b/examples/connext_dds/dynamic_data_get_enum_value/c++11/README.md new file mode 100644 index 000000000..08a0eb6a9 --- /dev/null +++ b/examples/connext_dds/dynamic_data_get_enum_value/c++11/README.md @@ -0,0 +1,112 @@ +# Example code: Get Enum Ordinals in Dynamic Data + +## 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 + +Run the following command from the example directory to execute the application. + +On *UNIX* systems: + +```bash +./dynamic_data_enum_example +``` + +On *Windows* Systems: + +```bash +dynamic_data_enum_example +``` + +## 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 +Solutions 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 used to + build the source code. All the valid values are described in the CMake + documentation for [CMake + Generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html). + +For example, to build an example in Debug/Dynamic mode run CMake as follows: + +```sh +cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON .. -G "Visual Studio 15 2017" -A x64 +``` + +### Configuring Connext Installation Path and Architecture + +The CMake build infrastructure will try to guess the location of your Connext +installation and the Connext architecture based on the default settings +for your host platform. If you installed Connext in a custom location, you +can use the `CONNEXTDDS_DIR` variable to indicate the path to your RTI Connext +installation folder. For example: + +```sh +cmake -DCONNEXTDDS_DIR=/home/rti/rti_connext_dds-x.y.z .. +``` + +Also, if you installed libraries for multiple target architectures on your system +(i.e., you installed more than one target `.rtipkg` file), 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 + +This example does not require the usage of rtiddsgen. Therefore, the +`CMakeLists.txt` script just creates the executable and link it with the Connext +API. + +For a more comprehensive example on how to build an RTI Connext 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/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx b/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx new file mode 100644 index 000000000..b5680f233 --- /dev/null +++ b/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx @@ -0,0 +1,153 @@ +/******************************************************************************* + (c) 2005-2015 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. + ******************************************************************************/ + +#include +#include + +#include + +using namespace dds::core::xtypes; + +EnumType create_enum_type() +{ + return EnumType( + "EngineState", + { EnumMember("off", 0), + EnumMember("on", 42)}); +} + +DynamicType create_struct_dynamic_type() +{ + // First create the type code for a struct + StructType my_struct("EnumStruct"); + EnumType inner_enum = create_enum_type(); + + // Member 1 will be an enum EngineState named engine_state_element + my_struct.add_member(Member("engine_state_element", + static_cast(inner_enum))); + + return my_struct; +} + +int32_t get_enum_ordinal_value_by_name( + DynamicType struct_dynamic_type, + std::string enum_element) { + + //Get value using scenario 1 of `print_enum_ordinal_value_by_name` + const StructType &dynamic_struct = + static_cast(struct_dynamic_type); + EnumType enum_type = static_cast( + dynamic_struct.member("engine_state_element").type()); + + // Return the specified value + return enum_type.member(enum_element).ordinal(); +} + +void print_enum_ordinal_values_from_dynamic_type( + DynamicType struct_dynamic_type) { + + // If you need a switch/case statement you can use + // enum_dynamic_type.kind().underlying() + if (struct_dynamic_type.kind() == TypeKind::STRUCTURE_TYPE) { + + // Different ways of getting the enum ordinals + // Scenario 1. We already know the member name and it is an enum + + // cast the DynamicType into a StructType + const StructType &dynamic_struct = + static_cast(struct_dynamic_type); + + EnumType enum_type = static_cast( + dynamic_struct.member("engine_state_element").type()); + + std::cout << "Scenario 1 - print enum ordinals from DynamicType" << std::endl; + std::cout << "On: " << enum_type.member("on").ordinal() << std::endl; + std::cout << "Off: " << enum_type.member("off").ordinal() << std::endl << std::endl; + + + // Scenario 2, iterate through all the elements in the StructType + // and do something for the enums + for (auto member : dynamic_struct.members()) { + // here you may want to use a switch/case + if (member.type().kind() == TypeKind::ENUMERATION_TYPE) { + EnumType engine_state_type = static_cast( + member.type()); + + // This assumes that we know the enum strings + if (engine_state_type.name() == "EngineState") { + std::cout << "Scenario 2 - print enum ordinals from DynamicType iterating members" << std::endl; + std::cout << "On: " << engine_state_type.member("on").ordinal() << std::endl; + std::cout << "Off: " << engine_state_type.member("off").ordinal() << std::endl << std::endl; + } + } + } + } + + return; +} + +void print_enum_ordinal_values_from_dynamic_data( + DynamicData struct_dynamic_data) { + + // Scenario 3, we can get the member type directly as a DynamicType + // This assumes that we already know the name "EngineState" and that it is + // an Enum. + // This is similar to Scenario 1, but getting directly the EngineState as a + // DynamicType instead of the struct that contains it. + DynamicType enum_member_type = struct_dynamic_data.member_type("engine_state_element"); + EnumType enum_type = static_cast(enum_member_type); + + std::cout << "Scenario 3 - print enum ordinals from DynamicData" << std::endl; + std::cout << "On: " << enum_type.member("on").ordinal() << std::endl; + std::cout << "Off: " << enum_type.member("off").ordinal() << std::endl << std::endl; + + return; +} + +void example() +{ + // Create the type of the struct with the enum + DynamicType enum_dynamic_type = create_struct_dynamic_type(); + + std::cout << "Print IDL corresponding type" << std::endl; + print_idl(enum_dynamic_type); + std::cout << std::endl; + + // Create the DynamicData. + DynamicData enum_data(enum_dynamic_type); + + // Set the value of the current member + enum_data.value( + "engine_state_element", + get_enum_ordinal_value_by_name(enum_dynamic_type, "on")); + + // Print the values of the enum elements from a dynamic data. It uses + // the DynamicType internally. + print_enum_ordinal_values_from_dynamic_type(enum_dynamic_type); + print_enum_ordinal_values_from_dynamic_data(enum_data); + + std::cout << "Print enum ordinal value of DynamicData" << std::endl; + std::cout << "Value: " << enum_data.value("engine_state_element") << std::endl; + + return; +} + +int main(int argc, char *argv[]) +{ + try { + example(); + } catch (const std::exception &ex) { + std::cerr << "Caught exception: " << ex.what() << std::endl; + return -1; + } + + return 0; +} From 87354f692f2df5ea9a242c945b9920e40c388a0f Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Fri, 24 Nov 2023 18:35:08 +0100 Subject: [PATCH 2/4] Updating copyright notice --- .../dynamic_data_get_enum_value/c++11/CMakeLists.txt | 2 +- .../c++11/dynamic_data_enum_example.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/connext_dds/dynamic_data_get_enum_value/c++11/CMakeLists.txt b/examples/connext_dds/dynamic_data_get_enum_value/c++11/CMakeLists.txt index c3d1caaec..e5cc4cb10 100644 --- a/examples/connext_dds/dynamic_data_get_enum_value/c++11/CMakeLists.txt +++ b/examples/connext_dds/dynamic_data_get_enum_value/c++11/CMakeLists.txt @@ -1,5 +1,5 @@ # -# (c) 2018 Copyright, Real-Time Innovations, Inc. All rights reserved. +# (c) 2023 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 diff --git a/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx b/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx index b5680f233..a014f89fb 100644 --- a/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx +++ b/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx @@ -1,5 +1,5 @@ /******************************************************************************* - (c) 2005-2015 Copyright, Real-Time Innovations, Inc. All rights reserved. + (c) 2023 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 From 112c2207ee3cb053917933c4736468c2f275a824 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Mon, 27 Nov 2023 11:56:25 +0100 Subject: [PATCH 3/4] Fixed linter issues --- .../c++11/dynamic_data_enum_example.cxx | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx b/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx index a014f89fb..ec48749cf 100644 --- a/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx +++ b/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx @@ -20,8 +20,7 @@ EnumType create_enum_type() { return EnumType( "EngineState", - { EnumMember("off", 0), - EnumMember("on", 42)}); + { EnumMember("off", 0), EnumMember("on", 42) }); } DynamicType create_struct_dynamic_type() @@ -31,17 +30,19 @@ DynamicType create_struct_dynamic_type() EnumType inner_enum = create_enum_type(); // Member 1 will be an enum EngineState named engine_state_element - my_struct.add_member(Member("engine_state_element", - static_cast(inner_enum))); + my_struct.add_member(Member( + "engine_state_element", + static_cast(inner_enum))); return my_struct; } int32_t get_enum_ordinal_value_by_name( DynamicType struct_dynamic_type, - std::string enum_element) { + std::string enum_element) +{ - //Get value using scenario 1 of `print_enum_ordinal_value_by_name` + // Get value using scenario 1 of `print_enum_ordinal_value_by_name` const StructType &dynamic_struct = static_cast(struct_dynamic_type); EnumType enum_type = static_cast( @@ -52,25 +53,27 @@ int32_t get_enum_ordinal_value_by_name( } void print_enum_ordinal_values_from_dynamic_type( - DynamicType struct_dynamic_type) { + DynamicType struct_dynamic_type) +{ // If you need a switch/case statement you can use // enum_dynamic_type.kind().underlying() if (struct_dynamic_type.kind() == TypeKind::STRUCTURE_TYPE) { - // Different ways of getting the enum ordinals // Scenario 1. We already know the member name and it is an enum // cast the DynamicType into a StructType const StructType &dynamic_struct = - static_cast(struct_dynamic_type); + static_cast(struct_dynamic_type); EnumType enum_type = static_cast( - dynamic_struct.member("engine_state_element").type()); + dynamic_struct.member("engine_state_element").type()); - std::cout << "Scenario 1 - print enum ordinals from DynamicType" << std::endl; + std::cout << "Scenario 1 - print enum ordinals from DynamicType" + << std::endl; std::cout << "On: " << enum_type.member("on").ordinal() << std::endl; - std::cout << "Off: " << enum_type.member("off").ordinal() << std::endl << std::endl; + std::cout << "Off: " << enum_type.member("off").ordinal() << std::endl + << std::endl; // Scenario 2, iterate through all the elements in the StructType @@ -78,14 +81,21 @@ void print_enum_ordinal_values_from_dynamic_type( for (auto member : dynamic_struct.members()) { // here you may want to use a switch/case if (member.type().kind() == TypeKind::ENUMERATION_TYPE) { - EnumType engine_state_type = static_cast( - member.type()); + EnumType engine_state_type = + static_cast(member.type()); // This assumes that we know the enum strings if (engine_state_type.name() == "EngineState") { - std::cout << "Scenario 2 - print enum ordinals from DynamicType iterating members" << std::endl; - std::cout << "On: " << engine_state_type.member("on").ordinal() << std::endl; - std::cout << "Off: " << engine_state_type.member("off").ordinal() << std::endl << std::endl; + std::cout << "Scenario 2 - print enum ordinals from " + "DynamicType iterating members" + << std::endl; + std::cout << "On: " + << engine_state_type.member("on").ordinal() + << std::endl; + std::cout << "Off: " + << engine_state_type.member("off").ordinal() + << std::endl + << std::endl; } } } @@ -95,19 +105,22 @@ void print_enum_ordinal_values_from_dynamic_type( } void print_enum_ordinal_values_from_dynamic_data( - DynamicData struct_dynamic_data) { - + DynamicData struct_dynamic_data) +{ // Scenario 3, we can get the member type directly as a DynamicType // This assumes that we already know the name "EngineState" and that it is // an Enum. // This is similar to Scenario 1, but getting directly the EngineState as a // DynamicType instead of the struct that contains it. - DynamicType enum_member_type = struct_dynamic_data.member_type("engine_state_element"); + DynamicType enum_member_type = + struct_dynamic_data.member_type("engine_state_element"); EnumType enum_type = static_cast(enum_member_type); - std::cout << "Scenario 3 - print enum ordinals from DynamicData" << std::endl; + std::cout << "Scenario 3 - print enum ordinals from DynamicData" + << std::endl; std::cout << "On: " << enum_type.member("on").ordinal() << std::endl; - std::cout << "Off: " << enum_type.member("off").ordinal() << std::endl << std::endl; + std::cout << "Off: " << enum_type.member("off").ordinal() << std::endl + << std::endl; return; } @@ -126,8 +139,8 @@ void example() // Set the value of the current member enum_data.value( - "engine_state_element", - get_enum_ordinal_value_by_name(enum_dynamic_type, "on")); + "engine_state_element", + get_enum_ordinal_value_by_name(enum_dynamic_type, "on")); // Print the values of the enum elements from a dynamic data. It uses // the DynamicType internally. @@ -135,7 +148,8 @@ void example() print_enum_ordinal_values_from_dynamic_data(enum_data); std::cout << "Print enum ordinal value of DynamicData" << std::endl; - std::cout << "Value: " << enum_data.value("engine_state_element") << std::endl; + std::cout << "Value: " << enum_data.value("engine_state_element") + << std::endl; return; } From ea6a738f8ce3cd25da0c66c719c1bd0cd5cd7a63 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Mon, 27 Nov 2023 11:58:00 +0100 Subject: [PATCH 4/4] Fixed linter issues --- .../c++11/dynamic_data_enum_example.cxx | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx b/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx index ec48749cf..c2f7e62fb 100644 --- a/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx +++ b/examples/connext_dds/dynamic_data_get_enum_value/c++11/dynamic_data_enum_example.cxx @@ -41,7 +41,6 @@ int32_t get_enum_ordinal_value_by_name( DynamicType struct_dynamic_type, std::string enum_element) { - // Get value using scenario 1 of `print_enum_ordinal_value_by_name` const StructType &dynamic_struct = static_cast(struct_dynamic_type); @@ -55,7 +54,6 @@ int32_t get_enum_ordinal_value_by_name( void print_enum_ordinal_values_from_dynamic_type( DynamicType struct_dynamic_type) { - // If you need a switch/case statement you can use // enum_dynamic_type.kind().underlying() if (struct_dynamic_type.kind() == TypeKind::STRUCTURE_TYPE) {