Using XML Application Creation to simplify prototype & app development in RTI Connext DDS Micro

rti-blog-post-image-2019-08-07-xml-connext-micro

XML-Based Application Creation can simplify and accelerate the development and programming of Connext DDS applications. It can also be used to build prototypes on Pro and migrate them to RTI Connext DDS Micro and Cert. This can be useful in many situations. For example, autonomous vehicle developers using Connext DDS Micro 3.0.0 now have a direct path to ASIL D safety-certified systems.

Connext DDS supports the use of XML for the complete system definition. This includes not only the definition of the data types and Quality of Service (QoS) settings, but also the definition of the Topics, DomainParticipants, and all the Entities they contain (Publishers, Subscribers, DataWriters and DataReaders). XML-Based Application Creation is already supported by RTI Connext DDS Professional.

Starting with RTI Connext DDS 6.0.0, XML-Based Application Creation can be used to configure RTI Connext DDS Micro applications , through a new tool called RTI Micro Application Generator (MAG). This will enable you to develop prototypes with RTI Connext DDS Professional using XML App Creation and quickly move to Connext DDS Micro using the same XML file.

MAG generates code from an XML configuration file. It creates DDS entities and registers all of the components needed for a Connext DDS Micro-based application.

Here’s a HelloWorld example (HelloWorld_appgen) to illustrate how you can start working with XML App Creation in Connext DDS Micro:

rti-blog-2019-08-07-xml-connext-micro-figure1


Figure 1: Using XML Application Creation with Connext DDS Micro to accelerate development of DDS-based applications

Step 1: Generate Type Support Code

Type-support files must be generated using rtiddsgen in order to run any Connext DDS Micro application. The definition of the type can be included in the same XML configuration file or using an IDL file, such as :

${RTIMEHOME}/rtiddsgen/scripts/rtiddsgen -micro -language C++ HelloWorld.xml

Step 2: Generate XML App Creation Code

When using XML App Creation, application-support files must also be generated using MAG. These application-support files contains the DDS entities and components defined inside the XML configuration file, such as:

"$(RTIMEHOME)/rtiddsmag/scripts/rtiddsmag" -language C HelloWorld.xml -referencedFile HelloWorldQos.xml

Step 3: Create Entities

Once the code has been generated, 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_<entity>_by_name() operations, such as DDS_DomainParticipant_lookup_datawriter_by_name(). Let’s see how this works in the example:

  • HelloWorldApplication.c

participant =
       DDS_DomainParticipantFactory_create_participant_from_config(
           factory,
            participant_name);
  • HelloWorld_publisher.c

datawriter = DDS_DomainParticipant_lookup_datawriter_by_name(
       participant,
        PUB_DATAWRITER_NAME);

Your application will require far fewer lines of code that it would need when using the standard API. Let’s see the difference between creating a DataWriter using the standard API vs using XML Application creation:

  • Standard API
