Skip to content

Commit 2221d63

Browse files
jaisontjivanpauno
authored andcommitted
Implement functions to get publisher and subcription informations like QoS policies from topic name (#511)
Signed-off-by: Jaison Titus <[email protected]> Signed-off-by: Miaofei <[email protected]>
1 parent 024c3ee commit 2221d63

File tree

5 files changed

+599
-4
lines changed

5 files changed

+599
-4
lines changed

rcl/include/rcl/graph.h

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ extern "C"
2222

2323
#include <rmw/names_and_types.h>
2424
#include <rmw/get_topic_names_and_types.h>
25+
#include <rmw/topic_endpoint_info_array.h>
2526

2627
#include "rcutils/types.h"
2728

@@ -420,8 +421,8 @@ rcl_names_and_types_fini(rcl_names_and_types_t * names_and_types);
420421
*
421422
* \param[in] node the handle to the node being used to query the ROS graph
422423
* \param[in] allocator used to control allocation and deallocation of names
423-
* \param[out] node_names struct storing discovered node names.
424-
* \param[out] node_namesspaces struct storing discovered node namespaces.
424+
* \param[out] node_names struct storing discovered node names
425+
* \param[out] node_namesspaces struct storing discovered node namespaces
425426
* \return `RCL_RET_OK` if the query was successful, or
426427
* \return `RCL_RET_ERROR` if an unspecified error occurs.
427428
*/
@@ -524,6 +525,126 @@ rcl_count_subscribers(
524525
const char * topic_name,
525526
size_t * count);
526527

528+
/// Return a list of all publishers to a topic.
529+
/**
530+
* The `node` parameter must point to a valid node.
531+
*
532+
* The `topic_name` parameter must not be `NULL`.
533+
*
534+
* When the `no_mangle` parameter is `true`, the provided `topic_name` should be a valid topic name
535+
* for the middleware (useful when combining ROS with native middleware (e.g. DDS) apps).
536+
* When the `no_mangle` parameter is `false`, the provided `topic_name` should follow
537+
* ROS topic name conventions.
538+
* In either case, the topic name should always be fully qualified.
539+
*
540+
* Each element in the `publishers_info` array will contain the node name, node namespace,
541+
* topic type, gid and the qos profile of the publisher.
542+
* It is the responsibility of the caller to ensure that `publishers_info` parameter points
543+
* to a valid struct of type rmw_topic_endpoint_info_array_t.
544+
* The `count` field inside the struct must be set to 0 and the `info_array` field inside
545+
* the struct must be set to null.
546+
* \see rmw_get_zero_initialized_topic_endpoint_info_array
547+
*
548+
* The `allocator` will be used to allocate memory to the `info_array` member
549+
* inside of `publishers_info`.
550+
* Moreover, every const char * member inside of
551+
* rmw_topic_endpoint_info_t will be assigned a copied value on allocated memory.
552+
* \see rmw_topic_endpoint_info_set_node_name and the likes.
553+
* However, it is the responsibility of the caller to
554+
* reclaim any allocated resources to `publishers_info` to avoid leaking memory.
555+
* \see rmw_topic_endpoint_info_array_fini
556+
*
557+
* <hr>
558+
* Attribute | Adherence
559+
* ------------------ | -------------
560+
* Allocates Memory | Yes
561+
* Thread-Safe | No
562+
* Uses Atomics | No
563+
* Lock-Free | Maybe [1]
564+
* <i>[1] implementation may need to protect the data structure with a lock</i>
565+
*
566+
* \param[in] node the handle to the node being used to query the ROS graph
567+
* \param[in] allocator allocator to be used when allocating space for
568+
* the array inside publishers_info
569+
* \param[in] topic_name the name of the topic in question
570+
* \param[in] no_mangle if true, the topic_name will be expanded to its fully qualified name
571+
* \param[out] publishers_info a struct representing a list of publisher information
572+
* \return `RCL_RET_OK` if the query was successful, or
573+
* \return `RCL_RET_NODE_INVALID` if the node is invalid, or
574+
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
575+
* \return `RCL_RET_BAD_ALLOC` if memory allocation fails, or
576+
* \return `RCL_RET_ERROR` if an unspecified error occurs.
577+
*/
578+
RCL_PUBLIC
579+
RCL_WARN_UNUSED
580+
rcl_ret_t
581+
rcl_get_publishers_info_by_topic(
582+
const rcl_node_t * node,
583+
rcutils_allocator_t * allocator,
584+
const char * topic_name,
585+
bool no_mangle,
586+
rmw_topic_endpoint_info_array_t * publishers_info);
587+
588+
/// Return a list of all subscriptions to a topic.
589+
/**
590+
* The `node` parameter must point to a valid node.
591+
*
592+
* The `topic_name` parameter must not be `NULL`.
593+
*
594+
* When the `no_mangle` parameter is `true`, the provided `topic_name` should be a valid topic name
595+
* for the middleware (useful when combining ROS with native middleware (e.g. DDS) apps).
596+
* When the `no_mangle` parameter is `false`, the provided `topic_name` should follow
597+
* ROS topic name conventions.
598+
* In either case, the topic name should always be fully qualified.
599+
*
600+
* Each element in the `subscriptions_info` array will contain the node name, node namespace,
601+
* topic type, gid and the qos profile of the subscription.
602+
* It is the responsibility of the caller to ensure that `subscriptions_info` parameter points
603+
* to a valid struct of type rmw_topic_endpoint_info_array_t.
604+
* The `count` field inside the struct must be set to 0 and the `info_array` field inside
605+
* the struct must be set to null.
606+
* \see rmw_get_zero_initialized_topic_endpoint_info_array
607+
*
608+
* The `allocator` will be used to allocate memory to the `info_array` member
609+
* inside of `subscriptions_info`.
610+
* Moreover, every const char * member inside of
611+
* rmw_topic_endpoint_info_t will be assigned a copied value on allocated memory.
612+
* \see rmw_topic_endpoint_info_set_node_name and the likes.
613+
* However, it is the responsibility of the caller to
614+
* reclaim any allocated resources to `subscriptions_info` to avoid leaking memory.
615+
* \see rmw_topic_endpoint_info_array_fini
616+
*
617+
* <hr>
618+
* Attribute | Adherence
619+
* ------------------ | -------------
620+
* Allocates Memory | Yes
621+
* Thread-Safe | No
622+
* Uses Atomics | No
623+
* Lock-Free | Maybe [1]
624+
* <i>[1] implementation may need to protect the data structure with a lock</i>
625+
*
626+
* \param[in] node the handle to the node being used to query the ROS graph
627+
* \param[in] allocator allocator to be used when allocating space for
628+
* the array inside publishers_info
629+
* \param[in] topic_name the name of the topic in question
630+
* \param[in] no_mangle if true, the topic_name will be expanded to its fully qualified name
631+
* \param[out] subscriptions_info a struct representing a list of subscriptions information
632+
* \return `RCL_RET_OK` if the query was successful, or
633+
* \return `RCL_RET_NODE_INVALID` if the node is invalid, or
634+
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
635+
* \return `RCL_RET_BAD_ALLOC` if memory allocation fails, or
636+
* \return `RCL_RET_ERROR` if an unspecified error occurs.
637+
*/
638+
RCL_PUBLIC
639+
RCL_WARN_UNUSED
640+
rcl_ret_t
641+
rcl_get_subscriptions_info_by_topic(
642+
const rcl_node_t * node,
643+
rcutils_allocator_t * allocator,
644+
const char * topic_name,
645+
bool no_mangle,
646+
rmw_topic_endpoint_info_array_t * subscriptions_info);
647+
527648
/// Check if a service server is available for the given service client.
528649
/**
529650
* This function will return true for `is_available` if there is a service server

rcl/src/rcl/graph.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ extern "C"
2525
#include "rmw/error_handling.h"
2626
#include "rmw/get_node_info_and_types.h"
2727
#include "rmw/get_service_names_and_types.h"
28+
#include "rmw/get_topic_endpoint_info.h"
2829
#include "rmw/get_topic_names_and_types.h"
2930
#include "rmw/names_and_types.h"
3031
#include "rmw/rmw.h"
32+
#include "rmw/topic_endpoint_info_array.h"
3133
#include "rmw/validate_namespace.h"
3234
#include "rmw/validate_node_name.h"
3335

@@ -375,6 +377,90 @@ rcl_count_subscribers(
375377
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
376378
}
377379

380+
typedef rmw_ret_t (* get_topic_endpoint_info_func_t)(
381+
const rmw_node_t * node,
382+
rcutils_allocator_t * allocator,
383+
const char * topic_name,
384+
bool no_mangle,
385+
rmw_topic_endpoint_info_array_t * info_array);
386+
387+
rcl_ret_t
388+
__rcl_get_info_by_topic(
389+
const rcl_node_t * node,
390+
rcutils_allocator_t * allocator,
391+
const char * topic_name,
392+
bool no_mangle,
393+
rmw_topic_endpoint_info_array_t * info_array,
394+
get_topic_endpoint_info_func_t get_topic_endpoint_info)
395+
{
396+
if (!rcl_node_is_valid(node)) {
397+
return RCL_RET_NODE_INVALID; // error already set.
398+
}
399+
const rcl_node_options_t * node_options = rcl_node_get_options(node);
400+
if (!node_options) {
401+
return RCL_RET_NODE_INVALID; // shouldn't happen, but error is already set if so
402+
}
403+
RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
404+
RCL_CHECK_ARGUMENT_FOR_NULL(topic_name, RCL_RET_INVALID_ARGUMENT);
405+
rmw_error_string_t error_string;
406+
rmw_ret_t rmw_ret = rmw_topic_endpoint_info_array_check_zero(info_array);
407+
if (rmw_ret != RMW_RET_OK) {
408+
error_string = rmw_get_error_string();
409+
rmw_reset_error();
410+
RCL_SET_ERROR_MSG_WITH_FORMAT_STRING(
411+
"rmw_topic_endpoint_info_array_t must be zero initialized: %s,\n"
412+
"Use rmw_get_zero_initialized_topic_endpoint_info_array",
413+
error_string.str);
414+
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
415+
}
416+
rmw_ret = get_topic_endpoint_info(
417+
rcl_node_get_rmw_handle(node),
418+
allocator,
419+
topic_name,
420+
no_mangle,
421+
info_array);
422+
if (rmw_ret != RMW_RET_OK) {
423+
error_string = rmw_get_error_string();
424+
rmw_reset_error();
425+
RCL_SET_ERROR_MSG(error_string.str);
426+
}
427+
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
428+
}
429+
430+
rcl_ret_t
431+
rcl_get_publishers_info_by_topic(
432+
const rcl_node_t * node,
433+
rcutils_allocator_t * allocator,
434+
const char * topic_name,
435+
bool no_mangle,
436+
rmw_topic_endpoint_info_array_t * publishers_info)
437+
{
438+
return __rcl_get_info_by_topic(
439+
node,
440+
allocator,
441+
topic_name,
442+
no_mangle,
443+
publishers_info,
444+
rmw_get_publishers_info_by_topic);
445+
}
446+
447+
rcl_ret_t
448+
rcl_get_subscriptions_info_by_topic(
449+
const rcl_node_t * node,
450+
rcutils_allocator_t * allocator,
451+
const char * topic_name,
452+
bool no_mangle,
453+
rmw_topic_endpoint_info_array_t * subscriptions_info)
454+
{
455+
return __rcl_get_info_by_topic(
456+
node,
457+
allocator,
458+
topic_name,
459+
no_mangle,
460+
subscriptions_info,
461+
rmw_get_subscriptions_info_by_topic);
462+
}
463+
378464
rcl_ret_t
379465
rcl_service_server_is_available(
380466
const rcl_node_t * node,

rcl/test/CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,21 @@ function(test_target_function)
101101
${AMENT_GTEST_ARGS}
102102
)
103103

104+
set(AMENT_GTEST_ARGS "")
105+
# TODO(mm318): why rmw_connext tests run much slower than rmw_fastrtps and rmw_opensplice tests
106+
if(rmw_implementation STREQUAL "rmw_connext_cpp")
107+
message(STATUS "Increasing test_info_by_topic${target_suffix} test timeout.")
108+
set(AMENT_GTEST_ARGS TIMEOUT 120)
109+
endif()
110+
rcl_add_custom_gtest(test_info_by_topic${target_suffix}
111+
SRCS rcl/test_info_by_topic.cpp
112+
ENV ${rmw_implementation_env_var}
113+
APPEND_LIBRARY_DIRS ${extra_lib_dirs}
114+
LIBRARIES ${PROJECT_NAME}
115+
AMENT_DEPENDENCIES ${rmw_implementation} "osrf_testing_tools_cpp" "test_msgs"
116+
${AMENT_GTEST_ARGS}
117+
)
118+
104119
rcl_add_custom_gtest(test_count_matched${target_suffix}
105120
SRCS rcl/test_count_matched.cpp
106121
ENV ${rmw_implementation_env_var}

rcl/test/rcl/test_graph.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -916,8 +916,8 @@ class NodeGraphMultiNodeFixture : public CLASSNAME(TestGraphFixture, RMW_IMPLEME
916916
/**
917917
* Verify the number of subsystems each node should have.
918918
*
919-
* @param node_state expected state of node
920-
* @param remote_node_state expected state of remote node
919+
* \param node_state expected state of node
920+
* \param remote_node_state expected state of remote node
921921
*/
922922
void VerifySubsystemCount(
923923
const expected_node_state && node_state,

0 commit comments

Comments
 (0)