4.2. Data Types¶
How data is stored or laid out in memory can vary from language to language, compiler to compiler, operating system to operating system, and processor to processor. This combination of language/compiler/operating system/processor is called a platform. Any modern middleware must be able to take data from one specific platform (for example, C/gcc.7.3.0/Linux®/PPC) and transparently deliver it to another (for example, C/gcc.7.3.0/Linux/Arm® v8). This process is commonly called serialization/deserialization, or marshalling/demarshalling.
Connext Micro data samples sent on the same Connext Micro topic share a data type. This type defines the fields that exist in the DDS data samples and what their constituent types are. The middleware stores and propagates this meta-information separately from the individual DDS data samples, allowing it to propagate DDS samples efficiently while handling byte ordering and alignment issues for you.
To publish and/or subscribe to data with Connext Micro, you will carry out the following steps:
Select a type to describe your data and use the RTI Code Generator to define a type at compile-time using a language-independent description language.
The RTI Code Generator accepts input in the following formats:
OMG IDL. This format is a standardized component of the DDS specification. It describes data types with a C++-like syntax. A link to the latest specification can be found here: https://www.omg.org/spec/IDL.
XML in a DDS-specific format. This XML format is terser, and therefore easier to read and write by hand, than an XSD file. It offers the general benefits of XML-extensibility and ease of integration, while fully supporting DDS-specific data types and concepts. A link to the latest specification, including a description of the XML format, can be found here: https://www.omg.org/spec/DDS-XTypes/.
XSD format. You can describe data types with XML schemas (XSD). A link to the latest specification, including a description of the XSD format, can be found here: https://www.omg.org/spec/DDS-XTypes/.
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.
Register your type with a logical name.
Create a Topic using the type name you previously registered.
If you’ve chosen to use a built-in type instead of defining your own, you will use the API constant corresponding to that type’s name.
Create one or more DataWriters to publish your data and one or more DataReaders to subscribe 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.
Whether publishing or subscribing to data, you will need to know how to create and delete (only in Connext Micro DDS data samples and how to get and set their fields. These tasks are described in Working with DDS Data Samples in the Core Libraries User’s Manual if you have Internet access).
4.2.1. Introduction to the Type System¶
A user data type is any custom type that your application defines for use with RTI Connext Micro. 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 Micro; 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 string and wstring
The following type-building constructs are also supported:
module (also called a package or namespace)
pointer
array of primitive or user type elements
bounded sequence of elements—a sequence is a variable-length ordered collection, such as a vector or list
typedef
union
struct
value type, a complex type that supports inheritance and other object-oriented features
To use a data type with Connext Micro, you must define that type in a way the middleware understands and then register the type with the middleware. These steps allow Connext Micro to serialize, deserialize, and otherwise operate on specific types. They will be described in detail in the following sections.
4.2.1.1. Sequences¶
A sequence contains an ordered collection of elements that are all of the same type. The operations supported in the sequence are documented in the C API Reference and C++ API Reference HTML documentation.
Elements in a sequence are accessed with their index, just like elements in an array. Indices start at zero in all APIs. Unlike arrays, however, sequences can grow in size. A sequence has two sizes associated 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 must be declared as bounded. A sequence’s “bound” is the maximum C API Reference The bound is either excplict or implicit:
An explicit bound is given directly in the IDL:
struct MyType { //Maximum of 32 longs sequence<32> a_long_seq; }
An implicit bound uses the unbounded notation in IDL, but relies on the -sequenceSize parameter passed to rtiddsgen for the maximum length:
struct MyType { sequence<long> a_long_seq; }
By default, any unbounded sequences found in an IDL file will be given a default bound of 100 elements. This default value can be overwritten using RTI Code Generator‘s -sequenceSize command-line argument (see Command-Line Arguments for rtiddsgen in the RTI Code Generator User’s Manual, available if you have Internet access).
4.2.1.2. Strings and Wide Strings¶
Connext Micro supports both strings consisting of single-byte characters (the IDL string type) and strings consisting of wide characters (IDL wstring). The wide characters supported by Connext Micro are large enough to store 4-byte Unicode/UTF16 characters.
Like sequences, strings must be bounded. A string’s “bound” is its maximum length (not counting the trailing NULL character in C and C++).
In C and Traditional C++, strings are mapped to char*.
The bound is either excplict or implicit:
An explicit bound is given directly in the IDL:
struct MyType { //Maximum of 32 bytes + NUL termination string<32> a_string; }
An implicit bound uses the unbounded notation in IDL, but relies on the -stringSize parameter passed to rtiddsgen for the maximum length:
struct MyType { // Unbounded notation, but not unbounded. Bound determined // by the -stringSize parameter to rtiddsgen string a_string; }
By default, any unbounded string found in an IDL file will be given a default bound of 255 elements. This default value can be overwritten using RTI Code Generator‘s -stringSize command-line argument (see the Command-Line Arguments chapter in the RTI Code Generator User’s Manual, available here if you have Internet access).
4.2.1.2.1. IDL String Encoding¶
The “Extensible and Dynamic Topic Types for DDS specification” (https://www.omg.org/spec/DDS-XTypes/) standardizes the default encoding for strings to UTF-8. This encoding shall be used as the wire format. Language bindings may use the representation that is most natural in that particular language. If this representation is different from UTF-8, the language binding shall manage the transformation to/from the UTF-8 wire representation.
As an extension, Connext Micro offers ISO_8859_1 as an alternative string wire encoding.
This section describes the encoding for IDL strings across different languages in Connext Micro and how to configure that encoding.
C, Traditional C++ (only in Connext Micro)
IDL strings are mapped to a NULL-terminated array of DDS_Char_ (char*). Users are responsible for using the right character encoding (UTF-8 or ISO_8859_1) when populating the string values. This applies to all generated code, DynamicData, and Built-in data types. The middleware does not transform from the language binding encoding to the wire encoding.
4.2.1.2.2. IDL Wide Strings Encoding¶
The “Extensible and Dynamic Topic Types for DDS specification” (https://www.omg.org/spec/DDS-XTypes/) standardizes the default encoding for wide strings to UTF-32. This encoding shall be used as the wire format.
Wide-string characters have a size of 4 bytes on the wire with UTF-32 encoding.
Language bindings may use the representation that is most natural in that particular language. If this representation is different from UTF-32, the language binding shall manage the transformation to/from the UTF-32 wire representation.
C, Traditional C++
IDL wide strings are mapped to a NULL-terminated array of DDS_Wchar (DDS_Wchar*). DDS_WChar is an unsigned 4-byte integer. Users are responsible for using the right character encoding (UTF-32) when populating the wide-string values. This applies to all generated code, DynamicData, and Built-in data types. Connext Micro does not transform from the language binding encoding to the wire encoding.
4.2.1.2.3. Sending Type Information on the Network¶
Connext Micro can send type information the network using a concept called type objects. A type objects is a description of a type suitable to network transmission, and is commonly used by for example tools to visualize data from any application.
However, please note that Connext Micro does not support sending type information on the network. Instead, tools can load type information from XML files generated from IDL using rtiddsgen. Please refer to the RTI Code Generator’s User’s Manual for more information (available here if you have Internet access).
4.2.2. Creating User Data Types with IDL¶
You can create user data types in a text file using IDL (Interface Description Language). IDL is programming-language independent, so the same file can be used to generate code in C and Traditional C++ (only Connext Micro). RTI Code Generator parses the IDL file and automatically generates all the necessary routines and wrapper functions to bind the types for use by Connext Micro at run time. You will end up with a set of required routines and structures that your application and Connext Micro will use to manipulate the data.
Please refer to Creating User Data Types with IDL in the Core Libraries User’s Manual (if you have Internet access) for more information.
Note: Not all features in RTI Code Generator are supported when generating code for Connext Micro, see Unsupported Features of rtiddsgen with Connext Micro.
4.2.3. Working with DDS Data Samples¶
You should now understand how to define and work with data types. 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.
In C:
You create and delete your own objects from factories, just as you create Connext Micro objects from factories. In the case of user Please refer to Creating User Data Types with IDL in the Core Libraries User’s Manual (if you have Internet access) for more information.
};
/* In your code: */
MyData* sample = MyDataTypeSupport_create_data();
char* str = sample->myString; /*empty, non-NULL string*/
/* not support in Micro Cert */
MyDataTypeSupport_delete_data(sample);
In Traditional C++:
Without the -constructor option, you create and delete objects using the TypeSupport factories.
MyData* sample = MyDataTypeSupport::create_data();
char* str = sample->myString; // empty, non-NULL string
// ...
MyDataTypeSupport::delete_data(sample);
Please refer to Working with DDS Data Samples in the Core Libraries User’s Manual for more information.