CARLA
Loading...
Searching...
No Matches
GenericCdrPubSubType.h
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB).
2// This work is licensed under the terms of the MIT license.
3// For a copy, see <https://opensource.org/licenses/MIT>.
4
5#pragma once
6
9
10#include <fastdds/dds/topic/TopicDataType.hpp>
11#include <fastrtps/rtps/common/SerializedPayload.h>
12#include <fastcdr/FastBuffer.h>
13#include <fastcdr/Cdr.h>
14
15#include <cstdint>
16#include <cstring>
17#include <functional>
18
19namespace carla {
20namespace ros2 {
21
22/// Generic FastDDS TopicDataType that serializes carla::ros2::msg::* POD structs
23/// directly to CDR via CdrSerialization.h, without needing fastddsgen-generated
24/// per-type PubSubType classes.
25///
26/// Replaces all 30 hand-generated *PubSubType classes.
27/// Type name and max size are provided by CdrTopicInfo<MsgType>.
28template<typename MsgType>
30 public:
31 using SerializedPayload_t = eprosima::fastrtps::rtps::SerializedPayload_t;
32
35 // m_typeSize is max CDR payload including the 4-byte DDS encapsulation header.
36 // FastDDS uses this to pre-allocate payload buffers.
37 const uint32_t max_payload = static_cast<uint32_t>(
39 // Add alignment padding + 4-byte encapsulation header, matching the pattern
40 // in fastddsgen-generated constructors (e.g. ClockPubSubTypes.cpp:36-37).
41 m_typeSize = max_payload +
42 static_cast<uint32_t>(
43 eprosima::fastcdr::Cdr::alignment(max_payload, 4u)) +
44 4u;
45 m_isGetKeyDefined = false;
46 }
47
48 ~GenericCdrPubSubType() override = default;
49
50 /// Serialize a MsgType instance into the FastDDS payload buffer.
51 /// Called by FastDDS DataWriter::write() before sending on the wire.
52 /// Serializes into an auto-growing heap buffer first so variable-length
53 /// fields (e.g. Image::data, PointCloud2::data) are not bounded by the
54 /// pre-allocated payload->data size. The bytes are then memcpy'd across.
55 /// FastDDS resizes payload->data before this call via getSerializedSizeProvider,
56 /// so the copy will always fit for correctly sized messages.
58 void* data,
59 SerializedPayload_t* payload) override {
60 const MsgType* msg = static_cast<const MsgType*>(data);
61
62 // Auto-growing FastBuffer: no fixed-size ceiling, handles any payload.
63 eprosima::fastcdr::FastBuffer fb;
64 // Force LITTLE_ENDIANNESS so the encapsulation header is CDR_LE
65 // ({0x00, 0x01}) per DDSI-RTPS v2.5 Table 10.3, regardless of host
66 // endianness. ROS2 ecosystems test against CDR_LE.
67 eprosima::fastcdr::Cdr ser(
68 fb,
69 eprosima::fastcdr::Cdr::LITTLE_ENDIANNESS,
70 eprosima::fastcdr::CdrVersion::XCDRv1);
71 payload->encapsulation = CDR_LE;
72
73 try {
74 ser.serialize_encapsulation();
75 serialize_cdr(ser, *msg);
76 } catch (eprosima::fastcdr::exception::Exception& /*e*/) {
77 return false;
78 }
79
80 const uint32_t len = static_cast<uint32_t>(ser.get_serialized_data_length());
81 if (len > payload->max_size) {
82 return false;
83 }
84 std::memcpy(payload->data, fb.getBuffer(), len);
85 payload->length = len;
86 return true;
87 }
88
89 /// FastDDS 2.13+ data-representation-aware serialize overload. CARLA always
90 /// emits classic CDR (XCDRv1, little-endian) regardless of the requested
91 /// representation, so this simply delegates to the 2-argument override. It
92 /// guarantees the writer path reaches our CDR serializer whichever overload
93 /// FastDDS calls internally.
95 void* data,
96 SerializedPayload_t* payload,
97 eprosima::fastdds::dds::DataRepresentationId_t /*data_representation*/)
98 override {
99 return serialize(data, payload);
100 }
101
102 /// Deserialize a FastDDS payload buffer into a MsgType instance.
103 /// Called by FastDDS DataReader after receiving data from the wire.
105 SerializedPayload_t* payload,
106 void* data) override {
107 MsgType* msg = static_cast<MsgType*>(data);
108
109 eprosima::fastcdr::FastBuffer fastbuffer(
110 reinterpret_cast<char*>(payload->data),
111 static_cast<size_t>(payload->length));
112 // The deserializer must accept either endianness on the wire, the
113 // actual byte order is determined from the encapsulation header by
114 // read_encapsulation(). LITTLE_ENDIANNESS here is just the initial
115 // hint Fast-CDR uses before the header is parsed.
116 eprosima::fastcdr::Cdr deser(
117 fastbuffer,
118 eprosima::fastcdr::Cdr::LITTLE_ENDIANNESS,
119 eprosima::fastcdr::CdrVersion::XCDRv1);
120
121 try {
122 deser.read_encapsulation();
123 payload->encapsulation = (deser.endianness() ==
124 eprosima::fastcdr::Cdr::BIG_ENDIANNESS) ? CDR_BE : CDR_LE;
125 deserialize_cdr(deser, *msg);
126 } catch (eprosima::fastcdr::exception::Exception& /*e*/) {
127 return false;
128 }
129
130 return true;
131 }
132
133 /// Return a function that gives the actual CDR-serialized size for this
134 /// specific message instance. FastDDS calls this before serialize() to
135 /// size (or resize) the payload buffer, so the buffer is always large enough
136 /// for variable-length fields like Image::data or PointCloud2::data.
137 std::function<uint32_t()> getSerializedSizeProvider(void* data) override {
138 const MsgType* msg = static_cast<const MsgType*>(data);
139 return [msg]() -> uint32_t {
140 return cdr_serialized_size(*msg);
141 };
142 }
143
144 /// FastDDS 2.13+ data-representation-aware size-provider overload. CARLA
145 /// serializes the same classic-CDR bytes regardless of the requested
146 /// representation, so this delegates to the 1-argument override.
147 std::function<uint32_t()> getSerializedSizeProvider(
148 void* data,
149 eprosima::fastdds::dds::DataRepresentationId_t /*data_representation*/)
150 override {
151 return getSerializedSizeProvider(data);
152 }
153
154 /// Allocate a new default-initialized MsgType on the heap.
155 void* createData() override {
156 return static_cast<void*>(new MsgType());
157 }
158
159 /// Delete a MsgType previously returned by createData().
160 void deleteData(void* data) override {
161 delete static_cast<MsgType*>(data);
162 }
163
164 /// CARLA topics are not keyed — always return false.
165 bool getKey(
166 void* /*data*/,
167 eprosima::fastrtps::rtps::InstanceHandle_t* /*ihandle*/,
168 bool /*force_md5*/) override {
169 return false;
170 }
171};
172
173} // namespace ros2
174} // namespace carla
Generic FastDDS TopicDataType that serializes carla::ros2::msg::* POD structs directly to CDR via Cdr...
std::function< uint32_t()> getSerializedSizeProvider(void *data) override
Return a function that gives the actual CDR-serialized size for this specific message instance.
eprosima::fastrtps::rtps::SerializedPayload_t SerializedPayload_t
bool deserialize(SerializedPayload_t *payload, void *data) override
Deserialize a FastDDS payload buffer into a MsgType instance.
bool serialize(void *data, SerializedPayload_t *payload) override
Serialize a MsgType instance into the FastDDS payload buffer.
~GenericCdrPubSubType() override=default
void deleteData(void *data) override
Delete a MsgType previously returned by createData().
std::function< uint32_t()> getSerializedSizeProvider(void *data, eprosima::fastdds::dds::DataRepresentationId_t) override
FastDDS 2.13+ data-representation-aware size-provider overload.
void * createData() override
Allocate a new default-initialized MsgType on the heap.
bool serialize(void *data, SerializedPayload_t *payload, eprosima::fastdds::dds::DataRepresentationId_t) override
FastDDS 2.13+ data-representation-aware serialize overload.
bool getKey(void *, eprosima::fastrtps::rtps::InstanceHandle_t *, bool) override
CARLA topics are not keyed — always return false.
uint32_t cdr_serialized_size(const T &msg)
Return the exact CDR-serialized size in bytes for a message instance, including the 4-byte DDS encaps...
void deserialize_cdr(eprosima::fastcdr::Cdr &cdr, msg::Time &m)
void serialize_cdr(eprosima::fastcdr::Cdr &cdr, const msg::Time &m)
This file contains definitions of common data structures used in traffic manager.
Per-type metadata needed by the middleware layer.