CARLA
Loading...
Searching...
No Matches
CycloneDDSSertype.cpp
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// Only meaningful when building the CycloneDDS middleware target.
6#ifndef CARLA_ROS2_MIDDLEWARE_TESTING
7#ifdef CARLA_ROS2_MIDDLEWARE_CYCLONEDDS
8
11#include "carla/Logging.h"
12
13#include <dds/ddsi/q_radmin.h>
14
15#include <cstdlib>
16#include <cstring>
17#include <cstdio>
18
19namespace carla {
20namespace ros2 {
21
22// ============================================================
23// Internal: serdata allocation
24// ============================================================
25
26struct ddsi_serdata* carla_cdr_alloc_serdata(
27 const struct ddsi_sertype* type,
28 enum ddsi_serdata_kind kind,
29 uint32_t cdr_size)
30{
31 void* mem = malloc(sizeof(struct carla_cdr_serdata) + static_cast<size_t>(cdr_size));
32 if (!mem) { return nullptr; }
33 struct carla_cdr_serdata* csd = reinterpret_cast<struct carla_cdr_serdata*>(mem);
34 ddsi_serdata_init(&csd->sd, type, kind);
35 csd->cdr_size = cdr_size;
36 return &csd->sd;
37}
38
39// ============================================================
40// serdata ops
41// ============================================================
42
43static bool carla_cdr_serdata_eqkey(
44 const struct ddsi_serdata* /*a*/,
45 const struct ddsi_serdata* /*b*/)
46{
47 return true; // no keyed topics — all instances are equivalent
48}
49
50static uint32_t carla_cdr_serdata_get_size(const struct ddsi_serdata* d) {
51 return reinterpret_cast<const struct carla_cdr_serdata*>(d)->cdr_size;
52}
53
54static struct ddsi_serdata* carla_cdr_from_ser(
55 const struct ddsi_sertype* type,
56 enum ddsi_serdata_kind kind,
57 const struct nn_rdata* fragchain,
58 size_t size)
59{
60 struct ddsi_serdata* sd =
61 carla_cdr_alloc_serdata(type, kind, static_cast<uint32_t>(size));
62 if (!sd) { return nullptr; }
63 uint8_t* dest = reinterpret_cast<uint8_t*>(
64 reinterpret_cast<struct carla_cdr_serdata*>(sd) + 1);
65 const size_t gathered = carla_cdr_gather_fragments(
66 dest, size, fragchain,
67 [](const struct nn_rdata* f) -> const uint8_t* {
68 return NN_RMSG_PAYLOADOFF(f->rmsg, NN_RDATA_PAYLOAD_OFF(f));
69 });
70 if (gathered != size) {
72 "carla_cdr_from_ser: incomplete fragment chain (",
73 gathered, " of ", size, " bytes); dropping sample");
74 ddsi_serdata_unref(sd);
75 return nullptr;
76 }
77 return sd;
78}
79
80static struct ddsi_serdata* carla_cdr_from_ser_iov(
81 const struct ddsi_sertype* type,
82 enum ddsi_serdata_kind kind,
83 ddsrt_msg_iovlen_t niov,
84 const ddsrt_iovec_t* iov,
85 size_t size)
86{
87 struct ddsi_serdata* sd =
88 carla_cdr_alloc_serdata(type, kind, static_cast<uint32_t>(size));
89 if (!sd) { return nullptr; }
90 uint8_t* dest = reinterpret_cast<uint8_t*>(
91 reinterpret_cast<struct carla_cdr_serdata*>(sd) + 1);
92 size_t off = 0u;
93 for (ddsrt_msg_iovlen_t i = 0; i < niov && off < size; ++i) {
94 const size_t avail = static_cast<size_t>(iov[i].iov_len);
95 const size_t copy = (off + avail > size) ? (size - off) : avail;
96 memcpy(dest + off, iov[i].iov_base, copy);
97 off += copy;
98 }
99 return sd;
100}
101
102static struct ddsi_serdata* carla_cdr_from_keyhash(
103 const struct ddsi_sertype* type,
104 const struct ddsi_keyhash* /*keyhash*/)
105{
106 return carla_cdr_alloc_serdata(type, SDK_KEY, 0u);
107}
108
109static struct ddsi_serdata* carla_cdr_from_sample(
110 const struct ddsi_sertype* /*type*/,
111 enum ddsi_serdata_kind /*kind*/,
112 const void* /*sample*/)
113{
114 // Publishing via dds_write() is not supported — use dds_writecdr() instead.
115 // Return nullptr to fail loudly rather than silently producing empty data.
116 log_error(
117 "carla_cdr_from_sample: dds_write() is not supported; "
118 "use dds_writecdr() instead");
119 return nullptr;
120}
121
122static void carla_cdr_to_ser(
123 const struct ddsi_serdata* d,
124 size_t off,
125 size_t sz,
126 void* buf)
127{
128 memcpy(buf, carla_cdr_data(d) + off, sz);
129}
130
131static struct ddsi_serdata* carla_cdr_to_ser_ref(
132 const struct ddsi_serdata* d,
133 size_t off,
134 size_t sz,
135 ddsrt_iovec_t* ref)
136{
137 // NOLINTNEXTLINE — CycloneDDS iov_base is void*; we provide a non-const pointer
138 ref->iov_base = const_cast<void*>(
139 static_cast<const void*>(carla_cdr_data(d) + off));
140 ref->iov_len = static_cast<ddsrt_iov_len_t>(sz);
141 return ddsi_serdata_ref(d);
142}
143
144static void carla_cdr_to_ser_unref(
145 struct ddsi_serdata* d,
146 const ddsrt_iovec_t* /*ref*/)
147{
148 ddsi_serdata_unref(d);
149}
150
151static bool carla_cdr_to_sample(
152 const struct ddsi_serdata* /*d*/,
153 void* /*sample*/,
154 void** /*bufptr*/,
155 void* /*buflim*/)
156{
157 // Receiving via dds_take() is not supported — use dds_takecdr() instead.
158 return false;
159}
160
161static struct ddsi_serdata* carla_cdr_to_untyped(const struct ddsi_serdata* d) {
162 return ddsi_serdata_ref(d);
163}
164
165static bool carla_cdr_untyped_to_sample(
166 const struct ddsi_sertype* /*type*/,
167 const struct ddsi_serdata* /*d*/,
168 void* /*sample*/,
169 void** /*bufptr*/,
170 void* /*buflim*/)
171{
172 return false;
173}
174
175static void carla_cdr_serdata_free(struct ddsi_serdata* d) {
176 // ddsi_serdata_unref() is only called when the refcount reaches zero.
177 // ddsi_serdata_init() only sets fields — no dynamic allocations to release.
178 free(d);
179}
180
181static size_t carla_cdr_serdata_print(
182 const struct ddsi_sertype* /*type*/,
183 const struct ddsi_serdata* d,
184 char* buf,
185 size_t size)
186{
187 if (size == 0u) { return 0u; }
188 int n = snprintf(buf, size, "<carla_cdr %u bytes>", carla_cdr_size(d));
189 return static_cast<size_t>(n < 0 ? 0 : n);
190}
191
192static void carla_cdr_serdata_get_keyhash(
193 const struct ddsi_serdata* /*d*/,
194 struct ddsi_keyhash* buf,
195 bool /*force_md5*/)
196{
197 memset(buf, 0, sizeof(*buf));
198}
199
200const struct ddsi_serdata_ops carla_cdr_serdata_ops = {
201 carla_cdr_serdata_eqkey, // eqkey
202 carla_cdr_serdata_get_size, // get_size
203 carla_cdr_from_ser, // from_ser
204 carla_cdr_from_ser_iov, // from_ser_iov
205 carla_cdr_from_keyhash, // from_keyhash
206 carla_cdr_from_sample, // from_sample
207 carla_cdr_to_ser, // to_ser
208 carla_cdr_to_ser_ref, // to_ser_ref
209 carla_cdr_to_ser_unref, // to_ser_unref
210 carla_cdr_to_sample, // to_sample
211 carla_cdr_to_untyped, // to_untyped
212 carla_cdr_untyped_to_sample, // untyped_to_sample
213 carla_cdr_serdata_free, // free
214 carla_cdr_serdata_print, // print
215 carla_cdr_serdata_get_keyhash // get_keyhash
216};
217
218// ============================================================
219// sertype ops
220// ============================================================
221
222static void carla_cdr_sertype_free(struct ddsi_sertype* tp) {
223 ddsi_sertype_fini(tp);
224 free(tp);
225}
226
227static void carla_cdr_sertype_zero_samples(
228 const struct ddsi_sertype* /*d*/,
229 void* /*samples*/,
230 size_t /*count*/)
231{
232 // CDR passthrough — no typed samples to zero
233}
234
235static void carla_cdr_sertype_realloc_samples(
236 void** ptrs,
237 const struct ddsi_sertype* /*d*/,
238 void* /*old*/,
239 size_t /*oldcount*/,
240 size_t count)
241{
242 for (size_t i = 0u; i < count; ++i) {
243 ptrs[i] = nullptr;
244 }
245}
246
247static void carla_cdr_sertype_free_samples(
248 const struct ddsi_sertype* /*d*/,
249 void** ptrs,
250 size_t count,
251 dds_free_op_t /*op*/)
252{
253 for (size_t i = 0u; i < count; ++i) {
254 free(ptrs[i]);
255 }
256}
257
258static bool carla_cdr_sertype_equal(
259 const struct ddsi_sertype* /*a*/,
260 const struct ddsi_sertype* /*b*/)
261{
262 // Type names are already matched by the caller before invoking this.
263 // Two carla_cdr_sertypes with the same name are considered equal.
264 return true;
265}
266
267static uint32_t carla_cdr_sertype_hash(const struct ddsi_sertype* /*tp*/) {
268 return 0u;
269}
270
271const struct ddsi_sertype_ops carla_cdr_sertype_ops = {
272 ddsi_sertype_v0, // version
273 nullptr, // arg
274 carla_cdr_sertype_free, // free
275 carla_cdr_sertype_zero_samples, // zero_samples
276 carla_cdr_sertype_realloc_samples, // realloc_samples
277 carla_cdr_sertype_free_samples, // free_samples
278 carla_cdr_sertype_equal, // equal
279 carla_cdr_sertype_hash, // hash
280 nullptr, // type_id
281 nullptr, // type_map
282 nullptr, // type_info
283 nullptr, // derive_sertype
284 nullptr, // get_serialized_size
285 nullptr // serialize_into
286};
287
288// ============================================================
289// Shared participant
290// ============================================================
291
292dds_entity_t carla_cdr_get_participant() {
293 // Function-local static: created once on first call, thread-safe in C++11.
294 // The participant lives until process exit; CycloneDDS cleans up internally.
295 // Use the effective domain id resolved by the abstraction layer
296 // (--ros-domain-id, else ROS_DOMAIN_ID, else the default domain 0), so the
297 // domain selection matches FastDDS instead of relying on DDS_DOMAIN_DEFAULT.
298 static dds_entity_t participant = []() {
299 const dds_domainid_t domain_id =
300 static_cast<dds_domainid_t>(MiddlewareConfig::GetEffectiveDomainId());
301 return dds_create_participant(domain_id, nullptr, nullptr);
302 }();
303 return participant;
304}
305
306} // namespace ros2
307} // namespace carla
308
309#endif // CARLA_ROS2_MIDDLEWARE_CYCLONEDDS
310#endif // !CARLA_ROS2_MIDDLEWARE_TESTING
This file contains definitions of common data structures used in traffic manager.
static void log_error(Args &&... args)
Definition Logging.h:110
static double sd[6]
Definition odrSpiral.cpp:52