.. include:: vars.rst .. _section-examples: ******************************************************************************** Example Application ******************************************************************************** |TSS| provides an example application, *hello_goodbye*, that runs on either |CONNEXT| *Professional* or |CONNEXT_MICRO|. It demonstrate how to use the |TSS| libraries with an application that uses a separate library to provide all |TSS| plugins. The actual FACE application includes only the minimum necessary code to build a FACE UoP using |TSS|. The example demonstrate how a TSS integrator can package additional functionality (plus the |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. hello_goodbye ================================================ 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_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: #. ``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``. #. ``::send_event()`` This function is the callback that will be registered with the |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()``. #. ``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``. #. ``main()`` The main function for the example. The application source has three important headers included: #. ``#include "FACE/TS.hpp"`` Defines the FACE TSS API. #. ``#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 |TSS| library, and ultimately the |CONNEXT| core. #. ``#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| and |TSS|: - ``HelloGoodbye.c (.h)`` Type definition for |CONNEXT|. - ``HelloGoodbyePlugin.c (.h)`` Type plugin for |CONNEXT|. - ``HelloGoodbyeSupport.c (.h)`` Type support for |CONNEXT|. - ``HelloGoodbye.hxx`` FACE type definition. - ``HelloGoodbye_Config.c`` Function to get configuration data for |TSS|. - ``HelloGoodbye_QosSupport.c`` QoS configuration per DDS entity for |TSS|. - ``HelloGoodbye_TypeSupport.c`` Function to get type plugin for |TSS|. - ``HelloGoodbye_TSS.cpp (.hpp)`` Typed implementation of FACE TS interface. See :ref:`label-tssplugins` for details on the TSS plugins. Prerequisites ------------- #. ``RTITSSARCH`` environment variable is set to the name of the target architecture (e.g., x64Linux3gcc4.8.2). #. If running with |CONNEXT| *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| *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. #. If running with |CONNEXT| *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| *Micro* installation. #. |TSS| libraries have been built for ``RTITSSARCH`` and either |CONNEXT| *Professional* or *Micro*. #. ``RTITSSHOME`` environment variable points to the location of the |TSS| installation. #. ``JREHOME`` environment variable points to the location of a JRE 1.6 or 1.7 installation. #. `CMake `_ is installed. Build the example ----------------- ``hello_goodbye`` contains a CMake script to generate the necessary plugins and build the application. When invoking CMake, use the same :ref:`command line definitions ` as when building the |RTI_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= -DRTI_TSS_ENABLE_FACE_COMPLIANCE= -DCMAKE_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. Run the example --------------- For |CONNEXT| *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. 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 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 `` 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. Further Modifications =========================== 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| *Professional*. 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. 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: .. code-block:: c 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 */ } 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. Troubleshooting =============== This section has tips for working around some common issues. Function returned an error -------------------------- The example applications may return an error message of the format: .. code-block:: none returned an error: For example, the following error message is ``FACE::TS::Receive_Message()`` returning the ``FACE::RETURN_CODE_TYPE`` with value 2. .. code-block:: none 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 :ref:`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``: .. code-block:: C++ 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; Callback not implemented -------------------------- Callback mode is currently not supported for Safety Base profile.