11#pragma once
22
3+ #include " agnocast/agnocast_client.hpp"
34#include " agnocast/agnocast_mq.hpp"
45#include " agnocast/agnocast_publisher.hpp"
56#include " agnocast/agnocast_subscription.hpp"
@@ -35,6 +36,9 @@ template <typename MessageT>
3536void send_performance_bridge_request (
3637 const std::string & topic_name, topic_local_id_t id, BridgeDirection direction);
3738template <typename ServiceT>
39+ void send_service_bridge_request (
40+ const std::string & service_name, const rclcpp::QoS & qos, BridgeDirection direction);
41+ template <typename ServiceT>
3842void send_performance_service_bridge_request (
3943 const std::string & service_name, const rclcpp::QoS & qos, BridgeDirection direction);
4044
@@ -56,7 +60,7 @@ void request_service_bridge_core(
5660{
5761 auto bridge_mode = get_bridge_mode ();
5862 if (bridge_mode == BridgeMode::Standard) {
59- throw std::runtime_error ( " Service bridges are not yet implemented for standard mode " );
63+ send_service_bridge_request<ServiceT>(service_name, qos, direction );
6064 } else {
6165 send_performance_service_bridge_request<ServiceT>(service_name, qos, direction);
6266 }
@@ -207,22 +211,74 @@ class AgnocastToRosBridge : public BridgeBase
207211 rclcpp::CallbackGroup::SharedPtr get_callback_group () const override { return agno_cb_group_; }
208212};
209213
214+ template <typename ServiceT>
215+ class RosToAgnocastServiceBridge : public ServiceBridgeBase
216+ {
217+ typename rclcpp::Service<ServiceT>::SharedPtr ros_srv_;
218+ typename agnocast::Client<ServiceT>::SharedPtr agno_client_;
219+ rclcpp::CallbackGroup::SharedPtr ros_srv_cb_group_;
220+ rclcpp::CallbackGroup::SharedPtr agno_client_cb_group_;
221+
222+ public:
223+ explicit RosToAgnocastServiceBridge (
224+ const rclcpp::Node::SharedPtr & parent_node, const std::string & service_name,
225+ const rmw_qos_profile_t & qos)
226+ {
227+ ros_srv_cb_group_ =
228+ parent_node->create_callback_group (rclcpp::CallbackGroupType::MutuallyExclusive, false );
229+ agno_client_cb_group_ =
230+ parent_node->create_callback_group (rclcpp::CallbackGroupType::MutuallyExclusive, false );
231+
232+ agno_client_ = std::make_shared<agnocast::Client<ServiceT>>(
233+ parent_node.get (), service_name, rclcpp::ServicesQoS (), agno_client_cb_group_);
234+
235+ ros_srv_ = parent_node->create_service <ServiceT>(
236+ service_name,
237+ [this ](
238+ const typename ServiceT::Request::SharedPtr ros_req,
239+ typename ServiceT::Response::SharedPtr ros_res) {
240+ auto agno_req = this ->agno_client_ ->borrow_loaned_request ();
241+ *agno_req = *ros_req;
242+
243+ auto future = this ->agno_client_ ->async_send_request (std::move (agno_req));
244+
245+ auto agno_res = future.get ();
246+ *ros_res = *agno_res;
247+ },
248+ qos, ros_srv_cb_group_);
249+ }
250+
251+ std::pair<rclcpp::CallbackGroup::SharedPtr, rclcpp::CallbackGroup::SharedPtr>
252+ get_callback_groups () const override
253+ {
254+ return {ros_srv_cb_group_, agno_client_cb_group_};
255+ }
256+ };
257+
210258template <typename MessageT>
211259std::shared_ptr<void > start_ros_to_agno_node (
212- rclcpp::Node::SharedPtr node, const BridgeTargetInfo & info, const rclcpp::QoS & qos)
260+ rclcpp::Node::SharedPtr node, const PubsubBridgeTargetInfo & info, const rclcpp::QoS & qos)
213261{
214262 std::string topic_name (static_cast <const char *>(info.topic_name ));
215263 return std::make_shared<RosToAgnocastBridge<MessageT>>(node, topic_name, qos);
216264}
217265
218266template <typename MessageT>
219267std::shared_ptr<void > start_agno_to_ros_node (
220- rclcpp::Node::SharedPtr node, const BridgeTargetInfo & info, const rclcpp::QoS & qos)
268+ rclcpp::Node::SharedPtr node, const PubsubBridgeTargetInfo & info, const rclcpp::QoS & qos)
221269{
222270 std::string topic_name (static_cast <const char *>(info.topic_name ));
223271 return std::make_shared<AgnocastToRosBridge<MessageT>>(node, topic_name, qos);
224272}
225273
274+ template <typename ServiceT>
275+ std::shared_ptr<void > start_ros_to_agno_service_node (
276+ rclcpp::Node::SharedPtr node, const ServiceBridgeTargetInfo & info, const rmw_qos_profile_t & qos)
277+ {
278+ std::string service_name (static_cast <const char *>(info.name ));
279+ return std::make_shared<RosToAgnocastServiceBridge<ServiceT>>(node, service_name, qos);
280+ }
281+
226282template <typename MsgStruct>
227283void send_mq_message (
228284 const std::string & mq_name, const MsgStruct & msg, long msg_size_limit,
@@ -274,55 +330,51 @@ void send_bridge_request(
274330 const std::string & topic_name, topic_local_id_t id, BridgeDirection direction)
275331{
276332 static const auto logger = rclcpp::get_logger (" agnocast_bridge_requester" );
333+
277334 // We capture 'fn_reverse' because bridge_manager is responsible for managing both directions
278335 // independently. Storing the reverse factory allows us to instantiate the return path on-demand
279336 // within the same process.
280- auto fn_current = (direction == BridgeDirection::ROS2_TO_AGNOCAST)
281- ? &start_ros_to_agno_node<MessageT>
282- : &start_agno_to_ros_node<MessageT>;
283- auto fn_reverse = (direction == BridgeDirection::ROS2_TO_AGNOCAST)
284- ? &start_agno_to_ros_node<MessageT>
285- : &start_ros_to_agno_node<MessageT>;
286-
287- Dl_info info = {};
288- if (dladdr (reinterpret_cast <void *>(fn_current), &info) == 0 || !info.dli_fname ) {
289- RCLCPP_ERROR (logger, " dladdr failed or filename NULL." );
337+ auto fn_current = reinterpret_cast <uintptr_t >(
338+ (direction == BridgeDirection::ROS2_TO_AGNOCAST) ? &start_ros_to_agno_node<MessageT>
339+ : &start_agno_to_ros_node<MessageT>);
340+ auto fn_reverse = reinterpret_cast <uintptr_t >(
341+ (direction == BridgeDirection::ROS2_TO_AGNOCAST) ? &start_agno_to_ros_node<MessageT>
342+ : &start_ros_to_agno_node<MessageT>);
343+
344+ MqMsgBridge msg = {};
345+ msg.direction = direction;
346+ msg.is_service = false ;
347+ msg.pubsub_target .target_id = id;
348+ snprintf (
349+ static_cast <char *>(msg.pubsub_target .topic_name ), TOPIC_NAME_BUFFER_SIZE, " %s" ,
350+ topic_name.c_str ());
351+ if (!build_bridge_factory_info (msg.factory , fn_current, fn_reverse, logger)) {
290352 return ;
291- }
353+ };
292354
293- std::error_code ec;
294- auto self_path = std::filesystem::read_symlink (" /proc/self/exe" , ec);
295-
296- bool is_self_executable = false ;
297- if (!ec) {
298- std::filesystem::path factory_lib_path (info.dli_fname );
299- if (std::filesystem::equivalent (factory_lib_path, self_path, ec)) {
300- is_self_executable = true ;
301- } else if (ec) {
302- RCLCPP_WARN (
303- logger, " Filesystem check error for '%s' vs '%s': %s" , info.dli_fname , self_path.c_str (),
304- ec.message ().c_str ());
305- }
306- }
355+ std::string mq_name = create_mq_name_for_bridge (standard_bridge_manager_pid);
356+ send_mq_message (mq_name, msg, BRIDGE_MQ_MESSAGE_SIZE, logger);
357+ }
307358
308- const char * symbol_to_send = MAIN_EXECUTABLE_SYMBOL;
309- if (!is_self_executable && info.dli_sname != nullptr ) {
310- symbol_to_send = info.dli_sname ;
311- }
359+ template <typename ServiceT>
360+ void send_service_bridge_request (
361+ const std::string & service_name, const rclcpp::QoS & qos, BridgeDirection direction)
362+ {
363+ static const auto logger = rclcpp::get_logger (" agnocast_service_bridge_requester" );
364+
365+ // FIXME(bdm-k): Assume the direction is ROS2_TO_AGNOCAST for now.
366+ auto fn_current = reinterpret_cast <uintptr_t >(&start_ros_to_agno_service_node<ServiceT>);
367+ uintptr_t fn_reverse = 0 ;
312368
313369 MqMsgBridge msg = {};
314370 msg.direction = direction;
315- msg.target .target_id = id;
316- snprintf (
317- static_cast <char *>(msg.target .topic_name ), TOPIC_NAME_BUFFER_SIZE, " %s" , topic_name.c_str ());
318- snprintf (
319- static_cast <char *>(msg.factory .shared_lib_path ), SHARED_LIB_PATH_BUFFER_SIZE, " %s" ,
320- info.dli_fname );
371+ msg.is_service = true ;
372+ msg.srv_target .qos = qos.get_rmw_qos_profile ();
321373 snprintf (
322- static_cast <char *>(msg.factory . symbol_name ), SYMBOL_NAME_BUFFER_SIZE , " %s" , symbol_to_send );
323- auto base_addr = reinterpret_cast < uintptr_t >(info. dli_fbase );
324- msg. factory . fn_offset = reinterpret_cast < uintptr_t >(fn_current) - base_addr ;
325- msg. factory . fn_offset_reverse = reinterpret_cast < uintptr_t >(fn_reverse) - base_addr;
374+ static_cast <char *>(msg.srv_target . name ), SERVICE_NAME_BUFFER_SIZE , " %s" , service_name. c_str () );
375+ if (! build_bridge_factory_info (msg. factory , fn_current, fn_reverse, logger)) {
376+ return ;
377+ }
326378
327379 std::string mq_name = create_mq_name_for_bridge (standard_bridge_manager_pid);
328380 send_mq_message (mq_name, msg, BRIDGE_MQ_MESSAGE_SIZE, logger);
0 commit comments