CARLA
Loading...
Searching...
No Matches
FastDDSSubscriberMiddleware.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
11#include "carla/Logging.h"
12
13#include <fastdds/dds/domain/DomainParticipant.hpp>
14#include <fastdds/dds/topic/Topic.hpp>
15#include <fastdds/dds/topic/TypeSupport.hpp>
16#include <fastdds/dds/subscriber/Subscriber.hpp>
17#include <fastdds/dds/subscriber/DataReader.hpp>
18#include <fastdds/dds/subscriber/DataReaderListener.hpp>
19#include <fastdds/dds/subscriber/SampleInfo.hpp>
20#include <fastdds/dds/subscriber/qos/DataReaderQos.hpp>
21#include <fastdds/dds/subscriber/qos/SubscriberQos.hpp>
22#include <fastdds/dds/topic/qos/TopicQos.hpp>
23#include <fastrtps/attributes/ParticipantAttributes.h>
24#include <fastrtps/qos/QosPolicies.h>
25
26#include <atomic>
27
28namespace carla {
29namespace ros2 {
30
31namespace efd = eprosima::fastdds::dds;
32using erc = eprosima::fastrtps::types::ReturnCode_t;
33
34/// FastDDS implementation of ISubscriberMiddleware.
35/// Parameterized on traits type S that provides:
36/// S::msg_type — the message type (a carla::ros2::msg::* POD struct)
37/// Deserialization is handled by GenericCdrPubSubType<msg_type> via CdrSerialization.h.
38///
39/// Uses FastDDSSharedParticipant for a single refcounted DomainParticipant
40/// across all FastDDS endpoints. See FastDDSPublisherMiddleware.h for the rationale.
41///
42/// Sets USER_DATA QoS on the DataReader to the REP-2016 KV payload
43/// "typehash=RIHS01_<hex>;" (PID_USER_DATA = 0x002c in DDSI-RTPS v2.5
44/// §9.6.2.2.2) so that Jazzy rmw_cyclonedds_cpp and rmw_fastrtps_cpp can
45/// perform REP-2011 type-hash-based endpoint matching without warning.
46template<typename S>
48 : public ISubscriberMiddleware,
49 public eprosima::fastdds::dds::DataReaderListener {
50 public:
51 using msg_type = typename S::msg_type;
52
56
58 efd::DataReader* reader,
59 const efd::SubscriptionMatchedStatus& info) override {
60 _alive.store(info.current_count > 0, std::memory_order_relaxed);
61 }
62
63 void on_data_available(efd::DataReader* reader) override {
64 efd::SampleInfo info;
65 erc rcode = reader->take_next_sample(_message_ptr, &info);
66 if (rcode == erc::ReturnCodeValue::RETCODE_OK) {
67 *_new_message_ptr = true;
68 } else {
69 log_error("FastDDSSubscriberMiddleware::on_data_available (",
70 _topic_name, ") failed with code:", rcode());
71 }
72 }
73
75 if (_datareader) {
76 // Detach listener before deletion so that on_data_available cannot
77 // fire on a partially-destroyed object.
78 _datareader->set_listener(nullptr);
79 _subscriber->delete_datareader(_datareader);
80 }
81 if (_subscriber) {
82 _participant->delete_subscriber(_subscriber);
83 }
84 if (_topic) {
85 _participant->delete_topic(_topic);
86 }
87 if (_participant) {
90 _participant = nullptr;
91 }
92 }
93
94 bool Init(
95 const std::string& topic_name,
96 void* message_ptr,
97 bool* new_message_flag) override {
98 return InitImpl(topic_name, message_ptr, new_message_flag, nullptr);
99 }
100
101 bool Init(
102 const std::string& topic_name,
103 void* message_ptr,
104 bool* new_message_flag,
105 const QosProfile& qos) override {
106 return InitImpl(topic_name, message_ptr, new_message_flag, &qos);
107 }
108
109 private:
110 /// Shared Init body. When @a qos is non-null the profile overrides the
111 /// FastDDS DataReader defaults (BEST_EFFORT / VOLATILE); when null the
112 /// defaults are kept, preserving the pre-QoS behavior for every existing
113 /// subscriber.
115 const std::string& topic_name,
116 void* message_ptr,
117 bool* new_message_flag,
118 const QosProfile* qos) {
119 _message_ptr = static_cast<msg_type*>(message_ptr);
120 _new_message_ptr = new_message_flag;
121
122 if (_type == nullptr) {
123 log_error("FastDDSSubscriberMiddleware: Invalid TypeSupport");
124 return false;
125 }
126
128 if (_participant == nullptr) {
129 log_error("FastDDSSubscriberMiddleware: Shared participant unavailable");
130 return false;
131 }
132
133 _type.register_type(_participant);
135
136 efd::SubscriberQos subqos = efd::SUBSCRIBER_QOS_DEFAULT;
137 _subscriber = _participant->create_subscriber(subqos, nullptr);
138 if (_subscriber == nullptr) {
139 log_error("FastDDSSubscriberMiddleware: Failed to create Subscriber");
140 return false;
141 }
142
143 // Reuse an existing topic on the shared participant when present: FastDDS
144 // rejects duplicate create_topic for the same name. find_topic bumps the
145 // participant's topic refcount, balanced by delete_topic in the destructor.
146 if (_participant->lookup_topicdescription(topic_name) != nullptr) {
147 _topic = _participant->find_topic(topic_name, eprosima::fastrtps::Duration_t{0, 0});
148 } else {
149 efd::TopicQos tqos = efd::TOPIC_QOS_DEFAULT;
150 _topic = _participant->create_topic(topic_name, _type->getName(), tqos);
151 }
152 if (_topic == nullptr) {
153 log_error("FastDDSSubscriberMiddleware: Failed to create Topic");
154 return false;
155 }
156
157 efd::DataReaderQos rqos = efd::DATAREADER_QOS_DEFAULT;
158
159 if (qos != nullptr) {
160 rqos.reliability().kind =
162 ? efd::RELIABLE_RELIABILITY_QOS
163 : efd::BEST_EFFORT_RELIABILITY_QOS;
164 rqos.durability().kind =
166 ? efd::TRANSIENT_LOCAL_DURABILITY_QOS
167 : efd::VOLATILE_DURABILITY_QOS;
168 rqos.history().kind =
170 ? efd::KEEP_LAST_HISTORY_QOS
171 : efd::KEEP_ALL_HISTORY_QOS;
172 rqos.history().depth = qos->history_depth;
173 }
174
175 // Set USER_DATA (PID_USER_DATA = 0x002c per OMG DDSI-RTPS v2.5 §9.6.2.2.2)
176 // to the REP-2016 type-hash KV payload "typehash=RIHS01_<hex>;".
177 auto ud = build_user_data_for<msg_type>();
178 if (!ud.empty()) {
179 rqos.user_data().data_vec(ud);
180 }
181
182 efd::DataReaderListener* listener =
183 static_cast<efd::DataReaderListener*>(this);
184 _datareader = _subscriber->create_datareader(_topic, rqos, listener);
185 if (_datareader == nullptr) {
186 log_error("FastDDSSubscriberMiddleware: Failed to create DataReader");
187 return false;
188 }
189
190 _topic_name = topic_name;
191 return true;
192 }
193
194 public:
195 bool IsAlive() const override {
196 return _alive.load(std::memory_order_relaxed);
197 }
198
199 std::string GetTopicName() const override {
200 return _topic_name;
201 }
202
203 private:
204 efd::DomainParticipant* _participant { nullptr };
205 efd::Subscriber* _subscriber { nullptr };
206 efd::Topic* _topic { nullptr };
207 efd::DataReader* _datareader { nullptr };
208 efd::TypeSupport _type { new GenericCdrPubSubType<msg_type>() };
209
210 msg_type* _message_ptr { nullptr };
211 bool* _new_message_ptr { nullptr };
212
213 std::string _topic_name;
214 std::atomic<bool> _alive { false };
215};
216
217} // namespace ros2
218} // namespace carla
static void release_type(const std::string &type_name)
Release one use of type_name.
static eprosima::fastdds::dds::DomainParticipant * acquire()
Increment the refcount and return the shared DomainParticipant.
static void retain_type(const std::string &type_name)
Notify the singleton that one more endpoint is using type_name so that unregister_type() is deferred ...
static void release()
Decrement the refcount.
FastDDS implementation of ISubscriberMiddleware.
void on_subscription_matched(efd::DataReader *reader, const efd::SubscriptionMatchedStatus &info) override
FastDDSSubscriberMiddleware(const FastDDSSubscriberMiddleware &)=delete
bool Init(const std::string &topic_name, void *message_ptr, bool *new_message_flag) override
Initialize the underlying middleware entities.
FastDDSSubscriberMiddleware & operator=(const FastDDSSubscriberMiddleware &)=delete
void on_data_available(efd::DataReader *reader) override
bool Init(const std::string &topic_name, void *message_ptr, bool *new_message_flag, const QosProfile &qos) override
Initialize with an explicit per-topic QoS profile (see QosProfile.h).
bool InitImpl(const std::string &topic_name, void *message_ptr, bool *new_message_flag, const QosProfile *qos)
Shared Init body.
Generic FastDDS TopicDataType that serializes carla::ros2::msg::* POD structs directly to CDR via Cdr...
Type-erased abstract interface for a subscriber middleware.
eprosima::fastrtps::types::ReturnCode_t erc
This file contains definitions of common data structures used in traffic manager.
static void log_error(Args &&... args)
Definition Logging.h:110
Middleware-neutral QoS profile passed to IPublisherMiddleware::Init / ISubscriberMiddleware::Init whe...
Definition QosProfile.h:27
Reliability reliability
Definition QosProfile.h:32
std::int32_t history_depth
Definition QosProfile.h:35