.. _section-appgen: Application Generation Using XML ================================ |rti_me|'s Application Generation feature enables you to specify an application in XML. It simplifies and accelerates application development by enabling the creation of DDS *Entities* (and registration of the factories) used in an application by compiling an XML configuration file, linking the result to an application, and calling a single API. Once created, all *Entities* can be retrieved from the application code using standard "lookup_by_name" operations so that they can be used to read and write data. UDP transport, DPDE (Dynamic Participant Dynamic Endpoint), and DPSE (Dynamic Participant Static Endpoint) discovery configuration can also be configured as needed. C or C++ source code is generated from the XML configuration and compiled with the application. Once you have your XML file definition, you must use the Micro Application Generator (MAG) tool to load the XML file definition into |me|. MAG is needed because |me| does not include an XML parser (this would significantly increase code size and amount of memory needed). MAG generates C source code from the XML configuration that you must then compile with the application. The generated C source code contains the same information as the XML configuration file. The generated C source code can be used from both the :link_connextmicro_dds_api_cpp_up_one:`C API Reference ` and :link_connextmicro_dds_api_cpp_up_one:`C++ API Reference `. The |me| Application Generation is enabled by default in this release when compiling with rtime-make. However, future releases may disable the feature by default. Thus, it is advised to always compile with the |me| Application Generation feature enabled (-DRTIME_DDS_ENABLE_APPGEN=1 to CMake). See :ref:`section-microum-examples`. .. _section-appgen-define-app: Defining an Application in XML ------------------------------ Each *Entity* configured in the XML file is given a name. This name is used to retrieve the entities at runtime using the |me| API. In the XML file, you need to distinguish between two names: - Configuration name: The name of a specific *Entity*'s configuration. It is given by the name attribute of the corresponding element. - Entity name in the *Entity*'s QoS: The Entity name in the *Entity*'s QoS. At runtime, the *Entity* will be created using the Entity name in the *Entity*'s QoS; the configuration name will be used if this is an empty string. The attribute multiplicity indicates that a set of *Entities* should be created from the same configuration. Since each *Entity* must have a unique name, the system will automatically append a number to the Entity name in the *Entity*'s QoS (or, if it is an empty string, the configuration name) to obtain the Entity name. For example, if we specified a multiplicity of “N”, then for each index “i” between 0 and N-1, the system will assign Entity names according to the table below: +-----------------------+----------+ | Entity Name | Index: i | +=======================+==========+ | “configuration_name” | 0 | +-----------------------+----------+ |“configuration_name#i” | [1,N-1] | +-----------------------+----------+ That is, the *Entity* name followed by the token “#” and an index. See :ref:`section-appgen-helloworld-example` for an example XML file. .. _section-appgen-important-points: Important Points ^^^^^^^^^^^^^^^^ Applications can create a |rti_me| *Entity* from a *DomainParticipant* configuration described in the XML configuration file. All the *Entities* defined by such *DomainParticipant* configuration are created automatically as part of the creation. In addition, multiple *DomainParticipant* configurations may be defined within a single XML configuration file. All the *Entities* created from a *DomainParticipant* configuration are automatically assigned an entity name. *Entities* can be retrieved via “lookup_by_name” operations specifying their name. Each *Entity* stores its own name in the QoS policies of the *Entity* so that they can be retrieved locally (via a lookup) and communicated via discovery. A configuration file is not tied to the application that uses it. Different applications may run using the same configuration file. A single file may define multiple *DomainParticipant* configurations. Normally, a single application will instantiate only one *DomainParticipant*, but an application can instantiate as many *DomainParticipants* as needed. Changes in the XML configuration file require regenerating the C/C++ source code and recompiling the application. .. _section-appgen-create-app: Generating the Application from XML ----------------------------------- |me| comes with a tool, the Micro Application Generator (MAG). This tool is used to generate supporting files to create XML-defined applications at runtime. .. _section-appgen-MAG: Micro Application Generator (MAG) Tool ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Micro Application Generator (MAG) is a required tool to configure |me| applications by generating code from an XML configuration file; it creates DDS entities and registers all the components needed for a |me|-based application. MAG can process your own XML configuration file, or it can process an *XML-Based Application Creation* file that you created for |rti_core_pro|. .. image:: /images/MAG_Overview.png |me| Application Generation, in combination with MAG, enables two important use cases: - Users who may eventually develop with |me|, but who haven't determined their final platform, can prototype applications on a generic platform and validate that the QoS and DDS Entity configuration is within scope of what |me| supports. MAG ignores fields in the XML file that |me| doesn't use (and produces an error for the few fields it cannot ignore; see "Unsupported values" in :ref:`section-appgen-errors-invalid-config`). - Users who want to develop directly with |me| can simplify their development efforts through shared XML files that can be configuration-managed. This reduces the burden on system integrators who want to configure |me| systems without having to manually code in static configurations. The main features of MAG are: - Generates code for the languages supported by |me|: C and C++. - Automatically configures the remote entities that are needed to communicate with applications that use static discovery. - Automatically tries to use the default values used by |me|, to reduce the size of the generated code. - Optimizes the components used by your application. By default, MAG generates code that will unregister transports that your application is not using. - Ignores fields and transports not supported by |me| (any fields or transports not described in the API Reference) and raises errors for things it can't ignore. See :ref:`section-appgen-errors-invalid-config`. .. note:: - MAG has been tested with Java 17.0.6, which is included in the |core_pro| installation. - MAG does not support customizable templates. (It doesn't support the functionality described in :link_external_community_doc_codegen_um:`Customizing the Generated Code ` in the *Code Generator User's Manual*.) Generating the Application with MAG ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Running MAG """"""""""" To run the MAG tool, use the following command: For example, on a Windows system: .. code-block:: none /rtiddsmag/scripts/rtiddsmag.bat -language C -referencedFile HelloWorldQos.xml HelloWorld.xml For example, on a Linux or macOS system: .. code-block:: none /rtiddsmag/scripts/rtiddsmag -language C -referencedFile HelloWorldQos.xml HelloWorld.xml Please refer to :ref:`section-command-line-options` for valid command-line options. Generated Files """"""""""""""" The following table shows the files that MAG creates for an example XML file, **HelloWorld.xml** (which contains the application definition) and a referenced file, **HelloWorldQos.xml** (which contains the QoS definition). This second file is optional; you can define the QoS in the application file. .. note:: Changes in the XML configuration file require regenerating the C/C++ source code and recompiling the application. .. list-table:: C and C++ Files Created for Example HelloWorld.xml :widths: 30 70 :header-rows: 1 * - Generated Files - Description * - HelloWorldAppgen.h (C and C++) - Generated code for each DDS *Entity* and its run-time components. * - HelloWorldAppgen.c (C and C++) - Generated code for each Entity Model; also contains the values of each array used in the header file. * - HelloWorldAppgen_plugin.h (C++ only) - Header file that contains the declarations of all the wrappers. * - HelloWorldAppgen_plugin.cxx (C++ only) - A wrapper for the _get() call (get_plugin_type): .. code-block:: none struct DDS_TypePluginI *HelloWorldPlugin_get_cpp(void) { return HelloWorldPlugin_get(); } .. warning:: You should not modify the generated code. MAG will overwrite your modifications when it regenerates the C/C++ code from XML if the ``-replace`` argument is used. .. _section-command-line-options: MAG Command-Line Options ^^^^^^^^^^^^^^^^^^^^^^^^ The following table shows the options available when using *rtiddsmag* to generate code for |me| applications. .. list-table:: Command-Line Options for rtiddsmag :widths: 30 70 :header-rows: 1 * - Option - Description * - -d - Generates the output in the specified directory. By default, MAG will generate files in the directory where the XML file is located. * - -dontAddLocations - Use this flag to avoid adding the input file location of fields into the generated files. By default (when this flag is not used), MAG will add the location where an entity was defined in the XML file. The location will be placed above the definition of that entity in the generated code. * - -dontOptimizeSE - Use this flag to avoid static endpoint discovery optimization. Then MAG will include all *DataWriters* and *DataReaders* when calculating the remote entities. By default (when this option is not used) MAG will optimize the number of remote entities by only including Data Writers and *DataReaders* that use the same Topic in the remote model. * - -dontUpdateResourceLimits - Use this flag to avoid automatically updating the resource limit settings for the DomainParticipantFactory, *DomainParticipants*, *DataReaders*, and *DataWriters*. **Note:** The use of this flag for the DomainParticipantFactory is currently not supported. By default (when this flag is not used), MAG will update the resource limits so it will at least be able to support the entities defined in the XML file. If your applications communicate with more remote entities that the ones specified in the XML file, you might need to manually update them. * - -dontUseDefaultValues - Use this flag to avoid automatically generating code using default QoS policy values when possible. By default (when this flag is not used), MAG will check whether the values that are set in every element of the QoS policies for each entity are the same as the defaults used by |me|. If that’s the case, the generated code will contain the default values for those policies, instead of the values set by the user. * - -dpdeName - Specifies the name used by MAG when registering a DPDE discovery plugin. By default, this name is **dpde**. * - -dpseName - Specifies the name used by MAG when registering a DPSE discovery plugin. By default, this name is **dpse**. * - -help - Prints out the command-line options for MAG. * - -idlFile - Specifies the IDL file name used by rtiddsgen to generate the code. This value is used by MAG to specify the Plugin header generated by rtiddsgen. By default, MAG uses the name of the XML file. * - -inputXml - Specifies the XML configuration file used to generate code. The XML configuration file can be passed directly to MAG without using the -inputXml option, by default MAG knows that any argument with no option is the input file. * - -language - Specifies the language to use for the generated files. The default language is C. * - -onlyValidate - Causes MAG to just validate the input file. It will not generate any code. * - -outputFinalQoS - Use this flag to display the final values of the specified QoS profile after applying inheritance. Although MAG currently doesn’t generate code to set the QoS for |me|, using this flag will determine the final values in the profile after applying inheritance. For complex XML files, with multiple levels of inheritance, it might be a challenge to determine the final QoS values. Using this flag simplifies the process. **Note:** This option does not check whether or not the final values are supported by |me|. * - -referencedFile - Specifies a file which is referenced from the one being used to generate code. In general, it is recommended to split the application definition from the QoS definition. This way, the QoS can be shared among various applications. **Note:** Can be repeated. ``-referencedFile -referencedFile ...`` * - -replace - Use this flag to overwrite existing generated files. * - -shmemName - Specifies the name used by MAG when registering a shared memory (SHMEM) transport plugin. By default, this name is **shmem**. * - -udpName - Specifies the name used by MAG when registering a UDP transport plugin. By default, this name is **udp**. * - -verbosity [1-4] - Sets the MAG verbosity: 1: Exceptions. 2: Exceptions and warnings. 3: Exceptions, warnings, and information. **(Default)** 4: Exceptions, warnings, information, and debug. * - -version - Displays the version of MAG being used, such as 4.0.1. Integrating Generated Files into Your Application’s Build ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Integrating the generated files into your application is as easy as including the generated files **HelloWorldAppgen.h** and **HelloWorldAppgen.c** in your application. If your application uses C++, you will also need to include **HelloWorldAppgen_plugin.h** and **HelloWorldAppgen_plugin.cxx**. Then you can create entities using the standard **DDS_DomainParticipantFactory_create_participant_from_config()** operation and retrieve all the entities from your application code using the standard **lookup__by_name()** operations, such as **lookup_datawriter_by_name()**. For details on these operations, see the `DomainParticipantFactory`_ module in the |me| API reference HTML documentation. .. _section-appgen-names-assigned-to-entities: .. _section-appgen-create-domainparticipant: Creating the Application ------------------------ Call API to Create DomainParticipant ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To create the application that MAG generates from the XML definition, you must call the API `create_participant_from_config()`_ to create the *DomainParticipant*. All applications start with the *DomainParticipant*. This API receives the configuration name and creates all the *Entities* defined by that configuration. .. _section-appgen-retrieving-entities: Retrieve Entities by Name ^^^^^^^^^^^^^^^^^^^^^^^^^ After creation, you can retrieve the defined *Entities* by using the `lookup_by_name()`_ operations available in the :link_connextmicro_dds_api_cpp_up_one:`C API Reference ` and :link_connextmicro_dds_api_cpp_up_one:`C++ API Reference `. .. _section-appgen-helloworld-example: A "Hello, World" Example ------------------------ This simple scenario consists of two applications: **HelloWorld_publisher**, which writes the *Topic*, HelloWorldTopic, and **HelloWorld_subscriber**, which subscribes to that *Topic*. *The files for this example are provided when you install* |me|. You will find them in the directory **/C/HelloWorld_appgen**. The following examples are provided: * **Domain Participant "HelloWorldDPDEPubDP"** This application defines a publisher which uses DPDE discovery. The application has one named "HelloWorldDPDEPubDP", one named "HelloWorldDPDEPub", and one named "HelloWorldDPDEDW" which uses topic name "Example HelloWorld". The application registers one type with name "HelloWorld" and defines one with name "Example HelloWorld" which uses the type "HelloWorld". * **Domain Participant "HelloWorldDPDESubDP"** This application defines a subscriber which uses DPDE discovery. The application has one named "HelloWorldDPDESubDP", one named "HelloWorldDPDESub", and one named "HelloWorldDPDEDR" which uses topic name "Example HelloWorld". The application registers one type with name "HelloWorld" and defines one with name "Example HelloWorld" which uses the type "HelloWorld". * **Domain Participant "HelloWorldDPSEPubDP"** This application defines a publisher which uses DPSE discovery. The application has one named "HelloWorldDPSEPubDP", one named "HelloWorldDPSEPub", and one named "HelloWorldDPSEDW" which uses topic name "Example HelloWorld" and has RTPS id 100. The application registers one type with name "HelloWorld" and defines one with name "Example HelloWorld" which uses type "HelloWorld". The application asserts one remote participant named "HelloWorldDPSESubDP" and one remote subscription with ID 200, type name "HelloWorld", and topic name "Example HelloWorld". * **Domain Participant "HelloWorldDPSESubDP"** This application defines a subscriber which uses DPSE discovery. The application has one named "HelloWorldDPSESubDP", one named "HelloWorldDPSESub", and one named "HelloWorldDPSEDR" which uses topic name "Example HelloWorld" and has RTPS id 200. The application registers one type with name "HelloWorld" and defines one with name "Example HelloWorld" which uses the type "HelloWorld". The application asserts one remote participant named "HelloWorldDPSEPubDP" and one remote subscription with ID 100, type name "HelloWorld", and topic name "Example HelloWorld". .. _section-generate-typesupport-code: Generate Type-Support Code from the Type Definition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The first step is to describe the data type in a programming language-neutral manner. Three languages are supported by *RTI Code Generator*: XML, IDL, and XSD. These three languages provide equivalent type-definition capabilities, so you can choose whichever one you prefer. You can even transform between one of these three languages and another with *RTI Code Generator*. That said, since the rest of the configuration files use XML, it is often more convenient to also use XML to describe the data types, so they can be shared or moved to other XML configuration files. The file **HelloWorld.xml** contains the XML description of the data type. You can find this file in **/C/HelloWorld_appgen**. Let’s examine the type used in this example: .. code-block:: xml The data associated with the HelloWorld *Topic* consists of two strings and a numeric counter: #. The first string contains the name of the sender of the message. This field is marked as the “key” since it signals the identity of the data-object. #. The second string contains a message. #. The third field is a simple counter, which the application increments with each message. Once the type has been defined, we use *rtiddsgen* to generate the code for the HelloWorld data type. We will use the C language in this example. **To generate code with rtiddsgen:** - On a Windows system: From your command shell, change directory to **\C\HelloWorld_appgen** and type: .. code-block:: none \rtiddsgen\scripts\rtiddsgen.bat -language C HelloWorld.xml .. note:: The Visual Studio solution in the example folder automatically calls *rtiddsgen*. - On a Linux or macOS system: From your command shell, change directory to **/C/HelloWorld_appgen** and type: .. code-block:: none /rtiddsgen/scripts/rtiddsgen -language C HelloWorld.xml After running *rtiddsgen*, you will see the following files in the **HelloWorld_appgen** directory: - **HelloWorld.h** - **HelloWorld.c** - **HelloWorldPlugin.h** - **HelloWorldPlugin.c** - **HelloWorldSupport.h** - **HelloWorldSupport.c** The most notable files are **HelloWorld.h** and **HelloWorldPlugin.h**: - **HelloWorld.h** contains the declaration of the C structure, built according to the specification in the XML file: .. code-block:: c typedef struct HelloWorld { CDR_String sender; CDR_String message; CDR_Long count; } HelloWorld; - **HelloWorldPlugin.h** contains the **get_plugin_type()** function that MAG will use when generating the code to create all the DDS entities: .. code-block:: c NDDSUSERDllExport extern struct NDDS_Type_Plugin* HelloWorldTypePlugin_get(void); Generate DDS Entities from the System Definition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This step uses *rtiddsmag* to generate code to support the creation of DDS entities using Application Generation in |me|. *rtiddsmag* supports C and C++. We will use C in this example. .. note:: You can do this step before or after generating Type-Support from the Type definition since the type code doesn’t need to exist when running *rtiddsmag*. **To generate code with rtiddsmag:** - On a Windows system: From your command shell, change directory to **\C\HelloWorld_appgen** and type: .. code-block:: none \rtiddsmag\scripts\rtiddsmag.bat -language C -referencedFile HelloWorldQos.xml HelloWorld.xml .. note:: The Visual Studio solution in the example folder automatically calls rtiddsmag. - On a Linux or macOS system: From your command shell, change directory to **/C/HelloWorld_appgen** and type: .. code-block:: none /rtiddsmag/scripts/rtiddsmag -language C -referencedFile HelloWorldQos.xml HelloWorld.xml We will examine the content of the generated files in the next section. Examine the XML Configuration Files and the Generated Code ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The entire **HelloWorld.xml** file is shown below. Let’s review its content to see how this scenario was constructed. The main sections in the file are: - :ref:`section-type-definition` - :ref:`section-domain-definition` - :ref:`section-domainparticipant-definition` .. code-block:: xml HelloWorldTopic .. _section-type-definition: Type Definition """"""""""""""" *rtiddsmag* doesn’t use the types section of the XML file to generate any code. This section is used by *rtiddsgen* to generate the code to support the direct use of the structure ‘HelloWorld’ from application code (see :ref:`section-generate-typesupport-code`). .. code-block:: xml .. _section-domain-definition: Domain Definition """"""""""""""""" The domain section defines the system’s *Topics* and their corresponding data types. To define a *Topic*, the associated data type must be registered with the domain, giving it a registered type name. The registered type name is used to refer to that data type within the domain when the *Topic* is defined. In this example, the configuration file registers the previously defined HelloWorld type under the name HelloWorldType. Then it defines a *Topic* named HelloWorldTopic, which is associated with the registered type, referring to its registered name, HelloWorldType. The value used in **get_plugin_type** depends on how the registration of the data-type is configured inside the domain: #. If a tag is specified *without* a type_ref attribute, the value of **get_type_plugin** is generated from the tag plus the string "Plugin_get". #. If a tag is specified *with* a type_ref attribute, the value of **get_type_plugin** is generated from that attribute plus the string "TypePlugin_get". Our example has type_ref = "HelloWorld", so the value of **get_type_plugin** will be **HelloWorldTypePlugin_get**. .. code-block:: xml *rtiddsmag* generates the following code for each entity that uses this *Topic*: - **HelloWorldAppgen.c** .. code-block:: c const struct APPGEN_TypeRegistrationModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_type_registrations[1] = { { "HelloWorldType", /* registered_type_name */ HelloWorldTypePlugin_get /* get_type_plugin */ } }; const struct APPGEN_TopicModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_topics[1] = { { "HelloWorldTopic", /* topic_name */ "HelloWorldType", /* type_name */ DDS_TopicQos_INITIALIZER /* topic_qos*/ } }; These two structures are used in the *DomainParticipant* definition, where they will be registered by |me| when calling the Micro Application Generation API. - **HelloWorldAppgen.h** .. code-block:: c extern const struct APPGEN_TypeRegistrationModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_type_registrations[1]; extern const struct APPGEN_TopicModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_topics[1]; #define RTI_APP_GEN__DP_HelloWorldAppLibrary_HelloWorldDPDEPubDP \ { \ ... 1UL, /* type_registration_count */ \ HelloWorldAppLibrary_HelloWorldDPDEPubDP_type_registrations, /* type_registrations*/ \ 1UL, /* topic_count */ \ HelloWorldAppLibrary_HelloWorldDPDEPubDP_topics, /* topics */ \ ... } .. note:: |me| automatically registers the types that *rtiddsmag* generates. This means the content inside the Domain definition must match the types generated by *rtiddsgen*. .. _section-domainparticipant-definition: DomainParticipant Definition """""""""""""""""""""""""""" The *DomainParticipant* section defines the *DomainParticipants* in the system and the *DataWriters* and *DataReaders* that each *DomainParticipant* has. *DomainParticipants* are defined within the tag. Each *DomainParticipant*: - Has a unique name (within the library) which will be used later by the application that creates it. - Is associated with a domain, which defines the **domain_id**, *Topics*, and the data types the *DomainParticipant* will use. - Defines the *Publishers* and *Subscribers* within the *DomainParticipant*. *Publishers* contain *DataWriters*, *Subscribers* contain *DataReaders*. - Defines the set of *DataReaders* it will use to read data. Each *DataReader* has a QoS and a unique name which can be used from application code to retrieve it. - Defines the set of *DataWriters* it will use to write data. Each *DataWriter* has a QoS and a unique name which can be used from application code to retrieve it. - Optionally, the *DomainParticipants*, *Publishers*, *Subscribers*, *DataWriters*, and *DataReaders* can specify a QoS profile that will be used to configure them. The example below defines four *DomainParticipants*, two of them (HelloWorldDPDEPubDP and HelloWorldDPDESubDP) use Dynamic Participant/Dynamic Endpoint (DPDE) and the other two (HelloWorldDPSEPubDP and HelloWorldDPSESubDP) use Dynamic Participant/Static Endpoint (DPSE) discovery: .. code-block:: xml       Examining the XML, we see that: - Each *DomainParticipant* is bound to the Domain, HelloWorldLibrary::HelloWorldDomain. - The two *DomainParticipants* that use DPDE as their discovery mechanism inherit from the profile QosLibrary::DPDELibrary, while the other two that use DPSE as their discovery mechanism inherit from QosLibrary::DPSELibrary. - Each *DomainParticipant* contains a single *Publisher* or *Subscriber*, which it turn contains a single *DataWriter* or *DataReader* that inherits from QosLibrary::DPDELibrary or QosLibrary::DPSELibrary, depending on the discovery mechanism used by its *DomainParticipant*. - Each *DataWriter* writes the *Topic* HelloWorldTopic, which is defined in the domain HelloWorldLibrary::HelloWorldDomain. Each *DataReader* reads the same *Topic*. Since both Dynamic *DomainParticipants* (those which are using DPDE as their discovery mechanism) are in the same the domain and the *DataWriter* writes the same *Topic* that the *DataReader* reads, the two *DomainParticipants* will communicate. This also apply to both static participants (those which are using DPSE as their discovery mechanism); the only difference is that *rtiddsmag* will generate extra code to configure the remote entities (for details, see :ref:`section-static-discovery`). Let’s look at the content of a *DomainParticipant* definition to explain the code generated by *rtiddsmag*. .. code-block:: xml *rtiddsmag* generates the code needed to register each component used by this *DomainParticipant* and unregister those components that are not being used. In our example, for each *DomainParticipant*, *rtiddsmag* registers the discovery transport, **dpde** or **dpse**; registers the UDP transport used by each *DomainParticipant* (since they use the same configuration, only one UDP transport configuration is generated); and unregisters the default UDP and INTRA transports, since they are not being used (these two are the only ones that can be unregistered by *rtiddsmag*). It also creates the code for each entity. In this case, it generates the code needed to create: - A *Publisher* named HelloWorldDPDEPub - A *DataWriter* named HelloWorldDPDEDW - A *DomainParticipant* named HelloWorldDPDEPubDP - The QoS used by this *DomainParticipant* (see :ref:`section-qos-definition`) **HelloWorldAppgen.c** .. code-block:: c const struct ComponentFactoryUnregisterModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_unregister_components[2] = { { "_udp", /* NETIO_DEFAULT_UDP_NAME */ NULL, /* udp struct RT_ComponentFactoryProperty** */ NULL /* udp struct RT_ComponentFactoryListener** */ }, { "_intra", /* NETIO_DEFAULT_INTRA_NAME */ NULL, /* _intra struct RT_ComponentFactoryProperty** */ NULL /* _intra struct RT_ComponentFactoryListener** */ } };   struct DPDE_DiscoveryPluginProperty HelloWorldAppLibrary_HelloWorldDPDEPubDP_dpde[1] = { RTI_APP_GEN___dpde__HelloWorldAppLibrary_HelloWorldDPDEPubDP_dpde1 }; struct UDP_InterfaceFactoryProperty HelloWorldAppLibrary_HelloWorldDPDEPubDP_udpv4[1] = { RTI_APP_GEN___udpv4__HelloWorldAppLibrary_HelloWorldDPDEPubDP_udp1 }; const struct ComponentFactoryRegisterModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_register_components[2] = { { "dpde1", /* register_name */ DPDE_DiscoveryFactory_get_interface, /* register_intf */ &HelloWorldAppLibrary_HelloWorldDPDEPubDP_dpde[0]._parent, /* register_property */ NULL /* register_listener */ }, { "udp1", /* register_name */ UDP_InterfaceFactory_get_interface, /* register_intf */ &HelloWorldAppLibrary_HelloWorldDPDEPubDP_udpv4[0]._parent._parent, /* register_property */ NULL /* register_listener */ } };   ...   const struct APPGEN_DataWriterModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_publisher_HelloWorldDPDEPub_data_writers[1] = { { "HelloWorldDPDEDW", /* name */ 1UL, /* multiplicity */ "HelloWorldTopic", /* topic_name */ RTI_APP_GEN___DW_QOS_HelloWorldAppLibrary_HelloWorldDPDEPubDP_HelloWorldDPDEPub_HelloWorldDPDEDW /* writer_qos */ } }; const struct APPGEN_PublisherModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_publishers[1] = { { "HelloWorldDPDEPub", /* name */ 1UL, /* multiplicity */ DDS_PublisherQos_INITIALIZER, /* publisher_qos */ 1UL, /* writer_count */ HelloWorldAppLibrary_HelloWorldDPDEPubDP_publisher_HelloWorldDPDEPub_data_writers /* data_writers */ } }; **HelloWorldAppgen.h** .. code-block:: c extern struct DPDE_DiscoveryPluginProperty HelloWorldAppLibrary_HelloWorldDPDEPubDP_dpde[1]; extern struct UDP_InterfaceFactoryProperty HelloWorldAppLibrary_HelloWorldDPDEPubDP_udpv4[1]; extern const struct ComponentFactoryUnregisterModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_unregister_components[2]; extern const struct ComponentFactoryRegisterModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_register_components[2];   #define RTI_APP_GEN__DPF_HelloWorldAppLibrary_HelloWorldDPDEPubDP \ { \ 2UL, /* unregister_count */ \ HelloWorldAppLibrary_HelloWorldDPDEPubDP_unregister_components, /* unregister_components */\ 2UL, /* register_count */ \ HelloWorldAppLibrary_HelloWorldDPDEPubDP_register_components, /* register_components */ \ RTI_APP_GEN___DPF_QOS_QosLibrary_DefaultProfile /* factory_qos */ \ }   extern const struct APPGEN_TypeRegistrationModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_type_registrations[1]; extern const struct APPGEN_TopicModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_topics[1]; extern const struct APPGEN_PublisherModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_publishers[1];   #define RTI_APP_GEN__DP_HelloWorldAppLibrary_HelloWorldDPDEPubDP \ { \ "HelloWorldDPDEPubDP", /* name */ \ RTI_APP_GEN__DPF_HelloWorldAppLibrary_HelloWorldDPDEPubDP, /* domain_participant_factory */ \ RTI_APP_GEN___DP_QOS_HelloWorldAppLibrary_HelloWorldDPDEPubDP, /* domain_participant_qos */ \ 0L, /* domain_id */ \ 1UL, /* type_registration_count */ \ HelloWorldAppLibrary_HelloWorldDPDEPubDP_type_registrations, /* type_registrations */ \ 1UL, /* topic_count */ \ HelloWorldAppLibrary_HelloWorldDPDEPubDP_topics, /* topics */ \ 1UL, /* publisher_count */ \ HelloWorldAppLibrary_HelloWorldDPDEPubDP_publishers, /* publishers */ \ 0UL, /* subscriber_count */ \ NULL, /* subscribers */ \ 0UL, /* remote_participant_count */ \ NULL, /* remote_participants */ \ 0UL, /* flow_controller_count */ \ NULL /* flow_controllers */ \ } .. _section-qos-definition: QoS Definition ^^^^^^^^^^^^^^ The defined DDS Entities have an associated QoS Policy, which can be defined in a separate file such as **HelloWorldQos.xml** or within the System XML file. For more information on how to configure DDS Entities in an XML file, see :link_external_community_doc_pro_um:`Configuring QoS with XML ` (if you have internet access). See the entire file below. Then we will examine the file section by section, showing the code generated by *rtiddsmag*. .. code-block:: xml   false   false 127.0.0.1 239.255.0.1 udpv4 udpv4://127.0.0.1 udpv4://239.255.0.1 udpv4 UDPv4 1 1 1 1 1 1 8 8 8 32 32 32 2 64 32 RELIABLE_RELIABILITY_QOS 250000000 0 udpv4 32 2 64 32 RELIABLE_RELIABILITY_QOS 10 10 udpv4 127.0.0.1 udpv4   SDP   DPSE .. note:: *rtiddsmag* only generates code for the QoS policies used by at least one entity, unless the QoS profile has either of the default flags **is_default_participant_factory_profile** or **is_default_qos** set to true. DomainParticipant Factory QoS """"""""""""""""""""""""""""" *rtiddsmag* only generates code for the in the that has the flag **is_default_participant_factory_profile** set to true. The log verbosity can also be configured by using inside . For example: .. code-block:: xml false 4 20 *rtiddsmag* generates the following code: **HelloWorldAppgen.h** .. code-block:: c #define RTI_APP_GEN___DPF_QOS_QosLibrary_DefaultProfile \ { \ { /* entity_factory */ \ DDS_BOOLEAN_FALSE /* autoenable_created_entities */ \ }, \ { /* resource_limits */ \ 4L, /* max_participants */ \ 20L /* max_components */ \ } \ } #define RTI_APP_GEN__DPF_HelloWorldAppLibrary_HelloWorldDPDEPubDP \ { \ ..., RTI_APP_GEN___DPF_QOS_QosLibrary_DefaultProfile /* factory_qos */ \ } DomainParticipant QoS """"""""""""""""""""" The example defines a base profile named DefaultProfile, which contains the base QoSs used by each *DomainParticipant*. You can see the content of the *DomainParticipant* QoS below. .. code-block:: xml false 127.0.0.1 239.255.0.1 udpv4 udpv4://127.0.0.1 udpv4://239.255.0.1 udpv4 UDPv4 1 1 1 1 1 1 8 8 8 32 32 This *DomainParticipant* is then inherited by two different profiles, which set up the discovery mechanism: .. code-block:: xml SDP DPSE *rtiddsmag* generates the following code for each *DomainParticipant* whose QoS inherits from any of the previous ones, adding those values that are specified in the XML configuration file (which is not the case in our example). **HelloWorldAppgen.c** .. code-block:: c const char *const HelloWorldAppLibrary_HelloWorldDPDEPubDP_initial_peers[2] = { "127.0.0.1", "239.255.0.1" }; const char *const HelloWorldAppLibrary_HelloWorldDPDEPubDP_discovery_enabled_transports[3] = { "udp1://", "udp1://127.0.0.1", "udp1://239.255.0.1" }; const char *const HelloWorldAppLibrary_HelloWorldDPDEPubDP_transport_enabled_transports[1] = { "udp1" }; const char *const HelloWorldAppLibrary_HelloWorldDPDEPubDP_user_traffic_enabled_transports[1] = { "udp1://" }; **HelloWorldAppgen.h** .. code-block:: c extern const char *const HelloWorldAppLibrary_HelloWorldDPDEPubDP_initial_peers[2]; extern const char *const HelloWorldAppLibrary_HelloWorldDPDEPubDP_discovery_enabled_transports[3]; extern const char *const HelloWorldAppLibrary_HelloWorldDPDEPubDP_transport_enabled_transports[1]; extern const char *const HelloWorldAppLibrary_HelloWorldDPDEPubDP_user_traffic_enabled_transports[1];   #define RTI_APP_GEN___DP_QOS_HelloWorldAppLibrary_HelloWorldDPDEPubDP \ { \ { /* entity_factory */ \ DDS_BOOLEAN_TRUE /* autoenable_created_entities */ \ }, \ { /* discovery */ \ REDA_StringSeq_INITIALIZER_W_LOAN(HelloWorldAppLibrary_HelloWorldDPDEPubDP_initial_peers, 2, 2), /* initial_peers */ \ REDA_StringSeq_INITIALIZER_W_LOAN(HelloWorldAppLibrary_HelloWorldDPDEPubDP_discovery_enabled_transports, 3, 3), /* enabled_transports */ \ { \ { { "dpde1" } }, /* RT_ComponentFactoryId_INITIALIZER */ \ NDDS_Discovery_Property_INITIALIZER \ }, /* discovery_component */ \ DDS_BOOLEAN_FALSE /* accept_unknown_peers */ \ }, \ { /* resource_limits */ \ 1L, /* local_writer_allocation */ \ 1L, /* local_reader_allocation */ \ 1L, /* local_publisher_allocation */ \ 1L, /* local_subscriber_allocation */ \ 1L, /* local_topic_allocation */ \ 1L, /* local_type_allocation */ \ 8L, /* remote_participant_allocation */ \ 8L, /* remote_writer_allocation */ \ 8L, /* remote_reader_allocation */ \ 32L, /* matching_writer_reader_pair_allocation */ \ 32L, /* matching_reader_writer_pair_allocation */ \ 32L, /* max_receive_ports */ \ 32L, /* max_destination_ports */ \ 65536, /* unbound_data_buffer_size */ \ 500UL, /* shmem_ref_transfer_mode_max_segments */ \ 0L, /* participant_user_data_max_length */ \ DDS_SIZE_AUTO, /* participant_user_data_max_count */ \ 0L, /* topic_data_max_length */ \ DDS_SIZE_AUTO, /* topic_data_max_count */ \ 0L, /* publisher_group_data_max_length */ \ DDS_SIZE_AUTO, /* publisher_group_data_max_count */ \ 0L, /* subscriber_group_data_max_length */ \ DDS_SIZE_AUTO, /* subscriber_group_data_max_count */ \ 0L, /* writer_user_data_max_length */ \ DDS_SIZE_AUTO, /* writer_user_data_max_count */ \ 0L, /* reader_user_data_max_length */ \ DDS_SIZE_AUTO, /* reader_user_data_max_count */ \ 64L, /* max_partitions */ \ 256L, /* max_partition_cumulative_characters */ \ DDS_LENGTH_UNLIMITED, /* max_partition_string_size */ \ DDS_LENGTH_UNLIMITED /* max_partition_string_allocation */ \ }, \ DDS_ENTITY_NAME_QOS_POLICY_DEFAULT, \ DDS_WIRE_PROTOCOL_QOS_POLICY_DEFAULT, \ { /* transports */ \ REDA_StringSeq_INITIALIZER_W_LOAN(HelloWorldAppLibrary_HelloWorldDPDEPubDP_transport_enabled_transports, 1, 1) /* enabled_transports */ \ }, \ { /* user_traffic */ \ REDA_StringSeq_INITIALIZER_W_LOAN(HelloWorldAppLibrary_HelloWorldDPDEPubDP_user_traffic_enabled_transports, 1, 1) /* enabled_transports */ \ }, \ DDS_TRUST_QOS_POLICY_DEFAULT, \ DDS_PROPERTY_QOS_POLICY_DEFAULT, \ DDS_USER_DATA_QOS_POLICY_DEFAULT \ } Publisher QoS """"""""""""" Our example doesn’t specify any value for *Publisher* QoS, however *rtiddsmag* would generate code if it was specified. DataWriter QoS """""""""""""" The example defines a base profile named DefaultProfile, which contains the base QoSs used by each *DomainParticipant*. You can see the content of the *DataWriter* QoS below. .. code-block:: xml 32 2 64 32 RELIABLE_RELIABILITY_QOS 250000000 0 udpv4 *rtiddsmag* generates the following code: **HelloWorldAppgen.c** .. code-block:: c const char *const HelloWorldAppLibrary_HelloWorldDPDEPubDP_HelloWorldDPDEPub_HelloWorldDPDEDW_transport_enabled_transports[1] = { "udp1://" }; **HelloWorldAppgen.h** .. code-block:: c extern const char *const HelloWorldAppLibrary_HelloWorldDPDEPubDP_HelloWorldDPDEPub_HelloWorldDPDEDW_transport_enabled_transports[1];   #define RTI_APP_GEN___DW_QOS_HelloWorldAppLibrary_HelloWorldDPDEPubDP_HelloWorldDPDEPub_HelloWorldDPDEDW \ { \ DDS_DEADLINE_QOS_POLICY_DEFAULT, \ DDS_LIVELINESS_QOS_POLICY_DEFAULT, \ { /* history */ \ DDS_KEEP_LAST_HISTORY_QOS, /* kind */ \ 32L /* depth */ \ }, \ { /* resource_limits */ \ 64L, /* max_samples */ \ 2L, /* max_instances */ \ 32L /* max_samples_per_instance */ \ }, \ DDS_OWNERSHIP_QOS_POLICY_DEFAULT, \ DDS_OWNERSHIP_STRENGTH_QOS_POLICY_DEFAULT, \ DDS_LATENCY_BUDGET_QOS_POLICY_DEFAULT, \ { /* reliability */ \ DDS_RELIABLE_RELIABILITY_QOS, /* kind */ \ { /* max_blocking_time */ \ 0L, /* sec */ \ 100000000L /* nanosec */ \ } \ }, \ DDS_DURABILITY_QOS_POLICY_DEFAULT, \ DDS_DESTINATION_ORDER_QOS_POLICY_DEFAULT, \ DDS_TRANSPORT_ENCAPSULATION_QOS_POLICY_DEFAULT, \ DDS_DATA_REPRESENTATION_QOS_POLICY_DEFAULT, \ { /* protocol */ \ DDS_RTPS_AUTO_ID, /* rtps_object_id */ \ { /* rtps_reliable_writer */ \ { /* heartbeat_period */ \ 0L, /* sec */ \ 250000000L /* nanosec */ \ }, \ 1L, /* heartbeats_per_max_samples */ \ DDS_LENGTH_UNLIMITED, /* max_send_window */ \ DDS_LENGTH_UNLIMITED, /* max_heartbeat_retries */ \ { /* first_write_sequence_number */ \ 0, /* high */ \ 1 /* low */ \ } \ }, \ DDS_BOOLEAN_TRUE /* serialize_on_write */ \ }, \ DDS_TYPESUPPORT_QOS_POLICY_DEFAULT, \ { /* transports */ \ REDA_StringSeq_INITIALIZER_W_LOAN(HelloWorldAppLibrary_HelloWorldDPDEPubDP_HelloWorldDPDEPub_HelloWorldDPDEDW_transport_enabled_transports, 1, 1) /* enabled_transports */ \ }, \ RTI_MANAGEMENT_QOS_POLICY_DEFAULT, \ DDS_DATAWRITERRESOURCE_LIMITS_QOS_POLICY_DEFAULT, \ DDS_PUBLISH_MODE_QOS_POLICY_DEFAULT, \ DDS_USER_DATA_QOS_POLICY_DEFAULT, \ DDS_DATAWRITERQOS_TRUST_INITIALIZER \ DDS_DATAWRITERQOS_APPGEN_INITIALIZER \ NULL, \ DDS_DataWriterTransferModeQosPolicy_INITIALIZER \ } Subscriber QoS """""""""""""" Our example doesn’t specify any value for Subscriber QoS, however *rtiddsmag* would generate code if it was specified. DataReader QoS """""""""""""" The example defines a base profile named DefaultProfile, which contains the base QoSs used by each *DomainParticipant*. You can see the content of the *DataReader* QoS below. .. code-block:: xml 32 2 64 32 RELIABLE_RELIABILITY_QOS 10 10 udpv4 127.0.0.1 udpv4 *rtiddsmag* generates the following code: **HelloWorldAppgen.c** .. code-block:: c const char *const HelloWorldAppLibrary_HelloWorldDPDESubDP_HelloWorldDPDESub_HelloWorldDPDEDR_transport_enabled_transports[2] = { "udp1://", "udp1://127.0.0.1" }; **HelloWorldAppgen.h** .. code-block:: c extern const char *const HelloWorldAppLibrary_HelloWorldDPDESubDP_HelloWorldDPDESub_HelloWorldDPDEDR_transport_enabled_transports[2]; #define RTI_APP_GEN___DR_QOS_HelloWorldAppLibrary_HelloWorldDPDESubDP_HelloWorldDPDESub_HelloWorldDPDEDR \ { \ DDS_DEADLINE_QOS_POLICY_DEFAULT, \ DDS_LIVELINESS_QOS_POLICY_DEFAULT, \ { /* history */ \ DDS_KEEP_LAST_HISTORY_QOS, /* kind */ \ 32L /* depth */ \ }, \ { /* resource_limits */ \ 64L, /* max_samples */ \ 2L, /* max_instances */ \ 32L /* max_samples_per_instance */ \ }, \ DDS_OWNERSHIP_QOS_POLICY_DEFAULT, \ DDS_LATENCY_BUDGET_QOS_POLICY_DEFAULT, \ { /* reliability */ \ DDS_RELIABLE_RELIABILITY_QOS, /* kind */ \ { /* max_blocking_time */ \ 0L, /* sec */ \ 0L /* nanosec */ \ } \ }, \ DDS_DURABILITY_QOS_POLICY_DEFAULT, \ DDS_DESTINATION_ORDER_QOS_POLICY_DEFAULT, \ DDS_TRANSPORT_ENCAPSULATION_QOS_POLICY_DEFAULT, \ DDS_DATA_REPRESENTATION_QOS_POLICY_DEFAULT, \ DDS_TYPESUPPORT_QOS_POLICY_DEFAULT, \ DDS_DATA_READER_PROTOCOL_QOS_POLICY_DEFAULT, \ { /* transports */ \ REDA_StringSeq_INITIALIZER_W_LOAN(HelloWorldAppLibrary_HelloWorldDPDESubDP_HelloWorldDPDESub_HelloWorldDPDEDR_transport_enabled_transports, 2, 2) /* enabled_transports */ \ }, \ { /* reader_resource_limits */ \ 10L, /* max_remote_writers */ \ 10L, /* max_remote_writers_per_instance */ \ 1L, /* max_samples_per_remote_writer */ \ 1L, /* max_outstanding_reads */ \ DDS_NO_INSTANCE_REPLACEMENT_QOS, /* instance_replacement */ \ 4L, /* max_routes_per_writer */ \ DDS_MAX_AUTO, /* max_fragmented_samples */ \ DDS_MAX_AUTO, /* max_fragmented_samples_per_remote_writer */ \ DDS_SIZE_AUTO /* shmem_ref_transfer_mode_attached_segment_allocation */ \ }, \ RTI_MANAGEMENT_QOS_POLICY_DEFAULT, \ DDS_USER_DATA_QOS_POLICY_DEFAULT, \ DDS_DATAREADERQOS_TRUST_INITIALIZER \ DDS_DATAREADERQOS_APPGEN_INITIALIZER \ NULL \ } Topic QoS """"""""" Our example doesn’t specify any value for Topic QoS; however, *rtiddsmag* would generate code if it were specified. Transport and Discovery Configuration ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *rtiddsmag* creates the code necessary to configure each one of the available transports used by |me| (UDP and SHMEM) and the discovery mechanism (Dynamic and Static discovery). It also generates the name automatically for each component regardless of if it is a transport or discovery; for this *rtiddsmag* will add a *DomainParticipant* number at the end of its name, only if that configuration is not used by any other *DomainParticipant*: - UDP Transport: **udp** + participant_number. - SHMEM Transport: **shmem** + participant_number. - DPDE: **dpde** + participant_number. - DPSE: **dpse** + participant_number. These names can be changed by using the **...Names** options described in :ref:`section-command-line-options`. .. note:: - *rtiddsmag* will only create the transport configuration based on the strongly typed XML elements in the schema. *rtiddsmag* **will not** use the values in the property tag to configure the transport. - If the length of one of these names exceeds the maximum length, *rtiddsmag* will throw an error. The following configuration specifies dynamic discovery: .. code-block:: xml SDP **HelloWorldAppgen.h** .. code-block:: c #define RTI_APP_GEN___dpde__HelloWorldAppLibrary_HelloWorldDPDEPubDP_dpde1 \ { \ RT_ComponentFactoryProperty_INITIALIZER, /* _parent */ \ { /*participant_liveliness_assert_period */ \ 30L, /* sec */ \ 0L /* nanosec */ \ }, \ { /*participant_liveliness_lease_duration */ \ 100L, /* sec */ \ 0L /* nanosec */ \ }, \ 5, /* initial_participant_announcements */ \ { /*initial_participant_announcement_period */ \ 1L, /* sec */ \ 0L /* nanosec */ \ }, \ DDS_BOOLEAN_FALSE, /* cache_serialized_samples */ \ DDS_LENGTH_AUTO, /* max_participant_locators */ \ 4, /* max_locators_per_discovered_participant */ \ 8, /* max_samples_per_builtin_endpoint_reader */ \ DDS_LENGTH_UNLIMITED, /* builtin_writer_max_heartbeat_retries */ \ { /*builtin_writer_heartbeat_period */ \ 0L, /* sec */ \ 100000000L /* nanosec */ \ }, \ 1L /* builtin_writer_heartbeats_per_max_samples */ \ DDS_PARTICIPANT_MESSAGE_READER_RELIABILITY_KIND_INITIALIZER \ }   #define RTI_APP_GEN___DP_QOS_HelloWorldAppLibrary_HelloWorldDPDEPubDP \ { \ ... { /* discovery */ \ REDA_StringSeq_INITIALIZER_W_LOAN(HelloWorldAppLibrary_HelloWorldDPDEPubDP_initial_peers, 2, 2), /* initial_peers */ \ REDA_StringSeq_INITIALIZER_W_LOAN(HelloWorldAppLibrary_HelloWorldDPDEPubDP_discovery_enabled_transports, 3, 3), /* enabled_transports */ \ { \ { { "dpde1" } }, /* RT_ComponentFactoryId_INITIALIZER */ \ NDDS_Discovery_Property_INITIALIZER \ }, /* discovery_component */ \ DDS_BOOLEAN_FALSE /* accept_unknown_peers */ \ }, \ ... } .. note:: - *rtiddsmag* will throw an error if the list of available transports for the *DomainParticipant*, *DataWriter*, and *DataReader* contains a transport alias that is not part of the **transport_builtin** mask. - *rtiddsmag* will not generate code for the SHMEM or UDPv4 transport if it is not specified in the **transport_builtin** mask. - UDP transformation is not supported in XML. When using the transport alias to specify the **enabled_transports** for the discovery *DomainParticipant*, *DataWriter* or *DataReader*, you could use the transport names for the built-in transport plugins: **shmem** and **udpv4**. *rtiddsmag* will automatically modify this alias to match the new one with the *DomainParticipant* number at the end of the name. Flow Controllers ^^^^^^^^^^^^^^^^ *rtiddsmag* creates code which will be used by |me| to create a flow controller. The flow controller is configured through properties in the XML file. Let’s see an example of how to configure a flow controller named **custom_flowcontroller** and the code that *rtiddsmag* generates: .. code-block:: xml ... dds.flow_controller.token_bucket.custom_flowcontroller.token_bucket.max_tokens 2 dds.flow_controller.token_bucket.custom_flowcontroller.token_bucket.tokens_added_per_period 2 dds.flow_controller.token_bucket.custom_flowcontroller.token_bucket.tokens_leaked_per_period -1 dds.flow_controller.token_bucket.custom_flowcontroller.token_bucket.period.sec 0 dds.flow_controller.token_bucket.custom_flowcontroller.token_bucket.period.nanosec 100000000 dds.flow_controller.token_bucket.custom_flowcontroller.token_bucket.bytes_per_token 1024   dds.flow_controller.token_bucket.custom_flowcontroller ASYNCHRONOUS_PUBLISH_MODE_QOS 12 **HelloWorldAppgen.c** .. code-block:: c const struct APPGEN_FlowControllerModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_flow_controllers[1] = { { "custom_flowcontroller", /* name */ RTI_APP_GEN___FC_P_QOS_HelloWorldAppLibrary_HelloWorldDPDEPubDP_custom_flowcontroller /* flow_controller_property */ } }; **HelloWorldAppgen.h** .. code-block:: c #define RTI_APP_GEN___FC_P_QOS_HelloWorldAppLibrary_HelloWorldDPDEPubDP_custom_flowcontroller \ { \ NETIO_FlowControllerProperty_INITIALIZER, \ DDS_EDF_FLOW_CONTROLLER_SCHED_POLICY, /* scheduling_policy */ \ { /* token_bucket */ \ 2L, /* max_tokens */ \ 2L, /* tokens_added_per_period */ \ -1L, /* tokens_leaked_per_period */ \ { /* period */ \ 0L, /* sec */ \ 100000000L /* nanosec */ \ }, \ 1024L /* bytes_per_token */ \ }, \ DDS_BOOLEAN_FALSE /* is_vendor_specific */ \ }   #define RTI_APP_GEN___DW_QOS_HelloWorldAppLibrary_HelloWorldDPDEPubDP_HelloWorldDPDEPub_HelloWorldDPDEDW \ { \ ... { /* publish_mode */ \ DDS_ASYNCHRONOUS_PUBLISH_MODE_QOS, /* max_remote_readers */ \ "custom_flowcontroller", /* flow_controller_name */ \ 12L /* priority */ \ }, \ ... }   extern const struct APPGEN_FlowControllerModel HelloWorldAppLibrary_HelloWorldDPDEPubDP_flow_controllers[1];   #define RTI_APP_GEN__DP_HelloWorldAppLibrary_HelloWorldDPDEPubDP \ { \ ... 1UL, /* flow_controller_count */ \ HelloWorldAppLibrary_HelloWorldDPDEPubDP_flow_controllers /* flow_controllers */ \ } .. _section-static-discovery: Static Discovery ^^^^^^^^^^^^^^^^ *rtiddsmag* iterates through each *DomainParticipant* definition in the XML configuration file, creating the remote entities that are needed to communicate with applications that use static discovery, and updating the **object_id** of each *DataWriter* or *DataReader* involved if they don’t have a valid value or they are using the default value. Let’s see an example of two applications that use static discovery and how *rtiddsmag* generates the necessary code that will be asserted by |me| to communicate with both applications: .. code-block:: xml   For these two *DomainParticipants*, *rtiddsmag* will update the **rtps_object_id** for the *DataWriter* and *DataReader*, since they didn’t have any values set in the XML file. You can see this in the following snippet from **HelloWorldAppgen.h**: .. code-block:: c #define RTI_APP_GEN___DW_QOS_HelloWorldAppLibrary_HelloWorldDPSEPubDP_HelloWorldDPSEPub_HelloWorldDPSEDW \ { \ ... { /* protocol */ \ 1UL, /* rtps_object_id */ \ { /* rtps_reliable_writer */ \ { /* heartbeat_period */ \ 0L, /* sec */ \ 250000000UL /* nanosec */ \ }, \ 1L, /* heartbeats_per_max_samples */ \ DDS_LENGTH_UNLIMITED, /* max_send_window */ \ DDS_LENGTH_UNLIMITED, /* max_heartbeat_retries */ \ { /* first_write_sequence_number */ \ 0, /* high */ \ 1 /* low */ \ } \ }, \ DDS_BOOLEAN_TRUE /* serialize_on_write */ \ }, \ ... }   #define RTI_APP_GEN___DR_QOS_HelloWorldAppLibrary_HelloWorldDPSESubDP_HelloWorldDPSESub_HelloWorldDPSEDR \ { \ ... { /* protocol */ \ 2UL /* rtps_object_id */ \ }, \ ... } *rtiddsmag* will also generate the remote *DomainParticipants*, *DataWriters*, and *DataReaders* that need to be asserted in order for endpoints to match: **HelloWorldAppgen.c** .. code-block:: c const struct APPGEN_RemoteSubscriptionModel HelloWorldAppLibrary_HelloWorldDPSEPubDP_remote_subscribers[1] = { RTI_APP_GEN__RSD_HelloWorldAppLibrary_HelloWorldDPSEPubDP_HelloWorldAppLibrary_HelloWorldDPSESubDP_HelloWorldDPSESub_HelloWorldDPSEDR };   const struct APPGEN_RemoteParticipantModel HelloWorldAppLibrary_HelloWorldDPSEPubDP_remote_participants[1] = { { "HelloWorldDPSESubDP", /* name */ 0UL, /* remote_publisher_count */ NULL, /* remote_publishers */ 1UL, /* remote_subscriber_count */ HelloWorldAppLibrary_HelloWorldDPSEPubDP_remote_subscribers /* remote_subscribers */ } };   const struct APPGEN_RemotePublicationModel HelloWorldAppLibrary_HelloWorldDPSESubDP_remote_publishers[1] = { RTI_APP_GEN__RPD_HelloWorldAppLibrary_HelloWorldDPSESubDP_HelloWorldAppLibrary_HelloWorldDPSEPubDP_HelloWorldDPSEPub_HelloWorldDPSEDW };   const struct APPGEN_RemoteParticipantModel HelloWorldAppLibrary_HelloWorldDPSESubDP_remote_participants[1] = { { "HelloWorldDPSEPubDP", /* name */ 1UL, /* remote_publisher_count */ HelloWorldAppLibrary_HelloWorldDPSESubDP_remote_publishers, /* remote_publishers */ 0UL, /* remote_subscriber_count */ NULL /* remote_subscribers */ } }; **HelloWorldAppgen.h** .. code-block:: c #define RTI_APP_GEN__RSD_HelloWorldAppLibrary_HelloWorldDPSEPubDP_HelloWorldAppLibrary_HelloWorldDPSESubDP_HelloWorldDPSESub_HelloWorldDPSEDR \ { \ { /* subscription_data */ \ { \ { 0, 0, 0, 2 } /* key */ \ }, \ { \ { 0, 0, 0, 0 } /* participant_key */ \ }, \ "HelloWorldTopic", /* topic_name */ \ "HelloWorldType", /* type_name */ \ DDS_DEADLINE_QOS_POLICY_DEFAULT, \ DDS_OWNERSHIP_QOS_POLICY_DEFAULT, \ DDS_LATENCY_BUDGET_QOS_POLICY_DEFAULT, \ { /* reliability */ \ DDS_RELIABLE_RELIABILITY_QOS, /* kind */ \ { /* max_blocking_time */ \ 0L, /* sec */ \ 0L /* nanosec */ \ } \ }, \ DDS_LIVELINESS_QOS_POLICY_DEFAULT, \ DDS_DURABILITY_QOS_POLICY_DEFAULT, \ DDS_DESTINATION_ORDER_QOS_POLICY_DEFAULT, \ DDS_SEQUENCE_INITIALIZER, \ DDS_SEQUENCE_INITIALIZER, \ DDS_DATA_REPRESENTATION_QOS_POLICY_DEFAULT \ DDS_TRUST_SUBSCRIPTION_DATA_INITIALIZER \ }, \ HelloWorldTypePlugin_get /* get_type_plugin */ \ } extern const struct APPGEN_RemoteSubscriptionModel HelloWorldAppLibrary_HelloWorldDPSEPubDP_remote_subscribers[1]; extern const struct APPGEN_RemoteParticipantModel HelloWorldAppLibrary_HelloWorldDPSEPubDP_remote_participants[1];   #define RTI_APP_GEN__DP_HelloWorldAppLibrary_HelloWorldDPSEPubDP \ { \ "HelloWorldDPSEPubDP", /* name */ \ RTI_APP_GEN__DPF_HelloWorldAppLibrary_HelloWorldDPSEPubDP, /* domain_participant_factory */ \ RTI_APP_GEN___DP_QOS_HelloWorldAppLibrary_HelloWorldDPSEPubDP, /* domain_participant_qos */ \ 0L, /* domain_id */ \ 1UL, /* type_registration_count */ \ HelloWorldAppLibrary_HelloWorldDPSEPubDP_type_registrations, /* type_registrations */ \ 1UL, /* topic_count */ \ HelloWorldAppLibrary_HelloWorldDPSEPubDP_topics, /* topics */ \ 1UL, /* publisher_count */ \ HelloWorldAppLibrary_HelloWorldDPSEPubDP_publishers, /* publishers */ \ 0UL, /* subscriber_count */ \ NULL, /* subscribers */ \ 1UL, /* remote_participant_count */ \ HelloWorldAppLibrary_HelloWorldDPSEPubDP_remote_participants /* remote_participants */ \ 0UL, /* flow_controller_count */ \ NULL, /* flow_controllers */ \ }   #define RTI_APP_GEN__RPD_HelloWorldAppLibrary_HelloWorldDPSESubDP_HelloWorldAppLibrary_HelloWorldDPSEPubDP_HelloWorldDPSEPub_HelloWorldDPSEDW \ { \ { /* publication_data */ \ { \ { 0, 0, 0, 1 } /* key */ \ }, \ { \ { 0, 0, 0, 0 } /* participant_key */ \ }, \ "HelloWorldTopic", /* topic_name */ \ "HelloWorldType", /* type_name */ \ DDS_DEADLINE_QOS_POLICY_DEFAULT, \ DDS_OWNERSHIP_QOS_POLICY_DEFAULT, \ DDS_OWNERSHIP_STRENGTH_QOS_POLICY_DEFAULT, \ DDS_LATENCY_BUDGET_QOS_POLICY_DEFAULT, \ { /* reliability */ \ DDS_RELIABLE_RELIABILITY_QOS, /* kind */ \ { /* max_blocking_time */ \ 0L, /* sec */ \ 100000000L /* nanosec */ \ } \ }, \ DDS_LIVELINESS_QOS_POLICY_DEFAULT, \ DDS_DURABILITY_QOS_POLICY_DEFAULT, \ DDS_DESTINATION_ORDER_QOS_POLICY_DEFAULT, \ DDS_SEQUENCE_INITIALIZER, \ DDS_DATA_REPRESENTATION_QOS_POLICY_DEFAULT \ DDS_TRUST_PUBLICATION_DATA_INITIALIZER \ }, \ HelloWorldTypePlugin_get /* get_type_plugin */ \ }   extern const struct APPGEN_RemotePublicationModel HelloWorldAppLibrary_HelloWorldDPSESubDP_remote_publishers[1]; extern const struct APPGEN_RemoteParticipantModel HelloWorldAppLibrary_HelloWorldDPSESubDP_remote_participants[1];   #define RTI_APP_GEN__DP_HelloWorldAppLibrary_HelloWorldDPSESubDP \ { \ "HelloWorldDPSESubDP", /* name */ \ RTI_APP_GEN__DPF_HelloWorldAppLibrary_HelloWorldDPSESubDP, /* domain_participant_factory */ \ RTI_APP_GEN___DP_QOS_HelloWorldAppLibrary_HelloWorldDPSESubDP, /* domain_participant_qos */ \ 0L, /* domain_id */ \ 1UL, /* type_registration_count */ \ HelloWorldAppLibrary_HelloWorldDPSESubDP_type_registrations, /* type_registrations */ \ 1UL, /* topic_count */ \ HelloWorldAppLibrary_HelloWorldDPSESubDP_topics, /* topics */ \ 0UL, /* publisher_count */ \ NULL, /* publishers */ \ 1UL, /* subscriber_count */ \ HelloWorldAppLibrary_HelloWorldDPSESubDP_subscribers, /* subscribers */ \ 1UL, /* remote_participant_count */ \ HelloWorldAppLibrary_HelloWorldDPSESubDP_remote_participants /* remote_participants */ \ 0UL, /* flow_controller_count */ \ NULL /* flow_controllers */ \ #define RTI_APP_GEN__RSD_HelloWorldAppLibrary_HelloWorldDPSEPubDP_HelloWorldAppLibrary_HelloWorldDPSESubDP_HelloWorldDPSESub_HelloWorldDPSEDR \ { \ { /* subscription_data */ \ { \ { 0, 0, 0, 2 } /* key */ \ }, \ { \ { 0, 0, 0, 0 } /* participant_key */ \ }, \ "HelloWorldTopic", /* topic_name */ \ "HelloWorldType", /* type_name */ \ DDS_DEADLINE_QOS_POLICY_DEFAULT, \ DDS_OWNERSHIP_QOS_POLICY_DEFAULT, \ DDS_LATENCY_BUDGET_QOS_POLICY_DEFAULT, \ { /* reliability */ \ DDS_RELIABLE_RELIABILITY_QOS, /* kind */ \ { /* max_blocking_time */ \ 0L, /* sec */ \ 0L /* nanosec */ \ } \ }, \ DDS_LIVELINESS_QOS_POLICY_DEFAULT, \ DDS_DURABILITY_QOS_POLICY_DEFAULT, \ DDS_DESTINATION_ORDER_QOS_POLICY_DEFAULT, \ DDS_SEQUENCE_INITIALIZER, \ DDS_SEQUENCE_INITIALIZER, \ DDS_DATA_REPRESENTATION_QOS_POLICY_DEFAULT \ DDS_TRUST_SUBSCRIPTION_DATA_INITIALIZER \ }, \ HelloWorldTypePlugin_get /* get_type_plugin */ \ } extern const struct APPGEN_RemoteSubscriptionModel HelloWorldAppLibrary_HelloWorldDPSEPubDP_remote_subscribers[1]; extern const struct APPGEN_RemoteParticipantModel HelloWorldAppLibrary_HelloWorldDPSEPubDP_remote_participants[1];   #define RTI_APP_GEN__DP_HelloWorldAppLibrary_HelloWorldDPSEPubDP \ { \ "HelloWorldDPSEPubDP", /* name */ \ RTI_APP_GEN__DPF_HelloWorldAppLibrary_HelloWorldDPSEPubDP, /* domain_participant_factory */ \ RTI_APP_GEN___DP_QOS_HelloWorldAppLibrary_HelloWorldDPSEPubDP, /* domain_participant_qos */ \ 0L, /* domain_id */ \ 1UL, /* type_registration_count */ \ HelloWorldAppLibrary_HelloWorldDPSEPubDP_type_registrations, /* type_registrations */ \ 1UL, /* topic_count */ \ HelloWorldAppLibrary_HelloWorldDPSEPubDP_topics, /* topics */ \ 1UL, /* publisher_count */ \ HelloWorldAppLibrary_HelloWorldDPSEPubDP_publishers, /* publishers */ \ 0UL, /* subscriber_count */ \ NULL, /* subscribers */ \ 1UL, /* remote_participant_count */ \ HelloWorldAppLibrary_HelloWorldDPSEPubDP_remote_participants /* remote_participants */ \ 0UL, /* flow_controller_count */ \ NULL, /* flow_controllers */ \ }   #define RTI_APP_GEN__RPD_HelloWorldAppLibrary_HelloWorldDPSESubDP_HelloWorldAppLibrary_HelloWorldDPSEPubDP_HelloWorldDPSEPub_HelloWorldDPSEDW \ { \ { /* publication_data */ \ { \ { 0, 0, 0, 1 } /* key */ \ }, \ { \ { 0, 0, 0, 0 } /* participant_key */ \ }, \ "HelloWorldTopic", /* topic_name */ \ "HelloWorldType", /* type_name */ \ DDS_DEADLINE_QOS_POLICY_DEFAULT, \ DDS_OWNERSHIP_QOS_POLICY_DEFAULT, \ DDS_OWNERSHIP_STRENGTH_QOS_POLICY_DEFAULT, \ DDS_LATENCY_BUDGET_QOS_POLICY_DEFAULT, \ { /* reliability */ \ DDS_RELIABLE_RELIABILITY_QOS, /* kind */ \ { /* max_blocking_time */ \ 0L, /* sec */ \ 100000000L /* nanosec */ \ } \ }, \ DDS_LIVELINESS_QOS_POLICY_DEFAULT, \ DDS_DURABILITY_QOS_POLICY_DEFAULT, \ DDS_DESTINATION_ORDER_QOS_POLICY_DEFAULT, \ DDS_SEQUENCE_INITIALIZER, \ DDS_DATA_REPRESENTATION_QOS_POLICY_DEFAULT \ DDS_TRUST_PUBLICATION_DATA_INITIALIZER \ }, \ HelloWorldTypePlugin_get /* get_type_plugin */ \ }   extern const struct APPGEN_RemotePublicationModel HelloWorldAppLibrary_HelloWorldDPSESubDP_remote_publishers[1]; extern const struct APPGEN_RemoteParticipantModel HelloWorldAppLibrary_HelloWorldDPSESubDP_remote_participants[1];   #define RTI_APP_GEN__DP_HelloWorldAppLibrary_HelloWorldDPSESubDP \ { \ "HelloWorldDPSESubDP", /* name */ \ RTI_APP_GEN__DPF_HelloWorldAppLibrary_HelloWorldDPSESubDP, /* domain_participant_factory */ \ RTI_APP_GEN___DP_QOS_HelloWorldAppLibrary_HelloWorldDPSESubDP, /* domain_participant_qos */ \ 0L, /* domain_id */ \ 1UL, /* type_registration_count */ \ HelloWorldAppLibrary_HelloWorldDPSESubDP_type_registrations, /* type_registrations */ \ 1UL, /* topic_count */ \ HelloWorldAppLibrary_HelloWorldDPSESubDP_topics, /* topics */ \ 0UL, /* publisher_count */ \ NULL, /* publishers */ \ 1UL, /* subscriber_count */ \ HelloWorldAppLibrary_HelloWorldDPSESubDP_subscribers, /* subscribers */ \ 1UL, /* remote_participant_count */ \ HelloWorldAppLibrary_HelloWorldDPSESubDP_remote_participants /* remote_participants */ \ 0UL, /* flow_controller_count */ \ NULL /* flow_controllers */ \ } .. _section-appgen-errors-invalid-config: Errors Caused by Invalid Configurations and QoS ----------------------------------------------- This section explains the different results thrown by MAG if it receives invalid configuration files. - **Invalid XML content** MAG will fail to validate the configuration file if it contains invalid content, such as elements/attributes that don’t exist in the schema or values that aren't supported by any of the existing types. For example: .. code-block:: xml ... ... .. image:: /images/InvalidXml.PNG - **Unsupported elements** MAG will throw a warning for any elements that are not supported by |me|. Unsupported elements will be ignored, such as the user_data in the following: .. code-block:: xml ... .. image:: /images/IgnoreWarning.PNG - **Unsupported values** MAG will throw an error if it finds a value that is not supported by |me|. .. code-block:: xml ... TRANSIENT_DURABILITY_QOS .. image:: /images/DurabilityError.PNG .. MAG will throw an error if the QoS values are not consistent with values supported in |me|. For example, the following XML contains a deadline period that is too large. .. code-block:: xml ... 123213123 12 .. image:: /images/DeadlineError.PNG .. MAG will throw an error if the **dds.xtypes.compliance_mask** property uses a different value than 0x00000008. .. image:: /images/UnsupportedPropError.png - **Unsupported QoS** Not all the QoS policies supported by |me| can be configured in XML. - QoS settings related to UDP transformation cannot be configured in XML. See the :ref:`section-udp-transport` section for more information on UDP transformation. - MAG does not support any PROPERTY QoS policy properties except the **dds.xtypes.compliance_mask** property.