DynamicData Serialization

Following method allows to serialize and deserialize data of arbitrary type (type definition must be known) and store it's representation. It can be useful in many scenarios, e.g:

  • save sample to file for a later use.
  • forward data received via DDS to an application with no access to DDS network

TypeCode Serialization is already covered in following example: http://community.rti.com/filedepot?cid=5&fid=28

To serialize and deserialize DDS_DynamicData you have to specify type definition via type code. Type code can be either generated with rtiddsgen or created manually

DDS_TypeCode *createTypeCode()
{
    DDS_TypeCodeFactory * factory = NULL;
    DDS_TypeCode * structTc = NULL;
    DDS_ExceptionCode_t ex = DDS_NO_EXCEPTION_CODE;
    DDS_StructMemberSeq structMembers;
    factory = DDS_TypeCodeFactory::get_instance();

    structTc = factory->create_struct_tc("test_type", structMembers, ex);
    structTc->add_member("bool_1", DDS_TYPECODE_MEMBER_ID_INVALID, factory->get_primitive_tc(DDS_TK_BOOLEAN),
                    DDS_TYPECODE_NONKEY_REQUIRED_MEMBER, ex);
    structTc->add_member("bool_2", DDS_TYPECODE_MEMBER_ID_INVALID, factory->get_primitive_tc(DDS_TK_BOOLEAN),
                    DDS_TYPECODE_NONKEY_REQUIRED_MEMBER, ex);
    structTc->add_member("bool_3", DDS_TYPECODE_MEMBER_ID_INVALID, factory->get_primitive_tc(DDS_TK_BOOLEAN),
                    DDS_TYPECODE_NONKEY_REQUIRED_MEMBER, ex);
    structTc->add_member("double_1", DDS_TYPECODE_MEMBER_ID_INVALID, factory->get_primitive_tc(DDS_TK_DOUBLE),
                    DDS_TYPECODE_NONKEY_REQUIRED_MEMBER, ex);
    structTc->add_member("ulong_1", DDS_TYPECODE_MEMBER_ID_INVALID, factory->get_primitive_tc(DDS_TK_ULONG),
                    DDS_TYPECODE_NONKEY_REQUIRED_MEMBER, ex);
    structTc->add_member("string_1", DDS_TYPECODE_MEMBER_ID_INVALID, factory->create_string_tc(60, ex),
                    DDS_TYPECODE_NONKEY_REQUIRED_MEMBER, ex);
    return structTc;
}

After you have  DDS_TypeCode you will need  DDSDynamicDataTypeSupport to create  DDS_DynamicData objects of this type

DDS_TypeCode* typeCode = createTypeCode();
DDSDynamicDataTypeSupport* typeSupport = new DDSDynamicDataTypeSupport(typeCode, DDS_DYNAMIC_DATA_TYPE_PROPERTY_DEFAULT);
DDS_DynamicData* dynamicData = typeSupport->create_data();

To serialize DDS data  RTICdrStream is used. It's possible to provide external buffer to get access to serialized data representation.

Important: You have to define  RTI_ENDIAN_LITTLE macro for you compiler if you platform uses little-endian representation (and it's most common case since x86 and x86-64 machines are little-endian) in order to correctly serialize and deserialize data. This define is used in  RTICdrStream_init to set correct native endianness of your platform.

With following code buffer is assigned to  RtiCdrStream :

char buffer[1000];
int bufferLen = 1000;
RTICdrStream serializationStream;
RTICdrStream_init(&serializationStream);
RTICdrStream_set(&serializationStream, buffer, bufferLen);

 Afterwards it's easy to serialize  DDS_DynamicData to  buffer using  to_stream method:

dynamicData->to_stream(serializationStream);

There is internal current position offset in RtiCdrStream so you should always set buffer with  RTICdrStream_set before serialization to reset offset. Size of serialized representation can be determined via current offset

int serializedSize = RTICdrStream_getCurrentPositionOffset(&serializationStream);

Deserialization is performed in similar way. First prepare stream by providing it buffer with serialized data:

RTICdrStream deserializationStream;
RTICdrStream_init(&deserializationStream);
RTICdrStream_set(&deserializationStream, buffer, bufferLen);

Next you can deserialize data. You should prepare DynamicData object before deserialization.

DDS_DynamicData* deserializedData = typeSupport->create_data();
deserializedData->from_stream(deserializationStream);

 

Comments

Connext DDS 5.2 introduced a new operation DDS_DynamicData::to_cdr_buffer that simplifies serialization of dynamic data so you no longer need to deal with the underlying RTICdrStream object.

For example, the dynamicData object can be serialized with:

// Figure out the needed how big the serialized buffer needs to be
unsigned int serialized_length;
dynamicData->to_cdr_buffer(NULL, &serialized_length);
char *serialized_buffer = malloc(serialized_length); 

unsigned int serialized_buffer_len;
dynamicData->to_cdr_buffer(serialized_buffer, &serialized_buffer_len);

 

Likewise to deserialize a dynamic data from a CDR buffer there is a new function DDS_DynamicData::from_cdr_buffer as in:

 dynamicData->from_cdr_buffer(serialized_buffer, serialized_buffer_len); 

Gerardo