RTI Connext
Core Libraries and Utilities
User’s Manual
Version 5.0
© 2012
All rights reserved.
Printed in U.S.A. First printing.
August 2012.
Trademarks
Copy and Use Restrictions
No part of this publication may be reproduced, stored in a retrieval system, or transmitted in any form (including electronic, mechanical, photocopy, and facsimile) without the prior written permission of Real- Time Innovations, Inc. The software described in this document is furnished under and subject to the RTI software license agreement. The software may be used or copied only under the terms of the license agreement.
Note: In this section, "the Software" refers to
This product implements the DCPS layer of the Data Distribution Service (DDS) specification version 1.2 and the DDS Interoperability Wire Protocol specification version 2.1, both of which are owned by the Object Management, Inc. Copyright
Portions of this product were developed using ANTLR (www.ANTLR.org). This product includes software developed by the University of California, Berkeley and its contributors.
Portions of this product were developed using AspectJ, which is distributed per the CPL license. AspectJ source code may be obtained from Eclipse. This product includes software developed by the University of California, Berkeley and its contributors.
Portions of this product were developed using MD5 from Aladdin Enterprises.
Portions of this product include software derived from Fnmatch, (c) 1989, 1993, 1994 The Regents of the University of California. All rights reserved. The Regents and contributors provide this software "as is" without warranty.
Portions of this product were developed using EXPAT from Thai Open Source Software Center Ltd and Clark Cooper Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd and Clark Cooper Copyright (c) 2001, 2002 Expat maintainers. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
Technical Support
232 E. Java Drive
Sunnyvale, CA 94089
Phone: |
(408) |
Email: |
support@rti.com |
Website: |
Available Documentation
To get you up and running as quickly as possible, we have divided the RTI® Connext™ (for- merly, RTI Data Distribution Service) documentation into several parts.
❏Getting Started Guide
If you want to use the Connext Extensible Types feature, please read:
• Addendum for Extensible Types (RTI_CoreLibrariesAndUtilities_GettingStarted _ExtensibleTypesAddendum.pdf) Extensible Types allow you to define data types in a more flexible way. Your data types can evolve over
If you are using Connext on an embedded platform or with a database, you will find additional documents that specifically address these configurations:
•Addendum for Embedded Systems (RTI_CoreLibrariesAndUtilities_GettingStarted _EmbeddedSystemsAddendum.pdf)
•Addendum for Database Setup (RTI_CoreLibrariesAndUtilities_GettingStarted
_DatabaseAddendum.pdf).
❏What’s New
❏Release Notes and Platform Notes (RTI_CoreLibrariesAndUtilities_ReleaseNotes.pdf and
❏Core Libraries and Utilities User’s Manual (RTI_CoreLibrariesAndUtilities
❏API Reference Documentation (ReadMe.html, RTI_CoreLibrariesAndUtilities
iii
The Programming How To's provide a good place to begin learning the APIs. These are hyperlinked code snippets to the full API documentation. From the ReadMe.html file, select one of the supported programming languages, then scroll down to the Program- ming How To’s. Start by reviewing the Publication Example and Subscription Example, which provide
Many readers will also want to look at additional documentation available online. In particular, RTI recommends the following:
❏The RTI Customer Portal, https://support.rti.com, provides access to RTI software, doc- umentation, and support. It also allows you to log support cases. Furthermore, the portal provides detailed solutions and a free public knowledge base. To access the software, documentation or log support cases, the RTI Customer Portal requires a username and password. You will receive this in the email confirming your purchase. If you do not have this email, please contact license@rti.com. Resetting your login password can be done directly at the RTI Customer Portal.
❏
•Example Performance Test (available for C++, Java
❏Whitepapers and other
1. RTI Connext .NET language binding is currently supported for C# and C++/CLI.
iv
Contents
|
|
Available Documentation.............................................................. |
iii |
|
|
|
Welcome to RTI Connext............................................................................ |
xix |
|
|
|
xix |
||
|
|
|
xix |
|
|
|
|
xix |
|
|
|
|
xix |
|
|
|
xx |
||
|
||||
Overview............................................................................................ |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
2.1.1 DCPS for |
||
|
||||
|
|
|||
|
|
|||
|
||||
|
||||
|
||||
|
|
|||
|
||||
|
||||
3 Data Types and Data Samples ........................................................ |
||||
|
||||
|
|
|||
|
|
|||
|
|
|||
|
||||
|
|
Registering |
v
................................................................................................ |
||
Enabling Entities ....................................................................................................................... |
||
Getting the StatusCondition |
||
4.2.1 .......................................QoS Requested vs. Offered |
||
vi
|
||||
|
|
|||
|
|
4.3.2 Special |
||
|
||||
|
|
|||
|
|
4.4.2 Creating and Deleting Listeners........................................................................................... |
||
|
|
|||
|
|
|||
|
|
|||
|
||||
|
|
|||
|
||||
|
|
4.6.1 Creating and Deleting WaitSets............................................................................................ |
||
|
|
|||
|
|
|||
|
|
4.6.4 Processing Triggered |
||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
||||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
||||
|
|
|||
|
||||
|
|
|||
|
||||
|
|
|||
|
|
5.4.2 Where Filtering is |
||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
Sending Data..................................................................................... |
||||
|
||||
|
||||
|
|
vii
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
Using a |
||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
Managing Data Instances (Working with Keyed Data Types)......................................... |
||
|
|||
|
|||
|
|||
|
ASYNCHRONOUS_PUBLISHER QosPolicy (DDS Extension) ...................................... |
||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
DATA_WRITER_PROTOCOL QosPolicy (DDS Extension)............................................. |
||
|
DATA_WRITER_RESOURCE_LIMITS QosPolicy (DDS Extension).............................. |
||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
MULTI_CHANNEL QosPolicy (DDS Extension)............................................................ |
||
|
viii
TRANSPORT_SELECTION QosPolicy (DDS Extension)............................................... |
||
TRANSPORT_UNICAST QosPolicy (DDS Extension) ................................................... |
||
Managing Fast DataWriters When Using a FlowController .......................................... |
||
Creating and Configuring Custom FlowControllers with Property QoS .................... |
||
Receiving Data.................................................................................. |
||||
|
||||
|
||||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
7.2.5 Beginning and Ending |
||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
||||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
||||
|
|
7.4.1 Using a |
||
|
|
|||
|
|
ix
8 Working with Domains ...................................................................... |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
Choosing a Domain ID and Creating Multiple Domains................................................. |
||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
SYSTEM_RESOURCE_LIMITS QoS Policy (DDS Extension).......................................... |
||
|
|||
|
|||
|
DISCOVERY_CONFIG QosPolicy (DDS Extension)......................................................... |
||
|
DOMAIN_PARTICIPANT_RESOURCE_LIMITS QosPolicy (DDS Extension) ............ |
||
|
|||
|
|||
|
TRANSPORT_BUILTIN QosPolicy (DDS Extension) ....................................................... |
||
|
TRANSPORT_MULTICAST_MAPPING QosPolicy (DDS Extension)........................... |
||
|
x
|
|||
|
|||
11 Collaborative DataWriters.............................................................. |
||
|
||
|
||
|
11.3.3 Specifying which DataWriters will Deliver Samples to the DataReader from a Logical |
|
|
Data |
|
|
||
xi
xii
xiii
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
xiv
21 Troubleshooting............................................................................... |
||
|
||
|
||
|
||
|
||
|
Part 4:
xv
Getting Requests and Sending Replies with a SimpleReplierListener ......................... |
||
Part 5: RTI Secure WAN Transport
25 Configuring RTI Secure WAN Transport ......................................... |
|||
|
|||
|
|||
|
Part 6: RTI Persistence Service
Introduction to RTI Persistence Service......................................... |
||||
Configuring Persistence Service.................................................... |
||||
|
||||
|
||||
|
|
|||
|
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
xvi
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
||||
|
|
Sample Memory Management With Durable Subscriptions ......................................... |
||
|
||||
|
||||
|
||||
|
||||
|
|
|||
Running RTI Persistence Service .................................................... |
||||
|
||||
|
||||
Administering Persistence Service from a Remote Location...... |
||||
|
||||
|
||||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
||||
Advanced Persistence Service Scenarios ................................... |
||||
|
Scenario: |
|||
|
||||
|
Part 7: RTI CORBA Compatibility Kit
Introduction to RTI CORBA Compatibility Kit ................................ |
|||
Generating |
|||
|
|||
|
xvii
33 Supported IDL Types ....................................................................... |
Part 8: RTI RTSJ Extension Kit
Introduction to RTI RTSJ Extension Kit............................................. |
||
Using RTI RTSJ Extension Kit ............................................................ |
36 Configuring the RTI TCP Transport.................................................. |
|
xviii
Welcome to RTI Connext
RTI Connext solutions provide a flexible data distribution infrastructure for integrating data sources of all types. At its core is the world's leading
Conventions
The terminology and example code in this manual assume you are using C++ without namespace support.
C, C++/CLI, C#, and Java APIs are also available; they are fully described in the API Reference HTML documentation.
Namespace support in C++, C++/CLI, and C# is also available; see the API Reference HTML documentation (from the Modules page, select Using DDS:: Namespace) for details.
Extensions to the DDS Standard
Connext implements the DDS Standard published by the OMG. It also includes features that are extensions to DDS. These include additional Quality of Service parameters, function calls, struc- ture fields, etc.
Extensions also include
Environment Variables
Connext documentation refers to pathnames that have been customized during installation. NDDSHOME refers to the installation directory of Connext.
Names of Supported Platforms
Connext runs on several different target platforms. To support this vast array of platforms, Con- next separates the executable, library, and object files for each platform into individual directo- ries.
xix
Each platform name has four parts: hardware architecture, operating system, operating system version and compiler. For example, i86Linux2.4gcc3.2 is the directory that contains files specific to Linux® version 2.4 for the Intel processor, compiled with gcc version 3.2.
For a full list of supported platforms, see the Platform Notes.
Additional Resources
The details of each API (such as function parameters, return values, etc.) and examples are in the API Reference HTML documentation. In case of discrepancies between the information in this document and the API Reference HTML documentation, the latter should be considered more
xx
Part 1: Introduction
This introduces the general concepts behind
1
Chapter 1 Overview
RTI Connext (formerly, RTI Data Distribution Service) is network middleware for distributed real- time applications. Connext simplifies application development, deployment and maintenance and provides fast, predictable distribution of
With Connext, you can:
❏Perform complex
❏Customize application operation to meet various
❏Provide
❏Use a variety of transports.
This chapter introduces basic concepts of middleware and common communication models, and describes how Connext’s
1.1What is Connext?
Connext is network middleware for
Connext implements the
With Connext, systems designers and programmers start with a
What is Middleware?
1.2What is Middleware?
Middleware is a software layer between an application and the operating system. Network middle- ware isolates the application from the details of the underlying computer architecture, operating system and network stack (see Figure 1.1). Network middleware simplifies the development of distributed systems by allowing applications to send and receive information without having to program using
Figure 1.1 Network Middleware
Connext is middleware that insulates applications from the raw
Despite the simplicity of the model, PS middleware can handle complex patterns of information flow. The use of PS middleware results in simpler, more modular distributed applications. Per- haps most importantly, PS middleware can automatically handle all network chores, including connections, failures, and network changes, eliminating the need for user applications to pro- gram of all those special cases. What experienced network middleware developers know is that handling special cases accounts for over 80% of the effort and code.
1.3Network Communications Models
The communications model underlying the network middleware is the most important factor in how applications communicate. The communications model impacts the performance, the ease to accomplish different communication transactions, the nature of detecting errors, and the robustness to different error conditions. Unfortunately, there is no “one size fits all” approach to distributed applications. Different communications models are better suited to handle different classes of application domains.
This section describes three main types of network communications models:
❏
❏
Network Communications Models
❏
TCP is a
Figure 1.2
A
B
The
Figure 1.3
Client |
Client |
|
Server |
request |
Client |
Client |
reply |
|
Features of Connext
While the
❏
❏Remote Method Invocation (alternate solutions: CORBA, COM, SOAP)
❏
❏Synchronous transfers (alternate solution: CORBA)
Figure 1.4
Subscriber |
Subscriber |
|
Publisher |
Subscriber
Publisher
1.4Features of Connext
Connext supports mechanisms that go beyond the basic
❏determining who should receive the messages,
❏where recipients are located,
❏what happens if messages cannot be delivered.
This is made possible by how Connext allows the user to specify Quality of Service (QoS) param- eters as a way to configure
Furthermore, Connext includes the following features, which are designed to meet the needs of distributed
❏
• Clear semantics for managing multiple sources of the same data.
Features of Connext
•Efficient data transfer, customizable Quality of Service, and error notification.
•Guaranteed periodic samples, with maximum rate set by subscriptions.
•Notification by a callback routine on data arrival to minimize latency.
•Notification when data does not arrive by an expected deadline.
•Ability to send the same message to multiple computers efficiently.
❏
❏Reliable messaging Enables subscribing applications to specify reliable delivery of samples.
❏Multiple Communication Networks Multiple independent communication networks (domains) each using Connext can be used over the same physical network. Applications are only able to participate in the domains to which they belong. Individual applications can be configured to participate in multiple domains.
❏Symmetric architecture Makes your application robust:
•No central server or privileged nodes, so the system is robust to node failures.
•Subscriptions and publications can be dynamically added and removed from the sys- tem at any time.
❏Pluggable Transports Framework Includes the ability to define new transport
❏Multiple
❏
❏
❏Compliance with Standards
•API complies with the DCPS layer of the OMG’s DDS specification.
•Data types comply with OMG Interface Definition Language™ (IDL).
•Data packet format complies with the International Engineering Consortium’s (IEC’s) publicly available specification for the RTPS wire protocol.
Chapter 2
Communications
This chapter describes the formal communications model used by Connext: the
This chapter includes the following sections:
❏Data Types, Topics, Keys, Instances, and Samples (Section 2.2)
❏DataWriters/Publishers and DataReaders/Subscribers (Section 2.3)
❏Domains and DomainParticipants (Section 2.4)
❏Quality of Service (QoS) (Section 2.5)
❏Application Discovery (Section 2.6)
2.1What is DCPS?
DCPS is the portion of the OMG DDS (Data Distribution Service) Standard that addresses data- centric
The
The
In contrast, in
What is DCPS?
types of method arguments). An
Data and
2.1.1DCPS for
DCPS, and specifically the Connext implementation, is well suited for
Efficiency
Determinism
Flexible delivery bandwidth Typical
DCPS allows subscribers to the same data to set individual limits on how fast data should be delivered each subscriber. This is similar to how some people get a newspaper every day while others can subscribe to only the Sunday paper.
Thread awareness
Connext provides
Data Types, Topics, Keys, Instances, and Samples
DCPS, and thus Connext, was designed and implemented specifically to address the require- ments above through configuration parameters known as QosPolicies defined by the DCPS standard (see QosPolicies (Section 4.2)). The following section introduces basic DCPS terminol- ogy and concepts.
2.2Data Types, Topics, Keys, Instances, and Samples
In
Within different programming languages there are several ‘primitive’ data types that all users of that language naturally share (integers, floating point numbers, characters, booleans, etc.). How- ever, in any
struct Time { long year; short day; short hour; short minute; short second;
};
struct StockPrice { float price; Time timeStamp;
};
Within a set of applications using DCPS, the different applications do not automatically know the structure of the data being sent, nor do they necessarily interpret it in the same way (if, for instance, they use different operating systems, were written with different languages, or were compiled with different compilers). There must be a way to share not only the data, but also information about how the data is structured.
In DCPS, data definitions are shared among applications using OMG IDL, a
2.2.1Data Topics — What is the Data Called?
Shared knowledge of the data types is a requirement for different applications to communicate with DCPS. The applications must also share a way to identify which data is to be shared. Data (of any data type) is uniquely distinguished by using a name called a Topic. By definition, a Topic corresponds to a single data type. However, several Topics may refer to the same data type.
Topics interconnect DataWriters and DataReaders. A DataWriter is an object in an application that tells Connext (and indirectly, other applications) that it has some values of a certain Topic. A cor- responding DataReader is an object in an application that tells Connext that it wants to receive values for the same Topic. And the data that is passed from the DataWriter to the DataReader is of the data type associated with the Topic. DataWriters and DataReaders are described more in Section 2.3.
Data Types, Topics, Keys, Instances, and Samples
For a concrete example, consider a system that distributes stock quotes between applications. The applications could use a data type called StockPrice. There could be multiple Topics of the StockPrice data type, one for each company’s stock, such as IBM, MSFT, GE, etc. Each Topic uses the same data type.
Data Type: StockPrice
struct StockPrice { float price;
Time timeStamp;
};
Topic: “IBM”
Topic: “MSFT”
Topic: “GE”
Now, an application that keeps track of the current value of a client’s portfolio would subscribe to all of the topics of the stocks owned by the client. As the value of each stock changes, the new price for the corresponding topic is published and sent to the application.
2.2.2Samples, Instances, and Keys
The value of data associated with a Topic can change over time. The different values of the Topic passed between applications are called samples. In our
For a data type, you can select one or more fields within the data type to form a key. A key is something that can be used to uniquely identify one instance of a Topic from another instance of the same Topic. Think of a key as a way to
However, for topics with keys, a unique value for the key identifies a unique instance of the topic. Samples are then updates to particular instances of a topic. Applications can subscribe to a topic and receive samples for many different instances. Applications can publish samples of one, all, or any number of instances of a topic. Many quality of service parameters actually apply on a per instance basis. Keys are also useful for subscribing to a group of related data streams (instances) without
For example, let’s change the StockPrice data type to include the symbol of the stock. Then instead of having a Topic for every stock, which would result in hundreds or thousands of topics and related DataWriters and DataReaders, each application would only have to publish or sub- scribe to a single Topic, say “StockPrices.” Successive values of a stock would be presented as successive samples of an instance of “StockPrices”, with each instance corresponding to a single stock symbol.
Data Type: StockPrice
struct StockPrice { float price; Time timeStamp;
char *symbol; //@key
};
Instance 1 = (Topic: “StockPrices”) + (Key: “MSFT”)
sample a, price = $28.00
sample b, price = $27.88
DataWriters/Publishers and DataReaders/Subscribers
Instance 2 = (Topic: “StockPrices”) + (Key: “IBM”)
sample a, price = $74.02
sample b, price = $73.50
Etc.
Just by subscribing to “StockPrices,” an application can get values for all of the stocks through a single topic. In addition, the application does not have to subscribe explicitly to any particular stock, so that if a new stock is added, the application will immediately start receiving values for that stock as well.
To summarize, the unique values of data being passed using DCPS are called samples. A sample is a combination of a Topic (distinguished by a Topic name), an instance (distinguished by a key), and the actual user data of a certain data type. As seen in Figure 2.1 on page
Figure 2.1 Relationship of Topics, Keys, and Instances
|
|
|
|
|
|
|
a_type:instance1 |
Type:a_type |
|
|
|
|
|
|
|
|
|
|
|
|
|
Key = key1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Key = ... |
|
|
|
|
|
|
|
|
|
Topic:a_topic |
|
|
|
a_type:instance2 |
|
|
|
|
|
|
|||
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Key = key2 |
|
|
|
|
|
|
|
|
a_type:instance3
Key = key3
By using keys, a Topic can identify a collection of
2.3DataWriters/Publishers and DataReaders/Subscribers
In DCPS, applications must use APIs to create entities (objects) in order to establish
The sending side uses objects called Publishers and DataWriters. The receiving side uses objects called Subscribers and DataReaders. Figure 2.2 illustrates the relationship of these objects.
❏An application uses DataWriters to send data. A DataWriter is associated with a single Topic. You can have multiple DataWriters and Topics in a single application. In addition, you can have more than one DataWriter for a particular Topic in a single application.
DataWriters/Publishers and DataReaders/Subscribers
Figure 2.2 Overview
❏A Publisher is the DCPS object responsible for the actual sending of data. Publishers own and manage DataWriters. A DataWriter can only be owned by a single Publisher while a Publisher can own many DataWriters. Thus the same Publisher may be sending data for many different Topics of different data types. When user code calls the write() method on a DataWriter, the data sample is passed to the Publisher object which does the actual dis- semination of data on the network. For more information, see Chapter 6: Sending Data.
❏The association between a DataWriter and a Publisher is often referred to as a publication although you never create a DCPS object known as a publication.
❏An application uses DataReaders to access data received over DCPS. A DataReader is asso- ciated with a single Topic. You can have multiple DataReaders and Topics in a single appli- cation. In addition, you can have more than one DataReader for a particular Topic in a single application.
❏A Subscriber is the DCPS object responsible for the actual receipt of published data. Sub- scribers own and manage DataReaders. A DataReader can only be owned by a single Sub- scriber while a Subscriber can own many DataReaders. Thus the same Subscriber may receive data for many different Topics of different data types. When data is sent to an application, it is first processed by a Subscriber; the data sample is then stored in the appropriate DataReader. User code can either register a listener to be called when new data arrives or actively poll the DataReader for new data using its read() and take() meth- ods. For more information, see Chapter 7: Receiving Data.
❏The association between a DataReader and a Subscriber is often referred to as a subscription although you never create a DCPS object known as a subscription.
Example: The
Domains and DomainParticipants
mat of the information, e.g., a printed magazine. The user data is the contents (text and graphics) of each sample (weekly issue). The middleware is the distribution service (usually the US Postal service) that delivers the magazine from where it is created (a printing house) to the individual subscribers (people’s homes). This analogy is illustrated in Figure 2.3. Note that by subscribing to a publication, subscribers are requesting current and future samples of that publication (such as once a week in the case of Newsweek), so that as new samples are published, they are delivered without having to submit another request for data.
Figure 2.3 An Example of
Topic = "Newsweek" |
|
|
|
Topic = "Newsweek" |
||
|
|
Sample |
|
|
||
|
|
|
|
|||
|
|
|
|
|
|
|
Publisher |
Issue for Feb. 15 |
Subscriber |
||||
|
Send |
|
|
|
Receive |
|
|
|
|
|
|||
|
|
Delivery |
|
Service |
|
|
|
|
|
|
|
The
By default, each data sample is propagated individually, independently, and uncorrelated with other samples. However, an application may request that several samples be sent as a coherent set, so that they may be interpreted as such on the receiving side.
2.4Domains and DomainParticipants
You may have several independent DCPS applications all running on the same set of computers. You may want to isolate one (or more) of those applications so that it isn’t affected by the others. To address this issue, DCPS has a concept called Domains.
Domains represent logical, isolated, communication networks. Multiple applications running on the same set of hosts on different Domains are completely isolated from each other (even if they are on the same machine). DataWriters and DataReaders belonging to different domains will never exchange data.
Applications that want to exchange data using DCPS must belong to the same Domain. To belong to a Domain, DCPS APIs are used to configure and create a DomainParticipant with a spe- cific Domain Index. Domains are differentiated by the Domain Index (an integer value). Applica- tions that have created DomainParticipants with the same Domain Index belong to the same
Domain. DomainParticipants own Topics, Publishers and Subscribers which in turn owns DataWrit- ers and DataReaders. Thus all DCPS Entities belong to a specific domain.
An application may belong to multiple domains simultaneously by creating multiple Domain- Participants with different domain indices. However, Publishers/DataWriters and Subscribers/
DataReaders only belong to the domain in which they were created.
As mentioned before, multiple domains may be used for application isolation which is useful when users are testing their applications using computers on the same network or even the same computers. By assigning each user different domains, one can guarantee that the data pro- duced by one user’s application won’t accidentally be received by another. In addition, domains
Quality of Service (QoS)
may be a way to scale and construct larger systems that are composed of
For more information, see Chapter 8: Working with Domains.
2.5Quality of Service (QoS)
The
2.5.1Controlling Behavior with Quality of Service (QoS) Policies
QosPolicies control many aspects of how and when data is distributed between applications. The overall QoS of the DCPS system is made up of the individual QosPolicies for each DCPS
Entity. There are QosPolicies for Topics, DataWriters, Publishers, DataReaders, Subscribers, and DomainParticipants.
On the publishing side, the QoS of each Topic, the Topic’s DataWriter, and the DataWriter’s Pub- lisher all play a part in controlling how and when data samples are sent to the middleware. Sim- ilarly, the QoS of the Topic, the Topic’s DataReader, and the DataReader’s Subscriber control behavior on the subscribing side.
Users will employ QosPolicies to control a variety of behaviors. For example, the DEADLINE policy sets up expectations of how often a DataReader expects to see samples. The OWNERSHIP and OWNERSHIP_STRENGTH policy are used together to configure and arbitrate whose data is passed to the DataReader when there are multiple DataWriters for the same instance of a Topic. The HISTORY policy specifies whether a DataWriter should save old data to send to new sub- scriptions that join the network later. Many other policies exist and they are presented in QosPolicies (Section 4.2).
Some QosPolicies represent “contracts” between publications and subscriptions. For communi- cations to take place properly, the QosPolicies set on the DataWriter side must be compatible with corresponding policies set on the DataReader side.
For example, the RELIABILITY policy is set by the DataWriter to state whether it is configured to send data reliably to DataReaders. Because it takes additional resources to send data reliably, some DataWriters may only support a
To address this issue, and yet keep the publications and subscriptions as decoupled as possible, DCPS provides a way to detect and notify when QosPolicies set by DataWriters and DataReaders are incompatible. DCPS employs a pattern known as RxO (Requested versus Offered). The DataReader sets a “requested” value for a particular QosPolicy. The DataWriter sets an “offered” value for that QosPolicy. When Connext matches a DataReader to a DataWriter, QosPolicies are checked to make sure that all requested values can be supported by the offered values.
Application Discovery
Note that not all QosPolicies are constrained by the RxO pattern. For example, it does not make sense to compare policies that affect only the DataWriter but not the DataReader or vice versa.
If the DataWriter can not satisfy the requested QosPolicies of a DataReader, Connext will not con- nect the two entities and will notify the applications on each side of the incompatibility if so con- figured.
For example, a DataReader sets its DEADLINE QoS to 4
In one application, the DataWriter sets its DEADLINE QoS to 2
In another application, the DataWriter sets its DEADLINE QoS to 5 seconds. It only commits to sending data at 5 second intervals. This will not satisfy the request of the DataReader. Connext will flag this incompatibility by calling
For a summary of the QosPolicies supported by Connext, see QosPolicies (Section 4.2).
2.6Application Discovery
The DCPS model provides anonymous, transparent,
So how is this all done? Ultimately, in each application for each publication, Connext must keep a list of applications that have subscribed to the same Topic, nodes on which they are located, and some additional QoS parameters that control how the data is sent. Also, Connext must keep a list of applications and publications for each of the Topics to which the application has subscribed.
This propagation of this information (the existence of publications and subscriptions and associ- ated QoS) between applications by Connext is known as the discovery process. While the DDS (DCPS) standard does not specify how discovery occurs, Connext uses a standard protocol RTPS for both discovery and formatting
When a DomainParticipant is created, Connext sends out packets on the network to announce its existence. When an application finds out that another application belongs to the same domain, then it will exchange information about its existing publications and subscriptions and associ- ated QoS with the other application. As new DataWriters and DataReaders are created, this infor- mation is sent to known applications.
The Discovery process is entirely configurable by the user and is discussed extensively in Chapter 14: Discovery.
Part 2: Core Concepts
This section includes the following chapters:
❏Chapter 3: Data Types and Data Samples
Chapter 3 Data Types and Data Samples
How data is stored or laid out in memory can vary from language to language, compiler to com- piler, operating system to operating system, and processor to processor. This combination of lan- guage/compiler/operating system/processor is called a platform. Any modern middleware must be able to take data from one specific platform (say C/gcc.3.2.2/Solaris/Sparc) and trans- parently deliver it to another (for example, Java/JDK 1.6/Windows XP/Pentium). This process is commonly called serialization/deserialization, or marshalling/demarshalling.
Messaging products have typically taken one of two approaches to this problem:
1.Do nothing. Messages consist only of opaque streams of bytes. The JMS BytesMessage is an example of this approach.
2.Send everything, every time.
The “do nothing” approach is lightweight on its surface but forces you, the user of the middle- ware API, to consider all data encoding, alignment, and padding issues. The “send everything” alternative results in large amounts of redundant information being sent with every packet, impacting performance.
Connext takes an intermediate approach. Just as objects in your application program belong to some data type, data samples sent on the same Connext topic share a data type. This type defines the fields that exist in the data samples and what their constituent types are. The middleware stores and propagates this
To publish and/or subscribe to data with Connext, you will carry out the following steps:
1.Select a type to describe your data.
You have a number of choices. You can choose one of these options, or you can mix and match them.
•Use a
This option may be sufficient if your data typing needs are very simple. If your data is highly structured, or you need to be able to examine fields within that data for filter- ing or other purposes, this option may not be appropriate. The
•Use the RTI code generator, rtiddsgen, to define a type at
Code generation offers two strong benefits not available with dynamic type defini- tion: (1) it allows you to share type definitions across programming languages, and (2) because the structure of the type is known at compile time, it provides rigorous static type safety.
The code generator accepts input in a number of formats to make it easy to integrate Connext with your development processes and IT infrastructure:
•OMG IDL. This format is a standard component of both the DDS and CORBA specifications. It describes data types with a
•XML schema (XSD), either independent or embedded in a WSDL file. XSD should be the format of choice for those using Connext alongside or connected to a web- services infrastructure. This format is described in Creating User Data Types with XML Schemas (XSD) (Section 3.5).
•XML in a
•Define a type programmatically at run time.
This method may be appropriate for applications with dynamic data description needs: applications for which types change frequently or cannot be known ahead of time. It is described in Defining New Types (Section 3.8.2).
2.Register your type with a logical name.
If you've chosen to use a
This step is described in the Defining New Types (Section 3.8.2).
3.Create a Topic using the type name you previously registered.
If you've chosen to use a
Creating and working with Topics is discussed in Chapter 5: Topics.
4.Create one or more DataWriters to publish your data and one or more DataReaders to sub- scribe to it.
The concrete types of these objects depend on the concrete data type you've selected, in order to provide you with a measure of type safety.
Creating and working with DataWriters and DataReaders are described in Chapter 6: Sending Data and Chapter 7: Receiving Data, respectively.
Whether publishing or subscribing to data, you will need to know how to create and delete data samples and how to get and set their fields. These tasks are described in Working with Data Samples (Section 3.9).
This chapter describes:
❏Introduction to the Type System (Section 3.1 on Page
❏
❏Creating User Data Types with IDL (Section 3.3 on Page
❏Creating User Data Types with Extensible Markup Language (XML) (Section 3.4 on Page
Introduction to the Type System
❏Creating User Data Types with XML Schemas (XSD) (Section 3.5 on Page
❏Using rtiddsgen (Section 3.6 on Page
❏Using Generated Types without Connext (Standalone) (Section 3.7 on Page
❏Interacting Dynamically with User Data Types (Section 3.8 on Page
❏Working with Data Samples (Section 3.9 on Page
3.1Introduction to the Type System
A user data type is any custom type that your application defines for use with Connext. It may be a structure, a union, a value type, an enumeration, or a typedef (or language equivalents).
Your application can have any number of user data types. They can be composed of any of the primitive data types listed below or of other user data types.
Only structures, unions, and value types may be read and written directly by Connext; enums, typedefs, and primitive types must be contained within a structure, union, or value type. In order for a DataReader and DataWriter to communicate with each other, the data types associated with their respective Topic definitions must be identical.
❏octet, char, wchar
❏short, unsigned short
❏long, unsigned long
❏long long, unsigned long long
❏float
❏double, long double
❏boolean
❏enum (with or without explicit values)
❏bounded and unbounded string and wstring
The following
❏module (also called a package or namespace)
❏pointer
❏array of primitive or user type elements
❏bounded/unbounded sequence of
❏typedef
❏bitfield2
❏union
❏struct
❏value type, a complex type that supports inheritance and other
1.Sequences of sequences are not supported directly. To work around this constraint, typedef the inner sequence and form a sequence of that new type.
2.Data types containing bitfield members are not supported by DynamicData.
Introduction to the Type System
To use a data type with Connext, you must define that type in a way the middleware under- stands and then register the type with the middleware. These steps allow Connext to serialize, deserialize, and otherwise operate on specific types. They will be described in detail in the fol- lowing sections.
3.1.1Sequences
A sequence contains an ordered collection of elements that are all of the same type. The opera- tions supported in the sequence are documented in the API Reference HTML documentation, which is available for all supported programming languages (select Modules, DDS API Refer- ence, Infrastructure Module, Sequence Support).
Java sequences implement the java.util.List interface from the standard Collections framework.
C++ users will find sequences conceptually similar to the deque class in the Standard Template Library (STL).
Elements in a sequence are accessed with their index, just like elements in an array. Indices start from zero. Unlike arrays, however, sequences can grow in size. A sequence has two sizes associ- ated with it: a physical size (the "maximum") and a logical size (the "length"). The physical size indicates how many elements are currently allocated by the sequence to hold; the logical size indicates how many valid elements the sequence actually holds. The length can vary from zero up to the maximum. Elements cannot be accessed at indices beyond the current length.
A sequence may be declared as bounded or unbounded. A sequence's "bound" is the maximum number of elements tha tthe sequence can contain at any one time. The bound is very important because it allows Connext to preallocate buffers to hold serialized and deserialized samples of your types; these buffers are used when communicating with other nodes in your distributed system. If a sequence had no bound, Connext would not know how large to allocate its buffers and would therefore have to allocate them on the fly as individual samples were read and writ-
3.1.2Strings and Wide Strings
Connext supports both strings consisting of
Like sequences, strings may be bounded or unbounded. A string's "bound" is its maximum length (not counting the trailing NULL character in C and C++).
3.1.3Introduction to TypeCode
Type
enum TCKind { TK_NULL, TK_SHORT, TK_LONG, TK_USHORT, TK_ULONG,
TK_FLOAT,
TK_DOUBLE,
TK_BOOLEAN, TK_CHAR, TK_OCTET, TK_STRUCT, TK_UNION, TK_ENUM, TK_STRING, TK_SEQUENCE, TK_ARRAY, TK_ALIAS, TK_LONGLONG, TK_ULONGLONG, TK_LONGDOUBLE, TK_WCHAR, TK_WSTRING, TK_VALUE, TK_SPARSE
}
Type codes unambiguously match type representations and provide a more reliable test than comparing the string type names.
The TypeCode class, modeled after the corresponding CORBA API, provides access to type- code information. For details on the available operations for the TypeCode class, see the API Reference HTML documentation, which is available for all supported programming languages (select Modules, DDS API Reference, Topic Module, Type Code Support).
3.1.3.1Sending TypeCodes on the Network
In addition to being used locally, serialized type codes are typically published automatically during discovery as part of the
Note: Type codes are not cached by Connext upon receipt and are therefore not available from the
DataReader's get_matched_publication_data() operation.
If your data type has an especially complex type code, you may need to increase the value of the type_code_max_serialized_length field in the DomainParticipant's
DOMAIN_PARTICIPANT_RESOURCE_LIMITS QosPolicy (DDS Extension) (Section 8.5.4). Or, to prevent the propagation of type codes altogether, you can set this value to zero (0). Be aware that some features of monitoring tools, as well as some features of the middleware itself (such as ContentFilteredTopics) will not work correctly if you disable TypeCode propagation.
3.2
Connext provides a set of standard types that are built into the middleware. These types can be used immediately; they do not require writing IDL, invoking the rtiddsgen utility (see Section 3.6), or using the dynamic type API (see Section 3.2.8).
The supported
The
❏Registering
❏Creating Topics for
❏Creating ContentFilteredTopics for
❏String
❏KeyedString
❏Octets
❏KeyedOctets
❏Type Codes for
3.2.1Registering
By default, the
3.2.2Creating Topics for
To create a topic for a
Note: In the following examples, you will see the sentinel "<BuiltinType>."
For C and C++: <BuiltinType> = String, KeyedString, Octets or KeyedOctets For Java and .NET1: <BuiltinType> = String, KeyedString, Bytes or KeyedBytes
C API:
const char* DDS_<BuiltinType>TypeSupport_get_type_name();
C++ API with namespace:
const char* DDS::<BuiltinType>TypeSupport::get_type_name();
C++ API without namespace:
const char* DDS<BuiltinType>TypeSupport::get_type_name();
C++/CLI API:
System::String^ DDS:<BuiltinType>TypeSupport::get_type_name();
C# API:
System.String DDS.<BuiltinType>TypeSupport.get_type_name();
1. RTI Connext .NET language binding is currently supported for C# and C++/CLI.
Java API:
String com.rti.dds.type.builtin.<BuiltinType>TypeSupport.get_type_name();
3.2.2.1Topic Creation Examples
For simplicity, error handling is not shown in the following examples.
C Example:
DDS_Topic * topic = NULL;
/* Create a builtin type Topic */
topic = DDS_DomainParticipant_create_topic( participant, "StringTopic",
DDS_StringTypeSupport_get_type_name(), &DDS_TOPIC_QOS_DEFAULT, NULL, DDS_STATUS_MASK_NONE);
C++ Example with Namespaces:
using namespace DDS;
...
/* Create a String builtin type Topic */ Topic * topic =
"StringTopic", StringTypeSupport::get_type_name(),
DDS_TOPIC_QOS_DEFAULT, NULL, DDS_STATUS_MASK_NONE);
C++/CLI Example:
using namespace DDS;
...
/* Create a builtin type Topic */
Topic^ topic =
"StringTopic", StringTypeSupport::get_type_name(), DomainParticipant::TOPIC_QOS_DEFAULT,
nullptr, StatusMask::STATUS_MASK_NONE);
C# Example:
using namespace DDS;
...
/* Create a builtin type Topic */
Topic topic = participant.create_topic(
"StringTopic", StringTypeSupport.get_type_name(), DomainParticipant.TOPIC_QOS_DEFAULT,
null, StatusMask.STATUS_MASK_NONE);
Java Example:
import com.rti.dds.type.builtin.*;
...
/* Create a builtin type Topic */
Topic topic = participant.create_topic(
"StringTopic", StringTypeSupport.get_type_name(), DomainParticipant.TOPIC_QOS_DEFAULT,
null, StatusKind.STATUS_MASK_NONE);
3.2.3Creating ContentFilteredTopics for
To create a ContentFilteredTopic for a
The field names used in the filter expressions for the
3.2.3.1ContentFilteredTopic Creation Examples
For simplicity, error handling is not shown in the following examples.
C Example:
DDS_Topic * topic = NULL;
DDS_ContentFilteredTopic * contentFilteredTopic = NULL; struct DDS_StringSeq parameters = DDS_SEQUENCE_INITIALIZER;
/* Create a string ContentFilteredTopic */ topic = DDS_DomainParticipant_create_topic(
participant, "StringTopic", DDS_StringTypeSupport_get_type_name(), &DDS_TOPIC_QOS_DEFAULT,NULL, DDS_STATUS_MASK_NONE);
contentFilteredTopic = DDS_DomainParticipant_create_contentfilteredtopic( participant, "StringContentFilteredTopic",
topic, "value = 'Hello World!'", ¶meters);
C++ Example with Namespaces:
using namespace DDS;
...
/* Create a String ContentFilteredTopic */ Topic * topic =
"StringTopic", StringTypeSupport::get_type_name(), TOPIC_QOS_DEFAULT, NULL, STATUS_MASK_NONE);
StringSeq parameters;
ContentFilteredTopic * contentFilteredTopic =
"StringContentFilteredTopic", topic, "value = 'Hello World!'", parameters);
C++/CLI Example:
using namespace DDS;
...
/* Create a String ContentFilteredTopic */ Topic^ topic =
"StringTopic", StringTypeSupport::get_type_name(), DomainParticipant::TOPIC_QOS_DEFAULT,
nullptr, StatusMask::STATUS_MASK_NONE);
StringSeq^ parameters = gcnew StringSeq();
ContentFilteredTopic^ contentFilteredTopic =
"StringContentFilteredTopic", topic, "value = 'Hello World!'", parameters);
C# Example:
using namespace DDS;
...
/* Create a String ContentFilteredTopic */ Topic topic = participant.create_topic(
"StringTopic", StringTypeSupport.get_type_name(), DomainParticipant.TOPIC_QOS_DEFAULT,
null, StatusMask.STATUS_MASK_NONE);
StringSeq parameters = new StringSeq();
ContentFilteredTopic contentFilteredTopic = participant.create_contentfilteredtopic(
"StringContentFilteredTopic", topic, "value = 'Hello World!'", parameters);
Java Example:
import com.rti.dds.type.builtin.*;
...
/* Create a String ContentFilteredTopic */ Topic topic = participant.create_topic(
"StringTopic", StringTypeSupport.get_type_name(), DomainParticipant.TOPIC_QOS_DEFAULT,
null, StatusKind.STATUS_MASK_NONE);
StringSeq parameters = new StringSeq();
ContentFilteredTopic contentFilteredTopic = participant.create_contentfilteredtopic(
"StringContentFilteredTopic", topic, "value = 'Hello World!'", parameters);
3.2.4String
The String
3.2.4.1Creating and Deleting Strings
In C and C++, Connext provides a set of operations to create (DDS::String_alloc()), destroy (DDS::String_free()), and clone strings (DDS::String_dup()). Select Modules, DDS API Refer- ence, Infrastructure Module, String support in the API Reference HTML documentation, which is available for all supported programming languages.
1. RTI Connext .NET language binding is currently supported for C# and C++/CLI.
Memory Considerations in Copy Operations:
When the read/take operations that take a sequence of strings as a parameter are used in copy mode, Connext allocates the memory for the string elements in the sequence if they are initialized to NULL.
If the elements are not initialized to NULL, the behavior depends on the language:
•In Java and .NET, the memory associated with the elements is reallocated with every sample, because strings are immutable objects.
•In C and C++, the memory associated with the elements must be large enough to hold the received data. Insufficient memory may result in crashes.
When take_next_sample() and read_next_sample() are called in C and C++, you must make sure that the input string has enough memory to hold the received data. Insuffi- cient memory may result in crashes.
3.2.4.2String DataWriter
The string DataWriter API matches the standard DataWriter API (see Using a
The following examples show how to write simple strings with a string
C Example:
DDS_StringDataWriter * stringWriter = ... ; DDS_ReturnCode_t retCode;
char * str = NULL;
/* Write some data */
retCode = DDS_StringDataWriter_write(
stringWriter, "Hello World!", &DDS_HANDLE_NIL);
str = DDS_String_dup("Hello World!");
retCode = DDS_StringDataWriter_write(stringWriter, str, &DDS_HANDLE_NIL); DDS_String_free(str);
C++ Example with Namespaces:
#include "ndds/ndds_namespace_cpp.h" using namespace DDS;
...
StringDataWriter * stringWriter = ... ;
/* Write some data */
ReturnCode_t retCode =
retCode =
DDS::String_free(str);
C++/CLI Example:
using namespace System; using namespace DDS;
...
StringDataWriter^ stringWriter = ... ;
/* Write some data */
C# Example:
using System; using DDS;
...
StringDataWriter stringWriter = ... ;
/* Write some data */
stringWriter.write("Hello World!", InstanceHandle_t.HANDLE_NIL); String str = "Hello World!";
stringWriter.write(str, InstanceHandle_t.HANDLE_NIL);
Java Example:
import com.rti.dds.publication.*; import com.rti.dds.type.builtin.*; import com.rti.dds.infrastructure.*;
...
StringDataWriter stringWriter = ... ;
/* Write some data */
stringWriter.write("Hello World!", InstanceHandle_t.HANDLE_NIL); String str = "Hello World!";
stringWriter.write(str, InstanceHandle_t.HANDLE_NIL);
3.2.4.3String DataReader
The string DataReader API matches the standard DataReader API (see Using a
The following examples show how to read simple strings with a string
C Example:
struct DDS_StringSeq dataSeq = DDS_SEQUENCE_INITIALIZER; struct DDS_SampleInfoSeq infoSeq = DDS_SEQUENCE_INITIALIZER; DDS_StringDataReader * stringReader = ... ; DDS_ReturnCode_t retCode;
int i;
/* Take and print the data */
retCode = DDS_StringDataReader_take(stringReader, &dataSeq, &infoSeq, DDS_LENGTH_UNLIMITED, DDS_ANY_SAMPLE_STATE, DDS_ANY_VIEW_STATE, DDS_ANY_INSTANCE_STATE);
for (i = 0; i < DDS_StringSeq_get_length(&data_seq); ++i) {
if (DDS_SampleInfoSeq_get_reference(&info_seq,
DDS_StringSeq_get(&data_seq, i));
}
}
/* Return loan */
retCode = DDS_StringDataReader_return_loan(stringReader, &data_seq, &info_seq);
C++ Example with Namespaces:
#include "ndds/ndds_namespace_cpp.h" using namespace DDS;
...
StringSeq dataSeq;
SampleInfoSeq infoSeq;
StringDataReader * stringReader = ... ;
/* Take a print the data */
ReturnCode_t retCode =
for (int i = 0; i < data_seq.length(); ++i) { if (infoSeq[i].valid_data) {
StringTypeSupport::print_data(dataSeq[i]);
}
}
/* Return loan */
retCode =
C++/CLI Example:
using namespace System; using namespace DDS;
...
StringSeq^ dataSeq = gcnew StringSeq();
SampleInfoSeq^ infoSeq = gcnew SampleInfoSeq();
StringDataReader^ stringReader = ... ;
/* Take and print the data */
ResourceLimitsQosPolicy::LENGTH_UNLIMITED, SampleStateKind::ANY_SAMPLE_STATE, ViewStateKind::ANY_VIEW_STATE, InstanceStateKind::ANY_INSTANCE_STATE);
for (int i = 0; i < data_seq.length(); ++i) { if
}
}
/* Return loan */
C# Example:
using System; using DDS;
...
StringSeq dataSeq = new StringSeq();
SampleInfoSeq infoSeq = new SampleInfoSeq();
StringDataReader stringReader = ... ;
/* Take and print the data */
stringReader.take(dataSeq, infoSeq, ResourceLimitsQosPolicy.LENGTH_UNLIMITED, SampleStateKind.ANY_SAMPLE_STATE, ViewStateKind.ANY_VIEW_STATE, InstanceStateKind.ANY_INSTANCE_STATE);
for (int i = 0; i < data_seq.length(); ++i) { if (infoSeq.get_at(i)).valid_data) {
StringTypeSupport.print_data(dataSeq.get_at(i));
}
}
}
}
Java Example:
import com.rti.dds.infrastructure.*; import com.rti.dds.subscription.*; import com.rti.dds.type.builtin.*;
...
StringSeq dataSeq = new StringSeq();
SampleInfoSeq infoSeq = new SampleInfoSeq();
StringDataReader stringReader = ... ;
/* Take and print the data */ stringReader.take(dataSeq, infoSeq,
ResourceLimitsQosPolicy.LENGTH_UNLIMITED, SampleStateKind.ANY_SAMPLE_STATE, ViewStateKind.ANY_VIEW_STATE, InstanceStateKind.ANY_INSTANCE_STATE);
for (int i = 0; i < data_seq.length(); ++i) {
if (((SampleInfo)infoSeq.get(i)).valid_data) { System.out.println((String)dataSeq.get(i));
}
}
/* Return loan */ stringReader.return_loan(dataSeq, infoSeq);
3.2.5KeyedString
The Keyed String
C/C++ Representation (without namespaces):
struct DDS_KeyedString { char * key;
char * value;
};
C++/CLI Representation:
namespace DDS {
public ref struct KeyedString: { public:
System::String^ key; System::String^ value;
...
};
};
C# Representation:
namespace DDS {
public class KeyedString { public System.String key; public System.String value;
};
};
Java Representation:
namespace DDS {
public class KeyedString { public System.String key; public System.String value;
};
};
3.2.5.1Creating and Deleting Keyed Strings
Connext provides a set of constructors/destructors to create/destroy Keyed Strings. For details, see the API Reference HTML documentation, which is available for all supported programming languages (select Modules, DDS API Reference, Topic Module,
If you want to manipulate the memory of the fields 'value' and 'key' in the KeyedString struct in C/C++, use the operations DDS::String_alloc(), DDS::String_dup(), and DDS::String_free(), as described in the API Reference HTML documentation (select Modules, DDS API Reference, Infrastructure Module, String Support).
3.2.5.2Keyed String DataWriter
The keyed string DataWriter API is extended with the following methods (in addition to the standard methods described in Using a
DDS::ReturnCode_t DDS::KeyedStringDataWriter::dispose( const char* key,
const DDS::InstanceHandle_t* instance_handle);
DDS::ReturnCode_t DDS::KeyedStringDataWriter::dispose_w_timestamp( const char* key,
const DDS::InstanceHandle_t* instance_handle, const struct DDS::Time_t* source_timestamp);
DDS::ReturnCode_t DDS::KeyedStringDataWriter::get_key_value( char * key,
const DDS::InstanceHandle_t* handle);
DDS::InstanceHandle_t DDS::KeyedStringDataWriter::lookup_instance(
const char * key);
DDS::InstanceHandle_t DDS::KeyedStringDataWriter::register_instance(
const char* key);
DDS::InstanceHandle_t
DDS_KeyedStringDataWriter::register_instance_w_timestamp(
const char * key,
const struct DDS_Time_t* source_timestamp);
DDS::ReturnCode_t DDS::KeyedStringDataWriter::unregister_instance( const char * key,
const DDS::InstanceHandle_t* handle);
DDS::ReturnCode_t DDS::KeyedStringDataWriter::unregister_instance_w_timestamp(
const char* key,
const DDS::InstanceHandle_t* handle,
const struct DDS::Time_t* source_timestamp);
DDS::ReturnCode_t DDS::KeyedStringDataWriter::write ( const char * key,
const char * str,
const DDS::InstanceHandle_t* handle);
DDS::ReturnCode_t DDS::KeyedStringDataWriter::write_w_timestamp( const char * key,
const char * str,
const DDS::InstanceHandle_t* handle,
const struct DDS::Time_t* source_timestamp);
These operations are introduced to provide maximum flexibility in the format of the input parameters for the write and instance management operations. For additional information and a complete description of the operations, see the API Reference HTML documentation, which is available for all supported programming languages.
The following examples show how to write keyed strings using a keyed string
C Example:
DDS_KeyedStringDataWriter * stringWriter = ... ; DDS_ReturnCode_t retCode;
struct DDS_KeyedString * keyedStr = NULL; char * str = NULL;
/* Write some data using the KeyedString structure */ keyedStr = DDS_KeyedString_new(255, 255);
retCode = DDS_KeyedStringDataWriter_write_string_w_key( stringWriter, keyedStr, &DDS_HANDLE_NIL);
DDS_KeyedString_delete(keyedStr);
/* Write some data using individual strings */
retCode = DDS_KeyedStringDataWriter_write_string_w_key( stringWriter, "Key 1",
"Value 1", &DDS_HANDLE_NIL);
str = DDS_String_dup("Value 2");
retCode = DDS_KeyedStringDataWriter_write_string_w_key( stringWriter, "Key 1", str, &DDS_HANDLE_NIL);
DDS_String_free(str);
C++ Example with Namespaces:
#include "ndds/ndds_namespace_cpp.h" using namespace DDS;
...
KeyedStringDataWriter * stringWriter = ... ;
/* Write some data using the KeyedString */ KeyedString * keyedStr = new KeyedString(255, 255);
ReturnCode_t retCode =
delete keyedStr;
#include "ndds/ndds_namespace_cpp.h" using namespace DDS;
...
KeyedStringDataWriter * stringWriter = ... ;
/* Write some data using the KeyedString */ KeyedString * keyedStr = new KeyedString(255, 255);
ReturnCode_t retCode =
delete keyedStr;
C++/CLI Example:
using namespace System; using namespace DDS;
...
KeyedStringDataWriter^ stringWriter = ... ;
/* Write some data using the KeyedString */ KeyedString^ keyedStr = gcnew KeyedString();
/* Write some data using individual strings */
String^ str = "Value 2";
C# Example
using System; using DDS;
...
KeyedStringDataWriter stringWriter = ... ;
/* Write some data using the KeyedString */ KeyedString keyedStr = new KeyedString(); keyedStr.key = "Key 1";
keyedStr.value = "Value 1";
stringWriter.write(keyedStr, InstanceHandle_t.HANDLE_NIL);
/* Write some data using individual strings */ stringWriter.write("Key 1", "Value 1", InstanceHandle_t.HANDLE_NIL);
String str = "Value 2";
stringWriter.write("Key 1", str, InstanceHandle_t.HANDLE_NIL);
Java Example :
import com.rti.dds.publication.*; import com.rti.dds.type.builtin.*; import com.rti.dds.infrastructure.*;
...
KeyedStringDataWriter stringWriter = ... ;
/* Write some data using the KeyedString */ KeyedString keyedStr = new KeyedString(); keyedStr.key = "Key 1";
keyedStr.value = "Value 1";
stringWriter.write(keyedStr, InstanceHandle_t.HANDLE_NIL);
/* Write some data using individual strings */ stringWriter.write("Key 1", "Value 1", InstanceHandle_t.HANDLE_NIL);
String str = "Value 2";
stringWriter.write("Key 1", str, InstanceHandle_t.HANDLE_NIL);
3.2.5.3Keyed String DataReader
The KeyedString DataReader API is extended with the following operations (in addition to the standard methods described in Using a
DDS::ReturnCode_t DDS::KeyedStringDataReader::get_key_value(
char * key, const DDS::InstanceHandle_t* handle);
DDS::InstanceHandle_t DDS::KeyedStringDataReader::lookup_instance(
const char * key);
For additional information and a complete description of these operations in all supported lan- guages, see the API Reference HTML documentation, which is available for all supported pro- gramming languages.
Memory considerations in copy operations:
For read/take operations with copy semantics, such as read_next_sample() and take_next_sample(), Connext allocates memory for the fields 'value' and 'key' if they are initialized to NULL.
If the fields are not initialized to NULL, the behavior depends on the language:
•In Java and .NET, the memory associated to the fields 'value' and 'key' will be reallo- cated with every sample.
•In C and C++, the memory associated with the fields 'value' and 'key' must be large enough to hold the received data. Insufficient memory may result in crashes.
The following examples show how to read keyed strings with a keyed string
C Example:
struct DDS_KeyedStringSeq dataSeq = DDS_SEQUENCE_INITIALIZER; struct DDS_SampleInfoSeq infoSeq = DDS_SEQUENCE_INITIALIZER; DDS_KeyedKeyedStringDataReader * stringReader = ... ; DDS_ReturnCode_t retCode;
int i;
/* Take and print the data */
retCode = DDS_KeyedStringDataReader_take(stringReader, &dataSeq, &infoSeq, DDS_LENGTH_UNLIMITED, DDS_ANY_SAMPLE_STATE, DDS_ANY_VIEW_STATE, DDS_ANY_INSTANCE_STATE);
for (i = 0; i < DDS_KeyedStringSeq_get_length(&data_seq); ++i) {
if (DDS_SampleInfoSeq_get_reference(&info_seq,
DDS_KeyedStringSeq_get_reference(&data_seq, i));
}
}
/* Return loan */
retCode = DDS_KeyedStringDataReader_return_loan(
stringReader, &data_seq, &info_seq);
C++ Example with Namespaces:
#include "ndds/ndds_namespace_cpp.h" using namespace DDS;
...
KeyedStringSeq dataSeq;
SampleInfoSeq infoSeq;
KeyedStringDataReader * stringReader = ... ;
/* Take a print the data */
ReturnCode_t retCode =
for (int i = 0; i < data_seq.length(); ++i) { if (infoSeq[i].valid_data) {
KeyedStringTypeSupport::print_data(&dataSeq[i]);
}
}
/* Return loan */
retCode =
C++/CLI Example:
using namespace System; using namespace DDS;
...
KeyedStringSeq^ dataSeq = gcnew KeyedStringSeq();
SampleInfoSeq^ infoSeq = gcnew SampleInfoSeq();
KeyedStringDataReader^ stringReader = ... ;
/* Take and print the data */
ResourceLimitsQosPolicy::LENGTH_UNLIMITED, SampleStateKind::ANY_SAMPLE_STATE, ViewStateKind::ANY_VIEW_STATE, InstanceStateKind::ANY_INSTANCE_STATE);
for (int i = 0; i < data_seq.length(); ++i) { if
}
}
/* Return loan */
C# Example:
using System; using DDS;
...
KeyedStringSeq dataSeq = new KeyedStringSeq();
SampleInfoSeq infoSeq = new SampleInfoSeq();
KeyedStringDataReader stringReader = ... ;
/* Take and print the data */ stringReader.take(dataSeq, infoSeq,
ResourceLimitsQosPolicy.LENGTH_UNLIMITED, SampleStateKind.ANY_SAMPLE_STATE, ViewStateKind.ANY_VIEW_STATE, InstanceStateKind.ANY_INSTANCE_STATE);
for (int i = 0; i < data_seq.length(); ++i) { if (infoSeq.get_at(i)).valid_data) {
KeyedStringTypeSupport.print_data(dataSeq.get_at(i));
}
}
/* Return loan */ stringReader.return_loan(dataSeq, infoSeq);
Java Example:
import com.rti.dds.infrastructure.*; import com.rti.dds.subscription.*; import com.rti.dds.type.builtin.*;
...
KeyedStringSeq dataSeq = new KeyedStringSeq();
SampleInfoSeq infoSeq = new SampleInfoSeq();
KeyedStringDataReader stringReader = ... ;
/* Take and print the data */ stringReader.take(dataSeq, infoSeq,
ResourceLimitsQosPolicy.LENGTH_UNLIMITED, SampleStateKind.ANY_SAMPLE_STATE, ViewStateKind.ANY_VIEW_STATE, InstanceStateKind.ANY_INSTANCE_STATE);
for (int i = 0; i < data_seq.length(); ++i) {
if (((SampleInfo)infoSeq.get(i)).valid_data) { System.out.println((
(KeyedString)dataSeq.get(i)).toString());
}
}
/* Return loan */ stringReader.return_loan(dataSeq, infoSeq);
3.2.6Octets
The octets
C/C++ Representation (without Namespaces):
struct DDS_Octets { int length;
unsigned char * value;
};
C++/CLI Representation:
namespace DDS {
public ref struct Bytes: { public:
System::Int32 length; System::Int32 offset; array<System::Byte>^ value;
...
};
};
C# Representation:
namespace DDS {
public class Bytes {
public System.Int32 length; public System.Int32 offset; public System.Byte[] value;
...
};
};
Java Representation:
package com.rti.dds.type.builtin;
public class Bytes implements Copyable { public int length;
public int offset; public byte[] value;
...
};
3.2.6.1Creating and Deleting Octets
Connext provides a set of constructors/destructors to create and destroy Octet objects. For details, see the API Reference HTML documentation, which is available for all supported pro- gramming languages (select Modules, DDS API Reference, Topic Module,
If you want to manipulate the memory of the value field inside the Octets struct in C/C++, use the operations DDS::OctetBuffer_alloc(), DDS::OctetBuffer_dup(), and
DDS::OctetBuffer_free(), described in the API Reference HTML documentation (select Mod- ules, DDS API Reference, Infrastructure Module, Octet Buffer Support).
3.2.6.2Octets DataWriter
In addition to the standard methods (see Using a
DDS::ReturnCode_t DDS::OctetsDataWriter::write(
const DDS::OctetSeq & octets,
const DDS::InstanceHandle_t & handle);
DDS::ReturnCode_t DDS::OctetsDataWriter::write(
const unsigned char * octets, int length,
const DDS::InstanceHandle_t& handle);
DDS::ReturnCode_t DDS::OctetsDataWriter::write_w_timestamp( const DDS::OctetSeq & octets,
const DDS::InstanceHandle_t & handle, const DDS::Time_t & source_timestamp);
DDS::ReturnCode_t DDS::OctetsDataWriter::write_w_timestamp( const unsigned char * octets, int length,
const DDS::InstanceHandle_t& handle, const DDS::Time_t& source_timestamp);
These methods are introduced to provide maximum flexibility in the format of the input param- eters for the write operations. For additional information and a complete description of these operations in all supported languages, see the API Reference HTML documentation.
The following examples show how to write an array of octets using an octets
C Example:
DDS_OctetsDataWriter * octetsWriter = ... ; DDS_ReturnCode_t retCode;
struct DDS_Octets * octets = NULL; char * octetArray = NULL;
/* Write some data using the Octets structure */ octets = DDS_Octets_new_w_size(1024);
retCode = DDS_OctetsDataWriter_write(octetsWriter, octets, &DDS_HANDLE_NIL); DDS_Octets_delete(octets);
/* Write some data using an octets array */ octetArray = (unsigned char *)malloc(1024); octetArray[0] = 46;
octetArray[1] = 47;
retCode = DDS_OctetsDataWriter_write_octets (octetsWriter, octetArray, 2, &DDS_HANDLE_NIL);
free(octetArray);
C++ Example with Namespaces:
#include "ndds/ndds_namespace_cpp.h" using namespace DDS;
...
OctetsDataWriter * octetsWriter = ... ;
/* Write some data using the Octets structure */ Octets * octets = new Octets(1024);
ReturnCode_t retCode =
delete octets;
/* Write |
some |
data using an octet array */ |
unsigned |
char |
* octetArray = new unsigned char[1024]; |
octetArray[0] |
= 46; |
|
octetArray[1] |
= 47; |
retCode =
delete []octetArray;
C++/CLI Example:
using namespace System; using namespace DDS;
...
BytesDataWriter^ octetsWriter = ...;
/* Write some data using Bytes */ Bytes^ octets = gcnew Bytes(1024);
octets.offset = 0;
/* Write some data using individual strings */ array<Byte>^ octetAray = gcnew array<Byte>(1024); octetArray[0] = 46;
octetArray[1] = 47;
C# Example:
using System; using DDS;
...
BytesDataWriter stringWriter = ...;
/* Write some data using the Bytes */ Bytes octets = new Bytes(1024); octets.value[0] = 46;
octets.value[1] = 47; octets.length = 2; octets.offset = 0;
octetWriter.write(octets, InstanceHandle_t.HANDLE_NIL);
/* Write some data using individual strings */ byte[] octetArray = new byte[1024]; octetArray[0] = 46;
octetArray[1] = 47;
octetsWriter.write(octetArray, 0, 2, InstanceHandle_t.HANDLE_NIL);
Java Example:
import com.rti.dds.publication.*; import com.rti.dds.type.builtin.*; import com.rti.dds.infrastructure.*;
...
BytesDataWriter octetsWriter = ... ;
/* Write some data using the Bytes class*/ Bytes octets = new Bytes(1024); octets.length = 2;
octets.offset = 0; octets.value[0] = 46; octets.value[1] = 47;
octetsWriter.write(octets, InstanceHandle_t.HANDLE_NIL);
/* Write some data using a byte array */ byte[] octetArray = new byte[1024]; octetArray[0] = 46;
octetArray[1] = 47;
octetsWriter.write(octetArray, 0, 2, InstanceHandle_t.HANDLE_NIL);
3.2.6.3Octets DataReader
The octets DataReader API matches the standard DataReader API (see Using a
Memory considerations in copy operations:
For read/take operations with copy semantics, such as read_next_sample() and take_next_sample(), Connext allocates memory for the field 'value' if it is initialized to NULL.
If the field 'value' is not initialized to NULL, the behavior depends on the language:
•In Java and .NET, the memory for the field 'value' will be reallocated if the current size is not large enough to hold the received data.
•In C and C++, the memory associated with the field 'value' must be big enough to hold the received data. Insufficient memory may result in crashes.
The following examples show how to read octets with an octets
C Example:
struct DDS_OctetsSeq dataSeq = DDS_SEQUENCE_INITIALIZER; struct DDS_SampleInfoSeq infoSeq = DDS_SEQUENCE_INITIALIZER; DDS_OctetsDataReader * octetsReader = ... ;
DDS_ReturnCode_t retCode; int i;
/* Take and print the data */
retCode = DDS_OctetsDataReader_take(octetsReader, &dataSeq, &infoSeq, DDS_LENGTH_UNLIMITED, DDS_ANY_SAMPLE_STATE, DDS_ANY_VIEW_STATE, DDS_ANY_INSTANCE_STATE);
for (i = 0; i < DDS_OctetsSeq_get_length(&dataSeq); ++i) {
if (DDS_SampleInfoSeq_get_reference(&infoSeq,
DDS_OctetsSeq_get_reference(&dataSeq, i));
}
}
/* Return loan */
retCode = DDS_OctetsDataReader_return_loan(octetsReader, &dataSeq, &infoSeq);
C++ Example with Namespaces:
#include "ndds/ndds_namespace_cpp.h" using namespace DDS;
...
OctetsSeq dataSeq; SampleInfoSeq infoSeq;
OctetsDataReader * octetsReader = ... ;
/* Take a print the data */
ReturnCode_t retCode =
for (int i = 0; i < data_seq.length(); ++i) { if (infoSeq[i].valid_data) {
OctetsTypeSupport::print_data(&dataSeq[i]);
}
}
/* Return loan */
retCode =
C++/CLI Example:
using namespace System; using namespace DDS;
...
BytesSeq^ dataSeq = gcnew BytesSeq();
SampleInfoSeq^ infoSeq = gcnew SampleInfoSeq();
BytesDataReader^ octetsReader = ... ;
/* Take and print the data */
ResourceLimitsQosPolicy::LENGTH_UNLIMITED, SampleStateKind::ANY_SAMPLE_STATE, ViewStateKind::ANY_VIEW_STATE, InstanceStateKind::ANY_INSTANCE_STATE);
for (int i = 0; i < data_seq.length(); ++i) { if
}
}
/* Return loan */
C# Example:
using System; using DDS;
...
BytesSeq dataSeq = new BytesSeq(); SampleInfoSeq infoSeq = new SampleInfoSeq(); BytesDataReader octetsReader = ... ;
/* Take and print the data */ octetsReader.take(dataSeq, infoSeq,
ResourceLimitsQosPolicy.LENGTH_UNLIMITED, SampleStateKind.ANY_SAMPLE_STATE, ViewStateKind.ANY_VIEW_STATE, InstanceStateKind.ANY_INSTANCE_STATE);
for (int i = 0; i < data_seq.length(); ++i) { if (infoSeq.get_at(i)).valid_data) {
BytesTypeSupport.print_data(dataSeq.get_at(i));
}
}
/* Return loan */ octetsReader.return_loan(dataSeq, infoSeq);
Java Example:
import com.rti.dds.infrastructure.*; import com.rti.dds.subscription.*; import com.rti.dds.type.builtin.*;
...
BytesSeq dataSeq = new BytesSeq(); SampleInfoSeq infoSeq = new SampleInfoSeq(); BytesDataReader octetsReader = ... ;
/* Take and print the data */ octetsReader.take(dataSeq, infoSeq,
ResourceLimitsQosPolicy.LENGTH_UNLIMITED, SampleStateKind.ANY_SAMPLE_STATE, ViewStateKind.ANY_VIEW_STATE, InstanceStateKind.ANY_INSTANCE_STATE);
for (int i = 0; i < data_seq.length(); ++i) {
if (((SampleInfo)infoSeq.get(i)).valid_data) { System.out.println(((Bytes)dataSeq.get(i)).toString());
}
}
/* Return loan */ octetsReader.return_loan(dataSeq, infoSeq);
3.2.7KeyedOctets
The keyed octets
C/C++ Representation (without Namespaces):
struct DDS_KeyedOctets { char * key;
int length;
unsigned char * value;
};
C++/CLI Representation:
namespace DDS {
public ref struct KeyedBytes { public:
System::String^ key; System::Int32 length; System::Int32 offset; array<System::Byte>^ value;
...
};
};
C# Representation:
namespace DDS {
public class KeyedBytes { public System.String key; public System.Int32 length; public System.Int32 offset; public System.Byte[] value;
…
};
};
Java Representation:
package com.rti.dds.type.builtin; public class KeyedBytes {
public String key; public int length; public int offset; public byte[] value;
...
};
3.2.7.1Creating and Deleting KeyedOctets
Connext provides a set of constructors/destructors to create/destroy KeyedOctets objects. For details, see the API Reference HTML documentation, which is available for all supported pro- gramming languages (select Modules, DDS API Reference, Topic Module,
To manipulate the memory of the value field in the KeyedOctets struct in C/C++: use
DDS::OctetBuffer_alloc(), DDS::OctetBuffer_dup(), and DDS::OctetBuffer_free(). See the API Reference HTML documentation (select Modules, DDS API Reference, Infrastructure Module, Octet Buffer Support).
To manipulate the memory of the key field in the KeyedOctets struct in C/C++: use
DDS::String_alloc(), DDS::String_dup(), and DDS::String_free(). See the API Reference HTML documentation (select Modules, DDS API Reference, Infrastructure Module, String Support).
3.2.7.2Keyed Octets DataWriter
In addition to the standard methods (see Using a
DDS::ReturnCode_t DDS::KeyedOctetsDataWriter::dispose( const char* key,
const DDS::InstanceHandle_t & instance_handle);
DDS::ReturnCode_t DDS::KeyedOctetsDataWriter::dispose_w_timestamp( const char* key,
const DDS::InstanceHandle_t & instance_handle, const DDS::Time_t & source_timestamp);
DDS::ReturnCode_t DDS::KeyedOctetsDataWriter::get_key_value( char * key,
const DDS::InstanceHandle_t& handle);
DDS::InstanceHandle_t DDS::KeyedOctetsDataWriter::lookup_instance(
const char * key);
DDS::InstanceHandle_t DDS::KeyedOctetsDataWriter::register_instance(
const char* key);
DDS::InstanceHandle_t
DDS::KeyedOctetsDataWriter::register_instance_w_timestamp(
const char * key,
const DDS::Time_t & source_timestamp);
DDS::ReturnCode_t DDS::KeyedOctetsDataWriter::unregister_instance( const char * key,
const DDS::InstanceHandle_t & handle);
DDS::ReturnCode_t DDS::KeyedOctetsDataWriter::unregister_instance_w_timestamp(
const char* key,
const DDS::InstanceHandle_t & handle, const DDS::Time_t & source_timestamp);
DDS::ReturnCode_t DDS::KeyedOctetsDataWriter::write( const char * key,
const unsigned char * octets, int length,
const DDS::InstanceHandle_t& handle);
DDS::ReturnCode_t DDS::KeyedOctetsDataWriter::write( const char * key,
const DDS::OctetSeq & octets,
const DDS::InstanceHandle_t & handle);
DDS::ReturnCode_t DDS::KeyedOctetsDataWriter::write_w_timestamp( const char * key,
const unsigned char * octets, int length,
const DDS::InstanceHandle_t& handle, const DDS::Time_t& source_timestamp);
DDS::ReturnCode_t DDS::KeyedOctetsDataWriter::write_w_timestamp( const char * key,
const DDS::OctetSeq & octets,
const DDS::InstanceHandle_t & handle, const DDS::Time_t & source_timestamp);
These methods are introduced to provide maximum flexibility in the format of the input param- eters for the write and instance management operations. For more information and a complete description of these operations in all supported languages, see the API Reference HTML docu- mentation.
The following examples show how to write keyed octets using a keyed octets
C Example:
DDS_KeyedOctetsDataWriter * octetsWriter = ... ; DDS_ReturnCode_t retCode;
struct DDS_KeyedOctets * octets = NULL; char * octetArray = NULL;
/* Write some data using the KeyedOctets structure */ octets = DDS_KeyedOctets_new_w_size(128,1024);
retCode = DDS_KeyedOctetsDataWriter_write(
octetsWriter, octets, &DDS_HANDLE_NIL);
DDS_KeyedOctets_delete(octets);
/* Write some data using an octets array */ octetArray = (unsigned char *)malloc(1024); octetArray[0] = 46;
octetArray[1] = 47;
retCode = DDS_KeyedOctetsDataWriter_write_octets_w_key ( octetsWriter, "Key 1", octetArray, 2, &DDS_HANDLE_NIL);
free(octetArray);
C++ Example with Namespaces:
#include "ndds/ndds_namespace_cpp.h" using namespace DDS;
...
KeyedOctetsDataWriter * octetsWriter = ... ;
/* Write some data using the KeyedOctets structure */ KeyedOctets * octets = new KeyedOctets(128,1024);
ReturnCode_t retCode =
delete octets;
/* Write |
some |
data using an octet array */ |
unsigned |
char |
* octetArray = new unsigned char[1024]; |
octetArray[0] |
= 46; |
|
octetArray[1] |
= 47; |
retCode =
delete []octetArray;
C++/CLI Example:
using namespace System; using namespace DDS;
...
KeyedOctetsDataWriter^ octetsWriter = ... ;
/* Write some data using KeyedBytes */ KeyedBytes^ octets = gcnew KeyedBytes(1024);
/* Write some data using individual strings */ array<Byte>^ octetAray = gcnew array<Byte>(1024); octetArray[0] = 46;
octetArray[1] = 47;
"Key 1", octetArray, 0, 2, InstanceHandle_t::HANDLE_NIL);
C# Example:
using System; using DDS;
...
KeyedBytesDataWriter stringWriter = ... ;
/* Write some data using the KeyedBytes */ KeyedBytes octets = new KeyedBytes(1024); octets.key = "Key 1";
octets.value[0] = 46; octets.value[1] = 47; octets.length = 2; octets.offset = 0;
octetWriter.write(octets, InstanceHandle_t.HANDLE_NIL);
/* Write some data using individual strings */ byte[] octetArray = new byte[1024]; octetArray[0] = 46;
octetArray[1] = 47;
octetsWriter.write(
"Key 1", octetArray, 0, 2, InstanceHandle_t.HANDLE_NIL);
Java Example:
import com.rti.dds.publication.*; import com.rti.dds.type.builtin.*; import com.rti.dds.infrastructure.*;
...
KeyedBytesDataWriter octetsWriter = ... ;
/* Write some data using the KeyedBytes class*/ KeyedBytes octets = new KeyedBytes(1024); octets.key = "Key 1";
octets.length = 2; octets.offset = 0; octets.value[0] = 46; octets.value[1] = 47;
octetsWriter.write(octets, InstanceHandle_t.HANDLE_NIL);
/* Write some data using a byte array */ byte[] octetArray = new byte[1024]; octetArray[0] = 46;
octetArray[1] = 47; octetsWriter.write(
"Key 1", octetArray, 0, 2, InstanceHandle_t.HANDLE_NIL);
3.2.7.3Keyed Octets DataReader
The KeyedOctets DataReader API is extended with the following methods (in addition to the standard methods described in Using a
DDS::ReturnCode_t DDS::KeyedOctetsDataReader::get_key_value( char * key,
const DDS::InstanceHandle_t* handle);
DDS::InstanceHandle_t DDS::KeyedOctetsDataReader::lookup_instance(
const char * key);
For more information and a complete description of these operations in all supported lan- guages, see the API Reference HTML documentation.
Memory considerations in copy operations:
For read/take operations with copy semantics, such as read_next_sample() and take_next_sample(), Connext allocates memory for the fields 'value' and 'key' if they are initialized to NULL.
If the fields are not initialized to NULL, the behavior depends on the language:
•In Java and .NET, the memory of the field 'value' will be reallocated if the current size is not large enough to hold the received data. The memory associated with the field 'key' will be reallocated with every sample (the key is an immutable object).
•In C and C++, the memory associated with the fields 'value' and 'key' must be large enough to hold the received data. Insufficient memory may result in crashes.
The following examples show how to read keyed octets with a keyed octets
C Example:
struct DDS_KeyedOctetsSeq dataSeq = DDS_SEQUENCE_INITIALIZER; struct DDS_SampleInfoSeq infoSeq = DDS_SEQUENCE_INITIALIZER; DDS_KeyedOctetsDataReader * octetsReader = ... ; DDS_ReturnCode_t retCode;
int i;
/* Take and print the data */
retCode = DDS_KeyedOctetsDataReader_take( octetsReader,
&dataSeq, &infoSeq, DDS_LENGTH_UNLIMITED, DDS_ANY_SAMPLE_STATE, DDS_ANY_VIEW_STATE, DDS_ANY_INSTANCE_STATE);
for (i = 0; i < DDS_KeyedOctetsSeq_get_length(&data_seq); ++i) {
if (DDS_SampleInfoSeq_get_reference(&info_seq,
DDS_KeyedOctetsSeq_get_reference(&data_seq, i));
}
}
/* Return loan */
retCode = DDS_KeyedOctetsDataReader_return_loan(
octetsReader, &data_seq, &info_seq);
C++ Example with Namespaces:
#include "ndds/ndds_namespace_cpp.h" using namespace DDS;
...
KeyedOctetsSeq dataSeq;
SampleInfoSeq infoSeq;
KeyedOctetsDataReader * octetsReader = ... ;
/* Take a print the data */
ReturnCode_t retCode = octetsReader->take( dataSeq, infoSeq, LENGTH_UNLIMITED,
ANY_SAMPLE_STATE, ANY_VIEW_STATE, ANY_INSTANCE_STATE); for (int i = 0; i < data_seq.length(); ++i) {
if (infoSeq[i].valid_data) { KeyedOctetsTypeSupport::print_data(&dataSeq[i]);
}
}
/* Return loan */
retCode =
C++/CLI Example:
using namespace System; using namespace DDS;
...
KeyedBytesSeq^ dataSeq = gcnew KeyedBytesSeq(); SampleInfoSeq^ infoSeq = gcnew SampleInfoSeq(); KeyedBytesDataReader^ octetsReader = ... ;
/* Take and print the data */
ResourceLimitsQosPolicy::LENGTH_UNLIMITED, SampleStateKind::ANY_SAMPLE_STATE, ViewStateKind::ANY_VIEW_STATE, InstanceStateKind::ANY_INSTANCE_STATE);
for (int i = 0; i < data_seq.length(); ++i) { if
}
}
/* Return loan */
C# Example:
using System; using DDS;
...
KeyedBytesSeq dataSeq = new KeyedButesSeq(); SampleInfoSeq infoSeq = new SampleInfoSeq(); KeyedBytesDataReader octetsReader = ... ;
/* Take and print the data */ octetsReader.take(dataSeq, infoSeq,
ResourceLimitsQosPolicy.LENGTH_UNLIMITED, SampleStateKind.ANY_SAMPLE_STATE, ViewStateKind.ANY_VIEW_STATE, InstanceStateKind.ANY_INSTANCE_STATE);
for (int i = 0; i < data_seq.length(); ++i) { if (infoSeq.get_at(i)).valid_data) {
KeyedBytesTypeSupport.print_data(dataSeq.get_at(i));
}
}
/* Return loan */ octetsReader.return_loan(dataSeq, infoSeq);
Java Example:
import com.rti.dds.infrastructure.*; import com.rti.dds.subscription.*; import com.rti.dds.type.builtin.*;
...
KeyedBytesSeq dataSeq = new KeyedBytesSeq(); SampleInfoSeq infoSeq = new SampleInfoSeq(); KeyedBytesDataReader octetsReader = ... ;
/* Take and print the data */ octetsReader.take(dataSeq, infoSeq,
ResourceLimitsQosPolicy.LENGTH_UNLIMITED, SampleStateKind.ANY_SAMPLE_STATE, ViewStateKind.ANY_VIEW_STATE, InstanceStateKind.ANY_INSTANCE_STATE);
for (int i = 0; i < data_seq.length(); ++i) {
if (((SampleInfo)infoSeq.get(i)).valid_data) { System.out.println(((KeyedBytes)dataSeq.get(i)).toString());
}
}
/* Return loan */ octetsReader.return_loan(dataSeq, infoSeq);
3.2.8Managing Memory for
When a sample is written, the DataWriter serializes it and stores the result in a buffer obtained from a pool of preallocated buffers. In the same way, when a sample is received, the DataReader deserializes it and stores the result in a sample coming from a pool of preallocated samples.
For data types generated by rtiddsgen, the size of the buffers and samples in both pools is known based on the IDL or XML description of the type.
For example:
struct MyString { string<128> value;
};
This
However, for
For example, a video surveillance application that is using the keyed octets
To accommodate both kinds of applications and optimize memory usage, you can configure the maximum size of the
Note: These properties must be set consistently with respect to the corresponding *.max_size properties in the DomainParticipant (see Table 3.16 on page
property must be less than or equal to the max_size property with the same name prefix in the
DomainParticipant.
Section 3.2.8.1 includes examples of how to set the maximum size of a string
<dds>
<qos_library name="BuiltinExampleLibrary"> <qos_profile name="BuiltinExampleProfile">
<datawriter_qos> <property>
<value>
<element> <name>dds.builtin_type.string.alloc_size</name> <value>2048</value>
</element>
</value>
</property> </datawriter_qos> <datareader_qos>
<property>
<value>
<element> <name>dds.builtin_type.string.alloc_size</name> <value>2048</value>
</element>
</value>
</property> </datareader_qos>
</qos_profile> </qos_library>
</dds>
Table 3.1 Properties for Allocating Size of
Property |
|
Description |
|
|
Type |
|
|
||
|
|
|
|
|
|
|
|
||
|
|
Maximum size of the strings published by the DataWriter |
||
|
|
or received by the DataReader (includes the |
||
string |
dds.builtin_type.string.alloc_size |
nated character). |
|
|
|
|
Default: dds.builtin_type.string.max_size if defined (see |
||
|
|
Table 3.16 on page |
|
|
|
|
|
||
|
|
Maximum size of the keys used by the DataWriter or |
||
|
dds.builtin_type.keyed_string. |
DataReader (includes the |
|
|
|
alloc_key_size |
Default: dds.builtin_type.keyed_string.max_key_size if |
||
keyed- |
|
defined (see Table 3.16 on page |
|
|
|
|
|
|
|
|
Maximum size of the strings published by the DataWriter |
|||
string |
|
|||
|
or received by the DataReader (includes the |
|||
|
dds.builtin_type.keyed_string. |
|||
|
nated character). |
|
||
|
alloc_size |
|
||
|
Default: |
dds.builtin_type.keyed_string.max_size |
if |
|
|
|
|||
|
|
defined (see Table 3.16 on page |
|
|
|
|
|
||
|
|
Maximum size of the octet sequences published by the |
||
octets |
dds.builtin_type.octets.alloc_size |
DataWriter or DataReader. |
|
|
|
|
Default: dds.builtin_type.octets.max_size if defined (see |
||
|
|
Table 3.16 on page |
|
|
|
|
|
|
|
Table 3.1 Properties for Allocating Size of
Property |
|
Description |
|
|
Type |
|
|
||
|
|
|
|
|
|
|
|
||
|
|
Maximum size of the key published by the DataWriter or |
||
|
dds.builtin_type.keyed_octets. |
received |
by the DataReader (includes the |
|
|
nated character). |
|
||
|
alloc_key_size |
|
||
|
Default: |
dds.builtin_type.keyed_octets.max_key_size |
if |
|
keyed- |
|
|||
|
defined (see Table 3.16 on page |
|
||
octets |
|
|
||
|
|
|
|
|
|
Maximum size of the octet sequences published by the |
|||
|
|
|||
|
dds.builtin_type.keyed_octets. |
DataWriter or DataReader. |
|
|
|
alloc_size |
Default: |
dds.builtin_type.keyed_octets.max_size |
if |
|
|
defined (see Table 3.16 on page |
|
|
|
|
|
|
|
3.2.8.1
For simplicity, error handling is not shown in the following examples.
C Example:
DDS_DataWriter * writer = NULL; DDS_StringDataWriter * stringWriter = NULL; DDS_Publisher * publisher = ... ;
DDS_Topic * stringTopic = ... ;
struct DDS_DataWriterQos writerQos = DDS_DataWriterQos_INITIALIZER; DDS_ReturnCode_t retCode;
retCode = DDS_DomainParticipant_get_default_datawriter_qos ( participant, &writerQos);
retCode = DDS_PropertyQosPolicyHelper_add_property ( &writerQos.property, "dds.builtin_type.string.alloc_size", "1000", DDS_BOOLEAN_FALSE);
writer = DDS_Publisher_create_datawriter(
publisher, stringTopic, &writerQos, NULL, DDS_STATUS_MASK_NONE);
stringWriter = DDS_StringDataWriter_narrow(writer); DDS_DataWriterQos_finalize(&writerQos);
C++ Example with Namespaces:
#include "ndds/ndds_namespace_cpp.h" using namespace DDS;
...
Publisher * publisher = ... ;
Topic * stringTopic = ... ;
DataWriterQos writerQos;
ReturnCode_t retCode =
retCode = PropertyQosPolicyHelper::add_property (
&writerQos.property, dds.builtin_type.string.alloc_size", "1000", BOOLEAN_FALSE);
DataWriter * writer = publisher->create_datawriter( stringTopic, writerQos, NULL, STATUS_MASK_NONE);
StringDataWriter * stringWriter = StringDataWriter::narrow(writer);
C++/CLI Example:
using namespace DDS;
...
Topic^ stringTopic = ... ;
Publisher^ publisher = ... ;
DataWriterQos^ writerQos = gcnew DataWriterQos();
"dds.builtin_type.string.alloc_size","1000", false);
DataWriter^ writer =
StringDataWriter^ stringWriter = safe_cast<StringDataWriter^>(writer);
C# Example:
using DDS;
...
Topic stringTopic = ... ;
Publisher publisher = ... ;
DataWriterQos writerQos = new DataWriterQos();
participant.get_default_datawriter_qos(writerQos);
PropertyQosPolicyHelper.add_property (writerQos.property_qos,
"dds.builtin_type.string.alloc_size", "1000", false);
StringDataWriter stringWriter =
(StringDataWriter) publisher.create_datawriter(stringTopic, writerQos, null, StatusMask.STATUS_MASK_NONE);
Java Example:
import com.rti.dds.publication.*; import com.rti.dds.type.builtin.*; import com.rti.dds.infrastructure.*;
...
Topic stringTopic = ... ;
Publisher publisher = ... ;
DataWriterQos writerQos = new DataWriterQos();
participant.get_default_datawriter_qos(writerQos);
PropertyQosPolicyHelper.add_property (writerQos.property,
"dds.builtin_type.string.alloc_size", "1000", false);
StringDataWriter stringWriter =
(StringDataWriter) publisher.create_datawriter(stringTopic, writerQos, null, StatusKind.STATUS_MASK_NONE);
3.2.9Type Codes for
The type codes associated with the
module DDS {
/* String */ struct String {
string<max_size> value;
};
/* KeyedString */ struct KeyedString {
string<max_size> key; //@key string<max_size> value;
};
/* Octets */ struct Octets {
sequence<octet, max_size> value;
};
/* KeyedOctets */ struct KeyedOctets {
string<max_size> key; //@key sequence<octet, max_size> value;
};
};
The maximum size (max_size) of the strings and sequences that will be included in the type code definitions can be configured on a
Table 3.2 Properties for Allocating Size of
Property |
Description |
||
Type |
|||
|
|
||
|
|
|
|
|
|
|
|
|
|
Maximum size of the strings published by the DataWriters |
|
String |
dds.builtin_type.string.max_size |
and received by the DataReaders belonging to a DomainPar- |
|
ticipant (includes the |
|||
|
|
||
|
|
Default: 1024 |
|
|
|
|
|
|
|
Maximum size of the keys used by the DataWriters and |
|
|
dds.builtin_type.keyed_string. |
DataReaders belonging to a DomainParticipant (includes the |
|
|
max_key_size |
||
Keyed- |
|
Default: 1024 |
|
|
|
||
|
Maximum size of the strings published by the DataWriters |
||
String |
|
||
|
and received by the DataReaders belonging to a DomainPar- |
||
|
dds.builtin_type.keyed_string. |
||
|
ticipant using the |
||
|
max_size |
||
|
nated character). |
||
|
|
||
|
|
Default: 1024 |
|
|
|
|
|
|
|
Maximum size of the octet sequences published by the |
|
Octets |
dds.builtin_type.octets.max_size |
DataWriters and DataReaders belonging to a DomainPartici- |
|
pant. |
|||
|
|
||
|
|
Default: 2048 |
|
|
|
|
|
|
|
Creating User Data Types with IDL |
Table 3.2 Properties for Allocating Size of |
|||
|
|
|
|
|
Property |
Description |
|
|
Type |
||
|
|
|
|
|
|
|
|
|
|
|
Maximum size of the key published by the DataWriter and |
|
|
dds.builtin_type.keyed_octets. |
received by the DataReaders belonging to the |
|
|
DomainParticipant (includes the |
|
|
|
max_key_size |
|
|
|
ter). |
|
|
Keyed- |
|
|
|
|
Default:1024. |
|
|
Octets |
|
|
|
|
|
|
|
|
Maximum size of the octet sequences published by the |
|
|
|
|
|
|
|
dds.builtin_type.keyed_octets. |
DataWriters and DataReaders belonging to a DomainPartici- |
|
|
max_size |
pant. |
|
|
|
Default: 2048 |
|
|
|
|
3.3Creating User Data Types with IDL
You can create user data types in a text file using IDL (Interface Description Language). IDL is
Connext only uses a subset of the IDL syntax. IDL was originally defined by the OMG for the use of CORBA client/server applications in an enterprise setting. Not all of the constructs that can be described by the language are as useful in the context of
The rtiddsgen utility will parse any file that follows version 3.0.3 of the IDL specification. It will quietly ignore all syntax that is not recognized by Connext. In addition, even though “anony- mous sequences” (sequences of sequences with no intervening typedef) are currently legal in IDL, they have been deprecated by the specification, and thus rtiddsgen does not support them.
Certain keywords are considered reserved by the IDL specification; see Table 3.3.
Table 3.3 Reserved IDL Keywords
abstract |
emits |
local |
pseudo |
typeid |
|
|
|
|
|
alias |
enum |
long |
public |
typename |
|
|
|
|
|
any |
eventtype |
mirrorport |
publishes |
typeprefix |
|
|
|
|
|
attribute |
exception |
module |
raises |
union |
|
|
|
|
|
boolean |
factory |
multiple |
readonly |
unsigned |
|
|
|
|
|
case |
FALSE |
native |
sequence |
uses |
|
|
|
|
|
char |
finder |
object |
setraises |
valuebase |
|
|
|
|
|
component |
fixed |
octet |
short |
valuetype |
|
|
|
|
|
connector |
float |
oneway |
string |
void |
|
|
|
|
|
const |
getraises |
out |
struct |
wchar |
|
|
|
|
|
consumes |
home |
port |
supports |
wstring |
|
|
|
|
|
context |
import |
porttype |
switch |
|
|
|
|
|
|
custom |
in |
primarykey |
TRUE |
|
|
|
|
|
|
Creating User Data Types with IDL
Table 3.3 Reserved IDL Keywords
default |
inout |
private |
truncatable |
|
|
|
|
|
|
double |
interface |
provides |
typedef |
|
|
|
|
|
|
The IDL constructs supported by rtiddsgen are described in Table 3.5, “Specifying Data Types in IDL for C and C++,” on page
For C and C++, rtiddsgen uses typedefs instead of the language keywords for primitive types. For example, DDS_Long instead of long or DDS_Double instead of double. This ensures that the types are of the same size regardless of the platform.1
The remainder of this section includes:
❏
❏TypeCode and rtiddsgen (Section 3.3.3)
❏rtiddsgen Translations for IDL Types (Section 3.3.4)
❏Escaped Identifiers (Section 3.3.5)
❏Referring to Other IDL Files (Section 3.3.6)
❏Preprocessor Directives (Section 3.3.7)
❏Using Custom Directives (Section 3.3.8)
3.3.1
When rtiddsgen generates code for data structures with
For
3.3.1.1Sequences
C, C++, C++/CLI, and C# users can allocate memory from a number of sources: from the heap, the stack, or from a custom allocator of some kind. In those languages, sequences provide the concept of memory "ownership." A sequence may own the memory allocated to it or be loaned memory from another source. If a sequence owns its memory, it will manage its underlying memory storage buffer itself. When a sequence's maximum size is changed, the sequence will free and reallocate its buffer as needed. However, if a sequence was created with loaned mem- ory by user code, then its memory is not its own to free or reallocate. Therefore, you cannot set the maximum size of a sequence whose memory is loaned. See the API Reference HTML docu- mentation, which is available for all supported programming languages (select Modules, DDS
1.The number of bytes sent on the wire for each data type is determined by the Common Data Representation (CDR) standard. For details on CDR, please see the Common Object Request Broker Architecture (CORBA) Specifica- tion, Version 3.1, Part 2: CORBA Interoperability, Section 9.3, CDR Transfer Syntax (http://www.omg.org/technology/ documents/corba_spec_catalog.htm).
Creating User Data Types with IDL
API Reference, Infrastructure Module, Sequence Support) for more information about how to loan and unloan memory for sequence.
In IDL, as described above, a sequence may be declared as bounded or unbounded. A sequence's "bound" is the greatest value its maximum may take. If you use the initializer func- tions rtiddsgen provides for your types, all sequences will have their maximums set to their declared bounds. However, the amount of data transmitted on the wire when the sample is writ- ten will vary.
3.3.1.2Strings and Wide Strings
The initialization functions that rtiddsgen provides for your types will allocate all of the memory for strings in a type to their declared bounds. Take
To Java and .NET users, an IDL string is a String object: it is immutable and knows its own length. C and C++ users must take care, however, as there is no way to determine how much memory is allocated to a character pointer "string"; all that can be determined is the string's cur- rent logical length. In some cases, Connext may need to copy a string into a structure that user code has provided. Connext does not free the memory of the string provided to it, as it cannot know from where that memory was allocated.
In the C and C++ APIs, Connext therefore uses the following conventions:
❏A string's memory is "owned" by the structure that contains that string. Calling the final- ization function provided for a type will free all recursively contained strings. If you have allocated a contained string in a special way, you must be careful to clean up your own memory and assign the pointer to NULL before calling the type’s finalize() method, so that Connext will skip over that string.
❏You must provide a
❏When you provide a
Connext provides a small set of C functions for dealing with strings. These functions simplify common tasks, avoid some
3.3.2Value Types
A value type is like a structure, but with support for additional
Readers familiar with value types in the context of CORBA should consult Table 3.4 to see which value
|
|
Creating User Data Types with IDL |
Table 3.4 Value Type Support |
|
|
|
|
|
|
Aspect |
Level of Support in rtiddsgen |
|
|
|
|
|
|
|
Inheritance |
Single inheritance from other value types |
|
|
|
|
Public state members |
Supported |
|
|
|
|
Private state members |
Become public when code is generated |
|
|
|
|
Custom keyword |
Ignored (the value type is parsed without the keyword and code is generated to |
|
work with it) |
|
|
|
|
|
|
|
|
Abstract value types |
No code generated (the value type is parsed, but no code is generated) |
|
|
|
|
Operations |
No code generated (the value type is parsed, but no code is generated) |
|
|
|
|
Truncatable keyword |
Ignored (the value type is parsed without the keyword and code is generated to |
|
work with it) |
|
|
|
|
|
|
|
3.3.3TypeCode and rtiddsgen
Type codes are enabled by default when you run rtiddsgen. The
Locally, your application can access the type code for a generated type "Foo" by calling the Foo::get_typecode() operation in the code for the type generated by rtiddsgen (unless
Note:
3.3.4rtiddsgen Translations for IDL Types
This section describes how to specify your data types in an IDL file. The rtiddsgen utility sup- ports all the types listed in the following tables:
❏Table 3.5, “Specifying Data Types in IDL for C and C++,” on page
❏Table 3.6, “Specifying Data Types in IDL for C++/CLI,” on page
❏Table 3.7, “Specifying Data Types in IDL for Java,” on page
In each table, the middle column shows the syntax for an IDL data type in the IDL file. The rightmost column shows the corresponding language mapping created by rtiddsgen.
Table 3.5 Specifying Data Types in IDL for C and C++
IDL Type |
Sample Entry in IDL File |
Sample Output Generated by rtiddsgen |
|
|
|
|
|
|
|
|
|
char |
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
{ |
|||
(see Note 1 |
char char_member; |
||
DDS_Char char_member; |
|||
below) |
}; |
||
} PrimitiveStruct; |
|||
|
|
||
|
|
|
|
|
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
|
{ |
||
wchar |
wchar wchar_member; |
||
DDS_Wchar wchar_member; |
|||
|
}; |
||
|
} PrimitiveStruct; |
||
|
|
||
|
|
|
|
|
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
octet |
{ |
||
octet octet_member; |
|||
DDS_Octet octect_member; |
|||
|
}; |
||
|
} PrimitiveStruct; |
||
|
|
||
|
|
|
|
|
|
Creating User Data Types with IDL |
|
Table 3.5 Specifying Data Types in IDL for C and C++ |
|
|
||
|
|
|
|
|
|
IDL Type |
Sample Entry in IDL File |
Sample Output Generated by rtiddsgen |
|
|
|
|
|
|
|
|
|
|
|
|
|
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
|
short |
{ |
|
|
|
short short_member; |
|
||
|
DDS_Short short_member; |
|||
|
|
}; |
||
|
|
} PrimitiveStruct; |
||
|
|
|
||
|
|
|
|
|
|
|
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
|
unsigned |
{ |
|
|
|
unsigned short |
|
||
|
DDS_UnsignedShort |
|||
|
short |
unsigned_short_member; |
||
|
unsigned_short_member; |
|||
|
|
}; |
||
|
|
} PrimitiveStruct; |
||
|
|
|
||
|
|
|
|
|
|
|
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
|
|
{ |
|
|
|
long |
long long_member; |
|
|
|
DDS_Long long_member; |
|||
|
|
}; |
||
|
|
} PrimitiveStruct; |
||
|
|
|
||
|
|
|
|
|
|
|
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
|
unsigned |
{ |
|
|
|
unsigned long |
|
||
|
DDS_UnsignedLong |
|||
|
long |
unsigned_long_member; |
||
|
unsigned_long_member; |
|||
|
|
}; |
||
|
|
} PrimitiveStruct; |
||
|
|
|
||
|
|
|
|
|
|
|
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
|
long long |
{ |
|
|
|
long long long_long_member; |
|
||
|
DDS_LongLong long_long_member; |
|||
|
|
}; |
||
|
|
} PrimitiveStruct; |
||
|
|
|
||
|
|
|
|
|
|
|
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
|
unsigned |
{ |
|
|
|
unsigned long long |
|
||
|
DDS_UnsignedLongLong |
|||
|
long long |
unsigned_long_long_member; |
||
|
unsigned_long_long_member; |
|||
|
|
}; |
||
|
|
} PrimitiveStruct; |
||
|
|
|
||
|
|
|
|
|
|
|
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
|
|
{ |
|
|
|
float |
float float_member; |
|
|
|
DDS_Float float_member; |
|||
|
|
}; |
||
|
|
} PrimitiveStruct; |
||
|
|
|
||
|
|
|
|
|
|
|
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
|
double |
{ |
|
|
|
double double_member; |
|
||
|
DDS_Double double_member; |
|||
|
|
}; |
||
|
|
} PrimitiveStruct; |
||
|
|
|
||
|
|
|
|
|
|
long dou- |
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
|
ble |
{ |
|
|
|
long double long_double_member; |
|
||
|
(see Note 2 |
DDS_LongDouble long_double_member; |
||
|
}; |
|||
|
} PrimitiveStruct; |
|||
|
below) |
|
||
|
|
|
|
|
|
pointer |
struct MyStruct { |
typedef struct MyStruct { |
|
|
(see Note 9 |
long * member; |
DDS_Long * member; |
|
|
below) |
}; |
} MyStruct; |
|
|
|
|
|
|
|
|
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
|
|
{ |
|
|
|
boolean |
boolean boolean_member; |
|
|
|
DDS_Boolean boolean_member; |
|||
|
|
}; |
||
|
|
} PrimitiveStruct; |
||
|
|
|
||
|
|
|
|
|
|
|
|
|
Creating User Data Types with IDL |
|
Table 3.5 Specifying Data Types in IDL for C and C++ |
|
|
|||
|
|
|
|
||
|
IDL Type |
Sample Entry in IDL File |
Sample Output Generated by rtiddsgen |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum PrimitiveEnum { |
typedef enum PrimitiveEnum |
|
|
|
|
{ |
|
|
|
|
|
ENUM1, |
|
|
|
|
|
ENUM1, |
||
|
|
|
ENUM2, |
||
|
|
|
ENUM2, |
||
|
|
|
ENUM3 |
||
|
|
|
ENUM3 |
||
|
|
|
}; |
||
|
|
|
} PrimitiveEnum; |
||
|
|
|
|
||
|
enum |
|
|
|
|
|
|
|
enum PrimitiveEnum { |
typedef enum PrimitiveEnum |
|
|
|
|
{ |
|
|
|
|
|
ENUM1 = 10, |
|
|
|
|
|
ENUM1 = 10, |
||
|
|
|
ENUM2 = 20, |
||
|
|
|
ENUM2 = 20, |
||
|
|
|
ENUM3 = 30 |
||
|
|
|
ENUM3 = 30 |
||
|
|
|
}; |
||
|
|
|
} PrimitiveEnum; |
||
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
C: #define SIZE 5 |
|
|
constant |
const short SIZE = 5; |
C++: static const DDS_Short size = 5; |
||
|
|
|
|
|
|
|
|
|
|
typedef struct BitfieldType |
|
|
|
|
struct BitfieldType { |
{ |
|
|
|
|
short myShort_1 : 1; |
DDS_Short myShort_1 : 1; |
|
|
|
|
unsigned short myUnsignedShort_1: |
DDS_UnsignedShort myUnsignedShort_1 |
|
|
|
|
1; |
: 1; |
|
|
|
|
long myLong_1: 1; |
DDS_Long myLong_1 : 1; |
|
|
|
|
unsigned long myUnsignedLong_1 :1; |
DDS_UnsignedLong myUnsignedLong_1 : |
|
|
bitfield |
char myChar_1 : 1; |
1; |
|
|
|
wchar myWChar_1 : 1; |
DDS_Char myChar_1 : 1; |
|||
|
|
|
|||
|
|
|
octet myOctet_1 : 1; |
DDS_Wchar myWChar_1 : 1; |
|
|
(see |
short : 0; |
DDS_Octet myOctet_1 : 1; |
||
|
12 below) |
long myLong_5 : 5; |
DDS_Short : 0; |
||
|
long myLong_30 : 30; |
DDS_Long myLong_5 : 5; |
|||
|
|
|
|||
|
|
|
short myShort_6 : 6; |
DDS_Long myLong_30 : 30; |
|
|
|
|
short myShort_3and4 : 3+4; |
DDS_Short myShort_6 : 6; |
|
|
|
|
short myShort; |
DDS_Short myShort_3and4 : 3+4; |
|
|
|
|
short myShort_8 : 8; |
DDS_Short myShort; |
|
|
|
|
long myLong_32: 32; |
DDS_Short myShort_8 : 8; |
|
|
|
|
}; |
DDS_Long myLong_32 : 32; |
|
|
|
|
|
} BitfieldType; |
|
|
|
|
|
|
|
|
struct |
|
struct PrimitiveStruct { |
typedef struct PrimitiveStruct |
|
|
|
|
|||
|
|
|
{ |
|
|
|
|
|
char char_member; |
|
|
|
(see |
char char_member; |
|||
|
}; |
||||
|
} PrimitiveStruct; |
||||
|
10 below) |
|
|||
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
typedef struct PrimitiveUnion |
|
|
union |
|
union PrimitiveUnion switch (long){ |
{ |
|
|
|
|
case 1: |
DDS_Long _d; |
|
|
(see Note 3 |
short short_member; |
struct { |
||
|
default: |
DDS_Short short_member; |
|||
|
and |
||||
|
long long_member; |
DDS_Long long_member; |
|||
|
10 below) |
}; |
} _u; |
||
|
|
|
|
} PrimitiveUnion; |
|
|
|
|
|
||
|
typedef |
typedef short TypedefShort; |
typedef DDS_Short TypedefShort; |
||
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with IDL |
|||
Table 3.5 Specifying Data Types in IDL for C and C++ |
|
|
|
|
|
|||
|
|
|
|
|||||
|
IDL Type |
Sample Entry in IDL File |
Sample Output Generated by rtiddsgen |
|||||
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
||
|
|
|
struct OneDArrayStruct { |
typedef struct OneDArrayStruct |
|
|
||
|
|
|
{ |
|
|
|
|
|
|
|
|
short short_array[2]; |
|
|
|
|
|
|
|
|
DDS_Short short_array[2]; |
|
|
|||
|
array |
of |
}; |
|
|
|||
|
} OneDArrayStruct; |
|
|
|
||||
|
above |
|
struct TwoDArrayStruct { |
|
|
|
|
|
|
types |
|
typedef struct TwoDArrayStruct |
|
|
|||
|
|
short short_array[1][2]; |
|
|
||||
|
|
|
{ |
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
DDS_Short short_array[1][2]; |
|
|
|||
|
|
|
|
|
|
|||
|
|
|
|
} TwoDArrayStruct; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bounded |
|
typedef struct SequenceStruct |
|
|
|||
|
sequence of |
|
|
|
||||
|
|
{ |
|
|
|
|
||
|
above |
|
|
|
|
|
|
|
|
|
struct SequenceStruct { |
DDSShortSeq short_sequence; |
|
|
|||
|
types |
|
sequence<short,4> short_sequence; |
} SequenceStruct; |
|
|
|
|
|
|
|
}; |
Note: Sequences of primitive types have been |
||||
|
(see |
|
||||||
|
|
predefined by Connext. |
|
|
|
|||
|
11 below) |
|
|
|
|
|||
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
||
|
unbounded |
|
typedef struct SequenceStruct |
|
|
|||
|
|
{ |
|
|
|
|
||
|
sequence of |
|
|
|
|
|
||
|
|
DDSShortSeq short_sequence; |
|
|
||||
|
above |
|
struct SequenceStruct { |
} SequenceStruct; |
|
|
|
|
|
types |
|
sequence<short> short_sequence; |
Note: rtiddsgen will supply a default bound. |
||||
|
|
|
}; |
|||||
|
(see |
|
You can specify that bound with the |
|||||
|
|
eSize” |
option; |
see |
||||
|
11 below) |
|
||||||
|
|
|
|
|
||||
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
||
|
array |
of |
struct ArraysOfSequences{ |
typedef struct ArraysOfSequences |
|
|
||
|
sequence<short,4> |
{ |
|
|
|
|
||
|
sequences |
sequences_array[2]; |
DDS_ShortSeq sequences_array[2]; |
|
|
|||
|
|
|
}; |
} ArraysOfSequences; |
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
typedef DDS_Short ShortArray[2]; |
|
|
||
|
|
|
|
DDS_SEQUENCE_NO_GET(ShortArraySeq, |
|
|
||
|
|
|
|
|
ShortArray); |
|
|
|
|
sequence of |
typedef short ShortArray[2]; |
typedef struct SequenceOfArrays |
|
|
|||
|
arrays |
|
|
|
|
|||
|
|
struct SequenceofArrays { |
{ |
|
|
|
|
|
|
|
|
|
|
|
|
||
|
(see |
sequence<ShortArray,2> |
ShortArraySeq arrays_sequence; |
|
|
|||
|
arrays_sequence; |
} SequenceOfArrays; |
|
|
|
|||
|
11 below) |
}; |
DDS_SEQUENCE_NO_GET is a Connext |
|||||
|
|
|
|
|||||
|
|
|
|
macro that defines a new sequence type for a |
||||
|
|
|
|
user data type. In this case, the user data type is |
||||
|
|
|
|
ShortArray. |
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
typedef sequence<short,4> |
typedef DDS_ShortSeq ShortSequence; |
|
|
||
|
sequence of |
|
|
|
|
|
||
|
sequences |
ShortSequence; |
DDS_SEQUENCE(ShortSequenceSeq, |
|
|
|||
|
|
|
|
|||||
|
|
|
struct SequencesOfSequences{ |
|
ShortSequence); |
|
|
|
|
|
|
|
|
|
|
|
|
|
(see Note 4 |
sequence<ShortSequence,2> |
typedef struct SequencesOfSequences{ |
|
|
|||
|
sequences_sequence; |
|
|
|||||
|
and |
ShortSequenceSeq |
|
|
|
|||
|
}; |
|
|
|
||||
|
11 below) |
sequences_sequence; |
|
|
|
|||
|
|
|
|
|
||||
|
|
|
|
} SequencesOfSequences; |
|
|
|
|
|
|
|
|
|
|
|
||
|
bounded |
struct PrimitiveStruct { |
typedef struct PrimitiveStruct { |
|
|
|||
|
char* string_member; |
|
|
|
||||
|
string<20> string_member; |
|
|
|
||||
|
string |
|
|
/* maximum length = (20) */ |
||||
|
|
}; |
|
|||||
|
|
|
} PrimitiveStruct; |
|
|
|
||
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with IDL |
|
Table 3.5 Specifying Data Types in IDL for C and C++ |
|
|
||
|
|
|
|
|
|
IDL Type |
Sample Entry in IDL File |
Sample Output Generated by rtiddsgen |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct PrimitiveStruct { |
|
|
|
|
char* string_member; |
|
|
unbounded |
struct PrimitiveStruct { |
/* maximum length = (255) */ |
|
|
string string_member; |
} PrimitiveStruct; |
||
|
string |
}; |
Note: rtiddsgen will supply a default bound. |
|
|
|
|
||
|
|
|
You can specify that bound with the |
|
|
|
|
Size |
|
|
|
|
|
|
|
|
|
typedef struct PrimitiveStruct { |
|
|
bounded |
struct PrimitiveStruct { |
DDS_Wchar * wstring_member; |
|
|
wstring<20> wstring_member; |
/* maximum length = (20) |
||
|
wstring |
|||
|
}; |
*/ |
|
|
|
|
|
||
|
|
|
} PrimitiveStruct; |
|
|
|
|
|
|
|
|
|
typedef struct PrimitiveStruct { |
|
|
|
struct PrimitiveStruct { |
DDS_Wchar * wstring_member; |
|
|
unbounded |
/* maximum length = (255) */ |
||
|
wstring |
wstring wstring_member; |
||
|
}; |
|
|
|
|
|
} PrimitiveStruct; |
||
|
|
|
||
|
|
|
Note: rtiddsgen will supply a default bound. |
|
|
|
|
|
|
|
|
|
With the |
|
|
|
|
for C++): |
|
|
|
|
namespace PackageName{ |
|
|
|
module PackageName { |
typedef struct Foo { |
|
|
module |
struct Foo { |
DDS_Long field; |
|
|
long field; |
} Foo; |
||
|
|
}; |
}; |
|
|
|
}; |
Without the |
|
|
|
|
typedef struct PackageName_Foo { |
|
|
|
|
DDS_Long field; |
|
|
|
|
} PackageName_Foo; |
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with IDL |
||
Table 3.5 Specifying Data Types in IDL for C and C++ |
|
|
|
|
||
|
|
|
|
|||
|
IDL Type |
Sample Entry in IDL File |
Sample Output Generated by rtiddsgen |
|||
|
|
|
|
|
||
|
|
|
|
|
||
|
|
|
C++: |
class MyValueType { |
||
|
|
|
|
public: |
|
|
|
|
|
|
MyValueType2 * member; |
||
|
|
|
|
}; |
|
|
|
|
|
|
class MyValueType { |
||
|
|
|
|
public: |
|
|
|
|
valuetype MyValueType { |
|
MyValueType2 |
member; |
|
|
|
|
}; |
|
|
|
|
|
public MyValueType2 * member; |
|
|
|
|
|
|
|
|
|
|
|
|
|
}; |
|
class MyValueType : public MyBa- |
||
|
|
|
|
|||
|
valuetype |
|
|
seValueType |
|
|
|
valuetype MyValueType { |
|
{ |
|
|
|
|
|
|
public: |
|
|
|
|
|
public MyValueType2 member; |
|
|
|
|
|
(see Note 9 |
|
MyValueType2 * member; |
|||
|
}; |
|
||||
|
|
}; |
|
|
||
|
and Note |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
C: |
|
|
|
|
|
10 below) |
|
typedef struct MyValueType { |
|||
|
|
valuetype MyValueType: MyBaseValueType |
|
MyValueType2 * member; |
||
|
|
{ |
|
} MyValueType; |
|
|
|
|
public MyValueType2 * member; |
|
|
|
|
|
|
}; |
|
typedef struct MyValueType { |
||
|
|
|
|
MyValueType2 |
member; |
|
|
|
|
|
} MyValueType; |
|
|
|
|
|
|
typedef struct MyValueType |
||
|
|
|
|
{ |
|
|
|
|
|
|
MyBaseValueType parent; |
||
|
|
|
|
MyValueType2 * member; |
||
|
|
|
|
} MyValueType; |
|
|
|
|
|
|
|
|
|
Table 3.6 Specifying Data Types in IDL for C++/CLI |
|
|
|
|
||
|
|
|
|
|||
|
IDL Type |
Sample Entry in IDL File |
Sample Output Generated by rtiddsgen |
|||
|
|
|
|
|||
|
|
|
|
|||
|
char |
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
|||
|
(see Note 1 |
char char_member; |
System::Char char_member; |
|||
|
below) |
}; |
}; |
|
|
|
|
|
|
|
|||
|
wchar |
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
|||
|
wchar wchar_member; |
System::Char wchar_member; |
||||
|
|
}; |
}; |
|
|
|
|
|
|
|
|||
|
|
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
|||
|
octet |
octet octet_member; |
System::Byte octet_member; |
|||
|
|
}; |
}; |
|
|
|
|
|
|
|
|||
|
short |
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
|||
|
short short_member; |
System::Int16 short_member; |
||||
|
|
}; |
}; |
|
|
|
|
|
|
|
|
|
|
|
unsigned |
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
|||
|
unsigned short |
|||||
|
System::UInt16 unsigned_short_member; |
|||||
|
short |
unsigned_short_member; |
||||
|
}; |
|
|
|
||
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
long |
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
|||
|
long long_member; |
System::Int32 long_member; |
||||
|
|
}; |
}; |
|
|
|
|
|
|
|
|||
|
unsigned |
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
|||
|
unsigned long unsigned_long_member; |
System::UInt32 unsigned_long_member; |
||||
|
long |
|||||
|
}; |
}; |
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with IDL |
|
Table 3.6 Specifying Data Types in IDL for C++/CLI |
|
|
|||
|
|
|
|
||
|
IDL Type |
Sample Entry in IDL File |
Sample Output Generated by rtiddsgen |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
long long |
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
||
|
long long long_long_member; |
System::Int64 long_long_member; |
|||
|
|
|
}; |
}; |
|
|
|
|
|
|
|
|
unsigned |
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
||
|
unsigned long long |
System::UInt64 |
|||
|
long long |
unsigned_long_long_member; |
unsigned_long_long_member; |
||
|
|
|
}; |
}; |
|
|
|
|
|
|
|
|
float |
|
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
|
|
|
float float_member; |
System::Single float_member; |
||
|
|
|
}; |
}; |
|
|
|
|
|
|
|
|
|
|
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
|
|
double |
double double_member; |
System::Double double_member; |
||
|
|
|
}; |
} PrimitiveStruct; |
|
|
|
|
|
|
|
|
long |
dou- |
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
|
|
ble |
|
|||
|
|
long double long_double_member; |
DDS::LongDouble long_double_member; |
||
|
(see Note 2 |
||||
|
}; |
} PrimitiveStruct; |
|||
|
below) |
|
|
|
|
|
|
|
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
|
|
boolean |
boolean boolean_member; |
System::Boolean boolean_member; |
||
|
|
|
}; |
}; |
|
|
|
|
|
|
|
|
|
|
|
public enum class |
|
|
|
|
enum PrimitiveEnum { |
PrimitiveEnum : System::Int32 { |
|
|
|
|
ENUM1, |
ENUM1, |
|
|
|
|
ENUM2, |
ENUM2, |
|
|
|
|
ENUM3 |
ENUM3 |
|
|
enum |
|
}; |
}; |
|
|
|
|
|
|
|
|
|
|
enum PrimitiveEnum { |
public enum class |
|
|
|
|
ENUM1 = 10, |
PrimitiveEnum : System::Int32 { |
|
|
|
|
ENUM2 = 20, |
ENUM1 = 10, |
|
|
|
|
ENUM3 = 30 |
ENUM2 = 20, |
|
|
|
|
}; |
ENUM3 = 30 |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
public ref class SIZE { |
|
|
constant |
const short SIZE = 5; |
public: |
||
|
static System::Int16 VALUE = 5; |
||||
|
|
|
|
||
|
|
|
|
}; |
|
|
|
|
|
|
|
|
struct |
|
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
|
|
|
|
|||
|
|
|
|
|
|
|
(see |
char char_member; |
System::Char char_member; |
||
|
}; |
}; |
|
||
|
10 below) |
|
|
||
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
public ref class PrimitiveUnion |
|
|
union |
|
union PrimitiveUnion switch (long){ |
{ |
|
|
|
|
case 1: |
System::Int32 _d; |
|
|
(see Note 3 |
short short_member; |
struct PrimitiveUnion_u { |
||
|
default: |
System::Int16 short_member; |
|||
|
and |
||||
|
long long_member; |
System::Int32 long_member; |
|||
|
10 below) |
}; |
} _u; |
||
|
|
|
|
}; |
|
|
|
|
|
|
|
|
array |
of |
struct OneDArrayStruct { |
public ref class OneDArrayStruct { |
|
|
array<System::Int16>^ short_array; |
||||
|
above |
|
short short_array[2]; |
||
|
|
/*length == 2*/ |
|||
|
types |
|
}; |
||
|
|
}; |
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with IDL |
|
Table 3.6 Specifying Data Types in IDL for C++/CLI |
|
|
|||
|
|
|
|
||
|
IDL Type |
Sample Entry in IDL File |
Sample Output Generated by rtiddsgen |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
bounded |
|
public ref class SequenceStruct { |
||
|
sequence of |
|
|||
|
|
ShortSeq^ short_sequence; |
|||
|
above |
|
|
||
|
|
struct SequenceStruct { |
/*max = 4*/ |
||
|
types |
|
sequence<short,4> short_sequence; |
}; |
|
|
|
|
}; |
Note: Sequences of primitive types have been |
|
|
(see |
|
|||
|
|
predefined by Connext. |
|||
|
11 below) |
|
|||
|
|
|
|
||
|
|
|
|
||
|
unbounded |
|
public ref class SequenceStruct { |
||
|
sequence of |
|
ShortSeq^ short_sequence; |
||
|
above |
|
struct SequenceStruct { |
/*max = <default bound>*/ |
|
|
|
}; |
|
||
|
types |
|
|
||
|
|
sequence<short> short_sequence; |
|
||
|
|
Note: rtiddsgen will supply a default bound. |
|||
|
|
|
}; |
||
|
|
|
You can specify that bound with the |
||
|
(see |
|
|||
|
|
||||
|
11 below) |
|
|||
|
|
|
|
|
|
|
|
|
|
public ref class ArraysOfSequences |
|
|
array |
of |
struct ArraysOfSequences{ |
{ |
|
|
sequence<short,4> |
array<DDS::ShortSeq^>^ |
|||
|
sequences |
sequences_array[2]; |
sequences_array; |
||
|
|
|
}; |
// maximum length = (2) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
bounded |
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
||
|
System::String^ string_member; |
||||
|
string<20> string_member; |
||||
|
string |
|
// maximum length = (20) |
||
|
|
}; |
|||
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ref class PrimitiveStruct { |
|
|
|
|
struct PrimitiveStruct { |
System::String^ string_member; |
|
|
unbounded |
// maximum length = (255) |
|||
|
string string_member; |
||||
|
}; |
|
|||
|
string |
|
}; |
|
|
|
|
Note: rtiddsgen will supply a default bound. |
|||
|
|
|
|
||
|
|
|
|
You can specify that bound with the |
|
|
|
|
|
Size |
|
|
|
|
|
|
|
|
bounded |
struct PrimitiveStruct { |
public ref class PrimitiveStruct { |
||
|
System::String^ string_member; |
||||
|
wstring<20> wstring_member; |
||||
|
wstring |
// maximum length = (20) |
|||
|
}; |
||||
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ref class PrimitiveStruct { |
|
|
|
|
|
System::String^ string_member; // |
|
|
unbounded |
struct PrimitiveStruct { |
maximum length = (255) |
||
|
}; |
|
|||
|
wstring |
wstring wstring_member; |
|
||
|
}; |
Note: rtiddsgen will supply a default bound. |
|||
|
|
|
|||
|
|
|
|
You can specify that bound with the |
|
|
|
|
|
Size |
|
|
|
|
|
|
|
|
|
|
module PackageName { |
namespace PackageName { |
|
|
module |
struct Foo { |
public ref class Foo { |
||
|
long field; |
System::Int32 field; |
|||
|
|
|
}; |
}; |
|
|
|
|
}; |
}; |
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with IDL |
|
Table 3.7 Specifying Data Types in IDL for Java |
|
|
|||
|
|
|
|
|
|
|
IDL Type |
Sample Entry in IDL file |
Sample Java Output Generated by |
||
|
rtiddsgen |
||||
|
|
|
|
||
|
|
|
|
|
|
|
char |
|
|
public class PrimitiveStruct |
|
|
|
|
struct PrimitiveStruct { |
{ |
|
|
(see Note |
char char_member; |
public char char_member; |
||
|
}; |
... |
|
||
|
below) |
|
|
} |
|
|
|
|
|
|
|
|
wchar |
|
|
public class PrimitiveStruct |
|
|
|
|
struct PrimitiveStruct { |
{ |
|
|
(see Note |
wchar wchar_member; |
public char wchar_member; |
||
|
}; |
... |
|
||
|
below) |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public class PrimitiveStruct |
|
|
octet |
|
struct PrimitiveStruct { |
{ |
|
|
|
octet octet_member; |
public byte byte_member; |
||
|
|
|
}; |
... |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public class PrimitiveStruct |
|
|
short |
|
struct PrimitiveStruct { |
{ |
|
|
|
short short_member; |
public short short_member; |
||
|
|
|
}; |
... |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
unsigned |
|
struct PrimitiveStruct { |
public class PrimitiveStruct |
|
|
short |
|
|||
|
|
{ |
|
||
|
|
|
unsigned short |
|
|
|
|
|
public short unsigned_short_member; |
||
|
|
|
unsigned_short_member; |
||
|
(see Note |
... |
|
||
|
}; |
|
|||
|
} |
|
|||
|
below) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class PrimitiveStruct |
|
|
long |
|
struct PrimitiveStruct { |
{ |
|
|
|
long long_member; |
public int long_member; |
||
|
|
|
}; |
... |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
unsigned |
|
struct PrimitiveStruct { |
public class PrimitiveStruct |
|
|
long |
|
|||
|
|
{ |
|
||
|
|
|
unsigned long |
|
|
|
|
|
public int unsigned_long_member; |
||
|
|
|
unsigned_long_member; |
||
|
(see Note |
... |
|
||
|
}; |
|
|||
|
} |
|
|||
|
below) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class PrimitiveStruct |
|
|
long long |
|
struct PrimitiveStruct { |
{ |
|
|
|
long long long_long_member; |
public long long_long_member; |
||
|
|
|
}; |
... |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
unsigned |
|
|
public class PrimitiveStruct |
|
|
long long |
|
struct PrimitiveStruct { |
{ |
|
|
|
|
unsigned long long |
public long |
|
|
(see Note |
unsigned_long_long_member; |
unsigned_long_long_member; |
||
|
}; |
... |
|
||
|
below) |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public class PrimitiveStruct |
|
|
float |
|
struct PrimitiveStruct { |
{ |
|
|
|
float float_member; |
public float float_member; |
||
|
|
|
}; |
... |
|
|
|
|
|
} |
|
|
|
|
|
|
|
Creating User Data Types with IDL
Table 3.7 Specifying Data Types in IDL for Java
IDL Type |
Sample Entry in IDL file |
Sample Java Output Generated by |
||
rtiddsgen |
||||
|
|
|
||
|
|
|
|
|
|
|
|
public class PrimitiveStruct |
|
double |
|
struct PrimitiveStruct { |
{ |
|
|
double double_member; |
public double double_member; |
||
|
|
}; |
... |
|
|
|
|
} |
|
|
|
|
||
long double |
|
public class PrimitiveStruct |
||
|
|
struct PrimitiveStruct { |
{ |
|
(see Note |
long double long_double_member; |
public double long_double_member; |
||
}; |
... |
|||
below) |
|
|
} |
|
|
|
|
|
|
pointer |
|
struct MyStruct { |
public class MyStruct { |
|
|
public int member; |
|||
(see Note |
long * member; |
|||
... |
||||
below) |
|
}; |
||
|
}; |
|||
|
|
|
||
|
|
|
|
|
|
|
|
public class PrimitiveStruct |
|
|
|
struct PrimitiveStruct { |
{ |
|
boolean |
|
boolean boolean_member; |
public boolean boolean_member; |
|
|
|
}; |
... |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public class PrimitiveEnum extends Enum |
|
|
|
|
{ |
|
|
|
|
public static PrimitiveEnum ENUM1 = |
|
|
|
|
new PrimitiveEnum ("ENUM1", 0); |
|
|
|
enum PrimitiveEnum { |
public static PrimitiveEnum ENUM2 = |
|
|
|
ENUM1, |
new PrimitiveEnum ("ENUM2", 1); |
|
|
|
ENUM2, |
|
|
|
|
ENUM3 |
public static PrimitiveEnum ENUM3 = |
|
|
|
}; |
new PrimitiveEnum ("ENUM3", 2); |
|
|
|
|
public static PrimitiveEnum |
|
|
|
|
valueOf(int ordinal); |
|
|
|
|
... |
|
enum |
|
|
} |
|
|
|
|
||
|
|
public class PrimitiveEnum extends Enum |
||
|
|
|
||
|
|
|
{ |
|
|
|
|
public static PrimitiveEnum ENUM1 = |
|
|
|
|
new PrimitiveEnum ("ENUM1", 10); |
|
|
|
enum PrimitiveEnum { |
public static PrimitiveEnum ENUM2 = |
|
|
|
ENUM1 = 10, |
new PrimitiveEnum ("ENUM2", 10); |
|
|
|
ENUM2 = 20, |
|
|
|
|
ENUM3 = 30 |
public static PrimitiveEnum ENUM3 = |
|
|
|
}; |
new PrimitiveEnum ("ENUM3", 20); |
|
|
|
|
public static PrimitiveEnum |
|
|
|
|
valueOf(int ordinal); |
|
|
|
|
... |
|
|
|
|
} |
|
|
|
|
|
|
constant |
|
|
public class SIZE { |
|
|
const short SIZE = 5; |
public static final short VALUE = 5; |
||
|
|
|
} |
|
|
|
|
|
Creating User Data Types with IDL
Table 3.7 Specifying Data Types in IDL for Java
IDL Type |
Sample Entry in IDL file |
Sample Java Output Generated by |
||
rtiddsgen |
||||
|
|
|
||
|
|
|
|
|
|
|
struct BitfieldType { |
public class BitfieldType |
|
|
|
{ |
||
|
|
short myShort_1 : 1; |
||
|
|
public short myShort_1; |
||
|
|
long myLong_1: 1; |
||
|
|
public int myLong_1; |
||
|
|
char myChar_1 : 1; |
||
|
|
public byte myChar_1; |
||
|
|
wchar myWChar_1 : 1; |
||
|
|
public char myWChar_1; |
||
bitfield |
|
octet myOctet_1 : 1; |
||
|
public byte myOctet_1; |
|||
|
|
short : 0; |
||
|
|
public int myLong_5; |
||
|
|
long myLong_5 : 5; |
||
(see Note 12 |
public int myLong_30; |
|||
long myLong_30 : 30; |
||||
public short myShort_6; |
||||
below) |
|
short myShort_6 : 6; |
||
|
public short myShort_3and4; |
|||
|
|
short myShort_3and4 : 3+4; |
||
|
|
public short myShort; |
||
|
|
short myShort; |
||
|
|
public short myShort_8; |
||
|
|
short myShort_8 : 8; |
||
|
|
public int myLong_32; |
||
|
|
long myLong_32: 32; |
||
|
|
... |
||
|
|
}; |
||
|
|
} |
||
|
|
|
||
|
|
|
|
|
struct |
|
|
public class PrimitiveStruct |
|
|
struct PrimitiveStruct { |
{ |
||
|
|
|||
(see Note 10 |
char char_member; |
public char char_member; |
||
}; |
||||
below) |
|
|
} |
|
|
|
|
||
|
|
|
|
|
union |
|
union PrimitiveUnion switch (long){ |
public class PrimitiveUnion { |
|
|
case 1: |
public int _d; |
||
|
|
|||
|
|
short short_member; |
public short short_member; |
|
(see Note 10 |
default: |
public int long_member; |
||
below) |
|
long long_member; |
... |
|
|
}; |
} |
||
|
|
|||
|
|
|
|
|
typedef |
of |
|
/* typedefs are unwounded to the original |
|
primitives, |
|
|||
typedef short ShortType; |
type when used */ |
|||
enums, |
|
|||
|
|
public class PrimitiveStruct |
||
strings |
|
|
||
|
struct PrimitiveStruct { |
{ |
||
|
|
ShortType short_member; |
public short short_member; |
|
(see Note |
}; |
... |
||
below) |
|
|
} |
|
|
|
|
||
|
|
|
|
|
typedef |
of |
|
/* Wrapper class */ |
|
sequences |
|
|
public class ShortArray |
|
or arrays |
|
typedef short ShortArray[2]; |
{ |
|
|
public short[] userData = new |
|||
|
|
|
||
(see Note |
|
short[2]; |
||
|
... |
|||
below) |
|
|
} |
|
|
|
|
|
|
|
|
|
public class OneDArrayStruct |
|
|
|
struct OneDArrayStruct { |
{ |
|
|
|
public short[] short_array = new |
||
|
|
short short_array[2]; |
||
|
|
short[2]; |
||
|
|
}; |
||
|
|
... |
||
|
|
|
||
array |
|
|
} |
|
|
|
|
||
|
|
public class TwoDArrayStruct |
||
|
|
|
||
|
|
struct TwoDArrayStruct { |
{ |
|
|
|
public short[][] short_array = new |
||
|
|
short short_array[1][2]; |
||
|
|
short[1][2]; |
||
|
|
}; |
||
|
|
... |
||
|
|
|
||
|
|
|
} |
|
|
|
|
|
Creating User Data Types with IDL
Table 3.7 Specifying Data Types in IDL for Java
IDL Type |
Sample Entry in IDL file |
Sample Java Output Generated by |
||
rtiddsgen |
||||
|
|
|
||
|
|
|
|
|
|
|
|
public class SequenceStruct |
|
bounded |
|
|
{ |
|
sequence |
|
struct SequenceStruct { |
public ShortSeq short_sequence = new |
|
|
|
sequence<short,4> |
ShortSeq((4)); |
|
(see Note 11 |
short_sequence; |
... |
||
}; |
} |
|||
below) |
|
|
Note: Sequences of primitive types have been pre- |
|
|
|
|
defined by Connext. |
|
|
|
|
|
|
|
|
|
public class SequenceStruct |
|
unbounded |
|
{ |
||
|
public ShortSeq short_sequence = new |
|||
sequence |
|
struct SequenceStruct { |
ShortSeq((100)); |
|
|
|
sequence<short> short_sequence; |
... |
|
(see Note 11 |
}; |
} |
||
Note: rtiddsgen will supply a default bound. You |
||||
below) |
|
|
||
|
|
can specify that bound with the |
||
|
|
|
||
|
|
|
||
|
|
|
|
|
|
|
|
public class ArraysOfSequences |
|
array |
of |
struct ArraysOfSequences{ |
{ |
|
sequence<short,4> |
public ShortSeq[] sequences_array = |
|||
sequences |
|
sequences_array[2]; |
new ShortSeq[2]; |
|
|
|
}; |
... |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Wrapper class */ |
|
|
|
|
public class ShortArray |
|
|
|
|
{ |
|
|
|
|
public short[] userData = new |
|
|
|
|
short[2]; |
|
|
|
|
... |
|
|
|
|
} |
|
sequence |
of |
typedef short ShortArray[2]; |
/* Sequence of wrapper class objects */ |
|
arrays |
|
|
||
|
struct SequenceOfArrays{ |
public final class ShortArraySeq |
||
|
|
|||
|
|
extends ArraySequence |
||
|
|
sequence<ShortArray,2> |
||
(see Note 11 |
{ |
|||
arrays_sequence; |
||||
... |
||||
below) |
|
}; |
||
|
} |
|||
|
|
|
||
|
|
|
public class SequenceOfArrays |
|
|
|
|
{ |
|
|
|
|
public ShortArraySeq arrays_sequence |
|
|
|
|
= new ShortArraySeq((2)); |
|
|
|
|
... |
|
|
|
|
} |
|
|
|
|
|
Creating User Data Types with IDL
Table 3.7 Specifying Data Types in IDL for Java
IDL Type |
Sample Entry in IDL file |
Sample Java Output Generated by |
||
rtiddsgen |
||||
|
|
|
||
|
|
|
|
|
|
|
|
/* Wrapper class */ |
|
|
|
|
public class ShortSequence |
|
|
|
|
{ |
|
|
|
|
public ShortSeq userData = new |
|
|
|
|
ShortSeq((4)); |
|
|
|
|
... |
|
|
|
|
} |
|
sequence |
of |
typedef sequence<short,4> |
/* Sequence of wrapper class objects */ |
|
sequences |
|
ShortSequence; |
||
|
public final class ShortSequenceSeq |
|||
|
|
|
||
|
|
struct SequencesOfSequences{ |
extends ArraySequence |
|
(see Note |
{ |
|||
sequence<ShortSequence,2> |
||||
... |
||||
and Note 11 |
sequences_sequence; |
|||
} |
||||
below) |
|
}; |
||
|
|
|||
|
|
|
public class SequencesOfSequences |
|
|
|
|
{ |
|
|
|
|
public ShortSequenceSeq |
|
|
|
|
sequences_sequence = new |
|
|
|
|
ShortSequenceSeq((2)); |
|
|
|
|
... |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public class PrimitiveStruct |
|
|
|
|
{ |
|
bounded |
|
struct PrimitiveStruct { |
public String string_member = new |
|
|
string<20> string_member; |
String(); |
||
string |
|
|||
|
}; |
/* maximum length = (20) */ |
||
|
|
|||
|
|
|
... |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public class PrimitiveStruct |
|
|
|
|
{ |
|
|
|
|
public String string_member = new |
|
|
|
struct PrimitiveStruct { |
String(); |
|
unbounded |
/* maximum length = (255) */ |
|||
string |
|
string string_member; |
... |
|
|
}; |
|||
|
|
} |
||
|
|
|
||
|
|
|
Note: rtiddsgen will supply a default bound. You |
|
|
|
|
can specify that bound with the |
|
|
|
|
||
|
|
|
|
|
|
|
|
public class PrimitiveStruct |
|
|
|
|
{ |
|
bounded |
|
struct PrimitiveStruct { |
public String wstring_member = new |
|
|
wstring<20> wstring_member; |
String(); |
||
wstring |
|
|||
|
}; |
/* maximum length = (20) */ |
||
|
|
|||
|
|
|
... |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public class PrimitiveStruct |
|
|
|
|
{ |
|
unbounded |
struct PrimitiveStruct { |
public String wstring_member = new |
||
String(); |
||||
wstring |
|
wstring wstring_member; |
/* maximum length = (255) */ |
|
|
}; |
|||
|
|
... |
||
|
|
|
||
|
|
|
} |
|
|
|
|
Note: rtiddsgen will supply a default bound. |
|
|
|
|
|
Creating User Data Types with IDL
Table 3.7 Specifying Data Types in IDL for Java
IDL Type |
Sample Entry in IDL file |
Sample Java Output Generated by |
|
rtiddsgen |
|
||
|
|
|
|
|
|
|
|
|
|
package PackageName; |
|
|
module PackageName { |
|
|
|
struct Foo { |
public class Foo |
|
module |
long field; |
{ |
|
|
}; |
public int field; |
|
|
}; |
… |
|
|
|
} |
|
|
|
|
|
|
|
public class MyValueType |
{ |
|
|
public MyValueType2 member; |
|
|
valuetype MyValueType { |
…. |
|
|
public MyValueType2 * member; |
}; |
|
|
}; |
|
|
valuetype |
|
public class MyValueType |
{ |
|
valuetype MyValueType { |
public MyValueType2 member; |
|
(see Note 9 |
public MyValueType2 member; |
…. |
|
}; |
}; |
|
|
and Note 10 |
|
|
|
below) |
valuetype MyValueType: |
public class MyValueType extends |
|
|
MyBaseValueType { |
MyBaseValueType |
|
|
public MyValueType2 * member; |
{ |
|
|
}; |
public MyValueType2 member; |
|
|
|
…. |
|
|
|
} |
|
|
|
|
|
Notes for Table 3.5 through Table 3.7:
1.Note that in C and C++, primitive types are not represented as native language types (e.g. long, char, etc.) but as custom types in the DDS namespace (DDS_Long, DDS_Char, etc.). These typedefs are used to ensure that a field’s size is the same across platforms.
2.Some platforms do not support long double or have different sizes for that type than defined by IDL (16 bytes). On such platforms, DDS_LongDouble (as well as the unsigned version) is mapped to a character array that matches the expected size of that type by default. If you are using a platform whose native mapping has exactly the expected size, you can instruct Connext to use the native type instead. That is, if sizeof(long double) == 16, you can tell Connext to map DDS_LongDouble to long dou- ble by defining the following macro either in code or on the compile line:
Not
3.Unions in IDL are mapped to structs in C and C++, so that Connext will not have to dynamically allocate memory for unions containing
4.
sequence<sequence<short,4>,4> MySequence;
Sequences of typedef’ed types, where the typedef is really a sequence, are supported. For example, this is supported:
typedef sequence<short,4> MyShortSequence;
Creating User Data Types with IDL
Not
sequence<MyShortSequence,4> MySequence;
5.IDL wchar and char are mapped to Java char,
6.There are no unsigned types in Java. The unsigned version for integer types is mapped to its signed version as specified in the standard OMG IDL to Java mapping.
7.There is no current support in Java for the IDL long double type. This type is mapped to double as specified in the standard OMG IDL to Java mapping.
8.Java does not have a typedef construct, nor does C++/CLI. Typedefs for types that are neither arrays nor sequences (struct, unions, strings, wstrings, primitive types and enums) are "unwound" to their original type until a simple IDL type or
9.In C and C++, all the members in a value type, structure or union that are declared with the pointer symbol (‘*’) will be mapped to references (pointers). In C++/CLI and Java, the pointer symbol is ignored because the members are always mapped as references.
10.
struct Outer {
short outer_short; struct Inner {
char inner_char; short inner_short;
} outer_nested_inner;
};
|
11. The sequence <Type>Seq is implicitly declared in the IDL file and therefore it cannot be |
|
declared explicitly by the user. For example, this is not supported: |
Not |
|
typedef sequence<Foo> FooSeq; //error |
12.Data types containing bitfield members are not supported by DynamicData (Section 3.8).
3.3.5Escaped Identifiers
To use an IDL keyword as an identifier, the keyword must be “escaped” by prepending an underscore, ‘_’. In addition, you must run rtiddsgen with the
struct MyStruct {
octet _octet; // octet is a keyword. To use the type // as a member name we add ‘_’
};
The use of ‘_’ is a purely lexical convention that turns off keyword checking. The generated code will not contain ‘_’. For example, the mapping to C would be as follows:
struct MyStruct { unsigned char octet;
};
Note: If you generate code from an IDL file to a language ‘X’ (for example, C++), the keywords of this language cannot be used as IDL identifiers, even if they are escaped. For example:
struct MyStruct { long int; // error
Creating User Data Types with IDL
long _int; // error
};
3.3.6Referring to Other IDL Files
IDL files may refer to other IDL files using a syntax borrowed from C, C++, and C++/CLI pre- processors:
#include “Bar.idl”
If such a statement is encountered by rtiddsgen and you are generating code for C, C++, and C++/CLI, rtiddsgen will assume that code has been generated for Bar.idl with corresponding header files, Bar.h and BarPlugin.h.
The generated code will automatically have:
#include “Bar.h” #include “BarPlugin.h”
added where needed to compile correctly.
Because Java types do not refer to one another in the same way, it is not possible for rtiddsgen to automatically generate Java import statements based on an IDL #include statement. Any #include statements will be ignored when Java code is generated. To add imports to your gener- ated Java code, you should use the //@copy directive (see Section 3.3.8.2).
3.3.7Preprocessor Directives
rtiddsgen supports the standard preprocessor directives defined by the IDL specification, such as
#if, #endif, #include, and #define.
To support these directives, rtiddsgen calls an external C preprocessor before parsing the IDL file. On Windows systems, the preprocessor is ‘cl.exe.’ On other architectures, the preprocessor is ‘cpp.’ You can change the default preprocessor with the
3.3.8Using Custom Directives
The following
//@copy (see Section
Creating User Data Types with IDL
Custom directives start with “//@”. Note: Do not put a space between the slashes and the @, or the directive will not be recognized by rtiddsgen.
The directives are also
3.3.8.1The @key Directive
To declare a key for your data type, insert the @key directive in the IDL file after one or more fields of the data type.
With each key, Connext associates an internal
If the maximum size of the serialized key is greater than 16 bytes, to generate the
Only struct definitions in IDL may have key fields. When rtiddsgen encounters //@key, it consid- ers the previously declared field in the enclosing structure to be part of the key. Table 3.8 on page
Table 3.8 Example Keys
Type |
Key Fields |
|
|
|
|
|
|
|
struct NoKey { |
|
|
long member1; |
|
|
long member2; |
|
|
} |
|
|
|
|
|
struct SimpleKey { |
|
|
long member1; //@key |
member1 |
|
long member2; |
||
|
||
} |
|
|
|
|
|
struct NestedNoKey { |
|
|
SimpleKey member1; |
|
|
long member2; |
|
|
} |
|
|
|
|
|
struct NestedKey { |
|
|
SimpleKey member1; //@key |
member1.member1 |
|
long member2; |
||
|
||
} |
|
|
|
|
|
struct NestedKey2 { |
|
|
NoKey member1; //@key |
member1.member1 |
|
long member2; |
member1.member2 |
|
} |
|
|
|
|
|
valuetype BaseValueKey { |
|
|
public long member1; //@key |
member1 |
|
} |
|
|
|
|
|
valuetype DerivedValueKey :BaseValueKey { |
member1 |
|
public long member2; //@key |
||
member2 |
||
} |
||
|
||
|
|
|
valuetype DerivedValue : BaseValueKey { |
|
|
public long member2; |
member1 |
|
} |
|
|
|
|
|
struct ArrayKey { |
member1[0] |
|
long member1[3]; //@key |
member1[1] |
|
} |
member1[2] |
|
|
|
Creating User Data Types with IDL
3.3.8.2The @copy and Related Directives
To copy a line of text verbatim into the generated code files, use the @copy directive in the IDL file. This feature is particularly useful when you want your generated code to contain text that is valid in the target programming language but is not valid IDL. It is often used to add user com- ments or headers or preprocessor commands into the generated code.
//@copy // Modification History //@copy //
//@copy // 17Jul05aaa, Created. //@copy
//@copy // #include “MyTypes.h”
These variations allow you to use the same IDL file for multiple languages:
Table 3.9
Copies code if the language is C or C++ |
|
|
|
Copies code if the language is C++/CLI |
|
|
|
Copies code if the language is Java. |
|
|
|
Copies code if the language is Ada. |
|
|
|
For example, to add import statements to generated Java code:
The above line would be ignored if the same IDL file was used to generate
In C, C++, and C++/CLI, the lines are copied into all of the “foo*.[h, c, cxx, cpp]” files generated from “foo.idl”. For Java, the lines are copied into all of the “*.java” files that were generated from the original “.idl” file. The lines will not be copied into any additional files that are gener- ated using the
If you want rtiddsgen to copy lines only into the files that declare the data
Note that the first whitespace character to follow “//@copy” is considered a delimiter and will not be copied into generated files. All subsequent text found on the line, including any leading whitespaces will be copied.
Table 3.10
Copies the text into the file where the type is declared (<type>.h for C |
||
and C++, or <type>.java for Java) |
||
|
||
|
|
|
Same |
||
|
|
|
Same |
||
|
|
|
Same |
||
|
|
|
Same |
||
|
|
|
Same |
||
file where the type is declared |
||
|
||
|
|
|
Same |
||
|
|
Creating User Data Types with IDL
3.3.8.3The
In IDL, the “module” keyword is used to create namespaces for the declaration of types and classes defined within the file. Here is an example IDL definition:
module PackageName { struct Foo {
long field;
};
};
For C++ and C++/CLI, you may use the
namespace PackageName{ typedef struct Foo {
DDS_Long field;
}Foo;
}PackageName;
When generating C++/CLI, the
For C, or if you do not use the
typedef struct PackageName_Foo { DDS_Long field;
} PackageName_Foo;
In Java, a Foo.java file will be created in a directory called PackageName to use the equivalent concept as defined by Java. The file PackageName/Foo.java will contain a declaration of Foo class:
public class Foo { public int field;
...
};
In a more complicated example, consider the following IDL definition:
module PackageName { struct Bar {
long field;
};
struct Foo {
Bar barField;
};
};
When rtiddsgen generates code for the above definition, it will resolve the “Bar” type to be within the scope of the PackageName module and automatically generate
In C or C++, if you do not use
typedef struct PackageName_Bar { DDS_Long field;
} PackageName_Foo;
typedef struct PackageName_Foo { PackageName_Bar barField;
} PackageName_Foo;
Creating User Data Types with IDL
In C++, if you use
namespace PackageName { typedef struct Bar {
DDS_Long field; } Bar;
typedef struct Foo
{
PackageName::Bar barField; } Foo;
}
And in Java, PackageName/Bar.java and PackageName/Foo.java would be created with the following code respectively:
public class Bar { public int field;
...
};
and
public class Foo {
public PackageName.Bar barField = PackageName.Bar.create();
...
};
However, sometimes you may not want rtiddsgen to resolve the types of variables when mod- ules are used. In the example above, instead of referring to the Bar as defined by the same pack- age, you may want the barField in Foo to use Bar directly without prepending a module name. To specify that rtiddsgen should not resolve the scope of a type, use the
For example:
module PackageName { struct Bar {
long field;
};
struct Foo {
Bar
};
};
When this directive is used, then for the field preceding the directive, rtiddsgen respects the reso- lution of its type name indicated in the IDL file. It will use the type unmodified in the gener- ated code. In C and C++:
typedef struct PackageName_Bar { DDS_Long field;
} PackageName_Foo;
typedef struct PackageName_Foo { Bar barField;
} PackageName_Foo;
And in Java, in PackageName/Bar.java and PackageName/Foo.java respectively:
public class Bar { public int field;
...
Creating User Data Types with IDL
};
and
public class Foo {
public Bar barField = Bar.create();
...
};
It is up to you to include the correct header files (or if using Java, to import the correct packages) so that the compiler resolves the ‘Bar’ type correctly.
When used at the end of the declaration of a structure in IDL, then the directive applies to all types within the structure.
struct MyStructure { Foo member1;
Bar member2;
By default, without using the directive, rtiddsgen will try to resolve the type of a field and to use the fully qualified name in the generated code. If the type is not found to be defined within the same scope as the structure in which it is used or in a parent scope, then rtiddsgen will generate code with just the type name itself, assuming that the name will be resolved by the compiler through other means available to the user (header files or import statements). A type is in the same scope as the structure if both the type and the structure in which it is used are defined within the same module.
3.3.8.4The
By default, rtiddsgen generates
We use the term
You can mark
In this example, rtiddsgen will generate DataWriter/DataReader code for TopLevelStruct only:
struct EmbeddedStruct{ short member;
struct TopLevelStruct{ EmbeddedStruct member;
};
Creating User Data Types with Extensible Markup Language (XML)
3.4Creating User Data Types with Extensible Markup Language (XML)
You can describe user data types with Extensible Markup Language (XML) notation. Connext provides DTD and XSD files that describe the XML format; see <NDDSHOME>/resource/ qos_profiles_5.0.x/rtiddsgen/schema/rti_dds_topic_types.dtd and <NDDSHOME>/resource/ qos_profiles_5.0.x/rtiddsgen/schema/rti_dds_topic_types.xsd, respectively (in 5.0.x, the x stands for the revision number of the current release).
The XML validation performed by rtiddsgen always uses the DTD definition. If the <!DOC- TYPE> tag is not in the XML file, rtiddsgen will look for the default DTD document in <NDDSHOME>/resource/rtiddsgen/schema. Otherwise, it will use the location specified in <!DOCTYPE>.
We recommend including a reference to the XSD/DTD files in the XML documents. This pro- vides helpful features in code editors such as Visual Studio® and Eclipse™, including validation and
To include a reference to the XSD document in your XML file, use the attribute xsi:noNamespaceSchemaLocation in the <types> tag. For example1:
<?xml version="1.0"
<types
"<same as NDDSHOME>/resource/rtiddsgen/schema/rti_dds_topic_types.xsd">
...
</types>
To include a reference to the DTD document in your XML file, use the <!DOCTYPE> tag. For example1:
<?xml version="1.0"
<!DOCTYPE types SYSTEM
"<same as NDDSHOME>/resource/rtiddsgen/schema/rti_dds_topic_types.dtd"> <types>
...
</types>
Table 3.11 shows how to map the type system constructs into XML.
Table 3.11 Mapping Type System Constructs to XML
Type/Construct |
|
Example |
||
|
|
|
|
|
IDL |
XML |
IDL |
XML |
|
|
|
|
|
|
|
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
char |
char |
<member name="char_member" |
||
char char_member; |
||||
type="char"/> |
||||
|
|
}; |
||
|
|
</struct> |
||
|
|
|
||
|
|
|
|
|
|
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
wchar |
wchar |
<member name="wchar_member" |
||
wchar wchar_member; |
||||
type="wchar"/> |
||||
|
|
}; |
||
|
|
</struct> |
||
|
|
|
||
|
|
|
|
1. Replace <same as NDDSHOME> with the full path to the Connext installation directory.
Creating User Data Types with Extensible Markup Language (XML)
Table 3.11 Mapping Type System Constructs to XML
Type/Construct |
|
Example |
|||
|
|
|
|
||
IDL |
XML |
IDL |
XML |
||
|
|
|
|
|
|
|
|
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
octet |
octet |
|
<member name="octet_member" |
||
|
octet octet_member; |
||||
|
type="octet"/> |
||||
|
|
|
}; |
||
|
|
|
</struct> |
||
|
|
|
|
||
|
|
|
|
|
|
|
|
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
short |
short |
|
<member name="short_member" |
||
|
short short_member; |
||||
|
type="short"/> |
||||
|
|
|
}; |
||
|
|
|
</struct> |
||
|
|
|
|
||
|
|
|
|
|
|
unsigned |
|
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
unsignedShort |
unsigned short |
<member name="unsigned_short_member" |
|||
short |
unsigned_short_member; |
type="unsignedShort"/> |
|||
|
|
||||
|
|
|
}; |
</struct> |
|
|
|
|
|
|
|
long |
long |
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
|
long long_member; |
<member name="long_member"type="long"/> |
|||
|
|
|
}; |
</struct> |
|
|
|
|
|
|
|
unsigned |
|
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
unsignedLong |
unsigned long |
<member name= "unsigned_long_member" |
|||
long |
unsigned_long_member; |
type="unsignedLong"/> |
|||
|
|
||||
|
|
|
}; |
</struct> |
|
|
|
|
|
|
|
|
|
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
long long |
longLong |
|
long long |
<member name="long_long_member" |
|
|
long_long_member; |
type="longLong"/> |
|||
|
|
|
|||
|
|
|
}; |
</struct> |
|
|
|
|
|
|
|
unsigned |
unsigned- |
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
|
unsigned long long |
<member name="unsigned_long_long_member" |
|||
long long |
LongLong |
unsigned_long_long_member; |
type="unsignedLongLong"/> |
||
|
|
|
}; |
</struct> |
|
|
|
|
|
|
|
|
|
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
float |
float |
|
<member name="float_member" |
||
|
float float_member; |
||||
|
type="float"/> |
||||
|
|
|
}; |
||
|
|
|
</struct> |
||
|
|
|
|
||
|
|
|
|
|
|
|
|
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
double |
double |
|
<member name="double_member" |
||
|
double double_member; |
||||
|
type="double"/> |
||||
|
|
|
}; |
||
|
|
|
</struct> |
||
|
|
|
|
||
|
|
|
|
|
|
long dou- |
|
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
longDouble |
long double |
<member name= "long_double_member" |
|||
ble |
|
|
long_double_member; |
type="longDouble"/> |
|
|
|
|
}; |
</struct> |
|
|
|
|
|
|
|
|
|
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
boolean |
boolean |
|
<member name="boolean_member" |
||
|
boolean boolean_member; |
||||
|
type="boolean"/> |
||||
|
|
|
}; |
||
|
|
|
</struct> |
||
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
<struct name="PrimitiveStruct"> |
|
|
string |
without |
|
<member name="string_member" |
|
|
|
type="string"/> |
|||
unbounde |
stringMaxLength |
struct PrimitiveStruct { |
</struct> |
||
attribute or with |
string string_member; |
or |
|||
d string |
stringMaxLength |
}; |
<struct name="PrimitiveStruct"> |
||
|
|||||
|
set to |
|
|
<member name="string_member" |
|
|
|
|
|
type="string" |
|
|
|
|
|
</struct> |
|
|
|
|
|
|
|
bounded |
string with string- |
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
||
<member name="string_member" |
|||||
MaxLength attri- |
string<20> string_member; |
||||
string |
type="string" stringMaxLength="20"/> |
||||
bute |
|
}; |
|||
|
|
</struct> |
|||
|
|
|
|
||
|
|
|
|
|
Creating User Data Types with Extensible Markup Language (XML)
Table 3.11 Mapping Type System Constructs to XML
Type/Construct |
|
|
Example |
|||
|
|
|
|
|
||
IDL |
XML |
|
IDL |
XML |
||
|
|
|
|
|
|
|
|
|
|
|
|
<struct name="PrimitiveStruct"> |
|
|
wstring |
without |
|
<member name="wstring_member" |
||
|
|
type="wstring"/> |
||||
unbounde |
stringMaxLength |
struct PrimitiveStruct { |
</struct> |
|||
attribute |
or |
with |
wstring wstring_member; |
or |
||
d wstring |
stringMaxLength |
}; |
<struct name="PrimitiveStruct"> |
|||
|
||||||
|
set to |
|
|
|
<member name="wstring_member" |
|
|
|
|
|
|
type="wstring" |
|
|
|
|
|
|
</struct> |
|
|
|
|
|
|
|
|
bounded |
wstring |
|
with |
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
stringMaxLength |
wstring<20> |
<member name="wstring_member" |
||||
wstring |
wstring_member; |
type="wstring" stringMaxLength="20"/> |
||||
attribute |
|
|
||||
|
|
|
}; |
</struct> |
||
|
|
|
|
|||
|
|
|
|
|
||
|
pointer |
attribute |
|
|
||
|
with |
values |
struct PrimitiveStruct { |
<struct name="PointerStruct"> |
||
|
<member name="long_member" type="long" |
|||||
pointer |
true,false,0 or 1 |
long * long_member; |
||||
pointer="true"/> |
||||||
|
Default |
(if |
not |
}; |
||
|
</struct> |
|||||
|
present): 0 |
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
<struct name="BitFieldStruct"> |
|
|
|
|
|
struct BitfieldStruct { |
<member name="short_member" |
|
|
bitfield |
attribute |
short short_member: 1; |
type="short" bitField="1"/> |
||
bitfielda |
unsigned short |
<member name="unsignedShort_member" |
||||
with the |
bitfield |
unsignedShort_member: 1; |
type="unsignedShort" bitField="1"/> |
|||
|
length |
|
|
short short_nmember_2: 0; |
<member type="short" bitField="0"/> |
|
|
|
|
|
long long_member : 5; |
<member name="long_member" |
|
|
|
|
|
}; |
type="long" bitField="5"/> |
|
|
|
|
|
|
</struct> |
|
|
|
|
|
|||
|
key attribute with |
|
|
|||
|
values true, false, |
struct KeyedPrimitiveStruct |
<struct name="KeyedPrimitiveStruct"> |
|||
key direc- |
0 or 1 |
|
|
{ |
||
|
|
<member name="short_member" |
||||
|
|
short short_member; // |
||||
tive b |
|
|
|
type="short" key="true"/> |
||
|
|
|
@key |
|||
|
Default |
(if |
not |
</struct> |
||
|
}; |
|||||
|
|
|||||
|
present): 0 |
|
|
|
||
|
|
|
|
|
||
|
resolveName |
|
|
|
||
|
attribute with val- |
struct |
<struct name= |
|||
resolve- |
ues true, |
false, 0 |
UnresolvedPrimitiveStruct { |
"UnresolvedPrimitiveStruct"> |
||
name |
or 1 |
|
|
PrimitiveStruct |
<member name="primitive_member" |
|
|
|
primitive_member; |
type="PrimitiveStruct" |
|||
directive b |
|
|
|
|||
|
|
|
resolveName="false"/> |
|||
|
Default |
(if |
not |
|||
|
}; |
</struct> |
||||
|
present): 1 |
|
|
|
||
|
|
|
|
|
|
|
|
topLevel |
|
|
|
|
|
|
attribute with val- |
|
<struct name="TopLevelPrimitiveStruct" |
|||
|
ues true, |
false, 0 |
struct |
|||
topLevel="false"> |
||||||
or 1 |
|
|
TopLevelPrimitiveStruct { |
|||
|
|
<member name="short_member" |
||||
directive b |
|
|
short short_member; |
|||
|
|
|
type="short"/> |
|||
|
|
|
|
|||
|
Default |
(if |
not |
</struct> |
||
|
|
|||||
|
|
|
||||
|
present): 1 |
|
|
|
||
|
|
|
|
|
|
|
Other |
|
|
|
//@copy This text will be |
<directive kind="copy"> |
|
directive tag |
|
This text will be copied in the |
||||
|
copied in the generated |
|||||
directives b |
|
generated files |
||||
|
|
|
|
|
||
|
|
|
|
files |
</directive> |
|
|
|
|
|
|
||
|
|
|
|
|
|
Creating User Data Types with Extensible Markup Language (XML)
Table 3.11 Mapping Type System Constructs to XML
Type/Construct |
|
Example |
||
|
|
|
|
|
IDL |
XML |
IDL |
XML |
|
|
|
|
|
|
|
|
enum PrimitiveEnum { |
<enum name="PrimitiveEnum"> |
|
|
|
ENUM1, |
<enumerator name="ENUM1"/> |
|
|
|
ENUM2, |
<enumerator name="ENUM2"/> |
|
|
|
ENUM3 |
<enumerator name="ENUM3"/> |
|
enum |
enum tag |
}; |
</enum> |
|
|
|
|||
enum PrimitiveEnum { |
<enum name="PrimitiveEnum"> |
|||
|
|
|||
|
|
ENUM1 = 10, |
<enumerator name="ENUM1" value="10"/> |
|
|
|
ENUM2 = 20, |
<enumerator name="ENUM2" value="20"/> |
|
|
|
ENUM3 = 30 |
<enumerator name="ENUM3" value="30"/> |
|
|
|
}; |
</enum> |
|
|
|
|
|
|
constant |
const tag |
const double PI = 3.1415; |
<const name="PI" type="double" |
|
value="3.1415"/> |
||||
|
|
|
||
|
|
|
|
|
|
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
|
struct |
struct tag |
<member name="short_member" |
||
short short_member; |
||||
type="short"/> |
||||
|
|
}; |
||
|
|
</struct> |
||
|
|
|
||
|
|
|
|
|
|
|
|
<union name="PrimitiveUnion"> |
|
|
|
|
<discriminator type="long"/> |
|
|
|
|
<case> |
|
|
|
|
<caseDiscriminator value="1"/> |
|
|
|
union PrimitiveUnion switch |
<member name="short_member" |
|
|
|
type="short"/> |
||
|
|
(long) { |
||
|
|
</case> |
||
|
|
case 1: |
||
|
|
<case> |
||
|
|
short short_member; |
||
|
|
<caseDiscriminator value="2"/> |
||
union |
union tag |
case 2: |
||
<caseDiscriminator value="3"/> |
||||
case 3: |
||||
|
|
<member name="float_member" |
||
|
|
float float_member; |
||
|
|
type="float"/> |
||
|
|
default: |
||
|
|
</case> |
||
|
|
long long_member; |
||
|
|
<case> |
||
|
|
}; |
||
|
|
<caseDiscriminator value="default"/> |
||
|
|
|
||
|
|
|
<member name="long_member" |
|
|
|
|
type="long"/> |
|
|
|
|
</case> |
|
|
|
|
</union> |
|
|
|
|
|
|
|
|
valuetype BaseValueType { |
<valuetype name="BaseValueType"> |
|
|
|
<member name="long_member" |
||
|
|
public long long_member; |
||
|
|
type="long" visibility="public"/> |
||
|
|
}; |
||
|
|
</valuetype> |
||
|
|
|
||
valuetype |
valuetype tag |
valuetype DerivedValueType: |
<valuetype name="DerivedValueType" |
|
|
|
BaseValueType { |
||
|
|
baseClass="BaseValueType"> |
||
|
|
public long |
||
|
|
<member name="long_member_2" |
||
|
|
long_member_2; |
||
|
|
type="long" visibility="public"/> |
||
|
|
}; |
||
|
|
</valuetype> |
||
|
|
|
||
|
|
|
|
|
|
|
typedef short ShortType; |
<typedef name="ShortType" type="short"/> |
|
|
|
|
|
|
|
|
|
<struct name="PrimitiveStruct"> |
|
|
|
struct PrimitiveStruct { |
<member name="short_member" |
|
|
|
type="short"/> |
||
typedef |
typedef tag |
short short_member; |
||
</struct> |
||||
}; |
||||
|
|
|
||
|
|
typedef PrimitiveStruct |
<typedef name="PrimitiveStructType" |
|
|
|
PrimitiveStructType; |
||
|
|
type="nonBasic" |
||
|
|
|
||
|
|
|
nonBasicTypeName="PrimitiveStruct"/> |
|
|
|
|
|
Creating User Data Types with Extensible Markup Language (XML)
Table 3.11 Mapping Type System Constructs to XML
Type/Construct |
|
|
Example |
||||
|
|
|
|
|
|
|
|
IDL |
|
|
XML |
|
IDL |
XML |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct OneArrayStruct { |
<struct name="OneArrayStruct"> |
|
|
|
|
|
|
<member name="short_array" |
|
|
|
|
|
|
|
short short_array[2]; |
|
|
|
|
|
|
|
type="short" arrayDimensions="2"/> |
|
|
|
|
|
|
|
}; |
|
|
|
Attribute |
|
|
</struct> |
||
arrays |
|
|
|
|
|||
|
arrayDimensions |
struct TwoArrayStruct { |
<struct name="TwoArrayStruct"> |
||||
|
|
||||||
|
|
|
|
|
|
<member name="short_array" |
|
|
|
|
|
|
|
short short_array[1][2]; |
|
|
|
|
|
|
|
type="short" arrayDimensions="1,2"/> |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
</struct> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Attribute |
|
|
struct SequenceStruct { |
<struct name="SequenceStruct"> |
|
bounded |
|
|
|
<member name="short_sequence" |
|||
|
|
|
sequence<short,4> |
||||
|
sequence- |
|
|
type="short" |
|||
sequence |
|
|
|
short_sequence; |
|||
|
MaxLength > 0 |
|
sequenceMaxLength="4"/> |
||||
|
|
|
}; |
||||
|
|
|
|
|
|
</struct> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Attribute |
|
|
struct SequenceStruct { |
<struct name="SequenceStruct"> |
|
unbounde |
sequence- |
|
|
sequence<short> |
<member name="short_sequence" |
||
d sequence |
MaxLength set to |
short_sequence; |
type="short" |
||||
|
|
|
|
|
}; |
</struct> |
|
|
|
|
|
|
|
||
|
|
Attributes |
|
struct |
<struct name= "ArrayOfSequenceStruct"> |
||
|
|
sequence- |
|
|
|||
array |
of |
|
|
ArrayOfSequencesStruct { |
<member name= "short_sequence_array" |
||
MaxLength |
|
sequence<short,4> |
type="short" arrayDimensions="2" |
||||
sequences |
And arrayDimen- |
short_sequence_array[2]; |
sequenceMaxLength="4"/> |
||||
|
|
||||||
|
|
sions |
|
|
|
}; |
</struct> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<typedef name="ShortArray" |
|
|
|
|
|
|
typedef short |
type="short" dimensions="2"/> |
|
|
|
|
|
|
ShortArray[2]; |
|
sequence |
|
Must |
be |
imple- |
|
<struct name= |
|
|
struct |
"SequenceOfArrayStruct"> |
|||||
|
mented |
with |
a |
||||
of arrays |
|
typedef tag |
|
SequenceOfArraysStruct { |
<member name= "short_array_sequence" |
||
|
|
|
sequence<ShortArray,2> |
type="nonBasic" |
|||
|
|
|
|
|
|
||
|
|
|
|
|
|
short_array_sequence; |
nonBasicTypeName="ShortSequence" |
|
|
|
|
|
|
}; |
sequenceMaxLength="2"/> |
|
|
|
|
|
|
|
</struct> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef sequence<short,4> |
<typedef name="ShortSequence" |
|
|
|
|
|
|
ShortSequence; |
|
|
|
|
|
|
|
type="short"sequenceMaxLength="4"/> |
|
|
|
|
|
|
|
|
|
sequence |
|
Must |
be |
imple- |
struct |
<struct name="SequenceofSequencesStruct"> |
|
|
<member name="short_sequence_sequence" |
||||||
of |
|
mented |
with |
a |
SequenceOfSequencesStruct |
||
|
type="nonBasic" |
||||||
sequences |
typedef tag |
|
{ |
||||
|
nonBasicTypeName="ShortSequence" |
||||||
|
|
|
|
|
|
sequence<ShortSequence,2> |
|
|
|
|
|
|
|
||
|
|
|
|
|
|
short_sequence_sequence; |
|
|
|
|
|
|
|
</struct> |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module PackageName { |
<module name="PackageName"> |
module |
|
module tag |
|
struct PrimitiveStruct { |
<struct name="PrimitiveStruct"> |
||
|
|
long long_member; |
<member name="long_member" type="long"/> |
||||
|
|
|
|
|
|
}; |
</struct> |
|
|
|
|
|
|
}; |
</module> |
|
|
|
|
|
|
|
|
include |
|
include tag |
|
#include |
<include file="PrimitiveTypes.xml"/> |
||
|
|
"PrimitiveTypes.idl" |
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
a.Data types containing bitfield members are not supported by DynamicData (Section 3.8).
b.Directives are RTI extensions to the standard IDL grammar. For additional information about directives see Using Custom Directives (Section 3.3.8).
Creating User Data Types with XML Schemas (XSD)
3.5Creating User Data Types with XML Schemas (XSD)
You can describe data types with XML schemas (XSD), either independent or embedded in a Web Services Description Language (WSDL) file. The format is based on the standard
Example Header for XSD:
<?xml version="1.0"
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:dds="http://www.omg.org/dds"
……
</xsd:schema>
Example Header for WSDL:
<?xml version="1.0"
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:dds="http://www.omg.org/dds" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
<xsd:schema
schemaLocation="rti_dds_topic_types_common.xsd"/>
……
</xsd:schema>
</types>
</definitions>
Table 3.12 describes how to map IDL types to XSD. The Connext code generator, rtiddsgen, will only accept XSD or WSDL files that follow this mapping.
Table 3.12 Mapping Type System Constructs to XSD
Type/Construct |
|
Example |
|
|
|
|
|
IDL |
XSD |
IDL |
XSD |
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
|
|
|
<xsd:sequence> |
char |
dds:chara |
struct PrimitiveStruct { |
<xsd:element name="char_member" |
char char_member; |
minOccurs="1" maxOccurs="1" |
||
|
|
}; |
type="dds:char"> |
|
|
|
</xsd:sequence> |
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
Creating User Data Types with XML Schemas (XSD) |
||
|
Table 3.12 Mapping Type System Constructs to XSD |
|
|
|||
|
|
|
|
|||
|
Type/Construct |
|
Example |
|||
|
|
|
|
|
||
|
IDL |
XSD |
IDL |
XSD |
||
|
|
|
|
|
||
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
||
|
|
|
|
<xsd:sequence> |
||
|
|
dds:wchara |
struct PrimitiveStruct { |
<xsd:element name="wchar_member" |
||
wchar |
wchar wchar_member; |
minOccurs="1" maxOccurs="1" |
||||
|
|
|
}; |
type="dds:wchar"> |
||
|
|
|
|
</xsd:sequence> |
||
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
||
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
||
|
|
|
|
<xsd:sequence> |
||
octet |
xsd:unsignedByte |
struct PrimitiveStruct { |
<xsd:element name="octet_member" |
|||
octet octet_member; |
minOccurs="1" maxOccurs="1" |
|||||
|
|
|
}; |
type="xsd:unsignedByte"> |
||
|
|
|
|
</xsd:sequence> |
||
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
||
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
||
|
|
|
|
<xsd:sequence> |
||
|
|
|
struct PrimitiveStruct { |
<xsd:element name="short_member" |
||
short |
xsd:short |
short short_member; |
minOccurs="1" maxOccurs="1" |
|||
|
|
|
}; |
type="xsd:short"/> |
||
|
|
|
|
</xsd:sequence> |
||
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
||
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
||
|
|
|
struct PrimitiveStruct { |
<xsd:sequence> |
||
unsigned |
xsd:unsigned- |
<xsd:element name="unsigned_short_member" |
||||
unsigned short |
||||||
minOccurs="1" maxOccurs="1" |
||||||
short |
Short |
unsigned_short_member; |
||||
type="xsd:unsignedShort"/> |
||||||
|
|
|
}; |
|||
|
|
|
</xsd:sequence> |
|||
|
|
|
|
|||
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
||
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
||
|
|
|
|
<xsd:sequence> |
||
long |
xsd:int |
struct PrimitiveStruct { |
<xsd:element name="long_member" |
|||
long long_member; |
minOccurs="1" maxOccurs="1" |
|||||
|
|
|
}; |
type="xsd:int"/> |
||
|
|
|
|
</xsd:sequence> |
||
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
||
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
||
|
|
|
struct PrimitiveStruct { |
<xsd:sequence> |
||
unsigned |
|
<xsd:element name= "unsigned_long_member" |
||||
|
unsigned long |
|||||
xsd:unsignedInt |
minOccurs="1" maxOccurs="1" |
|||||
long |
unsigned_long_member; |
|||||
|
type="xsd:unsignedInt"/> |
|||||
|
|
|
}; |
|||
|
|
|
</xsd:sequence> |
|||
|
|
|
|
|||
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
||
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
||
|
|
|
struct PrimitiveStruct { |
<xsd:sequence> |
||
|
|
|
<xsd:elementname= "long_long_member" |
|||
long long |
xsd:long |
long long |
||||
minOccurs="1" maxOccurs="1" |
||||||
long_long_member; |
||||||
|
|
|
type="xsd:long"/> |
|||
|
|
|
}; |
|||
|
|
|
</xsd:sequence> |
|||
|
|
|
|
|||
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with XML Schemas (XSD) |
|
|
Table 3.12 Mapping Type System Constructs to XSD |
|
|
|||
|
|
|
|
|
|
|
|
Type/Construct |
|
|
Example |
|
|
|
|
|
|
|
|
|
|
IDL |
XSD |
|
IDL |
XSD |
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
|
|
|
|
|
|
<xsd:sequence> |
|
unsigned |
xsd:unsigned- |
struct PrimitiveStruct { |
<xsd:element name= |
|
||
unsigned long long |
"unsigned_long_long_member" |
|
||||
long long |
Long |
|
unsigned_long_long_member; |
minOccurs="1" maxOccurs="1" |
|
|
|
|
|
|
}; |
type="xsd:unsignedLong"/> |
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
|
|
|
|
|
|
<xsd:sequence> |
|
|
|
|
|
struct PrimitiveStruct { |
<xsd:element name="float_member" |
|
float |
xsd:float |
|
float float_member; |
minOccurs="1" maxOccurs="1" |
|
|
|
|
|
|
}; |
type="xsd:float"/> |
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
|
|
|
|
|
|
<xsd:sequence> |
|
double |
xsd:double |
|
struct PrimitiveStruct { |
<xsd:element name="double_member" |
|
|
|
double double_member; |
minOccurs="1" maxOccurs="1" |
|
|||
|
|
|
|
}; |
type="xsd:double"/> |
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
|
|
|
|
|
struct PrimitiveStruct { |
<xsd:sequence> |
|
long |
|
|
<xsd:element name="long_double_member" |
|
||
dds:longDoublea |
long double |
|
||||
minOccurs="1" maxOccurs="1" |
|
|||||
double |
long_double_member; |
|
||||
|
|
type="dds:longDouble"/> |
|
|||
|
|
|
|
}; |
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
|
|
|
|
|
struct PrimitiveStruct { |
<xsd:sequence> |
|
|
|
|
|
<xsd:element name="boolean_member" |
|
|
boolean |
xsd:boolean |
|
boolean |
|
||
|
minOccurs="1" maxOccurs="1" |
|
||||
|
boolean_member; |
|
||||
|
|
|
|
type="xsd:boolean"/> |
|
|
|
|
|
|
}; |
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
|
|
|
|
|
|
<xsd:sequence> |
|
unbounded |
xsd:string |
|
struct PrimitiveStruct { |
<xsd:element name="string_member" |
|
|
|
string string_member; |
minOccurs="1" maxOccurs="1" |
|
|||
string |
|
|
}; |
type="xsd:string"/> |
|
|
|
|
|
|
|
||
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
|
|
|
|
|
|
<xsd:sequence> |
|
|
|
|
|
|
<xsd:element name="string_member" |
|
|
|
|
|
|
minOccurs="1" maxOccurs="1"> |
|
|
|
xsd:string |
with |
|
<xsd:simpleType> |
|
|
|
struct PrimitiveStruct { |
<xsd:restriction base="xsd:string"> |
|
||
bounded |
restriction |
to |
|
|||
string |
specify the maxi- |
string<20> string_member; |
<xsd:maxLength value="20" |
|
||
}; |
fixed="true"/> |
|
||||
|
|
mum length |
|
|
</xsd:restriction> |
|
|
|
|
|
|
|
|
|
|
|
|
|
</xsd:simpleType> |
|
|
|
|
|
|
</xsd:element> |
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with XML Schemas (XSD) |
|
|
Table 3.12 Mapping Type System Constructs to XSD |
|
|
||||
|
|
|
|
|
|
||
|
Type/Construct |
|
|
Example |
|
||
|
|
|
|
|
|
|
|
|
IDL |
XSD |
|
IDL |
XSD |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
|
|
|
|
|
|
|
<xsd:sequence> |
|
unbounded |
dds:wstringa |
|
struct PrimitiveStruct { |
<xsd:element name="wstring_member" |
|
||
|
wstring wstring_member; |
minOccurs="1" maxOccurs="1" |
|
||||
wstring |
|
|
|
}; |
type="dds:wstring"/> |
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
|
|
|
|
|
|
|
<xsd:sequence> |
|
|
|
|
|
|
|
<xsd:element name="wstring_member" |
|
|
|
|
|
|
|
minOccurs="1" maxOccurs="1"> |
|
|
|
xsd:wstring |
with |
|
<xsd:simpleType> |
|
|
|
|
struct PrimitiveStruct { |
<xsd:restriction base= |
|
|||
bounded |
restriction |
to |
wstring<20> |
"dds:wstring"> |
|
||
wstring |
specify the maxi- |
wstring_member; |
<xsd:maxLength value="20" |
|
|||
|
|
mum length |
|
}; |
fixed="true"/> |
|
|
|
|
|
|
|
|
</xsd:restriction> |
|
|
|
|
|
|
|
</xsd:simpleType> |
|
|
|
|
|
|
|
</xsd:element> |
|
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
|
|
|
@pointer |
|
<xsd:sequence> |
|
||
|
|
<true|false|1|0> |
struct PrimitiveStruct { |
<xsd:element name="long_member" |
|
||
|
|
minOccurs="1" maxOccurs="1" |
|
||||
pointer |
|
|
long * long_member; |
|
|||
|
|
type="xsd:int"/> |
|
||||
|
|
Default |
(if |
not |
}; |
|
|
|
|
|
|||||
|
|
specified): false |
|
|
|||
|
|
|
</xsd:sequence> |
|
|||
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="BitfieldStruct"> |
|
|
|
|
|
|
|
<xsd:sequence> |
|
|
|
|
|
|
|
<xsd:element name="short_member" |
|
|
|
|
|
|
|
minOccurs="1" maxOccurs="1" |
|
|
|
|
|
|
|
type="xsd:short"/> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct BitfieldStruct { |
<xsd:element name=‘unsignedShort_member" |
|
|
|
|
|
|
short short_member: 1; |
minOccurs="1" maxOccurs="1" |
|
|
|
|
unsigned short |
type="xsd:unsignedShort"/> |
|
||
bitfieldb |
|
unsignedShort_member: 1; |
|
||||
<bitfield length> |
|
||||||
short: 0; |
<xsd:element name="_ANONYMOUS_3" |
|
|||||
|
|
|
|
|
|||
|
|
|
|
long long_member: 5; |
minOccurs="1" maxOccurs="1" |
|
|
|
|
|
|
|
|
||
|
|
|
|
|
}; |
type="xsd:short"/> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:element name="long_member" |
|
|
|
|
|
|
|
minOccurs="1" maxOccurs="1" |
|
|
|
|
|
|
|
type="xsd:int"/> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="KeyedPrimitiveStruct"> |
|
||
|
|
|
|
|
|
<xsd:sequence> |
|
key |
<true|false|1|0> |
struct |
<xsd:element name="long_member" |
|
|||
|
|
KeyedPrimitiveStruct { |
minOccurs="1" maxOccurs="1" |
|
|||
directivec |
|
|
long long_member; //@key |
type="xsd:int"/> |
|
||
|
|
|
|
||||
|
|
|
|
|
}; |
|
|
|
|
Default |
(if |
not |
|
</xsd:sequence> |
|
|
|
specified): false |
|
</xsd:complexType> |
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with XML Schemas (XSD) |
|
|
Table 3.12 Mapping Type System Constructs to XSD |
|
|
||||
|
|
|
|
|
|
||
|
Type/Construct |
|
|
Example |
|
||
|
|
|
|
|
|
|
|
|
IDL |
XSD |
|
IDL |
XSD |
|
|
|
|
|
|
|
|
|
|
|
|
@resolve- |
|
<xsd:complexType name= |
|
||
|
|
Name |
|
|
struct |
"UnresolvedPrimitiveStruct"> |
|
resolve- |
|
|
|
UnresolvedPrimitiveStruct |
<xsd:sequence> |
|
|
<true|false|1|0> |
{ |
<xsd:element name="primitive_member" |
|
||||
name direc- |
|
|
PrimitiveStruct |
minOccurs="1" maxOccurs="1" |
|
||
tivec |
|
|
|
primitive_member; |
type="PrimitiveStruct"/> |
|
|
|
|
|
|
|
|
||
|
|
Default |
(if |
not |
}; |
</xsd:sequence> |
|
|
|
specified): true |
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType |
|
|
|
@topLevel |
|
name="TopLevelPrimitiveStruct"> |
|
||
|
|
<true|false|1|0> |
struct |
<xsd:sequence> |
|
||
|
|
<xsd:element name="short_member" |
|
||||
|
|
TopLevelPrimitiveStruct { |
|
||||
|
|
minOccurs="1" maxOccurs="1" |
|
||||
directivec |
|
|
|
short short_member; |
|
||
|
|
|
type="xsd:short"/> |
|
|||
|
|
Default |
(if |
not |
|
||
|
|
</xsd:sequence> |
|
||||
|
|
specified): true |
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
other |
@<directive |
//@copy This text will be |
|
||||
kind> |
|
|
copied in the generated |
|
|||
directivesc |
|
|
generated files |
|
|||
<value> |
|
files |
|
||||
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with XML Schemas (XSD) |
|
|
Table 3.12 Mapping Type System Constructs to XSD |
|
|
||
|
|
|
|
|
|
|
Type/Construct |
|
Example |
|
|
|
|
|
|
|
|
|
IDL |
XSD |
IDL |
XSD |
|
|
|
|
|
|
|
|
|
|
|
<xsd:simpleType name="PrimitiveEnum"> |
|
|
|
|
|
<xsd:restriction base="xsd:string"> |
|
|
|
|
|
<xsd:enumeration value="ENUM1"/> |
|
|
|
|
|
<xsd:enumeration value="ENUM2"/> |
|
|
|
|
|
<xsd:enumeration value="ENUM3"/> |
|
|
|
|
|
</xsd:restriction> |
|
|
|
|
|
</xsd:simpleType> |
|
|
|
|
|
<xsd:simpleType name="PrimitiveEnum"> |
|
|
|
|
|
<xsd:restriction base="xsd:string"> |
|
|
|
|
|
<xsd:enumeration value="ENUM1"> |
|
|
|
|
|
<xsd:annotation> |
|
|
|
|
enum PrimitiveEnum { |
<xsd:appinfo> |
|
|
|
|
ENUM1, |
<ordinal>10</ordinal> |
|
|
|
|
ENUM2, |
</xsd:appinfo> |
|
|
|
|
ENUM3 |
</xsd:annotation> |
|
enum |
xsd:simpleType |
}; |
</xsd:enumeration> |
|
|
|
<xsd:enumeration value="ENUM2"> |
|
|||
with enumeration |
|
|
|||
|
|
enum PrimitiveEnum { |
<xsd:annotation> |
|
|
|
|
|
ENUM1 = 10, |
<xsd:appinfo> |
|
|
|
|
ENUM2 = 20, |
<ordinal>20</ordinal> |
|
|
|
|
ENUM3 = 30 |
</xsd:appinfo> |
|
|
|
|
}; |
</xsd:annotation> |
|
|
|
|
|
</xsd:enumeration> |
|
|
|
|
|
<xsd:enumeration value="ENUM3"> |
|
|
|
|
|
<xsd:annotation> |
|
|
|
|
|
<xsd:appinfo> |
|
|
|
|
|
<ordinal>30</ordinal> |
|
|
|
|
|
</xsd:appinfo> |
|
|
|
|
|
</xsd:annotation> |
|
|
|
|
|
</xsd:enumeration> |
|
|
|
|
|
</xsd:restriction> |
|
|
|
|
|
</xsd:simpleType> |
|
|
|
|
|
|
|
constant |
IDL constants are mapped by substituting their value directly in the generated file |
|
|||
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
|
|
|
xsd:complexType |
|
<xsd:sequence> |
|
|
|
struct PrimitiveStruct { |
<xsd:element name="short_member" |
|
|
struct |
with |
short short_member; |
minOccurs="1" maxOccurs="1" |
|
|
|
|
xsd:sequence |
}; |
type="xsd:short"/> |
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with XML Schemas (XSD) |
|
|
Table 3.12 Mapping Type System Constructs to XSD |
|
|
||
|
|
|
|
|
|
|
Type/Construct |
|
Example |
|
|
|
|
|
|
|
|
|
IDL |
XSD |
IDL |
XSD |
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveUnion"> |
|
|
|
|
|
<xsd:sequence> |
|
|
|
|
|
<xsd:element name="discriminator" |
|
|
|
|
|
type="xsd:int"/> |
|
|
|
|
|
<xsd:choice> |
|
|
|
|
|
|
|
|
|
|
|
<xsd:element name="short_member" |
|
|
|
|
|
minOccurs="0" maxOccurs="1" |
|
|
|
|
|
type="xsd:short"> |
|
|
|
|
|
<xsd:annotation> |
|
|
|
|
union PrimitiveUnion |
<xsd:appinfo> |
|
|
|
|
<case>1</case> |
|
|
|
|
|
switch (long) { |
|
|
|
|
|
</xsd:appinfo> |
|
|
|
|
xsd:complexType |
case 1: |
|
|
|
|
</xsd:annotation> |
|
||
union |
short short_member; |
|
|||
with xsd:choice |
</xsd:element> |
|
|||
|
|
default: |
|
||
|
|
|
|
||
|
|
|
long long_member; |
|
|
|
|
|
<xsd:element name="long_member" |
|
|
|
|
|
}; |
|
|
|
|
|
minOccurs="0" maxOccurs="1" |
|
|
|
|
|
|
|
|
|
|
|
|
type="xsd:int"> |
|
|
|
|
|
<xsd:annotation> |
|
|
|
|
|
<xsd:appinfo> |
|
|
|
|
|
<case>default</case> |
|
|
|
|
|
</xsd:appinfo> |
|
|
|
|
|
</xsd:annotation> |
|
|
|
|
|
</xsd:element> |
|
|
|
|
|
</xsd:choice> |
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="BaseValueType"> |
|
|
|
|
|
<xsd:sequence> |
|
|
|
|
|
<xsd:element name=”long_member" |
|
|
|
|
|
maxOccurs="1" minOccurs="1" |
|
|
|
|
|
type="xs:int"/> |
|
|
|
|
|
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
valuetype BaseValueType { |
</xs:complexType> |
|
|
|
|
public long |
|
|
|
|
|
long_member; |
|
|
|
|
|
}; |
<xs:complexType name="DerivedValueType"> |
|
|
|
xsd:complexType |
|
<xs:complexContent> |
|
|
|
valuetype |
<xs:extension base="BaseValueType"> |
|
|
valuetype |
with @valuetype |
DerivedValueType: |
<xs:sequence> |
|
|
|
|
directive |
BaseValueType { |
<xs:element name= "long_member2" |
|
|
|
|
public long |
maxOccurs="1" minOccurs="1" |
|
|
|
|
long_member2; |
type="xs:int"/> |
|
|
|
|
public long |
|
|
|
|
|
long_member3; |
<xs:element name= "long_member3" |
|
|
|
|
}; |
maxOccurs="1" minOccurs="1" |
|
|
|
|
|
type="xs:int"/> |
|
|
|
|
|
|
|
|
|
|
|
</xs:sequence> |
|
|
|
|
|
</xs:extension> |
|
|
|
|
|
</xs:complexContent> |
|
|
|
|
|
</xs:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with XML Schemas (XSD) |
|
|
Table 3.12 Mapping Type System Constructs to XSD |
|
|
|||
|
|
|
|
|
||
|
Type/Construct |
|
Example |
|
||
|
|
|
|
|
|
|
|
IDL |
|
XSD |
IDL |
XSD |
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:simpleType name="ShortType"> |
|
|
|
|
|
|
<xsd:restriction base="xsd:short"/> |
|
|
|
|
|
|
</xsd:simpleType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name="PrimitiveStruct"> |
|
|
|
|
|
|
<xsd:sequence> |
|
|
|
|
|
typedef short ShortType; |
<xsd:element name="short_member" |
|
|
|
|
|
minOccurs="1" maxOccurs="1" |
|
|
|
|
|
|
|
|
|
|
|
|
|
struct PrimitiveStruct { |
type="xsd:short"/> |
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
Type |
definitions |
short short_member; |
|
|
|
|
</xsd:complexType> |
|
|||
|
|
}; |
|
|||
typedef |
are |
mapped to |
|
|
||
XML schema type |
|
|
||||
|
|
typedef PrimitiveType |
|
|||
|
|
|
|
|||
|
|
restrictions |
PrimitiveStructType; |
<xsd:complexType |
|
|
|
|
|
|
name="PrimitiveTypeStructType"> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexContent> |
|
|
|
|
|
|
<xsd:restriction base=”PrimitiveStruct”> |
|
|
|
|
|
|
<xsd:sequence> |
|
|
|
|
|
|
<xsd:element name="short_member" |
|
|
|
|
|
|
minOccurs="1" maxOccurs="1" |
|
|
|
|
|
|
type="xsd:short"/> |
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
</xsd:restriction> |
|
|
|
|
|
|
</xsd:complexContent> |
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<xsd:complexType name= |
|
|
|
n xsd:complex- |
|
"OneArrayStruct_short_array_ArrayOfShort"> |
|
|
|
|
|
<xsd:sequence> |
|
||
|
|
Type |
with |
|
<xsd:element name="item" minOccurs="2" |
|
|
|
sequence contain- |
|
maxOccurs="2" type="xsd:short"> |
|
|
|
|
ing |
one element |
|
</xsd:element> |
|
|
|
with min & max |
struct OneArrayStruct { |
</xsd:sequence> |
|
|
|
|
</xsd:complexType> |
|
|||
arrays |
occurs |
short short_array[2]; |
|
|||
|
||||||
|
|
|
|
}; |
|
|
|
|
|
|
<xsd:complexType name="OneArrayStruct"> |
|
|
|
|
There is one |
|
|
||
|
|
|
<xsd:sequence> |
|
||
|
|
xsd:complexType |
|
<xsd:element name="short_array" |
|
|
|
|
per array dimen- |
|
minOccurs="1" maxOccurs="1" |
|
|
|
|
sion |
|
|
type= |
|
|
|
|
|
|
"OneArrayStruct_short_array_ArrayOfShort"/> |
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with XML Schemas (XSD) |
||
|
Table 3.12 Mapping Type System Constructs to XSD |
|
|
|||||
|
|
|
|
|
||||
|
Type/Construct |
|
|
Example |
||||
|
|
|
|
|
|
|
||
|
IDL |
|
XSD |
|
IDL |
XSD |
||
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|||
|
|
|
|
|
|
<xsd:complexType name= |
||
|
|
|
|
|
|
"TwoArrayStruct_short_array_ArrayOfShort"> |
||
|
|
|
|
|
|
<xsd:sequence> |
||
|
|
|
|
|
|
<xsd:element name="item" minOccurs="2" |
||
|
|
|
|
|
|
maxOccurs="2" type="xsd:short"> |
||
|
|
|
|
|
|
</xsd:element> |
||
|
|
|
|
|
|
</xsd:sequence> |
||
|
|
|
|
|
|
</xsd:complexType> |
||
|
|
n xsd:complex- |
|
|||||
|
|
Type |
|
with |
|
|||
|
|
|
|
<xsd:complexType name= |
||||
|
|
sequence contain- |
|
"TwoArrayStruct_short_array_ArrayOfArrayOfShort"> |
||||
|
|
ing |
one element |
|
<xsd:sequence> |
|||
arrays |
with min & max |
struct TwoArrayStruct { |
<xsd:element name="item" |
|||||
minOccurs="1" maxOccurs="1" |
||||||||
occurs |
|
short short_array[2][1]; |
||||||
(cont’d) |
|
type= |
||||||
|
|
|
}; |
|||||
|
|
|
|
|
"TwoArrayStruct_short_array_ArrayOfShort"> |
|||
|
|
There is one |
|
|
||||
|
|
|
|
</xsd:element> |
||||
|
|
xsd:complexType |
|
</xsd:sequence> |
||||
|
|
per array dimen- |
|
</xsd:complexType> |
||||
|
|
sion |
|
|
|
|||
|
|
|
|
|
|
|||
|
|
|
|
|
|
member |
||
|
|
|
|
|
|
<xsd:complexType name="TwoArrayStruct"> |
||
|
|
|
|
|
|
<xsd:sequence> |
||
|
|
|
|
|
|
<xsd:element name="short_array" |
||
|
|
|
|
|
|
minOccurs="1" maxOccurs="1" |
||
|
|
|
|
|
|
type= |
||
|
|
|
|
|
|
"TwoArrayStruct_short_array_ArrayOfArrayOfShort"/> |
||
|
|
|
|
|
|
</xsd:sequence> |
||
|
|
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|||
|
|
|
|
|
|
<xsd:complexType name= |
||
|
|
|
|
|
|
"SequenceStruct_short_sequence_SequenceOfShort"> |
||
|
|
|
|
|
|
<xsd:sequence> |
||
|
|
|
|
|
|
<xsd:element name="item" minOccurs="0" |
||
|
|
|
|
|
|
maxOccurs="4" type="xsd:short"> |
||
|
|
|
|
|
|
</xsd:element> |
||
|
|
xsd:complexType |
|
</xsd:sequence> |
||||
bounded |
with |
sequence |
struct SequenceStruct { |
</xsd:complexType> |
||||
containing |
one |
sequence<short,4> |
|
|
||||
sequence |
short_sequence; |
|||||||
element with min |
||||||||
|
|
}; |
member |
|||||
|
|
& max occurs |
|
<xsd:complexType name="SequenceStruct"> |
||||
|
|
|
|
|
|
|||
|
|
|
|
|
|
<xsd:sequence> |
||
|
|
|
|
|
|
<xsd:element name="short_sequence" |
||
|
|
|
|
|
|
minOccurs="1" maxOccurs="1" |
||
|
|
|
|
|
|
type= |
||
|
|
|
|
|
|
"SequenceStruct_short_sequence_SequenceOfShort"/> |
||
|
|
|
|
|
|
</xsd:sequence> |
||
|
|
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with XML Schemas (XSD) |
||
|
Table 3.12 Mapping Type System Constructs to XSD |
|
|
|||||
|
|
|
|
|
||||
|
Type/Construct |
|
|
Example |
||||
|
|
|
|
|
|
|
||
|
IDL |
|
XSD |
|
IDL |
XSD |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|||
|
|
|
|
|
|
<xsd:complexType name= |
||
|
|
|
|
|
|
"SequenceStruct_short_sequence_SequenceOfShort"> |
||
|
|
|
|
|
|
<xsd:sequence> |
||
|
|
|
|
|
|
<xsd:element name="item" |
||
|
|
|
|
|
|
minOccurs="0" maxOccurs="unbounded" |
||
|
|
|
|
|
|
type="xsd:short"/> |
||
|
|
xsd:complexType |
|
</xsd:sequence> |
||||
unbound- |
with |
sequence |
struct SequenceStruct { |
</xsd:complexType> |
||||
ed |
containing |
one |
sequence<short> |
|
|
|||
short_sequence; |
||||||||
sequence |
element with min |
|||||||
}; |
member |
|||||||
|
|
& max occurs |
|
|
<xsd:complexType name="SequenceStruct"> |
|||
|
|
|
|
|
|
|||
|
|
|
|
|
|
<xsd:sequence> |
||
|
|
|
|
|
|
<xsd:element name="short_sequence" |
||
|
|
|
|
|
|
minOccurs="1" maxOccurs="1" |
||
|
|
|
|
|
|
type= |
||
|
|
|
|
|
|
"SequenceStruct_short_sequence_SequenceOfShort"/> |
||
|
|
|
|
|
|
</xsd:sequence> |
||
|
|
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with XML Schemas (XSD) |
|
|
Table 3.12 Mapping Type System Constructs to XSD |
|
|
||||
|
|
|
|
||||
|
Type/Construct |
|
Example |
||||
|
|
|
|
|
|
||
|
IDL |
|
XSD |
IDL |
XSD |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
<xsd:complexType |
|
|
|
|
|
|
|
name= |
|
|
|
|
|
|
|
"ArrayOfSequencesStruct_sequence_array_SequenceOf |
|
|
|
|
|
|
|
Short"> |
|
|
|
|
|
|
|
<xsd:sequence> |
|
|
|
|
|
|
|
<xsd:element name="item" |
|
|
|
|
|
|
|
minOccurs="0" maxOccurs="4" |
|
|
|
|
|
|
|
type="xsd:short"> |
|
|
|
|
|
|
|
</xsd:element> |
|
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
n + 1 xsd:com- |
|
|
|
|
|
|
|
plexType |
with |
|
||
|
|
|
sequence contain- |
|
<xsd:complexType |
||
|
|
|
ing one |
element |
|
name= |
|
|
|
|
with min & max |
|
"ArrayOfSequencesStruct_sequence_array_ArrayOf |
||
|
|
|
struct |
SequenceOfShort"> |
|||
|
|
|
occurs |
|
|||
array |
of |
|
ArrayOfSequencesStruct { |
<xsd:sequence> |
|||
|
|
||||||
|
|
sequence<short,4> |
<xsd:element name="item" |
||||
sequences |
|
|
|
||||
|
There is one |
sequence_sequence[2]; |
minOccurs="2" maxOccurs="2" |
||||
|
|
|
|||||
|
|
|
xsd:complexType |
}; |
type= |
||
|
|
|
per array dimen- |
|
"ArrayOfSequencesStruct_sequence_array_SequenceOf |
||
|
|
|
|
Short"> |
|||
|
|
|
sion and one |
|
|||
|
|
|
|
</xsd:element> |
|||
|
|
|
xsd:complexType |
|
|||
|
|
|
|
</xsd:sequence> |
|||
|
|
|
for the sequence |
|
</xsd:complexType> |
||
|
|
|
|
|
|
||
|
|
|
|
|
|
array of sequences |
|
|
|
|
|
|
|
<xsd:complexType name="ArrayOfSequencesStruct"> |
|
|
|
|
|
|
|
<xsd:sequence> |
|
|
|
|
|
|
|
<xsd:element name="sequence_array" |
|
|
|
|
|
|
|
minOccurs="1" maxOccurs="1" |
|
|
|
|
|
|
|
type= |
|
|
|
|
|
|
|
"ArrayOfSequencesStruct_sequence_array_ArrayOf |
|
|
|
|
|
|
|
SequenceOfShort"/> |
|
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with XML Schemas (XSD) |
|
|
Table 3.12 Mapping Type System Constructs to XSD |
|
|
||||
|
|
|
|
|
|||
|
Type/Construct |
|
|
Example |
|||
|
|
|
|
|
|
|
|
|
IDL |
|
XSD |
|
IDL |
XSD |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
<xsd:complexType name="ShortArray"> |
|
|
|
|
|
|
|
<xsd:sequence> |
|
|
|
|
|
|
|
<xsd:element name="item" |
|
|
|
|
|
|
|
minOccurs="2" maxOccurs="2" |
|
|
|
|
|
|
|
type="xsd:short"> |
|
|
|
|
|
|
|
</xsd:element> |
|
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
||
|
|
|
|
|
|
<xsd:complexType name= |
|
|
|
Sequences |
of |
typedef short |
"SequencesOfArraysStruct_array_sequence_SequenceO |
||
|
|
arrays |
must |
be |
ShortArray[2]; |
fShortArray"> |
|
sequence of |
implemented |
|
|
<xsd:sequence> |
|||
|
struct |
<xsd:element name="item" |
|||||
using an explicit |
|||||||
arrays |
type |
definition |
SequenceOfArraysStruct { |
minOccurs="0" maxOccurs="2" |
|||
|
|
sequence<ShortArray,2> |
type="ShortArray"> |
||||
|
|
(typedef) for |
the |
||||
|
|
arrays_sequence; |
</xsd:element> |
||||
|
|
array |
|
|
|||
|
|
|
|
}; |
</xsd:sequence> |
||
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
||
|
|
|
|
|
|
<xsd:complexType name="SequenceOfArraysStruct"> |
|
|
|
|
|
|
|
<xsd:sequence> |
|
|
|
|
|
|
|
<xsd:element name="arrays_sequence" |
|
|
|
|
|
|
|
minOccurs="1" maxOccurs="1" |
|
|
|
|
|
|
|
type= |
|
|
|
|
|
|
|
"SequencesOfArraysStruct_arrays_sequence_Sequence |
|
|
|
|
|
|
|
OfShortArray"/> |
|
|
|
|
|
|
|
</xsd:sequence> |
|
|
|
|
|
|
|
</xsd:complexType> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Creating User Data Types with XML Schemas (XSD) |
||
|
Table 3.12 Mapping Type System Constructs to XSD |
|
|
|||||
|
|
|
|
|||||
|
Type/Construct |
|
Example |
|||||
|
|
|
|
|
|
|||
|
IDL |
|
XSD |
IDL |
XSD |
|||
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|||
|
|
|
|
|
|
<xsd:complexType name="ShortSequence"> |
||
|
|
|
|
|
|
<xsd:sequence> |
||
|
|
|
|
|
|
<xsd:element name="item" |
||
|
|
|
|
|
|
minOccurs="0" maxOccurs="4" |
||
|
|
|
|
|
|
type="xsd:short"> |
||
|
|
|
|
|
|
</xsd:element> |
||
|
|
|
|
|
|
</xsd:sequence> |
||
|
|
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
|
|||
|
|
|
|
|
|
<xsd:complexType name= |
||
|
|
Sequences |
of |
typedef sequence<short,4> |
"SequencesOfSequences_sequences_sequence_Sequence |
|||
|
|
sequences |
must |
ShortSequence; |
OfShortSequence"> |
|||
sequence of |
be |
implemented |
|
<xsd:sequence> |
||||
struct |
<xsd:element name="item" |
|||||||
using an explicit |
||||||||
sequences |
type |
definition |
SequenceOfSequences { |
minOccurs="0" maxOccurs="2" |
||||
|
|
sequence<ShortSequence, 2> |
type="ShortSequence"> |
|||||
|
|
(typedef) |
for the |
sequences_sequence; |
</xsd:element> |
|||
|
|
second sequence |
||||||
|
|
}; |
</xsd:sequence> |
|||||
|
|
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
|
|||
|
|
|
|
|
|
<xsd:complexType name="SequenceOfSequences"> |
||
|
|
|
|
|
|
<xsd:sequence> |
||
|
|
|
|
|
|
<xsd:element name="sequences_sequence" |
||
|
|
|
|
|
|
minOccurs="1" maxOccurs="1" |
||
|
|
|
|
|
|
type="SequencesOfSequences_ |
||
|
|
|
|
|
|
sequences_sequence_SequenceOfShortSequence"/> |
||
|
|
|
|
|
|
</xsd:sequence> |
||
|
|
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
|
|
||
|
|
Modules |
are |
|
<xsd:complexType name= |
|||
|
|
module PackageName { |
"PackageName.PrimitiveStruct"> |
|||||
|
|
mapped |
adding |
<xsd:sequence> |
||||
module |
the |
name |
of the |
struct PrimitiveStruct { |
<xsd:element name="long_member" |
|||
long long_member; |
||||||||
module before the |
minOccurs="1" maxOccurs="1" |
|||||||
|
|
}; |
||||||
|
|
name of each type |
type="xsd:int"/> |
|||||
|
|
}; |
||||||
|
|
</xsd:sequence> |
||||||
|
|
inside the module |
|
|||||
|
|
|
|
|
|
</xsd:complexType> |
||
|
|
|
|
|
|
|
||
include |
xsd:include |
#include |
<xsd:include schemaLocation= |
|||||
"PrimitiveType.idl" |
"PrimitiveType.xsd"/> |
|||||||
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
a.All files that use the primitive types char, wchar, long double and wstring must reference rti_dds_topic_types_common.xsd. See Primitive Types (Section 3.5.1).
b.Data types containing bitfield members are not supported by DynamicData (Section 3.8).
c.Directives are RTI extensions to the standard IDL grammar. For additional information about directives see Using Custom Directives (Sec- tion 3.3.8).
d.The discriminant values can be described using comments (as specified by the standard) or xsd:annotation tags. We recommend using annotations because comments may be removed by XSD/XML parsers.
Using rtiddsgen
3.5.1Primitive Types
The primitive types char, wchar, long double, and wstring are not supported natively in XSD. Connext provides definitions for these types in the file <NDDSHOME>/resource/rtiddsgen/ schema/rti_dds_topic_types_common.xsd. All files that use the primitive types char, wchar, long double and wstring must reference rti_dds_topic_types_common.xsd. For example:
<?xml version="1.0"
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:dds="http://www.omg.org/dds">
<xsd:import namespace="http://www.omg.org/dds" schemaLocation="rti_dds_topic_types_common.xsd"/>
<xsd:complexType name="Foo"> <xsd:sequence>
<xsd:element name="myChar" minOccurs="1" maxOccurs="1" type="dds:char"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
3.6Using rtiddsgen
The rtiddsgen utility provided by Connext creates the code needed to define and register a user data type with Connext. Using this tool is optional if:
❏You are using dynamic types (see Managing Memory for
❏You are using one of the
To use rtiddsgen, you must supply a description of the type in an IDL, XML, XSD, or WSDL file. The supported syntax for each one of the notations is described in Section 3.8.5.1 (IDL), Section 3.4 (XML) and Section 3.5 (XSD and WSDL). You can define multiple data types in the same
Table 3.13 on page
On Windows systems: Before running rtiddsgen, run VCVARS32.BAT in the same command prompt that you will use to run rtiddsgen.
Table 3.13 Files Created by rtiddsgen for C, C++, C++/CLI, C# for Example “Hello.idl”
Generated Files |
Description |
Required files for the user data type. The source files should be compiled and linked with the user applica- tion. The header files are required to use the data type in source.
You should not modify these files unless you intend to customize the generated code supporting your type.
Hello.[c,cxx, cpp]
HelloSupport.[c, cxx, cpp]
Generated code for the data types. These files contain the implementa-
HelloPlugin.[c,cxx, cpp]
tion for your data types.
Hello.h
HelloSupport.h
Header files that contain declarations used in the implementation of
HelloPlugin.h
your data types.
Using rtiddsgen
Table 3.13 Files Created by rtiddsgen for C, C++, C++/CLI, C# for Example “Hello.idl”
|
Generated Files |
|
|
Description |
|
|
|
|
|
|
|
|
|
|
|
||
|
Optional files generated when you use the |
||||
|
You may modify and use these files as a way to create simple applications that publish or subscribe to the |
||||
|
user data type. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Example code for an application that publishes the user data type. This |
|
|
|
|
|
example shows the basic steps to create all of the Connext objects needed |
|
|
Hello_publisher.[c, cxx, cpp, cs] |
to send data. |
|||
|
|
|
|
You will need to modify the code to set and change the values being |
|
|
|
|
|
sent in the data structure. Otherwise, just compile and run. |
|
|
|
|
|
|
|
|
|
|
|
Example code for an application that subscribes to the user data type. |
|
|
|
|
|
This example shows the basic steps to create all of the Connext objects |
|
|
Hello_subscriber.[c, cxx, cpp,cs] |
needed to receive data using a “listener” function. |
|||
|
|
|
|
No modification of this file is required. It is ready for you to compile |
|
|
|
|
|
and run. |
|
|
|
|
|
|
|
|
Hello.dsw or Hello.sln, |
|
Microsoft Visual C++ or Visual Studio .NET Project workspace and |
||
|
Hello_publisher.dsp |
or |
|||
|
Hello_publisher.vcproj, |
|
project files, generated only for “i86Win32” architectures. To compile |
||
|
|
the generated source code, open the workspace file and build the two |
|||
|
Hello_subscriber.dsp |
or |
|||
|
Hello_subscriber.vcproj |
|
projects. |
|
|
|
|
|
|
||
|
|
|
|
|
|
|
makefile_Hello_<architecture> |
|
Makefile for |
||
|
|
ture> would be linux2.4gcc3.2.2. |
|||
|
|
|
|
||
|
|
|
|
|
|
Table 3.14 Files Created by rtiddsgen for Java for Example “Hello.idl” |
|||||
|
|
|
|
||
|
Data Type |
Generated Files |
Description |
||
|
|
|
|
||
|
|
||||
|
Since the Java language requires individual files to be created for each class, rtiddsgen will generate a |
||||
|
source file for every IDL construct that translates into a class in Java. |
||||
|
|
|
|
|
|
|
Constants |
<Name>.java |
|
|
Class associated with the constant |
|
|
|
|
|
|
|
Enums |
<Name>.java |
|
|
Class associated with enum type |
|
|
|
|
|
|
|
|
<Name>.java |
|
|
Structure/Union class |
|
|
<Name>Seq.java |
|
||
|
Structures/ |
|
Sequence class |
||
|
<Name>DataReader.java |
||||
|
Unions |
Connext DataReader and DataWriter classes |
|||
|
<Name>DataWriter.java |
||||
|
|
Support (serialize, deserialize, etc.) class |
|||
|
|
<Name>TypeSupport.java |
|||
|
|
|
|||
|
|
|
|
|
|
|
Typedef of |
<Name>.java |
|
|
Wrapper class |
|
sequences or |
<Name>Seq.java |
|
Sequence class |
|
|
arrays |
<Name>TypeSupport.java |
Support (serialize, deserialize, etc.) class |
||
|
|
|
|
||
|
Optional files generated when you use the |
||||
|
use these files as a way to create simple applications that publish or subscribe to the user data type. |
||||
|
|
|
|
|
|
|
|
|
|
|
Example code for applications that publish or subscribe to |
|
|
<Name>Publisher.java |
the user data type. You should modify the code in the pub- |
||
|
|
lisher application to set and change the value of the pub- |
|||
|
Structures/ |
<Name>Subscriber.java |
|||
|
lished data. Otherwise, both files should be ready to |
||||
|
Unions |
|
|
|
|
|
|
|
|
compile and run. |
|
|
|
|
|
|
|
|
|
|
|
||
|
|
makefile_Hello_<architecture> |
Makefile for |
||
|
|
|
|
|
ple <architecture> is linux2.4gcc3.2.2. |
|
Structures/ |
<Name>TypeCode.java |
|
||
|
Unions/ |
Type code class associated with the IDL type given by |
|||
|
(Note: this is not generated if |
||||
|
Typedefs/ |
<Name>. |
|||
|
Enums |
you use |
|
||
|
|
|
|
|
|
|
|
|
|
|
|
Using rtiddsgen
NOTE: Before using an
makefile to compile an application, make sure the set as described in the Getting Started Guide. For must be set when generating the project files.
3.6.1rtiddsgen
There are several
Note: CORBA support requires the RTI CORBA Compatibility Kit
rtiddsgen
Table 3.15 describes the options (in alphabetical order).
Table 3.15 Options for rtiddsgen
Option |
Description |
Converts the input type description file into CCL format. This option creates a new file with the same name as the input file and a .ccl extension.
Converts the input type description file into CCs format. This option creates a new file with the same name as the input file and a .ccs extension.
Using rtiddsgen
Table 3.15 Options for rtiddsgen
Option |
Description |
|
|
|
|
|
|
|
Converts the input type description file into IDL format. This option creates |
||
a new file with the same name as the input file and a .idl extension. |
||
|
||
|
|
|
Converts the input type description file into WSDL format. This option cre- |
||
ates a new file with the same name as the input file and a .wsdl extension. |
||
|
||
|
|
|
Converts the input type description file into XML format. This option creates |
||
a new file with the same name as the input file and a .xml extension. |
||
|
||
|
|
|
Converts the input type description file into XSD format. This option creates |
||
a new file with the same name as the input file and a .xsd extension. |
||
|
||
|
|
|
|
This option is only available when using the RTI CORBA Compatibility Kit for |
|
Connext (available for purchase as a separate product). Please see Part 7: RTI |
||
|
||
|
|
|
|
Defines preprocessor macros. |
|
Note: On Windows systems, enclose the argument in quotation marks: |
||
|
||
|
|
|
Generates the output in the specified directory. By default, rtiddsgen will gen- |
||
erate files in the directory where the input |
||
|
||
|
|
|
|
Assigns a suffix to the name of a DataReader interface. Only applies if |
|
is also specified. By default, the suffix is 'DataReader'. Therefore, given the |
||
|
type 'Foo' the name of the DataReader interface will be 'FooDataReader'. |
|
|
|
|
|
Assigns a suffix to the name of a DataWriter interface. Only applies if |
|
is also specified. By default, the suffix is 'DataWriter'. Therefore, given the |
||
|
type 'Foo' the name of the DataWriter interface will be 'FooDataWriter'. |
|
|
|
|
Creates XML files for debugging rtiddsgen only. Use this option only at the |
||
direction of RTI support; it is unlikely to be useful to you otherwise. |
||
|
||
|
|
|
Enables use of the escape character '_' in IDL identifiers. When |
||
used, this option is always enabled. |
||
|
||
|
|
|
|
Generates example application code and makefiles (for |
|
tems) or workspace and project files (for Windows systems) based on the |
||
|
||
|
makefiles. Valid options for <arch> are listed in the Platform Notes. |
|
|
|
|
When converting to CCS or CCL files, expand octet sequences. The default |
||
is to use a blob type. |
||
|
||
|
|
|
When converting to CCS or CCL files, expand char sequences. The default is |
||
to use a string type. |
||
|
||
|
|
|
|
Adds to the list of directories to be searched for |
|
XML, XSD or WSDL files). Note: A |
||
|
include a file in another format. |
|
|
|
|
Indicates that the input file is an IDL file, regardless of the file extension. |
||
|
|
|
Indicates that the input file is a WSDL file, regardless of the file extension. |
||
|
|
|
Indicates that the input file is a XML file, regardless of the file extension. |
||
|
|
|
Indicates that the input file is a XSD file, regardless of the file extension. |
||
|
|
|
IDLInputFile.idl |
File containing IDL descriptions of your data types. If |
|
the file must have a ‘.idl’ extension. |
||
|
||
|
|
|
Prints out the command line options for rtiddsgen. |
||
|
|
|
Specifies the language to use for the generated files. The default language is |
||
C++; you can also choose C, C++/CLI, C#, Java, or Ada. |
||
|
||
|
|
|
|
Using rtiddsgen |
Table 3.15 Options for rtiddsgen |
|
|
|
|
|
|
Option |
Description |
|
|
|
|
|
|
|
|
Generates code for the |
|
The METP library requires a special version of Connext; please contact sup- |
|
|
|
port@rti.com for more information. |
|
|
|
|
Specifies the use of C++ namespace. (For C++ only. For C++/CLI and C#, it |
|
|
is |
|
|
|
|
|
|
|
|
|
Forces rtiddsgen to put ‘copy’ logic into the corresponding TypeSupport class |
|
|
rather than the type itself. This option is only used for Java code generation. |
|
This option is not compatible with the use of ndds_standalone_type.jar (see |
|
|
|
Section 3.7). Note that when generating code for Java, the |
|
|
implies the |
|
|
Disables |
|
|
can be used in a standalone |
|
|
|
|
Note: If you are using a large data type (more than 64 K) and type code sup- |
|
|
port, you will see a warning when type code information is sent. Connext has |
|
|
|
|
|
|
a type code size limit of 64K. To avoid the warning when working with data |
|
|
types with type codes larger than 64K, turn off type code support by using - |
|
|
notypecode. |
|
|
|
|
|
Allows rtiddsgen to overwrite any existing generated files. If it is not present |
|
and existing files are found, rtiddsgen will print a warning but will not over- |
|
|
|
write them. |
|
|
|
|
See Optimizing Typedefs |
|
|
|
|
|
|
Specifies the CORBA ORB. The majority of code generated is independent of |
|
|
the ORB. However, for some IDL features the code generated depends on the |
|
ORB. rtiddsgen generates code compatible with |
|
|
select an ACE_TAO version use the |
|
|
|
|
|
|
ACE_TAO1.6. |
|
|
This option can only be used with the |
|
|
|
|
|
Specifies the root package into which generated classes will be placed. It |
|
applies to Java only. If the |
|
|
|
those modules will be considered subpackages of the package specified here. |
|
|
|
|
Disables the preprocessor. |
|
|
|
|
|
|
Specifies a preprocessor option. This parameter can be used multiple times |
|
to provide the |
|
|
|
ppPath. |
|
|
|
|
|
Specifies the preprocessor. If you only specify the name of an executable |
|
|
(not a complete path to that executable), the executable must be found in |
|
|
your Path. The default value is "cpp" for |
|
"cl.exe" for Windows architectures.If you use |
|
|
path and filename for cl.exe or the cpp preprocessor, you must also use - |
|
|
<preprocessor |
|
|
ppOption (described below) to set the following preprocessor options: |
|
|
executable> |
|
|
If you use a |
|
|
|
|
|
|
|
|
|
If you use a |
|
|
|
|
|
|
|
Sets the size assigned to unbounded sequences. The default value is 100 ele- |
|
|
ments. |
|
|
|
|
|
|
|
|
Sets the size assigned to unbounded strings, not counting a terminating |
|
|
NULL character. The default value is 255 bytes. |
|
|
|
|
|
|
|
|
|
Using rtiddsgen |
Table 3.15 Options for rtiddsgen |
|
|
|
|
|
|
Option |
Description |
|
|
|
|
|
|
|
Assigns a suffix to the names of the implicit sequences defined for IDL types. |
|
|
fix> |
Only applies if |
|
fore, given the type 'Foo' the name of the implicit sequence will be 'FooSeq'. |
|
|
|
|
|
|
|
|
Cancels any previous definition of <name>. |
|
|
|
|
|
|
Makes the generated code compatible with RTI Data Distribution Service 4.2e. |
|
This option should be used when compatibility with 4.2e is required and the |
|
|
topic data types contain double, long long, unsigned long long, or long dou- |
|
|
|
|
|
|
ble members. |
|
|
|
|
|
rtiddsgen verbosity: |
|
1: exceptions |
|
|
2: exceptions and warnings |
|
|
|
|
|
|
3: exceptions, warnings and information (Default) |
|
|
|
|
|
Displays the version of rtiddsgen being used, such as 5.0.x. (Note: To see |
|
‘patch’ revision information (such as 5.0.x rev. n), see What Version am I |
|
|
|
|
|
|
|
|
WSDLInputFile.wsdl |
WSDL file containing XSD descriptions of your data types. If |
|
not used, the file must have an .wsdl extension. |
|
|
|
|
|
|
|
|
XMLInputFile.idl |
File containing XML descriptions of your data types. If |
|
used, the file must have an .xml extension. |
|
|
|
|
|
|
|
|
XSDInputFile.xsd |
File containing XSD descriptions of your data types. If |
|
the file must have an .xsd extension. |
|
|
|
|
|
|
|
a. CORBA support is only available when using the RTI CORBA Compatibility Kit (available for purchase as a sepa- rate product). See Part 7: RTI CORBA Compatibility Kit.
3.6.1.1Optimizing Typedefs
The
❏0 (default): No optimization. Typedef’ed types are treated as full types and
❏1: The compiler generates
This will save at least one function call for serialization, deserialization, and other manip- ulation of the parent structure. This optimization level is always safe to use unless the user intends to modify the generated
❏2: Same as level 1 with the addition that the
Using Generated Types without Connext (Standalone)
This typedef optimization level is only recommend if you only have a single IDL file that contains the definitions of all of the user data types passed by Connext on the network. If you have multiple IDL files, and types defined in one file use typedefs that are defined in another, then rtiddsgen will generate code assuming that the
For example, consider this declaration:
typedef short MyShort
struct MyStructure { MyShort member;
};
With optimization 0: The
With optimization 1: The type
With optimization 2: The
3.7Using Generated Types without Connext (Standalone)
You can use the generated
The directory <NDDSHOME>/resource/rtiddsgen/standalone contains the required helper files:
❏include: header and templates files for C and C++.
❏src: source files for C and C++.
❏class: Java jar file.
Note: You must use rtiddsgen’s
3.7.1Using Standalone Types in C
The generated files that can be used standalone are:
❏<idl file name>.c: Types source file
❏<idl file name>.h: Types header file
The type
Using Generated Types without Connext (Standalone)
To use the
1.Make sure you use rtiddsgen’s
2.Include the directory <NDDSHOME>/resource/rtiddsgen/standalone/include in the list of directories to be searched for header files.
3.Add the source files, ndds_standalone_type.c and <idl file name>.c, to your project.
4.Include the file <idl file name>.h in the source files that will use the generated types in a standalone manner.
5.Compile the project using the following two preprocessor definitions:
a.NDDS_STANDALONE_TYPE
b.The definition for your platform (RTI_VXWORKS, RTI_QNX, RTI_WIN32, RTI_INTY, RTI_LYNX or RTI_UNIX)
3.7.2Using Standalone Types in C++
The generated files that can be used standalone are:
❏<idl file name>.cxx: Types source file
❏<idl file name>.h: Types header file
The
To use the generated types in a standalone manner:
1.Make sure you use rtiddsgen’s
2.Include the directory <NDDSHOME>/resource/rtiddsgen/standalone/include in the list of directories to be searched for header files.
3.Add the source files, ndds_standalone_type.cxx and <idl file name>.cxx, to your proj- ect.
4.Include the file <idl file name>.h in the source files that will use the rtiddsgen types in a standalone manner.
5.Compile the project using the following two preprocessor definitions:
a.NDDS_STANDALONE_TYPE
b.The definition for your platform (such as RTI_VXWORKS, RTI_QNX, RTI_WIN32, RTI_INTY, RTI_LYNX or RTI_UNIX)
3.7.3Standalone Types in Java
The generated files that can be used standalone are:
❏<idl type>.java
❏<idl type>Seq.java
The type code (<idl file>TypeCode.java),
DataReader code (<idl file>DataReader.java) and DataWriter code (<idl file>DataWriter.java) cannot be used standalone.
Interacting Dynamically with User Data Types
To use the generated types in a standalone manner:
1.Make sure you use rtiddsgen’s
2.Include the file ndds_standalone_type.jar in the classpath of your project.
3.Compile the project using the standalone types files (<idl type>.java and <idl type>Seq.java).
3.8Interacting Dynamically with User Data Types
3.8.1Introduction to TypeCode
Type
enum TCKind { TK_NULL, TK_SHORT, TK_LONG, TK_USHORT, TK_ULONG, TK_FLOAT, TK_DOUBLE, TK_BOOLEAN, TK_CHAR, TK_OCTET, TK_STRUCT, TK_UNION, TK_ENUM, TK_STRING, TK_SEQUENCE, TK_ARRAY, TK_ALIAS, TK_LONGLONG, TK_ULONGLONG, TK_LONGDOUBLE, TK_WCHAR, TK_WSTRING, TK_VALUE, TK_SPARSE
}
Type codes unambiguously match type representations and provide a more reliable test than comparing the string type names.
The TypeCode class, modeled after the corresponding CORBA API, provides access to type- code information. For details on the available operations for the TypeCode class, see the API Reference HTML documentation, which is available for all supported programming languages (select Modules, DDS API Reference, Topic Module, Type Code Support).
Type codes are enabled by default when you run rtiddsgen. The
Interacting Dynamically with User Data Types
Note:
3.8.2Defining New Types
Note: This section does not apply when using the separate
Locally, your application can access the type code for a generated type "Foo" by calling the Foo_get_typecode() operation in the code for the type generated by rtiddsgen (unless
Creating a TypeCode is parallel to the way you would define the type statically: you define the type itself with some name, then you add members to it, each with its own name and type.
For example, consider the following statically defined type. It might be in C, C++, or IDL; the syntax is largely the same.
struct MyType { long my_integer; float my_float; bool my_bool;
string<128> my_string; // @key
};
This is how you would define the same type at run time in C++:
DDS_ExceptionCode_t ex = DDS_NO_EXCEPTION_CODE; DDS_StructMemberSeq structMembers; // ignore for now DDS_TypeCodeFactory* factory = DDS_TypeCodeFactory::get_instance(); DDS_TypeCode* structTc =
"MyType", structMembers, ex);
// If structTc is NULL, check 'ex' for more information.
More detailed documentation for the methods and constants you see above, including example code, can be found in the API Reference HTML documentation, which is available for all sup- ported programming languages.
If, as in the example above, you know all of the fields that will exist in the type at the time of its construction, you can use the StructMemberSeq to simplify the code:
DDS_StructMemberSeq structMembers;
Interacting Dynamically with User Data Types
structMembers.ensure_length(4, 4);
DDS_TypeCodeFactory* factory = DDS_TypeCodeFactory::get_instance();
structMembers[0].name = DDS_String_dup("my_integer"); structMembers[0].type =
structMembers[1].name = DDS_String_dup("my_float"); structMembers[1].type =
structMembers[2].name = DDS_String_dup("my_bool"); structMembers[2].type =
structMembers[3].name = DDS_String_dup("my_string"); structMembers[3].type =
DDS_ExceptionCode_t ex = DDS_NO_EXCEPTION_CODE; DDS_TypeCode* structTc =
structMembers, ex);
After you have defined the TypeCode, you will register it with a DomainParticipant using a logi- cal name. You will use this logical name later when you create a Topic.
DDSDynamicDataTypeSupport* type_support =
new DDSDynamicDataTypeSupport(structTc, DDS_DYNAMIC_DATA_TYPE_PROPERTY_DEFAULT);
DDS_ReturnCode_t retcode =
Now that you have created a type, you will need to know how to interact with objects of that type. Continue reading Section 3.8.3 below for more information.
3.8.3Sending Only a Few Fields
In some cases, your data model may contain a large number of potential fields, but it may not be desirable or appropriate to include a value for every one of them with every data sample.
❏It may use too much bandwidth. You may have a very large data structure, parts of which are updated very frequently. Rather than resending the entire data structure with every change, you may wish to send only those fields that have changed and rely on the recipients to reassemble the complete state themselves.
❏It may not make sense. Some fields may only have meaning in the presence of other fields. For example, you may have an event stream in which certain fields are only rele- vant for certain kinds of events.
To support these and similar cases, Connext supports sparse value types. A sample of such a type only contains the field values that were explicitly set by the sender. A recipient of that sam- ple will receive an error when trying to look up the value of any other field.
An endpoint (DataWriter or DataReader) using a sparse value type will not communicate with another endpoint using a
Interacting Dynamically with User Data Types
Because direct programming language representations of data types typically have no way to express the concept of sparse fields (there is no way, for example, for a C structure to omit some of its fields), using sparse types requires use of the dynamic type API described in Defining New Types (Section 3.8.2). You will use the Dynamic Data API to work with sparse samples, just as you would with samples of any other dynamically defined type. For more information about working with sparse samples, see Objects of Dynamically Defined Types (Section 3.9.2) or the API Reference HTML documentation (select Modules, DDS API Reference, Topic Module, Dynamic Data).
A sparse version of the "MyType" type described above would be defined like this:
DDS_ExceptionCode_t ex = DDS_NO_EXCEPTION_CODE; DDS_TypeCodeFactory* factory = DDS_TypeCodeFactory::get_instance(); DDS_TypeCode* sparseTc =
"MySparseType", DDS_VM_NONE, NULL, ex);
// add members
Detailed descriptions of the methods and constants you see above can be found in the API Ref- erence HTML documentation.
Integral to the definition of a sparse type are the member IDs of its fields. An ID is a
Although member IDs are a relatively efficient way to describe a sample's contents, they do use network bandwidth. This can be an important issue if you are considering using sparse types to decrease the size of your data samples on the network. Although the relative cost of adding member IDs to your packets will vary depending on the sizes and layout of your fields, the fol- lowing is a good rule of thumb: if you expect a given data sample to contain less than half of the fields that are legal for its type, sparse types will probably save you on bandwidth. If, on the other hand, most samples contain most fields, you will probably be better off using a plain struc- ture type and simply ignoring irrelevant fields on the receiving side.
3.8.4Type Extension and Versioning
As your system evolves, you may find that your data types need to change. And unless your system is relatively small, you may not be able to bring it all down at once in order to modify them. Instead, you may need to upgrade your types one component at a
You can use the sparse types described above to efficiently version
Interacting Dynamically with User Data Types
❏You can add new fields to a type at any time. Because the type is sparse, existing pub- lishers of the type that have not been updated will simply omit the new field in any data samples they send. If you anticipate changing your types in future versions of your sys- tem, make sure that you ignore fields that you do not recognize, so that your application will be robust to future type changes.
❏You cannot remove fields from an existing type. Doing so would break older applica- tions and invalidate historical samples that might already be in the caches of upgraded applications. Instead, simply stop sending values for the fields you wish to deprecate.
3.8.5Sending Type Codes on the Network
In addition to being used locally, serialized type codes are typically published automatically during discovery as part of the
Note: Type codes are not cached by Connext upon receipt and are therefore not available from the
DataReader's get_matched_publication_data() operation.
If your data type has an especially complex type code, you may need to increase the value of the type_code_max_serialized_length field in the DomainParticipant's
DOMAIN_PARTICIPANT_RESOURCE_LIMITS QosPolicy (DDS Extension) (Section 8.5.4). Or, to prevent the propagation of type codes altogether, you can set this value to zero (0). Be aware that some features of monitoring tools, as well as some features of the middleware itself (such as ContentFilteredTopics) will not work correctly if you disable TypeCode propagation.
3.8.5.1Type Codes for
The type codes associated with the
module DDS {
/* String */ struct String {
string<max_size> value;
};
/* KeyedString */ struct KeyedString {
string<max_size> key; //@key string<max_size> value;
};
/* Octets */ struct Octets {
sequence<octet, max_size> value;
};
/* KeyedOctets */ struct KeyedOctets {
string<max_size> key; //@key sequence<octet, max_size> value;
};
Working with Data Samples
};
The maximum size (max_size) of the strings and sequences that will be included in the type code definitions can be configured on a
Table 3.16 Properties for Allocating Size of
Built- |
|
|
|
in |
Property |
Description |
|
Type |
|
|
|
|
|
|
|
|
|
Maximum size of the strings published by the DataWriters |
|
String |
dds.builtin_type.string.max_size |
and received by the DataReaders belonging to a DomainPartic- |
|
ipant (includes the |
|
||
|
|
|
|
|
|
Default: 1024 |
|
|
|
|
|
|
|
Maximum size of the keys used by the DataWriters and |
|
|
dds.builtin_type.keyed_string. |
DataReaders belonging to a DomainParticipant (includes the |
|
|
max_key_size |
|
|
Keyed- |
|
Default: 1024 |
|
|
|
|
|
|
Maximum size of the strings published by the DataWriters |
||
String |
|
||
|
and received by the DataReaders belonging to a DomainPartic- |
||
|
dds.builtin_type.keyed_string. |
||
|
ipant using the |
||
|
max_size |
||
|
character). |
|
|
|
|
|
|
|
|
Default: 1024 |
|
|
|
|
|
|
|
Maximum size of the octet sequences published by the |
|
Octets |
dds.builtin_type.octets.max_size |
DataWriters and DataReaders belonging to a DomainPartici- |
|
pant. |
|
||
|
|
|
|
|
|
Default: 2048 |
|
|
|
|
|
|
|
Maximum size of the key published by the DataWriter and |
|
|
dds.builtin_type.keyed_octets. |
received by the DataReaders belonging |
to the |
|
DomainParticipant (includes the |
charac- |
|
|
max_key_size |
||
|
ter). |
|
|
Keyed- |
|
|
|
|
Default:1024. |
|
|
Octets |
|
|
|
|
|
|
|
|
Maximum size of the octet sequences published by the |
||
|
|
||
|
dds.builtin_type.keyed_octets. |
DataWriters and DataReaders belonging to a DomainPartici- |
|
|
max_size |
pant. |
|
|
|
Default: 2048 |
|
|
|
|
|
3.9Working with Data Samples
You should now understand how to define and work with data types, whether you're using the simple data types built into the middleware (see
Now that you have chosen one or more data types to work with, this section will help you understand how to create and manipulate objects of those types.
Working with Data Samples
3.9.1Objects of Concrete Types
If you use one of the
In C and C++, you create and delete your own objects from factories, just as you create Connext objects from factories. In the case of user data types, the factory is a singleton object called the type support. Objects allocated from these factories are deeply allocated and fully initialized.
/* In the generated header file: */ struct MyData {
char* myString;
};
/* In your code: */
MyData* sample = MyDataTypeSupport_create_data();
char* str =
/* ... */
MyDataTypeSupport_delete_data(sample);
In C++, as in C, you create and delete objects using the TypeSupport factories.
MyData* sample = MyDataTypeSupport::create_data(); char* str =
MyDataTypeSupport::delete_data(sample);
In C# and C++/CLI, you can use a
//In the generated code (C++/CLI): public ref struct MyData {
public:
System::String^ myString;
};
//In your code, if you are using C#: MyData sample = new MyData();
System.String str = sample.myString; // empty,
//In your code, if you are using C++/CLI:
MyData^ sample = gcnew MyData();
System::String^ str =
In Java, you can use a
//In the generated code: public class MyData {
public String myString = "";
}
//In your code:
MyData sample = new MyData();
String str =
Working with Data Samples
3.9.2Objects of Dynamically Defined Types
If you are working with a data type that was discovered or defined at run time, you will use the reflective API provided by the DynamicData class to get and set the fields of your object.
Consider the following type definition:
struct MyData { long myInteger;
};
As with a statically defined type, you will create objects from a TypeSupport factory. How to cre- ate or otherwise obtain a TypeCode, and how to subsequently create from it a Dynamic- DataTypeSupport, is described in Defining New Types (Section 3.8.2).
For more information about the DynamicData and DynamicDataTypeSupport classes, consult the API Reference HTML documentation, which is available for all supported programming languages (select Modules, DDS API Reference, Topic Module, Dynamic Data).
In C:
DDS_DynamicDataTypeSupport* support = ...;
DDS_DynamicData* sample = DDS_DynamicDataTypeSupport_create_data(support); DDS_Long theInteger = 0;
DDS_ReturnCode_t success = DDS_DynamicData_set_long(sample, "myInteger", DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED, 5);
/* Error handling omitted. */
success = DDS_DynamicData_get_long(sample, &theInteger, "myInteger", DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED);
/* Error handling omitted. "theInteger" now contains the value 5 if no error occurred.
*/
In C++:
DDSDynamicDataTypeSupport* support = ...; DDS_DynamicData* sample =
DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED, 5); // Error handling omitted.
DDS_Long theInteger = 0;
success =
//Error handling omitted.
//"theInteger" now contains the value 5 if no error occurred.
In C++/CLI:
using DDS;
DynamicDataTypeSupport^ support = ...; DynamicData^ sample =
DynamicData::MEMBER_ID_UNSPECIFIED, 5);
int theInteger =
0 /*redundant w/ field name*/);
/* Exception handling omitted.
* "theInteger" now contains the value 5 if no error occurred. */
In C#:
using namespace DDS; DynamicDataTypeSupport support = ...;
Working with Data Samples
DynamicData sample = support.create_data(); sample.set_long("myInteger", DynamicData.MEMBER_ID_UNSPECIFIED, 5);
int theInteger = sample.get_long("myInteger", DynamicData.MEMBER_ID_UNSPECIFIED);
/* Exception handling omitted.
* "theInteger" now contains the value 5 if no error occurred. */
In Java:
import com.rti.dds.dynamicdata.*; DynamicDataTypeSupport support = ...;
DynamicData sample = (DynamicData) support.create_data(); sample.set_int("myInteger", DynamicData.MEMBER_ID_UNSPECIFIED, 5);
int theInteger = sample.get_int("myInteger", DynamicData.MEMBER_ID_UNSPECIFIED);
/* Exception handling omitted.
* "theInteger" now contains the value 5 if no error occurred. */
Chapter 4 Entities
The main classes extend an abstract base class called an Entity. Every Entity has a set of associ- ated events known as statuses and a set of associated Quality of Service Policies (QosPolicies). In addition, a Listener may be registered with the Entity to be called when status changes occur. Entities may also have attached Conditions, which provide a way to wait for status changes.
This chapter describes the common operations and general designed patterns shared by all Enti- ties including DomainParticipants, Topics, Publishers, DataWriters, Subscribers, and DataReaders. In subsequent chapters, the specific statuses, Listeners, Conditions, and QosPolicies for each class will be discussed in detail.
4.1Common Operations for All Entities
All Entities (DomainParticipants, Topics, Publishers, DataWriters, Subscribers, and DataReaders) pro- vide operations for:
Common Operations for All Entities
❏Enabling Entities (Section 4.1.2)
❏Getting an Entity’s Instance Handle (Section 4.1.3)
❏Getting Status and Status Changes (Section 4.1.4)
❏Getting and Setting Listeners (Section 4.1.5)
❏Getting the StatusCondition (Section 4.1.6)
❏Getting and Setting QosPolicies (Section 4.1.7)
4.1.1Creating and Deleting Entities
The factory design pattern is used in creating and deleting Entities. Instead of declaring and con- structing or destructing Entities directly, a factory object is used to create an Entity. Almost all entity factories are objects that are also entities. The only exception is the factory for a Domain- Participant. See Table 4.1.
Table 4.1 Entity Factories
Entity |
Created by |
|
|
|
|
|
|
|
DomainParticipant |
DomainParticipantFactory |
|
(a static singleton object provided by Connext) |
||
|
||
|
|
|
Topic |
|
|
|
|
|
Publisher |
|
|
|
|
|
Subscriber |
DomainParticipant |
|
|
|
|
DataWritera |
|
|
DataReadera |
|
|
DataWritera |
Publisher |
|
DataReadera |
Subscriber |
a. DataWriters may be created by a DomainParticipant or a Publisher. Similarly, DataReaders may be created by a
DomainParticipant or a Subscriber.
All entities that are factories have:
❏Operations to create and delete child entities. For example:
DDSPublisher::create_datawriter, DDSDomainParticipant::delete_topic
❏Operations to get and set the default QoS values used when creating child entities. For example:
DDSSubscriber::get_default_datareader_qos, DDSDomainParticipantFactory::set_default_participant_qos
❏An ENTITYFACTORY QosPolicy (Section 6.4.2) to specify whether or not the newly cre- ated child entity should be automatically enabled upon creation.
An entity that is a factory cannot be deleted until all the child entities created by it have been deleted.
Each Entity obtained through create_<entity>() must eventually be deleted by calling delete_<entity>, or by calling delete_contained_entities().
Common Operations for All Entities
4.1.2Enabling Entities
The enable() operation changes an Entity from a
By default, all Entities are automatically created in the enabled state. This means that as soon as the Entity is created, it is ready to be used. In some cases, you may want to create the Entity in a ‘disabled’ state. For example, by default, as soon as you create a DataReader, the DataReader will start receiving new samples for its Topic if they are being sent. However, your application may still be initializing other components and may not be ready to process the data at that time. In that case, you can tell the Subscriber to create the DataReader in a disabled state. After all of the other parts of the application have been created and initialized, then the DataReader can be enabled to actually receive messages.
To create a particular entity in a disabled state, modify the EntityFactory QosPolicy of its corre- sponding factory entity before calling create_<entity>(). For example, to create a disabled DataReader, modify the Subscriber’s QoS as follows:
DDS_SubscriberQos subscriber_qos;
DDS_BOOLEAN_FALSE;
DDSDataReader* datareader = subscriber->create_datareader( topic, DDS_DATAREADER_QOS_DEFAULT, listener);
When the application is ready to process received data, it can enable the DataReader:
4.1.2.1Rules for Calling enable()
In the following, a ‘Factory’ refers to a DomainParticipant, Publisher, or Subscriber; a ‘child’ refers to an entity created by the factory:
❏If the factory is disabled, its children are always created disabled, regardless of the set- ting in the factory's EntityFactoryQoS.
❏If the factory is enabled, its children will be created either enabled or disabled, according to the setting in the factory's EntityFactory Qos.
❏Calling enable() on a child whose factory object is still disabled will fail and return
DDS_RECODE_RECONDITION_NOT_MET.
❏Calling enable() on a factory with EntityFactoryQoS set to DDS_BOOLEAN_TRUE will recursively enable all of the factory’s children. If the factory’s EntityFactoryQoS is set to DDS_BOOLEAN_FALSE, only the factory itself will be enabled.
❏Calling enable() on an entity that is already enabled returns DDS_RETCODE_OK and has no effect.
❏There is no complementary “disable” operation. You cannot disable an entity after it is enabled. Disabled entities must have been created in that state.
❏An entity’s Listener will only be invoked if the entity is enabled.
❏The existence of an entity is not propagated to other DomainParticipants until the entity is enabled (see Chapter 14: Discovery).
Common Operations for All Entities
❏If a DataWriter/DataReader is to be created in an enabled state, then the associated Topic must already be enabled. The enabled state of the Topic does not matter, if the Publisher/ Subscriber has its EntityFactory QosPolicy to create children in a disabled state.
❏When calling enable() for a DataWriter/DataReader, both the Publisher/Subscriber and the
Topic must be enabled, or the operation will fail and return
DDS_RETCODE_PRECONDITION_NOT_MET.
The following operations may be invoked on disabled Entities:
❏get_qos() and set_qos() Some
Finally, there are extended QosPolicies that are not a part of the DDS specification but offered by Connext to control extended features for an Entity. Some of those extended QosPolicies cannot be changed after the Entity has been
Into which exact categories a QosPolicy
❏get_status_changes() and get_*_status() The status of an Entity can be retrieved at any time (but the status of a disabled Entity never changes).
❏get_statuscondition() An Entity’s StatusCondition can be checked at any time (although the status of a disabled Entity never changes).
❏get_listener() and set_listener() An Entity’s Listener can be changed at any time.
❏create_*() and delete_*() A factory Entity can still be used to create or delete any child Entity that it can produce. Note: following the rules discussed previously, a disabled Entity will always create its children in a disabled state, no matter what the value of the EntityFactory QosPolicy is.
❏lookup_*() An Entity can always look up children it has previously created.
Most other operations are not allowed on disabled Entities. Executing one of those operations when an Entity is disabled will result in a return code of DDS_RETCODE_NOT_ENABLED. The documentation for a particular operation will explicitly state if it is not allowed to be used if the Entity is disabled.
Note: The builtin transports are implicitly registered when (a) the DomainParticipant is enabled,
(b) the first DataWriter/DataReader is created, or (c) you look up a builtin data reader, whichever happens first. Any changes to the builtin transport properties that are made after the builtin transports have been registered will have no affect on any DataWriters/DataReaders.
4.1.3Getting an Entity’s Instance Handle
The Entity class provides an operation to retrieve an instance handle for the object. The opera- tion is simply:
InstanceHandle_t get_instance_handle()
An instance handle is a global ID for the entity that can be used in methods that allow user applications to determine if the entity was locally created, if an entity is owned (created) by another entity, etc.
Common Operations for All Entities
4.1.4Getting Status and Status Changes
The get_status_changes() operation retrieves the set of events, also known in DDS terminology as communication statuses, in the Entity that have changed since the last time get_status_changes() was called. This method actually returns a value that must be bitwise AND’ed with an enumerated bit mask to test whether or not a specific status has changed. The operation can be used in a polling mechanism to see if any statuses related to the Entity have changed. If an entity is disabled, all communication statuses are in the “unchanged” state so the list returned by the get_status_changes() operation will be empty.
A set of statuses is defined for each class of Entities. For each status, there is a corresponding operation,
DataWriter has a DDS_OFFERED_DEADLINE_MISSED status; it also has a get_offered_deadline_missed_status() operation:
DDS_StatusMask statuses;
DDS_OfferedDeadlineMissedStatus deadline_stat;
statuses =
if (statuses & DDS_OFFERED_DEADLINE_MISSED_STATUS) {
deadline_stat.total_count);
}
See Section 4.3 for more information about statuses.
4.1.5Getting and Setting Listeners
Each type of Entity has an associated Listener, see Listeners (Section 4.4). A Listener represents a set of functions that users may install to be called asynchronously when the state of communica- tion statuses change.
The get_listener() operation returns the current Listener attached to the Entity.
The set_listener() operation installs a Listener on an Entity. The Listener will only be invoked on the changes of statuses specified by the accompanying mask. Only one listener can be attached to each Entity. If a Listener was already attached, set_listener() will replace it with the new one.
The get_listener() and set_listener() operations are directly provided by the DomainParticipant,
Topic, Publisher, DataWriter, Subscriber, and DataReader classes so that listeners and masks used in the argument list are specific to each Entity.
Note: The set_listener() operation is not synchronized with the listener callbacks, so it is possi- ble to set a new listener on an participant while the old listener is in a callback. Therefore you should be careful not to delete any listener that has been set on an enabled participant unless some
See Section 4.4 for more information about Listeners.
4.1.6Getting the StatusCondition
Each type of Entity may have an attached StatusCondition, which can be accessed through the get_statuscondition() operation. You can attach the StatusCondition to a WaitSet, to cause your application to wait for specific status changes that affect the Entity.
See Section 4.6 for more information about StatusConditions and WaitSets.
Common Operations for All Entities
4.1.7Getting and Setting QosPolicies
Each type of Entity has an associated set of QosPolicies (see Section 4.2). QosPolicies allow you to configure and set properties for the Entity.
While most QosPolicies are defined by the DDS specification, some are offered by Connext as extensions to control parameters specific to the implementation.
There are two ways to specify a QoS policy:
❏Programmatically, as described in this section.
❏QosPolicies can also be configured from XML resources (files,
The get_qos() operation retrieves the current values for the set of QosPolicies defined for the
Entity.
QosPolicies can be set programmatically when an Entity is created, or modified with the Entity's set_qos() operation.
The set_qos() operation sets the QosPolicies of the entity. Note: not all QosPolicy changes will take effect instantaneously; there may be a delay since some QosPolicies set for one entity, for example, a DataReader, may actually affect the operation of a matched entity in another applica- tion, for example, a DataWriter.
The get_qos() and set_qos() operations are passed QoS structures that are specific to each derived entity class, since the set of QosPolicies that effect each class of entities is different.
Each QosPolicy has default values (listed in the API Reference HTML documentation). If you want to use custom values, there are three ways to change QosPolicy settings:
❏Before Entity creation (if custom values should be used for multiple Entities). See Section 4.1.7.1.
❏During Entity creation (if custom values are only needed for a particular Entity). See Section 4.1.7.2.
❏After Entity creation (if the values initially specified for a particular Entity are no longer appropriate). See Section 4.1.7.3.
Regardless of when or how you make QoS changes, there are some rules to follow:
❏Some QosPolicies interact with each other and thus must be set in a consistent manner. For instance, the maximum value of the HISTORY QosPolicy’s depth parameter is limited by values set in the RESOURCE_LIMITS QosPolicy. If the values within a QosPolicy structure are inconsistent, then set_qos() will return the error INCONSISTENT_POLICY, and the operation will have no effect.
❏Some policies can only be set when the Entity is created, or before the Entity is enabled. Others can be changed at any time. In general, all standard DDS QosPolicies can be changed before the Entity is enabled. A subset can be changed after the Entity is enabled.
4.1.7.1Changing the QoS Defaults Used to Create Entities: set_default_*_qos()
Each parent factory has a set of default QoS settings that are used when the child entity is cre- ated. The DomainParticipantFactory has default QoS values for creating DomainParticipants. A
Common Operations for All Entities
DomainParticipant has a set of default QoS for each type of entity that can be created from the
DomainParticipant (Topic, Publisher, Subscriber, DataWriter, and DataReader). Likewise, a Publisher has a set of default QoS values used when creating DataWriters, and a Subscriber has a set of default QoS values used when creating DataReaders.
An entity’s QoS are set when it is created. Once an entity is created, all of its
You can change these default values so that they are automatically applied when new child enti- ties are created. For example, suppose you want all DataWriters for a particular Publisher to have their RELIABILITY QosPolicy set to RELIABLE. Instead of making this change for each DataW- riter when it is created, you can change the default used when any DataWriter is created from the
Publisher by using the Publisher’s set_default_datawriter_qos() operation.
DDS_DataWriterQos default_datawriter_qos;
// get the current default values
// change to desired default values default_datawriter_qos.reliability.kind =
DDS_RELIABLE_RELIABILITY_QOS;
// set the new default values
// created datawriters will use new default values
datawriter =
Note: It is not safe to get or set the default QoS values for an entity while another thread may be simultaneously calling get_default_<entity>_qos(), set_default_<entity>_qos(), or create_<entity>() with DDS_<ENTITY>_QOS_DEFAULT as the qos parameter (for the same entity).
Another way to make QoS changes is by using XML resources (files, strings). For more informa- tion, see Chapter 17: Configuring QoS with XML.
4.1.7.2Setting QoS During Entity Creation
If you only want to change a QosPolicy for a particular entity, you can pass in the desired QosPolicies for an entity in its creation routine.
To customize an entity's QoS before creating it:
1.(C API Only) Initialize a QoS object with the appropriate INITIALIZER constructor.
2.Call the relevant get_<entity>_default_qos() method.
3.Modify the QoS values as desired.
4.Create the entity.
For example, to change the RELIABLE QosPolicy for a DataWriter before creating it:
// Initialize the QoS object DDS_DataWriterQos datawriter_qos;
// Get the default values
Common Operations for All Entities
// Modify the QoS values as desired datawriter_qos.reliability.kind = DDS_BEST_EFFORT_RELIABILITY_QOS;
// Create the DataWriter with new values datawriter =
Another way to set QoS during entity creation is by using a QoS profile. For more information, see Chapter 17: Configuring QoS with XML.
4.1.7.3Changing the QoS for an Existing Entity
Some policies can also be changed after the entity has been created. To change such a policy after the entity has been created, use the entity’s set_qos() operation.
For example, suppose you want to tweak the DEADLINE QoS for an existing DataWriter:
DDS_DataWriterQos datawriter_qos;
// get the current values
// make desired changes datawriter_qos.deadline.period.sec = 3; datawriter_qos.deadline.period.nanosec = 0;
// set new values
Another way to make QoS changes is by using a QoS profile. For more information, see Chapter 17: Configuring QoS with XML.
Note: In the code examples presented in this section, we are not testing for the return code for the set_qos(), set_default_*_qos() functions. If the values used in the QosPolicy structures are inconsistent then the functions will fail and return INCONSISTENT_POLICY. In addition, set_qos() may return IMMUTABLE_POLICY if you try to change a QosPolicy on an Entity after that policy has become immutable. User code should test for and address those anomalous conditions.
4.1.7.4Default Values
Connext provides special constants for each Entity type that can be used in set_qos() and set_default_*_qos() to reset the QosPolicy values to the original DDS default values:
❏DDS_PARTICIPANT_QOS_DEFAULT
❏DDS_PUBLISHER_QOS_DEFAULT
❏DDS_SUBSCRIBER_QOS_DEFAULT
❏DDS_DATAWRITER_QOS_DEFAULT
❏DDS_DATAREADER_QOS_DEFAULT
❏DDS_TOPIC_QOS_DEFAULT
For example, if you want to set a DataWriter’s QoS back to their
Or if you want to reset the default QosPolicies used by a Publisher to create DataWriters back to their
QosPolicies
Note: These defaults cannot be used to initialize a QoS structure for an entity. For example, the following is NOT allowed:
Not
create_datawriter(dataWriterQos);
4.2QosPolicies
Connext’s behavior is controlled by the Quality of Service (QoS) policies of the data communica- tion entities (DomainParticipant, Topic, Publisher, Subscriber, DataWriter, and DataReader) used in your applications. This section summarizes each of the QosPolicies that you can set for the vari- ous entities.
The QosPolicy class is the abstract base class for all the QosPolicies. It provides the basic mecha- nism for an application to specify quality of service parameters. Table 4.2 on page
The detailed description of a QosPolicy that applies to multiple Entities is provided in the first chapter that discusses an Entity whose behavior the QoS affects. Otherwise, the discussion of a QosPolicy can be found in the chapter of the particular Entity to which the policy applies. As you will see in the detailed description sections, all QosPolicies have one or more parameters that are used to configure the policy. The how’s and why’s of tuning the parameters are also dis- cussed in those sections.
As first discussed in Controlling Behavior with Quality of Service (QoS) Policies (Section 2.5.1), QosPolicies may interact with each other, and certain values of QosPolicies can be incompatible with the values set for other policies.
The set_qos() operation will fail if you attempt to specify a set of values would result in an inconsistent set of policies. To indicate a failure, set_qos() will return INCONSISTENT_POLICY. Section 4.2.1 provides further information on QoS compatibility within an Entity as well as across matching Entities, as does the discussion/reference section for each QosPolicy listed in Table 4.2 on page
The values of some QosPolicies cannot be changed after the Entity is created or after the Entity is enabled. Others may be changed at any time. The detailed section on each QosPolicy states when each policy can be changed. If you attempt to change a QosPolicy after it becomes immu- table (because the associated Entity has been created or enabled, depending on the policy), set_qos() will fail with a return code of IMMUTABLE_POLICY.
Table 4.2 QosPolicies
QosPolicy |
Summary |
|
|
Asynchronous- |
Configures the mechanism that sends user data in an external middleware thread. See |
Publisher |
|
|
|
|
This QoS policy is used in the context of two features: |
|
For a Collaborative DataWriter, specifies the group of DataWriters expected to collabora- |
Availability |
tively provide data and the timeouts that control when to allow data to be available that |
may skip samples. |
|
|
For a Durable Subscription, configures a set of Durable Subscriptions on a DataWriter. |
|
See Section 6.5.1. |
|
|
|
|
|
QosPolicies |
|
|
Table 4.2 QosPolicies |
|
|
|
|
|
|
|
|
|
QosPolicy |
Summary |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Specifies and configures the mechanism that allows Connext to collect multiple user |
|
|
Batch |
data samples to be sent in a single network packet, to take advantage of the efficiency of |
|
||
|
|
sending larger packets and thus increase effective throughput. See Section 6.5.2. |
|
|
|
|
|
|
|
Database |
Various settings and resource limits used by Connext to control its internal database. See |
|
||
|
|
|||
|
|
|
|
|
|
|
|
||
DataReaderProtocol |
This QosPolicy configures the Connext |
|
||
|
|
|
|
|
DataReaderResourceLimits |
Various settings that configure how DataReaders allocate and use physical memory for |
|
||
internal resources. See Section 7.6.2. |
|
|
||
|
|
|
|
|
|
|
|
||
DataWriterProtocol |
This QosPolicy configures the Connext |
|
||
|
|
|
|
|
|
|
Controls how many threads can concurrently block on a write() call of this DataWriter. |
|
|
DataWriterResourceLimits |
Also controls the number of batches managed by the DataWriter and the instance- |
|
||
|
|
replacement kind used by the DataWriter. See Section 6.5.4. |
|
|
|
|
|
|
|
|
|
For a DataReader, specifies the maximum expected elapsed time between arriving data |
|
|
|
|
samples. |
|
|
Deadline |
For a DataWriter, specifies a commitment to publish samples with no greater elapsed |
|
||
|
|
time between them. |
|
|
|
|
See Section 6.5.5. |
|
|
|
|
|
|
|
|
|
Controls how Connext will deal with data sent by multiple DataWriters for the same |
|
|
DestinationOrder |
topic. Can be set to "by reception timestamp" or to "by source timestamp." See |
|
||
|
|
|
|
|
|
|
|
|
|
Discovery |
Configures the mechanism used by Connext to automatically discover and connect with |
|
||
new remote applications. See Section 8.5.2. |
|
|
||
|
|
|
|
|
|
|
|
|
|
DiscoveryConfig |
Controls the amount of delay in discovering entities in the system and the amount of |
|
||
discovery traffic in the network. See Section 8.5.3. |
|
|||
|
|
|
||
|
|
|
|
|
DomainParticipantResource- |
Various settings that configure how DomainParticipants allocate and use physical mem- |
|
||
ory for internal resources, including the maximum sizes of various properties. See |
|
|||
Limits |
|
|
||
|
|
|
|
|
|
|
|
|
|
Durability |
Specifies whether or not Connext will store and deliver data that were previously pub- |
|
||
lished to new DataReaders. See Section 6.5.7. |
|
|
||
|
|
|
|
|
|
|
|
|
|
DurabilityService |
Various settings to configure the external |
Persistence Service used by Connext for |
|
|
DataWriters with a Durability QoS setting of Persistent Durability. See Section 6.5.8. |
|
|||
|
|
|
||
|
|
|
||
EntityFactory |
Controls whether or not child entities are created in the enabled state. See Section 6.4.2. |
|
||
|
|
|
||
EntityName |
Assigns a name to a DomainParticipant. See Section 8.5.5. |
|
||
|
|
|
|
|
Event |
Configures the DomainParticipant’s internal |
thread that handles timed events. See |
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
ExclusiveArea |
Configures |
deadlock prevention capabilities. See |
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
Along with TOPIC_DATA QosPolicy (Section 5.2.1) and USER_DATA QosPolicy (Sec- |
|
|
GroupData |
tion 6.5.25), this QosPolicy is used to attach a buffer of bytes to Connext's discovery |
|
||
|
|
|
|
|
|
|
|
|
|
|
|
Specifies how much data must to stored by Connextfor the DataWriter or DataReader. |
|
|
History |
This QosPolicy affects the RELIABILITY QosPolicy (Section 6.5.19) as well as the |
|
||
|
|
|
||
|
|
|
||
LatencyBudget |
Suggestion to Connext on how much time is allowed to deliver data. See Section 6.5.11. |
|
||
|
|
|
|
|
Lifespan |
Specifies how long Connext should consider data sent by an user application to be valid. |
|
||
See Section 6.5.12. |
|
|
||
|
|
|
|
|
|
|
|
|
|
QosPolicies
Table 4.2 QosPolicies
QosPolicy |
Summary |
|
|
|
|
|
|
|
Liveliness |
Specifies and configures the mechanism that allows DataReaders to detect when DataW- |
|
riters become disconnected or "dead." See Section 6.5.13. |
||
|
||
|
|
|
Logging |
Configures the properties associated with Connext logging. See Section 8.4.1. |
|
|
|
|
MultiChannel |
Configures a DataWriter’s ability to send data on different multicast groups (addresses) |
|
based on the value of the data. See Section 6.5.14. |
||
|
||
|
|
|
Ownership |
Along with Ownership Strength, specifies if DataReaders for a topic can receive data |
|
from multiple DataWriters at the same time. See Section 6.5.15. |
||
|
||
|
|
|
OwnershipStrength |
Used to arbitrate among multiple DataWriters of the same instance of a Topic when |
|
Ownership QoSPolicy is EXLUSIVE. See Section 6.5.16. |
||
|
||
|
|
|
Partition |
Adds string identifiers that are used for matching DataReaders and DataWriters for the |
|
same Topic. See Section 6.4.5. |
||
|
||
|
|
|
Presentation |
Controls how Connext presents data received by an application to the DataReaders of the |
|
data. See Section 6.4.6. |
||
|
||
|
|
|
Profile |
Configures the way that XML documents containing QoS profiles are loaded by RTI. |
|
See Section 8.4.2. |
||
|
||
|
|
|
|
Stores name/value(string) pairs that can be used to configure certain parameters of |
|
Property |
Connext that are not exposed through formal QoS policies. It can also be used to store |
|
and propagate |
||
|
||
|
code during discovery. See Section 6.5.17. |
|
|
|
|
|
Specifies how Connext sends application data on the network. By default, data is sent in |
|
PublishMode |
the user thread that calls the DataWriter’s write() operation. However, this QosPolicy |
|
|
can be used to tell Connext to use its own thread to send the data. See Section 6.5.18. |
|
|
|
|
ReaderDataLifeCycle |
Controls how a DataReader manages the lifecycle of the data that it has received. See |
|
|
||
|
|
|
ReceiverPool |
Configures threads used by Connext to receive and process data from transports (for |
|
example, UDP sockets). See Section 8.5.6. |
||
|
||
|
|
|
Reliability |
Specifies whether or not Connext will deliver data reliably. See Section 6.5.19. |
|
|
|
|
|
Controls the amount of physical memory allocated for entities, if dynamic allocations |
|
ResourceLimits |
are allowed, and how they occur. Also controls memory usage among different instance |
|
|
values for keyed topics. See Section 6.5.20. |
|
|
|
|
|
Configures |
|
SystemResourceLimits |
change the maximum number of DomainParticipants that can be created within a single |
|
|
process (address space). See Section 8.4.3. |
|
|
|
|
TimeBasedFilter |
Set by a DataReader to limit the number of new data values received over a period of |
|
time. See Section 7.6.4. |
||
|
||
|
|
|
TopicData |
Along with Group Data QosPolicy and User Data QosPolicy, used to attach a buffer of |
|
bytes to Connext's discovery |
||
|
||
|
|
|
TransportBuiltin |
Specifies which |
|
|
|
|
|
Specifies the multicast address on which a DataReader wants to receive its data. Can |
|
TransportMulticast |
specify a port number as well as a subset of the available transports with which to |
|
|
receive the multicast data. See Section 7.6.5. |
|
|
|
|
|
Specifies the automatic mapping between a list of topic expressions and multicast |
|
TransportMulticastMapping |
address that can be used by a DataReader to receive data for a specific topic. See |
|
|
||
|
|
|
TransportPriority |
Set by a DataWriter to tell Connext that the data being sent is a different "priority" than |
|
other data. See Section 6.5.21. |
||
|
||
|
|
QosPolicies
Table 4.2 QosPolicies
QosPolicy |
Summary |
|
|
|
|
|
|
|
TransportSelection |
Allows you to select which physical transports a DataWriter or DataReader may use to |
|
send or receive its data. See Section 6.5.22. |
||
|
||
|
|
|
TransportUnicast |
Specifies a subset of transports and port number that can be used by an Entity to receive |
|
data. See Section 6.5.23. |
||
|
||
|
|
|
TypeConsistencyEnforcement |
Defines rules that determine whether the type used to publish a given data stream is |
|
consistent with that used to subscribe to it. See Section 7.6.6. |
||
|
|
|
|
Used to attach |
|
TypeSupport |
are passed to the serialization or deserialization routine of the associated data type. See |
|
|
||
|
|
|
UserData |
Along with Topic Data QosPolicy and Group Data QosPolicy, used to attach a buffer of |
|
bytes to Connext's discovery |
||
|
||
|
|
|
WireProtocol |
Specifies IDs used by the RTPS wire protocol to create globally unique identifiers. See |
|
|
||
|
|
|
WriterDataLifeCycle |
Controls how a DataWriter handles the lifecycle of the instances (keys) that the DataW- |
|
riter is registered to manage. See Section 6.5.26. |
||
|
||
|
|
4.2.1QoS Requested vs. Offered
Some QosPolicies that apply to entities on the sending and receiving sides must have their val- ues set in a compatible manner. This is known as the policy’s ‘requested vs. offered’ (RxO) prop- erty. Entities on the publishing side ‘offer’ to provide a certain behavior. Entities on the subscribing side ‘request’ certain behavior. For Connext to connect the sending entity to the receiving entity, the offered behavior must satisfy the requested behavior.
For some QosPolicies, the allowed values may be graduated in a way that the offered value will satisfy the requested value if the offered value is either greater than or less than the requested value. For example, if a DataWriter’s DEADLINE QosPolicy specifies a duration less than or equal to a DataReader’s DEADLINE QosPolicy, then the DataWriter is promising to publish data at least as fast or faster than the DataReader requires new data to be received. This is a compatible situation (see Section 6.5.5).
Other QosPolicies require the values on the sending side and the subscribing side to be exactly equal for compatibility to be met. For example, if a DataWriter’s OWNERSHIP QosPolicy is set to SHARED, and the matching DataReader’s value is set to EXCLUSIVE, then this is an incom- patible situation since the DataReader and DataWriter have different expectations of what will happen if more than one DataWriter publishes an instance of the Topic (see OWNERSHIP QosPolicy (Section 6.5.15)).
Finally there are QosPolicies that do not require compatibility between the sending entity and the receiving entity, or that only apply to one side or the other. Whether or not related entities on the publishing and subscribing sides must use compatible settings for a QosPolicy is indicated in the policy’s RxO property, which is provided in the detailed section on each QosPolicy.
RxO = YESThe policy is set at both the publishing and subscribing ends and the values must be set in a compatible manner. What it means to be compatible is defined by the QosPolicy.
RxO = NOThe policy is set only on one end or at both the publishing and subscribing ends, but the two settings are independent. There the requested vs. offered semantics are not used for these QosPolicies.
For those QosPolicies that follow the RxO semantics, Connext will compare the values of those policies for compatibility. If they are compatible, then Connext will connect the sending entity to
QosPolicies
the receiving entity allowing data to be sent between them. If they are found to be incompatible, then Connext will not interconnect the entities preventing data to be sent between them.
In addition, Connext will record this event by changing the associated communication status in both the sending and receiving applications, see Types of Communication Status (Section 4.3.1). Also, if you have installed Listeners on the associated Entities, then Connext will invoke the asso- ciated callback functions to notify user code that an incompatible QoS combination has been found, see Types of Listeners (Section 4.4.1).
For Publishers and DataWriters, the status corresponding to this situation is
OFFERED_INCOMPATIBLE_QOS_STATUS. For Subscribers and DataReaders, the correspond- ing status is REQUESTED_INCOMPATIBLE_QOS_STATUS. The question of why a
DataReader is not receiving data sent from a matching DataWriter can often be answered if you have instrumented the application with Listeners for the statuses noted previously.
4.2.2Special QosPolicy Handling Considerations for C
Many QosPolicy structures contain
In the C language, it is not safe to use an Entity’s QosPolicy structure declared in user code unless it has been initialized first. In addition, user code should always finalize an Entity’s QosPolicy structure to release any memory allocated for the
Thus, for a general Entity’s QosPolicy, Connext will provide:
❏DDS_<Entity>Qos_INITIALIZER This is a macro that should be used when a DDS_<Entity>Qos structure is declared in a C application.
struct DDS_<Entity>Qos qos = DDS_<Entity>Qos_INITIALIZER;
❏DDS_<Entity>Qos_initialize() This is a function that can be used to initialize a DDS_<Entity>Qos structure instead of the macro above.
struct DDS_<Entity>Qos qos; DDS_<Entity>QOS_initialize(&qos);
❏DDS_<Entity>Qos_finalize() This is a function that should be used to finalize a DDS_<Entity>Qos structure when the structure is no longer needed. It will free any memory allocated for sequences contained in the structure.
struct DDS_<Entity>Qos qos = DDS_<Entity>Qos_INITIALIZER;
...
<use qos>
...
// now done with qos
DDS_<Entity>QoS_finalize(&qos);
❏DDS<Entity>Qos_copy() This is a function that can be used to copy one DDS_<Entity>Qos structure to another. It will copy the sequences contained in the source structure and allocate memory for sequence elements if needed. In the code below, both dstQos and srcQos must have been initialized at some point earlier in the code.
Statuses
DDS_<Entity>QOS_copy(&dstQos, &srcQos);
4.3Statuses
This section describes the different statuses that exist for an entity. A status represents a state or an event regarding the entity. For instance, maybe Connext found a matching DataReader for a DataWriter, or new data has arrived for a DataReader.
Your application can retrieve an Entity’s status by:
❏explicitly checking for any status changes with get_status_changes().
❏explicitly checking a specific status with get_<statusname>_status().
❏using a Listener, which provides asynchronous notification when a status changes.
❏using StatusConditions and WaitSets, which provide a way to wait for status changes.
If you want your application to be notified of status changes asynchronously: create and install a Listener for the Entity. Then internal Connext threads will call the listener methods when the sta- tus changes. See Listeners (Section 4.4).
If you want your application to wait for status changes: set up StatusConditions to indicate the statuses of interest, attach the StatusConditions to a WaitSet, and then call the WaitSet’s wait() operation. The call to wait() will block until statuses in the attached Conditions changes (or until a timeout period expires). See Conditions and WaitSets (Section 4.6).
This section includes the following:
❏Types of Communication Status (Section 4.3.1)
❏Special
4.3.1Types of Communication Status
Each Entity is associated with a set of Status objects representing the “communication status” of that Entity. The list of statuses actively monitored by Connext is provided in Table 4.3 on page 4- 15. A status structure contains values that give you more information about the status; for exam- ple, how many times the event has occurred since the last time the user checked the status, or how many time the event has occurred in total.
Changes to status values cause activation of corresponding StatusCondition objects and trigger invocation of the corresponding Listener functions to asynchronously inform the application that the status has changed. For example, a change in a Topic’s INCONSISTENT_TOPIC_STATUS may trigger the TopicListener’s on_inconsistent_topic() callback routine (if such a Listener is installed).
Statuses can be grouped into two categories:
❏Plain communication status: In addition to a flag that indicates whether or not a status has changed, a plain communication status also contains state and thus has a correspond- ing structure to hold its current value.
❏Read communication status: A read communication status is more like an event and has no state other than whether or not it has occurred. Only two statuses listed in Table 4.3 are read communications statuses: DATA_AVAILABLE and DATA_ON_READERS.
As mentioned in Section 4.1.4, all entities have a get_status_changes() operation that can be used to explicitly poll for changes in any status related to the entity. For plain statuses, each entry
|
|
|
|
Statuses |
|
Table 4.3 Communication Statuses |
|
|
|
||
|
|
|
|
|
|
|
Related |
Status (DDS_*_STATUS) |
Description |
Reference |
|
|
Entity |
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Another Topic exists with the same name but dif- |
|
|
|
Topic |
INCONSISTENT_TOPIC |
ferent |
|
|
|
|
|
type. |
|
|
|
|
|
|
|
|
|
|
|
This status indicates that a DataWriter has |
|
|
|
|
|
received an |
|
|
|
|
APPLICATION_ |
for a sample. The listener provides the identities |
|
|
|
|
ACKNOWLEDGMENT |
of the sample and acknowledging DataReader, as |
|
|
|
|
|
well as |
|
|
|
|
|
DataReader by the acknowledgment message. |
|
|
|
|
|
|
|
|
|
|
DATA_WRITER_CACHE |
The status of the DataWriter’s cache. |
|
|
|
|
This status does not have a Listener. |
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The status of a DataWriter’s internal protocol |
|
|
|
|
|
related metrics (such as the number of samples |
|
|
|
|
DATA_WRITER_PROTOCOL |
pushed, pulled, filtered) and the status of wire |
|
|
|
|
|
protocol traffic. |
|
|
|
|
|
This status does not have a Listener. |
|
|
|
|
|
|
|
|
|
|
|
The liveliness that the DataWriter has committed |
|
|
|
|
|
to (through its Liveliness QosPolicy) was not |
|
|
|
|
LIVELINESS_LOST |
respected (assert_liveliness() or write() not called |
|
|
|
Data- |
|
in time), thus DataReader entities may consider |
|
|
|
|
the DataWriter as no longer active. |
|
|
|
|
Writer |
|
|
|
|
|
|
|
|
|
|
|
OFFERED_DEADLINE_ |
The deadline that the DataWriter has committed |
|
|
|
|
|
|
|
||
|
|
through its Deadline QosPolicy was not |
|
||
|
|
MISSED |
|
||
|
|
respected for a specific instance of the Topic. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
OFFERED_INCOMPATIBLE_ |
An offered QosPolicy value was incompatible |
|
|
|
|
with what was requested by a DataReader of the |
|
||
|
|
QOS |
|
||
|
|
same Topic. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The DataWriter found a DataReader that matches |
|
|
|
|
PUBLICATION_MATCHED |
the Topic, has compatible QoSs and a common |
|
|
|
|
partition, or a previously matched DataReader has |
|
||
|
|
|
been deleted. |
|
|
|
|
|
|
|
|
|
|
RELIABLE_WRITER_ |
The number of unacknowledged samples in a |
|
|
|
|
reliable DataWriter's cache has reached one of the |
|
||
|
|
CACHE_CHANGED |
|
||
|
|
predefined trigger points. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
One or more reliable DataReaders has either been |
|
|
|
|
RELIABLE_READER_ |
discovered, deleted, or changed between active |
|
|
|
|
ACTIVITY_CHANGED |
and inactive state as specified by the Liveli- |
|
|
|
|
|
nessQosPolicy of the DataReader. |
|
|
|
|
|
|
|
|
|
|
|
|
Statuses |
|
Table 4.3 Communication Statuses |
|
|
|
||
|
|
|
|
|
|
|
Related |
Status (DDS_*_STATUS) |
Description |
Reference |
|
|
Entity |
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
Subscriber |
DATA_ON_READERS |
New data is available for any of the readers that |
|
|
|
|
|
were created from the Subscriber. |
|
|
|
|
DATA_AVAILABLE |
New data (one or more samples) are available for |
|
|
|
|
|
the specific DataReader. |
|
|
|
|
DATA_READER_CACHE |
The status of the reader's cache. |
|
|
|
|
This status does not have a Listener. |
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The status of a DataReader’s internal protocol |
|
|
|
|
|
related metrics (such as the number of samples |
|
|
|
|
DATA_READER_PROTOCOL |
received, filtered, rejected) and the status of wire |
|
|
|
|
|
protocol traffic. |
|
|
|
|
|
This status does not have a Listener. |
|
|
|
|
|
|
|
|
|
|
|
The liveliness of one or more DataWriters that |
|
|
|
|
|
were writing instances read by the DataReader |
|
|
|
|
LIVELINESS_CHANGED |
has either been discovered, deleted, or changed |
|
|
|
|
|
between active and inactive state as specified by |
|
|
|
Data- |
|
the LivelinessQosPolicy of the DataWriter. |
|
|
|
Reader |
REQUESTED_DEADLINE_ |
New data was not received for an instance of the |
|
|
|
|
Topic within the time period set by the |
|
||
|
|
MISSED |
|
||
|
|
DataReader’s Deadline QosPolicy. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
REQUESTED_ |
A requested QosPolicy value was incompatible |
|
|
|
|
with what was offered by a DataWriter of the |
|
||
|
|
INCOMPATIBLE_QOS |
|
||
|
|
same Topic. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SAMPLE_LOST |
A sample sent by Connext has been lost (never |
|
|
|
|
|
received). |
|
|
|
|
SAMPLE_REJECTED |
A received sample has been rejected due to a |
|
|
|
|
|
resource limit (buffers filled). |
|
|
|
|
|
The DataReader has found a DataWriter that |
|
|
|
|
SUBSCRIPTION_MATCHED |
matches the Topic, has compatible QoSs and a |
|
|
|
|
common partition, or an existing matched |
|
||
|
|
|
DataWriter has been deleted. |
|
|
|
|
|
|
|
|
has operations to get the current value of the status; for example, the Topic class has a get_inconsistent_topic_status() operation. For read statuses, your application should use the take() operation on the DataReader to retrieve the newly arrived data that is indicated by
DATA_AVAILABLE and DATA_ON_READER.
Note that the two read communication statuses do not change independently. If data arrives for a DataReader, then its DATA_AVAILABLE status changes. At the same time, the DATA_ON_READERS status changes for the DataReader’s Subscriber.
Both types of status have a StatusChangedFlag. This flag indicates whether that particular com- munication status has changed since the last time the status was read by the application. The way the StatusChangedFlag is maintained is slightly different for the plain communication status and the read communication status, as described in the following sections:
Statuses
4.3.1.1Changes in Plain Communication Status
As seen in Figure 4.1 on page
Figure 4.1 Status Changes for Plain Communication Status
status changes
StatusChangedFlag = FALSE |
StatusChangedFlag = TRUE |
User calls get_*_status(), or after listener is invoked
The communication status is also reset to FALSE whenever the associated listener operation is called, as the listener implicitly accesses the status which is passed as a parameter to the opera- tion.
The fact that the status is reset prior to calling the listener means that if the application calls the get_<plain communication status>() operation from inside the listener, it will see the status already reset.
An exception to this rule is when the associated listener is the 'nil' listener. The 'nil' listener is treated as a
For example, the value of the StatusChangedFlag associated with the REQUESTED_DEADLINE_MISSED status will become TRUE each time new deadline occurs (which increases the RequestedDeadlineMissed status’ total_count field). The value changes to FALSE when the application accesses the status via the corresponding get_requested_deadline_missed_status() operation on the proper Entity.
4.3.1.2Changes in Read Communication Status
As seen in Figure 4.2 on page
❏The arrival of new data.
❏A change in the InstanceStateKind of a contained instance. This can be caused by either:
•Notification that an instance has been disposed by:
•the DataWriter that owns it, if OWNERSHIP = EXCLUSIVE
•or by any DataWriter, if OWNERSHIP = SHARED
•The loss of liveliness of the DataWriter of an instance for which there is no other
DataWriter.
•The arrival of the notification that an instance has been unregistered by the only DataWriter that is known to be writing the instance.
Statuses
Depending on the kind of StatusChangedFlag, the flag transitions to FALSE again as follows:
❏The DATA_AVAILABLE StatusChangedFlag becomes FALSE when either on_data_available() is called or the read/take operation (or their variants) is called on the associated DataReader.
❏The DATA_ON_READERS StatusChangedFlag becomes FALSE when any of the follow- ing occurs:
•on_data_on_readers() is called.
•on_data_available() is called on any DataReader belonging to the Subscriber.
•One of the read/take operations (or their variants) is called on any DataReader belong- ing to the Subscriber.
Figure 4.2 Status Changes for Read Communication Status
Listeners
4.3.2Special
Some status structures contain
In the C language, it is not safe to use a status structure that has internal sequences declared in user code unless it has been initialized first. In addition, user code should always finalize a sta- tus structure to release any memory allocated for the
Thus, for a general status structure, Connext will provide:
❏DDS_<STATUS>STATUS_INITIALIZER This is a macro that should be used when a DDS_<Status>Status structure is declared in a C application.
struct DDS_<Status>Status status = DDS_<Status>Status_INITIALIZER;
❏DDS_<Status>Status_initialize() This is a function that can be used to initialize a DDS_<Status>Status structure instead of the macro above.
struct DDS_<Status>Status status; DDS_<Status>Status_initialize(&Status);
❏DDS_<Status>Status_finalize() This is a function that should be used to finalize a DDS_<Status>Status structure when the structure is no longer needed. It will free any memory allocated for sequences contained in the structure.
struct DDS_<Status>Status status = DDS_<Status>Status_INITIALIZER;
...
<use status>
...
// now done with Status DDS_<Status>Status_finalize(&status);
❏DDS<Status>Status_copy() This is a function that can be used to copy one DDS_<Sta- tus>Status structure to another. It will copy the sequences contained in the source struc- ture and allocate memory for sequence elements if needed. In the code below, both dstStatus and srcStatus must have been initialized at some point earlier in the code.
DDS_<Status>Status_copy(&dstStatus, &srcStatus);
Note that many status structures do not have sequences internally. For those structures, you do not need to use the macro and methods provided above. However, they have still been created for your convenience.
4.4Listeners
This section describes Listeners and how to use them:
❏Types of Listeners (Section 4.4.1)
Listeners
❏Hierarchical Processing of Listeners (Section 4.4.4)
❏Operations Allowed within Listener Callbacks (Section 4.4.5)
Listeners are triggered by changes in an entity’s status. For instance, maybe Connext found a matching DataReader for a DataWriter, or new data has arrived for a DataReader.
4.4.1Types of Listeners
The Listener class is the abstract base class for all listeners. Each entity class (DomainParticipant, Topic, Publisher, DataWriter, Subscriber, and DataReader) has its own derived Listener class that add methods for handling
Figure 4.3 Listener Class Hierarchy
DDSListener
DDSDataReaderListener DDSDataWriterListener DDSTopicListener
DDSSubscriberListener DDSPublisherListener
DDSDomainParticipantListener
You can choose which changes in status will trigger a callback by installing a listener with a bit- mask. Bits in the mask correspond to different statuses. The bits that are true indicate that the lis- tener will be called back when there are changes in the corresponding status.
You can specify a listener and set its
During Entity creation:
DDS_StatusMask mask = DDS_REQUESTED_DEADLINE_MISSED_STATUS |
DDS_DATA_AVAILABLE_STATUS;
datareader =
or afterwards:
DDS_StatusMask mask = DDS_REQUESTED_DEADLINE_MISSED_STATUS |
DDS_DATA_AVAILABLE_STATUS;
As you can see in the above examples, there are two components involved when setting up lis- teners: the listener itself and the mask. Both of these can be null. Table 4.4 describes what hap- pens when a status change occurs. See Hierarchical Processing of Listeners (Section 4.4.4) for more information.
|
|
|
Listeners |
|
Table 4.4 Effect of Different Combinations of Listeners and Status Bit Masks |
|
|||
|
|
|
|
|
|
|
No Bits Set in Mask |
Some/All Bits Set in Mask |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
For the statuses that are enabled in the |
|
|
Listener is |
Connext finds the next most relevant lis- |
mask, the most relevant listener will be |
|
|
called. |
|
||
|
Specified |
tener for the changed status. |
The 'statusChangedFlag' for the relevant |
|
|
|
|
|
|
|
|
|
status is reset. |
|
|
|
|
|
|
|
Listener is |
Connext behaves as if the listener is not |
Connext behaves as if the listener callback is |
|
|
installed and finds the next most relevant |
installed, but the callback is doing nothing. |
|
|
|
NULL |
|
||
|
listener for that status. |
This is called a ‘nil’ listener. |
|
|
|
|
|
||
|
|
|
|
|
4.4.2Creating and Deleting Listeners
There is no factory for creating or deleting a Listener; use the natural means in each language binding (for example, “new” or “delete” in C++ or Java). For example:
class HelloWorldListener : public DDSDataReaderListener { virtual void on_data_available(DDSDataReader* reader);
};
void HelloWorldListener::on_data_available(DDSDataReader* reader)
{
printf("received data\n");
}
// Create a Listener
HelloWorldListener *reader_listener = NULL; reader_listener = new HelloWorldListener();
// Delete a Listener delete reader_listener;
A listener cannot be deleted until the entity it is attached to has been deleted. For example, you must delete the DataReader before deleting the DataReader’s listener.
Note: Due to a
4.4.3Special Considerations for Listeners in C
In C, a Listener is a structure with function pointers to the user callback routines. Often, you may only be interested in a subset of the statuses that can be monitored with the Listener. In those cases, you may not set all of the functions pointers in a listener structure to a valid function. In that situation, we recommend that the unused,
To help, in the C language, we provide a macro that can be used to initialize a Listener structure so that all of its callback pointers are set to NULL. For example
DDS_<Entity>Listener listener = DDS_<Entity>Listener_INITIALIZER;
// now only need to set the listener callback pointers for statuses // to be monitored
There is no need to do this in languages other than C.
Listeners
4.4.4Hierarchical Processing of Listeners
As seen in Figure 4.3 on page
Suppose, however, that an Entity does not install a Listener, or installs a Listener that does not have particular communication status selected in the bitmask. In this case, if/when that particu- lar status changes for that Entity, the corresponding Listener for that Entity’s parent is called. Sta- tus changes are “propagated” from child Entity to parent Entity until a Listener is found that is registered for that status. Connext will give up and drop the
For example, suppose that Connext finds a matching DataWriter for a local DataReader. This event will change the SUBSCRIPTION_MATCHED status. So the local DataReader object is checked to see if the application has installed a listener that handles the SUBSCRIPTION_MATCH sta- tus. If not, the Subscriber that created the DataReader is checked to see if it has a listener installed that handles the same event. If not, the DomainParticipant is checked. The DomainParticipantLis- tener methods are called only if none of the descendent entities of the DomainParticipant have lis- teners that handle the particular status that has changed. Again, all listeners are optional. Your application does not have to handle any communication statuses.
Table 4.5 lists the callback functions that are available for each Entity’s status listener.
Table 4.5 Listener Callback Functions
Entity Listener for: |
Callback Functions |
|
|
|
|
|
Topics |
on_inconsistent_topic() |
|
|
|
|
|
on_liveliness_lost() |
|
|
|
|
|
on_offered_deadline_missed() |
|
|
|
|
Publishers and DataWriters |
on_offered_incompatible_qos() |
|
|
|
|
on_publication_matched() |
|
|
|
|
|
|
|
|
|
on_reliable_reader_activity_changed() |
|
|
|
|
|
on_reliable_writer_cache_changed() |
DomainParticipants |
|
|
Subscribers |
on_data_on_readers() |
|
|
|
|
|
|
on_data_available |
|
|
|
|
|
on_liveliness_changed() |
|
|
|
|
|
on_requested_deadline_missed() |
|
Subscribers and DataReaders |
|
|
on_requested_incompatible_qos() |
|
|
|
|
|
|
on_sample_lost() |
|
|
|
|
|
on_sample_rejected() |
|
|
|
|
|
on_subscription_matched() |
|
|
|
4.4.4.1Processing Read Communication Statuses
The processing of the DATA_ON_READERS and DATA_AVAILABLE read communication statuses are handled slightly differently since, when new data arrives for a DataReader, both sta-
Exclusive Areas (EAs)
tuses change simultaneously. However, only one, if any, Listener will be called to handle the event.
If there is a Listener installed to handle the DATA_ON_READERS status in the DataReader’s
Subscriber or in the DomainParticipant, then that Listener’s on_data_on_readers() function will be called back. The DataReaderListener’s on_data_available() function is called only if the DATA_ON_READERS status is not handle by any relevant listeners.
This can be useful if you have generic processing to do whenever new data arrives for any DataReader. You can execute the generic code in the on_data_on_readers() method, and then dis- patch the processing of the actual data to the specific DataReaderListener’s on_data_available() function by calling the notify_datareaders() method on the Subscriber.
For example:
void on_data_on_readers (DDSSubscriber *subscriber)
{
//Do some general processing that needs to be done
//whenever new data arrives, but is independent of
//any particular DataReader
< generic processing code here >
//Now dispatch the actual processing of the data
//to the specific DataReader for which the data
//was received
}
4.4.5Operations Allowed within Listener Callbacks
Due to the potential for deadlock, some Connext APIs should not be invoked within the func- tions of listener callbacks. Exactly which Connext APIs are restricted depends on the Entity upon which the Listener is installed, as well as the configuration of ‘Exclusive Areas,’ as discussed in Section 4.5.
Please read and understand Exclusive Areas (EAs) (Section 4.5) and Restricted Operations in Listener Callbacks (Section 4.5.1) to ensure that the calls made from your Listeners are allowed and will not cause potential deadlock situations.
4.5Exclusive Areas (EAs)
Listener callbacks are invoked by internal Connext threads. To prevent undesirable, multi- threaded interaction, the internal threads may take and hold semaphores (mutexes) used for mutual exclusion. In your listener callbacks, you may want to invoke functions provided by the Connext API. Internally, those Connext functions also may take mutexes to prevent errors due to
Exclusive Areas (EAs)
Once there are multiple mutexes to protect different critical regions, the possibility for deadlock exists. Consider Figure 4.4’s scenario, in which there are two threads and two mutexes.
Figure 4.4 Multiple Mutexes Leading to a Deadlock Condition
Thread1 |
Thread2 |
take(MutexA) |
take(MutexB) |
take(MutexB) |
take(MutexA) |
X |
X |
Deadlock!
Thread1 takes MutexA while simultaneously Thread2 takes MutexB. Then, Thread1 takes MutexB and simultaneously Thread2 takes MutexA. Now both threads are blocked since they hold a mutex that the other thread is trying to take. This is a deadlock condition.
While the probability of entering the deadlock situation in Figure 4.4 depends on execution tim- ing, when there are multiple threads and multiple mutexes, care must be taken in writing code to prevent those situations from existing in the first place. Connext has been carefully created and analyzed so that we know our threads internally are safe from deadlock interactions.
However, when Connext threads that are holding mutexes call user code in listeners, it is possi- ble for user code to inadvertently cause the threads to deadlock if Connext APIs that try to take other mutexes are invoked. To help you avoid this situation, RTI has defined a concept known as Exclusive Areas, some restrictions regarding the use of Connext APIs within user callback code, and a QoS policy that allows you to configure Exclusive Areas.
Connext uses Exclusive Areas (EAs) to encapsulate mutexes and critical regions. Only one thread at a time can be executing code within an EA. The formal definition of EAs and their implemen- tation ensures safety from deadlock and efficient entering and exiting of EAs. While every Entity created by Connext has an associated EA, EAs may be shared among several entities. A thread is automatically in the entity's EA when it is calling the entity’s listener.
Connext allows you to configure all the Entities within an application in a single domain to share a single Exclusive Area. This would greatly restrict the concurrency of thread execution within Connext’s
You may also have the best of both worlds by configuring a set of Entities to share a global EA and others to have their own. For the Entities that have their own EAs, the types of Connext oper- ations that you can call from the Entity’s callback are restricted.
To understand why the general EA framework limits the operations that can be called in an EA, consider a modification to the example previously presented in Figure 4.4. Suppose we create a rule that is followed when we write our code. “For all situations in which a thread has to take multiple mutexes, we write our code so that the mutexes are always taken in the same order.” Following the rule will ensure us that the code we write cannot enter a deadlock situation due to the taking of the mutexes, see Figure 4.5.
Connext defines an ordering of the mutexes it creates. Generally speaking, there are three ordered levels of Exclusive Areas:
Exclusive Areas (EAs)
Figure 4.5 Taking Multiple Mutexes in a Specific Order to Eliminate Deadlock
Thread1 |
Thread2 |
|
take(MutexA) |
X take(MutexA) |
|
take(MutexB) |
|
|
|
|
|
|
|
|
|
|
|
give(MutexB) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
give(MutexA) |
|
take(MutexB) |
|
||
|
||
|
||
|
|
|
|
|
|
By creating an order in which multiple mutexes are taken, you can guarantee that no deadlock situation will arise. In this case, if a thread must take both MutexA and MutexB, we write our code so that in those cases MutexA is always taken before MutexB.
❏ParticipantEA There is only one ParticipantEA per participant. The creation and dele- tion of all Entities (create_xxx(), delete_xxx()) take the ParticipantEA. In addition, the enable() method for an Entity and the setting of the Entity’s QoS, set_qos(), also take the ParticipantEA
❏SubscriberEA This EA is created on a
❏PublisherEA This EA is created on a
In addition, you should also be aware that:
❏The three EA levels are ordered in the following manner: ParticipantEA < SubscriberEA < PublisherEA
❏When executing user code in a listener callback of an Entity, the internal Connext thread is already in the EA of that Entity or used by that Entity.
❏If a thread is in an EA, it can call methods associated with either a higher EA level or that share the same EA. It cannot call methods associated with a lower EA level nor ones that use a different EA at the same level.
Exclusive Areas (EAs)
4.5.1Restricted Operations in Listener Callbacks
Based on the background and rules provided in Exclusive Areas (EAs) (Section 4.5), this section describes how EAs restrict you from using various Connext APIs from within the Listener call- backs of different Entities.
Note: these restrictions do not apply to builtin topic listener callbacks.
By default, each Publisher and Subscriber creates and uses its own EA, and shares it with its chil- dren DataWriters and DataReaders, respectively. In that case:
Within a DataWriter/DataReader’s Listener callback, do not:
❏create any entities
❏delete any entities
❏enable any entities
❏set QoS’s on any entities
Within a Subscriber/DataReader’s Listener callback, do not call any operations on:
❏Other Subscribers
❏DataReaders that belong to other Subscribers
❏Publishers/DataWriters that have been configured to use the ParticipantEA (see below)
Within a Publisher/DataWriter Listener callback, do not call any operations on:
❏Other Publishers
❏DataWriters that belong to other Publishers
❏Any Subscribers
❏Any DataReaders
Connext will enforce the rules to avoid deadlock, and any attempt to call an illegal method from within a Listener callback will return DDS_RETCODE_ILLEGAL_OPERATION.
However, as previously mentioned, if you are willing to
Use the EXCLUSIVE_AREA QosPolicy (DDS Extension) (Section 6.4.3) of the Publisher or Sub- scriber to set whether or not to use a shared exclusive area. By default, Publishers and Subscribers will create and use their own individual EAs. You can configure a subset of the Publishers and Subscribers to share the ParticipantEA if you need the Listeners associated with those entities or children entities to be able to call any of the restricted methods listed above.
Regardless of how the EXCLUSIVE_AREA QosPolicy is set, the following operations are never allowed in any Listener callback:
❏Destruction of the entity to which the Listener is attached. For instance, a DataWriter/
DataReader Listener callback must not destroy its DataWriter/DataReader.
❏Within the TopicListener callback, you cannot call any operations on DataReaders, DataW- riters, Publishers, Subscribers or DomainParticipants.
Conditions and WaitSets
4.6Conditions and WaitSets
Conditions and WaitSets provide another way for Connext to communicate status changes (including the arrival of data) to your application. While a Listener is used to provide a callback for asynchronous access, Conditions and WaitSets provide synchronous data access. In other words, Listeners are
A WaitSet allows an application to wait until one or more attached Conditions becomes true (or until a timeout expires).
Briefly, your application can create a WaitSet, attach one or more Conditions to it, then call the WaitSet’s wait() operation. The wait() blocks until one or more of the WaitSet’s attached Condi- tions becomes TRUE.
A Condition has a trigger_value that can be TRUE or FALSE. You can retrieve the current value by calling the Condition’s only operation, get_trigger_value().
There are three kinds of Conditions. A Condition is a root class for all the conditions that may be attached to a WaitSet. This basic class is specialized in three classes:
❏GuardConditions (Section 4.6.6) are created by your application. Each GuardCondition has a single,
❏ReadConditions and QueryConditions (Section 4.6.7) are created by your application, but triggered by Connext. ReadConditions provide a way for you to specify the data sam-
ples that you want to wait for, by indicating the desired
❏StatusConditions (Section 4.6.8) are created automatically by Connext, one for each Entity. A StatusCondition is triggered by Connext when there is a change to any of that Entity’s enabled statuses.
Figure 4.6 on page
A WaitSet can be associated with more than one Entity (including multiple DomainParticipants). It can be used to wait on Conditions associated with different DomainParticipants. A WaitSet can only be in use by one application thread at a time.
4.6.1Creating and Deleting WaitSets
There is no factory for creating or deleting a WaitSet; use the natural means in each language binding (for example, “new” or “delete” in C++ or Java).
For example, to delete a WaitSet:
delete waitset;
There are two ways to (DDS_WaitSetProperty_t
create a
❏If properties are not specified when the WaitSet is created, the WaitSet will wake up as soon as a trigger event occurs (that is, when an attached Condition becomes true). This is the default behavior if properties are not specified.
1.These states are described in The SampleInfo Structure (Section 7.4.6).
Conditions and WaitSets
Figure 4.6 Conditions and WaitSets
Table 4.6 WaitSet Properties (DDS_WaitSet_Property_t)
Type |
Field Name |
Description |
|
|
|
|
|
|
|
|
|
long |
max_event_count |
Maximum number of trigger events to cause a WaitSet to wake up. |
|
|
|
|
|
|
|
Maximum delay from occurrence of first trigger event to cause a |
|
|
|
WaitSet to wake up. |
|
DDS_Duration_t |
max_event_delay |
This value should reflect the maximum acceptable latency |
|
increase (time delay from occurrence of the event to waking up |
|||
|
|
||
|
|
the waitset) incurred as a result of waiting for additional events |
|
|
|
before waking up the waitset. |
|
|
|
|
Conditions and WaitSets
This ‘immediate
To create a WaitSet with default behavior:
WaitSet* waitset = new WaitSet();
❏If properties are specified when the WaitSet is created, the WaitSet will wait for either (a) up to max_event_count trigger events to occur, (b) up to max_event_delay time from the occurrence of the first trigger event, or (c) up to the timeout maximum wait duration specified in the call to wait().
To create a WaitSet with properties:
DDS_WaitSetProperty_t prop;
Prop.max_event_count = 5;
DDSWaitSet* waitset = new DDSWaitSet(prop);
4.6.2WaitSet Operations
WaitSets have only a few operations, as listed in Table 4.7 on page
Table 4.7 WaitSet Operations
Operation |
Description |
|
|
|
|
|
|
|
|
Attaches a Condition to this WaitSet. |
|
|
You may attach a Condition to a WaitSet that is currently being waited upon |
|
|
(via the wait() operation). In this case, if the Condition has a trigger_value of |
|
attach_condition |
TRUE, then attaching the Condition will unblock the WaitSet. |
|
|
Adding a Condition that is already attached to the WaitSet has no effect. If the |
|
|
Condition cannot be attached, Connext will return an OUT_OF_RESOURCES |
|
|
error code. |
|
|
|
|
|
Detaches a Condition from the WaitSet. Attempting to detach a Condition that is |
|
detach_condition |
not to attached the WaitSet will result in a PRECONDITION_NOT_MET |
|
|
error code. |
|
|
|
|
wait |
Blocks execution of the thread until one or more attached Conditions becomes true, or |
|
until a |
||
|
||
|
|
|
get_conditions |
Retrieves a list of attached Conditions. |
|
|
|
|
get_property |
Retrieves the DDS_WaitSetProperty_t structure of the associated WaitSet. |
|
|
|
|
set_property |
Sets the DDS_WaitSetProperty_t structure, to configure the associated WaitSet to |
|
return after one or more trigger events have occurred. |
||
|
||
|
|
4.6.3Waiting for Conditions
The WaitSet’s wait() operation allows an application thread to wait for any of the attached Condi- tions to trigger (become TRUE).
If any of the attached Conditions are already TRUE when wait() is called, it returns immediately. If none of the attached Conditions are TRUE, wait()
Conditions and WaitSets
wait() call will return when either (a) one or more of the attached Conditions becomes TRUE or
(b) a
Note: The resolution of the timeout period is constrained by the resolution of the system clock.
You can also configure the properties of the WaitSet so that it will wait for up to max_event_count trigger events to occur before returning, or for up to max_event_delay time from the occurrence of the first trigger event before returning. See Creating and Deleting Wait- Sets (Section 4.6.1).
If wait() does not timeout, it returns a list of the attached Conditions that became TRUE and therefore unblocked the wait.
If wait() does timeout, it returns TIMEOUT and an empty list of Conditions.
Only one application thread can be waiting on the same WaitSet. If wait() is called on a WaitSet that already has a thread blocking on it, the operation will immediately return PRECONDITION_NOT_MET.
Note: If you detach a Condition from a Waitset that is currently in a wait state (that is, you are waiting on it), wait() may return OK and an empty sequence of conditions.
4.6.3.1How WaitSets Block
The blocking behavior of the WaitSet is illustrated in Figure 4.7. The result of a wait() operation depends on the state of the WaitSet, which in turn depends on whether at least one attached Con- dition has a trigger_value of TRUE.
If the wait() operation is called on a WaitSet with state BLOCKED, it will block the calling thread. If wait() is called on a WaitSet with state UNBLOCKED, it will return immediately.
When the WaitSet transitions from BLOCKED to UNBLOCKED, it wakes up the thread (if there is one) that had called wait() on it. There is no implied “event queuing” in the awakening of a WaitSet. That is, if several Conditions attached to the WaitSet have their trigger_value transition to true in sequence, Connext will only unblock the WaitSet once.
Figure 4.7 WaitSet Blocking Behavior
4.6.4Processing Triggered
When wait() returns, it provides a list of the attached Condition objects that have a trigger_value of true. Your application can use this list to do the following for each Condition in the returned list:
❏If it is a StatusCondition:
• First, call get_status_changes() to see what status changed.
Conditions and WaitSets
•If the status changes refer to plain communication status: call get_<communication_status>() on the relevant Entity.
•If the status changes refer to DATA_ON_READERS1: call get_datareaders() on the rel- evant Subscriber.
•If the status changes refer to DATA_AVAILABLE: call read() or take() on the relevant
DataReader.
❏If it is a ReadCondition or a QueryCondition: You may want to call read_w_condition() or take_w_condition() on the DataReader, with the ReadCondition as a parameter (see read_w_condition and take_w_condition (Section 7.4.3.6)).
Note that this is just a suggestion, you do not have to use the “w_condition” operations (or any read/take operations, for that matter) simply because you used a WaitSet. The “w_condition” operations are just a convenient way to use the same status masks that were set on the ReadCondition or QueryCondition.
❏If it is a GuardCondition: check to see which GuardCondition changed, then react accord- ingly. Recall that GuardConditions are completely controlled by your application.
See Conditions and WaitSet Example (Section 4.6.5) to see how to determine which of the attached Conditions is in the returned list.
4.6.5Conditions and WaitSet Example
This example creates a WaitSet and then waits for one or more attached Conditions to become true.
// Create a WaitSet
WaitSet* waitset = new WaitSet();
// Attach Conditions DDSCondition* cond1 = ...;
DDSCondition* cond2 =
DDS_ANY_VIEW_STATE, DDS_ANY_INSTANCE_STATE);
DDSCondition* cond4 = new DDSGuardCondition();
DDSCondition* cond5 = ...;
DDS_ReturnCode_t retcode;
retcode =
// ... error
}
retcode =
// ... error
}
retcode =
// ... error
}
retcode =
1. And then read/take on the returned DataReader objects.
Conditions and WaitSets
// ... error
}
retcode =
// ... error
}
// Wait for a condition to trigger or timeout
DDS_Duration_t timeout = { 0, 1000000 }; // 1ms
DDSConditionSeq active_conditions; // holder for active conditions bool is_cond1_triggered = false;
bool is_cond2_triggered = false; DDS_ReturnCode_t retcode;
retcode =
if (retcode == DDS_RETCODE_TIMEOUT) { // handle timeout
printf("Wait timed out. No conditions were triggered.\n");
}
else if (retcode != DDS_RETCODE_OK) {
//... check for cause of failure
}else {
//success
if (active_conditions.length() == 0) {
printf("Wait timed out!! No conditions triggered.\n");
}else
// check if "cond1" or "cond2" are triggered: for(i = 0; i < active_conditions.length(); ++i) {
if (active_conditions[i] == cond1) { printf("Cond1 was triggered!"); is_cond1_triggered = true;
}
if (active_conditions[i] == cond2) { printf("Cond2 was triggered!"); is_cond2_triggered = true;
}
if (is_cond1_triggered && is_cond2_triggered) { break;
}
}
}
}
if (is_cond1_triggered) {
// ... do something because "cond1" was triggered ...
}
if (is_cond2_triggered) {
// ... do something because "cond2" was triggered ...
}
// Delete the waitset delete waitset; waitset = NULL;
Conditions and WaitSets
4.6.6GuardConditions
GuardConditions are created by your application. GuardConditions provide a way for your appli- cation to manually awaken a WaitSet. Like all Conditions, it has a single boolean trigger_value. Your application can manually trigger the GuardCondition by calling set_trigger_value().
Connext does not trigger or clear this type of
A GuardCondition has no factory. It is created as an object directly by the natural means in each language binding (e.g., using “new” in C++ or Java). For example:
// Create a Guard Condition
Condition* my_guard_condition = new GuardCondition();
// Delete a Guard Condition delete my_guard_condition;
When first created, the trigger_value is FALSE.
A GuardCondition has only two operations, get_trigger_value() and set_trigger_value().
When your application calls set_trigger_value(DDS_BOOLEAN_TRUE), Connext will awaken any WaitSet to which the GuardCondition is attached.
4.6.7ReadConditions and QueryConditions
ReadConditions are created by your application, but triggered by Connext. ReadConditions provide
a way for you to specify the data samples that you want to wait for, by indicating the desired
A QueryCondition is a special ReadCondition that allows you to specify a query expression and parameters, so you can filter on the locally available (already received) data. QueryConditions use the same
Multiple mask combinations can be associated with a single content filter. This is important because the maximum number of content filters that may be created per DataReader is 32, but more than 32 QueryConditions may be created per DataReader, if they are different
ReadConditions and QueryConditions are created by using the DataReader’s create_readcondition() and create_querycondition() operations. For example:
DDSReadCondition* my_read_condition = reader->create_readcondition( DDS_NOT_READ_SAMPLE_STATE, DDS_ANY_VIEW_STATE, DDS_ANY_INSTANCE_STATE);
DDSQueryCondition* my_query_condition = reader->create_querycondition( DDS_NOT_READ_SAMPLE_STATE, DDS_ANY_VIEW_STATE, DDS_ANY_INSTANCE_STATE query_expression, query_parameters);
1. These states are described in The SampleInfo Structure (Section 7.4.6).
Conditions and WaitSets
Note: If you are using a ReadCondition to simply detect the presence of new data, consider using a StatusCondition (Section 4.6.8) with the DATA_AVAILABLE_STATUS instead, which will per- form better in this situation.
A DataReader can have multiple attached ReadConditions and QueryConditions. A ReadCondition or QueryCondition may only be attached to one DataReader.
To delete a ReadCondition or QueryCondition, use the DataReader’s delete_readcondition() opera- tion:
DDS_ReturnCode_t delete_readcondition (DDSReadCondition *condition)
After a ReadCondition is triggered, use the FooDataReader’s read/take “with condition” opera- tions (see Section 7.4.3.6) to access the samples.
Table 4.8 lists the operations available on ReadConditions.
Table 4.8 ReadCondition and QueryCondition Operations
Operation |
Description |
|
|
|
|
|
|
|
get_datareader |
Returns the DataReader to which the ReadCondition or QueryCondition is |
|
attached. |
||
|
||
|
|
|
|
Returns the instance states that were specified when the ReadCondition or Que- |
|
get_instance_state_mask |
ryCondition was created. These are the sample’s instance states that Connext |
|
|
checks to determine whether or not to trigger the ReadCondition or QueryCondi- |
|
|
tion . |
|
|
|
|
|
Returns the |
|
get_sample_state_mask |
Condition was created. These are the sample states that Connext checks to deter- |
|
|
mine whether or not to trigger the ReadCondition or QueryCondition. |
|
|
|
|
|
Returns the |
|
get_view_state_mask |
Condition was created. These are the view states that Connext checks to deter- |
|
|
mine whether or not to trigger the ReadCondition or QueryCondition. |
|
|
|
4.6.7.1How ReadConditions are Triggered
A ReadCondition has a trigger_value that determines whether the attached WaitSet is BLOCKED or UNBLOCKED. Unlike the StatusCondition, the trigger_value of the ReadCondition is tied to the presence of at least one sample with a
The trigger_value of a ReadCondition depends on the presence of samples on the associated DataReader. This implies that a single ‘take’ operation can potentially change the trigger_value of several ReadConditions or QueryConditions. For example, if all samples are taken, any ReadCon- ditions and QueryConditions associated with the DataReader that had trigger_value==TRUE before will see the trigger_value change to FALSE. Note that this does not guarantee that Wait- Set objects that were separately attached to those conditions will not be awakened. Once we have trigger_value==TRUE on a condition, it may wake up the attached WaitSet, the condition transitioning to trigger_value==FALSE does not necessarily 'unwakeup' the WaitSet, since 'unwakening' may not be possible. The consequence is that an application blocked on a WaitSet may return from wait() with a list of conditions, some of which are no longer “active.” This is unavoidable if multiple threads are concurrently waiting on separate WaitSet objects and taking data associated with the same DataReader.
Consider the following example: A ReadCondition that has a sample_state_mask = {NOT_READ} will have a trigger_value of TRUE whenever a new sample arrives and will tran- sition to FALSE as soon as all the newly arrived samples are either read (so their status changes
Conditions and WaitSets
to READ) or taken (so they are no longer managed by Connext). However, if the same ReadCondi- tion had a sample_state_mask = {READ, NOT_READ}, then the trigger_value would only become FALSE once all the newly arrived samples are taken (it is not sufficient to just read them, since that would only change the SampleState to READ), which overlaps the mask on the Read- Condition.
4.6.7.2QueryConditions
A QueryCondition is a special ReadCondition that allows your application to also specify a filter on the locally available data.
The query expression is similar to a SQL WHERE clause and can be parameterized by argu- ments that are dynamically changeable by the set_query_parameters() operation.
QueryConditions are triggered in the same manner as ReadConditions, with the additional require- ment that the sample must also satisfy the conditions of the content filter associated with the
QueryCondition.
Table 4.9 QueryCondition Operations
Operation |
Description |
|
|
|
|
|
|
|
get_query_expression |
Returns the query expression specified when the QueryCondition was created. |
|
|
|
|
|
Returns the query parameters associated with the QueryCondition. That is, the |
|
get_query_parameters |
parameters specified on the last successful call to set_query_parameters(), or if |
|
set_query_parameters() was never called, the arguments specified when the Que- |
||
|
||
|
ryCondition was created. |
|
|
|
|
set_query_parameters |
Changes the query parameters associated with the QueryCondition. |
|
|
|
4.6.8StatusConditions
StatusConditions are created automatically by Connext, one for each Entity. Connext will trigger the StatusCondition when there is a change to any of that Entity’s enabled statuses.
By default, when Connext creates a StatusCondition, all status bits are turned on, which means it will check for all statuses to determine when to trigger the StatusCondition. If you only want Con- next to check for specific statuses, you can use the StatusCondition’s set_enabled_statuses() oper- ation and set just the desired status bits.
The trigger_value of the StatusCondition depends on the communication status of the Entity (e.g., arrival of data, loss of information, etc.), ‘filtered’ by the set of enabled statuses on the Sta- tusCondition.
The set of enabled statuses and its relation to Listeners and WaitSets is detailed in How Status- Conditions are Triggered (Section 4.6.8.1).
Table 4.10 lists the operations available on StatusConditions.
Unlike other types of Conditions, StatusConditions are created by Connext, not by your applica- tion. To access an Entity’s StatusCondition, use the Entity’s get_statuscondition() operation. For example:
Condition* my_status_condition =
After a StatusCondition is triggered, call the Entity’s get_status_changes() operation to see which status(es) changed.
Conditions and WaitSets
Table 4.10 StatusCondition Operations
Operation |
|
Description |
|
|
|
||
|
|
||
|
Defines the list of communication statuses that are taken into account to deter- |
||
|
mine the trigger_value of the StatusCondition. This operation may change the |
||
|
trigger_value of the StatusCondition. |
||
set_enabled_statuses |
WaitSets behavior depend on the changes of the trigger_value of their attached |
||
conditions. Therefore, any WaitSet to which the StatusCondition is attached is |
|||
|
|||
|
potentially affected by this operation. |
||
|
If this function is not invoked, the default list of enabled statuses includes all the |
||
|
statuses. |
|
|
|
|
||
|
Retrieves the list of communication statuses that are taken into account to deter- |
||
get_enabled_statuses |
mine the trigger_value of the StatusCondition. This operation returns the statuses |
||
that were explicitly set on |
the last call to set_enabled_statuses() or, if |
||
|
|||
|
set_enabled_statuses() was never called, the default list |
||
|
|
||
get_entity |
Returns the Entity associated with the StatusCondition. Note that there is exactly |
||
one Entity associated with each StatusCondition. |
|||
|
|||
|
|
|
4.6.8.1How StatusConditions are Triggered
The trigger_value of a StatusCondition is the boolean OR of the ChangedStatusFlag of all the communication statuses to which it is sensitive. That is, trigger_value==FALSE only if all the values of the ChangedStatusFlags are FALSE.
The sensitivity of the StatusCondition to a particular communication status is controlled by the list of enabled_statuses set on the Condition by means of the set_enabled_statuses() operation.
4.6.9Using Both Listeners and WaitSets
You can use Listeners and WaitSets in the same application. For example, you may want to use WaitSets and Conditions to access the data, and Listeners to be warned asynchronously of errone- ous communication statuses.
We recommend that you choose one or the other mechanism for each particular communication status (not both). However, if both are enabled, the Listener mechanism is used first, then the WaitSet objects are signaled.
Chapter 5 Topics
For a DataWriter and DataReader to communicate, they need to use the same Topic. A Topic includes a name and an association with a user data type that has been registered with Connext. Topic names are how different parts of the communication system find each other. Topics are named streams of data of the same data type. DataWriters publish samples into the stream; DataReaders subscribe to data from the stream. More than one Topic can use the same user data type, but each Topic needs a unique name.
Topics, DataWriters, and DataReaders relate to each other as follows:
❏Multiple Topics (each with a unique name) can use the same user data type.
❏Applications may have multiple DataWriters for each Topic.
❏Applications may have multiple DataReaders for each Topic.
❏DataWriters and DataReaders must be associated with the same Topic in order for them to be connected.
❏Topics are created and deleted by a DomainParticipant, and as such, are owned by that DomainParticipant. When two applications (DomainParticipants) want to use the same Topic, they must both create the Topic (even if the applications are on the same node).
This chapter includes the following sections:
❏Topic QosPolicies (Section 5.2)
❏Status Indicator for Topics (Section 5.3)
❏ContentFilteredTopics (Section 5.4)
Builtin Topics: Connext uses ‘Builtin Topics’ to discover and keep track of remote entities, such as new participants in the domain. Builtin Topics are discussed in Chapter 16.
5.1Topics
Before you can create a Topic, you need a user data type (see Chapter 3) and a DomainParticipant (Section 8.3). The user data type must be registered with the DomainParticipant (as we saw in the User Data Types chapter in Section 3.8.5.1).
Once you have created a Topic, what do you do with it? Topics are primarily used as parameters in other Entities’ operations. For instance, a Topic is required when a Publisher or Subscriber cre- ates a DataWriter or DataReader, respectively. Topics do have a few operations of their own, as
Topics
listed in Table 5.1. For details on using these operations, see the reference section or the API Ref- erence HTML documentation.
Figure 5.1 Topic Module
|
|
|
Note: MultiTopics |
are not |
|
|
|
supported. |
|
Table 5.1 Topic Operations |
|
|
||
|
|
|
|
|
|
Purpose |
Operation |
Description |
Reference |
|
|
|
|
|
|
|
enable |
Enables the Topic. |
|
|
|
|
|
|
|
|
get_qos |
Gets the Topic’s current QosPolicy settings. This is most |
|
|
|
often used in preparation for calling set_qos(). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Sets the Topic’s QoS. You can use this operation to change |
|
|
|
set_qos |
the values for the Topic’s QosPolicies. Note, however, |
|
|
|
that not all QosPolicies can be changed after the Topic has |
||
|
|
|
been created. |
|
|
|
|
|
|
|
Configuring |
set_qos_with_ |
Sets the Topic’s QoS based on a specified QoS profile. |
|
|
the Topic |
profile |
|
|
|
get_listener |
Gets the currently installed Listener. |
|
|
|
|
|
||
|
|
|
|
|
|
|
|
Sets the Topic’s Listener. If you create the Topic without a |
|
|
|
set_listener |
Listener, you can use this operation to add one later. Set- |
|
|
|
ting the listener to NULL will remove the listener from |
|
|
|
|
|
|
|
|
|
|
the Topic. |
|
|
|
|
|
|
|
|
|
A |
|
|
|
narrow |
icDescription pointer and ‘narrows’ it to a DDSTopic |
|
|
|
|
pointer. |
|
|
|
|
|
|
|
|
|
|
Topics |
Table 5.1 Topic Operations |
|
|
||
|
|
|
|
|
|
Purpose |
Operation |
Description |
Reference |
|
|
|
|
|
|
|
|
|
|
|
|
get_inconsistent_ |
Allows an application to retrieve a Topic’s |
|
|
Checking |
topic_status |
INCONSISTENT_TOPIC_STATUS status. |
|
|
|
Gets a list of statuses that have changed since the last |
|
|
|
Status |
|
|
|
|
get_status_changes |
time the application read the status or the listeners were |
||
|
|
|||
|
|
|
called. |
|
|
|
|
|
|
|
Navigating |
get_name |
Gets the topic_name string used to create the Topic. |
|
|
|
|
||
|
Relation- |
get_type_name |
Gets the type_name used to create the Topic. |
|
|
|
|||
|
ships |
|
|
|
|
get_participant |
Gets the DomainParticipant to which this Topic belongs. |
||
|
|
|||
|
|
|
|
|
5.1.1Creating Topics
Topics are created using the DomainParticipant’s create_topic() or create_topic_with_profile() operation:
DDSTopic * create_topic (const char *topic_name, const char *type_name, const DDS_TopicQos &qos,
DDSTopicListener *listener, DDS_StatusMask mask)
DDSTopic * create_topic_with_profile (
const char *topic_name, const char *type_name, const char *library_name, const char *profile_name,
DDSTopicListener *listener, DDS_StatusMask mask)
A QoS profile is way to use QoS settings from an XML file or string. With this approach, you can change QoS settings without recompiling the application. For details, see Chapter 17: Configuring QoS with XML.
topic_name Name for the new Topic, must not exceed 255 characters.
type_name |
Name for the user data type, must not exceed 255 characters. It must be the same |
|
name that was used to register the type, and the type must be registered with the |
|
same DomainParticipant used to create this Topic. See Section 3.6. |
qos |
If you want to use the default QoS settings (described in the API Reference HTML |
|
documentation), use DDS_TOPIC_QOS_DEFAULT for this parameter (see |
|
Figure 5.2). If you want to customize any of the QosPolicies, supply a QoS struc- |
|
ture (see Section 5.1.3). |
|
If you use DDS_TOPIC_QOS_DEFAULT, it is not safe to create the topic while |
|
another thread may be simultaneously calling the DomainParticipant’s |
|
set_default_topic_qos() operation. |
listener |
Listeners are callback routines. Connext uses them to notify your application of spe- |
|
cific events (status changes) that may occur with respect to the Topic. The listener |
|
parameter may be set to NULL if you do not want to install a Listener. If you use |
|
NULL, the Listener of the DomainParticipant to which the Topic belongs will be |
|
used instead (if it is set). For more information on TopicListeners, see Section 5.1.5. |
|
Topics |
mask |
This |
|
The bits in the mask that are set must have corresponding callbacks implemented |
|
in the Listener. If you use NULL for the Listener, use |
|
DDS_STATUS_MASK_NONE for this parameter. If the Listener implements all |
|
callbacks, use DDS_STATUS_MASK_ALL. For information on statuses, see Lis- |
|
library_name A QoS Library is a named set of QoS profiles. See QoS Libraries (Section 17.10). If NULL is used for library_name, the DomainParticipant’s default library is assumed.
profile_name A QoS profile groups a set of related QoS, usually one per entity. See QoS Profiles (Section 17.9). If NULL is used for profile_name, the DomainParticipant’s default profile is assumed and library_name is ignored.
Note: It is not safe to create a topic while another thread is calling lookup_topicdescription() for that same topic (see Section 8.3.7).
Figure 5.2 Creating a Topic with Default QosPolicies
const char *type_name = NULL;
// register the type
type_name = FooTypeSupport::get_type_name();
retcode = FooTypeSupport::register_type(participant, type_name); if (retcode != DDS_RETCODE_OK) {
// handle error
}
// create the topic
DDSTopic* topic =
if (topic == NULL) {
// process error here
};
For more examples, see Configuring QoS Settings when the Topic is Created (Section 5.1.3.1).
5.1.2Deleting Topics
To delete a Topic, use the DomainParticipant’s delete_topic() operation:
DDS_ReturnCode_t delete_topic (DDSTopic * topic)
Note, however, that you cannot delete a Topic if there are any existing DataReaders or DataWriters (belonging to the same DomainParticipant) that are still using it. All DataReaders and DataWriters associated with the Topic must be deleted first.
5.1.3Setting Topic QosPolicies
A Topic’s QosPolicies control its behavior, or more specifically, the behavior of the DataWriters and DataReaders of the Topic. You can think of the policies as the ‘properties’ for the Topic. The DDS_TopicQos structure has the following format:
DDS_TopicQos struct { |
|
DDS_TopicDataQosPolicy |
topic_data; |
DDS_DurabilityQosPolicy |
durability; |
DDS_DurabilityServiceQosPolicy |
durability_service; |
DDS_DeadlineQosPolicy |
deadline; |
Topics
DDS_LatencyBudgetQosPolicy |
latency_budget; |
DDS_LivelinessQosPolicy |
liveliness; |
DDS_ReliabilityQosPolicy |
reliability; |
DDS_DestinationOrderQosPolicy |
destination_order; |
DDS_HistoryQosPolicy |
history; |
DDS_ResourceLimitsQosPolicy |
resource_limits; |
DDS_TransportPriorityQosPolicy |
transport_priority; |
DDS_LifespanQosPolicy |
lifespan; |
DDS_OwnershipQosPolicy |
ownership; |
} DDS_TopicQos; |
|
Table 5.2 summarizes the meaning of each policy (arranged alphabetically). For information on why you would want to change a particular QosPolicy, see the section noted in the Reference column. For defaults and valid ranges, please refer to the API Reference HTML documentation for each policy.
Table 5.2 Topic QosPolicies
QosPolicy |
Description |
|
|
|
|
|
|
|
|
For a DataReader, specifies the maximum expected elapsed time between arriving |
|
|
data samples. |
|
Deadline |
For a DataWriter, specifies a commitment to publish samples with no greater |
|
|
elapsed time between them. |
|
|
See Section 6.5.5. |
|
|
|
|
|
Controls how Connext will deal with data sent by multiple DataWriters for the |
|
DestinationOrder |
same topic. Can be set to "by reception timestamp" or to "by source timestamp". |
|
|
See Section 6.5.6. |
|
|
|
|
Durability |
Specifies whether or not Connext will store and deliver data that were previously |
|
published to new DataReaders. See Section 6.5.7. |
||
|
||
|
|
|
DurabilityService |
Various settings to configure the external Persistence Service used by Connext for |
|
DataWriters with a Durability QoS setting of Persistent Durability. See Section 6.5.8. |
||
|
|
|
|
Specifies how much data must to stored by Connext for the DataWriter or |
|
History |
DataReader. This QosPolicy affects the RELIABILITY QosPolicy (Section 6.5.19) as |
|
|
well as the DURABILITY QosPolicy (Section 6.5.7). See Section 6.5.10. |
|
LatencyBudget |
Suggestion to Connext on how much time is allowed to deliver data. See |
|
|
||
|
|
|
Lifespan |
Specifies how long Connext should consider data sent by an user application to be |
|
valid. See Section 6.5.12. |
||
|
||
|
|
|
Liveliness |
Specifies and configures the mechanism that allows DataReaders to detect when |
|
DataWriters become disconnected or "dead." See Section 6.5.13. |
||
|
||
|
|
|
Ownership |
Along with Ownership Strength, specifies if DataReaders for a topic can receive |
|
data from multiple DataWriters at the same time. See Section 6.5.15. |
||
|
||
|
|
|
Reliability |
Specifies whether or not Connext will deliver data reliably. See Section 6.5.19. |
|
|
|
|
|
Controls the amount of physical memory allocated for entities, if dynamic alloca- |
|
ResourceLimits |
tions are allowed, and how they occur. Also controls memory usage among differ- |
|
|
ent instance values for keyed topics. See Section 6.5.20. |
|
|
|
|
TopicData |
Along with Group Data QosPolicy and User Data QosPolicy, used to attach a buf- |
|
fer of bytes to Connext's discovery |
||
|
||
|
|
|
TransportPriority |
Set by a DataWriter to tell Connext that the data being sent is a different "priority" |
|
than other data. See Section 6.5.21. |
||
|
||
|
|
Topics
5.1.3.1Configuring QoS Settings when the Topic is Created
As described in Creating Topics (Section 5.1.1), there are different ways to create a Topic, depend- ing on how you want to specify its QoS (with or without a QoS profile).
❏In Figure 5.2 on page
❏To create a Topic with
❏You can also create a Topic and specify its QoS settings via a QoS profile. To do so, call create_topic_with_profile().
❏If you want to use a QoS profile, but then make some changes to the QoS before creating the Topic, call get_topic_qos_from_profile(), modify the QoS and use the modified QoS when calling create_topic().
5.1.3.2Changing QoS Settings After the Topic Has Been Created
There are 2 ways to change an existing Topic’s QoS after it is has been
❏To change QoS programmatically (that is, without using a QoS Profile), see the example code in Figure 5.3 on page
❏You can also change a Topic’s (and all other Entities’) QoS by using a QoS Profile. For an example, see Figure 5.4 on page
Figure 5.3 Changing the QoS of an Existing Topic (without a QoS Profile)
DDS_TopicQos topic_qos;1
// Get current QoS. topic points to an existing DDSTopic. if
// handle error
}
//Next, make changes.
//New ownership kind will be Exclusive
topic_qos.ownership.kind = DDS_EXCLUSIVE_OWNERSHIP_QOS;
// Set the new QoS
if
}
1. For the C API, you need to use DDS_TopicQos_INITIALIZER or DDS_TopicQos_initialize(). See Spe- cial QosPolicy Handling Considerations for C (Section 4.2.2)
Topics
Figure 5.4 Changing the QoS of an Existing Topic with a QoS Profile
retcode =
“FooProfileLibrary”,”FooProfile”);
if (retcode != DDS_RETCODE_OK) { // handle error
}
5.1.4Copying QoS From a Topic to a DataWriter or DataReader
Only the TOPIC_DATA QosPolicy strictly applies to
DDS_TopicQos structure.
Because many QosPolicies affect the behavior of matching DataWriters and DataReaders, the DDS_TopicQos structure is provided as a convenient way to set the values for those policies in a single place in the application. Otherwise, you would have to modify the individual QosPoli- cies within separate DataWriter and DataReader QoS structures. And because some QosPolicies are compared between DataReaders and DataWriters, you will need to make certain that the indi- vidual values that you set are compatible (see Section 4.2.1).
The use of the DDS_TopicQos structure to set the values of any QosPolicy except
To cause a DataWriter to use its Topic’s QoS settings, either:
❏Pass DDS_DATAWRITER_QOS_USE_TOPIC_QOS to create_datawriter(), or
❏Call the Publisher’s copy_from_topic_qos() operation
To cause a DataReader to use its Topic’s QoS settings, either:
❏Pass DDS_DATAREADER_QOS_USE_TOPIC_QOS to create_datareader(), or
❏Call the Subscriber’s copy_from_topic_qos() operation
Please refer to the API Reference HTML documentation for the Publisher’s create_datawriter() and Subscriber’s create_datareader() methods for more information about using values from the
Topic QosPolicies when creating DataWriters and DataReaders.
5.1.5Setting Up TopicListeners
When you create a Topic, you have the option of giving it a Listener. A TopicListener includes just one callback routine, on_inconsistent_topic(). If you create a TopicListener (either as part of the Topic creation call, or later with the set_listener() operation), Connext will invoke the TopicLis- tener’s on_inconsistent_topic() method whenever it detects that another application has created a Topic with same name but associated with a different user data type. For more information, see INCONSISTENT_TOPIC Status (Section 5.3.1).
Note: Some operations cannot be used within a listener callback, see Restricted Operations in Listener Callbacks (Section 4.5.1).
If a Topic’s Listener has not been set and Connext detects an inconsistent Topic, the DomainPartici- pantListener (if it exists) will be notified instead (see Section 8.3.5). So you only need to set up a
Topic QosPolicies
TopicListener if you need to perform specific actions when there is an error on that particular Topic. In most cases, you can set the TopicListener to NULL and process
5.1.6Navigating Relationships Among Entities
5.1.6.1Finding a Topic’s DomainParticipant
To retrieve a handle to the Topic’s DomainParticipant, use the get_participant() operation:
DDSDomainParticipant*DDSTopicDescription::get_participant()
Notice that this method belongs to the DDSTopicDescription class, which is the base class for
DDSTopic.
5.1.6.2Retrieving a Topic’s Name or Type Name
If you want to retrieve the topic_name or type_name used in the create_topic() operation, use these methods:
const char* DDSTopicDescription::get_type_name(); const char* DDSTopicDescription::get_name();
Notice that these methods belong to the DDSTopicDescription class, which is the base class for
DDSTopic.
5.2Topic QosPolicies
This section describes the only QosPolicy that strictly applies to Topics (and no other types of
Most of the QosPolicies that can be set on a Topic can also be set on the corresponding DataWriter and/or DataReader. The Topic’s QosPolicy is essentially just a place to store QoS settings that you plan to share with multiple entities that use that Topic (see how in Section 5.1.3); they are not used otherwise and are not propagated on the wire.
5.2.1TOPIC_DATA QosPolicy
This QosPolicy provides an area where your application can store additional information related to the Topic. This information is passed between applications during discovery (see Chapter 14: Discovery) using
The value of the TOPIC_DATA QosPolicy is sent to remote applications when they are first dis- covered, as well as when the Topic’s set_qos() method is called after changing the value of the TOPIC_DATA. User code can set listeners on the builtin DataReaders of the builtin Topics used by Connext to propagate discovery information. Methods in the builtin topic listeners will be called whenever new applications, DataReaders, and DataWriters are found. Within the user callback, you will have access to the TOPIC_DATA that was set for the associated Topic.
Currently, TOPIC_DATA of the associated Topic is only propagated with the information that declares a DataWriter or DataReader. Thus, you will need to access the value of TOPIC_DATA
Topic QosPolicies
through DDS_PublicationBuiltinTopicData or DDS_SubscriptionBuiltinTopicData (see Chapter 16:
The structure for the TOPIC_DATA QosPolicy includes just one field, as seen in Table 5.3. The field is a sequence of octets that translates to a contiguous buffer of bytes whose contents and length is set by the user. The maximum size for the data are set in the DOMAIN_PARTICIPANT_RESOURCE_LIMITS QosPolicy (DDS Extension) (Section 8.5.4).
Table 5.3 DDS_TopicDataQosPolicy
Type |
Field Name |
Description |
|
|
|
|
|
|
DDS_OctetSeq |
value |
default: empty |
|
|
|
This policy is similar to the GROUP_DATA (Section 6.4.4) and USER_DATA (Section 6.5.25) pol- icies that apply to other types of Entities.
5.2.1.1Example
One possible use of TOPIC_DATA is to send an associated XML schema that can be used to pro- cess the data stored in the associated user data structure of the Topic. The schema, which can be passed as a long sequence of characters, could be used by an XML parser to take samples of the data received for a Topic and convert them for updating some graphical user interface, web application or database.
5.2.1.2Properties
This QosPolicy can be modified at any time. A change in the QosPolicy will cause Connext to send packets containing the new TOPIC_DATA to all of the other applications in the domain.
Because Topics are created independently by the applications that use the Topic, there may be dif- ferent instances of the same Topic (same topic name and data type) in different applications. The TOPIC_DATA for different instances of the same Topic may be set differently by different appli- cations.
5.2.1.3Related QosPolicies
❏GROUP_DATA QosPolicy (Section 6.4.4)
❏USER_DATA QosPolicy (Section 6.5.25)
❏DOMAIN_PARTICIPANT_RESOURCE_LIMITS QosPolicy (DDS Extension) (Section 8.5.4)
5.2.1.4Applicable Entities
5.2.1.5System Resource Considerations
As mentioned earlier, the maximum size of the TOPIC_DATA is set in the topic_data_max_length field of the DOMAIN_PARTICIPANT_RESOURCE_LIMITS QosPolicy (DDS Extension) (Section 8.5.4). Because Connext will allocate memory based on this value, you should only increase this value if you need to. If your system does not use TOPIC_DATA, then you can set this value to 0 to save memory. Setting the value of the TOPIC_DATA QosPolicy to hold data longer than the value set in the topic_data_max_length field will result in failure and an INCONSISTENT_QOS_POLICY return code.
Status Indicator for Topics
However, should you decide to change the maximum size of TOPIC_DATA, you must make cer- tain that all applications in the domain have changed the value of topic_data_max_length to be the same. If two applications have different limits on the size of TOPIC_DATA, and one applica- tion sets the TOPIC_DATA QosPolicy to hold data that is greater than the maximum size set by another application, then the DataWriters and DataReaders of that Topic between the two applica- tions will not connect. This is also true for the GROUP_DATA (Section 6.4.4) and USER_DATA (Section 6.5.25) QosPolicies.
5.3Status Indicator for Topics
There is only one communication status defined for a Topic, ON_INCONSISTENT_TOPIC. You can use the get_inconsistent_topic_status() operation to access the current value of the status or use a TopicListener to catch the change in the status as it occurs. See Section 4.4 for a general dis- cussion on Listeners and Statuses.
5.3.1INCONSISTENT_TOPIC Status
In order for a DataReader and a DataWriter with the same Topic to communicate, their types must be consistent according to the DataReader’s
The status is a structure of type DDS_InconsistentTopicStatus, see Table 5.4. The total_count keeps track of the total number of (DataReader, DataWriter) pairs with topic names that match the Topic to which this status is attached, but whose types are inconsistent. The TopicListener’s on_inconsistent_topic() operation is invoked when this status changes (an inconsistent topic is found). You can also retrieve the current value by calling the Topic’s get_inconsistent_topic_status() operation.
The value of total_count_change reflects the number of inconsistent topics that were found since the last time get_inconsistent_topic_status() was called by user code or on_inconsistent_topic() was invoked by Connext.
Table 5.4 DDS_InconsistentTopicStatus Structure
Type |
Field Name |
Description |
|
|
|
|
|
|
|
|
Total cumulative count of (DataReader, DataWriter) pairs whose topic |
DDS_Long |
total_count |
names match the Topic to which this status is attached, but whose |
|
|
types are inconsistent. |
|
|
|
DDS_Long |
total_count_change |
The change in total_count since the last time this status was read. |
|
|
|
5.4ContentFilteredTopics
A ContentFilteredTopic is a Topic with filtering properties. It makes it possible to subscribe to topics and at the same time specify that you are only interested in a subset of the Topic’s data.
For example, suppose you have a Topic that contains a temperature reading for a boiler, but you are only interested in temperatures outside the normal operating range. A ContentFilteredTopic
ContentFilteredTopics
can be used to limit the number of data samples a DataReader has to process and may also reduce the amount of data sent over the network.
This section includes the following:
❏Where Filtering is
❏Creating ContentFilteredTopics (Section 5.4.3)
❏Deleting ContentFilteredTopics (Section 5.4.4)
❏Using a ContentFilteredTopic (Section 5.4.5)
❏SQL Filter Expression Notation (Section 5.4.6)
❏STRINGMATCH Filter Expression Notation (Section 5.4.7)
❏Custom Content Filters (Section 5.4.8)
5.4.1Overview
A ContentFilteredTopic creates a relationship between a Topic, also called the related topic, and
❏The filter expression evaluates a logical expression on the Topic content. The filter expression is similar to the WHERE clause in a SQL expression.
❏The parameters are strings that give values to the 'parameters' in the filter expression. There must be one parameter string for each parameter in the filter expression.
A ContentFilteredTopic is a type of topic description, and can be used to create DataReaders. However, a ContentFilteredTopic is not an
A ContentFilteredTopic relates to other entities in Connext as follows:
❏ContentFilteredTopics are used when creating DataReaders, not DataWriters.
❏Multiple DataReaders can be created with the same ContentFilteredTopic.
❏A ContentFilteredTopic belongs to (is created/deleted by) a DomainParticipant.
❏A ContentFilteredTopic and Topic must be in the same DomainParticipant.
❏A ContentFilteredTopic can only be related to a single Topic.
❏A Topic can be related to multiple ContentFilteredTopics.
❏A ContentFilteredTopic can have the same name as a Topic, but ContentFilteredTopics must have unique names within the same DomainParticipant.
❏A DataReader created with a ContentFilteredTopic will use the related Topic's QoS and
Listeners.
❏Changing filter parameters on a ContentFilteredTopic causes all DataReaders using the same ContentFilteredTopic to see the change.
❏A Topic cannot be deleted as long as at least one ContentFilteredTopic that has been cre- ated with it exists.
❏A ContentFilteredTopic cannot be deleted as long as at least one DataReader that has been created with the ContentFilteredTopic exists.
ContentFilteredTopics
5.4.2Where Filtering is
Filtering may be performed on either side of the distributed application. (The DataWriter obtains the filter expression and parameters from the DataReader during discovery.)
Connext also supports
A DataWriter will automatically filter data samples for a DataReader if all of the following are true; otherwise filtering is performed by the DataReader.
1.The DataWriter is filtering for no more than writer_resource_limits.max_remote_reader_filters DataReaders at the same time.
•There is a
•If a DataWriter is filtering max_remote_reader_filters DataReaders at the same time and a new filtered DataReader is created, then the newly created DataReader (max_remote_reader_filters + 1) is not filtered. Even if one of the first (max_remote_reader_filters) DataReaders is deleted, that already created DataReader (max_remote_reader_filters + 1) will still not be filtered. However, any subsequently created DataReaders will be filtered as long as the number of DataReaders currently being filtered is not more than writer_resource_limits.max_remote_reader_filters.
2.The DataReader is not subscribing to data using multicast.
3.There are no more than 4 matching DataReaders in the same locator (see Peer Descriptor Format (Section 14.2.1)).
4.The DataWriter has infinite liveliness. (See LIVELINESS QosPolicy (Section 6.5.13).)
5.The DataWriter is not using an Asynchronous Publisher. (That is, the DataWriter’s PUBLISH_MODE QosPolicy (DDS Extension) (Section 6.5.18) kind is set to
DDS_SYNCHRONOUS_PUBLISHER_MODE_QOS.) See Note below.
6.If you are using a custom filter (not the default one), it must be registered in the Domain- Participant of the DataWriter and the DataReader.
Notes:
Connext supports limited
In addition to filtering new samples, a DataWriter can also be configured to filter previously written samples stored in the DataWriter’s queue for newly discovered DataReaders. To do so, use the refilter field in the DataWriter’s HISTORY QosPolicy (Section 6.5.10).
5.4.3Creating ContentFilteredTopics
To create a ContentFilteredTopic that uses the default SQL filter, use the DomainParticipant’s create_contentfilteredtopic() operation:
DDS_ContentFilteredTopic *create_contentfilteredtopic
(const char |
* name, |
const DDS_Topic * related_topic,
ContentFilteredTopics
const char |
* filter_expression, |
const DDS_StringSeq & expression_parameters)
Or, to use a custom filter or the builtin STRINGMATCH filter (see Section 5.4.7), use the create_contentfilteredtopic_with_filter() variation:
DDS_ContentFilteredTopic *create_contentfilteredtopic_with_filter
(const |
char |
* |
name, |
DDSTopic |
* |
related_topic, |
|
const |
char |
* |
filter_expression, |
const |
DDS_StringSeq & expression_parameters, |
||
const |
char |
* |
filter_name = |
|
DDS_SQLFILTER_NAME) |
name |
Name of the ContentFilteredTopic. Note that it is legal for a ContentFil- |
|
teredTopic to have the same name as a Topic in the same DomainParticipant, |
|
but a ContentFilteredTopic cannot have the same name as another Content- |
|
FilteredTopic in the same DomainParticipant. This parameter cannot be |
|
NULL. |
related_topic The related Topic to be filtered. The related topic must be in the same DomainParticipant as the ContentFilteredTopic. This parameter cannot be NULL. The same related topic can be used in many different ContentFil- teredTopics.
filter_expression A logical expression on the contents on the Topic. If the expression evalu- ates to TRUE, a sample is received; otherwise it is discarded. This parame- ter cannot be NULL. Once a ContentFilteredTopic is created, its filter_expression cannot be changed. The notation for this expression depends on the filter that you are using (specified by the filter_name parameter). See SQL Filter Expression Notation (Section 5.4.6) and STRINGMATCH Filter Expression Notation (Section 5.4.7).
expression_parameters A string sequence of filter expression parameters. Each parameter cor- responds to a positional argument in the filter expression: element 0 corre- sponds to positional argument 0, element 1 to positional argument 1, and so forth.
|
The |
expression_parameters |
can |
be |
changed |
with |
||
|
set_expression_parameters() |
|
|
|
||||
|
append_to_expression_parameter() |
and |
||||||
|
remove_from_expression_parameter() (Section 5.4.5.4). |
|
|
|||||
filter_name |
Name of the content filter to use for filtering. The filter must have been pre- |
|||||||
|
viously registered with the DomainParticipant (see Registering a Custom |
|||||||
|
5.4.8.2)). |
|
There |
are two |
builtin |
filters, |
||
|
DDS_SQLFILTER_NAME1 |
|
(the |
default |
filter) |
and |
||
|
||||||||
|
tered. |
|
|
|
|
|
|
|
|
To |
use |
the |
STRINGMATCH |
filter, |
call |
||
|
create_contentfilteredtopic_with_filter() |
|
|
with |
||||
|
"DDS_STRINGMATCHFILTER_NAME" as the filter_name. STRING- |
|||||||
|
MATCH filter expressions have the syntax: |
|
|
|
||||
|
<field name> MATCH <string pattern> (see Section 5.4.7). |
|
1. In the Java and C# APIs, you can access the names of the builtin filters by using DomainParticipant.SQLFILTER_NAME and DomainParticipant.STRINGMATCHFILTER_NAME.
ContentFilteredTopics
.If you run rtiddsgen with
To summarize:
❏To use the builtin default SQL filter:
•Do not use
•Call create_contentfilteredtopic()
•See SQL Filter Expression Notation (Section 5.4.6)
❏To use the builtin STRINGMATCH filter:
•Do not use
•Call create_contentfilteredtopic_with_filter(), setting the filter_name to
DDS_STRINGMATCHFILTER_NAME
•See STRINGMATCH Filter Expression Notation (Section 5.4.7)
❏To use a custom filter:
•call create_contentfilteredtopic_with_filter(), setting the filter_name to a registered custom filter
❏To use rtiddsgen with
•call create_contentfilteredtopic_with_filter(), setting the filter_name to a registered custom filter
Note: Be careful with memory management of the string sequence in some of the ContentFil- teredTopic APIs. See the String Support section in the API Reference HTML documentation (within the Infrastructure module) for details on sequences.
5.4.4Deleting ContentFilteredTopics
To delete a ContentFilteredTopic, use the DomainParticipant’s delete_contentfilteredtopic() operation:
1.Make sure no DataReaders are using the ContentFilteredTopic. (If this is not true, the operation returns PRECONDITION_NOT_MET.)
2.Delete the ContentFilteredTopic by using the DomainParticipant’s delete_contentfilteredtopic() operation.
DDS_ReturnCode_t delete_contentfilteredtopic (DDSContentFilteredTopic * a_contentfilteredtopic)
5.4.5Using a ContentFilteredTopic
Once you’ve created a ContentFilteredTopic, you can use the operations listed in Table 5.5.
Table 5.5 ContentFilteredTopic Operations
Operation |
Description |
Reference |
|
|
|
|
|
|
append_to_expression_parameter |
Concatenates a string value to the input expres- |
|
|
sion parameter |
|
get_expression_parameters |
Gets the expression parameters. |
|
|
|
|
ContentFilteredTopics
Table 5.5 ContentFilteredTopic Operations
Operation |
Description |
Reference |
|
|
|
|
|
|
get_filter_expression |
Gets the expression. |
|
|
|
|
get_related_topic |
Gets the related Topic. |
|
|
|
|
narrow |
Casts a DDS_TopicDescription pointer to a Con- |
|
|
tentFilteredTopic pointer. |
|
remove_from_expression_parameter |
Removes a string value from the input expression |
|
|
parameter |
|
set_expression_parameters |
Changes the expression parameters. |
|
|
|
|
5.4.5.1Getting the Current Expression Parameters
To get the expression parameters, use the ContentFilteredTopic’s get_expression_parameters() operation:
DDS_ReturnCode_t get_expression_parameters
(struct DDS_StringSeq & parameters)
parameters The filter expression parameters.
The memory for the strings in this sequence is managed as described in the String Support section of the API Reference HTML documentation (within the Infra- structure module). In particular, be careful to avoid a situation in which Connext allocates a string on your behalf and you then reuse that string in such a way that Connext believes it to have more memory allocated to it than it actually does. This parameter cannot be NULL.
This operation gives you the expression parameters that were specified on the last successful call to set_expression_parameters() or, if that was never called, the parameters specified when the ContentFilteredTopic was created.
5.4.5.2Setting Expression Parameters
To change the expression parameters associated with a ContentFilteredTopic:
DDS_ReturnCode_t set_expression_parameters
(const struct DDS_StringSeq & parameters)
parameters The filter expression parameters. Each element in the parameter sequence corre- sponds to a positional parameter in the filter expression. When using the default DDS_SQLFILTER_NAME, parameter strings are automatically converted to the member type. For example, "4" is converted to the integer 4. This parameter can- not be NULL.
Note: The ContentFilteredTopic’s operations do not manage the sequences; you must ensure that the parameter sequences are valid. Please refer to the String Support section in the API Ref- erence HTML documentation (within the Infrastructure module) for details on sequences.
5.4.5.3Appending a String to an Expression Parameter
To concatenate a string to an expression parameter, use the ContentFilteredTopic's append_to_expression_parameter() operation:
DDS_ReturnCode_t append_to_expression_parameter( const DDS_Long index, const char* value);
When using the STRINGMATCH filter, index must be 0.
ContentFilteredTopics
This function is only intended to be used with the builtin SQL and STRINGMATCH filters. This function can be used in expression parameters associated with MATCH operators (see SQL Extension: Regular Expression Matching (Section 5.4.6.4)) to add a pattern to the match pattern list. For example, if filter_expression is:
symbol MATCH 'IBM'
Then append_to_expression_parameter(0, "MSFT") would generate the expression:
symbol MATCH 'IBM,MSFT'
5.4.5.4Removing a String from an Expression Parameter
To remove a string from an expression parameter use the ContentFilteredTopic's remove_from_expression_parameter() operation:
DDS_ReturnCode_t remove_from_expression_parameter( const DDS_Long index, const char* value)
When using the STRINGMATCH filter, index must be 0.
This function is only intended to be used with the builtin SQL and STRINGMATCH filters. It can be used in expression parameters associated with MATCH operators (see SQL Extension: Regular Expression Matching (Section 5.4.6.4)) to remove a pattern from the match pattern list. For example, if filter_expression is:
symbol MATCH 'IBM,MSFT'
Then remove_from_expression_parameter(0, "IBM") would generate the expression:
symbol MATCH 'MSFT'
5.4.5.5Getting the Filter Expression
To get the filter expression that was specified when the ContentFilteredTopic was created: const char* get_filter_expression ()
There is no corresponding set operation. The filter expression can only be set when the Content- FilteredTopic is created.
5.4.5.6Getting the Related Topic
To get the related topic that was specified when the ContentFilteredTopic was created:
DDS_Topic * get_related_topic ()
5.4.5.7‘Narrowing’ a ContentFilteredTopic to a TopicDescription
To safely cast a DDS_TopicDescription pointer to a ContentFilteredTopic pointer, use the Con- tentFilteredTopic’s narrow() operation:
DDS_TopicDescription* narrow ()
5.4.6SQL Filter Expression Notation
A SQL filter expression is similar to the WHERE clause in SQL. The SQL expression format pro- vided by Connext also supports the MATCH operator as an extended operator (see Section 5.4.6.4).
The following sections provide more information:
ContentFilteredTopics
❏Token Expressions (Section 5.4.6.2)
❏Type Compatibility in the Predicate (Section 5.4.6.3)
❏SQL Extension: Regular Expression Matching (Section 5.4.6.4)
❏Composite Members (Section 5.4.6.5)
❏Enumerations (Section 5.4.6.7)
❏Example SQL Filter Expressions (Section 5.4.6.11)
5.4.6.1SQL Grammar
This section describes the subset of SQL syntax, in
The following notational conventions are used:
❏NonTerminals are typeset in italics.
❏'Terminals' are quoted and typeset in a fixed width font. They are written in upper case in most cases in the
❏TOKENS are typeset in bold.
❏The notation (element // ',') represents a
Expression ::= |
FilterExpression |
| |
TopicExpression |
| |
QueryExpression |
|
. |
|
|
FilterExpression |
::= Condition |
||
TopicExpression |
::= SelectFrom { Where } ';' |
||
QueryExpression |
::= { Condition }{ 'ORDER BY' (FIELDNAME // ',') } |
||
|
|
|
. |
SelectFrom |
|
::= 'SELECT' Aggregation 'FROM' Selection |
|
|
|
. |
|
Aggregation |
|
::= '*' |
|
|
|
| |
(SubjectFieldSpec // ',') |
|
|
. |
|
SubjectFieldSpec |
::= FIELDNAME |
||
|
|
| |
FIELDNAME 'AS' IDENTIFIER |
|
|
| |
FIELDNAME IDENTIFIER |
|
|
. |
|
Selection |
::= |
TOPICNAME |
|
|
| |
TOPICNAME NaturalJoin JoinItem |
|
|
. |
|
|
JoinItem |
::= |
TOPICNAME |
|
|
| |
TOPICNAME NaturalJoin JoinItem |
|
|
| |
'(' TOPICNAME NaturalJoin JoinItem ')' |
|
|
. |
|
|
NaturalJoin ::= |
'INNER JOIN' |
||
|
| |
'INNER NATURAL JOIN' |
|
|
| |
'NATURAL JOIN' |
ContentFilteredTopics
|
| |
'NATURAL INNER JOIN' |
|
. |
|
Where |
::= |
'WHERE' Condition |
|
. |
|
Condition |
::= |
Predicate |
|
| |
Condition 'AND' Condition |
|
| |
Condition 'OR' Condition |
|
| |
'NOT' Condition |
|
| |
'(' Condition ')' |
|
. |
|
Predicate |
::= |
ComparisonPredicate |
|
| |
BetweenPredicate |
|
. |
|
ComparisonPredicate ::= ComparisonTerm RelOp ComparisonTerm
|
. |
|
ComparisonTerm |
::= FieldIdentifier |
|
|
| Parameter |
|
|
. |
|
BetweenPredicate |
::= |
FieldIdentifier 'BETWEEN' Range |
|
| |
FieldIdentifier 'NOT BETWEEN' Range |
|
. |
|
FieldIdentifier |
::= FIELDNAME |
|
|
| IDENTIFIER |
|
|
. |
|
RelOp |
::= |
'=' | '>' | '>=' | '<' | '<=' | '<>' | 'LIKE' | 'MATCH' |
|
. |
|
Range |
::= |
Parameter 'AND' Parameter |
|
. |
|
Parameter |
::= |
INTEGERVALUE |
|
| |
CHARVALUE |
|
| |
FLOATVALUE |
|
| |
STRING |
|
| |
ENUMERATEDVALUE |
|
| |
BOOLEANVALUE |
|
| |
PARAMETER |
|
. |
|
Note: INNER JOIN, INNER NATURAL JOIN, NATURAL JOIN, and NATURAL INNER JOIN are all aliases, in the sense that they have the same semantics. They are all supported because they all are part of the SQL standard.
5.4.6.2Token Expressions
The syntax and meaning of the tokens used in SQL grammar is described as follows:
IDENTIFIER: LETTER (PART_LETTER)* where LETTER: [
PART_LETTER: [
ContentFilteredTopics
notation '[n]', where n is a natural number (zero included). FIELDNAME must resolve to a primitive IDL type; that is either boolean, octet, (unsigned) short, (unsigned) long, (unsigned) long long, float double, char, wchar, string, wstring, or enum.
FIELDNAME: FieldNamePart ( "." FieldNamePart )* where FieldNamePart : IDENTIFIER ( "[" Index "]" )*
Index> :
|
Primitive IDL types referenced by FIELDNAME are treated as different types in Predicate according to the following table:
Predicate Data Type |
IDL Type |
|
|
BOOLEANVALUE |
boolean |
|
|
INTEGERVALUE |
octet, (unsigned) short, (unsigned) long, (unsigned) long long |
|
|
FLOATVALUE |
float, double |
|
|
CHARVALUE |
char, wchar |
|
|
STRING |
string, wstring |
|
|
ENUMERATEDVALUE |
enum |
|
|
TOPICNAME : IDENTIFIER
INTEGERVALUE :
CHARVALUE : "'" (~["'"])? "'"
FLOATVALUE :
where EXPONENT: ["e","E"]
STRING : "'" (~["'"])* "'"
ENUMERATEDVALUE : "'" ["A" - "Z", "a" - "z"] ["A" - "Z", "a" - "z", "_", "0" - "9"]* "'"
ContentFilteredTopics
BOOLEANVALUE : ["TRUE","FALSE"]
PARAMETER : "%"
5.4.6.3Type Compatibility in the Predicate
As seen in Table 5.6, only certain combinations of type comparisons are valid in the Predicate.
Table 5.6 Valid Type Comparisons
|
BOOLEAN |
INTEGER |
FLOAT |
CHAR |
STRING |
ENUMERATED |
|
VALUE |
VALUE |
VALUE |
VALUE |
VALUE |
|
|
|
|
|
|
|
|
BOOLEAN |
YES |
|
|
|
|
|
|
|
|
|
|
|
|
INTEGERVALUE |
|
YES |
YES |
|
|
|
|
|
|
|
|
|
|
FLOATVALUE |
|
YES |
YES |
|
|
|
|
|
|
|
|
|
|
CHARVALUE |
|
|
|
YES |
YES |
YES |
|
|
|
|
|
|
|
STRING |
|
|
|
YES |
YES a |
YES |
ENUMERATED |
|
YES |
|
YES b |
YES b |
YES c |
VALUE |
|
|
|
|
|
|
a.See Section 5.4.6.4.
b.Because of the formal notation of the Enumeration values, they are compatible with string and char literals, but they are not compatible with string or char variables, i.e., "MyEnum='EnumValue'" is correct, but "MyEnum=MyS- tring" is not allowed.
c.Only for
5.4.6.4SQL Extension: Regular Expression Matching
The relational operator MATCH may only be used with string fields. The
MATCH is
The pattern allows limited "wild card" matching under the rules in Table 5.7 on page
The syntax is similar to the POSIX® fnmatch syntax1. The MATCH syntax is also similar to the 'subject' strings of TIBCO Rendezvous®. Some example expressions include:
"symbol MATCH
"symbol MATCH 'NASDAQ/GOOG,NASDAQ/MSFT'"
Table 5.7 Wild Card Matching
Character |
Meaning |
,
A , separates a list of alternate patterns. The field string is matched if it matches one or more of the patterns.
/
A / in the pattern string matches a / in the field string. It separates a sequence of mandatory substrings.
1. See http://www.opengroup.org/onlinepubs/000095399/functions/fnmatch.html.
ContentFilteredTopics
Table 5.7 Wild Card Matching
Character |
|
Meaning |
|
|
|
|
|
|
? |
|
A ? in the pattern string matches any single |
|
string. |
|
|
|
|
|
|
|
* |
|
A * in the pattern string matches 0 or more |
|
|
|
% |
|
This special character is used to designate filter expression parameters. |
|
|
|
\ |
|
(Not supported) Escape character for special characters. |
|
|
|
[charlist] |
|
Matches any one of the characters in charlist. |
|
|
|
[!charlist] |
or |
(Not supported) Matches any one of the characters not in charlist. |
[^charlist] |
|
|
|
Matches any character from s to e, inclusive. |
|
|
|
|
(Not supported) Matches any character not in the interval s to e. |
||
|
|
|
5.4.6.5Composite Members
Any member can be used in the filter expression, with the following exceptions:
❏
❏bitfields are not supported
❏LIKE is not supported
Composite members are accessed using the familiar dot notation, such as "x.y.z > 5". For unions, the notation is special due to the nature of the IDL union type.
On the publishing side, you can access the union discriminator with myunion._d and the actual member with myunion._u.mymember. If you want to use a ContentFilteredTopic on the sub- scriber side and filter a sample with a
5.4.6.6Strings
The filter expression and parameters can use IDL strings. String constants must appear between single quotation marks (').
For example:
"fish = 'salmon' "
Strings used as parameter values must contain the enclosing quotation marks (') within the parameter value; do not place the quotation marks within the expression statement. For exam- ple, the expression " symbol MATCH %0 " with parameter 0 set to " 'IBM' " is legal, whereas the expression " symbol MATCH '%0' " with parameter 0 set to " IBM " will not compile.
5.4.6.7Enumerations
A filter expression can use enumeration values, such as GREEN, instead of the numerical value. For example, if x is an enumeration of GREEN, YELLOW and RED, the following expressions are valid:
"x = 'GREEN'" "X < 'RED'"
5.4.6.8Pointers
Pointers can be used in filter expressions and are automatically dereferenced to the correct value.
ContentFilteredTopics
For example:
struct Point { long x; long y;
};
struct Rectangle { Point *u_l; Point *l_r;
};
The following expression is valid on a Topic of type Rectangle:
"u_l.x > l_r.x"
5.4.6.9Arrays
Arrays are accessed with the familiar [] notation.
For example:
struct ArrayType { long value[255][5];
};
The following expression is valid on a Topic of type ArrayType:
"value[244][2] = 5"
In order to compare an array of bytes(octets in idl), instead of comparing each individual ele- ment of the array using [] notation, Connext provides a helper function, hex(). The hex() function can be used to represent an array of bytes (octets in IDL). To use the hex() function, use the nota- tion &hex() and pass the byte array as a sequence of hexadecimal values.
For example:
&hex (07 08 09 0A 0B 0c 0D 0E 0F 10 11 12 13 14 15 16)
Here the
Note: If the length of the octet array represented by the hex() function does not match the length of the field being compared, it will result in a compilation error.
For example:
struct ArrayType { octet value[2];
};
The following expression is valid:
"value = &hex(12 0A)"
5.4.6.10Sequences
Sequence elements can be accessed using the () or [] notation.
For example:
struct SequenceType { sequence<long> s;
};
The following expressions are valid on a Topic of type SequenceType:
"s(1) = 5"
ContentFilteredTopics
"s[1] = 5"
5.4.6.11Example SQL Filter Expressions
Assume that you have a Topic with two floats, X and Y, which are the coordinates of an object moving inside a rectangle measuring 200 x 200 units. This object moves quite a bit, generating lots of samples that you are not interested in. Instead you only want to receive samples outside the middle of the rectangle, as seen in Figure 5.5. That is, you want to filter out data points in the gray box.
Figure 5.5 Filtering Example
The filter expression would look like this (remember the expression is written so that samples that we do want will pass):
"(X < 50 or X > 150) and (Y < 50 or Y > 150)"
While this filter works, it cannot be changed after the ContentFilteredTopic has been created. Suppose you would like the ability to adjust the coordinates that are considered outside the acceptable range (changing the size of the gray box). You can achieve this by using filter param- eters. An more flexible way to write the expression is this:
"(X < %0 or X > %1) and (Y < %2 or Y > %3)"
Recall that when you create a ContentFilteredTopic (see Section 5.4.3), you pass a expression_parameters string sequence as one of the parameters. Each element in the string sequence corresponds to one argument.
See the String and Sequence Support sections of the API Reference HTML documentation (from the Modules page, select Infrastructure).
In C++, the filter parameters could be assigned like this:
FilterParameter[0] = "50";
FilterParameter[1] = "150";
FilterParameter[2] = "50";
FilterParameter[3] = "150";
With these parameters, the filter expression is identical to the first approach. However, it is now possible to change the parameters by calling set_expression_parameters(). For example, per- haps you decide that you only want to see data points where X < 10 or X > 190. To make this change:
ContentFilteredTopics
FilterParameter[0] = 10
FilterParameter[1] = 190 set_expression_parameters(....)
Note: The new filter parameters will affect all DataReaders that have been created with this Con- tentFilteredTopic.
5.4.7STRINGMATCH Filter Expression Notation
The STRINGMATCH Filter is a subset of the SQL filter; it only supports the MATCH relational operator on a single string field. It is introduced mainly for the use case of partitioning data according to channels in the DataWriter's MULTI_CHANNEL QosPolicy (DDS Extension) (Sec- tion 6.5.14) in Market Data applications.
A STRINGMATCH filter expression has the following syntax:
<field name> MATCH <string pattern>
The STRINGMATCH filter is provided to support the narrow use case of filtering a single string field of the sample against a
The STRINGMATCH filter must contain only one <field name>, and a single occurrence of the MATCH operator. The <string pattern> must be either the single parameter %0, or a single,
During creation of a STRINGMATCH filter, the <string pattern> is automatically parameterized. That is, during creation, if the <string pattern> specified in the filter expression is not the param- eter %0, then the
The initial matching string list is converted to an explicit parameter value so that subsequent additions and deletions of string values to and from the list of matching strings may be per- formed with the append_to_expression_parameter() and remove_from_expression_parameter() operations mentioned above.
5.4.7.1Example STRINGMATCH Filter Expressions
❏This expression evaluates to TRUE if the value of symbol is equal to NASDAQ/MSFT: symbol MATCH 'NASDAQ/MSFT'
❏This expression evaluates to TRUE if the value of symbol is equal to NASDAQ/IBM or
NASDAQ/MSFT:
symbol MATCH 'NASDAQ/IBM,NASDAQ/MSFT'
❏This expression evaluates to TRUE if the value of symbol corresponds to NASDAQ and starts with a letter between M and Y:
symbol MATCH
5.4.7.2STRINGMATCH Filter Expression Parameters
In the builtin STRINGMATCH filter, there is one, and only one, parameter: parameter 0. (If you want to add more parameters, see Appending a String to an Expression Parameter (Section
ContentFilteredTopics
5.4.5.3).) The parameter can be specified explicitly using the same syntax as the SQL filter or implicitly by using a constant string pattern. For example:
symbol |
MATCH |
%0 (Explicit parameter) |
symbol |
MATCH |
‘IBM’ (Implicit parameter initialized to IBM) |
Strings used as parameter values must contain the enclosing quotation marks (') within the parameter value; do not place the quotation marks within the expression statement. For exam- ple, the expression " symbol MATCH %0 " with parameter 0 set to " 'IBM' " is legal, whereas the expression " symbol MATCH '%0' " with parameter 0 set to " IBM " will not compile.
5.4.8Custom Content Filters
By default, a ContentFilteredTopic will use a
If you want to use a different filter, you must register it first, then create the ContentFiltered- Topic using create_contentfilteredtopic_with_filter() (see Creating ContentFilteredTopics (Sec- tion 5.4.3)).
One reason to use a custom filter is that the default filter can only filter based on relational oper- ations between topic members, not on a computation involving topic members. For example, if you want to filter based on the sum of the members, you must create your own filter.
Notes:
❏The API for using a custom content filter is subject to change in a future release.
❏Custom content filters are not supported when using the .NET APIs.
5.4.8.1Filtering on the Writer Side with Custom Filters
There are two approaches for performing
The second approach is to evaluate the written sample once for the writer and then rely on the filter implementation to provide a set of readers whose filter passes the sample. This approach allows the filter implementation to cache the result of filtering, if possible. For example, consider a scenario where the data is described by the struct shown below, where 10<x<20:
struct MyData { int x;
int y;
};
If the filter expression is based only on the x field, the filter implementation can maintain a hash map for all the different values of x and cache the filtering results in the hash map. Then any future evaluations will only be O(1), because it only requires a lookup in the hash map.
But if in the same example, a reader has a content filter that is based on both x and y, or just y, the filter implementation cannot cache the
ContentFilteredTopics
Table 5.8 DDS_ExpressionProperty
Type |
Field Name |
Description |
|
|
|
|
|
|
|
|
|
DDS_Boolean |
key_only_filter |
Indicates if the filter expression is based only on key fields. In this |
|
case, Connext itself can cache the filtering results. |
|||
|
|
||
|
|
|
|
|
|
Indicates if the filter implementation can cache the filtering result for |
|
|
writer_side_filter_ |
the expression provided. If this is true then Connext will do no cach- |
|
DDS_Boolean |
ing or explicit filter evaluation for the associated DataReader. It will |
||
optimization |
|||
|
|
instead rely on the filter implementation to provide appropriate |
|
|
|
results. |
|
|
|
|
5.4.8.2Registering a Custom Filter
To use a custom filter, it must be registered in the following places:
❏Register the custom filter in any subscribing application in which the filter is used to cre- ate a ContentFilteredTopic and corresponding DataReader.
❏In each publishing application, you only need to register the custom filter if you want to perform
For example, suppose Application A on the subscription side creates a Topic named X and a ContentFilteredTopic named filteredX (and a corresponding DataReader), using a previously registered content filter, myFilter. With only that, you will have filtering on the subscription side. If you also want to perform filtering in any application that publishes Topic X, then you also need to register the same definition of the ContentFilter myFilter in that application.
To register a new filter, use the DomainParticipant’s register_contentfilter() operation1:
DDS_ReturnCode_t register_contentfilter(const char * filter_name, const DDSContentFilter * contentfilter)
)
filter_name The name of the filter. The name must be unique within the DomainParticipant. The filter_name cannot have a length of 0. The same filtering functions and handle can be registered under different names.
content_filter This class specifies the functions that will be used to process the filter.
You must derive from the DDSContentFilter base class and implement the vir- tual compile, evaluate, and finalize functions described below.
Optionally, you can derive from the DDSWriterContentFilter base class instead, to implement additional filtering operations that will be used by the DataWriter. When performing
•compile
The function that will be used to compile a filter expression and parameters. Connext will call this function when a ContentFilteredTopic is created and when the filter parameters are changed. This parameter cannot be NULL. See Compile Function (Section 5.4.8.5). This is a member of DDSContentFil- ter and DDSWriterContentFilter.
1.This operation is an extension to the DDS standard.
ContentFilteredTopics
•evaluate
The function that will be called by Connext each time a sample is received. Its purpose is to evaluate the sample based on the filter. This parameter cannot be NULL. See Evaluate Function (Section 5.4.8.6). This is a member of DDSContentFilter and DDSWriterContentFilter.
•finalize
The function that will be called by Connext when an instance of the custom content filter is no longer needed. This parameter may be NULL. See Final- ize Function (Section 5.4.8.7). This is a member of DDSContentFilter and DDSWriterContentFilter.
•writer_attach
The function that will be used to create some state required to perform filter- ing on the writer side using the operations provided in DDSWriterContent- Filter. Connext will call this function for every DataWriter; it will be called only the first time the DataWriter matches a DataReader using the specified fil- ter. This function will not be called for any subsequent DataReaders that match the DataWriter and are using the same filter. See Writer Attach Func- tion (Section 5.4.8.8). This is a member of DDSWriterContentFilter.
•writer_detach
The function that will be used to delete any state created using the writer_attach function. Connext will call this function when the DataWriter is deleted. See Writer Detach Function (Section 5.4.8.9). This is a member of DDSWriterContentFilter.
•writer_compile
The function that will be used by the DataWriter to compile filter expression and parameters provided by the reader. Connext will call this function when the DataWriter discovers a DataReader with a ContentFilteredTopic or when a DataWriter is notified of a change in DataReader’s filter parameter. This func- tion will receive as an input a DDS_Cookie_t which uniquely identifies the DataReader for which the function was invoked. See Writer Compile Func- tion (Section 5.4.8.10). This is a member of DDSWriterContentFilter.
•writer_evaluate
The function that will be called by Connext every time a DataWriter writes a new sample. Its purpose is to evaluate the sample for all the readers for which the DataWriter is performing
•writer_return_loan
The function that will be called by Connext to return the loan on a sequence of DDS_Cookie_t provided by the writer_evaluate function. See Writer Return Loan Function (Section 5.4.8.12). This is a member of DDSWriterCon- tentFilter.
•writer_finalize
The function that will be called by Connext to notify the filter implementa- tion that the DataWriter is no longer matching with a DataReader for which it was previously performing
ContentFilteredTopics
Function (Section 5.4.8.13). This is a member of DDSWriterContentFilter.
5.4.8.3Unregistering a Custom Filter
To unregister a filter, use the DomainParticipant’s unregister_contentfilter() operation1, which is useful if you want to reuse a particular filter name. (Note: You do not have to unregister the fil- ter before deleting the parent DomainParticipant. If you do not need to reuse the filter name to register another filter, there is no reason to unregister the filter.)
DDS_ReturnCode_t unregister_contentfilter(const char * filter_name)
filter_name The name of the previously registered filter. The name must be unique within the DomainParticipant. The filter_name cannot have a length of 0.
If you attempt to unregister a filter that is still being used by a ContentFiltered-
Topic, unregister_contentfilter() will return PRECONDITION_NOT_MET.
If there are still existing discovered DataReaders with the same filter_name and the filter's compile function has previously been called on the discovered DataReaders, the filter’s finalize function will be called on those discovered DataReaders before the content filter is unregistered. This means filtering will be performed on the application that is creating the DataReader.
5.4.8.4Retrieving a ContentFilter
If you know the name of a ContentFilter, you can get a pointer to its structure. If the ContentFil- ter has not already been registered, this operation will return NULL.
DDS_ContentFilter *lookup_contentfilter (const char * filter_name)
5.4.8.5Compile Function
The compile function specified in the ContentFilter will be used to compile a filter expression and parameters. Please note that the term ‘compile’ is intentionally defined very broadly. It is entirely up to you, as the user, to decide what this function should do. The only requirement is that the error_code parameter passed to the compile function must return OK on successful exe- cution. For example:
DDS_ReturnCode_t sample_compile_function(
void ** |
new_compile_data, |
const char * |
expression, |
const DDS_StringSeq & parameters, |
|
const DDS_TypeCode * |
type_code, |
const char * |
type_class_name, |
void * |
old_compile_data) |
{
*new_compile_data = (void*)DDS_String_dup(parameters[0]); return DDS_RETCODE_OK;
}
new_compile_data A
|
value is passed to the evaluate and finalize functions. |
expression |
An ASCIIZ string with the filter expression the ContentFilteredTopic was |
|
created with. Note that the memory used by the parameter pointer is |
|
owned by Connext. If you want to manipulate this string, you must make |
|
a copy of it first. Do not free the memory for this string. |
1. This operation is an extension to the DDS standard.
ContentFilteredTopics
parameters |
A string sequence of expression parameters used to create the ContentFil- |
||||
|
teredTopic. The string sequence is equal (but not identical) to the string |
||||
|
sequence |
passed |
to |
create_contentfilteredtopic() |
(see |
expression_parameters in Section 5.4.3).
Important: |
The sequence passed to the compile function is owned by Connext and |
|
must not be referred to outside the compile function. |
type_code |
A pointer to the type code of the related Topic. A type code is a description |
|
of the topic members, such as their type (long, octet, etc.), but does not |
|
contain any information with respect to the memory layout of the struc- |
|
tures. The type code can be used to write filters that can be used with any |
|
type. See Using Generated Types without Connext (Standalone) (Section |
|
3.7). [Note: If you are using the Java API, this parameter will always be |
|
NULL.] |
type_class_name |
Fully qualified class name of the related Topic. |
old_compile_data |
The new_compile_data value from a previous call to this instance of a con- |
|
tent filter. If compile is called more than once for an instance of a Con- |
|
tentFilteredTopic (such as if the expression parameters are changed), then |
|
the new_compile_data value returned by the previous invocation is |
|
passed in the old_compile_data parameter (which can be NULL). If this |
|
is a new instance of the filter, NULL is passed. This parameter is useful |
|
for freeing or reusing previously allocated resources. |
5.4.8.6Evaluate Function
The evaluate function specified in the ContentFilter will be called each time a sample is received. This function’s purpose is to determine if a sample should be filtered out (not put in the receive queue).
For example:
DDS_Boolean sample_evaluate_function(
void* compile_data, const void* sample,
struct DDS_FilterSampleInfo * meta_data) {
char *parameter = (char*)compile_data; DDS_Long x;
Foo *foo_sample = (Foo*)sample;
sscanf(parameter,"%d",&x);
return
}
The function may use the following parameters:
compile_data |
The last return value from the compile function for this instance of the con- |
|
tent filter. Can be NULL. |
sample |
A pointer to a C structure with the data to filter. Note that the evaluate func- |
|
tion always receives deserialized data. |
meta_data |
A pointer to the meta data associated with the sample. |
|
Note: Currently the meta_data field only supports related_sample_identity |
|
(described in Table 6.15, “DDS_WriteParams_t,” on page |
ContentFilteredTopics
5.4.8.7Finalize Function
The finalize function specified in the ContentFilter will be called when an instance of the cus- tom content filter is no longer needed. When this function is called, it is safe to free all resources used by this particular instance of the custom content filter.
For example:
void sample_finalize_function ( void* compile_data) { /* free parameter string from compile function */ DDS_String_free((char *)compile_data);
}
The finalize function may use the following optional parameters:
system_key See Section 5.4.8.5.
handle This is the opaque returned by the last call to the compile function.
5.4.8.8Writer Attach Function
The writer_attach function specified in the WriterContentFilter will be used to create some state that can be used by the filter to perform
The function has the following parameter:
writer_filter_data A
5.4.8.9Writer Detach Function
The writer_detach function specified in the WriterContentFilter will be used to free up any state that was created using the writer_attach function.
The function has the following parameter:
writer_filter_data A pointer to the state created using the writer_attach function.
5.4.8.10Writer Compile Function
The writer_compile function specified in the WriterContentFilter will be used by a DataWriter to compile a filter expression and parameters associated with a DataReader for which the DataW- riter is performing filtering. The function will receive as input a DDS_Cookie_t that uniquely identifies the DataReader for which the function was invoked.
The function has the following parameters:
writer_filter_data A pointer to the state created using the writer_attach function.
prop |
A pointer to DDS_ExpressionProperty. This is an output parameter. It |
||||
|
allows you to indicate to Connext if a filter expression can be optimized (as |
||||
|
described in Filtering on the Writer Side with Custom Filters (Section |
||||
|
5.4.8.1)). |
|
|
|
|
expression |
An ASCIIZ string with the filter expression the ContentFilteredTopic was |
||||
|
created with. Note that the memory used by the parameter pointer is |
||||
|
owned by Connext. If you want to manipulate this string, you must make a |
||||
|
copy of it first. Do not free the memory for this string. |
|
|||
parameters |
A string sequence of expression parameters used to create the ContentFil- |
||||
|
teredTopic. The string sequence is equal (but not identical) to the string |
||||
|
sequence |
passed |
to |
create_contentfilteredtopic() |
(see |
|
expression_parameters in Creating ContentFilteredTopics (Section 5.4.3)). |
ContentFilteredTopics
|
Important: The sequence passed to the compile function is owned by Con- |
|
next and must not be referred to outside the writer_compile function. |
type_code |
A pointer to the type code of the related Topic. A type code is a description |
|
of the topic members, such as their type (long, octet, etc.), but does not con- |
|
tain any information with respect to the memory layout of the structures. |
|
The type code can be used to write filters that can be used with any type. |
|
See Using Generated Types without Connext (Standalone) (Section 3.7). |
|
[Note: If you are using the Java API, this parameter will always be NULL.] |
type_class_name |
The fully qualified class name of the related Topic. |
cookie |
DDS_Cookie_t to uniquely identify the DataReader for which the |
|
writer_compile function was called. |
5.4.8.11Writer Evaluate Function
The writer_evaluate function specified in the WriterContentFilter will be used by a DataWriter to retrieve the list of DataReaders whose filter passed the sample. The writer_evaluate function returns a sequence of cookies which identifies the set of DataReaders whose filter passes the sam- ple.
The function has the following parameters:
writer_filter_data A pointer to the state created using the writer_attach function. |
|
||||||
sample |
A pointer to the data to be filtered. Note that the writer_evaluate function |
||||||
|
always receives deserialized data. |
|
|
|
|
||
meta_data |
A pointer to the |
|
|
||||
|
Note: |
Currently |
the |
meta_data |
field |
only |
supports |
related_sample_identity (described in Table 6.15, “DDS_WriteParams_t,” on page
5.4.8.12Writer Return Loan Function
Connext uses the writer_return_loan function specified in the WriterContentFilter to indicate to the filter implementation that it has finished using the sequence of cookies returned by the fil- ter’s writer_evaluate function. Your filter implementation should not free the memory associ- ated with the cookie sequence before the writer_return_loan function is called.
The function has the following parameters:
writer_filter_data A pointer to the state created using the writer_attach function.
cookies |
The sequence of cookies for which the writer_return_loan function was |
|
called. |
5.4.8.13Writer Finalize Function
The writer_finalize function specified in the WriterContentFilter will be called when the DataW- riter no longer matches with a DataReader that was created with ContentFilteredTopic. This will allow the filter implementation to delete any state it was maintaining for the DataReader.
The function has the following parameters:
writer_filter_data A pointer to the state created using the writer_attach function.
cookie |
A DDS_Cookie_t to uniquely identify the DataReader for which the |
|
writer_finalize was called. |
Chapter 6 Sending Data
This chapter discusses how to create, configure, and use Publishers and DataWriters to send data. It describes how these entities interact, as well as the types of operations that are available for them.
This chapter includes the following sections:
❏Preview: Steps to Sending Data (Section 6.1)
❏Publisher/Subscriber QosPolicies (Section 6.4)
❏DataWriter QosPolicies (Section 6.5)
❏FlowControllers (DDS Extension) (Section 6.6)
The goal of this chapter is to help you become familiar with the Entities you need for sending data. For
6.1Preview: Steps to Sending Data
To send samples of a data instance:
1.Create and configure the required Entities:
a.Create a DomainParticipant (see Section 8.3.1).
b.Register user data types1 with the DomainParticipant. For example, the ‘FooData- Type’.
c.Use the DomainParticipant to create a Topic with the registered data type.
d.Optionally2, use the DomainParticipant to create a Publisher.
e.Use the Publisher or DomainParticipant to create a DataWriter for the Topic.
f.Use a
1.Type registration is not required for
2.You are not required to explicitly create a Publisher; instead, you can use the 'implicit Publisher' created from the DomainParticipant. See Creating Publishers Explicitly vs. Implicitly (Section 6.2.1).
Publishers
g.Optionally, register data instances with the DataWriter. If the Topic’s user data type contain key fields, then registering a data instance (data with a specific key value) will improve performance when repeatedly sending data with the same key. You may reg- ister many different data instances; each registration will return an instance handle cor- responding to the specific key value. For
2.Every time there is changed data to be published:
a.Store the data in a variable of the correct data type (for instance, variable ‘Foo’ of the type ‘FooDataType’).
b.Call the FooDataWriter’s write() operation, passing it a reference to the variable ‘Foo’. For
DDS_HANDLE_NIL.
For keyed data types, you should pass in the instance handle corresponding to the instance stored in ‘Foo’, if you have registered the instance previously. This means that the data stored in ‘Foo’ has the same key value that was used to create instance handle.
c.The write() function will take a snapshot of the contents of ‘Foo’ and store it in Con- next internal buffers from where the data sample is sent under the criteria set by the Publisher’s and DataWriter’s QosPolicies. If there are matched DataReaders, then the data sample will have been passed to the physical transport
6.2Publishers
An application that intends to publish information needs the following Entities: DomainPartici- pant, Topic, Publisher, and DataWriter. All Entities have a corresponding specialized Listener and a set of QosPolicies. A Listener is how Connext notifies your application of status changes relevant to the Entity. The QosPolicies allow your application to configure the behavior and resources of the Entity.
❏A DomainParticipant defines the domain in which the information will be made available.
❏A Topic defines the name under which the data will be published, as well as the type (for- mat) of the data itself.
❏An application writes data using a DataWriter. The DataWriter is bound at creation time to a Topic, thus specifying the name under which the DataWriter will publish the data and the type associated with the data. The application uses the DataWriter’s write() operation to indicate that a new value of the data is available for dissemination.
❏A Publisher manages the activities of several DataWriters. The Publisher determines when the data is actually sent to other applications. Depending on the settings of various QosPolicies of the Publisher and DataWriter, data may be buffered to be sent with the data of other DataWriters or not sent at all. By default, the data is sent as soon as the DataW- riter’s write() function is called.
You may have multiple Publishers, each managing a different set of DataWriters, or you may choose to use one Publisher for all your DataWriters.
For more information, see Creating Publishers Explicitly vs. Implicitly (Section 6.2.1).
Publishers
Figure 6.1 on page
Figure 6.1 Publication Module
Publishers are used to perform the operations listed in Table 6.1 on page
Note: Some operations cannot be used within a listener callback, see Restricted Operations in Listener Callbacks (Section 4.5.1).
6.2.1Creating Publishers Explicitly vs. Implicitly
To send data, your application must have a Publisher. However, you are not required to explicitly create one. If you do not create one, the middleware will implicitly create a Publisher the first time you create a DataWriter using the DomainParticipant’s operations. It will be created with default QoS (DDS_PUBLISHER_QOS_DEFAULT) and no Listener.
Publishers
Table 6.1 Publisher Operations
Working |
Operation |
|
|
Description |
|
|
Reference |
||
with ... |
|
|
|
|
|||||
|
|
|
|
|
|
|
|
||
|
|
|
|
||||||
|
begin_coherent_ |
Indicates that the application will begin a coherent set |
|||||||
|
changes |
of modifications. |
|
|
|
|
|
||
|
create_datawriter |
Creates a DataWriter that will belong to the Publisher. |
|
||||||
|
|
|
|||||||
|
create_datawriter_ |
Sets the DataWriter’s QoS based on a specified QoS |
|||||||
|
with_profile |
profile. |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
copy_from_topic_qos |
Copies relevant QosPolicies from a Topic into a |
|||||||
|
|
DataWriterQoS structure. |
|
|
|
|
|||
|
delete_contained_ |
Deletes all of the DataWriters that were created by the |
|||||||
|
entities |
Publisher. |
|
|
|
|
|
|
|
|
delete_datawriter |
Deletes a DataWriter that belongs to the Publisher. |
|||||||
|
|
|
|
|
|
|
|
|
|
|
end_coherent_changes |
Ends |
the |
coherent |
set |
initiated |
by |
||
|
|
begin_coherent_changes(). |
|
|
|
|
|||
|
get_all_datawriters |
Retrieves all the DataWriters created from this Pub- |
|||||||
DataWriters |
|
lisher. |
|
|
|
|
|
|
|
get_default_ |
Copies the Publisher’s default DataWriterQoS values |
||||||||
|
|||||||||
|
datawriter_qos |
into a DataWriterQos structure. |
|
|
|
||||
|
get_status_changes |
Will always return 0 since there are no Statuses cur- |
|||||||
|
|
rently defined for Publishers. |
|
|
|
|
|||
|
lookup_datawriter |
Retrieves a DataWriter previously created for a specific |
|||||||
|
|
Topic. |
|
|
|
|
|
|
|
|
set_default_datawriter_ |
Sets or changes the default DataWriterQos values. |
|
||||||
|
qos |
|
|
|
|
|
|
||
|
set_default_datawriter_ |
Sets or changes the default DataWriterQos values |
|||||||
|
|
||||||||
|
qos_with_profile |
based on a QoS profile. |
|
|
|
|
|||
|
|
|
|
||||||
|
|
Blocks until all data written by the Publisher’s reliable |
|
||||||
|
wait_for_ |
DataWriters are acknowledged by all matched reliable |
|||||||
|
acknowledgments |
DataReaders, or until the a specified timeout duration, |
|||||||
|
|
max_wait, elapses. |
|
|
|
|
|||
|
|
|
|
|
|||||
|
get_default_library |
Gets the Publisher’s default QoS profile library. |
|
|
|||||
|
|
|
|
|
|||||
|
get_default_profile |
Gets the Publisher’s default QoS profile. |
|
|
|||||
|
|
|
|
|
|||||
Libraries |
get_default_profile_ |
Gets the library that contains the Publisher’s |
default |
||||||
and Profiles |
library |
QoS profile. |
|
|
|
|
|||
|
|
|
|
|
|||||
|
set_default_library |
Sets the default library for a Publisher. |
|
|
|
||||
|
|
|
|
|
|
||||
|
set_default_profile |
Sets the default profile for a Publisher. |
|
|
|
||||
|
|
|
|
||||||
Participants |
get_participant |
Gets the DomainParticipant that was used to create the |
|||||||
|
|
Publisher. |
|
|
|
|
|
|
|
|
|
|
Publishers |
|
Table 6.1 Publisher Operations |
|
|
|
||
|
|
|
|
|
|
|
Working |
Operation |
Description |
Reference |
|
|
with ... |
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enable |
Enables the Publisher. |
|
|
|
|
|
|
|
|
|
|
get_qos |
Gets the Publisher’s current QosPolicy settings. This is |
|
|
|
|
most often used in preparation for calling set_qos(). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Sets the Publisher’s QoS. You can use this operation to |
|
|
|
|
set_qos |
change the values for the Publisher’s QosPolicies. Note, |
|
|
|
|
however, that not all QosPolicies can be changed after |
|
||
|
|
|
the Publisher has been created. |
|
|
|
|
|
|
|
|
|
|
set_qos_with_profile |
Sets the Publisher’s QoS based on a specified QoS pro- |
|
|
|
Publishers |
file. |
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
get_listener |
Gets the currently installed Listener. |
|
|
|
|
|
|
|
|
|
|
set_listener |
Sets the Publisher’s Listener. If you created the Pub- |
|
|
|
|
lisher without a Listener, you can use this operation to |
|
|
|
|
|
|
add one later. |
|
|
|
|
|
|
|
|
|
|
|
Provides a hint that multiple |
|
|
|
|
suspend_publications |
Publisher are about to be written. Connext does not |
|
|
|
|
|
currently use this hint. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resume_publications |
Reverses the action of suspend_publications(). |
|
|
|
|
|
|
|
|
A Publisher (implicit or explicit) gets its own default QoS and the default QoS for its child DataWriters from the DomainParticipant. These default QoS are set when the Publisher is created. (This is true for Subscribers and DataReaders, too.)
The 'implicit Publisher' can be accessed using the DomainParticipant’s get_implicit_publisher() operation (see Section 8.3.9). You can use this ‘implicit Publisher’ just like any other Publisher (it has the same operations, QosPolicies, etc.). So you can change the mutable QoS and set a Lis- tener if desired.
DataWriters are created by calling create_datawriter() or create_datawriter_with_profile()— these operations exist for DomainParticipants and Publishers. If you use the DomainParticipant to create a DataWriter, it will belong to the implicit Publisher. If you use a Publisher to create a DataWriter, it will belong to that Publisher.
The middleware will use the same implicit Publisher for all DataWriters that are created using the
DomainParticipant’s operations.
Having the middleware implicitly create a Publisher allows you to skip the step of creating a Publisher. However, having all your DataWriters belong to the same Publisher can reduce the con- currency of the system because all the write operations will be serialized.
6.2.2Creating Publishers
Before you can explicitly create a Publisher, you need a DomainParticipant (see Section 8.3). To create a Publisher, use the DomainParticipant’s create_publisher() or create_publisher_with_profile() operations:
DDSPublisher * create_publisher (const DDS_PublisherQos &qos,
DDSPublisherListener *listener,
DDS_StatusMask mask)
DDSPublisher * create_publisher_with_profile (
const char *library_name, const char *profile_name,
Publishers
DDSPublisherListener *listener,
DDS_StatusMask mask)
A QoS profile is way to use QoS settings from an XML file or string. With this approach, you can change QoS settings without recompiling the application. For details, see Chapter 17: Configur- ing QoS with XML.
qos If you want the default QoS settings (described in the API Reference HTML documenta- tion), use DDS_PUBLISHER_QOS_DEFAULT for this parameter (see Figure 6.2). If you want to customize any of the QosPolicies, supply a QoS structure (see Figure 6.3). The QoS structure for a Publisher is described in Section 6.4.
Note: If you use DDS_PUBLISHER_QOS_DEFAULT, it is not safe to create the Pub- lisher while another thread may be simultaneously calling set_default_publisher_qos().
listener Listeners are callback routines. Connext uses them to notify your application when spe- cific events (status changes) occur with respect to the Publisher or the DataWriters created by the Publisher. The listener parameter may be set to NULL if you do not want to install a
Listener. If you use NULL, the Listener of the DomainParticipant to which the Publisher belongs will be used instead (if it is set). For more information on PublisherListeners, see Section 6.2.5.
mask This
library_name A QoS Library is a named set of QoS profiles. See QoS Libraries (Section 17.10). If NULL is used for library_name, the DomainParticipant’s default library is assumed (see Section 6.2.4.3).
profile_name A QoS profile groups a set of related QoS, usually one per entity. See QoS Profiles (Section 17.9). If NULL is used for profile_name, the DomainParticipant’s default profile is assumed and library_name is ignored.
Figure 6.2 Creating a Publisher with Default QosPolicies
// create the publisher DDSPublisher* publisher =
if (publisher == NULL) { // handle error
};
For more examples, see Configuring QoS Settings when the Publisher is Created (Section 6.2.4.1).
After you create a Publisher, the next step is to use the Publisher to create a DataWriter for each Topic, see Section 6.3.1. For a list of operations you can perform with a Publisher, see Table 6.1 on page
Publishers
6.2.3Deleting Publishers
This section applies to both implicitly and explicitly created Publishers. To delete a Publisher:
1.You must first delete all DataWriters that were created with the Publisher. Use the Pub- lisher’s delete_datawriter() operation to delete them one at a time, or use the delete_contained_entities() operation (Section 6.2.3.1) to delete them all at the same time.
DDS_ReturnCode_t delete_datawriter (DDSDataWriter *a_datawriter)
2. Delete the Publisher by using the DomainParticipant’s delete_publisher() operation.
DDS_ReturnCode_t delete_publisher (DDSPublisher *p)
Note: A Publisher cannot be deleted within a Listener callback, see Restricted Operations in Lis- tener Callbacks (Section 4.5.1).
6.2.3.1Deleting Contained DataWriters
The Publisher’s delete_contained_entities() operation deletes all the DataWriters that were cre- ated by the Publisher.
DDS_ReturnCode_t delete_contained_entities ()
After this operation returns successfully, the application may delete the Publisher (see Section 6.2.3).
6.2.4Setting Publisher QosPolicies
A Publisher’s QosPolicies control its behavior. Think of the policies as the configuration and behavior ‘properties’ of the Publisher. The DDS_PublisherQos structure has the following for- mat:
DDS_PublisherQos struct { |
|
DDS_PresentationQosPolicy |
presentation; |
DDS_PartitionQosPolicy |
partition; |
DDS_GroupDataQosPolicy |
group_data; |
DDS_EntityFactoryQosPolicy |
entity_factory; |
DDS_AsynchronousPublisherQosPolicy asynchronous_publisher; |
|
DDS_ExclusiveAreaQosPolicy |
exclusive_area; |
} DDS_PublisherQos; |
|
Note: set_qos() cannot always be used in a listener callback; see Restricted Operations in Lis- tener Callbacks (Section 4.5.1).
Table 6.2 summarizes the meaning of each policy. (They appear alphabetically in the table.) For information on why you would want to change a particular QosPolicy, see the referenced sec- tion. For defaults and valid ranges, please refer to the API Reference HTML documentation for each policy.
Table 6.2 Publisher QosPolicies
QosPolicy |
|
Description |
|
|
|
|
|
|
Configures the mechanism that sends user data in an exter- |
||
|
nal middleware thread. |
|
|
|
|
Controls whether or not child entities are created in the |
||
|
enabled state. |
|
|
|
|
|
|
Publishers |
Table 6.2 Publisher QosPolicies |
|
|
|
|
|
|
QosPolicy |
Description |
|
|
|
|
|
|
|
Configures |
|
|
tion capabilities. |
|
|
|
|
|
|
Along with TOPIC_DATA QosPolicy (Section 5.2.1) and |
|
USER_DATA QosPolicy (Section 6.5.25), this QosPolicy is |
|
|
used to attach a buffer of bytes to Connext's discovery meta- |
|
|
|
|
|
|
data. |
|
|
|
|
Adds string identifiers that are used for matching DataRead- |
|
|
ers and DataWriters for the same Topic. |
|
|
|
|
|
|
|
|
Controls how Connext presents data received by an applica- |
|
|
tion to the DataReaders of the data. |
|
|
|
|
|
|
|
6.2.4.1Configuring QoS Settings when the Publisher is Created
As described in Creating Publishers (Section 6.2.2), there are different ways to create a Publisher, depending on how you want to specify its QoS (with or without a QoS Profile).
❏In Figure 6.2 on page
DomainParticipant’s set_default_publisher_qos() or set_default_publisher_qos_with_profile() operation (see Section 8.3.6.4).
❏To create a Publisher with
❏You can also create a Publisher and specify its QoS settings via a QoS Profile. To do so, call create_publisher_with_profile(), as seen in Figure 6.4 on page
❏If you want to use a QoS profile, but then make some changes to the QoS before creating the Publisher, call the DomainParticipantFactory’s get_publisher_qos_from_profile(), modify the QoS and use the modified QoS structure when calling create_publisher(), as seen in Figure 6.5 on page
For more information, see Creating Publishers (Section 6.2.2) and Chapter 17: Configuring QoS with XML.
Publishers
Figure 6.3 Creating a Publisher with
DDS_PublisherQos publisher_qos;1
// get defaults
if
// handle error
}
//make QoS changes here
//for example, this changes the ENTITY_FACTORY QoS publisher_qos.entity_factory.autoenable_created_entities =
DDS_BOOLEAN_FALSE;
// create the publisher DDSPublisher* publisher =
NULL, DDS_STATUS_MASK_NONE);
if (publisher == NULL) { // handle error
}
1. For the C API, you need to use DDS_PublisherQos_INITIALIZER or DDS_PublisherQos_initialize(). See Section 4.2.2
Figure 6.4 Creating a Publisher with a QoS Profile
// create the publisher with QoS profile DDSPublisher* publisher =
“MyPublisherLibary”,
“MyPublisherProfile”,
NULL, DDS_STATUS_MASK_NONE);
if (publisher == NULL) { // handle error
}
Publishers
Figure 6.5 Getting QoS Values from a Profile, Changing QoS Values, Creating a Publisher with Modified QoS Values
DDS_PublisherQos publisher_qos;1
// Get publisher QoS from profile
retcode =
if (retcode != DDS_RETCODE_OK) { // handle error
}
//Makes QoS changes here
//New entity_factory autoenable_created_entities will be true publisher_qos.entity_factory.autoenable_created_entities =
DDS_BOOLEAN_TRUE;
// create the publisher with modified QoS
DDSPublisher* publisher = participant->create_publisher( “Example Foo”, type_name, publisher_qos,
NULL, DDS_STATUS_MASK_NONE);
if (publisher == NULL) { // handle error
}
1. For the C API, you need to use DDS_PublisherQos_INITIALIZER or DDS_PublisherQos_initialize(). See Section 4.2.2
6.2.4.2Changing QoS Settings After the Publisher Has Been Created
There are 2 ways to change an existing Publisher’s QoS after it is has been
❏To change an existing Publisher’s QoS programmatically (that is, without using a QoS profile): get_qos() and set_qos(). See the example code in Figure 6.6. It retrieves the cur- rent values by calling the Publisher’s get_qos() operation. Then it modify the value and call set_qos() to apply the new value. Note, however, that some QosPolicies cannot be changed after the Publisher has been
❏You can also change a Publisher’s (and all other Entities’) QoS by using a QoS Profile and calling set_qos_with_profile(). For an example, see Figure 6.7. For more information, see Chapter 17: Configuring QoS with XML.
Publishers
Figure 6.6 Changing the Qos of an Existing Publisher
DDS_PublisherQos publisher_qos;1
// Get current QoS. publisher points to an existing DDSPublisher. if
// handle error
}
//make changes
//New entity_factory autoenable_created_entities will be true
publisher_qos.entity_factory.autoenable_created_entities =DDS_BOOLEAN_TRUE; // Set the new QoS
if
}
1.For the C API, you need to use DDS_PublisherQos_INITIALIZER or DDS_PublisherQos_Initialize(). See Section 4.2.2
Figure 6.7 Changing the QoS of an Existing Publisher with a QoS Profile
retcode = publisher->set_qos_with_profile( “PublisherProfileLibrary”,”PublisherProfile”);
if (retcode != DDS_RETCODE_OK) { // handle error
}
6.2.4.3Getting and Setting the Publisher’s Default QoS Profile and Library
You can retrieve the default QoS profile used to create Publishers with the get_default_profile() operation.
You can also get the default library for Publishers, as well as the library that contains the Pub- lisher’s default profile (these are not necessarily the same library); these operations are called get_default_library() and get_default_library_profile(), respectively. These operations are for informational purposes only (that is, you do not need to use them as a precursor to setting a library or profile.) For more information, see Chapter 17: Configuring QoS with XML.
virtual const char * get_default_library () const char * get_default_profile ()
const char * get_default_profile_library ()
There are also operations for setting the Publisher’s default library and profile:
DDS_ReturnCode_t set_default_library (const char * library_name) DDS_ReturnCode_t set_default_profile (const char * library_name, const char * profile_name)
These operations only affect which library/profile will be used as the default the next time a default Publisher library/profile is needed during a call to one of this Publisher’s operations.
When calling a Publisher operation that requires a profile_name parameter, you can use NULL to refer to the default profile. (This same information applies to setting a default library.) If the default library/profile is not set, the Publisher inherits the default from the DomainParticipant.
set_default_profile() does not set the default QoS for DataWriters created by the Publisher; for this functionality, use the Publisher’s set_default_datawriter_qos_with_profile(), see
Publishers
Section 6.2.4.4 (you may pass in NULL after having called the Publisher’s set_default_profile()).
set_default_profile() does not set the default QoS for newly created Publishers; for this function- ality, use the DomainParticipant’s set_default_publisher_qos_with_profile() operation, see Section 8.3.6.4.
6.2.4.4Getting and Setting Default QoS for DataWriters
These operations set the default QoS that will be used for new DataWriters if create_datawriter() is called with DDS_DATAWRITER_QOS_DEFAULT as the ‘qos’ parameter:
DDS_ReturnCode_t set_default_datawriter_qos (const DDS_DataWriterQos &qos)
DDS_ReturnCode_t set_default_datawriter_qos_with_profile (
const char *library_name, const char *profile_name)
The above operations may potentially allocate memory, depending on the sequences contained in some QoS policies.
To get the default QoS that will be used for creating DataWriters if create_datawriter() is called with DDS_PARTICIPANT_QOS_DEFAULT as the ‘qos’ parameter:
DDS_ReturnCode_t get_default_datawriter_qos (DDS_DataWriterQos & qos)
This operation gets the QoS settings that were specified on the last successful call to set_default_datawriter_qos() or set_default_datawriter_qos_with_profile(), or if the call was never made, the default values listed in DDS_DataWriterQos.
Note: It is not safe to set the default DataWriter QoS values while another thread may be simulta- neously calling get_default_datawriter_qos(), set_default_datawriter_qos(), or create_datawriter() with DDS_DATAWRITER_QOS_DEFAULT as the qos parameter. It is also not safe to get the default DataWriter QoS values while another thread may be simultaneously calling set_default_datawriter_qos(),
6.2.4.5Other Publisher
❏ Copying a Topic’s QoS into a DataWriter’s QoS This method is provided as a convenience for setting the values in a DataWriterQos structure before using that structure to create a DataWriter. As explained in Section 5.1.3, most of the policies in a TopicQos structure do not apply directly to the Topic itself, but to the associated DataWriters and DataReaders of that Topic. The TopicQos serves as a single container where the values of QosPolicies that must be set compatibly across matching DataWriters and DataReaders can be stored.
Thus instead of setting the values of the individual QosPolicies that make up a DataWrit- erQos structure every time you need to create a DataWriter for a Topic, you can use the Publisher’s copy_from_topic_qos() operation to “import” the Topic’s QosPolicies into a DataWriterQos structure. This operation copies the relevant policies in the TopicQos to the corresponding policies in the DataWriterQos.
This copy operation will often be used in combination with the Publisher’s get_default_datawriter_qos() and the Topic’s get_qos() operations. The Topic’s QoS val- ues are merged on top of the Publisher’s default DataWriter QosPolicies with the result used to create a new DataWriter, or to set the QoS of an existing one (see Section 6.3.15).
❏Copying a Publisher’s QoS C API users should use the DDS_PublisherQos_copy() opera- tion rather than using structure assignment when copying between two QoS structures. The copy() operation will perform a deep copy so that policies that allocate heap mem- ory such as sequences are copied correctly. In C++, C++/CLI, C# and Java, a copy con- structor is provided to take care of sequences automatically.
Publishers
❏Clearing
6.2.5Setting Up PublisherListeners
Like all Entities, Publishers may optionally have Listeners. Listeners are
Note: Some operations cannot be used within a listener callback, see Restricted Operations in Listener Callbacks (Section 4.5.1).
As illustrated in Figure 6.1 on page
Instead, the methods of a PublisherListener will be called back for changes in the Statuses of any of the DataWriters that the Publisher has created. This is only true if the DataWriter itself does not have a DataWriterListener installed, see Section 6.3.4. If a DataWriterListener has been installed and has been enabled to handle a Status change for the DataWriter, then Connext will call the method of the DataWriterListener instead.
If you want a Publisher to handle status events for its DataWriters, you can set up a PublisherLis- tener during the Publisher’s creation or use the set_listener() method after the Publisher is created. The last parameter is a
DDS_StatusMask mask = DDS_OFFERED_DEADLINE_MISSED_STATUS | DDS_OFFERED_INCOMPATIBLE_QOS_STATUS;
publisher =
or
DDS_StatusMask mask = DDS_OFFERED_DEADLINE_MISSED_STATUS | DDS_OFFERED_INCOMPATIBLE_QOS_STATUS;
As previously mentioned, the callbacks in the PublisherListener act as ‘default’ callbacks for all the DataWriters contained within. When Connext wants to notify a DataWriter of a relevant Status change (for example, PUBLICATION_MATCHED), it first checks to see if the DataWriter has the corresponding DataWriterListener callback enabled (such as the on_publication_matched() operation). If so, Connext dispatches the event to the DataWriterListener callback. Otherwise, Con- next dispatches the event to the corresponding PublisherListener callback.
A particular callback in a DataWriter is not enabled if either:
❏The application installed a NULL DataWriterListener (meaning there are no callbacks for the DataWriter at all).
Publishers
❏The application has disabled the callback for a DataWriterListener. This is done by turning off the associated status bit in the mask parameter passed to the set_listener() or create_datawriter() call when installing the DataWriterListener on the DataWriter. For more information on DataWriterListeners, see Section 6.3.4.
Similarly, the callbacks in the DomainParticipantListener act as ‘default’ callbacks for all the Pub- lishers that belong to it. For more information on DomainParticipantListeners, see Section 8.3.5.
For example, Figure 6.8 shows how to create a Publisher with a Listener that simply prints the events it receives.
Figure 6.8 Example Code to Create a Publisher with a Simple Listener
class MyPublisherListener : public DDSPublisherListener { public:
virtual void on_offered_deadline_missed(DDSDataWriter* writer, const DDS_OfferedDeadlineMissedStatus& status);
virtual void on_liveliness_lost(DDSDataWriter* writer, const DDS_LivelinessLostStatus& status);
virtual void on_offered_incompatible_qos(DDSDataWriter* writer, const DDS_OfferedIncompatibleQosStatus& status);
virtual void on_publication_matched(DDSDataWriter* writer, const DDS_PublicationMatchedStatus& status);
virtual void
on_reliable_writer_cache_changed(DDSDataWriter* writer, const DDS_ReliableWriterCacheChangedStatus& status);
virtual void on_reliable_reader_activity_changed (DDSDataWriter* writer,
const DDS_ReliableReaderActivityChangedStatus& status);
};
void MyPublisherListener::on_offered_deadline_missed( DDSDataWriter* writer,
const DDS_OfferedDeadlineMissedStatus& status)
{
printf(“on_offered_deadline_missed\n”);
}
// ...Implement all remaining listeners in a similar manner...
DDSPublisherListener *myPubListener = new MyPublisherListener();
DDSPublisher* publisher = participant->create_publisher( DDS_PUBLISHER_QOS_DEFAULT, myPubListener, DDS_STATUS_MASK_ALL);
Publishers
6.2.6Finding a Publisher’s Related Entities
These Publisher operations are useful for obtaining a handle to related entities:
❏get_participant(): Gets the DomainParticipant with which a Publisher was created.
❏lookup_datawriter(): Finds a DataWriter created by the Publisher with a Topic of a particu- lar name. Note that in the event that multiple DataWriters were created by the same Pub- lisher with the same Topic, any one of them may be returned by this method.
❏DDS_Publisher_as_Entity(): This method is provided for C applications and is neces- sary when invoking the parent class Entity methods on Publishers. For example, to call the Entity method get_status_changes() on a Publisher, my_pub, do the following:
DDS_Entity_get_status_changes(DDS_Publisher_as_Entity(my_pub))
DDS_Publisher_as_Entity() is not provided in the C++, C++/CLI, C# and Java APIs because the
6.2.7Waiting for Acknowledgments in a Publisher
The Publisher’s wait_for_acknowledgments() operation blocks the calling thread until either all data written by the Publisher’s reliable DataWriters is acknowledged or the duration specified by the max_wait parameter elapses, whichever happens first.
Note that if a thread is blocked in the call to wait_for_acknowledgments() on a Publisher and a different thread writes new samples on any of the Publisher’s reliable DataWriters, the new sam- ples must be acknowledged before unblocking the thread that is waiting on wait_for_acknowledgments().
DDS_ReturnCode_t wait_for_acknowledgments
(const DDS_Duration_t & max_wait)
This operation returns DDS_RETCODE_OK if all the samples were acknowledged, or
DDS_RETCODE_TIMEOUT if the max_wait duration expired first.
There is a similar operation available for individual DataWriters, see Section 6.3.11.
The reliability protocol used by Connext is discussed in Chapter 10: Reliable Communications.
6.2.8Statuses for Publishers
There are no statuses specific to the Publisher itself. The following statuses can be monitored by the PublisherListener for the Publisher’s DataWriters.
❏OFFERED_DEADLINE_MISSED Status (Section 6.3.6.4)
❏LIVELINESS_LOST Status (Section 6.3.6.3)
❏OFFERED_INCOMPATIBLE_QOS Status (Section 6.3.6.5)
❏PUBLICATION_MATCHED Status (Section 6.3.6.6)
❏RELIABLE_WRITER_CACHE_CHANGED Status (DDS Extension) (Section 6.3.6.7)
❏RELIABLE_READER_ACTIVITY_CHANGED Status (DDS Extension) (Section 6.3.6.8)
DataWriters
6.2.9Suspending and Resuming Publications
The operations suspend_publications() and resume_publications() provide a hint to Connext that multiple
6.3DataWriters
To create a DataWriter, you need a DomainParticipant and a Topic.
You need a DataWriter for each Topic that you want to publish. Once you have a DataWriter, you can use it to perform the operations listed in Table 6.3. The most important operation is write(), described in Section 6.3.8. For more details on all operations, see the API Reference HTML docu- mentation.
DataWriters are created by using operations on a DomainParticipant or a Publisher, as described in Section 6.3.1. If you use the DomainParticipant’s operations, the DataWriter will belong to an implicit Publisher that is automatically created by the middleware. If you use a Publisher’s opera- tions, the DataWriter will belong to that Publisher. So either way, the DataWriter belongs to a Pub- lisher.
Note: Some operations cannot be used within a listener callback, see Restricted Operations in Listener Callbacks (Section 4.5.1).
Table 6.3 DataWriter Operations
Working with |
Operation |
Description |
Reference |
|
... |
||||
|
|
|
||
|
|
|
|
|
|
assert_liveliness |
Manually asserts the liveliness of the DataWriter. |
||
|
|
|
|
|
|
enable |
Enables the DataWriter. |
||
|
|
|
|
|
|
get_qos |
Gets the QoS. |
||
|
|
|
|
|
|
lookup_instance |
Gets a handle, given an instance. (Useful for |
||
DataWriters |
|
keyed data types only.) |
|
|
|
set_qos |
Modifies the QoS. |
||
|
|
|
|
|
|
set_qos_with_profile |
Modifies the QoS based on a QoS profile. |
||
|
|
|
|
|
|
get_listener |
Gets the currently installed Listener. |
||
|
|
|
||
|
set_listener |
Replaces the Listener. |
||
|
|
|||
|
|
|
|
|
|
|
|
DataWriters |
|
Table 6.3 DataWriter Operations |
|
|
|
||
|
|
|
|
|
|
|
Working with |
Operation |
Description |
Reference |
|
|
... |
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dispose |
States that the instance no longer exists. (Useful |
|
|
|
|
for keyed data types only.) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Same as dispose, but allows the application to |
|
|
|
|
dispose_w_timestamp |
override the automatic source_timestamp. (Use- |
|
|
|
|
|
ful for keyed data types only.) |
|
|
|
|
|
|
|
|
|
|
flush |
Makes the batch available to be sent on the net- |
|
|
|
|
|
work. |
|
|
|
|
get_key_value |
Maps an instance_handle to the corresponding |
|
|
|
|
|
key. |
|
|
|
|
|
A |
|
|
|
|
narrow |
DDSDataWriter pointer and ‘narrows’ it to a ‘Foo- |
|
|
|
|
|
DataWriter’ where ‘Foo’ is the related data type. |
|
|
|
|
|
|
|
|
|
FooData- |
|
States the intent of the DataWriter to write values |
|
|
|
Writer |
register_instance |
of the |
|
|
|
(See |
Improves the performance of subsequent writes |
|
|
|
|
|
|
|
||
|
|
to the instance. (Useful for keyed data types only.) |
|
|
|
|
|
register_instance_w_ |
Like register_instance, but allows the application |
|
|
|
|
to override the automatic source_timestamp. |
|
|
|
|
|
timestamp |
|
|
|
|
|
(Useful for keyed data types only.) |
|
||
|
|
|
|
||
|
|
|
Reverses register_instance. Relinquishes the own- |
|
|
|
|
unregister_instance |
ership of the instance. (Useful for keyed data |
|
|
|
|
|
types only.) |
|
|
|
|
|
|
|
|
|
|
unregister_instance_w_ |
Like unregister_instance, but allows the applica- |
|
|
|
|
tion to override the automatic source_timestamp. |
|
|
|
|
|
timestamp |
|
|
|
|
|
(Useful for keyed data types only.) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
write |
Writes a new value for a |
|
|
|
|
|
|
|
|
|
|
write_w_timestamp |
Same as write, but allows the application to over- |
|
|
|
|
ride the automatic source_timestamp. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Same as write, but allows the application to spec- |
|
|
|
|
write_w_params |
ify parameters such as source timestamp and |
|
|
|
|
|
instance handle. |
|
|
|
|
|
|
|
|
|
|
|
Same as dispose, but allows the application to |
|
|
|
FooData- |
dispose_w_params |
specify parameters such as source timestamp and |
|
|
|
|
instance handle.. |
|
|
|
|
Writer |
|
|
|
|
|
|
|
|
|
|
|
(See |
|
Same as register, but allows the application to |
|
|
|
register_w_params |
specify parameters such as source timestamp, |
|
|
|
|
|
|
instance handle. |
|
|
|
|
|
|
|
|
|
|
|
Same as unregister, but allows the application to |
|
|
|
|
|
|
|
|
|
|
unregister_w_params |
specify parameters such as source timestamp, and |
|
|
|
|
|
instance handle. |
|
|
|
|
|
|
|
|
|
|
|
|
DataWriters |
|
Table 6.3 DataWriter Operations |
|
|
|
||
|
|
|
|
|
|
|
Working with |
Operation |
Description |
Reference |
|
|
... |
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get_matched_ |
Gets a list of subscriptions that have a matching |
|
|
|
|
Topic and compatible QoS. These are the subscrip- |
|
|
|
|
|
subscriptions |
|
|
|
|
|
tions currently associated with the DataWriter. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Matched |
get_matched_ |
Gets information on a subscription with a match- |
|
|
|
subscription_data |
ing Topic and compatible QoS. |
|
||
|
Subscriptions |
|
|||
|
|
|
|
|
|
|
|
Gets a list of locators for subscriptions that have a |
|
|
|
|
|
|
|
|
|
|
|
get_matched_ |
matching Topic and compatible QoS. These are |
|
|
|
|
subscription_locators |
the subscriptions currently associated with the |
|
|
|
|
|
DataWriter. |
|
|
|
|
|
|
|
|
|
|
|
Gets a list of statuses that have changed since the |
|
|
|
|
get_status_changes |
last time the application read the status or the lis- |
|
|
|
|
|
teners were called. |
|
|
|
|
|
|
|
|
|
|
get_liveliness_lost_status |
Gets LIVELINESS_LOST status. |
|
|
|
|
|
|
|
|
|
|
get_offered_deadline_ |
Gets OFFERED_DEADLINE_MISSED status. |
|
|
|
|
missed_status |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get_offered_ |
Gets OFFERED_INCOMPATIBLE_QOS status. |
|
|
|
|
incompatible_qos_status |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get_publication_match_ |
Gets PUBLICATION_MATCHED_QOS status. |
|
|
|
|
status |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get_reliable_writer_ |
Gets RELIABLE_WRITER_CACHE_CHANGED |
|
|
|
|
cache_changed_status |
status |
|
|
|
|
|
|
||
|
|
|
|
|
|
|
Status |
get_reliable_reader_ |
Gets |
|
|
|
RELIABLE_READER_ACTIVITY_CHANGED |
|
|
||
|
|
activity_changed_status |
|
|
|
|
|
status |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get_datawriter_cache_ |
Gets DATA_WRITER_CACHE_status |
|
|
|
|
status |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get_datawriter_protocol_ |
Gets DATA_WRITER_PROTOCOL status |
|
|
|
|
status |
|
|
|
|
|
get_matched_ |
Gets DATA_WRITER_PROTOCOL status for this |
|
|
|
|
subscription_datawriter_ |
DataWriter, per matched subscription identified |
|
|
|
|
protocol_status |
by the subscription_handle. |
|
|
|
|
|
|
|
|
|
|
get_matched_ |
Gets DATA_WRITER_PROTOCOL status for this |
|
|
|
|
subscription_datawriter_ |
|
|
|
|
|
DataWriter, per matched subscription as identi- |
|
|
|
|
|
protocol_status_ |
fied by a locator. |
|
|
|
|
by_locator |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get_publisher |
Gets the Publisher to which the DataWriter |
|
|
|
|
belongs. |
|
||
|
|
|
|
||
|
|
get_topic |
Get the Topic associated with the DataWriter. |
|
|
|
Other |
|
|
|
|
|
|
Blocks the calling thread until either all data writ- |
|
|
|
|
|
|
|
|
|
|
|
wait_for_ |
ten by the DataWriter is acknowledged by all |
|
|
|
|
acknowledgements |
matched Reliable DataReaders, or until the a speci- |
|
|
|
|
|
fied timeout duration, max_wait, elapses. |
|
|
|
|
|
|
|
|
DataWriters
6.3.1Creating DataWriters
Before you can create a DataWriter, you need a DomainParticipant, a Topic, and optionally, a Pub- lisher.
DataWriters are created by calling create_datawriter() or create_datawriter_with_profile()— these operations exist for DomainParticipants and Publishers. If you use the DomainParticipant to create a DataWriter, it will belong to the implicit Publisher described in Section 6.2.1. If you use a Publisher’s operations to create a DataWriter, it will belong to that Publisher.
DDSDataWriter* create_datawriter ( DDSTopic *topic,
const DDS_DataWriterQos &qos,
DDSDataWriterListener *listener, DDS_StatusMask mask)
DDSDataWriter * create_datawriter_with_profile ( DDSTopic * topic,
const char * library_name, const char * profile_name,
DDSDataWriterListener * listener, DDS_StatusMask mask)
A QoS profile is way to use QoS settings from an XML file or string. With this approach, you can change QoS settings without recompiling the application. For details, see Chapter 17: Configur- ing QoS with XML.
topic The Topic that the DataWriter will publish. This must have been previously created by the same DomainParticipant.
qos If you want the default QoS settings (described in the API Reference HTML documenta- tion), use the constant DDS_DATAWRITER_QOS_DEFAULT for this parameter (see Figure 6.9 on page
Note: If you use DDS_DATAWRITER_QOS_DEFAULT for the qos parameter, it is not safe to create the DataWriter while another thread may be simultaneously calling the Pub- lisher’s set_default_datawriter_qos() operation.
listener Listeners are callback routines. Connext uses them to notify your application of specific events (status changes) that may occur with respect to the DataWriter. The listener parame- ter may be set to NULL; in this case, the PublisherListener (or if that is NULL, the Domain- ParticipantListener) will be used instead. For more information, see Section 6.3.4.
mask This
library_name A QoS Library is a named set of QoS profiles. See QoS Libraries (Section 17.10).
profile_name A QoS profile groups a set of related QoS, usually one per entity. See QoS Profiles (Section 17.9).
For more examples on how to create a DataWriter, see Configuring QoS Settings when the DataWriter is Created (Section 6.3.15.1)
After you create a DataWriter, you can use it to write data. See Writing Data (Section 6.3.8).
DataWriters
Note: When a DataWriter is created, only those transports already registered are available to the DataWriter. The
Figure 6.9 Creating a DataWriter with Default QosPolicies and a Listener
// MyWriterListener is user defined, extends DDSDataWriterListener DDSDataWriterListener* writer_listener = new MyWriterListener();
DDSDataWriter* writer = publisher->create_datawriter( topic,
DDS_DATAWRITER_QOS_DEFAULT, writer_listener, DDS_STATUS_MASK_ALL);
if (writer == NULL) { // ... error
};
// narrow it for your specific data type
FooDataWriter* foo_writer = FooDataWriter::narrow(writer);
6.3.2Getting All DataWriters
To retrieve all the DataWriters created by the Publisher, use the Publisher’s get_all_datawriters() operation:
DDS_ReturnCode_t get_all_datawriters(DDS_Publisher* self,
struct DDS_DataWriterSeq* writers);
6.3.3Deleting DataWriters
To delete a single DataWriter, use the Publisher’s delete_datawriter() operation:
DDS_ReturnCode_t delete_datawriter (DDSDataWriter *a_datawriter)
Note: A DataWriter cannot be deleted within its own writer listener callback, see Restricted Operations in Listener Callbacks (Section 4.5.1)
DataWriters
To delete all of a Publisher’s DataWriters, use the Publisher’s delete_contained_entities() opera- tion (see Section 6.2.3.1).
Special instructions for deleting DataWriters if you are using the ‘Timestamp’ APIs and BY_SOURCE_TIMESTAMP Destination Order:
This note only applies when the DataWriter’s DestinationOrderQosPolicy’s kind is BY_SOURCE_TIMESTAMP.
Calls to delete_datawriter() may fail if your application has previously used the “with time- stamp” APIs (write_w_timestamp(), register_instance_w_timestamp(), unregister_instance_w_timestamp(), or dispose_w_timestamp()) with a timestamp that is larger than the time at which delete_datawriter() is called.
To prevent delete_datawriter() from failing in this situation, either:
❏Change the WriterDataLifeCycle QoS Policy so that Connext will not
writer_qos.writer_data_lifecycle. autodispose_unregistered_instances =
DDS_BOOLEAN_FALSE; or
❏Explicitly call unregister_instance_w_timestamp() for all instances modified with the
*_w_timestamp() APIs before calling delete_datawriter().
6.3.4Setting Up DataWriterListeners
DataWriters may optionally have Listeners. Listeners are essentially callback routines and provide the means for Connext to notify your application of the occurrence of events (status changes) rel- evant to the DataWriter. For more general information on Listeners, see Listeners (Section 4.4).
Note: Some operations cannot be used within a listener callback, see Restricted Operations in Listener Callbacks (Section 4.5.1).
If you do not implement a DataWriterListener, the associated PublisherListener is used instead. If that Publisher also does not have a Listener, then the DomainParticipant’s Listener is used if one exists (see Section 6.2.5 and Section 8.3.5).
Listeners are typically set up when the DataWriter is created (see Section 6.2). You can also set one up after creation by using the set_listener() operation. Connext will invoke a DataWriter’s Lis- tener to report the status changes listed in Table 6.4 (if the Listener is set up to handle the partic- ular status, see Section 6.3.4).
Table 6.4 DataWriterListener Callbacks
This DataWriterListener
... is triggered by ...
callback...
on_instance_replaced()
A replacement of an existing instance by a new instance; see Con- figuring DataWriter Instance Replacement (Section 6.5.20.2)
on_liveliness_lost |
A change to LIVELINESS_LOST Status (Section 6.3.6.3) |
on_offered_deadline_missed
A change to OFFERED_DEADLINE_MISSED Status (Section 6.3.6.4)
on_offered_incompatible_qos
A change to OFFERED_INCOMPATIBLE_QOS Status (Section 6.3.6.5)
DataWriters
Table 6.4 DataWriterListener Callbacks
This DataWriterListener
... is triggered by ...
callback...
on_publication_matched |
A change to PUBLICATION_MATCHED Status (Section 6.3.6.6) |
on_reliable_writer_cache_changed
A change to RELIABLE_WRITER_CACHE_CHANGED Status (DDS Extension) (Section 6.3.6.7)
on_reliable_reader_activity_changed
A change to RELIABLE_READER_ACTIVITY_CHANGED Status (DDS Extension) (Section 6.3.6.8)
6.3.5Checking DataWriter Status
You can access an individual communication status for a DataWriter with the operations shown in Table 6.5.
Table 6.5 DataWriter Status Operations
Use this operation... |
...to retrieve this status: |
|
|
|
|
get_datawriter_cache_status |
|
|
|
|
|
get_datawriter_protocol_status |
|
|
|
|
|
get_matched_subscription_datawriter_ |
|
|
protocol_status |
||
|
|
|
get_matched_subscription_datawriter_ |
|
|
protocol_status_by_locator |
|
|
|
|
|
get_liveliness_lost_status |
|
|
|
|
|
get_offered_deadline_missed_status |
||
|
|
|
get_offered_incompatible_qos_status |
||
|
|
|
get_publication_match_status |
|
|
|
|
|
get_reliable_writer_cache_changed_status |
||
|
||
|
|
|
|
|
|
get_reliable_reader_activity_changed_status |
||
|
|
|
get_status_changes |
A list of what changed in all of the above. |
|
|
|
|
These methods are useful in the event that no Listener callback is set to receive notifications of status changes. If a Listener is used, the callback will contain the new status information, in which case calling these methods is unlikely to be necessary.
The get_status_changes() operation provides a list of statuses that have changed since the last time the status changes were ‘reset.’ A status change is reset each time the application calls the corresponding get_*_status(), as well as each time Connext returns from calling the Listener call- back associated with that status.
For more on status, see Setting Up DataWriterListeners (Section 6.3.4), Statuses for DataWriters (Section 6.3.6), and Listeners (Section 4.4).
6.3.6Statuses for DataWriters
There are several types of statuses available for a DataWriter. You can use the get_*_status() operations (Section 6.3.15) to access them, or use a DataWriterListener (Section 6.3.4) to listen for changes in their values. Each status has an associated data structure and is described in more detail in the following sections.
DataWriters
❏DATA_WRITER_CACHE_STATUS (Section 6.3.6.1)
❏DATA_WRITER_PROTOCOL_STATUS (Section 6.3.6.2)
❏LIVELINESS_LOST Status (Section 6.3.6.3)
❏OFFERED_DEADLINE_MISSED Status (Section 6.3.6.4)
❏OFFERED_INCOMPATIBLE_QOS Status (Section 6.3.6.5)
❏PUBLICATION_MATCHED Status (Section 6.3.6.6)
❏RELIABLE_WRITER_CACHE_CHANGED Status (DDS Extension) (Section 6.3.6.7)
❏RELIABLE_READER_ACTIVITY_CHANGED Status (DDS Extension) (Section 6.3.6.8)
6.3.6.1DATA_WRITER_CACHE_STATUS
This status keeps track of the number of samples in the DataWriter’s queue.
This status does not have an associated Listener. You can access this status by calling the DataW- riter’s get_datawriter_cache_status() operation, which will return the status structure described in Table 6.6.
Table 6.6 DDS_DataWriterCacheStatus
Type |
Field Name |
Description |
|
|
|
|
|
|
|
|
|
DDS_Long |
sample_count_peak |
Highest number of samples in the DataWriter’s queue over the |
|
lifetime of the DataWriter. |
|||
|
|
||
|
|
|
|
DDS_Long |
sample_count |
Current number of samples in the DataWriter’s queue. |
|
|
|
|
6.3.6.2DATA_WRITER_PROTOCOL_STATUS
This status includes internal protocol related metrics (such as the number of samples pushed, pulled, filtered) and the status of
❏Pulled samples are samples sent for repairs (that is, samples that had to be resent), for late joiners, and all samples sent by the local DataWriter when push_on_write (in DATA_WRITER_PROTOCOL QosPolicy (DDS Extension) (Section 6.5.3)) is DDS_BOOLEAN_FALSE.
❏Pushed samples are samples sent on write() when push_on_write is DDS_BOOLEAN_TRUE.
❏Filtered samples are samples that are not sent due to DataWriter filtering
This status does not have an associated Listener. You can access this status by calling the follow- ing operations on the DataWriter (all of which return the status structure described in Table 6.7 on page
❏get_datawriter_protocol_status() returns the sum of the protocol status for all the matched subscriptions for the DataWriter.
❏get_matched_subscription_datawriter_protocol_status() returns the protocol status of a particular matched subscription, identified by a subscription_handle.
❏get_matched_subscription_datawriter_protocol_status_by_locator() returns the proto- col status of a particular matched subscription, identified by a locator. (See Locator For- mat (Section 14.2.1.1).)
Note: Status for a remote entity is only kept while the entity is alive. Once a remote entity is no longer alive, its status is deleted. If you try to get the matched subscription status for a remote entity that is no longer alive, the ‘get status’ call will return an error.
DataWriters
Table 6.7 DDS_DataWriterProtocolStatus
Type |
Field Name |
Description |
|
|
|
|
|
|
|
|
|
|
pushed_sample_count |
The number of user samples pushed on write from a |
|
|
local DataWriter to a matching remote DataReader. |
||
|
|
||
|
|
|
|
|
|
The incremental change in the number of user sam- |
|
|
pushed_sample_count_change |
ples pushed on write from a local DataWriter to a |
|
|
matching remote DataReader since the last time the |
||
|
|
||
|
|
status was read. |
|
DDS_LongLong |
|
|
|
|
The number of bytes of user samples pushed on write |
||
|
pushed_sample_bytes |
from a local DataWriter to a matching remote |
|
|
|
DataReader. |
|
|
|
|
|
|
|
The incremental change in the number of bytes of user |
|
|
pushed_sample_bytes_change |
samples pushed on write from a local DataWriter to a |
|
|
matching remote DataReader since the last time the |
||
|
|
||
|
|
status was read. |
|
|
|
|
|
|
filtered_sample_count |
The number of user samples preemptively filtered by |
|
|
a local DataWriter due to |
||
|
|
||
|
|
|
|
|
|
The incremental change in the number of user sam- |
|
|
filtered_sample_count_change |
ples preemptively filtered by a local DataWriter due to |
|
|
ContentFilteredTopics since the last time the status |
||
|
|
||
DDS_LongLong |
|
was read. |
|
|
|
||
filtered_sample_bytes |
The number of user samples preemptively filtered by |
||
|
|||
|
a local DataWriter due to ContentFilteredTopics. |
||
|
|
||
|
|
|
|
|
|
The incremental change in the number of user sam- |
|
|
filtered_sample_bytes_change |
ples preemptively filtered by a local DataWriter due to |
|
|
ContentFilteredTopics since the last time the status |
||
|
|
||
|
|
was read. |
|
|
|
|
|
|
sent_heartbeat_count |
The number of Heartbeats sent between a local |
|
|
DataWriter and matching remote DataReaders. |
||
|
|
||
|
|
|
|
|
|
The incremental change in the number of Heartbeats |
|
|
sent_heartbeat_count_change |
sent between a local DataWriter and matching remote |
|
|
|
DataReaders since the last time the status was read. |
|
DDS_LongLong |
|
|
|
sent_heartbeat_bytes |
The number of bytes of Heartbeats sent between a |
||
|
local DataWriter and matching remote DataReader. |
||
|
|
||
|
|
|
|
|
|
The incremental change in the number of bytes of |
|
|
sent_heartbeat_bytes_change |
Heartbeats sent between a local DataWriter and |
|
|
matching remote DataReaders since the last time the |
||
|
|
||
|
|
status was read. |
|
|
|
|
|
|
pulled_sample_count |
The number of user samples pulled from local DataW- |
|
|
riter by matching DataReaders. |
||
|
|
||
|
|
|
|
|
|
The incremental change in the number of user sam- |
|
|
pulled_sample_count_change |
ples pulled from local DataWriter by matching |
|
DDS_LongLong |
|
DataReaders since the last time the status was read. |
|
|
|
||
pulled_sample_bytes |
The number of bytes of user samples pulled from local |
||
|
|||
|
DataWriter by matching DataReaders. |
||
|
|
||
|
|
|
|
|
|
The incremental change in the number of bytes of user |
|
|
pulled_sample_bytes_change |
samples pulled from local DataWriter by matching |
|
|
|
DataReaders since the last time the status was read. |
|
|
|
|
DataWriters
Table 6.7 DDS_DataWriterProtocolStatus
Type |
Field Name |
Description |
|
|
|
|
|
|
|
|
|
|
received_ack_count |
The number of ACKs from a remote DataReader |
|
|
received by a local DataWriter. |
||
|
|
||
|
|
|
|
|
|
The incremental change in the number of ACKs from |
|
|
received_ack_count_change |
a remote DataReader received by a local DataWriter |
|
DDS_LongLong |
|
since the last time the status was read. |
|
|
|
||
received_ack_bytes |
The number of bytes of ACKs from a remote |
||
|
|||
|
DataReader received by a local DataWriter. |
||
|
|
||
|
|
|
|
|
|
The incremental change in the number of bytes of |
|
|
received_ack_bytes_change |
ACKs from a remote DataReader received by a local |
|
|
|
DataWriter since the last time the status was read. |
|
|
|
|
|
|
received_nack_count |
The number of NACKs from a remote DataReader |
|
|
received by a local DataWriter. |
||
|
|
||
|
|
|
|
|
|
The incremental change in the number of NACKs |
|
|
received_nack_count_change |
from a remote DataReader received by a local DataW- |
|
DDS_LongLong |
|
riter since the last time the status was read. |
|
|
|
||
received_nack_bytes |
The number of bytes of NACKs from a remote |
||
|
|||
|
DataReader received by a local DataWriter. |
||
|
|
||
|
|
|
|
|
|
The incremental change in the number of bytes of |
|
|
received_nack_bytes_change |
NACKs from a remote DataReader received by a local |
|
|
|
DataWriter since the last time the status was read. |
|
|
|
|
|
|
sent_gap_count |
The number of GAPs sent from local DataWriter to |
|
|
matching remote DataReaders. |
||
|
|
||
|
|
|
|
|
|
The incremental change in the number of GAPs sent |
|
|
sent_gap_count_change |
from local DataWriter to matching remote DataReaders |
|
DDS_LongLong |
|
since the last time the status was read. |
|
|
|
||
sent_gap_bytes |
The number of bytes of GAPs sent from local DataW- |
||
|
|||
|
riter to matching remote DataReaders. |
||
|
|
||
|
|
|
|
|
|
The incremental change in the number of bytes of |
|
|
sent_gap_bytes_change |
GAPs sent from local DataWriter to matching remote |
|
|
|
DataReaders since the last time the status was read. |
|
|
|
|
|
|
rejected_sample_count |
The number of times a sample is rejected for unantici- |
|
|
pated reasons in the send path. |
||
|
|
||
DDS_LongLong |
|
|
|
|
The incremental change in the number of times a sam- |
||
|
rejected_sample_count_change |
ple is rejected due to exceptions in the send path since |
|
|
|
the last time the status was read. |
|
|
|
|
|
DDS_Long |
send_window_size |
Current maximum number of outstanding samples |
|
allowed in the DataWriter's queue. |
|||
|
|
||
|
|
|
|
|
|
|
DataWriters |
|
Table 6.7 DDS_DataWriterProtocolStatus |
|
|
|
||
|
|
|
|
|
|
|
Type |
Field Name |
|
Description |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
first_available_sample_ |
Sequence number of the first available sample in the |
|
|
|
|
sequence_number |
DataWriter's reliability queue. |
|
|
|
|
|
|
|
|
|
|
last_available_sample_ |
Sequence number of the last available sample in the |
|
|
|
|
sequence_number |
DataWriter's reliability queue. |
|
|
|
|
|
|
|
|
|
|
first_unacknowledged_sample_ |
Sequence number of the first unacknowledged sample |
|
|
|
DDS_Sequence |
sequence_number |
in the DataWriter's reliability queue. |
|
|
|
Number_t |
first_available_sample_virtual_ |
Virtual sequence number of the first available sample |
|
|
|
|
sequence_number |
in the DataWriter's reliability queue. |
|
|
|
|
|
|
|
|
|
|
last_available_sample_virtual_ |
Virtual sequence number of the last available sample |
|
|
|
|
sequence_number |
in the DataWriter's reliability queue. |
|
|
|
|
|
|
|
|
|
|
first_unacknowledged_sample_virtual_ |
Virtual sequence number of the first unacknowledged |
|
|
|
|
sequence_number |
sample in the DataWriter's reliability queue. |
|
|
|
|
|
|
|
|
|
|
first_unacknowledged_sample_ |
Instance Handle of the matching remote DataReader |
|
|
|
|
for which the DataWriter has kept the first available |
|
||
|
|
subscription_handle |
|
||
|
DDS_Sequence |
sample in the reliability queue. |
|
||
|
|
|
|||
|
Number_t |
first_unelapsed_keep_duration_ |
Sequence number |
of the first sample kept in the |
|
|
|
DataWriter's queue |
whose keep_duration (applied |
|
|
|
|
sample_sequence_number |
|
||
|
|
when disable_positive_acks is set) has not yet elapsed. |
|
||
|
|
|
|
||
|
|
|
|
|
|
DataWriters
6.3.6.3LIVELINESS_LOST Status
A change to this status indicates that the DataWriter failed to signal its liveliness within the time specified by the LIVELINESS QosPolicy (Section 6.5.13).
It is different than the RELIABLE_READER_ACTIVITY_CHANGED Status (DDS Extension) (Section 6.3.6.8) status that provides information about the liveliness of a DataWriter’s matched DataReaders; this status reflects the DataWriter’s own liveliness.
The structure for this status appears in Table 6.8 on page
Table 6.8 DDS_LivelinessLostStatus
Type |
Field Name |
Description |
|
|
|
|
|
|
|
|
|
DDS_Long |
total_count |
Cumulative number of times the DataWriter failed to explicitly signal |
|
its liveliness within the liveliness period. |
|||
|
|
||
|
|
|
|
DDS_Long |
total_count_change |
The change in total_count since the last time the Listener was called |
|
or the status was read. |
|||
|
|
|
The DataWriterListener’s on_liveliness_lost() callback is invoked when this status changes. You can also retrieve the value by calling the DataWriter’s get_liveliness_lost_status() operation.
6.3.6.4OFFERED_DEADLINE_MISSED Status
A change to this status indicates that the DataWriter failed to write data within the time period set in its DEADLINE QosPolicy (Section 6.5.5).
The structure for this status appears in Table 6.9.
Table 6.9 DDS_OfferedDeadlineMissedStatus
Type |
Field Name |
Description |
|
|
|
|
|
|
|
|
|
DDS_Long |
total_count |
Cumulative number of times the DataWriter failed to write |
|
within its offered deadline. |
|||
|
|
||
|
|
|
|
DDS_Long |
total_count_change |
The change in total_count since the last time the Listener was |
|
called or the status was read. |
|||
|
|
||
|
|
|
|
DDS_Instance |
last_instance_handle |
Handle to the last |
|
Handle_t |
offered deadline was missed. |
||
|
|||
|
|
|
The DataWriterListener’s on_offered_deadline_missed() operation is invoked when this status changes. You can also retrieve the value by calling the DataWriter’s get_deadline_missed_status() operation.
6.3.6.5OFFERED_INCOMPATIBLE_QOS Status
A change to this status indicates that the DataWriter discovered a DataReader for the same Topic, but that DataReader had requested QoS settings incompatible with this DataWriter’s offered QoS.
The structure for this status appears in Table 6.10.
Table 6.10 DDS_OfferedIncompatibleQoSStatus
Type |
Field Name |
Description |
|
|
|
|
|
|
|
|
Cumulative number of times the DataWriter discovered a |
DDS_Long |
total_count |
DataReader for the same Topic with a requested QoS that is |
|
|
incompatible with that offered by the DataWriter. |
|
|
|
DDS_Long |
total_count_change |
The change in total_count since the last time the Listener was |
called or the status was read. |
||
|
|
|
DataWriters
Table 6.10 DDS_OfferedIncompatibleQoSStatus
Type |
Field Name |
Description |
|
|
|
|
|
|
|
|
|
|
|
The ID of the QosPolicy that was found to be incompatible the |
|
DDS_QosPolicyId_t |
last_policy_id |
last time an incompatibility was detected. (Note: if there are |
|
multiple incompatible policies, only one of them is reported |
|||
|
|
||
|
|
here.) |
|
|
|
|
|
|
|
A list |
|
DDS_ |
policies |
that the DataWriter discovered a DataReader for the same Topic |
|
QosPolicyCountSeq |
with a requested QoS that is incompatible with that offered by |
||
|
|
the DataWriter. |
|
|
|
|
The DataWriterListener’s on_offered_incompatible_qos() changes. You can also retrieve the value get_offered_incompatible_qos_status() operation.
callback is invoked when this status by calling the DataWriter’s
6.3.6.6PUBLICATION_MATCHED Status
A change to this status indicates that the DataWriter discovered a matching DataReader.
A ‘match’ occurs only if the DataReader and DataWriter have the same Topic, same data type (implied by having the same Topic), and compatible QosPolicies. In addition, if user code has directed Connext to ignore certain DataReaders, then those DataReaders will never be matched. See Section 16.4.2 for more on setting up a DomainParticipant to ignore specific DataReaders.
The structure for this status appears in Table 6.11.
Table 6.11 DDS_PublicationMatchedStatus
Type |
Field Name |
Description |
|
|
|
|
|
|
|
total_count |
Cumulative number of times the DataWriter discovered a |
|
"match" with a DataReader. |
|
|
|
|
|
|
|
|
total_count_change |
The change in total_count since the last time the Listener was |
|
called or the status was read. |
|
|
|
|
|
|
|
DDS_Long |
current_count |
The number of DataReaders currently matched to the DataW- |
|
riter. |
|
|
|
|
|
|
|
|
current_count_peak |
The highest value that current_count has reached until now. |
|
|
|
|
current_count_change |
The change in current_count since the last time the listener |
|
was called or the status was read. |
|
|
|
|
|
|
|
DDS_Instance |
last_subscription_handle |
Handle to the last DataReader that matched the DataWriter |
Handle_t |
causing the status to change. |
|
|
|
|
The DataWriterListener’s on_publication_matched() callback is invoked when this status changes. You can also retrieve the value by calling the DataWriter’s get_publication_match_status() operation.
DataWriters
6.3.6.7RELIABLE_WRITER_CACHE_CHANGED Status (DDS Extension)
A change to this status indicates that the number of unacknowledged samples1 in a reliable DataWriter's cache has reached one of these trigger points:
❏The cache is empty (contains no unacknowledged samples)
❏The cache is full (the number of unacknowledged samples has reached the value speci- fied in DDS_ResourceLimitsQosPolicy::max_samples)
❏The number of unacknowledged samples has reached a high or low watermark. See the high_watermark and low_watermark fields in Table 6.36 of the DATA_WRITER_PROTOCOL QosPolicy (DDS Extension) (Section 6.5.3).
For more about the reliable protocol used by Connext and specifically, what it means for a sam- ple to be ‘unacknowledged,’ see Chapter 10: Reliable Communications.
The structure for this status appears in Table 6.12. The supporting structure,
DDS_ReliableWriterCacheEventCount, is described in Table 6.13.
Table 6.12 DDS_ReliableWriterCacheChangedStatus
|
Type |
|
Field Name |
Description |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
empty_reliable_writer_ |
How many times the reliable DataWriter's cache of unac- |
|
|
|
|
cache |
|
knowledged samples has become empty. |
|
|
|
|
|
|
|
|
|
full_reliable_writer_ |
How many times the reliable DataWriter's cache of unac- |
|
|
DDS_ReliableWriter |
cache |
|
knowledged samples has become full. |
|
|
CacheEventCount |
low_watermark_ |
How many times the reliable DataWriter's cache of unac- |
||
|
|
|
reliable_writer_cache |
knowledged samples has fallen to the low watermark. |
|
|
|
|
|
|
|
|
|
|
high_watermark_ |
How many times the reliable DataWriter's cache of unac- |
|
|
|
|
reliable_writer_cache |
knowledged samples has risen to the high watermark. |
|
|
|
|
|
|
|
|
|
|
unacknowledged_ |
The current number of unacknowledged samples in the |
|
|
DDS_Long |
|
sample_count |
|
DataWriter's cache. |
|
|
|
|
|
|
|
|
unacknowledged_ |
The highest value that unacknowledged_sample_count |
||
|
|
|
|||
|
|
|
sample_count_peak |
has reached until now. |
|
|
|
|
|
|
|
Table 6.13 DDS_ReliableWriterCacheEventCount |
|
||||
|
|
|
|
|
|
|
Type |
Field Name |
|
Description |
|
|
|
|
|
||
|
|
|
|
||
|
DDS_Long |
total_count |
The total number of times the event has occurred. |
||
|
|
|
|
|
|
|
DDS_Long |
total_count_change |
The number of times the event has occurred since the Listener was |
||
|
last invoked or the status read. |
||||
|
|
|
|
||
|
|
|
|
|
|
The DataWriterListener’s on_reliable_writer_cache_changed() tus changes. You can also retrieve the value get_reliable_writer_cache_changed_status() operation.
callback is invoked when this sta- by calling the DataWriter’s
6.3.6.8RELIABLE_READER_ACTIVITY_CHANGED Status (DDS Extension)
This status indicates that one or more reliable DataReaders has become active or inactive.
This status is the reciprocal status to the LIVELINESS_CHANGED Status (Section 7.3.7.4) on the DataReader. It is different than LIVELINESS_LOST Status (Section 6.3.6.3) status on the DataW- riter, in that the latter informs the DataWriter about its own liveliness; this status informs the DataWriter about the liveliness of its matched DataReaders.
1.If batching is enabled, this still refers to a number of samples, not batches.
DataWriters
A reliable DataReader is considered active by a reliable DataWriter with which it is matched if that DataReader acknowledges the samples that it has been sent in a timely fashion. For the defi- nition of "timely" in this context, see DATA_WRITER_PROTOCOL QosPolicy (DDS Extension) (Section 6.5.3).
This status is only used for DataWriters whose RELIABILITY QosPolicy (Section 6.5.19) is set to RELIABLE. For
The structure for this status appears in Table 6.14.
Table 6.14 DDS_ReliableReaderActivityChangedStatus
Type |
Field Name |
Description |
|
|
|
|
active_count |
The current number of reliable readers currently matched with |
|
this reliable DataWriter. |
|
|
|
|
|
|
|
|
|
The number of reliable readers that have been dropped by this |
|
not_active_count |
reliable DataWriter because they failed to send acknowledge- |
DDS_Long |
|
ments in a timely fashion. |
|
active_count_change |
The change in the number of active reliable DataReaders since the |
|
Listener was last invoked or the status read. |
|
|
|
|
|
|
|
|
inactive_count_change |
The change in the number of inactive reliable DataReaders since |
|
|
the Listener was last invoked or the status read. |
DDS_Instance |
last_instance_handle |
The instance handle of the last reliable DataReader to be deter- |
Handle_t |
|
mined to be inactive. |
The DataWriterListener’s on_reliable_reader_activity_changed() callback is invoked when this status changes. You can also retrieve the value by calling the DataWriter’s get_reliable_reader_activity_changed_status() operation.
6.3.7Using a
Recall that a Topic is bound to a data type that specifies the format of the data associated with the Topic. Data types are either defined dynamically or in code generated from definitions in IDL or XML; see Chapter 3: Data Types and Data Samples. For each of your application's generated data types, such as 'Foo', there will be a FooDataWriter class (or a set of functions in C). This class allows the application to use a
In fact, you will use the FooDataWriter any time you need to perform
using FooDataWriter. For operations that are not
You may notice that the Publisher’s create_datawriter() operation returns a pointer to an object of type DDSDataWriter; this is because the create_datawriter() method is used to create DataWrit- ers of any data type. However, when executed, the function actually returns a specialization (an object of a derived class) of the DataWriter that is specific for the data type of the associated Topic. For a Topic of type ‘Foo’, the object actually returned by create_datawriter() is a FooData- Writer.
To safely cast a generic DDSDataWriter pointer to a FooDataWriter pointer, you should use the static narrow() method of the FooDataWriter class. The narrow() method will return NULL if the generic DDSDataWriter pointer is not pointing at an object that is really a FooDataWriter.
1.In the C API, the non
DataWriters
For instance, if you create a Topic bound to the type ‘Alarm’, all DataWriters created for that Topic will be of type ‘AlarmDataWriter.’ To access the
DDSDataWriter* writer =
AlarmDataWriter *alarm_writer = AlarmDataWriter::narrow(writer); if (alarm_writer == NULL) {
// ... error
};
In the C API, there is also a way to do the opposite of narrow(). FooDataWriter_as_datawriter() casts a FooDataWriter as a DDSDataWriter, and FooDataReader_as_datareader() casts a FooDa- taReader as a DDSDataReader.
6.3.8Writing Data
The write() operation informs Connext that there is a new value for a
When you call write(), Connext automatically attaches a stamp of the current time that is sent with the data sample to the DataReader(s). The timestamp appears in the source_timestamp field of the DDS_SampleInfo structure that is provided along with your data using DataReaders (see The SampleInfo Structure (Section 7.4.6)).
DDS_ReturnCode_t write (const Foo &instance_data,
const DDS_InstanceHandle_t &handle)
You can use an alternate DataWriter operation called write_w_timestamp(). This performs the same action as write(), but allows the application to explicitly set the source_timestamp. This is useful when you want the user application to set the value of the timestamp instead of the default clock used by Connext.
DDS_ReturnCode_t write_w_timestamp (const Foo &instance_data, const DDS_InstanceHandle_t &handle, const DDS_Time_t &source_timestamp)
Note that, in general, the application should not mix these two ways of specifying timestamps. That is, for each DataWriter, the application should either always use the automatic timestamp- ing mechanism (by calling the normal operations) or always specify a timestamp (by calling the “w_timestamp” variants of the operations). Mixing the two methods may result in not receiving sent data.
You can also use an alternate DataWriter operation, write_w_params(), which performs the same action as write(), but allows the application to explicitly set the fields contained in the DDS_WriteParams structure, see Table 6.15 on page
Note: Prioritized samples are not supported when using the Java, Ada, or .NET APIs. Therefore the priority field in DDS_WriteParams_t does not exist when using these APIs.
When using the C API, a newly created variable of type DDS_WriteParams_t should be initial- ized by setting it to DDS_WRITEPARAMS_DEFAULT.
DataWriters
Table 6.15 DDS_WriteParams_t
Type |
Field Name |
|
|
|
Description |
|
|
|
||
|
|
|
||||||||
|
|
|
||||||||
|
|
Allows retrieving the actual value of those fields that were |
||||||||
|
|
automatic. |
|
|
|
|
|
|
||
DDS_Boolean |
replace_auto |
When this field is set to true, the fields that were configured |
||||||||
with |
an |
automatic |
value |
(for |
example, |
|||||
|
|
|||||||||
|
|
DDS_AUTO_SAMPLE_IDENTITY in identity) receive their |
||||||||
|
|
actual value after write_w_params is called. |
|
|
|
|||||
|
|
|
||||||||
|
|
Identity of the sample being written. The identity consists of a |
||||||||
|
|
pair (Virtual Writer GUID, Virtual Sequence Number). |
|
|
||||||
|
|
When the value DDS_AUTO_SAMPLE_IDENTITY is used, the |
||||||||
|
|
write_w_params() operation will determine the sample iden- |
||||||||
|
|
tity as follows: |
|
|
|
|
|
|||
|
|
• The Virtual Writer GUID (writer_guid) is the virtual |
||||||||
|
|
|
GUID associated with the DataWriter writing the sam- |
|||||||
|
|
|
ple. This virtual GUID is configured using the member |
|||||||
|
|
|
virtual_guid in DATA_WRITER_PROTOCOL_STATUS |
|||||||
DDS_ |
identity |
|
|
|
|
|
|
|||
• The Virtual Sequence Number (sequence_number) is |
||||||||||
SampleIdentity_t |
||||||||||
|
||||||||||
|
|
|
increased by one with respect to the previous value. |
|
||||||
|
|
The virtual sequence numbers for a given virtual GUID must be |
||||||||
|
|
strictly monotonically increasing. If you try to write a sample |
||||||||
|
|
with a sequence number smaller or equal to the last sequence |
||||||||
|
|
number, the write operation will fail. |
|
|
|
|||||
|
|
A DataReader can inspect the identity of a received sample by |
||||||||
|
|
accessing the fields original_publication_virtual_guid and |
||||||||
|
|
original_publication_virtual_sequence_number in The Sam- |
||||||||
|
|
|
|
|
|
|||||
|
|
|
|
|
||||||
|
|
The identity of another sample related to this one. |
|
|
||||||
|
|
The value of this field identifies another sample that is logically |
||||||||
|
|
related to the one that is written. |
|
|
|
|
||||
|
|
For example, the DataWriter created by a Replier (sets |
||||||||
|
|
|||||||||
|
|
Pattern) uses this field to associate the identity of the request |
||||||||
DDS_ |
related_sample_ |
sample to reponse sample. |
|
|
|
|
||||
SampleIdentity_t |
identity |
To specify that there is no related sample identity use the value |
||||||||
|
|
DDS_UNKNOWN_SAMPLE_IDENTITY, |
|
|
|
|||||
|
|
A DataReader can inspect the related sample identity of a |
||||||||
|
|
received |
sample |
by |
accessing |
the |
fields |
|||
|
|
related_original_publication_virtual_guid |
|
|
and |
|||||
|
|
related_original_publication_virtual_sequence_number |
in |
|||||||
|
|
|
|
|
||||||
|
|
|
||||||||
|
|
Source timestamp that will be associated to the sample that is |
||||||||
|
|
written. |
|
|
|
|
|
|
||
|
|
If source_timestamp is set to DDS_TIMER_INVALID, the mid- |
||||||||
DDS_Time |
source_timestamp |
dleware will assign the value. |
|
|
|
|
||||
|
|
A DataReader can inspect the source_timestamp value of a |
||||||||
|
|
received sample by accessing the field source_timestamp |
||||||||
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DataWriters |
|
|
Table 6.15 DDS_WriteParams_t |
|
|
|
|
|
|
||
|
|
|
|
|
|
|
||
|
Type |
Field Name |
|
Description |
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DDS_ |
|
The instance handle. |
|
|
|
|
|
|
handle |
This value can be either the handle returned by a previous call |
|
|||||
|
InstanceHandle_t |
|
||||||
|
|
|
to register_instance or the special value DDS_HANDLE_NIL. |
|
||||
|
|
|
Positive integer designating the relative priority of the sample, |
|
||||
|
|
|
used to determine the transmission order of pending transmis- |
|
||||
|
|
|
sions. |
|
|
|
|
|
|
|
|
To use publication priorities, the DataWriter’s PUBLISH_MODE |
|
||||
|
|
|
QosPolicy (DDS Extension) (Section 6.5.18) must be set for |
|
||||
|
|
|
asynchronous publishing and the DataWriter must use a |
|
||||
|
DDS_Long |
priority |
FlowController |
with |
a |
first |
|
|
|
|
|
scheduling_policy. |
|
|
|
|
|
|
|
|
For |
|
||||
|
|
|
a sample may be used as a filter criteria for determining |
|
||||
|
|
|
channel membership. |
|
|
|
|
|
|
|
|
For additional information in Priority Samples see Prioritized |
|
||||
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
The write() operation also asserts liveliness on the DataWriter, the associated Publisher, and the associated DomainParticipant. It has the same effect with regards to liveliness as an explicit call to assert_liveliness(), see Section 6.3.17 and the LIVELINESS QosPolicy (Section 6.5.13). Maintain- ing liveliness is important for DataReaders to know that the DataWriter still exists and for the proper behavior of the OWNERSHIP QosPolicy (Section 6.5.15).
See also: Clock Selection (Section 8.6).
6.3.8.1Blocking During a write()
The write() operation may block if the RELIABILITY QosPolicy (Section 6.5.19) kind is set to Reliable and the modification would cause data to be lost or cause one of the limits specified in the RESOURCE_LIMITS QosPolicy (Section 6.5.20) to be exceeded. Specifically, write() may block in the following situations (note that the list may not be exhaustive), even if its HISTORY QosPolicy (Section 6.5.10) is KEEP_LAST:
❏If max_samples1 < max_instances, then the DataWriter may block regardless of the depth field in the HISTORY QosPolicy (Section 6.5.10).
❏If max_samples < (max_instances * depth), then in the situation where the max_samples resource limit is exhausted, Connext may discard samples of some other instance, as long as at least one sample remains for such an instance. If it is still not possible to make space available to store the modification, the writer is allowed to block.
❏If min_send_window_size < max_samples), then it is possible for the send_window_size limit to be reached before Connext is allowed to discard samples, in which case the DataWriter will block.
This operation may also block when using BEST_EFFORT Reliability (Section 6.5.20) and ASYN- CHRONOUS Publish Mode (Section 6.5.18) QoS settings. In this case, the DataWriter will queue samples until they are sent by the asynchronous publishing thread. The number of samples that can be stored is determined by the HISTORY QosPolicy (Section 6.5.10). If the asynchronous thread does not send samples fast enough (such as when using a slow FlowController (Section 6.6)), the queue may fill up. In that case, subsequent write calls will block.
1. max_samples in is DDS_ResourceLimitsQosPolicy
DataWriters
If this operation does block for any of the above reasons, the RELIABILITY max_blocking_time configures the maximum time the write operation may block (waiting for space to become avail- able). If max_blocking_time elapses before the DataWriter can store the modification without exceeding the limits, the operation will fail and return RETCODE_TIMEOUT.
6.3.9Flushing Batches of Data Samples
The flush() operation makes a batch of data samples available to be sent on the network.
DDS_ReturnCode_t flush ()
If the DataWriter’s PUBLISH_MODE QosPolicy (DDS Extension) (Section 6.5.18) kind is not ASYNCHRONOUS, the batch will be sent on the network immediately in the context of the call- ing thread.
If the DataWriter’s PublishModeQosPolicy kind is ASYNCHRONOUS, the batch will be sent in the context of the asynchronous publishing thread.
The flush() operation may block based on the conditions described in Blocking During a write() (Section 6.3.8.1).
If this operation does block, the max_blocking_time in the RELIABILITY QosPolicy (Section 6.5.19) configures the maximum time the write operation may block (waiting for space to become available). If max_blocking_time elapses before the DataWriter is able to store the mod- ification without exceeding the limits, the operation will fail and return TIMEOUT.
For more information on batching, see the BATCH QosPolicy (DDS Extension) (Section 6.5.2).
6.3.10Writing Coherent Sets of Data Samples
A publishing application can request that a set of
This is useful in cases where the values are
To use this mechanism:
1.Call the Publisher’s begin_coherent_changes() operation to indicate the start a coherent set.
2.For each sample in the coherent set: call the FooDataWriter’s write() operation.
3.Call the Publisher’s end_coherent_changes() operation to terminate the set.
Calls to begin_coherent_changes() and end_coherent_changes() can be nested.
See also: the coherent_access field in the PRESENTATION QosPolicy (Section 6.4.6).
6.3.11Waiting for Acknowledgments in a DataWriter
The DataWriter’s wait_for_acknowledgments() operation blocks the calling thread until either all data written by the reliable DataWriter is acknowledged by (a) all reliable DataReaders that are matched and alive and (b) by all required subscriptions (see Required Subscriptions (Section 6.3.13)), or until the duration specified by the max_wait parameter elapses, whichever happens first.
DataWriters
Note that if a thread is blocked in the call to wait_for_acknowledgments() on a DataWriter and a different thread writes new samples on the same DataWriter, the new samples must be acknowl- edged before unblocking the thread waiting on wait_for_acknowledgments().
DDS_ReturnCode_t wait_for_acknowledgments (
const DDS_Duration_t & max_wait)
This operation returns DDS_RETCODE_OK if all the samples were acknowledged, or
DDS_RETCODE_TIMEOUT if the max_wait duration expired first.
If the DataWriter does not have its RELIABILITY QosPolicy (Section 6.5.19) kind set to RELI- ABLE, the operation will immediately return DDS_RETCODE_OK.
There is a similar operation available at the Publisher level, see Waiting for Acknowledgments in a Publisher (Section 6.2.7).
The reliability protocol used by Connext is discussed in Chapter 10: Reliable Communications. The application acknowledgment mechanism is discussed in Application Acknowledgment (Section 6.3.12) and Chapter 13: Guaranteed Delivery of Data.
6.3.12Application Acknowledgment
The RELIABILITY QosPolicy (Section 6.5.19) determines whether or not data published by a DataWriter will be reliably delivered by Connext to matching DataReaders. The reliability protocol used by Connext is discussed in Chapter 10: Reliable Communications.
With
The mechanism to let a DataWriter know to keep the sample around, not just until it has been acknowledged by the reliability protocol, but until the application has been able to process the sample is aptly called Application Acknowledgment. A reliable DataWriter will keep the samples until the application acknowledges the samples. When the subscriber application is restarted, the middleware will know that the application did not acknowledge successfully processing the samples and will resend them.
6.3.12.1Application Acknowledgment Kinds
Connext supports three kinds of application acknowledgment, which is configured in the RELI- ABILITY QosPolicy (Section 6.5.19)):
1.DDS_PROTOCOL_ACKNOWLEDGMENT_MODE (Default): In essence, this mode is identical to using no
2.DDS_APPLICATION_AUTO_ACKNOWLEDGMENT_MODE: Samples are automati- cally acknowledged by the middleware after the subscribing application accesses them, either through calling take() or read() on the sample. The samples are acknowledged after return_loan() is called.
DataWriters
3.DDS_APPLICATION_EXPLICIT_ACKNOWLEDGMENT_MODE: Samples are acknowledged after the subscribing application explicitly calls acknowledge on the sam- ple. This can be done by either calling the DataReader’s acknowledge_sample() or acknowledge_all() operations. When using acknowledge_sample(), the application will provide the DDS_SampleInfo to identify the sample being acknowledge. When using acknowledge_all, all the samples that have been read or taken by the reader will be acknowledged.
Note: Even in DDS_APPLICATION_EXPLICIT_ACKNOWLEDGMENT_MODE, some samples may be automatically acknowledged. This is the case when samples are filtered out by the reader using
6.3.12.2Explicitly Acknowledging a Single Sample (C++)
void MyReaderListener::on_data_available(DDSDataReader *reader)
{
Foo sample; DDS_SampleInfo info;
FooDataReader* fooReader = FooDataReader::narrow(reader); DDS_ReturnCode_t retcode =
if (info.valid_data) { // Process sample
..
retcode =
// Error
}
}
}else {
//Not OK or NO DATA
}
6.3.12.3Explicitly Acknowledging All Samples (C++)
void MyReaderListener::on_data_available(DDSDataReader *reader)
{
...
// Loop while samples available for(;;) {
retcode =
// No more samples break;
}
// Process sample
...
}
retcode =
// Error
}
}
DataWriters
6.3.12.4Notification of Delivery with Application Acknowledgment
A DataWriter can use the wait_for_acknowledgments() operation to be notified when all the samples in the DataWriter’s queue have been acknowledged. See Waiting for Acknowledgments in a DataWriter (Section 6.3.11).
retCode =
// Error
}
retcode =
if (retCode != DDS_RETCODE_TIMEOUT) {
//Timeout: Sample not acknowledged yet
}else {
//Error
}
}
Connext does not provide a way to get delivery notifications on a per DataReader and sample basis. If your application requires acknowledgment of message receipt, use the Request/Reply communication pattern with an Acknowledgment type (see Chapter 22: Introduction to the
6.3.12.5
When the subscribing application confirms it has successfully processed a sample, an AppAck RTPS message is sent to the publishing application. This message will be resent until the pub- lishing application confirms receipt of the AppAck message by sending an AppAckConf RTPS message. See Figures 6.10 through 6.12.
Figure 6.10 AppAck RTPS Messages Sent when Application Acknowledges a Sample
DataWriters
Figure 6.11 AppAck RTPS Messages Resent Until Acknowledged Through AppAckConf RTPS Message
Figure 6.12 AppAck RTPS Messages Sent as a Sequence of Intervals, Combined to Optimize for Bandwidth
6.3.12.6Periodic and
You can configure whether AppAck RTPS messages are sent immediately or periodically through the DATA_READER_PROTOCOL QosPolicy (DDS Extension) (Section 7.6.1 on page 7- 52). The samples_per_app_ack (in Table 7.20, “DDS_RtpsReliableReaderProtocol_t,” on page 7- 54) determines the minimum number of samples acknowledged by one
DataWriters
Acknowledgment message. The middleware will not send an AppAck message until it has at least this many samples pending acknowledgment. By default, samples_per_app_ack is 1 and the AppAck RTPS message is sent immediately. Independently, the app_ack_period (in Table 7.20, “DDS_RtpsReliableReaderProtocol_t,” on page
6.3.12.7Application Acknowledgment and Persistence Service
Application Acknowledgment is fully supported by RTI Persistence Service. The combination of Application Acknowledgment and Persistence Service is actually a common configuration. In addition to keeping samples available until fully acknowledged, Persistence Service, when used in
Figure 6.13 Application Acknowledgment and Persistence Service
|
|
A single AppAck notifies both |
|
|
|
the original DataWriter and |
|
|
|
Persistence Service. |
|
AppAck |
|
AppAck |
|
DataWriter |
Global |
DataReader |
|
Dataspace |
|||
|
|
||
|
|
AppAck |
Persistence Service
Samples acknowledged to the Original DataWriter are not sent by the Persistence service.
6.3.12.8Application Acknowledgment and Routing Service
Application Acknowledgment is supported by RTI Routing Service: That is, Routing Service will acknowledge the sample it has processed. Routing Service is an active participant in the Connext system and not transparent to the publisher or subscriber. As such, Routing Service will acknowl- edge to the publisher, and the subscriber will acknowledge to Routing Service. However, the pub- lisher will not get a notification from the subscriber directly.
6.3.13Required Subscriptions
The DURABILITY QosPolicy (Section 6.5.7) specifies whether acknowledged samples need to be kept in the DataWriter’s queue and made available to
DataWriters
There are scenarios where you know a priori that a particular set of applications will join the system: e.g., a logging service or a known processing application. The Required Subscription fea- ture is designed to keep data until these known late joining applications acknowledge the data.
Another use case is when DataReaders become temporarily inactive due to not responding to heartbeats, or when the subscriber temporarily became disconnected and purged from the dis- covery database. In both cases, the DataWriter will no longer keep the sample for this DataReader. The Required Subscription feature will keep the data until these known DataReaders have acknowledged the data.
To use Required Subscriptions, the DataReaders and DataWriters must have their RELIABILITY QosPolicy (Section 6.5.19) kind set to RELIABLE.
6.3.13.1Named, Required and Durable Subscriptions
Before describing the Required Subscriptions, it is important to understand a few concepts:
❏Named Subscription: Through the ENTITY_NAME QosPolicy (DDS Extension) (Section 6.5.9), each DataReader can be given a specific name. This name can be used by tools to identify a specific DataReader. Additionally, the DataReader can be given a role_name. For example: LOG_APP_1 DataReader belongs to the logger applications (role_name = “LOGGER”).
❏Required Subscription is a named subscription to which a DataWriter is configured to deliver data to. This is true even if the DataReaders serving those subscriptions are not available yet. The DataWriter must store the sample until it has been acknowledged by all active reliable DataReaders and acknowledged by all required subscriptions. The DataW- riter is not waiting for a specific DataReader, rather it is waiting for DataReaders belonging to the required subscription by setting their role_name to the subscription name.
❏Durable Subscription is a required subscription where samples are stored and for- warded by an external service. In this case, the required subscription is served by RTI Persistence Service. See Configuring Durable Subscriptions in Persistence Service (Section 27.9).
6.3.13.2Durability QoS and Required Subscriptions
The DURABILITY QosPolicy (Section 6.5.7) and the Required Subscriptions feature complement each other.
The DurabilityQosPolicy determines whether or not Connext will store and deliver previously acknowledged samples to new DataReaders that join the network later. You can specify to either not make the samples available (DDS_VOLATILE_DURABILITY_QOS kind), or to make them available and declare you are storing the samples in memory (DDS_TRANSIENT_LOCAL_DURABILITY_QOS or DDS_TRANSIENT_DURABILITY_QOS kind) or in permanent storage (DDS_PERSISTENT_DURABILITY_QOS).
Required subscriptions help answer the question of when a sample is considered acknowledged before the DurabilityQosPolicy determines whether to keep it. When required subscriptions are used, a sample is considered acknowledged by a DataWriter when both the active DataReaders and a quorum of required subscriptions have acknowledged the sample. (Acknowledging a sample can be done either at the protocol or application
6.3.13.3Required Subscriptions Configuration
Each DataReader can be configured to be part of a named subscription, by giving it a role_name using the ENTITY_NAME QosPolicy (DDS Extension) (Section 6.5.9). A DataWriter can then be configured using the AVAILABILITY QosPolicy (DDS Extension) (Section 6.5.1)
DataWriters
(required_matched_endpoint_groups) with a list of required named subscriptions identified by the role_name. Additionally, the DataWriter can be configured with a quorum or minimum num- ber of DataReaders from a given named subscription that must receive a sample.
When configured with a list of required subscriptions, a DataWriter will store a sample until the sample is acknowledged by all active reliable DataReaders, as well as all required subscriptions. When a quorum is specified, a minimum number of DataReaders of the required subscription must acknowledge a sample in order for the sample to be considered acknowledged. Specifying a quorum provides a level of redundancy in the system as multiple applications or services acknowledge they have received the sample. Each individual DataReader is identified using its own virtual GUID (see DATA_READER_PROTOCOL QosPolicy (DDS Extension) (Section 7.6.1)).
6.3.14Managing Data Instances (Working with Keyed Data Types)
This section applies only to data types that use keys, see Samples, Instances, and Keys (Section 2.2.2). Using the following operations for
Topics come in two flavors: those whose associated data type has specified some fields as defin- ing the ‘key,’ and those whose associated data type has not. An example of a
Figure 6.14 Data Type with a Key
typedef struct Flight { long flightId; //@key string departureAirport; string arrivalAirport; Time_t departureTime;
Time_t estimatedArrivalTime; Location_t currentPosition;
};
If the data type has some fields that act as a ‘key,’ the Topic essentially defines a collection of
Since the key fields are contained within the data structure, Connext could examine the key fields each time it needs to determine which
The register_instance() operation provides a handle to the instance (of type DDS_InstanceHandle_t) that can be used later to refer to the instance.
6.3.14.1Registering and Unregistering Instances
If your data type has a key, you may improve performance by registering an instance (data asso- ciated with a particular value of the key) before you write data for the instance. You can do this for any number of instances up the maximum number of instances configured in the DataW- riter’s RESOURCE_LIMITS QosPolicy (Section 6.5.20). Instance registration is completely optional.
Registration tells Connext that you are about to modify (write or dispose of) a specific instance. This allows Connext to
DataWriters
If you write without registering, you can pass the NIL instance handle as part of the write() call.
If you register the instance first, Connext can look up the instance beforehand and return a han- dle to that instance. Then when you pass this handle to the write() operation, Connext no longer needs to analyze the data to check what instance it is for. Instead, it can directly update the instance pointed to by the instance handle.
In summary, by registering an instance, all subsequent write() calls to that instance become more efficient. If you only plan to write once to a particular instance, registration does not ‘buy’ you much in performance, but in general, it is good practice.
To register an instance, use the DataWriter’s register_instance() operation. For best performance, it should be invoked prior to calling any operation that modifies the instance, such as write(), write_w_timestamp(), dispose(), or dispose_w_timestamp().
When you are done using that instance, you can unregister it. To unregister an instance, use the DataWriter’s unregister_instance() operation. Unregistering tells Connext that the DataWriter does not intend to modify that
Figure 6.15 Registering an Instance
Flight myFlight;
// writer is a
DDS_InstanceHandle_t fl265Handle =
...
// Each time we update the flight, we can pass the handle
myFlight.departureAirport |
= “SJC”; |
|
myFlight.arrivalAirport |
= “LAX”; |
|
myFlight.departureTime |
= {120000, 0}; |
|
myFlight.estimatedArrivalTime |
= |
{130200, 0}; |
myFlight.currentPosition |
= |
{ {37, 20}, {121, 53} }; |
if
}
...
// Once we are done updating the flight, it can be unregistered if
DDS_RETCODE_OK) { // ... handle error
}
Once an instance has been unregistered, and assuming that no other DataWriters are writing val- ues for the instance, the matched DataReaders will eventually get an indication that the instance no longer has any DataWriters. This is communicated to the DataReaders by means of the DDS_SampleInfo that accompanies each
DataWriters
The unregister_instance() operation may affect the ownership of the data instance (see the OWNERSHIP QosPolicy (Section 6.5.15)). If the DataWriter was the exclusive owner of the instance, then calling unregister_instance() relinquishes that ownership, and another DataW- riter can become the exclusive owner of the instance.
The unregister_instance() operation indicates only that a particular DataWriter no longer has anything to say about the instance.
Note that this is different than the dispose() operation discussed in the next section, which informs DataReaders that the
6.3.14.2Disposing of Data
The dispose() operation informs DataReaders that, as far as the DataWriter knows, the data- instance no longer exists and can be considered “not alive.” When the dispose() operation is called, the instance state stored in the DDS_SampleInfo structure, accessed through DataRead- ers, will change to NOT_ALIVE_DISPOSED for that particular instance.
autodispose_unregistered_instances in the WRITER_DATA_LIFECYCLE QoS Policy (Section 6.5.26) controls whether instances are automatically disposed when they are unregistered.
For example, in a flight tracking system, when a flight lands, a DataWriter may dispose the data- instance corresponding to the flight. In that case, all DataReaders who are monitoring the flight will see the instance state change to NOT_ALIVE_DISPOSED, indicating that the flight has landed.
Note that this is different than unregister_instance() (Section 6.3.14.1), which indicates only that a particular DataWriter no longer wishes to modify an
If a particular instance is never disposed, its instance state will eventually change from ALIVE to NOT_ALIVE_NO_WRITERS once all the DataWriters that were writing that instance unreg- ister the instance or lose their liveliness. For more information on DataWriter liveliness, see the LIVELINESS QosPolicy (Section 6.5.13).
See also: Propagating Serialized Keys with
6.3.14.3Looking Up an Instance Handle
Some operations, such as write(), require an instance_handle parameter. If you need to get such as handle, you can call the FooDataWriter’s lookup_instance() operation, which takes an instance as a parameter and returns a handle to that instance. This is useful for keyed data types.
DDS_InstanceHandle_t lookup_instance (const Foo & key_holder)
The instance must have already been registered (see Section 6.3.14.1). If the instance is not regis- tered, this operation returns DDS_HANDLE_NIL.
6.3.14.4Getting the Key Value for an Instance
Once you have an instance handle (using register_instance() or lookup_instance()), you can use the DataWriter’s get_key_value() operation to retrieve the value of the key of the corresponding instance. The key fields of the data structure passed into get_key_value() will be filled out with the original values used to generate the instance handle. The key fields are defined when the data type is defined, see Samples, Instances, and Keys (Section 2.2.2) for more information.
DataWriters
Following our example in Figure 6.15 on page
DDS_InstanceHandle_t (fl265Handle) that can be used in the call to the FlightDataWriter’s get_key_value() operation. The value of the key is returned in a structure of type Flight with the flightId field filled in with the integer 265.
See also: Propagating Serialized Keys with
6.3.15Setting DataWriter QosPolicies
The DataWriter’s QosPolicies control its resources and behavior.
The DDS_DataWriterQos structure has the following format:
DDS_DataWriterQos struct { |
|
DDS_DurabilityQosPolicy |
durability; |
DDS_DurabilityServiceQosPolicy |
durability_service; |
DDS_DeadlineQosPolicy |
deadline; |
DDS_LatencyBudgetQosPolicy |
latency_budget; |
DDS_LivelinessQosPolicy |
liveliness; |
DDS_ReliabilityQosPolicy |
reliability; |
DDS_DestinationOrderQosPolicy |
destination_order; |
DDS_HistoryQosPolicy |
history; |
DDS_ResourceLimitsQosPolicy |
resource_limits; |
DDS_TransportPriorityQosPolicy |
transport_priority; |
DDS_LifespanQosPolicy |
lifespan; |
DDS_UserDataQosPolicy |
user_data; |
DDS_OwnershipQosPolicy |
ownership; |
DDS_OwnershipStrengthQosPolicy |
ownership_strength; |
DDS_WriterDataLifecycleQosPolicy |
writer_data_lifecycle; |
// extensions to the DDS standard: |
|
DDS_DataWriterResourceLimitsQosPolicy writer_resource_limits; |
|
DDS_DataWriterProtocolQosPolicy |
protocol; |
DDS_TransportSelectionQosPolicy |
transport_selection; |
DDS_TransportUnicastQosPolicy |
unicast; |
DDS_PublishModeQosPolicy |
publish_mode; |
DDS_PropertyQosPolicy |
property; |
DDS_BatchQosPolicy |
batch; |
DDS_MultiChannelQosPolicy |
multi_channel; |
DDS_AvailabilityQosPolicy |
availability; |
DDS_EntityNameQosPolicy |
publication_name; |
DDS_TypeSupportQosPolicy |
type_support; |
} DDS_DataWriterQos; |
|
Note: set_qos() cannot always be used within a listener callback, see Restricted Operations in Listener Callbacks (Section 4.5.1).
Table 6.16 summarizes the meaning of each policy. (They appear alphabetically in the table.) For information on why you would want to change a particular QosPolicy, see the referenced sec- tion. For defaults and valid ranges, please refer to the API Reference HTML documentation.
Many of the DataWriter QosPolicies also apply to DataReaders (see Section 7.3). For a DataWriter to communicate with a DataReader, their QosPolicies must be compatible. Generally, for the QosPolicies that apply both to the DataWriter and the DataReader, the setting in the DataWriter is considered an “offer” and the setting in the DataReader is a “request.” Compatibility means that what is offered by the DataWriter equals or surpasses what is requested by the DataReader. Each policy’s description includes compatibility restrictions. For more information on compatibility, see QoS Requested vs. Offered
DataWriters
Table 6.16 DataWriter QosPolicies
QosPolicy |
Description |
|
|
|
|
|
|
|
|
This QoS policy is used in the context of two features: |
|
|
• Availability QoS Policy and Collaborative DataWriters (Section 6.5.1.1) |
|
|
• Availability QoS Policy and Required Subscriptions (Section 6.5.1.2) |
|
Availability |
For Collaborative DataWriters, Availability specifies the group of DataWrit- |
|
ers expected to collaboratively provide data and the timeouts that control |
||
|
when to allow data to be available that may skip samples. |
|
|
For Required Subscriptions, Availability configures a set of Required Sub- |
|
|
scriptions on a DataWriter. |
|
|
See Section 6.5.1 |
|
|
|
|
|
Specifies and configures the mechanism that allows Connext to collect multi- |
|
Batch |
ple user data samples to be sent in a single network packet, to take advan- |
|
tage of the efficiency of sending larger packets and thus increase effective |
||
|
||
|
throughput. See Section 6.5.2. |
|
|
|
|
DataWriterProtocol |
This QosPolicy configures the Connext |
|
|
||
|
|
|
DataWriterResourceLimits |
Controls how many threads can concurrently block on a write() call of this |
|
DataWriter. See Section 6.5.4. |
||
|
||
|
|
|
|
• For a DataReader, it specifies the maximum expected elapsed time |
|
|
between arriving data samples. |
|
Deadline |
• For a DataWriter, it specifies a commitment to publish samples with no |
|
|
greater elapsed time between them. |
|
|
See Section 6.5.5. |
|
|
|
|
|
Controls how Connext will deal with data sent by multiple DataWriters for |
|
DestinationOrder |
the same topic. Can be set to "by reception timestamp" or to "by source time- |
|
|
stamp". See Section 6.5.6. |
|
|
|
|
Durability |
Specifies whether or not Connext will store and deliver data that were previ- |
|
ously published to new DataReaders. See Section 6.5.7. |
||
|
||
|
|
|
|
Various settings to configure the external Persistence Servicea used by Connext |
|
DurabilityService |
for DataWriters with a Durability QoS setting of Persistent Durability. See |
|
|
||
|
|
|
EntityName |
Assigns a name to a DataWriter. See Section 6.5.9. |
|
|
|
|
|
Specifies how much data must to stored by Connextfor the DataWriter or |
|
History |
DataReader. This QosPolicy affects the RELIABILITY QosPolicy (Section |
|
6.5.19) as well as the DURABILITY QosPolicy (Section 6.5.7). See |
||
|
||
|
||
|
|
|
LatencyBudget |
Suggestion to Connext on how much time is allowed to deliver data. See |
|
|
||
|
|
|
Lifespan |
Specifies how long Connext should consider data sent by an user application |
|
to be valid. See Section 6.5.12. |
||
|
||
|
|
|
Liveliness |
Specifies and configures the mechanism that allows DataReaders to detect |
|
when DataWriters become disconnected or "dead." See Section 6.5.13. |
||
|
||
|
|
|
MultiChannel |
Configures a DataWriter’s ability to send data on different multicast groups |
|
(addresses) based on the value of the data. See Section 6.5.14. |
||
|
||
|
|
|
Ownership |
Along with OwnershipStrength, specifies if DataReaders for a topic can |
|
receive data from multiple DataWriters at the same time. See Section 6.5.15. |
||
|
||
|
|
|
OwnershipStrength |
Used to arbitrate among multiple DataWriters of the same instance of a Topic |
|
when Ownership QosPolicy is EXLUSIVE. See Section 6.5.16. |
||
|
||
|
|
DataWriters
Table 6.16 DataWriter QosPolicies
QosPolicy |
Description |
|
|
|
|
|
|
|
Partition |
Adds string identifiers that are used for matching DataReaders and DataWrit- |
|
ers for the same Topic. See Section 6.4.5. |
||
|
||
|
|
|
|
Stores name/value (string) pairs that can be used to configure certain |
|
|
parameters of Connext that are not exposed through formal QoS policies. It |
|
Property |
can also be used to store and propagate |
|
|
pairs, which can be retrieved by user code during discovery. See |
|
|
||
|
|
|
|
Specifies how Connext sends application data on the network. By default, |
|
PublishMode |
data is sent in the user thread that calls the DataWriter’s write() operation. |
|
However, this QosPolicy can be used to tell Connext to use its own thread to |
||
|
||
|
send the data. See Section 6.5.18. |
|
|
|
|
Reliability |
Specifies whether or not Connext will deliver data reliably. See Section 6.5.19. |
|
|
|
|
|
Controls the amount of physical memory allocated for entities, if dynamic |
|
ResourceLimits |
allocations are allowed, and how they occur. Also controls memory usage |
|
|
among different instance values for keyed topics. See Section 6.5.20. |
|
|
|
|
TransportPriority |
Set by a DataWriter to tell Connext that the data being sent is a different "pri- |
|
ority" than other data. See Section 6.5.21. |
||
|
||
|
|
|
TransportSelection |
Allows you to select which physical transports a DataWriter or DataReader |
|
may use to send or receive its data. See Section 6.5.22. |
||
|
||
|
|
|
TransportUnicast |
Specifies a subset of transports and port number that can be used by an |
|
Entity to receive data. See Section 6.5.23. |
||
|
||
|
|
|
|
Used to attach |
|
TypeSupport |
These values are passed to the serialization or deserialization routine of the |
|
|
associated data type. See Section 6.5.24. |
|
|
|
|
UserData |
Along with Topic Data QosPolicy and Group Data QosPolicy, used to attach |
|
a buffer of bytes to Connext's discovery |
||
|
||
|
|
|
WriterDataLifeCycle |
Controls how a DataWriter handles the lifecycle of the instances (keys) that |
|
the DataWriter is registered to manage. See Section 6.5.26. |
||
|
||
|
|
a. Persistence Service is included with Connext Messaging.
Some of the policies may be changed after the DataWriter has been created. This allows the application to modify the behavior of the DataWriter while it is in use. To modify the QoS of an
ageneral pattern for all Entities, described in Section 4.1.7.3.
6.3.15.1Configuring QoS Settings when the DataWriter is Created
As described in Creating DataWriters (Section 6.3.1), there are different ways to create a DataW- riter, depending on how you want to specify its QoS (with or without a QoS Profile).
❏In Figure 6.9 on page
DataWriters
❏To create a DataWriter with
❏You can also create a DataWriter and specify its QoS settings via a QoS Profile. To do so, you will call create_datawriter_with_profile(), as seen in Figure 6.17 on page
❏If you want to use a QoS profile, but then make some changes to the QoS before creating the DataWriter, call get_datawriter_qos_from_profile() and create_datawriter() as seen in Figure 6.18 on page
For more information, see Creating DataWriters (Section 6.3.1) and Chapter 17: Configuring QoS with XML.
Figure 6.16 Creating a DataWriter with Modified QosPolicies (not from a profile)
DDS_DataWriterQos writer_qos;1
//initialize writer_qos with default values
//make QoS changes
writer_qos.history.depth = 5;
// Create the writer with modified qos
DDSDataWriter * writer = publisher->create_datawriter( topic, writer_qos,
NULL, DDS_STATUS_MASK_NONE);
if (writer == NULL) { // ... error
}
// narrow it for your specific data type
FooDataWriter* foo_writer = FooDataWriter::narrow(writer);
1. Note: In C, you must initialize the QoS structures before they are used, see Section 4.2.2.
Figure 6.17 Creating a DataWriter with a QoS Profile
// Create the datawriter DDSDataWriter * writer =
publisher->create_datawriter_with_profile( topic,
“MyWriterLibrary”,
“MyWriterProfile”,
NULL, DDS_STATUS_MASK_NONE);
if (writer == NULL) { // ... error
};
// narrow it for your specific data type
FooDataWriter* foo_writer = FooDataWriter::narrow(writer);
DataWriters
Figure 6.18 Getting QoS Values from a Profile, Changing QoS Values, Creating a DataWriter with Modified QoS Values
DDS_DataWriterQos writer_qos;1
// Get writer QoS from profile
retcode = factory->get_datawriter_qos_from_profile( writer_qos, “WriterProfileLibrary”, “WriterProfile”);
if (retcode != DDS_RETCODE_OK) { // handle error
}
// Makes QoS changes writer_qos.history.depth = 5;
DDSDataWriter * writer = publisher->create_datawriter( topic, writer_qos,
NULL, DDS_STATUS_MASK_NONE);
if (participant == NULL) { // handle error
}
1. Note: In C, you must initialize the QoS structures before they are used, see Section 4.2.2.
DataWriters
6.3.15.2Changing QoS Settings After the DataWriter Has Been Created
There are 2 ways to change an existing DataWriter’s QoS after it is has been
❏To change QoS programmatically (that is, without using a QoS Profile), use get_qos() and set_qos(). See the example code in Figure 6.19. It retrieves the current values by call- ing the DataWriter’s get_qos() operation. Then it modifies the value and calls set_qos() to apply the new value. Note, however, that some QosPolicies cannot be changed after the DataWriter has been
❏You can also change a DataWriter’s (and all other Entities’) QoS by using a QoS Profile and calling set_qos_with_profile(). For an example, see Figure 6.20. For more informa- tion, see Chapter 17: Configuring QoS with XML.
Figure 6.19 Changing the QoS of an Existing DataWriter (without a QoS Profile)
DDS_DataWriterQos writer_qos;1
// Get current QoS.
if
}
//Makes QoS changes here writer_qos.history.depth = 5;
//Set the new QoS
if
}
1. For the C API, you need to use DDS_ParticipantQos_INITIALIZER or DDS_ParticipantQos_initialize(). See Section 4.2.2
Figure 6.20 Changing the QoS of an Existing DataWriter with a QoS Profile
retcode = writer->set_qos_with_profile( “WriterProfileLibrary”,”WriterProfile”);
if (retcode != DDS_RETCODE_OK) { // handle error
}
DataWriters
6.3.15.3Using a Topic’s QoS to Initialize a DataWriter’s QoS
Several DataWriter QosPolicies can also be found in the QosPolicies for Topics (see Section 5.1.3). The QosPolicies set in the Topic do not directly affect the DataWriters (or DataReaders) that use that Topic. In many ways, some QosPolicies are a
There are many ways to use the QosPolicies’ values set in the Topic when setting the QosPolicies’ values in a DataWriter. The most straightforward way is to get the values of policies directly from the Topic and use them in the policies for the DataWriter, as shown in Figure 6.21.
Figure 6.21 Copying Selected QoS from a Topic when Creating a DataWriter
DDS_DataWriterQos writer_qos;1
DDS_TopicQos topic_qos;
//topic and publisher already created
//get current QoS for the topic, default QoS for the writer if
// handle error
}
if
}
//Copy specific policies from the topic QoS to the writer QoS writer_qos.deadline = topic_qos.deadline; writer_qos.reliability = topic_qos.reliability;
//Create the DataWriter with the modified QoS
DDSDataWriter* writer =
1. Note in C, you must initialize the QoS structures before they are used, see Section 4.2.2.
DataWriters
You can use the Publisher’s copy_from_topic_qos() operation to copy all of the common policies from the Topic QoS to a DataWriter QoS. This is illustrated in Figure 6.22.
Figure 6.22 Copying all QoS from a Topic when Creating a DataWriter
DDS_DataWriterQos writer_qos;1 DDS_TopicQos topic_qos;
// topic, publisher, writer_listener already created
if
}
if
{
// handle error
}
//copy relevant QosPolicies from topic’s qos into writer’s qos
//Optionally, modify policies as desired
writer_qos.deadline.duration.sec = 1; writer_qos.deadline.duration.nanosec = 0;
// Create the DataWriter with the modified QoS DDSDataWriter* writer =
writer_qos, writer_listener, DDS_STATUS_MASK_ALL);
1. Note in C, you must initialize the QoS structures before they are used, see Section 4.2.2.
In another design pattern, you may want to start with the default QoS values for a DataWriter and override them with the QoS values of the Topic. Figure 6.23 gives an example of how to do this.
Because this is a common pattern, Connext provides a special macro,
DDS_DATAWRITER_QOS_USE_TOPIC_QOS, that can be used to indicate that the DataW- riter should be created with the set of QoS values that results from modifying the default DataW- riter QosPolicies with the QoS values specified by the Topic. Figure 6.24 shows how the macro is used.
DataWriters
The code fragments shown in Figure 6.23 and Figure 6.24 result in identical QoS settings for the created DataWriter.
Figure 6.23 Combining Default Topic and DataWriter QoS (Option 1)
DDS_DataWriterQos writer_qos;1 DDS_TopicQos topic_qos;
// topic, publisher, writer_listener already created
if
}
if
}
if
// handle error
}
// Create the DataWriter with the combined QoS
DDSDataWriter* writer =
1. Note in C, you must initialize the QoS structures before they are used, see Section 4.2.2.
Figure 6.24 Combining Default Topic and DataWriter QoS (Option 2)
// topic, publisher, writer_listener already created
DDSDataWriter* writer =
For more information on the general use and manipulation of QosPolicies, see Section 4.1.7.
6.3.16Navigating Relationships Among Entities
6.3.16.1Finding Matching Subscriptions
The following DataWriter operations can be used to get information on the DataReaders that are currently associated with the DataWriter (that is, the DataReaders to which Connext will send the data written by the DataWriter).
❏get_matched_subscriptions()
❏get_matched_subscription_data()
❏get_matched_subscription_locators()
get_matched_subscriptions() will return a sequence of handles to matched DataReaders. You can use these handles in the get_matched_subscription_data() method to get information about the DataReader such as the values of its QosPolicies.
get_matched_subscription_locators() retrieves a list of locators for subscriptions currently "associated" with the DataWriter. Matched subscription locators include locators for all those subscriptions in the same domain that have a matching Topic, compatible QoS, and a common partition that the DomainParticipant has not indicated should be "ignored." These are the locators
DataWriters
that Connext uses to communicate with matching DataReaders. (See Locator Format (Section 14.2.1.1).)
You can also get the DATA_WRITER_PROTOCOL_STATUS for matching subscriptions with these operations (see Section 6.3.6.2):
❏get_matched_subscription_datawriter_protocol_status()
❏get_matched_subscription_datawriter_protocol_status_by_locator()
Notes:
❏Status/data for a matched subscription is only kept while the matched subscription is alive. Once a matched subscription is no longer alive, its status is deleted. If you try to get the status/data for a matched subscription that is no longer alive, the 'get status' or ' get data' call will return an error.
❏DataReaders that have been ignored using the DomainParticipant’s ignore_subscription() operation are not considered to be matched even if the DataReader has the same Topic and compatible QosPolicies. Thus, they will not be included in the list of DataReaders returned by get_matched_subscriptions() or get_matched_subscription_locators(). See Section 16.4.2 for more on ignore_subscription().
❏The get_matched_subscription_data() operation does not retrieve the following infor- mation from
6.3.16.2Finding Related Entities
These operations are useful for obtaining a handle to various related entities:
❏get_publisher()
❏get_topic()
get_publisher() returns the Publisher that created the DataWriter. get_topic() returns the Topic with which the DataWriter is associated.
6.3.17Asserting Liveliness
The assert_liveliness() operation can be used to manually assert the liveliness of the DataWriter without writing data. This operation is only useful if the kind of LIVELINESS QosPolicy (Sec- tion 6.5.13) is MANUAL_BY_PARTICIPANT or MANUAL_BY_TOPIC.
How DataReaders determine if DataWriters are alive is configured using the LIVELINESS QosPolicy (Section 6.5.13). The lease_duration parameter of the LIVELINESS QosPolicy is a contract by the DataWriter to all of its matched DataReaders that it will send a packet within the time value of the lease_duration to state that it is still alive.
There are three ways to assert liveliness. One is to have Connext itself send liveliness packets periodically when the kind of LIVELINESS QosPolicy is set to AUTOMATIC. The other two ways to assert liveliness, used when liveliness is set to MANUAL, are to call write() to send data or to call the assert_liveliness() operation without sending data.
Publisher/Subscriber QosPolicies
6.4Publisher/Subscriber QosPolicies
This section provides detailed information on the QosPolicies associated with a Publisher. Note that Subscribers have the exact same set of policies. Table 6.2 on page
❏ASYNCHRONOUS_PUBLISHER QosPolicy (DDS Extension) (Section 6.4.1)
❏ENTITYFACTORY QosPolicy (Section 6.4.2)
❏EXCLUSIVE_AREA QosPolicy (DDS Extension) (Section 6.4.3)
❏GROUP_DATA QosPolicy (Section 6.4.4)
❏PARTITION QosPolicy (Section 6.4.5)
❏PRESENTATION QosPolicy (Section 6.4.6)
6.4.1ASYNCHRONOUS_PUBLISHER QosPolicy (DDS Extension)
This QosPolicy is used to enable or disable asynchronous publishing and asynchronous batch flushing for the Publisher.
This QosPolicy can be used to reduce amount of time spent in the user thread to send data. You can use it to send large data reliably. Large in this context means that the data cannot be sent as a single packet by a transport. For example, to send data larger than 63K reliably using UDP/IP, you must configure Connext to send the data using asynchronous Publishers.
If so configured, the Publisher will spawn two threads, one for asynchronous publishing and one for asynchronous batch flushing. The asynchronous publisher thread will be shared by all DataWriters (belonging to this Publisher) that have their PUBLISH_MODE QosPolicy (DDS Extension) (Section 6.5.18) kind set to ASYNCHRONOUS. The asynchronous publishing thread will then handle the data transmission chores for those DataWriters. This thread will only be spawned when the first of these DataWriters is enabled.
The asynchronous batch flushing thread will be shared by all DataWriters (belonging to this Pub- lisher) that have batching enabled and max_flush_delay different than DURATION_INFINITE in BATCH QosPolicy (DDS Extension) (Section 6.5.2). This thread will only be spawned when the first of these DataWriters is enabled.
This QosPolicy allows you to adjust the asynchronous publishing and asynchronous batch flushing threads independently.
Batching and asynchronous publication are independent of one another. Flushing a batch on an asynchronous DataWriter makes it available for sending to the DataWriter's FlowControllers (DDS Extension) (Section 6.6). From the point of view of the FlowController, a batch is treated like one large sample.
Connext will sometimes coalesce multiple samples into a single network datagram. For example, samples buffered by a FlowController or sent in response to a negative acknowledgement (NACK) may be coalesced. This behavior is distinct from sample batching. Data samples sent by different asynchronous DataWriters belonging to the same Publisher to the same destination will not be coalesced into a single network packet. Instead, two separate network packets will be sent. Only samples written by the same DataWriter and intended for the same destination will be coalesced.
This QosPolicy includes the members in Table 6.17.
|
|
|
Publisher/Subscriber QosPolicies |
Table 6.17 DDS_AsynchronousPublisherQosPolicy |
|
||
|
|
|
|
|
Type |
Field Name |
Description |
|
|
|
|
|
|
|
|
|
|
|
Disables asynchronous publishing. To write |
|
DDS_Boolean |
disable_asynchronous_write |
asynchronously, this field must be FALSE |
|
|
|
(the default). |
|
|
|
|
|
DDS_ThreadSettings_t |
thread |
Settings for the publishing thread. These set- |
|
tings are |
||
|
|
|
|
|
|
|
|
|
|
|
Disables asynchronous batch flushing. To flush |
|
DDS_Boolean |
disable_asynchronous_batch |
asynchronously, this field must be FALSE (the |
|
|
|
default). |
|
|
|
|
|
|
|
Settings for the asynchronous batch flushing |
|
DDS_ThreadSettings_t |
asynchronous_batch_thread |
thread. |
|
|
|
These settings are |
|
|
|
|
6.4.1.1Properties
This QosPolicy cannot be modified after the Publisher is created.
Since it is only for Publishers, there are no compatibility restrictions for how it is set on the pub- lishing and subscribing sides.
6.4.1.2Related QosPolicies
❏If disable_asynchronous_write is TRUE (not the default), then any DataWriters created from this Publisher must have their PUBLISH_MODE QosPolicy (DDS Extension) (Sec- tion 6.5.18) kind set to SYNCHRONOUS. (Otherwise create_datawriter() will return INCONSISTENT_QOS.)
❏If disable_asynchronous_batch is TRUE (not the default), then any DataWriters created from this Publisher must have max_flush_delay in BATCH QosPolicy (DDS Extension) (Section 6.5.2) set to DURATION_INFINITE. (Otherwise create_datawriter() will return INCONSISTENT_QOS.)
❏DataWriters configured to use the MULTI_CHANNEL QosPolicy (DDS Extension) (Sec- tion 6.5.14) do not support asynchronous publishing; an error is returned if a
6.4.1.3Applicable Entities
6.4.1.4System Resource Considerations
Two threads can potentially be created.
For asynchronous publishing, system resource usage depends on the activity of the asynchro- nous thread controlled by the FlowController (see FlowControllers (DDS Extension) (Section 6.6)).
For asynchronous batch flushing, system resource usage depends on the activity of the asyn- chronous thread controlled by max_flush_delay in BATCH QosPolicy (DDS Extension) (Section 6.5.2).
Publisher/Subscriber QosPolicies
6.4.2ENTITYFACTORY QosPolicy
This QosPolicy controls whether or not child entities are created in the enabled state.
This QosPolicy applies to the DomainParticipantFactory, DomainParticipants, Publishers, and Sub- scribers, which act as ‘factories’ for the creation of subordinate entities. A DomainParticipantFac- tory is used to create DomainParticipants. A DomainParticipant is used to create both Publishers and Subscribers. A Publisher is used to create DataWriters, similarly a Subscriber is used to create
DataReaders.
Entities can be created either in an ‘enabled’ or ‘disabled’ state. An enabled entity can actively participate in communication. A disabled entity cannot be discovered or take part in communi- cation until it is explicitly enabled. For example, Connext will not send data if the write() opera- tion is called on a disabled DataWriter, nor will Connext deliver data to a disabled DataReader. You can only enable a disabled entity. Once an entity is enabled, you cannot disable it, see Section 4.1.2 about the enable() method.
The ENTITYFACTORY contains only one member, as illustrated in Table 6.18.
Table 6.18 DDS_EntityFactoryQosPolicy
Type |
Field Name |
Description |
|
|
|
|
|
DDS_BOOLEAN_TRUE: enable entities when they are cre- |
DDS_Boolean |
autoenable_created_entities |
ated |
DDS_BOOLEAN_FALSE: do not enable entities when they |
||
|
|
are created |
|
|
|
The ENTITYFACTORY QosPolicy controls whether the entities created from the factory are automatically enabled upon creation or are left disabled. For example, if a Publisher is config- ured to
Note: if an entity is disabled, then all of the child entities it creates are also created in a disabled state, regardless of the setting of this QosPolicy. However, enabling a disabled entity will enable all of its children if this QosPolicy is set to autoenable child entities.
Note: an entity can only be enabled; it cannot be disabled after its been enabled.
See Section 6.4.2.1 for an example of how to set this policy.
There are various reasons why you may want to create entities in the disabled state:
❏To get around a “chicken and
For example, if you create a DomainParticipant in the enabled state, it will immediately start sending packets to other nodes trying to discover if other Connext applications exist. However, you may want to configure the
❏You may want to create entities without having them automatically start to work. This especially pertains to DataReaders. If you create a DataReader in an enabled state and you are using DataReaderListeners, Connext will immediately search for matching DataWriters and callback the listener as soon as data is published. This may not be what you want to happen if your application is still in the middle of initialization when data arrives.
Publisher/Subscriber QosPolicies
So typically, you would create all entities in a disabled state, and then when all parts of the application have been initialized, one would enable all entities at the same time using the enable() operation on the DomainParticipant, see Section 4.1.2.
❏An entity’s existence is not advertised to other participants in the network until the entity is enabled. Instead of sending an individual declaration packet to other applications announcing the existence of the entity, Connext can be more efficient in bundling multiple declarations into a single packet when you enable all entities at the same time.
See Section 4.1.2 for more information about enabled/disabled entities.
6.4.2.1Example
The code in Figure 6.25 illustrates how to use the ENTITYFACTORY QoS.
Figure 6.25 Configuring a Publisher so that New DataWriters are Disabled
DDS_PublisherQos publisher_qos;1
// topic, publisher, writer_listener already created
if
}
publisher_qos.entity_factory.autoenable_created_entities = DDS_BOOLEAN_FALSE;
if
}
//Subsequently created DataWriters are created disabled and
//must be explicitly enabled by the
DDS_DATAWRITER_QOS_DEFAULT, writer_listener, DDS_STATUS_MASK_ALL);
... // now do other initialization
//Now explicitly enable the DataWriter, this will allow other
//applications to discover the DataWriter and for this application
//to send data when the DataWriter’s write() method is called
1.Note in C, you must initialize the QoS structures before they are used, see Section 4.2.2.
6.4.2.2Properties
This QosPolicy can be modified at any time.
It can be set differently on the publishing and subscribing sides.
6.4.2.3Related QosPolicies
This QosPolicy does not interact with any other policies.
6.4.2.4Applicable Entities
Publisher/Subscriber QosPolicies
❏DomainParticipants (Section 8.3)
6.4.2.5System Resource Considerations
This QosPolicy does not significantly impact the use of system resources.
6.4.3EXCLUSIVE_AREA QosPolicy (DDS Extension)
This QosPolicy controls the creation and use of Exclusive Areas. An exclusive area (EA) is a mutex with
EAs allow Connext to be
Within an EA, all calls to the code protected by the EA are single threaded. Each DomainPartici- pant, Publisher and Subscriber represents a separate EA. All DataWriters of the same Publisher and all DataReaders of the same Subscriber share the EA of its parent. This means that the DataWriters of the same Publisher and the DataReaders of the same Subscriber are inherently single threaded.
Within an EA, there are limitations on how code protected by a different EA can be accessed. For example, when data is being processed by user code received in the DataReaderListener of a Subscriber EA, the user code may call the write() function of a DataWriter that is protected by the EA of its Publisher. So you can send data in the function called to process received data. How- ever, you cannot create entities or call functions that are protected by the EA of the DomainPartic- ipant. See Exclusive Areas (EAs) (Section 4.5) for the complete documentation on Exclusive Areas.
With this QoS, you can force a Publisher or Subscriber to share the same EA as its DomainPartici- pant. Using this capability, the restriction of not being to create entities in a DataReaderListener's on_data_available() callback is lifted. However, the
Note that the restrictions on calling methods in a different EA only exists for user code that is called in registered Listeners by internal DomainParticipant threads. User code may call all Con- next functions for any Entities from their own threads at any time.
The EXCLUSIVE_AREA includes a single member, as listed in Table 6.19. For the default value, please refer to the API Reference HTML documentation.
Table 6.19 DDS_ExclusiveAreaQosPolicy
Type |
Field Name |
Description |
|
|
|
|
|
|
|
|
|
|
|
DDS_BOOLEAN_FALSE: |
|
DDS_Boolean |
use_shared_exclusive_area |
subordinates will not use the same EA |
|
DDS_BOOLEAN_TRUE: |
|||
|
|
||
|
|
subordinates will use the same EA |
|
|
|
|
The implications and restrictions of using a private or shared EA are discussed in Section 4.5. The basic
Behavior when the Publisher or Subscriber’s use_shared_exclusive_area is set to FALSE:
Publisher/Subscriber QosPolicies
❏The creation of the Publisher/Subscriber will create an EA that will be used only by the
Publisher/Subscriber and the DataWriters/DataReaders that belong to them.
❏Consequences: This setting maximizes concurrency at the expense of creating a mutex for the Publisher or Subscriber. In addition, using a separate EA may restrict certain Con- next operations (see Operations Allowed within Listener Callbacks (Section 4.4.5)) from being called from the callbacks of Listeners attached to those entities and the entities that they create. This limitation results from a
Behavior when the Publisher or Subscriber’s use_shared_exclusive_area is set to TRUE:
❏The creation of the Publisher/Subscriber does not create a new EA. Instead, the Publisher/ Subscriber, along with the DataWriters/DataReaders that they create, will use a common EA shared with the DomainParticipant.
❏Consequences: By sharing the same EA among multiple entities, you may decrease the amount of concurrency in the application, which can adversely impact performance. However, this setting does use less resources and allows you to call almost any operation on any Entity within a listener callback (see Exclusive Areas (EAs) (Section 4.5) for full details).
6.4.3.1Example
The code in Figure 6.26 illustrates how to change the EXCLUSIVE_AREA policy.
Figure 6.26 Creating a Publisher with a Shared Exclusive Area
DDS_PublisherQos publisher_qos;1
// domain, publisher_listener have been previously created if
DDS_RETCODE_OK) {
// handle error
}
publisher_qos.exclusive_area.use_shared_exclusive_area = DDS_BOOLEAN_TRUE;
DDSPublisher* publisher =
1.Note in C, you must initialize the QoS structures before they are used, see Section 4.2.2.
6.4.3.2Properties
This QosPolicy cannot be modified after the Entity has been created. It can be set differently on the publishing and subscribing sides.
6.4.3.3Related QosPolicies
This QosPolicy does not interact with any other policies.
6.4.3.4Applicable Entities
Publisher/Subscriber QosPolicies
6.4.3.5System Resource Considerations
This QosPolicy affects the use of
6.4.4GROUP_DATA QosPolicy
This QosPolicy provides an area where your application can store additional information related to the Publisher and Subscriber. This information is passed between applications during discov- ery (see Chapter 14: Discovery) using
Use cases are often
The value of the GROUP_DATA QosPolicy is sent to remote applications when they are first dis- covered, as well as when the Publisher or Subscriber’s set_qos() method is called after changing the value of the GROUP_DATA. User code can set listeners on the
Currently, GROUP_DATA of the associated Publisher or Subscriber is only propagated with the information that declares a DataWriter or DataReader. Thus, you will need to access the value of GROUP_DATA through DDS_PublicationBuiltinTopicData or DDS_SubscriptionBuiltinTopicData (see Chapter 16:
The structure for the GROUP_DATA QosPolicy includes just one field, as seen in Table 6.20. The field is a sequence of octets that translates to a contiguous buffer of bytes whose contents and length is set by the user. The maximum size for the data are set in the DOMAIN_PARTICIPANT_RESOURCE_LIMITS QosPolicy (DDS Extension) (Section 8.5.4).
Table 6.20 DDS_GroupDataQosPolicy
Type |
Field Name |
Description |
|
|
|
|
|
|
DDS_OctetSeq |
value |
Empty by default |
|
|
|
This policy is similar to the USER_DATA QosPolicy (Section 6.5.25) and TOPIC_DATA QosPol- icy (Section 5.2.1) that apply to other types of Entities.
6.4.4.1Example
One possible use of GROUP_DATA is to pass some credential or certificate that your subscriber application can use to accept or reject communication with the DataWriters that belong to the Publisher (or vice versa, where the publisher application can validate the permission of DataReaders of a Subscriber to receive its data). The value of the GROUP_DATA of the Publisher is propagated in the ‘group_data’ field of the DDS_PublicationBuiltinTopicData that is sent with the declaration of each DataWriter. Similarly, the value of the GROUP_DATA of the Subscriber is propagated in the ‘group_data’ field of the DDS_SubscriptionBuiltinTopicData that is sent with the declaration of each DataReader.
When Connext discovers a DataWriter/DataReader, the application can be notified of the discov- ery of the new entity and retrieve information about the DataWriter/DataReader QoS by reading the DCPSPublication or DCPSSubscription
Publisher/Subscriber QosPolicies
whether or not the DataWriter/DataReader should be allowed to communicate with local DataReaders/DataWriters. If communication is not allowed, the application can use the Domain- Participant’s ignore_publication() or ignore_subscription() operation to reject the newly discov- ered remote entity as one with which the application allows Connext to communicate. See Figure 16.2, “Ignoring Publications,” on page
The code in Figure 6.27 illustrates how to change the GROUP_DATA policy.
Figure 6.27 Creating a Publisher with GROUP_DATA
DDS_PublisherQos publisher_qos;1 int i = 0;
//Bytes that will be used for the group data. In this case 8 bytes
//of some information that is meaningful to the user application char myGroupData[GROUP_DATA_SIZE] =
{ 0x34, 0xaa, 0xfe, 0x31, 0x7a, 0xf2, 0x34, 0xaa};
//assume that domainparticipant and publisher_listener
//are already created
if
// handle error
}
// Must set the size of the sequence first publisher_qos.group_data.value.maximum(GROUP_DATA_SIZE); publisher_qos.group_data.value.length(GROUP_DATA_SIZE);
for (i = 0; i < GROUP_DATA_SIZE; i++) { publisher_qos.group_data.value[i] = myGroupData[i]
}
DDSPublisher* publisher = participant->create_publisher( publisher_qos, publisher_listener, DDS_STATUS_MASK_ALL);
1.Note in C, you must initialize the QoS structures before they are used, see Section 4.2.2.
6.4.4.2Properties
This QosPolicy can be modified at any time.
It can be set differently on the publishing and subscribing sides.
6.4.4.3Related QosPolicies
❏TOPIC_DATA QosPolicy (Section 5.2.1)
❏USER_DATA QosPolicy (Section 6.5.25)
❏DOMAIN_PARTICIPANT_RESOURCE_LIMITS QosPolicy (DDS Extension) (Section 8.5.4)
6.4.4.4Applicable Entities
Publisher/Subscriber QosPolicies
6.4.4.5System Resource Considerations
As mentioned earlier, the maximum size of the GROUP_DATA is set in the publisher_group_data_max_length and subscriber_group_data_max_length fields of the DOMAIN_PARTICIPANT_RESOURCE_LIMITS QosPolicy (DDS Extension) (Section 8.5.4). Because Connext will allocate memory based on this value, you should only increase this value if you need to. If your system does not use GROUP_DATA, then you can set this value to zero to save memory. Setting the value of the GROUP_DATA QosPolicy to hold data longer than the value set in the [publisher/subscriber]_group_data_max_length fields will result in failure and an INCONSISTENT_QOS_POLICY return code.
However, should you decide to change the maximum size of GROUP_DATA, you must make certain that all applications in the domain have changed the value of [publisher/sub- scriber]_group_data_max_length to be the same. If two applications have different limits on the size of GROUP DATA, and one application sets the GROUP_DATA QosPolicy to hold data that is greater than the maximum size set by another application, then the matching DataWriters and DataReaders of the Publisher and Subscriber between the two applications will not connect. This is also true for the TOPIC_DATA (Section 5.2.1) and USER_DATA (Section 6.5.25) QosPolicies.
6.4.5PARTITION QosPolicy
The PARTITION QoS provides another way to control which DataWriters will
The PARTITION QoS applies to Publishers and Subscribers, therefore the DataWriters and DataReaders belong to the partitions as set on the Publishers and Subscribers that created them. The mechanism implementing the PARTITION QoS is relatively lightweight, and membership in a partition can be dynamically changed. Unlike the creation and destruction of DomainPartici- pants, there is no spawning and killing of threads or allocation and deallocation of memory when Publishers and Subscribers add or remove themselves from partitions.
The PARTITION QoS consists of a set of partition names that identify the partitions of which the Entity is a member. These names are simply strings, and DataWriters and DataReaders are consid- ered to be in the same partition if they have more than one partition name in common in the PARTITION QoS set on their Publishers or Subscribers.
Conceptually each partition name can be thought of as defining a “visibility plane” within the domain. DataWriters will make their data available on all the visibility planes that correspond to its Publisher’s partition names, and the DataReaders will see the data that is placed on any of the visibility planes that correspond to its Subscriber’s partition names.
Figure 6.28 illustrates the concept of PARTITION QoS. In this figure, all DataWriters and DataReaders belong to the same domain and refer to the same Topic. DataWriter1 is configured to belong to three partitions: partition_A, partition_B, and partition_C. DataWriter2 belongs to partition_C and partition_D.
Similarly, DataReader1 is configured to belong to partition_A and partition_B, and DataReader2 belongs only to partition_C. Given this topology, the data written by DataWriter1 is visible in partitions A, B, and C. The oval tagged with the number “1” represents one
Similarly, the data written by DataWriter2 is visible in partitions C and D. The oval tagged with the number “2” represents one
Publisher/Subscriber QosPolicies
Figure 6.28 Controlling Visibility of Data with the PARTITION QoS
The result is that the data written by DataWriter1 will be received by both DataReader1 and DataReader2, but the data written by DataWriter2 will only be visible by DataReader2.
Publishers and Subscribers always belong to a partition. By default, Publishers and Subscribers belong to a single partition whose name is the empty string, ““. If you set the PARTITION QoS to be an empty set, Connext will assign the Publisher or Subscriber to the default partition, ““. Thus, for the example above, without using the PARTITION QoS, DataReaders 1 and 2 would have received all data samples written by DataWriters 1 and 2.
6.4.5.1Rules for PARTITION Matching
On the Publisher side, the PARTITION QosPolicy associates a set of strings (partition names) with the Publisher. On the Subscriber side, the application also uses the PARTITION QoS to asso- ciate partition names with the Subscriber.
Taking into account the PARTITION QoS, a DataWriter will communicate with a DataReader if and only if the following conditions apply:
1.The DataWriter and DataReader belong to the same domain. That is, their respective DomainParticipants are bound to the same domain ID (see Section 8.3.1).
2.The DataWriter and DataReader have matching Topics. That is, each is associated with a Topic with the same topic_name and data type.
3.The QoS offered by the DataWriter is compatible with the QoS requested by the
DataReader.
4.The application has not used the ignore_participant(), ignore_datareader(), or ignore_datawriter() APIs to prevent the association (see Section 16.4).
5.The Publisher to which the DataWriter belongs and the Subscriber to which the DataReader belongs must have at least one matching partition name.
The last condition reflects the visibility of the data introduced by the PARTITION QoS. Match- ing partition names is done by string comparison, thus partition names are case sensitive.
Publisher/Subscriber QosPolicies
NOTE: Failure to match partitions is not considered an incompatible QoS and does not trigger any listeners or change any status conditions.
6.4.5.2Pattern Matching for PARTITION Names
You may also add strings that are regular expressions1 to the PARTITION QosPolicy. A regular expression does not define a set of partitions to which the Publisher or Subscriber belongs, as much as it is used in the partition matching process to see if a remote entity has a partition name that would be matched with the regular expression. That is, the regular expressions in the PAR- TITION QoS of a Publisher are never matched against those found in the PARTITION QoS of a Subscriber. Regular expressions are always matched against “concrete” partition names. Thus, a concrete partition name may not contain any reserved characters that are used to define regular expressions, for example ‘*’, ‘.’, ‘+’, etc.
If a PARTITION QoS only contains regular expressions, then the Publisher or Subscriber will be assigned automatically to the default partition with the empty string name (““). Thus, do not be fooled into thinking that a PARTITION QoS that only contains the string “*” matches another PARTITION QoS that only contains the string “*”. Yes, the Publisher will match the Subscriber, but it is because they both belong to the default ““ partition.
DataWriters and DataReaders are considered to have a partition in common if the sets of parti- tions that their associated Publishers and Subscribers have defined have:
❏at least one concrete partition name in common
❏a regular expression in one Entity that matches a concrete partition name in another Entity
The programmatic representation of the PARTITION QoS is shown in Table 6.21. The QosPolicy contains the single string sequence, name. Each element in the sequence can be a concrete name or a regular expression. The Entity will be assigned to the default ““ partition if the sequence is empty.
Table 6.21 DDS_PartitionQosPolicy
Type |
Field Name |
Description |
|
|
|
|
|
|
|
|
Empty by default. |
DDS_StringSeq |
name |
There can be up to 64 names, with a maximum of 256 characters |
|
|
summed across all names. |
|
|
|
You can have one long partition string of 256 chars, or multiple shorter strings that add up to 256 or less characters. For example, you can have one string of 4 chars and one string of 252 chars.
6.4.5.3Example
Since the set of partitions for a Publisher or Subscriber can be dynamically changed, the Partition QosPolicy is useful to control which DataWriters can send data to which DataReaders and vice
Note when using Partitions and Durability: If a Publisher changes partitions after startup, it is possible for a reliable,
1.As defined by the POSIX fnmatch API
Part 3: Advanced Concepts
This part of the manual will guide you through some of the more advanced concepts:
❏Chapter 10: Reliable Communications
❏Chapter 11: Collaborative DataWriters
❏Chapter 12: Mechanisms for Achieving Information Durability and Persistence
❏Chapter 13: Guaranteed Delivery of Data
❏Chapter 15: Transport Plugins
❏Chapter 17: Configuring QoS with XML
❏Chapter 18:
❏Chapter 19: Connext Threading Model
Part 4:
Important! The Request/Reply communication pattern is only available with RTI Connext Mes- saging.
As
❏Chapter 22: Introduction to the
Part 5: RTI Secure WAN Transport
The material in this part of the manual is only relevant if you have installed Secure WAN Trans- port.
This feature is not part of the standard Connext package; it must be downloaded and installed separately. It is only available on specific architectures. See the Secure WAN Transport Release Notes and Installation Guide for details.
Secure WAN Transport is an optional package that enables participant discovery and data exchange in a secure manner over the public WAN. Secure WAN Transport enables Connext to address the challenges in NAT traversal and authentication of all participants. By implementing UDP hole punching using the STUN protocol and providing security to channels by leveraging DTLS (Datagram TLS), you can securely exchange information between different sites separated by firewalls.
Part 6: RTI Persistence Service
The material in this part of the manual describes Persistence Service, which is included with Con- next Messaging. It saves data samples so they can be delivered to subscribing applications that join the system at a later
❏Chapter 26: Introduction to RTI Persistence Service
❏Chapter 27: Configuring Persistence Service
❏Chapter 28: Running RTI Persistence Service
❏Chapter 29: Administering Persistence Service from a Remote Location
Part 7: RTI CORBA Compatibility Kit
The material in this part of the manual is only relevant if you have purchased the CORBA Com- patibility Kit, an optional package that allows Connext’s code generator, rtiddsgen, to output type- specific code that is compatible with OCI’s distribution of TAO and the JacORB distribution.
❏Chapter 31: Introduction to RTI CORBA Compatibility Kit
❏Chapter 32: Generating
Part 8: RTI RTSJ Extension Kit
The material in this part of the manual is only relevant if you have purchased RTI RTSJ Extension Kit, an optional package that allows you to configure Connext applications to use
Part 9: RTI TCP Transport
RTI TCP Transport is only available on specific architectures. See the Platform Notes for details.
Out of the box, Connext uses the UDPv4 and Shared Memory transport to communicate with other DDS applications. This configuration is appropriate for systems running within a single LAN. However, using UDPv4 introduces some problems when Connext applications in different LANs need to communicate:
❏UDPv4 traffic is usually filtered out by the LAN firewalls for security reasons.
❏Forwarded ports are usually TCP ports.
❏Each LAN may run in its own private IP address space and use NAT (Network Address Translation) to communicate with other networks.
TCP Transport enables participant discovery and data exchange using the TCP protocol (either on a local LAN, or over the public WAN). TCP Transport allows Connext to address the chal- lenges of using TCP as a
This part of the User’s Manual contains the following chapter: