.. include:: vars.rst .. _section-architecture: ########################### Capabilities and Interfaces ########################### ****************************** Programming Language Support ****************************** |TSS| supports the FACE TSS APIs in C++ and C. ****************************** Operating System Environment ****************************** |TSS| has been implemented using the POSIX API calls prescribed for the applicable conformance profile. This usage has been validated using the FACE Conformance Test Suite (CTS). .. _label-tssplugins: **************** TSS Capabilities **************** |TSS| supports the following capabilities: - Transport Service (TS) - TSS Distribution - TSS Configuration - Type Abstraction - Transport Protocol Module |TSS| generates support code with the included *Code Generator* (*rtiddsgen*) tool to enable these capabilities. FACE Profiles ============= |TSS| officially supports two FACE Compliance profiles, GeneralPurpose and SafetyBase. While the ``RTI_TSS_ENABLE_FACE_COMPLIANCE`` CMake definition can be set to any FACE TSS profile, this release of |TSS| supports the GeneralPurpose and SafetyBase Profiles with |CONNEXT_MICRO| 2.4.13.1, 2.4.13.4, and 2.4.13.5. GeneralPurpose Profile ---------------------- |TSS| supports the GeneralPurpose Profile with |CONNEXT_MICRO|. While ``RTI_TSS_ENABLE_FACE_COMPLIANCE`` can be set to either GeneralPurpose or None, both are mapped to the GeneralPurpose Profile. Run the following CMake command to build |TSS| for the GeneralPurpose Profile with |CONNEXT_MICRO|: .. code-block:: bash cmake -DRTI_CONNEXT_TYPE=micro -DRTI_TSS_ENABLE_FACE_COMPLIANCE=GeneralPurpose -DCMAKE_BUILD_TYPE=Release ../ .. note:: Refer to the :ref:`section-build` chapter for a step-by-step guide to building |TSS| libraries. SafetyBase Profile ------------------ |TSS| also supports the SafetyBase Profile with |CONNEXT_MICRO|. While ``RTI_TSS_ENABLE_FACE_COMPLIANCE`` can be set to either SafetyExtended, SafetyBase, or Security, all three are mapped to the SafetyBase Profile because |TSS| does not specifically support SafetyExtended or Security. Run the following CMake command to build |TSS| (Release) for the SafetyBase Profile: .. code-block:: bash cmake -DRTI_CONNEXT_TYPE=micro -DRTI_TSS_ENABLE_FACE_COMPLIANCE=SafetyBase -DCMAKE_BUILD_TYPE=Release ../ .. note:: |CONNEXT_MICRO| is the only option for ``-DRTI_CONNEXT_TYPE`` when building for the SafetyBase profile. Limitations ----------- |TSS| built for the SafetyBase profile is different from TSS built for GeneralPurpose. |TSS| SafetyBase is limited to only using DPSE discovery. For details on DPSE discovery, see the Discovery section of the |CONNEXT_MICRO| documentation, located in the ``doc`` folder of your |CONNEXT_MICRO| installation directory (````). |TSS| SafetyBase also does not support multicast, octect, or internal logging. Most importantly, |TSS| SafetyBase does not support deallocation or reallocation of allocated memory. This limitation extends to all RTI entities and resources. Type Support ============ DDS is a strongly typed API that requires explicit definition of the data types to be used. The definition is provided in a platform- and language-neutral description such as IDL. .. note:: |TSS| supports user data types in IDL files only. FACE requires that the user data types are in the FACE::DM namespace. In IDL, the module keyword is used to create namespaces for the declaration of types defined within the file. For example: .. code-block:: c module FACE { module DM { struct {}; }; }; .. warning:: Declaring structs in IDL files outside of the FACE::DM module is not permitted by the FACE technical standard. However, *rtiddsgen* will not raise an error in this case; it is up to you to ensure that no structs are declared elsewhere. Once this definition is provided, the *rtiddsgen* tool is used to generate type support code for the given data type(s). The generated code (for a specific language) contains the following definitions: - the type itself - the |DW| and |DR| code - serialization and deserialization code - other utilities needed to use the data type in DDS systems In a DDS application, the generated type support is "registered" with a |DP| via an explicit call: .. code-block:: c HelloWorldTypeSupport_register_type(participant, type_name); Essentially, this function installs a type support plugin that registers the various type-specific utilities so that the DDS core can use the type. The FACE TSS API is also strongly typed. The modified version of the *rtiddsgen* tool provided with |TSS| generates both the type support and the type plugin required by |TSS|. The generated type plugin files (for example, HelloGoodbye, HelloGoodbyePlugin, and HelloGoodbyeSupport) should not need any modification. The ``register_type`` function for a specific type is configured from the :ref:`Configuration Interface ` capability described below. |TA| Base and Typed Interfaces ============================== While the FACE 3.x TSS Type-Specific interface is defined and implemented by |TSS| independently of any user data type, the TSS Type-Specific Typed interface must be defined for each type. Consequently, the *rtiddsgen* tool is used to generate the following headers and source files: - ``/TypedTS.hpp`` defines the Type-Specific Typed interface for the user data type. - ``/TypedTS_Impl.hpp`` defines a class implementating the interface defined in ``/TypedTS.hpp``. - ``/TypedTS_Impl.cpp`` is the implementation of ``/TypedTS_Impl.hpp``. .. _label-tss3_config_interface: Using the FACE 3.x Configuration Interface ========================================== |TSS| utilizes the FACE 3.x Configuration Interface. Configure |TSS| by customizing configuration data within a Configuration Interface instance and then setting its reference with the |TA| or |TPM|. The |TA| configuration data is XML-based and uses ``name:value`` string pairs to handle its configuration elements. The |TPM| configuration data is used by the lower level DDS product to configure its DDS settings. |TPM| utilizes configuration names set in the DDS data to handle its configuration. |TA| configuration implementation --------------------------------- |TSS| provides example source code for a Configuration Interface. You need to replicate the XML configuration layout in your implemenation of the Configuration Interface. |TSS| provides the ``tss_configuration_schema.xsd`` file to validate the configuration XML, as well as an example ``TSS.xml`` configuration file. .. warning:: The example configuration is provided as a baseline configuration. Modify the example configuration to adjust for your connections and |TPMS|. If you already have a configuration UoC implemented, the following section describes the expected string format for the byte_array returned by ``Read_Configuration()``. For example, ``guid:5;`` could be used as a configuration string for registering a |TPM| with |TA|. A configuration string for a connection could be, for example, ``tpm:5;tpm:5;tpm:7;``. For each |TPM| to be registered with the |TA|, the |TA| expects to receive a configuration string in the returned buffer in the format ``guid:`` when ``Read_Configuration()`` is called to load a list of |TPMS| to be injected. For example, ``guid:5;``. For each connection to be created with the |TA|, the |TA| expects a configuration string in the returned buffer in the format ``tpm:;tpm:;...tpm:;``, where each |TPM| that is going to participate on the connection needs to be identified by its GUID. For example, ``tpm:5;tpm:5;tpm:7;``. |TA| XML configuration elements ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |TSS| includes a set of XML elements that are used to configure the |TA|. The xsd for those elements can be found in ``/resource/configuration/schema/tss_configuration_schema.xsd``. The elements are: - configs This is the root element of the configuration file. It contains all the configuration elements for a system. - config This element contains all the configuration data for a specific configuration. It has a required name attribute that is used to identify the configuration. This attribute must match what is passed into the ``Configuration_Open()`` call in the code. It contains the following elements: - connections This element contains a list of the connections for a specific configuration. - connection This element contains the connection configuration details for a specific connection in the |TA|. It has a required name attribute that is used to identify the connection. The name attribute must match what is passed into the ``Create_Connection`` call in the code. It contains the following elements: - tpms This element contains a list of the |TPMS| for a specific connection. - tpm This element contains |TPM| information for the specific connection. It has a required guid attribute that is used to identify the |TPM|. The guid attribute must match a |TPM| guid in the list of |TPMS| under the tpms element under the config element - tpms This element contains the |TPMS| for a specific configuration. - tpm This element contains the configuration data for a specific |TPM| that's needed by the |TA|. It has required guid and name attributes that are used to identify the |TPM|. Each name and guid must be unique per configuration. - types This element contains a list of the types for a specific configuration. .. note:: The types element is not used in the current implementation of |TSS|. - type This element contains all the type elements for a specific type. It has a required name attribute that is used to lidentify the type. |TPM| configuration implementation ---------------------------------- |TPM| provides example source code for a Configuration Interface. You need to copy the HelloWorld example configuration for your language and implement the ``FACE::Configuration`` interface (if using C++) or the ``FACE_Configuration`` interface (if using C) and the interface's Configuration Services API. Examples and descriptions of what is required are in the following sections. .. warning:: The example configuration is provided as a baseline configuration. You will need to modify the example Configuration Interface implementations and QoS functions. OSAPI configuration for Connext Micro ------------------------------------- When building |TPM| with |CONNEXT_MICRO|, the OSAPI is used to allocate memory during the initialization phase. OSAPI must be set up before calling any of the functions it provides. To do so, the example code calls the ``_set_osapi_property`` function, followed by the ``DDS_DomainParticipantFactory_get_instance`` function. Example OSAPI configuration in C++: .. code-block:: C++ void Initialize(const FACE::Configuration::INITIALIZATION_TYPE &initialization_information, FACE::RETURN_CODE_TYPE::Value &return_code) { UNUSED_ARG(initialization_information); if (_initialized) { return_code = FACE::RETURN_CODE_TYPE::NO_ERROR; return; } #ifdef RTI_CONNEXT_MICRO /* OSAPI needs to be set up before it can be used. */ if (!_set_osapi_property()) { return_code = FACE::RETURN_CODE_TYPE::INVALID_CONFIG; return; } DDS_DomainParticipantFactory *factory = NULL; factory = DDS_DomainParticipantFactory_get_instance(); if (factory == NULL) { return_code = FACE::RETURN_CODE_TYPE::INVALID_CONFIG; return; } /* If and only if the set up above are successfully, * OSAPI is ready to be used after this point. */ #endif if (!_populate_system_config() || !_populate_domain_config() || !_populate_type_support_config() || !_populate_connection_config()) { return_code = FACE::RETURN_CODE_TYPE::INVALID_CONFIG; return; } _initialized = DDS_BOOLEAN_TRUE; return_code = FACE::RETURN_CODE_TYPE::NO_ERROR; } Example OSAPI configuration in C: .. code-block:: C FACE_interface_return FACE_Configuration_Initialize( struct FACE_Configuration* this_obj, const FACE_Configuration_INITIALIZATION_TYPE *initialization_information, FACE_RETURN_CODE_TYPE *return_code) { if(this_obj == NULL) { return FACE_INTERFACE_NULL_PARAM; } UNUSED_ARG(initialization_information); if (_initialized) { *return_code = FACE_RETURN_CODE_TYPE_NO_ERROR; return FACE_INTERFACE_NO_ERROR; } #ifdef RTI_CONNEXT_MICRO /* OSAPI needs to be set up before it can be used. OSAPI should only be called once by the program otherwise undefined behavior may occur.*/ if (!_set_osapi_property()) { *return_code = FACE_RETURN_CODE_TYPE_INVALID_CONFIG; return FACE_INTERFACE_NO_ERROR; } DDS_DomainParticipantFactory *factory = NULL; factory = DDS_DomainParticipantFactory_get_instance(); if (factory == NULL) { *return_code = FACE_RETURN_CODE_TYPE_INVALID_CONFIG; return FACE_INTERFACE_NO_ERROR; } /* If and only if the set up above is successful, * OSAPI can be used after this point. */ #endif if (!_populate_system_config() || !_populate_domain_config() || !_populate_type_support_config() || !_populate_connection_config()) { *return_code = FACE_RETURN_CODE_TYPE_INVALID_CONFIG; return FACE_INTERFACE_NO_ERROR; } _initialized = DDS_BOOLEAN_TRUE; *return_code = FACE_RETURN_CODE_TYPE_NO_ERROR; return FACE_INTERFACE_NO_ERROR; } To modify the OSAPI properties, you can override the ``_set_osapi_property`` function instead of creating a plugin function, then pass it to the now-deprecated ``RTI_TSS_System_Configuration.configure_osapi_system_property_fn`` |CONNEXT_MICRO| function (this function does nothing by default). Use the following steps to override the ``_set_osapi_property`` function: 1. Create a variable of struct ``OSAPI_SystemProperty`` and initialize it with ``OSAPI_SystemProperty_INITIALIZER``. |br| |br| 2. Get the current OSAPI properties by passing the variable to the ``OSAPI_System_get_property`` function. |br| |br| 3. Modify the ``OSAPI_SystemProperty`` variable. Notable properties include: - ``OSAPI_SystemProperty.timer_property.thread.port_property.parent.period`` - ``OSAPI_SystemProperty.timer_property.thread.port_property.parent.time_capacity`` - ``OSAPI_SystemProperty.timer_property.thread.port_property.parent.name`` - ``OSAPI_SystemProperty.timer_property.thread.port_property.parent.deadline`` - ``OSAPI_SystemProperty.timer_property.thread.stack_size`` - ``OSAPI_SystemProperty.timer_property.thread.priority`` 4. Pass the modified ``OSAPI_SystemProperty`` variable to ``OSAPI_System_set_property``. Configuration data types ------------------------------- The configuration data types of the ``RTI::Configuration`` class are defined in the file ``code/C/include/RTI/TSS/Configuration.h``. They are organized in the following categories: - System Configuration (``RTI_TSS_System_Configuration_T``) - |DP| Configuration (``RTI_TSS_DDS_DomainParticipant_Configuration_T``) - Type Configuration (``RTI_TSS_TypeSupport_Configuration_T``) - Connection Configuration (``RTI_TSS_Channel_Configuration_t``) System configuration ^^^^^^^^^^^^^^^^^^^^^^^^ The system configuration sets system properties for |TPM| and the underlying DDS factories. It is applied upon the very first call, idempotently, to ``FACE::TSS::TPM_TPMTS::Initialize()`` (if using C++) or ``FACE_TSS_TPM_TPMTS_Initialize()`` (if using C). A system configuration is represented by ``RTI_TSS_System_Configuration_T``. Example system configuration in C/C++: .. code-block:: C /*RTI_TSS_System_Configuration */ typedef struct RTI_TSS_System_Configuration { /*Name of the System Configuration */ const char * config_name; #if not in a Safety Base profile /*Logging verbosity */ LogVerbosity verbosity; #endif /*the configure_domain_participant_factory_qos_fn that configues the domain participant factory*/ RTI_TSS_DomainParticipantFactoryQosCallback configure_domain_participant_factory_qos_fn; /*additional configuration data */ void *user_data; #if using RTI Connext Micro /*max number of connections that are allowed in the system */ RTI_UINT32 max_channels; /*max number of topics that are allowed in the system */ RTI_UINT32 max_topics; /*pointer to an array of the Micro components used for configuring the low level Micro Settings*/ RTI_TSS_Micro_Component_T *components; /*number of components */ RTI_UINT32 components_length; #endif #if using RTI Connext Pro /*pointer to the xml qos file */ const char *xml_qos_file; /*pointer to the qos_library to be used by the system */ const char* qos_library; /*pointer to the qos_profile to be used by the system*/ const char* qos_profile; #endif } RTI_TSS_System_Configuration_T; The example RTI configuration class defines a function, ``_populate_system_config()``, that sets a static array of system configurations that are read by a Base instance when it is initialized with the Configuration Interface. Example system configuration snippet in C++: .. code-block:: C++ /* Example system configuration snippet from a Foo_TSSConfigInterface.hpp */ static const FACE::UnsignedLong _system_configurations_length = 2; RTI_TSS_System_Configuration_T _system_configurations[_system_configurations_length]; FACE::Boolean _populate_system_config() { /* Customize each element of _system_configurations[] with a system configuration * that may be used to configure your Connext TSS application. */ if (!RTI_TSS_System_Configuration_initialize(&_system_configurations[0])) { return false; } _system_configurations[0].config_name = "HelloWorld"; ... if (!RTI_TSS_System_Configuration_initialize(&_system_configurations[1])) { return false; } _system_configurations[1].config_name = "GoodbyeWorld"; ... } Example system configuration snippet in C: .. code-block:: C /* Example system configuration snippet from a Foo_TSSConfigInterface.hpp */ static const FACE_unsigned_long _system_configurations_length = 2; RTI_TSS_System_Configuration_T _system_configurations[_system_configurations_length]; FACE_boolean _populate_system_config() { /* Customize each element of _system_configurations[] with a system configuration * that may be used to configure your Connext TSS application. */ if (!RTI_TSS_System_Configuration_initialize(&_system_configurations[0])) { return false; } _system_configurations[0].config_name = "HelloWorld"; ... if (!RTI_TSS_System_Configuration_initialize(&_system_configurations[1])) { return false; } _system_configurations[1].config_name = "GoodbyeWorld"; ... } Connext Micro RT components """"""""""""""""""""""""""" For |CONNEXT_MICRO| (or |CONNEXT_MICRO_CERT|), run-time (RT) components must be configured and registered during system initialization. These components for |CONNEXT_MICRO| include transports (UDP, ARINC 653) and discovery (DPDE, DPSE). To support their configuration, the system configuration type contains an array of configurations for |CONNEXT_MICRO| RT components, all of which are registered with |CONNEXT_MICRO| upon initialization. Because the property of each component is complicated to set, the example configuration provides functions for you to customize that return the component property. The snippet below shows how components are configured for a system configuration. Note how the function ``_new_udp_property()`` is defined and configured to return a ``UDP_InterfaceFactoryProperty`` for the UDP component. This pattern is applied for other components as well. Example in C++: .. code-block:: C++ /* Example Micro components snippet from a Foo_TSSConfigInterface.hpp */ FACE::Boolean _populate_system_config() { ... /* Customize the Micro run-time components for _system_configurations[0] */ _system_configurations[0].components_length = 4; _system_configurations[0].components = new RTI_TSS_Micro_Component_t[_system_configurations[0].components_length]; // Writer History Component if (!RTI_TSS_Micro_Component_initialize(&_system_configurations[0].components[0])) { return false; } _system_configurations[0].components[0].name = DDSHST_WRITER_DEFAULT_HISTORY_NAME; _system_configurations[0].components[0].component = WHSM_HistoryFactory_get_interface(); _system_configurations[0].components[0].listener = NULL; _system_configurations[0].components[0].property = NULL; // Reader History Component if (!RTI_TSS_Micro_Component_initialize(&_system_configurations[0].components[1])) { return false; } _system_configurations[0].components[1].name = DDSHST_READER_DEFAULT_HISTORY_NAME; _system_configurations[0].components[1].component = RHSM_HistoryFactory_get_interface(); _system_configurations[0].components[1].listener = NULL; _system_configurations[0].components[1].property = NULL; // UDP Component if (!RTI_TSS_Micro_Component_initialize(&_system_configurations[0].components[2])) { return false; } _system_configurations[0].components[2].name = NETIO_DEFAULT_UDP_NAME; _system_configurations[0].components[2].component = UDP_InterfaceFactory_get_interface(); _system_configurations[0].components[2].listener = NULL; _system_configurations[0].components[2].property = (struct RT_ComponentFactoryProperty*) _new_udp_property(); // DPSE Component struct DPSE_DiscoveryPluginProperty *dpse_properties = (struct DPSE_DiscoveryPluginProperty*) malloc( sizeof(struct DPSE_DiscoveryPluginProperty)); if (DPSE_DiscoveryPluginProperty_initialize(dpse_properties) != DDS_RETCODE_OK) { printf("Failed to Initialize DPSE properties"); return false; } if (!RTI_TSS_Micro_Component_initialize(&_system_configurations[0].components[3])) { return false; } _system_configurations[0].components[3].name = "dpse"; _system_configurations[0].components[3].component = DPSE_DiscoveryFactory_get_interface(); _system_configurations[0].components[3].listener = NULL; _system_configurations[0].components[3].property = (struct RT_ComponentFactoryProperty*) dpse_properties; ... } /* Customize the UDP property for the Micro UDP transport component */ struct UDP_InterfaceFactoryProperty *_new_udp_property() { struct UDP_InterfaceFactoryProperty *udp_property = (struct UDP_InterfaceFactoryProperty *) malloc( sizeof(struct UDP_InterfaceFactoryProperty)); memset(udp_property, 0, sizeof(struct UDP_InterfaceFactoryProperty)); *udp_property = UDP_INTERFACE_FACTORY_PROPERTY_DEFAULT; udp_property->disable_auto_interface_config = RTI_TRUE; REDA_StringSeq_set_maximum(&udp_property->allow_interface,1); REDA_StringSeq_set_length(&udp_property->allow_interface,1); *DDS_StringSeq_get_reference(&udp_property->allow_interface,0) = DDS_String_dup("loopback"); if (!UDP_InterfaceTable_add_entry(&udp_property->if_table, 0x7f000001,0xff000000,"loopback", UDP_INTERFACE_INTERFACE_UP_FLAG)) { printf("Failed UDP table add entry!\n"); return NULL; } ... return udp_property; } Example in C: .. code-block:: C /* Example Micro components snippet from a Foo_TSSConfigInterface.hpp */ FACE_boolean _populate_system_config() { ... /* Customize the Micro run-time components for _system_configurations[0] */ _system_configurations[0].components_length = 4; _system_configurations[0].components = new RTI_TSS_Micro_Component_t[_system_configurations[0].components_length]; // Writer History Component if (!RTI_TSS_Micro_Component_initialize(&_system_configurations[0].components[0])) { return false; } _system_configurations[0].components[0].name = DDSHST_WRITER_DEFAULT_HISTORY_NAME; _system_configurations[0].components[0].component = WHSM_HistoryFactory_get_interface(); _system_configurations[0].components[0].listener = NULL; _system_configurations[0].components[0].property = NULL; // Reader History Component if (!RTI_TSS_Micro_Component_initialize(&_system_configurations[0].components[1])) { return false; } _system_configurations[0].components[1].name = DDSHST_READER_DEFAULT_HISTORY_NAME; _system_configurations[0].components[1].component = RHSM_HistoryFactory_get_interface(); _system_configurations[0].components[1].listener = NULL; _system_configurations[0].components[1].property = NULL; // UDP Component if (!RTI_TSS_Micro_Component_initialize(&_system_configurations[0].components[2])) { return false; } _system_configurations[0].components[2].name = NETIO_DEFAULT_UDP_NAME; _system_configurations[0].components[2].component = UDP_InterfaceFactory_get_interface(); _system_configurations[0].components[2].listener = NULL; _system_configurations[0].components[2].property = (struct RT_ComponentFactoryProperty*) _new_udp_property(); // DPSE Component struct DPSE_DiscoveryPluginProperty *dpse_properties = (struct DPSE_DiscoveryPluginProperty*) malloc( sizeof(struct DPSE_DiscoveryPluginProperty)); if (DPSE_DiscoveryPluginProperty_initialize(dpse_properties) != DDS_RETCODE_OK) { printf("Failed to Initialize DPSE properties"); return false; } if (!RTI_TSS_Micro_Component_initialize(&_system_configurations[0].components[3])) { return false; } _system_configurations[0].components[3].name = "dpse"; _system_configurations[0].components[3].component = DPSE_DiscoveryFactory_get_interface(); _system_configurations[0].components[3].listener = NULL; _system_configurations[0].components[3].property = (struct RT_ComponentFactoryProperty*) dpse_properties; ... } /* Customize the UDP property for the Micro UDP transport component */ struct UDP_InterfaceFactoryProperty *_new_udp_property() { struct UDP_InterfaceFactoryProperty *udp_property = (struct UDP_InterfaceFactoryProperty *) malloc( sizeof(struct UDP_InterfaceFactoryProperty)); memset(udp_property, 0, sizeof(struct UDP_InterfaceFactoryProperty)); *udp_property = UDP_INTERFACE_FACTORY_PROPERTY_DEFAULT; udp_property->disable_auto_interface_config = RTI_TRUE; REDA_StringSeq_set_maximum(&udp_property->allow_interface,1); REDA_StringSeq_set_length(&udp_property->allow_interface,1); *DDS_StringSeq_get_reference(&udp_property->allow_interface,0) = DDS_String_dup("loopback"); if (!UDP_InterfaceTable_add_entry(&udp_property->if_table, 0x7f000001,0xff000000,"loopback", UDP_INTERFACE_INTERFACE_UP_FLAG)) { printf("Failed UDP table add entry!\n"); return NULL; } ... return udp_property; } Connext Micro ARINC 653 transport """"""""""""""""""""""""""""""""" Configuration of the ARINC 653 transport of |CONNEXT_MICRO| requires registration of the RT components for the Port Manager and the ARINC Interface(s). |CONNEXT_MICRO| requires one Port Manager instance for each ARINC 653 partition in order to create APEX ports and manage their sending and receiving of messages. |CONNEXT_MICRO| also requires one ARINC 653 interface instance for each |DP|. The snippet below configures a Port Manager with one APEX send port and one APEX receive port and an ARINC Interface that uses the aforementioned Port Manager. Example ARINC 653 snippet in C++: .. code-block:: C++ /* Example ARINC 653 snippet from a Foo_TSSConfigInterface.hpp */ FACE::Boolean _populate_system_config() { ... // ARINC 653 Port Manager if (!RTI_TSS_Micro_Component_initialize(&_system_configurations[0].components[5])) { return false; } _system_configurations[0].components[5].name = NETIO_DEFAULT_PORTMANAGER_NAME; _system_configurations[0].components[5].component = ARINC_PortManagerFactory_get_interface(); _system_configurations[0].components[5].listener = NULL; _system_configurations[0].components[5].property = (struct RT_ComponentFactoryProperty*) _new_prtmgr_property(); // ARINC 653 Transport if (!RTI_TSS_Micro_Component_initialize(&_system_configurations[0].components[6])) { return false; } _system_configurations[0].components[6].name = NETIO_DEFAULT_ARINC_NAME; _system_configurations[0].components[6].component = ARINC_InterfaceFactory_get_interface(); _system_configurations[0].components[6].listener = NULL; _system_configurations[0].components[6].property = (struct RT_ComponentFactoryProperty*) _new_arinc_property(); ... } struct ARINC_PortManagerFactoryProperty *_new_prtmgr_property() { struct ARINC_RouteProperty *route_property = NULL; struct ARINC_ReceivePortProperty *receive_port_prop = NULL; struct ARINC_PortManagerFactoryProperty *port_mgr_prop = (struct ARINC_PortManagerFactoryProperty *) malloc( sizeof(struct ARINC_PortManagerFactoryProperty)); memset(port_mgr_prop, 0, sizeof(struct ARINC_PortManagerFactoryProperty)); *port_mgr_prop = ARINC_PORTMANAGER_FACTORY_PROPERTY_DEFAULT; /* Configure synchronous or asynchronous processing. * Synchronous (TRUE) will use this Port Manager's receive thread to pass * a received message all the way up to the receiving application. * Asynchronous (FALSE) will enqueue the message with the ARINC Interface, which * then uses its receive thread to pass each message up to the receiving application. */ port_mgr_prop->sync_processing = RTI_TRUE; /* Configure APEX process attributes of the Port Manager's receive thread */ port_mgr_prop->thread_property.port_property.parent.deadline = SOFT; port_mgr_prop->thread_property.port_property.parent.period = 100000000; port_mgr_prop->thread_property.port_property.parent.time_capacity = 100000000; port_mgr_prop->thread_property.stack_size = 32000; port_mgr_prop->thread_property.priority = 99; #define RTI_PORTMGR_RECV_THREAD_NAME "rti.ARINC.pm.rcv_thrd" OSAPI_Memory_zero(&port_mgr_prop->thread_property.port_property.parent.name, MAX_NAME_LENGTH); OSAPI_Memory_copy(&port_mgr_prop->thread_property.port_property.parent.name, RTI_PORTMGR_RECV_THREAD_NAME, OSAPI_String_length(RTI_PORTMGR_RECV_THREAD_NAME)); /* Configure send routes */ ARINC_RoutePropertySeq_set_maximum(&port_mgr_prop->send_routes, 1); ARINC_RoutePropertySeq_set_length(&port_mgr_prop->send_routes, 1); route_property = ARINC_RoutePropertySeq_get_reference( &port_mgr_prop->send_routes, 0); /* Configure a route from an APEX queuing port sending via a channel * with a unique channel identifier. */ #define RTI_APP_SEND_PORT_NAME "Part1_send" route_property->channel_identifier = 1; route_property->send_port_property.max_message_size = 1024; route_property->send_port_property.max_queue_size = 32; OSAPI_Memory_copy(route_property->send_port_property.port_name, RTI_APP_SEND_PORT_NAME, OSAPI_String_length(RTI_APP_SEND_PORT_NAME)); /* Configure APEX queuing ports to receive */ ARINC_ReceivePortPropertySeq_set_maximum(&port_mgr_prop->receive_ports,1); ARINC_ReceivePortPropertySeq_set_length(&port_mgr_prop->receive_ports,1); receive_port_prop = ARINC_ReceivePortPropertySeq_get_reference( &port_mgr_prop->receive_ports,0); /* Configure an APEX queuing port receiving via a channel with * a unique channel identifier. */ #define RTI_APP_RECV_PORT_NAME "Part1_recv" receive_port_prop->channel_identifier = 2; receive_port_prop->receive_port_property.max_message_size = 1024; receive_port_prop->receive_port_property.max_queue_size = 32; receive_port_prop->max_receive_queue_size = 32; OSAPI_Memory_copy(receive_port_prop->receive_port_property.port_name, RTI_APP_RECV_PORT_NAME, OSAPI_String_length(RTI_APP_RECV_PORT_NAME)); return port_mgr_prop; } struct ARINC_InterfaceFactoryProperty *_new_arinc_property() { struct ARINC_InterfaceFactoryProperty *arinc_property = (struct ARINC_InterfaceFactoryProperty *) malloc(sizeof(struct ARINC_InterfaceFactoryProperty)); *arinc_property = ARINC_INTERFACE_FACTORY_PROPERTY_DEFAULT; /* Configure APEX process attributes of the ARINC Interface's receive thread. * Used only when this interface's Port Manager's sync_processing property is FALSE. */ arinc_property->recv_thread.port_property.parent.deadline = SOFT; arinc_property->recv_thread.port_property.parent.period = 100000000; arinc_property->recv_thread.port_property.parent.time_capacity = 100000000; arinc_property->recv_thread.stack_size = 16000; arinc_property->recv_thread.priority = 97; #define RTI_RECV_THREAD_NAME "rti.ARINC.p2.rcv_thrd" OSAPI_Memory_zero(&arinc_property->recv_thread.port_property.parent.name, MAX_NAME_LENGTH); OSAPI_Memory_copy(&arinc_property->recv_thread.port_property.parent.name, RTI_RECV_THREAD_NAME, OSAPI_String_length(RTI_RECV_THREAD_NAME)); return arinc_property; } Example ARINC 653 snippet in C: .. code-block:: C /* Example ARINC 653 snippet from a Foo_TSSConfigInterface.hpp */ FACE_boolean _populate_system_config() { ... // ARINC 653 Port Manager if (!RTI_TSS_Micro_Component_initialize(&_system_configurations[0].components[5])) { return false; } _system_configurations[0].components[5].name = NETIO_DEFAULT_PORTMANAGER_NAME; _system_configurations[0].components[5].component = ARINC_PortManagerFactory_get_interface(); _system_configurations[0].components[5].listener = NULL; _system_configurations[0].components[5].property = (struct RT_ComponentFactoryProperty*) _new_prtmgr_property(); // ARINC 653 Transport if (!RTI_TSS_Micro_Component_initialize(&_system_configurations[0].components[6])) { return false; } _system_configurations[0].components[6].name = NETIO_DEFAULT_ARINC_NAME; _system_configurations[0].components[6].component = ARINC_InterfaceFactory_get_interface(); _system_configurations[0].components[6].listener = NULL; _system_configurations[0].components[6].property = (struct RT_ComponentFactoryProperty*) _new_arinc_property(); ... } struct ARINC_PortManagerFactoryProperty *_new_prtmgr_property() { struct ARINC_RouteProperty *route_property = NULL; struct ARINC_ReceivePortProperty *receive_port_prop = NULL; struct ARINC_PortManagerFactoryProperty *port_mgr_prop = (struct ARINC_PortManagerFactoryProperty *) malloc( sizeof(struct ARINC_PortManagerFactoryProperty)); memset(port_mgr_prop, 0, sizeof(struct ARINC_PortManagerFactoryProperty)); *port_mgr_prop = ARINC_PORTMANAGER_FACTORY_PROPERTY_DEFAULT; /* Configure synchronous or asynchronous processing. * Synchronous (TRUE) will use this Port Manager's receive thread to pass * a received message all the way up to the receiving application. * Asynchronous (FALSE) will enqueue the message with the ARINC Interface, which * then uses its receive thread to pass each message up to the receiving application. */ port_mgr_prop->sync_processing = RTI_TRUE; /* Configure APEX process attributes of the Port Manager's receive thread */ port_mgr_prop->thread_property.port_property.parent.deadline = SOFT; port_mgr_prop->thread_property.port_property.parent.period = 100000000; port_mgr_prop->thread_property.port_property.parent.time_capacity = 100000000; port_mgr_prop->thread_property.stack_size = 32000; port_mgr_prop->thread_property.priority = 99; #define RTI_PORTMGR_RECV_THREAD_NAME "rti.ARINC.pm.rcv_thrd" OSAPI_Memory_zero(&port_mgr_prop->thread_property.port_property.parent.name, MAX_NAME_LENGTH); OSAPI_Memory_copy(&port_mgr_prop->thread_property.port_property.parent.name, RTI_PORTMGR_RECV_THREAD_NAME, OSAPI_String_length(RTI_PORTMGR_RECV_THREAD_NAME)); /* Configure send routes */ ARINC_RoutePropertySeq_set_maximum(&port_mgr_prop->send_routes, 1); ARINC_RoutePropertySeq_set_length(&port_mgr_prop->send_routes, 1); route_property = ARINC_RoutePropertySeq_get_reference( &port_mgr_prop->send_routes, 0); /* Configure a route from an APEX queuing port sending via a channel * with a unique channel identifier. */ #define RTI_APP_SEND_PORT_NAME "Part1_send" route_property->channel_identifier = 1; route_property->send_port_property.max_message_size = 1024; route_property->send_port_property.max_queue_size = 32; OSAPI_Memory_copy(route_property->send_port_property.port_name, RTI_APP_SEND_PORT_NAME, OSAPI_String_length(RTI_APP_SEND_PORT_NAME)); /* Configure APEX queuing ports to receive */ ARINC_ReceivePortPropertySeq_set_maximum(&port_mgr_prop->receive_ports,1); ARINC_ReceivePortPropertySeq_set_length(&port_mgr_prop->receive_ports,1); receive_port_prop = ARINC_ReceivePortPropertySeq_get_reference( &port_mgr_prop->receive_ports,0); /* Configure an APEX queuing port receiving via a channel with * a unique channel identifier. */ #define RTI_APP_RECV_PORT_NAME "Part1_recv" receive_port_prop->channel_identifier = 2; receive_port_prop->receive_port_property.max_message_size = 1024; receive_port_prop->receive_port_property.max_queue_size = 32; receive_port_prop->max_receive_queue_size = 32; OSAPI_Memory_copy(receive_port_prop->receive_port_property.port_name, RTI_APP_RECV_PORT_NAME, OSAPI_String_length(RTI_APP_RECV_PORT_NAME)); return port_mgr_prop; } struct ARINC_InterfaceFactoryProperty *_new_arinc_property() { struct ARINC_InterfaceFactoryProperty *arinc_property = (struct ARINC_InterfaceFactoryProperty *) malloc(sizeof(struct ARINC_InterfaceFactoryProperty)); *arinc_property = ARINC_INTERFACE_FACTORY_PROPERTY_DEFAULT; /* Configure APEX process attributes of the ARINC Interface's receive thread. * Used only when this interface's Port Manager's sync_processing property is FALSE. */ arinc_property->recv_thread.port_property.parent.deadline = SOFT; arinc_property->recv_thread.port_property.parent.period = 100000000; arinc_property->recv_thread.port_property.parent.time_capacity = 100000000; arinc_property->recv_thread.stack_size = 16000; arinc_property->recv_thread.priority = 97; #define RTI_RECV_THREAD_NAME "rti.ARINC.p2.rcv_thrd" OSAPI_Memory_zero(&arinc_property->recv_thread.port_property.parent.name, MAX_NAME_LENGTH); OSAPI_Memory_copy(&arinc_property->recv_thread.port_property.parent.name, RTI_RECV_THREAD_NAME, OSAPI_String_length(RTI_RECV_THREAD_NAME)); return arinc_property; } DDS DomainParticipant configuration ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The |DP| configuration sets the properties and QoS of a DDS |DP|. Each |TPM| connection relies on DDS entities created within a |DP|, so each connection configuration itself will use a |DP| configuration (``RTI_TSS_DDS_DomainParticipant_Configuration_T.config_name``). Different |DP| configurations can be created to account for any combination of different domain IDs or |DP| QoS used by your TSS installation. A |DP| configuration is represented by ``RTI_TSS_DDS_DomainParticipant_Configuration_T``. Example configuration in C: .. code-block:: C typedef struct RTI_TSS_DDS_DomainParticipant_Configuration { /*name of the Domain Participant Configuration*/ const char *config_name; /*domain_id that the Domain Participant belongs to*/ DDS_DomainId_t domain_id; /*the configure_domain_participant_qos_fn that configures the domain participant qos settings*/ RTI_TSS_DomainParticipantQosCallback configure_domain_participant_qos_fn; /*additional configuration data */ void *user_data; /*pointer to the domain participant listener */ struct DDS_DomainParticipantListener dp_listener; /*listener status mask*/ DDS_StatusMask dp_listener_status; #if using Micro /*a structure describing the discovery configuration */ struct RTI_TSS_DiscoveryConfigPlugin discovery_config; #endif #if using Pro /*a pointer to the qos_library for the Domain Participant*/ const char *qos_library; /*a pointer to the qos_profile for the Domain Participant */ const char *qos_profile; #endif } RTI_TSS_DDS_DomainParticipant_Configuration_T; A note about |DPs| and |TOPICS|: - |TPM| will only create a single |DP| for each unique domain. If more than one connection uses the same domain, the |DP| will be reused. A shared |DP| will not be deleted until the last connection using the |DP| is deleted. - Similarly, |TPM| will create a single |TOPIC| for each unique domain. Much like the |DP|, the |TOPIC| will be reused if more than one connection uses the same |TOPIC| (in the same domain). A shared |TOPIC| will not be deleted until the last connection using the |TOPIC| is deleted (as a result of destroying the connection). .. note:: It is important to know and configure the |DP| QoS of the first created connection. Because only one |DP| is created for each unique DDS domain, the corresponding participant QoS function of the first created connection will be applied. Connext Micro DPSE configuration """""""""""""""""""""""""""""""" Configuration of Dynamic-Participant, Static-Endpoint (DPSE) discovery for |CONNEXT_MICRO| requires functions to be called to assert discoverable remote DDS endpoints. To support this, the |DP| configuration has a discovery plugin field (``RTI_TSS_DDS_DomainParticipant_Configuration_T.discovery_plugin``) to configure the discoverable remote *Entities* for that |DP|. The following snippets configure DPSE to discover two remote |DPS|, one with a remote publisher and the other with a remote subscriber. Example DPSE configuration snippet in C++: .. code-block:: C++ /* Example DPSE snippet from a Foo_TSSConfigInterface.hpp */ FACE::Boolean _populate_domain_config() { if (!RTI_TSS_DDS_DomainParticipant_Configuration_initialize(&_domain_configurations[0])) { return false; } _domain_configurations[0].config_name = "publisher_domain"; ... #ifdef RTI_CONNEXT_MICRO _set_discovery_config(_domain_configurations[0].discovery_config); ... #endif ... } #ifdef RTI_CONNEXT_MICRO void _set_discovery_config(struct RTI_TSS_DiscoveryConfigPlugin &cfg) { /* This configuration will be used by those participants using DPSE */ FACE::UnsignedLong i; RTI_TSS_RemoteParticipantEntry_T *current_par_entry = NULL; RTI_TSS_RemoteSubscriptionEntry_T *current_sub_entry = NULL; RTI_TSS_RemotePublicationEntry_T *current_pub_entry = NULL; struct DDS_SubscriptionBuiltinTopicData rem_subscription_data = DDS_SubscriptionBuiltinTopicData_INITIALIZER; struct DDS_PublicationBuiltinTopicData rem_publication_data = DDS_PublicationBuiltinTopicData_INITIALIZER; RTI_TSS_DiscoveryConfigPlugin_initialize(&cfg); cfg.dpse_component_name = "dpse"; /* The amount of remote participant_entries that will be asserted */ cfg.length = 2; cfg.participant_entries = (RTI_TSS_RemoteParticipantEntry_T *) malloc(sizeof(RTI_TSS_RemoteParticipantEntry_T) * cfg.length); memset(cfg.participant_entries, 0, sizeof(RTI_TSS_RemoteParticipantEntry_T)); /* Configure the remote publisher participant */ current_par_entry = &cfg.participant_entries[1]; current_par_entry->participant_name = "publisher"; current_par_entry->sub_length = 0; /* Configure remote publisher */ current_par_entry->pub_length = 1; current_par_entry->publication_entries = (RTI_TSS_RemotePublicationEntry_T *) malloc( sizeof(RTI_TSS_RemotePublicationEntry_T) * current_par_entry->pub_length); memset(current_par_entry->publication_entries, 0, sizeof(RTI_TSS_RemotePublicationEntry_T) * current_par_entry->pub_length); rem_publication_data.key.value[DDS_BUILTIN_TOPIC_KEY_OBJECT_ID] = 100; rem_publication_data.topic_name = DDS_String_dup("Example FACE_DM_RTI_InteropExample"); rem_publication_data.type_name = DDS_String_dup("FACE::DM::RTI::InteropExample"); rem_publication_data.reliability.kind = DDS_RELIABLE_RELIABILITY_QOS; current_pub_entry = ¤t_par_entry->publication_entries[0]; current_pub_entry->data = rem_publication_data; current_pub_entry->key_kind = FACE_DM_RTI_InteropExample_get_key_kind( FACE_DM_RTI_InteropExampleTypePlugin_get(), NULL); /* Configure the remote subscriber participant */ current_par_entry = &cfg.participant_entries[0]; current_par_entry->participant_name = "subscriber"; current_par_entry->pub_length = 0; /* Configure remote subscriber */ current_par_entry->sub_length = 1; current_par_entry->subscription_entries = (RTI_TSS_RemoteSubscriptionEntry_T *) malloc(sizeof(RTI_TSS_RemoteSubscriptionEntry_T) * current_par_entry->sub_length); memset(current_par_entry->subscription_entries, 0, sizeof(RTI_TSS_RemoteSubscriptionEntry_T) * current_par_entry->sub_length); rem_subscription_data.key.value[DDS_BUILTIN_TOPIC_KEY_OBJECT_ID] = 200; rem_subscription_data.topic_name = DDS_String_dup("Example FACE_DM_RTI_InteropExample"); rem_subscription_data.type_name = DDS_String_dup("FACE::DM::RTI::InteropExample"); rem_subscription_data.reliability.kind = DDS_RELIABLE_RELIABILITY_QOS; current_sub_entry = ¤t_par_entry->subscription_entries[0]; current_sub_entry->data = rem_subscription_data; current_sub_entry->key_kind = FACE_DM_RTI_InteropExample_get_key_kind( FACE_DM_RTI_InteropExampleTypePlugin_get(), NULL); } #endif //RTI_CONNEXT_MICRO Example DPSE configuration snippet in C: .. code-block:: C /* Example DPSE snippet from a Foo_TSSConfigInterface.hpp */ FACE_boolean _populate_domain_config() { if (!RTI_TSS_DDS_DomainParticipant_Configuration_initialize(&_domain_configurations[0])) { return false; } _domain_configurations[0].config_name = "publisher_domain"; ... #ifdef RTI_CONNEXT_MICRO _set_discovery_config(_domain_configurations[0].discovery_config); ... #endif ... } #ifdef RTI_CONNEXT_MICRO void _set_discovery_config(struct RTI_TSS_DiscoveryConfigPlugin &cfg) { /* This configuration will be used by those participants using DPSE */ FACE_unsigned_long i; RTI_TSS_RemoteParticipantEntry_T *current_par_entry = NULL; RTI_TSS_RemoteSubscriptionEntry_T *current_sub_entry = NULL; RTI_TSS_RemotePublicationEntry_T *current_pub_entry = NULL; struct DDS_SubscriptionBuiltinTopicData rem_subscription_data = DDS_SubscriptionBuiltinTopicData_INITIALIZER; struct DDS_PublicationBuiltinTopicData rem_publication_data = DDS_PublicationBuiltinTopicData_INITIALIZER; RTI_TSS_DiscoveryConfigPlugin_initialize(&cfg); cfg.dpse_component_name = "dpse"; /* The amount of remote participant_entries that will be asserted */ cfg.length = 2; cfg.participant_entries = (RTI_TSS_RemoteParticipantEntry_T *) malloc(sizeof(RTI_TSS_RemoteParticipantEntry_T) * cfg.length); memset(cfg.participant_entries, 0, sizeof(RTI_TSS_RemoteParticipantEntry_T)); /* Configure the remote publisher participant */ current_par_entry = &cfg.participant_entries[1]; current_par_entry->participant_name = "publisher"; current_par_entry->sub_length = 0; /* Configure remote publisher */ current_par_entry->pub_length = 1; current_par_entry->publication_entries = (RTI_TSS_RemotePublicationEntry_T *) malloc( sizeof(RTI_TSS_RemotePublicationEntry_T) * current_par_entry->pub_length); memset(current_par_entry->publication_entries, 0, sizeof(RTI_TSS_RemotePublicationEntry_T) * current_par_entry->pub_length); rem_publication_data.key.value[DDS_BUILTIN_TOPIC_KEY_OBJECT_ID] = 100; rem_publication_data.topic_name = DDS_String_dup("Example FACE_DM_RTI_InteropExample"); rem_publication_data.type_name = DDS_String_dup("FACE::DM::RTI::InteropExample"); rem_publication_data.reliability.kind = DDS_RELIABLE_RELIABILITY_QOS; current_pub_entry = ¤t_par_entry->publication_entries[0]; current_pub_entry->data = rem_publication_data; current_pub_entry->key_kind = FACE_DM_RTI_InteropExample_get_key_kind( FACE_DM_RTI_InteropExampleTypePlugin_get(), NULL); /* Configure the remote subscriber participant */ current_par_entry = &cfg.participant_entries[0]; current_par_entry->participant_name = "subscriber"; current_par_entry->pub_length = 0; /* Configure remote subscriber */ current_par_entry->sub_length = 1; current_par_entry->subscription_entries = (RTI_TSS_RemoteSubscriptionEntry_T *) malloc(sizeof(RTI_TSS_RemoteSubscriptionEntry_T) * current_par_entry->sub_length); memset(current_par_entry->subscription_entries, 0, sizeof(RTI_TSS_RemoteSubscriptionEntry_T) * current_par_entry->sub_length); rem_subscription_data.key.value[DDS_BUILTIN_TOPIC_KEY_OBJECT_ID] = 200; rem_subscription_data.topic_name = DDS_String_dup("Example FACE_DM_RTI_InteropExample"); rem_subscription_data.type_name = DDS_String_dup("FACE::DM::RTI::InteropExample"); rem_subscription_data.reliability.kind = DDS_RELIABLE_RELIABILITY_QOS; current_sub_entry = ¤t_par_entry->subscription_entries[0]; current_sub_entry->data = rem_subscription_data; current_sub_entry->key_kind = FACE_DM_RTI_InteropExample_get_key_kind( FACE_DM_RTI_InteropExampleTypePlugin_get(), NULL); } #endif //RTI_CONNEXT_MICRO Type Support configuration ^^^^^^^^^^^^^^^^^^^^^^^^^^ The Type Support configuration sets the DDS type-specific functions to be used for a specific type identified by a unique name (``RTI_TSS_TypeSupport_Configuration.type_name``). Each Type Support configuration holds a pointer to the DDS ``register_type`` function for that type (``RTI_TSS_TypeSupport_Configuration.register_type_fn``). A Type Support configuration is represented by ``RTI_TSS_TypeSupport_Configuration_T``. .. code-block:: C typedef struct RTI_TSS_TypeSupport_Configuration { /*name of the type*/ const char* type_name; /*the register_type_fn that registers the type*/ RTI_TSS_RegisterTypeFunction register_type_fn; } RTI_TSS_TypeSupport_Configuration_T; The following snippets set up a Type Support configuration. Example in C++: .. code-block:: C++ /***** FACE::DM::RTI::HelloWorld *****/ if (!RTI_TSS_TypeSupport_Configuration_initialize(&_type_support_configurations[0])) { return false; } _type_support_configurations[0].type_name = "FACE::DM::RTI::HelloWorld"; _type_support_configurations[0].register_type_fn = FACE_DM_RTI_HelloWorldTypeSupport_register_type; Example in C: .. code-block:: C /***** FACE_DM_RTI_HelloWorld *****/ if (!RTI_TSS_TypeSupport_Configuration_initialize(&_type_support_configurations[0])) { return false; } _type_support_configurations[0].type_name = "FACE::DM::RTI::HelloWorld"; _type_support_configurations[0].register_type_fn = FACE_DM_RTI_HelloWorldTypeSupport_register_type; Connection configuration ^^^^^^^^^^^^^^^^^^^^^^^^ The Connection configuration sets a named connection and its underlying DDS *Entities*. The ``RTI_TSS_Channel_Configuration_t.config_name`` must match the connection_name parameter of ``FACE::TSS::TPM::TPMTS::Open_Channel`` (if using C++) or ``FACE_TSS_TPM_TPMTS_Open_Channel`` (if using C). The connection configuration will use the Type Support configuration identified by the ``RTI_TSS_Channel_Configuration_t.type_name`` field. Each connection's DDS *Entities* are managed by the |DP| corresponding to the named |DP| configuration (``RTI_TSS_Channel_Configuration_t.domain_config_name``). The DDS QoS for each DDS *Entity* type (|PUB|, |SUB|, |DW|, |DR|, |TOPIC|) are set by separate functions (``configure_*_qos_fnc()``). A Connection configuration is represented by ``RTI_TSS_Channel_Configuration_T``. Example Connection configuration in C: .. code-block:: C typedef struct RTI_TSS_Channel_Configuration { /*name of the connection configuration */ const char *config_name; /*name of the domain configuration*/ const char *domain_config_name; /*direction indicates if the connection is a send or receive*/ FACE_CONNECTION_DIRECTION_TYPE direction; /*name of the topic for the connection */ const char *topic_name; /*name of the type for the connection */ const char *type_name; /*the configure_publisher_qos_fn that configures the publisher qos settings */ RTI_TSS_PublisherQosCallback configure_publisher_qos_fn; /*the publisher listener for this connection*/ struct DDS_PublisherListener publisher_listener; /*the statusmask for the publisher listener */ DDS_StatusMask publisher_listener_status; /*the configure_subscriber_qos_fn that configures the subscriber qos settings */ RTI_TSS_SubscriberQosCallback configure_subscriber_qos_fn; /*the subscriber listener for this connection*/ struct DDS_SubscriberListener subscriber_listener; /*the statusmask for the subscriber listener */ DDS_StatusMask subscriber_listener_status; /*the configure_topic_qos_fn that configures the topic qos settings */ RTI_TSS_TopicQosCallback configure_topic_qos_fn; /*the topic listener for this connection */ struct DDS_TopicListener topic_listener; /*the statusmask for the topic listener */ DDS_StatusMask topic_listener_status; #if using Pro /*name of the content filtered topic*/ const char *content_filter_topic_name; /*the content filter expressionson*/ const char *content_filter_topic_expr; /*the content filter parameters*/ struct DDS_StringSeq content_filter_topic_params; #endif /*the configure_datawriter_qos_fn that configures the datawriter qos settings */ RTI_TSS_DataWriterQosCallback configure_datawriter_qos_fn; /*the writer listener for this connection */ struct DDS_DataWriterListener writer_listener; /*the statusmask for the topic listener */ DDS_StatusMask writer_listener_status; /*the configure_datareader_qos_fn that configures the datareader qos settings */ RTI_TSS_DataReaderQosCallback configure_datareader_qos_fn; /*the reader listener for this connection */ struct DDS_DataReaderListener reader_listener; /*the statusmask for the topic listener */ DDS_StatusMask reader_listener_status; /*additional configuration data */ void *user_data; #if using Pro /*set the connection to ignore itself */ DDS_Boolean bi_dir_ignore_self; /*pointer to the qos_library for the connection*/ const char* qos_library; /*pointer to the qos_profile for the connection*/ const char* qos_profile; #endif } RTI_TSS_Channel_Configuration_T; The following snippets configure one connection. Example configuration in C++: .. code-block:: C++ /* Example Connection snippet from a Foo_TSSConfigInterface.hpp */ static const FACE::UnsignedLong _connection_configurations_length = 2 * 3; RTI_TSS_Channel_Configuration_T _connection_configurations[_connection_configurations_length]; FACE::Boolean _populate_connection_config() { /***** FACE::DM::RTI::HelloWorld *****/ if (!RTI_TSS_Channel_Configuration_initialize(&_connection_configurations[0])) { return false; } _connection_configurations[0].config_name = "FACE::DM::RTI::HelloWorld publisher"; _connection_configurations[0].domain_config_name = "domain_0"; _connection_configurations[0].direction = FACE_SOURCE; _connection_configurations[0].topic_name = "Example FACE::DM::RTI::HelloWorld"; _connection_configurations[0].type_name = "FACE::DM::RTI::HelloWorld"; _connection_configurations[0].configure_publisher_qos_fn = FACE_DM_RTI_HelloWorld_publisher_qos; _connection_configurations[0].configure_topic_qos_fn = FACE_DM_RTI_HelloWorld_topic_qos; _connection_configurations[0].configure_datawriter_qos_fn = FACE_DM_RTI_HelloWorld_datawriter_qos; _connection_configurations[0].configure_subscriber_qos_fn = NULL; _connection_configurations[0].configure_datareader_qos_fn = NULL; _connection_configurations[0].user_data = NULL; #ifndef RTI_CONNEXT_MICRO _connection_configurations[0].bi_dir_ignore_self = DDS_BOOLEAN_TRUE; _connection_configurations[0].qos_library = "FACE_DM_RTI_HelloWorld_Library"; _connection_configurations[0].qos_profile = "FACE_DM_RTI_HelloWorld_Profile"; #endif ... } Example configuration in C: .. code-block:: C /* Example Connection snippet from a Foo_TSSConfigInterface.hpp */ static const FACE_unsigned_long _connection_configurations_length = 2 * 3; RTI_TSS_Channel_Configuration_T _connection_configurations[_connection_configurations_length]; FACE_boolean _populate_connection_config() { /***** FACE_DM_RTI_HelloWorld *****/ if (!RTI_TSS_Channel_Configuration_initialize(&_connection_configurations[0])) { return false; } _connection_configurations[0].config_name = "FACE::DM::RTI::HelloWorld publisher"; _connection_configurations[0].domain_config_name = "domain_0"; _connection_configurations[0].direction = FACE_SOURCE; _connection_configurations[0].topic_name = "Example FACE::DM::RTI::HelloWorld"; _connection_configurations[0].type_name = "FACE::DM::RTI::HelloWorld"; _connection_configurations[0].configure_publisher_qos_fn = FACE_DM_RTI_HelloWorld_publisher_qos; _connection_configurations[0].configure_topic_qos_fn = FACE_DM_RTI_HelloWorld_topic_qos; _connection_configurations[0].configure_datawriter_qos_fn = FACE_DM_RTI_HelloWorld_datawriter_qos; _connection_configurations[0].configure_subscriber_qos_fn = NULL; _connection_configurations[0].configure_datareader_qos_fn = NULL; _connection_configurations[0].user_data = NULL; #ifndef RTI_CONNEXT_MICRO _connection_configurations[0].bi_dir_ignore_self = DDS_BOOLEAN_TRUE; _connection_configurations[0].qos_library = "FACE_DM_RTI_HelloWorld_Library"; _connection_configurations[0].qos_profile = "FACE_DM_RTI_HelloWorld_Profile"; #endif ... } .. note:: Per the FACE TSS specification, the QoS for a connection's *Entities* is established at creation time for that connection and cannot be dynamically modified during communication. .. note:: If a bi-directional connection is created (with ``bi_dir_ignore_self`` set to ``TRUE``), it will not be able to communicate with other connections in the same instance with the same |DP| configuration. This is because ``DDS_DomainParticipant_ignore_publication()`` is called internally when creating a new connection with ``bi_dir_ignore_self`` set to ``TRUE``. For more information, refer to the API Reference in the |CONNEXT_MICRO| User's Manual located in your |CONNEXT_MICRO| installation directory (``\doc``). How configuration data is used in C++ ------------------------------------- An ``RTI::Configuration`` instance is set within a ``FACE::TSS::TPM::TPMTS_impl`` instance by calling the ``FACE::TSS::TPM::TPMTS_impl::Set_Reference()`` function. A subsequent call to ``FACE::TSS::TPM::TPMTS_impl::Initialize()`` will initialize the TPM instance with the configuration data in ``RTI::Configuration``. If this is the first call to ``FACE::TSS::TPM::TPMTS_impl::Initialize()``, the system property will be used to allocate the resources for |TPM| and DDS. When creating a connection, the connection configuration name (``RTI_TSS_Channel_Configuration_t.config_name``) matching the connection_name parameter to ``FACE::TSS::TPM::TPMTS_impl::Open_Channel()`` is used to configure the created connection. ``Open_Channel()`` will fail and return a ``FACE::RETURN_CODE_TYPE::Value::INVALID_CONFIG``if no matching ``config_name`` is found. How configuration data is used in C ----------------------------------- An ``RTI_Configuration`` instance is set within an ``RTI_TPM`` instance by calling ``Configuration_Injectable_Set_Reference()`` with an ``RTI_TPM`` cast as a ``FACE_Configuration_Injectable *``. A subsequent call to ``FACE_TSS_TPM_TPMTS_Initialize()`` initializes the TPM instance with the configuration data in ``RTI_Configuration``. If this is the first call to ``FACE_TSS_TPM_TPMTS_Initialize()``, the system property will be used to allocate the resources for |TPM| and DDS. When creating a connection, the connection configuration name (``RTI_TSS_Channel_Configuration_t.config_name``) matching the connection_name parameter to ``FACE_TSS_TPM_TPMTS_Open_Channel()`` is used to configure the created connection. ``Open_Channel()`` will fail and return a ``FACE_RETURN_CODE_TYPE_INVALID_CONFIG`` error if no matching ``config_name`` is found. Extending the Configuration Interface ------------------------------------- You are required to implement the configuration to suit your needs. You can copy the HelloWorld example configuration for your language as a starting point and working reference. The only hard requisites are: - All FACE Configuration functions must be implemented. - In a C FACE Configuration instance, the following variables must be defined in the Configuration Implementation provided to FACE_TSS_Base: .. code-block:: C /*ce \dref_RTI_TSS_SYSTEM_CONFIGURATION_CONTAINER_NAME */ FACE_string RTI_TSS_SYSTEM_CONFIGURATION_CONTAINER_NAME; /*ce \dref_RTI_TSS_DOMAIN_PARTICIPANT_CONFIGURATION_CONTAINER_NAME */ FACE_string RTI_TSS_DOMAIN_PARTICIPANT_CONFIGURATION_CONTAINER_NAME; /*ce \dref_RTI_TSS_TYPE_SUPPORT_CONFIGURATION_CONTAINER_NAME */ FACE_string RTI_TSS_TYPE_SUPPORT_CONFIGURATION_CONTAINER_NAME; /*ce \dref_RTI_TSS_CONNECTION_CONFIGURATION_CONTAINER_NAME */ FACE_string RTI_TSS_CHANNEL_CONFIGURATION_CONTAINER_NAME; The above variables must also be initialized as follows: .. code-block:: C FACE_string_init_managed_cstring(&RTI_TSS_SYSTEM_CONFIGURATION_CONTAINER_NAME, "RTI_TSS_SYSTEM_CONFIGURATION"); FACE_string_init_managed_cstring(&RTI_TSS_DOMAIN_PARTICIPANT_CONFIGURATION_CONTAINER_NAME, "RTI_TSS_DOMAIN_PARTICIPANT_CONFIGURATION"); FACE_string_init_managed_cstring(&RTI_TSS_TYPE_SUPPORT_CONFIGURATION_CONTAINER_NAME, "RTI_TSS_TYPE_SUPPORT_CONFIGURATION"); FACE_string_init_managed_cstring(&RTI_TSS_CHANNEL_CONFIGURATION_CONTAINER_NAME, "RTI_TSS_CONNECTION_CONFIGURATION"); - The ``Open`` method should return a handle for each one of the well-known container names defined at: - ``RTI_TSS_SYSTEM_CONFIGURATION_CONTAINER_NAME`` - ``RTI_TSS_DOMAIN_PARTICIPANT_CONFIGURATION_CONTAINER_NAME`` - ``RTI_TSS_TYPE_SUPPORT_CONFIGURATION_CONTAINER_NAME`` - ``RTI_TSS_CHANNEL_CONFIGURATION_CONTAINER_NAME`` - The ``Read`` method should return, based on the handle returned by ``Open``, a reference to an object of type: - ``RTI_TSS_System_Configuration_T`` - ``RTI_TSS_DDS_DomainParticipant_Configuration_T`` - ``RTI_TSS_TypeSupport_Configuration_T`` - ``RTI_TSS_Channel_Configuration_t`` Dynamic Memory Allocation ========================= |TSS| does *not* free dynamically allocated memory when built for FACE Safety Base or Safety Extended profiles. Dynamically allocated memory in the generated TSS plugins is also *not* returned.