Typesupport
The TypeSupport is a crucial component in DDS which provides an interface for handling data types in a standardized way. It is responsible for managing the serialization, deserialization, and type-specific operations for user-defined data types in a DDS system.
In this sense, the TypeSupport ensures the seamless exchange of data between DataReader and DataWriter by providing a common data representation.
A Safe DDS type support is any class that implements dds::TypeSupport, that allows registering the type support within the DDS system and handle the type key identifier.
Data representation
For the purpose of achieving interoperability with other DDS vendors, it is necessary that the implementation of any Safe DDS TypeSupport adheres to a commonly accepted serialization and deserialization format known as CDR (Common Data Representation). To facilitate CDR-compliant serialization and deserialization functionality, the following classes are provided:
To set and decode the type of data representation used, the following structure is provided:
By leveraging these classes, the Safe DDS TypeSupport implementation ensures compatibility with other DDS vendors, promoting effective communication and data exchange across various DDS systems.
Registering a type
For a DDS TypeSupport to be utilized effectively, it is necessary to register it within a the application DomainParticipant. Once this registration process is completed, it is possible to leverage the safety-typed APIs offered by TypedDataReader and TypedDataWriter.
In order to register a dds::TypeSupport interface into a dds::DomainParticipant, the TypeSupport::register_type method shall be used.
// Register the type
CustomTypeSupport type_support{};
type_support.register_type(*participant, type_name);
Safe DDS Gen
Safe DDS Gen is a Java application that generates application code to support type handling when using Safe DDS from data types defined in an IDL (Interface Definition Language) file. It does so by generating code which leverages Safe DDS APIs. This generated source code can be used in any Safe DDS application in order to define the data type of a topic, which will later be used to publish or subscribe. Please refer to Typesupport for more information on data types.
To declare the structured data, the IDL format must be used. IDL is a specification language, made by OMG (Object Management Group), which describes an interface in a language independent manner, allowing communication between software components that do not share the same language. The Safe DDS Gen tool reads the IDL files and parses a subset of the OMG IDL specification to generate source code for data serialization, this subset is detailed in the Supported IDL types section.
Safe DDS Gen generated source code uses provided CDR serialization implementations detailed on Data representation. Therefore, as stated in the RTPS standard, when the data are sent, the serialization is performed using the corresponding Common Data Representation (CDR).
The main feature of Safe DDS Gen is to facilitate the implementation of DDS applications without the knowledge of serialization or deserialization mechanisms.
For installing Safe DDS Gen, please refer to Installation.
HelloWorld TypeSupport
For reference, this documentation provides a simple example of a TypeSupport implementation for the HelloWorld data type used in the getting started section:
// Data Type used by HelloWorldTypeSupport
struct HelloWorld
{
uint32_t index;
uint32_t message_size;
char message[255];
};
// TypeSupport for HelloWorld
class HelloWorldTypeSupport :
public dds::TypedTypeSupport<HelloWorld>
{
public:
// Definition of internal data type
using DataType = HelloWorld;
// Implementation of dds::TypedTypeSupport
dds::ReturnCode register_type(
dds::DomainParticipant& participant,
const memory::IStringView& type_name) noexcept override
{
return participant.register_type(*this, type_name);
}
const memory::IStringView& get_type_name() const noexcept override
{
static constexpr char const* default_name = "HelloWorldTypeSupport";
static const memory::container::StaticString256 typesupport_name(default_name);
return typesupport_name;
}
bool has_keys() const noexcept override
{
return false;
}
uint32_t max_serialized_size() const noexcept override
{
return
sizeof(serialization::RepresentationHeader) +
sizeof(HelloWorld::index) +
sizeof(HelloWorld::message_size) +
sizeof(HelloWorld::message);
}
uint32_t serialized_size(
const DataType& sample,
serialization::cdr::XCDRVersion /* xcdr_version */) const noexcept override
{
return
sizeof(serialization::RepresentationHeader) +
sizeof(HelloWorld::index) +
sizeof(HelloWorld::message_size) +
sample.message_size;
}
safedds::ReturnCode serialize(
const DataType& sample,
memory::IByteArrayView& buffer,
serialization::cdr::XCDRVersion xcdr_version) const noexcept override
{
// Do not serialize if size is bigger than buffer capacity
if (buffer.size() < serialized_size(sample, xcdr_version))
{
return safedds::ReturnCode::SERIALIZATION_INVALID_BUFFER_LENGTH;
}
/***************************************************
* RETURN CODE SAFETY CHECKS ARE OMITTED FOR CLARITY
***************************************************/
// Create a CDR serializer on the provided buffer
serialization::cdr::Serializer ser(buffer, portable::MACHINE_ENDIANNESS,
serialization::cdr::XCDRVersion::XCDRV1);
// Serialize a RepresentationHeader
serialization::RepresentationHeader representation_header{};
representation_header.init_as_cdr();
ser.serialize_array(
representation_header.encapsulation_kind.data(),
serialization::RepresentationHeader::ENCAPSULATION_KIND_SIZE);
ser.serialize_array(
representation_header.encapsulation_options.data(),
serialization::RepresentationHeader::ENCAPSULATION_OPTIONS_SIZE);
// Serialize the data type
ser.serialize(sample.index);
ser.serialize(sample.message_size);
ser.serialize_array(sample.message, sample.message_size);
return safedds::ReturnCode::OK;
}
safedds::ReturnCode deserialize(
const memory::IConstByteArrayView& buffer,
DataType& sample) const noexcept override
{
/***************************************************
* RETURN CODE SAFETY CHECKS ARE OMITTED FOR CLARITY
***************************************************/
// Create a CDR deserializer for the representation header on native endianness
serialization::cdr::Deserializer representation_header_deser(buffer, portable::MACHINE_ENDIANNESS,
serialization::cdr::XCDRVersion::XCDRV1);
// Deserialize RepresentationHeader
serialization::RepresentationHeader representation_header{};
protocol::rtps::RTPSTypeSupport::deserialize(
representation_header_deser,
representation_header);
// Retrieve the payload buffer
memory::byte_array::ByteArrayView payload_view = {nullptr, 0U};
representation_header_deser.deserializer_skip(
representation_header_deser.deserializer_remaining_size(),
payload_view);
// Create a deserializer for the payload
serialization::cdr::Deserializer deserializer(
payload_view,
representation_header.get_endianness(),
serialization::cdr::XCDRVersion::XCDRV1);
// Deserialize the data type
deserializer.deserialize(sample.index);
deserializer.deserialize(sample.message_size);
deserializer.deserialize_array(sample.message, sample.message_size);
return safedds::ReturnCode::OK;
}
dds::ReturnCode get_key(
const DataType& /* data */,
dds::KeyHash& key_hash) const noexcept override
{
key_hash = dds::KeyHash{};
return dds::ReturnCode::ILLEGAL_OPERATION;
}
dds::ReturnCode get_key_from_payload(
const memory::IConstByteArrayView& /* view */,
const protocol::PayloadKind& /* kind */,
dds::KeyHash& key_hash) const noexcept override
{
key_hash = dds::KeyHash{};
return dds::ReturnCode::ILLEGAL_OPERATION;
}
};