QoS Provider¶
This page provides information on using the QoS provider API of Eclipse Cyclone DDS. The QoS provider API allows users to specify the QoS settings of their DDS entities outside of application code in XML. This can be seen as a useful feature where code recompilation is restricted during the later stages of application development / during application support. The following sections explain the API and explain how to build QoS Profiles in XML.
XML file syntax¶
The syntax for the XML configuration file is defined in DDS Consolidated XML Syntax.
Entity QoS¶
To configure the QoS for a DDS Entity using XML, the following tags have to be used:
<domainparticipant_qos>
<publisher_qos>
<subscriber_qos>
<topic_qos>
<datawriter_qos>
<datareader_qos>
Each XML tag with or without an associated name can be uniquely identified by its fully qualified name in C++ style. In case of unnamed XML tag, only one tag of this kind is allowed in scope of parent <qos_profile>.
QoS Policies¶
The fields in a Qos policy are described in XML using a 1-to-1 mapping with the equivalent IDL representation in the DDS specification. For example, the Reliability Qos policy is represented with the following structures:
struct Duration_t {
long sec;
unsigned long nanosec;
};
struct ReliabilityQosPolicy {
ReliabilityQosPolicyKind kind;
Duration_t max_blocking_time;
};
The equivalent representation in XML is as follows:
<reliability>
<kind></kind>
<max_blocking_time>
<sec></sec>
<nanosec></nanosec>
</max_blocking_time>
</reliability>
Sequences¶
In general, the sequences contained in the QoS policies are described with the following XML format:
<a_sequence_member_name>
<element>...</element>
<element>...</element>
...
</a_sequence_member_name>
Each element of the sequence is enclosed in an <element> tag, as shown in the following example:
<property>
<value>
<element>
<name>my name</name>
<value>my value</value>
</element>
<element>
<name>my name2</name>
<value>my value2</value>
</element>
</value>
</property>
Enumerations¶
Enumeration values are represented using their IDL string representation. For example:
<history>
<kind>KEEP_ALL_HISTORY_QOS</kind>
</history>
Time values (Durations)¶
Following values can be used for fields that require seconds or nanoseconds:
DURATION_INFINITE_SEC
DURATION_INFINITE_NSEC
The following example shows the use of time values:
<deadline>
<period>
<sec>DURATION_INFINITE_SEC</sec>
<nanosec>DURATION_INFINITE_NSEC</nanosec>
</period>
</deadline>
QoS Profiles¶
A QoS profile groups a set of related QoS, usually one per entity. For example:
<qos_profile name="StrictReliableCommunicationProfile">
<datareader_qos>
<history>
<kind>KEEP_LAST_HISTORY_QOS</kind>
<depth>5</depth>
</history>
</datareader_qos>
<datawriter_qos>
<history>
<kind>KEEP_LAST_HISTORY_QOS</kind>
<depth>1</depth>
</history>
</datawriter_qos>
</qos_profile>
QoS profiles may inherit from each other, parent profile are specified via base_name attribute. For example:
<qos_profile name="AAA">
<datareader_qos>
<history>
<kind>KEEP_LAST_HISTORY_QOS</kind>
<depth>5</depth>
</history>
</datareader_qos>
<datawriter_qos>
<history>
<kind>KEEP_LAST_HISTORY_QOS</kind>
<depth>1</depth>
</history>
</datawriter_qos>
</qos_profile>
<qos_profile name="BBB" base_name="AAA">
<datareader_qos>
<history>
<kind>KEEP_LAST_HISTORY_QOS</kind>
<depth>2</depth>
</history>
</datareader_qos>
</qos_profile>
In that particular case profile BBB derived from profile AAA, and override it’s datareader_qos.history.depth QoS value, but as a result BBB profile not only contains updated datareader_qos but merge datawriter_qos (from AAA profile) also. For inheritance over different qos_library base_name should contains full profile name e.g. <qos_library-name>::<qos_profile-name>.
XML Example¶
Consider the following XML file that describes two QoS profiles:
- FooQosProfile
DataReaderQos - KEEP_LAST (5)
DataWriterQos - KEEP_LAST (1)
TopicQos - KEEP_ALL
- BarQosProfile
DataWriterQos - KEEP_ALL
TopicQos - KEEP_LAST (5)
<dds xmlns="http://www.omg.org/dds/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="file://DDS_QoSProfile.xsd">
<qos_library name="myqoslib">
<qos_profile name="foo_profile">
<datareader_qos>
<history>
<kind>KEEP_LAST_HISTORY_QOS</kind>
<depth>5</depth>
</history>
</datareader_qos>
<datawriter_qos>
<history>
<kind>KEEP_LAST_HISTORY_QOS</kind>
<depth>1</depth>
</history>
</datawriter_qos>
<topic_qos name="my_topic">
<history>
<kind>KEEP_ALL_HISTORY_QOS</kind>
</history>
</topic_qos>
</qos_profile>
<qos_profile name="bar_profile">
<datawriter_qos>
<history>
<kind>KEEP_ALL_HISTORY_QOS</kind>
</history>
</datawriter_qos>
<topic_qos name="my_topic">
<history>
<kind>KEEP_LAST_HISTORY_QOS</kind>
<depth>10</depth>
</history>
</topic_qos>
</qos_profile>
</qos_library>
</dds>
Code Example¶
The following C application is an example to illustrate how the QoS settings from the above XML could be accessed.
#include "dds/dds.h"
#include "dds/ddsc/dds_qos_provider.h"
#include "datatypes.h"
int main (int argc, char **argv)
{
(void) argc;
(void) argv;
// provider will contain:
// myqoslib::foo_profile READER (KEEP_LAST 5)
// myqoslib::foo_profile WRITER (KEEP_LAST 1)
// myqoslib::foo_profile::my_topic TOPIC (KEEP_ALL)
// myqoslib::bar_profile WRITER (KEEP_ALL)
// myqoslib::bar_profile::my_topic TOPIC (KEEP_LAST 10)
dds_qos_provider_t *provider;
dds_return_t ret = dds_create_qos_provider ("/path/to/qos_definitions.xml", &provider);
assert (ret == DDS_RETCODE_OK);
const dds_qos_t *tp_qos, *wr_qos;
// qos can be accessed by <lib_name>::<profile_name>::[entity_name] if exist.
ret = dds_qos_provider_get_qos (provider, DDS_TOPIC_QOS, "myqoslib::bar_profile::my_topic", &tp_qos);
assert (ret == DDS_RETCODE_OK);
// or if entity_qos is unnamed only by <lib_name>::<profile_name>.
ret = dds_qos_provider_get_qos (provider, DDS_WRITER_QOS, "myqoslib::bar_profile", &wr_qos);
assert (ret == DDS_RETCODE_OK);
dds_entity_t pp = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL);
dds_entity_t tp = dds_create_topic (pp, &mydatatype_desc, "topic_A", tp_qos, NULL);
dds_entity_t wr = dds_create_writer (pp, tp, wr_qos, NULL);
dds_delete (pp);
dds_delete_qos_provider (provider);
return 0;
}
#include "dds/dds.hpp"
#include "DataType.hpp"
using namespace org::eclipse::cyclonedds;
int main()
{
// foo_provider will contain:
// myqoslib::foo_profile READER (KEEP_LAST 5)
// myqoslib::foo_profile WRITER (KEEP_LAST 1)
// myqoslib::foo_profile::my_topic TOPIC (KEEP_ALL)
// bar_provider will contain:
// myqoslib::bar_profile WRITER (KEEP_ALL)
// myqoslib::bar_profile::my_topic TOPIC (KEEP_LAST 10)
dds::core::QosProvider foo_provider("/path/to/qos_definitions.xml", "myqoslib::foo_profile");
dds::core::QosProvider bar_provider("/path/to/qos_definitions.xml", "myqoslib::bar_profile");
auto topic_qos = bar_provider.topic_qos("my_topic");
auto writer_qos = bar_provider.datawriter_qos();
dds::domain::DomainParticipant participant(domain::default_id());
dds::topic::Topic<DataType::Msg> topic(participant, "topic_A", topic_qos);
dds::pub::Publisher publisher(participant);
dds::pub::DataWriter<DataType::Msg> writer(publisher, topic, writer_qos);
(void)writer;
return 0;
}
from dataclasses import dataclass
from cyclonedds.domain import DomainParticipant
from cyclonedds.pub import DataWriter
from cyclonedds.sub import DataReader
from cyclonedds.topic import Topic
from cyclonedds.qos_provider import QosProvider
from cyclonedds.qos import (
DataReaderQos, DataWriterQos, DomainParticipantQos, PublisherQos, Qos,
SubscriberQos, TopicQos,
)
from cyclonedds.idl import IdlStruct
@dataclass
class DataType(IdlStruct, typename="DataType"):
data: str
# provider will contain:
# myqoslib::foo_profile READER (KEEP_LAST 5)
# myqoslib::foo_profile WRITER (KEEP_LAST 1)
# myqoslib::foo_profile::my_topic TOPIC (KEEP_ALL)
# myqoslib::bar_profile WRITER (KEEP_ALL)
# myqoslib::bar_profile::my_topic TOPIC (KEEP_LAST 10)
provider = QosProvider("/path/to/qos_definitions.xml")
# qos can be accessed by <lib_name>::<profile_name>::[entity_name] if exist.
tp_qos = provider.get_topic_qos("myqoslib::bar_profile::my_topic")
# or if entity_qos is unnamed only by <lib_name>::<profile_name>.
wr_qos = provider.get_writer_qos("myqoslib::bar_profile")
dp = DomainParticipant()
tp = Topic(dp, "topic_A", DataType, tp_qos)
dw = DataWriter(dp, tp, wr_qos)
Also C API allows you to specify which library, profile QoS Provider should contains.
Important
CXX API doesn’t allow wild cards and have strict initialization/access format
Let’s extend XML file example above, and omit QoS settings details for simplicity.
<dds xmlns="http://www.omg.org/dds/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="file://DDS_QoSProfile.xsd">
<qos_library name="qos1_lib">
<qos_profile name="foo_profile">
<datareader_qos/>
<datawriter_qos/>
<topic_qos/>
</qos_profile>
<qos_profile name="bar_profile">
<datawriter_qos/>
<topic_qos/>
</qos_profile>
</qos_library>
<qos_library name="qos2_lib">
<qos_profile name="foo_profile">
<datareader_qos/>
<datawriter_qos/>
<topic_qos/>
</qos_profile>
<qos_profile name="bar_profile">
<datawriter_qos/>
<topic_qos/>
</qos_profile>
</qos_library>
</dds>
Let’s create QoS Provider that contains versions of both profiles from different libraries.
Important
CXX API doesn’t allow wild cards and have strict initialization/access format, that’s why we can’t mix profiles from different libraries and required to initialize each profile instance.
#include "dds/dds.h"
#include "dds/ddsc/dds_qos_provider.h"
#include "datatypes.h"
int main (int argc, char **argv)
{
(void) argc;
(void) argv;
// foo_provider will contain:
// qos1_lib::foo_profile READER
// qos1_lib::foo_profile WRITER
// qos1_lib::foo_profile TOPIC
// qos2_lib::foo_profile READER
// qos2_lib::foo_profile WRITER
// qos2_lib::foo_profile TOPIC
dds_qos_provider_t *foo_provider;
char *foo_scope = "*::foo_profile";
dds_return_t ret = dds_create_qos_provider_scope ("/path/to/qos_definitions.xml", &foo_provider, foo_scope);
assert (ret == DDS_RETCODE_OK);
// bar_provider will contain:
// qos1_lib::bar_profile WRITER
// qos1_lib::bar_profile TOPIC
// qos2_lib::bar_profile WRITER
// qos2_lib::bar_profile TOPIC
dds_qos_provider_t *bar_provider;
char *bar_scope = "*::bar_profile";
dds_return_t ret = dds_create_qos_provider_scope ("/path/to/qos_definitions.xml", &bar_provider, bar_scope);
assert (ret == DDS_RETCODE_OK);
...
dds_delete_qos_provider (foo_provider);
dds_delete_qos_provider (bar_provider);
return 0;
}
#include "dds/dds.hpp"
#include "DataType.hpp"
using namespace org::eclipse::cyclonedds;
int main()
{
// foo_provider1 will contain:
// qos1_lib::foo_profile READER
// qos1_lib::foo_profile WRITER
// qos1_lib::foo_profile TOPIC
// foo_provider2 will contain:
// qos2_lib::foo_profile READER
// qos2_lib::foo_profile WRITER
// qos2_lib::foo_profile TOPIC
dds::core::QosProvider foo_provider1("/path/to/qos_definitions.xml", "qos1_lib::foo_profile");
dds::core::QosProvider foo_provider2("/path/to/qos_definitions.xml", "qos2_lib::foo_profile");
// bar_provider will contain:
// qos1_lib::bar_profile WRITER
// qos1_lib::bar_profile TOPIC
// bar_provider2 will contain:
// qos2_lib::bar_profile WRITER
// qos2_lib::bar_profile TOPIC
dds::core::QosProvider bar_provider1("/path/to/qos_definitions.xml", "qos1_lib::bar_profile");
dds::core::QosProvider bar_provider2("/path/to/qos_definitions.xml", "qos2_lib::bar_profile");
...
return 0;
}
from dataclasses import dataclass
from cyclonedds.domain import DomainParticipant
from cyclonedds.pub import DataWriter
from cyclonedds.sub import DataReader
from cyclonedds.topic import Topic
from cyclonedds.qos_provider import QosProvider
from cyclonedds.qos import (
DataReaderQos, DataWriterQos, DomainParticipantQos, PublisherQos, Qos,
SubscriberQos, TopicQos,
)
from cyclonedds.idl import IdlStruct
@dataclass
class DataType(IdlStruct, typename="DataType"):
data: str
# foo_provider will contain:
# qos1_lib::foo_profile READER
# qos1_lib::foo_profile WRITER
# qos1_lib::foo_profile TOPIC
# qos2_lib::foo_profile READER
# qos2_lib::foo_profile WRITER
# qos2_lib::foo_profile TOPIC
foo_provider = QosProvider("/path/to/qos_definitions.xml", "*::foo_profile")
# bar_provider will contain:
# qos1_lib::bar_profile WRITER
# qos1_lib::bar_profile TOPIC
# qos2_lib::bar_profile WRITER
# qos2_lib::bar_profile TOPIC
bar_provider = QosProvider("/path/to/qos_definitions.xml", "*::bar_profile")
...
Known limitations¶
The “topic_filter” attribute for writer, reader and topic QoSes to associate a set of topics to a specific QoS when that QoS is part of a DDS profile, is not supported yet.
The “entity_factory” attribute for participant, writer and reader QoSes, support only “true” for “<autoenable_created_entities>”.
The C++ API QosProvider may throw an UnsupportedError when trying to access a policy that is not supported yet.