Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add node graph api to rcl #333

Merged
merged 1 commit into from
Dec 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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