Skip to content

Commit

Permalink
Add node graph api to rcl. (#333)
Browse files Browse the repository at this point in the history
This is an omnibus rollup of all of the previous commits
from #333
  • Loading branch information
ross-desmond authored and jacobperron committed Dec 7, 2018
1 parent c5798e4 commit 8d6fb9a
Show file tree
Hide file tree
Showing 6 changed files with 603 additions and 19 deletions.
163 changes: 163 additions & 0 deletions rcl/include/rcl/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,169 @@ typedef rmw_names_and_types_t rcl_names_and_types_t;

#define rcl_get_zero_initialized_names_and_types rmw_get_zero_initialized_names_and_types

/// Return a list of publisher topic names and their types per node.
/**
* This function returns a list of topic names in the ROS graph for param node_name and their types.
*
* The node parameter must not be `NULL`, and must point to a valid node.
*
* The topic_names_and_types parameter must be allocated and zero initialized.
* The topic_names_and_types is the output for this function, and contains
* allocated memory.
* Therefore, it should be passed to rcl_names_and_types_fini() when
* it is no longer needed.
* Failing to do so will result in leaked memory.
*
* There may be some demangling that occurs when listing the topics from the
* middleware implementation.
* If the no_demangle argument is true, then this will be avoided and the
* topics will be returned as they appear to the middleware.
*
* \see rmw_get_topic_names_and_types for more details on no_demangle
*
* The returned names are not automatically remapped by this function.
* Attempting to create publishers or subscribers using names returned by this function may not
* result in the desired topic name being used depending on the remap rules in use.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Maybe [1]
* <i>[1] implementation may need to protect the data structure with a lock</i>
*
* \param[in] node the handle to the node being used to query the ROS graph
* \param[in] allocator allocator to be used when allocating space for strings
* \param[in] no_demangle if true, list all topics without any demangling
* \param[in] node_name of the node to look up topics
* \param[in] node_namespace of the node to look up topics
* \param[out] topic_names_and_types list of topic names and their types
* \return `RCL_RET_OK` if the query was successful, or
* \return `RCL_RET_NODE_INVALID` if the node is invalid, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_get_publisher_names_and_types_by_node(
const rcl_node_t * node,
rcl_allocator_t * allocator,
bool no_demangle,
const char * node_name,
const char * node_namespace,
rcl_names_and_types_t * topic_names_and_types);

/// Return a list of subcriber topic names and their types per node.
/**
* This function returns a list of topic names in the ROS graph for param node_name and their types.
*
* The node parameter must not be `NULL`, and must point to a valid node.
*
* The topic_names_and_types parameter must be allocated and zero initialized.
* The topic_names_and_types is the output for this function, and contains
* allocated memory.
* Therefore, it should be passed to rcl_names_and_types_fini() when
* it is no longer needed.
* Failing to do so will result in leaked memory.
*
* There may be some demangling that occurs when listing the topics from the
* middleware implementation.
* If the no_demangle argument is true, then this will be avoided and the
* topics will be returned as they appear to the middleware.
*
* \see rmw_get_topic_names_and_types for more details on no_demangle
*
* The returned names are not automatically remapped by this function.
* Attempting to create publishers or subscribers using names returned by this function may not
* result in the desired topic name being used depending on the remap rules in use.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Maybe [1]
* <i>[1] implementation may need to protect the data structure with a lock</i>
*
* \param[in] node the handle to the node being used to query the ROS graph
* \param[in] allocator allocator to be used when allocating space for strings
* \param[in] no_demangle if true, list all topics without any demangling
* \param[in] node_name of the node to look up topics
* \param[in] node_namespace of the node to look up topics
* \param[out] topic_names_and_types list of topic names and their types
* \return `RCL_RET_OK` if the query was successful, or
* \return `RCL_RET_NODE_INVALID` if the node is invalid, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_get_subscriber_names_and_types_by_node(
const rcl_node_t * node,
rcl_allocator_t * allocator,
bool no_demangle,
const char * node_name,
const char * node_namespace,
rcl_names_and_types_t * topic_names_and_types);

/// Return a list of service names and their types per node.
/**
* This function returns a list of service names in the ROS graph for param node_name and their types.
*
* The node parameter must not be `NULL`, and must point to a valid node.
*
* The topic_names_and_types parameter must be allocated and zero initialized.
* The topic_names_and_types is the output for this function, and contains
* allocated memory.
* Therefore, it should be passed to rcl_names_and_types_fini() when
* it is no longer needed.
* Failing to do so will result in leaked memory.
*
* There may be some demangling that occurs when listing the topics from the
* middleware implementation.
* If the no_demangle argument is true, then this will be avoided and the
* topics will be returned as they appear to the middleware.
*
* \see rmw_get_topic_names_and_types for more details on no_demangle
*
* The returned names are not automatically remapped by this function.
* Attempting to create publishers or subscribers using names returned by this function may not
* result in the desired topic name being used depending on the remap rules in use.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Maybe [1]
* <i>[1] implementation may need to protect the data structure with a lock</i>
*
* \param[in] node the handle to the node being used to query the ROS graph
* \param[in] allocator allocator to be used when allocating space for strings
* \param[in] node_name of the node to look up topics
* \param[in] node_namespace of the node to look up topics
* \param[out] service_names_and_types list of service names and their types
* \return `RCL_RET_OK` if the query was successful, or
* \return `RCL_RET_NODE_INVALID` if the node is invalid, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_get_service_names_and_types_by_node(
const rcl_node_t * node,
rcl_allocator_t * allocator,
const char * node_name,
const char * node_namespace,
rcl_names_and_types_t * service_names_and_types);

/// Return a list of topic names and their types.
/**
* This function returns a list of topic names in the ROS graph and their types.
Expand Down
113 changes: 113 additions & 0 deletions rcl/src/rcl/graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,126 @@ extern "C"
#include "rcl/error_handling.h"
#include "rcutils/allocator.h"
#include "rcutils/types.h"
#include "rmw/get_node_info_and_types.h"
#include "rmw/get_service_names_and_types.h"
#include "rmw/get_topic_names_and_types.h"
#include "rmw/names_and_types.h"
#include "rmw/rmw.h"

#include "./common.h"

rcl_ret_t
rcl_get_publisher_names_and_types_by_node(
const rcl_node_t * node,
rcl_allocator_t * allocator,
bool no_demangle,
const char * node_name,
const char * node_namespace,
rcl_names_and_types_t * topic_names_and_types)
{
if (!rcl_node_is_valid(node)) {
return RCL_RET_NODE_INVALID;
}
RCL_CHECK_ARGUMENT_FOR_NULL(allocator, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(node_name, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(node_namespace, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(topic_names_and_types, RCL_RET_INVALID_ARGUMENT);

const char * valid_namespace = "/";
if (strlen(node_namespace) > 0) {
valid_namespace = node_namespace;
}
rmw_ret_t rmw_ret;
rmw_ret = rmw_names_and_types_check_zero(topic_names_and_types);
if (rmw_ret != RMW_RET_OK) {
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
}
rcutils_allocator_t rcutils_allocator = *allocator;
rmw_ret = rmw_get_publisher_names_and_types_by_node(
rcl_node_get_rmw_handle(node),
&rcutils_allocator,
node_name,
valid_namespace,
no_demangle,
topic_names_and_types
);
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
}

rcl_ret_t
rcl_get_subscriber_names_and_types_by_node(
const rcl_node_t * node,
rcl_allocator_t * allocator,
bool no_demangle,
const char * node_name,
const char * node_namespace,
rcl_names_and_types_t * topic_names_and_types)
{
if (!rcl_node_is_valid(node)) {
return RCL_RET_NODE_INVALID;
}
RCL_CHECK_ARGUMENT_FOR_NULL(allocator, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(node_name, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(node_namespace, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(topic_names_and_types, RCL_RET_INVALID_ARGUMENT);

const char * valid_namespace = "/";
if (strlen(node_namespace) > 0) {
valid_namespace = node_namespace;
}
rmw_ret_t rmw_ret;
rmw_ret = rmw_names_and_types_check_zero(topic_names_and_types);
if (rmw_ret != RMW_RET_OK) {
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
}
rcutils_allocator_t rcutils_allocator = *allocator;
rmw_ret = rmw_get_subscriber_names_and_types_by_node(
rcl_node_get_rmw_handle(node),
&rcutils_allocator,
node_name,
valid_namespace,
no_demangle,
topic_names_and_types
);
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
}

rcl_ret_t
rcl_get_service_names_and_types_by_node(
const rcl_node_t * node,
rcl_allocator_t * allocator,
const char * node_name,
const char * node_namespace,
rcl_names_and_types_t * service_names_and_types)
{
if (!rcl_node_is_valid(node)) {
return RCL_RET_NODE_INVALID;
}
RCL_CHECK_ARGUMENT_FOR_NULL(allocator, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(node_name, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(node_namespace, RCL_RET_INVALID_ARGUMENT);
RCL_CHECK_ARGUMENT_FOR_NULL(service_names_and_types, RCL_RET_INVALID_ARGUMENT);

const char * valid_namespace = "/";
if (strlen(node_namespace) > 0) {
valid_namespace = node_namespace;
}
rmw_ret_t rmw_ret;
rmw_ret = rmw_names_and_types_check_zero(service_names_and_types);
if (rmw_ret != RMW_RET_OK) {
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
}
rcutils_allocator_t rcutils_allocator = *allocator;
rmw_ret = rmw_get_service_names_and_types_by_node(
rcl_node_get_rmw_handle(node),
&rcutils_allocator,
node_name,
valid_namespace,
service_names_and_types
);
return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
}

rcl_ret_t
rcl_get_topic_names_and_types(
const rcl_node_t * node,
Expand Down
14 changes: 8 additions & 6 deletions rcl/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,15 @@ function(test_target_function)
AMENT_DEPENDENCIES ${rmw_implementation}
)

set(SKIP_TEST "")
set(AMENT_GTEST_ARGS "")
# TODO(wjwwood): remove this when the graph API works properly for connext dynamic
if(
rmw_implementation STREQUAL "rmw_connext_dynamic_cpp"
)
if(rmw_implementation STREQUAL "rmw_connext_dynamic_cpp")
message(STATUS "Skipping test_graph${target_suffix} test.")
set(SKIP_TEST "SKIP_TEST")
set(AMENT_GTEST_ARGS "SKIP_TEST")
# TODO(mm318): why rmw_connext tests run much slower than rmw_fastrtps and rmw_opensplice tests
elseif(rmw_implementation STREQUAL "rmw_connext_cpp")
message(STATUS "Increasing test_graph${target_suffix} test timeout.")
set(AMENT_GTEST_ARGS TIMEOUT 90)
endif()
rcl_add_custom_gtest(test_graph${target_suffix}
SRCS rcl/test_graph.cpp
Expand All @@ -100,7 +102,7 @@ function(test_target_function)
APPEND_LIBRARY_DIRS ${extra_lib_dirs}
LIBRARIES ${PROJECT_NAME}
AMENT_DEPENDENCIES ${rmw_implementation} "test_msgs"
${SKIP_TEST}
${AMENT_GTEST_ARGS}
)

rcl_add_custom_gtest(test_count_matched${target_suffix}
Expand Down
8 changes: 6 additions & 2 deletions rcl/test/cmake/rcl_add_custom_gtest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ set(rcl_add_custom_gtest_INCLUDED TRUE)
macro(rcl_add_custom_gtest target)
cmake_parse_arguments(_ARG
"SKIP_TEST;TRACE"
""
"TIMEOUT"
"SRCS;ENV;APPEND_ENV;APPEND_LIBRARY_DIRS;INCLUDE_DIRS;LIBRARIES;AMENT_DEPENDENCIES"
${ARGN})
if(_ARG_UNPARSED_ARGUMENTS)
Expand All @@ -69,9 +69,13 @@ macro(rcl_add_custom_gtest target)
else()
set(_ARG_SKIP_TEST "")
endif()
if(_ARG_TIMEOUT)
set(_ARG_TIMEOUT "TIMEOUT" ${_ARG_TIMEOUT})
endif()

# Pass args along to ament_add_gtest().
ament_add_gtest(${target} ${_ARG_SRCS} ${_ARG_ENV} ${_ARG_APPEND_ENV} ${_ARG_APPEND_LIBRARY_DIRS} ${_ARG_SKIP_TEST})
ament_add_gtest(${target} ${_ARG_SRCS} ${_ARG_ENV} ${_ARG_APPEND_ENV} ${_ARG_APPEND_LIBRARY_DIRS}
${_ARG_SKIP_TEST} ${_ARG_TIMEOUT})
# Check if the target was actually created.
if(TARGET ${target})
if(_ARG_TRACE)
Expand Down
Loading

0 comments on commit 8d6fb9a

Please sign in to comment.