4. Example Application

Connext TSS provides an example application, hello_goodbye, that runs on either Connext DDS Professional or Connext DDS Micro. It demonstrate how to use the Connext TSS libraries with an application that uses a separate library to provide all Connext TSS plugins.

The actual FACE application includes only the minimum necessary code to build a FACE UoP using Connext TSS.

The example demonstrate how a TSS integrator can package additional functionality (plus the Connext TSS plugins) into a linkable library that can be used by FACE UoP. They also show how to combine multiple connections in the same application and how to setup a callback to process received data.

4.1. hello_goodbye

4.1.1. Source Code Overview

The data type used by the example can be found in examples/hello_goodbye/idl/HelloGoodbye.idl. It contains two types, HelloWorld and GoodbyeWorld, and each type contains a keyed field.

Note

RTI Connext TSS supports user data types in IDL files only. To convert other FACE data model formats to IDL, contact RTI Support or your local account team for assistance.

The source in the app directory contains the main source for the FACE application: app/HelloGoodbyeExample.cpp.

There are four functions defined in this file:

  1. publisher_main() This function implements the logic for when the application is launched as a publisher. The example shows how to call various FACE TSS functions, as well as the calling convention for providing data samples. It publishes samples of type HelloWorld.
  2. <user-type>::send_event() This function is the callback that will be registered with the Connext TSS library for receiving data. Note that the function is named from the perspective of the TSS that “sends the event” to the application. The actual registration of the callback is done in the function subscriber_main().
  3. subscriber_main() This function implements the logic for when the application is launched as a subscriber. The example shows how to call various FACE TSS functions as well as the calling convention for providing data samples. The subscriber uses the send_event() function to process the data. It subscribes to samples of type HelloWorld.
  4. main() The main function for the example.

The application source has three important headers included:

  1. #include "FACE/TS.hpp" Defines the FACE TSS API.

  2. #include "gen/HelloGoodbye.hxx" This file is generated by rtiddsgen from the IDL file containing the data type definition, idl/HelloWorld.idl.

    The header file contains the definition of the HelloGoodbye type for the C++ language. The application includes this header file because the FACE API operates on actual data types. So the application must use this generated definition to pass the expected type to the Connext TSS library, and ultimately the Connext DDS core.

  3. #include "gen/HelloGoodbye_TSS.hpp" This file is generated by rtiddsgen from the IDL file containing the type specific part of the FACE TS API.

In the example code, you’ll see publisher_main() and subscriber_main() use the type HelloWorld. Its structure is passed to the FACE TSS API calls.

The source files in the gen directory was generated by rtiddsgen. They are the type-specific plugins necessary to configure and interface with Connext DDS and Connext TSS:

  • HelloGoodbye.c (.h) Type definition for Connext DDS.
  • HelloGoodbyePlugin.c (.h) Type plugin for Connext DDS.
  • HelloGoodbyeSupport.c (.h) Type support for Connext DDS.
  • HelloGoodbye.hxx FACE type definition.
  • HelloGoodbye_Config.c Function to get configuration data for Connext TSS.
  • HelloGoodbye_QosSupport.c QoS configuration per DDS entity for Connext TSS.
  • HelloGoodbye_TypeSupport.c Function to get type plugin for Connext TSS.
  • HelloGoodbye_TSS.cpp (.hpp) Typed implementation of FACE TS interface.

See TSS Capabilities for details on the TSS plugins.

4.1.2. Prerequisites

  1. RTITSSARCH environment variable is set to the name of the target architecture (e.g., x64Linux3gcc4.8.2).
  2. If running with Connext DDS Professional, it must be installed and built for RTITSSARCH, and it must conform with the intended FACE profile. The NDDSHOME environment variable is set to the location of the Connext DDS Professional installation. The ROXMLHOME environment variable is set to the location of the libroxml installation, and the LD_LIBRARY_PATH environment variable includes the location of the libroxml shared library.
  3. If running with Connext DDS Micro, it must be installed and built for RTITSSARCH, and it must conform with the intended FACE profile. The RTIMEHOME environment variable is set to the location of the Connext DDS Micro installation.
  4. Connext TSS libraries have been built for RTITSSARCH and either Connext DDS Professional or Micro.
  5. RTITSSHOME environment variable points to the location of the Connext TSS installation.
  6. JREHOME environment variable points to the location of a JRE 1.6 or 1.7 installation.
  7. CMake is installed.

4.1.3. Build the example

hello_goodbye contains a CMake script to generate the necessary plugins and build the application.

When invoking CMake, use the same command line definitions as when building the RTI Connext TSS libraries:

  • RTI_CONNEXT_TYPE
  • RTI_TSS_ENABLE_FACE_COMPLIANCE
  • CMAKE_BUILD_TYPE
cd ${RTITSSHOME}/examples/hello_goodbye
mkdir build
cd build
cmake -DRTI_CONNEXT_TYPE=<pro|micro> -DRTI_TSS_ENABLE_FACE_COMPLIANCE=<your_face_profile> -DCMAKE_BUILD_TYPE=<your_build_type> ../
cmake --build .

Alternatively, use cmake-gui to see and configure additional CMake settings.

cd ${RTITSSHOME}/examples/hello_goodbye
mkdir build_gui
cd build_gui
cmake-gui ../
cmake --build .

The generated plugins will be in the gen directory:

Note

By default, each run of CMake to build this example will call rtiddsgen to replace, or overwrite, all files in the gen directory.

