From f6f0d40aed50a30539cfa59a56a556f06914c06d Mon Sep 17 00:00:00 2001 From: Timothy Simpson Date: Fri, 29 May 2026 11:45:32 +0100 Subject: [PATCH 1/2] Add ObjectComputing CLA --- CLA/CLA_ObjectComputing.md | 60 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 CLA/CLA_ObjectComputing.md diff --git a/CLA/CLA_ObjectComputing.md b/CLA/CLA_ObjectComputing.md new file mode 100644 index 0000000..504b78d --- /dev/null +++ b/CLA/CLA_ObjectComputing.md @@ -0,0 +1,60 @@ +# OMG DDS INTEROPERABILITY REPOSITORY - CONTRIBUTOR LICENSE AGREEMENT + +**This Contributor License Agreement ("Agreement") specifies the terms under which the individual or corporate entity specified in the signature block below (“You”) agree to make intellectual property contributions to the OMG DDS Interoperability Repository. BY SIGNING BELOW YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS AGREEMENT. If You are signing this Agreement in Your capacity as an employee, THEN YOUR EMPLOYER AND YOU ARE BOTH BOUND BY THIS AGREEMENT.** + +1. Definitions + + 1. "OMG DDS Interoperability Repository" (or “Repository”) means the Git repository [https://github.com/omg-dds/dds-rtps](https://github.com/omg-dds/dds-rtps). + + 2. "Moderator" means an entity or individual responsible for authorizing changes to the Repository. + + 3. "Submit" (or “Submitted”) means any submission, including source code, binaries, code, pull requests, issue reports, comments, etc., made to the Moderators for inclusion in the Repository either through the Git repository interface or through electronic file transfer. + + 4. A "Contribution" is any original work of authorship, including any modifications or additions to an existing work, that You Submit to the DDS Interoperability Repository. + + 5. A "User" is anyone who accesses the Repository. + +2. Allowable Contribution Representations + + 1. You represent that You have the necessary rights to the Contribution(s) to meet the obligations of this Agreement. If You are employed, Your employer has authorized Contribution(s) under this Agreement. + + 2. You represent that you have no knowledge of third-party intellectual property rights that are likely to be infringed by the Contribution(s). You represent that you have no knowledge that such infringement or any allegation of misappropriation of intellectual property rights is likely to be claimed or has already been claimed. + +3. License + + You grant Moderators a perpetual, worldwide, non-exclusive, assignable, paid-up license to publish, display, and redistribute the Contribution as part of the Repository. You also license to Moderators under the same terms any other intellectual property rights required to publish, display, and redistribute the Contributions as part of the Repository. You further grant all Users of the Repository a license to the Contribution under the terms of the [OMG DDS Interoperability Testing License](../LICENSE.md) included in the Repository. Moderators are under no obligation to publish Contributions. + +4. No Warranty, Consequential Damages. Limited Liability + + Other than explicitly stated herein, You provide the Contribution(s) "as is" with no warranty nor claims of fitness to any purpose. Neither party shall be liable for consequential or special damages of any kind. Other than for breach of warranty or representations herein, the liability of either party to the other shall be limited to $1000. + +5. General + + 1. If You are an agency of the United States Government, then this Agreement will be governed by the United States federal common law. Otherwise, this Agreement will be governed by the laws of the State of California except with regard to its choice of law rules. + + 2. A party may assign this Agreement to an entity acquiring essentially all of the party’s relevant business. + +6. Electronic Signatures + + "Electronic Signature" means any electronic sound, symbol, or process attached to or logically associated with a record and executed and adopted by a party with the intent to sign such record. + + Each party agrees that the Electronic Signatures, whether digital or encrypted, of the parties included in this Agreement are intended to authenticate this writing and to have the same force and effect as manual signatures. + + +IN WITNESS WHEREOF, You, intending to be legally bound, have executed this Agreement or caused Your employer’s proper and duly authorized officer to execute and deliver this Agreement, for good and valuable consideration, the sufficiency of which is hereby acknowledged, as of the day and year first written below. + +**For:** + +Entity Name: Object Computing, Inc. + +Address: 12140 Woodcrest Exec. Dr., Ste 250, St. Louis, MO 63141 USA + + ("**You**") + +**By:** + +Name: Timothy Simpson + +Title: Principal Software Engineer + +Date: May 29, 2026 From 04ec8bc708e10352e99ac8731c0445d5aac4876c Mon Sep 17 00:00:00 2001 From: Timothy Simpson Date: Fri, 29 May 2026 11:46:13 +0100 Subject: [PATCH 2/2] Add OpenDDS variant / test_main support --- src/cxx/opendds-cmake/CMakeLists.txt | 14 ++ src/cxx/test_main.cxx | 26 ++- src/cxx/variant_opendds.h | 260 +++++++++++++++++++++++++++ 3 files changed, 291 insertions(+), 9 deletions(-) create mode 100644 src/cxx/opendds-cmake/CMakeLists.txt create mode 100644 src/cxx/variant_opendds.h diff --git a/src/cxx/opendds-cmake/CMakeLists.txt b/src/cxx/opendds-cmake/CMakeLists.txt new file mode 100644 index 0000000..b69f723 --- /dev/null +++ b/src/cxx/opendds-cmake/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.12) +project(opendds_shape_main CXX) + +find_package(OpenDDS REQUIRED) + +add_executable(shape_main + ../test_main.cxx +) + +target_compile_definitions(shape_main + PRIVATE OPENDDS +) + +target_link_libraries(shape_main OpenDDS::Rtps_Udp) diff --git a/src/cxx/test_main.cxx b/src/cxx/test_main.cxx index 0307ea0..5776788 100644 --- a/src/cxx/test_main.cxx +++ b/src/cxx/test_main.cxx @@ -1033,11 +1033,14 @@ class TestApplication { //------------------------------------------------------------- TestApplication() { - dpf = NULL; - dp = NULL; - - pub = NULL; - sub = NULL; + dpf = NULL; + dp = NULL; + pub = NULL; + sub = NULL; + topic = NULL; + dr = NULL; + dw = NULL; + dt = NULL; } //------------------------------------------------------------- @@ -1046,6 +1049,9 @@ class TestApplication { if (dt) cleanup_type( dp, dt ); if (dp) dp->delete_contained_entities( ); if (dpf) dpf->delete_participant( dp ); +#if defined(OPENDDS) + TheServiceParticipant->shutdown(); +#endif } //------------------------------------------------------------- @@ -1054,7 +1060,7 @@ class TestApplication { #ifndef OBTAIN_DOMAIN_PARTICIPANT_FACTORY #define OBTAIN_DOMAIN_PARTICIPANT_FACTORY DomainParticipantFactory::get_instance() #endif - DomainParticipantFactory *dpf = OBTAIN_DOMAIN_PARTICIPANT_FACTORY; + dpf = OBTAIN_DOMAIN_PARTICIPANT_FACTORY; if (dpf == NULL) { logger.log_message("failed to create participant factory (missing license?).", Verbosity::ERROR); return false; @@ -1193,7 +1199,7 @@ class TestApplication { if ( options->disable_type_info ) dw_qos.rtps_writer.send_typeobj_v2 = 0; #endif - + printf("Create writer for topic: %s type: %s\n", options->topic_name, options->type_name ); dw = pub->create_datawriter( topic, dw_qos, NULL, 0); @@ -1278,14 +1284,14 @@ class TestApplication { logger.log_message(" * ignore_member_names = " + std::to_string(dr_qos.type_consistency.ignore_member_names), Verbosity::DEBUG ); logger.log_message(" * prevent_type_widening = " + std::to_string(dr_qos.type_consistency.prevent_type_widening), Verbosity::DEBUG ); logger.log_message(" * force_type_validation = " + std::to_string(dr_qos.type_consistency.force_type_validation), Verbosity::DEBUG ); - + #if defined(TWINOAKS_COREDX) if ( options->disable_type_info ) dr_qos.rtps_reader.send_typeobj_v2 = 0; #endif printf("Create reader for topic: %s\n", options->topic_name ); - + dr = sub->create_datareader(topic, dr_qos, NULL, LISTENER_STATUS_MASK_NONE); @@ -1378,6 +1384,8 @@ class TestApplication { DynamicDataWriter *ddw = dynamic_cast(dw); #if defined(RTI_CONNEXT_DDS) ddw->write(*dd, HANDLE_NIL); +#elif defined(OPENDDS) + ddw->write(dd, HANDLE_NIL); #elif defined(TWINOAKS_COREDX) ddw->write(dd, HANDLE_NIL); #endif diff --git a/src/cxx/variant_opendds.h b/src/cxx/variant_opendds.h new file mode 100644 index 0000000..70ee113 --- /dev/null +++ b/src/cxx/variant_opendds.h @@ -0,0 +1,260 @@ +#ifndef VARIANT_OPENDDS_H +#define VARIANT_OPENDDS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define LISTENER_STATUS_MASK_ALL (0xFFFFFFFF) +#define CONFIGURE_PARTICIPANT_FACTORY configure_opendds(); + +#define DDS_BOOLEAN_TRUE true +#define DDS_BOOLEAN_FALSE false +#define DDS_RETCODE_OK 0 + +namespace DDS { + typedef DynamicType* DynamicType_ptr_xtypes; +} + +inline OpenDDS::RTPS::RtpsDiscovery_rch& opendds_rtps_discovery() { + static OpenDDS::RTPS::RtpsDiscovery_rch disc; + return disc; +} + +inline bool& opendds_type_information_disabled() { + static bool disabled = false; + return disabled; +} + +inline void opendds_set_xtypes(OpenDDS::RTPS::RtpsDiscoveryConfig::UseXTypes use_xtypes) { + OpenDDS::RTPS::RtpsDiscovery_rch& disc = opendds_rtps_discovery(); + if (!disc.is_nil()) { + disc->use_xtypes(use_xtypes); + } +} + +inline void configure_opendds() { + using namespace OpenDDS::DCPS; + using namespace OpenDDS::RTPS; + + TheServiceParticipant->config_store()->set( + "RTPS_DISCOVERY_RTPS_DISCOVERY_SPDP_PORT_MODE", "system"); + + TransportInst_rch inst = TransportRegistry::instance()->get_inst("rtps_transport"); + if (inst.is_nil()) { + inst = TransportRegistry::instance()->create_inst("rtps_transport", "rtps_udp"); + } + TransportConfig_rch config = TransportRegistry::instance()->get_config("rtps_interop_demo"); + if (config.is_nil()) { + config = TransportRegistry::instance()->create_config("rtps_interop_demo"); + if (!inst.is_nil()) { + config->instances_.push_back(inst); + } + } + TransportRegistry::instance()->global_config(config); + + RtpsDiscovery_rch& disc = opendds_rtps_discovery(); + if (disc.is_nil()) { + disc = make_rch("RtpsDiscovery"); + TheServiceParticipant->add_discovery(static_rchandle_cast(disc)); + } + TheServiceParticipant->set_default_discovery(disc->key()); +} + +inline void StringSeq_push(DDS::StringSeq &string_seq, const char *elem) { + CORBA::ULong len = string_seq.length(); + string_seq.length(len + 1); + string_seq[len] = CORBA::string_dup(elem); +} + +inline DDS::TypeConsistencyEnforcementQosPolicy TypeConsistency_get_default() { + DDS::TypeConsistencyEnforcementQosPolicy policy; + policy.kind = DDS::ALLOW_TYPE_COERCION; + policy.ignore_member_names = false; + policy.ignore_sequence_bounds = true; + policy.ignore_string_bounds = true; + policy.prevent_type_widening = false; + policy.force_type_validation = false; + return policy; +} + +inline DDS::DynamicTypeSupport_ptr get_type_support(DDS::DynamicType_ptr dt) { + return new ::DDS::DynamicTypeSupport(dt); +} + +inline const char* get_qos_policy_name(DDS::QosPolicyId_t policy_id) { + return "Unknown Policy"; +} + +inline void disable_type_information(DDS::DomainParticipantQos &dp_qos) { + (void)dp_qos; + opendds_type_information_disabled() = true; + opendds_set_xtypes(OpenDDS::RTPS::RtpsDiscoveryConfig::XTYPES_NONE); +} + +inline void set_type_object_version(DDS::DomainParticipantQos &dp_qos, int version) { + (void)dp_qos; + if (opendds_type_information_disabled()) { + opendds_set_xtypes(OpenDDS::RTPS::RtpsDiscoveryConfig::XTYPES_NONE); + return; + } + if (version != 2) { + fprintf(stderr, "OpenDDS does not support selecting TypeObject version %d; using XTypes complete TypeInformation.\n", version); + } + opendds_set_xtypes(OpenDDS::RTPS::RtpsDiscoveryConfig::XTYPES_COMPLETE); +} + +inline void print_type_objectV1(DDS::DynamicType_ptr dt) { +} + +inline void print_type_objectV2(DDS::DynamicType_ptr dt) { +} + +inline void print_typeid(DDS::DynamicType_ptr dt, int version) { + (void)dt; + (void)version; +} + +inline std::string make_xtypes_path(const char* folder, const char* file, const char* subdir, const char* ext) { + if (folder && file) { + return std::string(folder) + "/" + subdir + "/" + file + ext; + } + if (file) { + return std::string(file); + } + if (folder) { + return std::string(folder); + } + return std::string(); +} + +inline DDS::DynamicType_ptr create_type(DDS::DomainParticipant_ptr dp, const char* type_folder, const char* type_file, const char* type_name) { + (void)dp; + if (!type_name) { + return 0; + } + + const std::string file_path = make_xtypes_path(type_folder, type_file, "xml", ".xml"); + if (file_path.empty()) { + return 0; + } + + DDS::DynamicType_var type; + const DDS::ReturnCode_t rc = OpenDDS::XTypes::load_xml_type( + type, ACE_TEXT_CHAR_TO_TCHAR(file_path.c_str()), type_name); + return rc == DDS::RETCODE_OK ? type._retn() : 0; +} + +inline DDS::DynamicType_ptr CREATE_TYPE(DDS::DomainParticipant_ptr dp, const char* type_folder, const char* type_file, const char* type_name) { + return create_type(dp, type_folder, type_file, type_name); +} + +inline DDS::ReturnCode_t register_type(DDS::DomainParticipant_ptr dp, DDS::DynamicType_ptr dt, const char* type_name) { + if (!dp || !dt) return DDS::RETCODE_ERROR; + DDS::DynamicTypeSupport_var ts = new ::DDS::DynamicTypeSupport(dt); + return ts->register_type(dp, type_name); +} + +inline DDS::ReturnCode_t REGISTER_TYPE(DDS::DomainParticipant_ptr dp, DDS::DynamicType_ptr dt, const char* type_name) { + return register_type(dp, dt, type_name); +} + +inline void cleanup_type(DDS::DomainParticipant_ptr dp, DDS::DynamicType_ptr dt) { + (void)dp; + (void)dt; +} + +inline void CLEANUP_TYPE(DDS::DomainParticipant_ptr dp, DDS::DynamicType_ptr dt) { + cleanup_type(dp, dt); +} + +inline DDS::DynamicData_ptr create_data(DDS::DynamicType_ptr dt) { + return ::DDS::DynamicDataFactory::get_instance()->create_data(dt); +} + +inline DDS::DynamicData_ptr CREATE_DATA(DDS::DynamicType_ptr dt) { + return create_data(dt); +} + +inline DDS::ReturnCode_t init_data(DDS::DynamicData_ptr dd, const char* data_folder, const char* data_file) { + if (!dd || (!data_folder && !data_file)) return DDS::RETCODE_OK; + + const std::string file_path = make_xtypes_path(data_folder, data_file, "json", ".json"); + OpenDDS::XTypes::DynamicDataJsonOptions options; + options.discriminator_format = OpenDDS::XTypes::DYNAMIC_DATA_JSON_DISCRIMINATOR_AUTO; + return OpenDDS::XTypes::dynamic_data_from_json_file( + dd, ACE_TEXT_CHAR_TO_TCHAR(file_path.c_str()), options); +} + +inline DDS::ReturnCode_t INIT_DATA(DDS::DynamicData_ptr dd, const char* data_folder, const char* data_file) { + return init_data(dd, data_folder, data_file); +} + +inline void print_data(DDS::DynamicData_ptr dd) { + OpenDDS::XTypes::DynamicDataJsonOptions options; + options.discriminator_format = OpenDDS::XTypes::DYNAMIC_DATA_JSON_DISCRIMINATOR_ACTIVE_MEMBER; + std::string json; + if (OpenDDS::XTypes::dynamic_data_to_json(json, dd, options) == DDS::RETCODE_OK) { + printf("%s\n", json.c_str()); + } else { + printf("{\"\":true}\n"); + } +} + +inline void PRINT_DATA(DDS::DynamicData_ptr dd) { + print_data(dd); +} + +inline void cleanup_data(DDS::DynamicData_ptr dd) { + (void)dd; +} + +inline void CLEANUP_DATA(DDS::DynamicData_ptr dd) { + cleanup_data(dd); +} + +inline bool check_data(DDS::DynamicData_ptr dd, const char* data_folder, const char* data_file) { + if (!dd || (!data_folder && !data_file)) return true; + DDS::DynamicData_var expected = create_data(dd->type()); + if (init_data(expected, data_folder, data_file) != DDS_RETCODE_OK) return false; + const bool equal = OpenDDS::XTypes::dynamic_data_equal(dd, expected); + if (!equal) { + printf("Expected:\n"); + print_data(expected); + } + return equal; +} + +inline bool CHECK_DATA(DDS::DynamicData_ptr dd, const char* data_folder, const char* data_file) { + return check_data(dd, data_folder, data_file); +} + +#define SECONDS_FIELD_NAME sec +#define LISTENER_STATUS_MASK_NONE 0 +#define GET_TOPIC_DESCRIPTION(dr) dr->get_topicdescription() +#define OBTAIN_DOMAIN_PARTICIPANT_FACTORY TheParticipantFactory + +struct TypeConsistencyKind_O { + CORBA::Short value; + TypeConsistencyKind_O(CORBA::Short v) : value(v) {} + operator CORBA::Short() const { return value; } +}; +#define TypeConsistencyKind TypeConsistencyKind_O + +#define sample_info (&sample_infos[i]) +#define sample samples[i] + +#endif