publisher = DDS_DomainParticipant_create_publisher(
application->participant,
           &DDS_PUBLISHER_QOS_DEFAULT,
           NULL,
           DDS_STATUS_MASK_NONE);
   if (publisher == NULL) {
       printf("publisher == NULL\n");
       goto done;
dw_qos.resource_limits.max_samples_per_instance;
   dw_qos.history.depth = 32;
   dw_qos.protocol.rtps_reliable_writer.heartbeat_period.sec = 0;
   dw_qos.protocol.rtps_reliable_writer.heartbeat_period.nanosec = 250000000;
   
dw_listener.on_publication_matched =
       HelloWorldPublisher_on_publication_matched;
   datawriter = DDS_Publisher_create_datawriter(
publisher,
application->topic,
&dw_qos,
           &dw_listener,
           DDS_PUBLICATION_MATCHED_STATUS);

   if (datawriter == NULL) {
       printf("datawriter == NULL\n");
       goto done;
    }
  • XML Application creation

datawriter = DDS_DomainParticipant_lookup_datawriter_by_name(
application->participant,
       PUB_DATAWRITER_NAME);
    if (datawriter == NULL) {
    printf("datawriter == NULL\n");
       goto done;
    }

Here’s a summary of the most notable features for the MAG:

  1. Reference a QoS file(s)
  2. Print final QoS values
  3. Transport and Discovery Configuration
  4. Asserting Remote Entities
  5. Fewer lines used by the generated code

1. Reference a QoS file(s)

The Quality of Service (QoS) section of the XML file can be separated from the Application definition into one or more separate files. This might be useful if different teams are responsible for different applications, and the QoS properties are shared.

2. Print final QoS values

MAG can also be used to determine the final value of a specific QoS. This option (-outputFinalQoS) can be useful if you want to know what are the final value of a QoS after applying inheritance.

3. Transport and Discovery Configuration

MAG generates the code necessary to register any standard Micro transport (UDPv4, SHMEM) used by your application. This includes the UDP and SHMEM Transport and the two discovery mechanism: Dynamic Participant/Dynamic Endpoint (DPDE) and Dynamic Participant/Static Endpoint (DPSE). MAG also unregisters the default INTRA transport if it is not used by your application.

By default, MAG will generate the name used by each transport, adding a DomainParticipant number at the end of its name. These names can be changed by using the following options: -dpdeName, -dpseName, -udpName and -shmemName.

4. Asserting Remote Entities

An application using DPSE discovery must specify the remote entities so they can be discovered by your application. MAG automatically configures the remote entities for each DomainParticipant, DataWriter and DataReader by looking for matches in the XML (DataWriters and DataReaders which are publishing or subscribing to the same Topic in the same domain ID).

Here’s an example:

<domain_participant_library name="...">
   <domain_participant name="..."
        domain_ref="HelloWorldLibrary::HelloWorldDomain">
       <publisher name="...">
            <data_writer topic_ref="HelloWorldTopic" name="..."/>
</publisher>
<participant_qos>
    ...
    <discovery_config>
<builtin_discovery_plugins>DPSE</builtin_discovery_plugins>
           </discovery_config>
       </participant_qos>
   </domain_participant>
   <domain_participant name="..."
    domain_ref="HelloWorldLibrary::HelloWorldDomain">
       <subscriber name="...">
        <data_reader topic_ref="HelloWorldTopic" name="..."/>
       </subscriber>
       <participant_qos>
        ...
           <discovery_config>
<builtin_discovery_plugins>DPSE</builtin_discovery_plugins>
           </discovery_config>
       </participant_qos>
   </domain_participant>
</domain_participant_library>

The previous snippet defines two applications using static discovery. The first application defines a DataWriter while the second defines a DataReader. Both applications share a common Domain (HelloWorldLibrary::HelloWorldDomain) and each DataWriter and DataReader publish/subscribe to the same topic HelloWorldTopic. MAG will automatically generate the remote entities for each application so they can communicate with each other. These remote entities will be asserted automatically when using the standard DDS_DomainParticipantFactory_create_participant_from_config() operation.

The generated code will contain all the remote entities found by MAG. The following code shows the remote reader from the second application that is going to be asserted by the first application:

#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 */ \
}

5. Fewer lines used by the generated code

By default, MAG tries to reduce the amount of lines generated by checking whether the values set in every element of the individual QoS policies for each entity are the same as the defaults used by Connext DDS Micro. If that’s the case, the generated code will contain the default values for those policies, instead of the values set by you. For example:

<participant_qos>
   <resource_limits>
       <local_writer_allocation>
           <max_count>1</max_count>
       </local_writer_allocation>
       <local_reader_allocation>
           <max_count>1</max_count>
       </local_reader_allocation>
   </resource_limits>
</participant_qos>

In this case MAG finds that the value of the resource limits are the same as the default values used by Connext DDS Micro, and then changes the generated code to use the default value for that policy. The generated code will look like this:

#define RTI_APP_GEN___DP_QOS_... \
{ \
   ..., \
   DDS_DOMAIN_PARTICIPANT_RESOURCE_LIMITS_QOS_POLICY_DEFAULT, \
   ... \
}

Instead of the following:

#define RTI_APP_GEN___DP_QOS_... \
{ \
   ..., \
   {   /* 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 */ \
       1L, /* remote_participant_allocation */ \
       1L, /* remote_writer_allocation */ \
       1L, /* remote_reader_allocation */ \
       32L, /* matching_writer_reader_pair_allocation */ \
       32L, /* matching_reader_writer_pair_allocation */ \
       8L, /* max_receive_ports */ \
       8L, /* max_destination_ports */ \
       65536, /* unbound_data_buffer_size */ \
       500UL /* shmem_ref_transfer_mode_max_segments */ \
   }, \
   ... \
}

To learn more about XML-Based Application Creation, please refer to the XML-Based Application Creation Getting Started Guide and join me on the September 11 webinar. Register today!

 

About the Author

rti-blog-author-valentin-carrascoValentín Pérez joined RTI in 2016 as a Software Engineer on the Engineering team. After a short period on the RTI customer support team, he joined the RTI Tools team, where he developed RTI Launcher and Micro Application Generator. He has published several Blog posts on RTI’s website. Valentín holds a BS degree in Computer Engineering and later obtained a MS degree in Software Development, both from the Universidad de Granada, Spain.

Getting Started with Connext DDS

Connext® DDS is the world's leading implementation of the Data Distribution Service (DDS) standard for Real-Time Systems. Try a fully-functional version of Connext DDS for 30 days.


Free Trial