To keep the generated source from being replaced, use the CMake command-line definition ‘-DRTI_REPLACE_GEN=false’.

The resulting executable is output as ../bin/${RTITSSARCH}/${RTI_CONNEXT_TYPE}/hello_goodbye_app.

Note

Each build is for a single combination of Connext DDS type, FACE profile, and CMake build type. Additional builds for different configuration combinations are best done out-of-source (i.e., from a directory separate from the source, like the build and build-gui directories above), but note that the resulting applications are copied to the same output directory.

4.1.4. Run the example

For Connext DDS Professional, by default the example must be run from the hello_goodbye directory where the default HelloGoodbye_Qos.xml XML QoS configuration file is located. The location of this file can be configured in gen/HelloGoodbye_Config.c.

The example can be run as a publisher or a subscriber.

4.1.4.1. Run as a publisher

To run the example as a publisher, launch the executable with the -pub command-line option:

./bin/${RTITSSARCH}/${RTI_CONNEXT_TYPE}/hello_goodbye_app -pub

The output of a publisher will look like this:

---------------------------------------------------------
 RTI Connext TSS HelloWorld Example (Connext DDS Micro)
---------------------------------------------------------
Sending unlimited samples ...
sending message 0
sending message 1
sending message 2
sending message 3
sending message 4
sending message 5

4.1.4.2. Run as a subscriber

To run the example as a subscriber, use the -sub command-line option:

./bin/${RTITSSARCH}/${RTI_CONNEXT_TYPE}/hello_goodbye_app -sub

Alternatively, to run a subscriber in callback mode, use the +sub command-line option:

./bin/${RTITSSARCH}/${RTI_CONNEXT_TYPE}/hello_goodbye_app +sub

An optional argument is the number of messages to send/receive before exiting. This is provided by the -num <NUM SAMPLES> arguments.

The output of a subscriber receiving samples from a publisher will look like this:

---------------------------------------------------------
 RTI Connext TSS HelloWorld Example (Connext DDS Micro)
---------------------------------------------------------
Receiving unlimited samples ...
received data: id[1] msg[Hello World 1]
received data: id[0] msg[Hello World 2]
received data: id[1] msg[Hello World 3]
received data: id[0] msg[Hello World 4]
received data: id[1] msg[Hello World 5]

Note that if there is no data available, the Receive_Message call will return a FACE::NOT_AVAILABLE error (ordinal value is 2), but the example will continue polling without shutting down.

4.2. Further Modifications

4.2.1. DDS QoS

In general, QoS for underlying DDS entities are configured in the generated _QoSPlugin.c source files. XML profiles may also be used for Connext DDS Professional.

4.2.2. Adding Connections

Each created connection creates an underlying DDS writer and/or reader, so resource limits QoS may need to be increased for additional connections.

4.2.3. Multiple IDLs

When using data types from more than one IDL file, the _TypeSupport.c files will need to be modified to define just one RTI_TSS_get_type_support() function between them. This is already done for a single IDL file containing multiple types.

For example, given Foo.idl and Bar.idl, both their generated Foo_TypeSupport.c and Bar_TypeSupport.c define RTI_TSS_get_type_support(), and that is resolved by defining just one function but with contents of both bodies:

RTI_TSS_TypeSupportPlugin*
RTI_TSS_get_type_support(const char* type_name) {
    struct Logger* logger = Logger_getInstance();

    static RTI_TSS_TypeSupportPlugin* FACE_DM_Foo_type_plugin = NULL;
    static RTI_TSS_TypeSupportPlugin* FACE_DM_Bar_type_plugin = NULL;

    if( strcmp( type_name, "FACE::DM::Foo" ) == 0 ) {
      /* set and return Foo plugin */
    }

    if( strcmp( type_name, "FACE::DM::Bar" ) == 0 ) {
      /* set and return Bar plugin */
    }

4.2.4. DDS Interoperability

Considerations when interoperating with other DDS endpoints (TSS or non-TSS):

  • The DDS domain must be the same. Configured in _QosPlugin.c
  • QoS must be compatible. Configured in _QosPlugin.c.
  • Type and topic names must match. Configured in _Config.c.

4.3. Troubleshooting

This section has tips for working around some common issues.

4.3.1. Function returned an error

The example applications may return an error message of the format:

<function> returned an error: <return_code>

For example, the following error message is FACE::TS::Receive_Message() returning the FACE::RETURN_CODE_TYPE with value 2.

Receive_Message returned an error: 2

The return code can be found in a header file, and the return code of each function can be found in either source or the API Reference documentation.

So for the above example, searching the headers in include/FACE reveals the FACE::RETURN_CODE_TYPE enum in include/FACE/common.hpp, where 2 maps to NOT_AVAILABLE:

typedef enum RETURN_CODE_TYPE
  {
    NO_ERROR ,
    NO_ACTION ,
    NOT_AVAILABLE ,
    ADDR_IN_USE ,
    INVALID_PARAM ,
    INVALID_CONFIG ,
    PERMISSION_DENIED ,
    INVALID_MODE ,
    TIMED_OUT ,
    MESSAGE_STALE ,
    CONNECTION_IN_PROGRESS ,
    CONNECTION_CLOSED ,
    DATA_BUFFER_TOO_SMALL
  } RETURN_CODE_TYPE;

4.3.2. Callback not implemented

Callback mode is currently not supported for Safety Base profile.