Skip to content

Commit

Permalink
Add ~/get_type_description service (rep2011) (#1052)
Browse files Browse the repository at this point in the history
* Add ~/get_type_description service API
* Add node type cache
* Register subscription, publication, service and action types with node type cache
* Add functions to convert between rosidl_runtime_c / type_description_interfaces structs

RCL does not initialize the get_type_description service itself, instead providing a full enough API for full language clients to initialize it and register its callback within their threading/execution framework

Signed-off-by: Hans-Joachim Krauch <[email protected]>
Signed-off-by: Emerson Knapp <[email protected]>
  • Loading branch information
achim-k committed Jul 6, 2023
1 parent 43f8163 commit a4633b8
Show file tree
Hide file tree
Showing 24 changed files with 2,001 additions and 24 deletions.
2 changes: 2 additions & 0 deletions rcl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ set(${PROJECT_NAME}_sources
src/rcl/network_flow_endpoints.c
src/rcl/node.c
src/rcl/node_options.c
src/rcl/node_type_cache.c
src/rcl/publisher.c
src/rcl/remap.c
src/rcl/node_resolve_name.c
Expand All @@ -70,6 +71,7 @@ set(${PROJECT_NAME}_sources
src/rcl/time.c
src/rcl/timer.c
src/rcl/type_hash.c
src/rcl/type_description_conversions.c
src/rcl/validate_enclave_name.c
src/rcl/validate_topic_name.c
src/rcl/wait.c
Expand Down
112 changes: 112 additions & 0 deletions rcl/include/rcl/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ extern "C"
#include "rcl/types.h"
#include "rcl/visibility_control.h"

#include "type_description_interfaces/srv/get_type_description.h"

extern const char * const RCL_DISABLE_LOANED_MESSAGES_ENV_VAR;

typedef struct rcl_node_impl_s rcl_node_impl_t;
typedef struct rcl_service_s rcl_service_t;

/// Structure which encapsulates a ROS Node.
typedef struct rcl_node_s
Expand Down Expand Up @@ -549,6 +552,115 @@ RCL_PUBLIC
rcl_ret_t
rcl_get_disable_loaned_message(bool * disable_loaned_message);

/// Initialize the node's ~/get_type_description service.
/**
* This function initializes the node's ~/get_type_description service
* which can be used to retrieve information about types used by the node's
* publishers, subscribers, services or actions.
*
* Note that this will not register any callback for the service, client-level code
* must register rcl_node_type_description_service_handle_request or a custom callback
* to handle incoming requests, via that client's executor/waitset capabilities.
*
* This will initialize the node's type cache, if it has not been initialized already.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Yes
*
* \param[in] node handle to the node for which to initialize the service
* \return #RCL_RET_OK if the service was successfully initialized, or
* \return #RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* \return #RCL_RET_ALREADY_INIT if the service is already initialized, or
* \return #RCL_RET_BAD_ALLOC if memory allocation for the service failed, or
* \return #RCL_RET_ERROR if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t rcl_node_type_description_service_init(rcl_node_t * node);

/// Finalizes the node's ~/get_type_description service.
/**
* This function finalizes the node's private ~/get_type_description service.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Yes
*
* \param[in] node the handle to the node whose type cache should be initialized
* \return #RCL_RET_OK if service was deinitialized successfully, or
* \return #RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* \return #RCL_RET_SERVICE_INVALID if the service is invalid, or
* \return #RCL_RET_NODE_INVALID if the node is invalid, or
* \return #RCL_RET_ERROR if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t rcl_node_type_description_service_fini(rcl_node_t * node);


/// Returns a pointer to the node's ~/get_type_description service.
/**
* On success, sets service_out to the initialized service.
* rcl_node_type_description_service_init must be called before this.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Yes
*
* \param[in] node the handle to the node
* \param[out] service_out Handle to pointer that will be set
* \return #RCL_RET_OK if valid service was returned successfully, or
* \return #RCL_RET_NODE_INVALID if node is invalid, or
* \return #RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* \return #RCL_RET_NOT_INIT if the service hasn't yet been initialized, or
* \return #RCL_RET_ERROR if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t rcl_node_get_type_description_service(
const rcl_node_t * node,
rcl_service_t ** service_out);


/// Process a single pending request to the GetTypeDescription service.
/**
* This function may be called to handle incoming requests by any client starting the service.
* It is not intended to be called directly by users.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Yes
*
* \param[in] node the handle to the node
* \param[in] request_header ID of the incoming request
* \param[in] request Request that came in to the service
* \param[out] response Allocated, uninitialized response to the request
* \return void
*/
RCL_PUBLIC
void rcl_node_type_description_service_handle_request(
rcl_node_t * node,
const rmw_request_id_t * request_header,
const type_description_interfaces__srv__GetTypeDescription_Request * request,
type_description_interfaces__srv__GetTypeDescription_Response * response);

#ifdef __cplusplus
}
#endif
Expand Down
3 changes: 0 additions & 3 deletions rcl/include/rcl/node_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ typedef struct rcl_node_options_s

/// Middleware quality of service settings for /rosout.
rmw_qos_profile_t rosout_qos;

/// Register the ~/get_type_description service. Defaults to false.
bool enable_type_description_service;
} rcl_node_options_t;

/// Return the default node options in a rcl_node_options_t.
Expand Down
174 changes: 174 additions & 0 deletions rcl/include/rcl/node_type_cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef RCL__NODE_TYPE_CACHE_H_
#define RCL__NODE_TYPE_CACHE_H_

#include "rcl/node.h"
#include "rcl/types.h"
#include "rcl/visibility_control.h"
#include "rosidl_runtime_c/type_description/type_description__struct.h"
#include "rosidl_runtime_c/type_description/type_source__struct.h"
#include "type_description_interfaces/msg/type_description.h"
#include "type_description_interfaces/msg/type_source.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct rcl_type_info_t
{
type_description_interfaces__msg__TypeDescription * type_description;
type_description_interfaces__msg__TypeSource__Sequence * type_sources;
} rcl_type_info_t;

/// Initialize the node's type cache.
/**
* This function initializes hash map of the node's type cache such that types
* can be registered and retrieved.
* Note that to correctly capture all types used by a node, this needs to be called
* before any "builtin" publishers or services are created.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Yes
*
* \param[in] node the handle to the node whose type cache should be initialized
* \return #RCL_RET_OK if the node's type cache was successfully initialized, or
* \return #RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* \return #RCL_RET_NODE_INVALID if the given `node` is invalid, or
* \return #RCL_RET_ERROR if an unspecified error occurs.
*/
RCL_WARN_UNUSED
rcl_ret_t rcl_node_type_cache_init(rcl_node_t * node);

/// Finalize the node's type cache.
/**
* This function clears the hash map of the node's type cache and deallocates
* used memory.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Yes
*
* \param[in] node the handle to the node whose type cache should be finalized
* \return #RCL_RET_OK if the node's type cache was successfully finalized, or
* \return #RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* \return #RCL_RET_NODE_INVALID if the given `node` is invalid, or
* \return #RCL_RET_ERROR if an unspecified error occurs.
*/
RCL_WARN_UNUSED
rcl_ret_t rcl_node_type_cache_fini(rcl_node_t * node);

/// Register a type with the node's type cache.
/**
* This function registers the given type, uniquely identified by the type_hash,
* with the node with the node's type cache. Multiple registrations of the same
* type will increment its registration count.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Yes
*
* \param[in] node the handle to the node whose type cache should be finalized
* \param[in] type_hash hash of the type
* \param[in] type_description type description struct
* \param[in] type_description_sources type description sources struct
* \return #RCL_RET_OK if the type was successfully registered, or
* \return #RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* \return #RCL_RET_NODE_INVALID if the given `node` is invalid, or
* \return #RCL_RET_ERROR if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t rcl_node_type_cache_register_type(
const rcl_node_t * node, const rosidl_type_hash_t * type_hash,
const rosidl_runtime_c__type_description__TypeDescription * type_description,
const rosidl_runtime_c__type_description__TypeSource__Sequence * type_description_sources
);

/// Unregister a message type from the node's type cache.
/**
* This function uses the given `type_hash` to unregister the associated type in
* the node's type cache. If the type has been registered multiple times, the
* type will only be removed if its registration count reaches 0.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Yes
*
* \param[in] node the handle to the node whose type cache should be finalized
* \param[in] type_hash type hash
* \return #RCL_RET_OK if the type was successfully registered, or
* \return #RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* \return #RCL_RET_NODE_INVALID if the given `node` is invalid, or
* \return #RCL_RET_ERROR if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t rcl_node_type_cache_unregister_type(
const rcl_node_t * node, const rosidl_type_hash_t * type_hash);

/// Retrieve type information from the node's type cache.
/**
* This function returns the desired type information from the node's type cache
*
* The `type_info` field must point to an allocated `rcl_type_info_t` object to
* which the type information will be written.
*
* <hr>
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No
* Uses Atomics | No
* Lock-Free | Yes
*
* \param[in] node the handle to the node whose type cache should be queried
* \param[in] type_hash type hash
* \param[out] type_info pointer to the type info struct that will be populated
* \return #RCL_RET_OK if type information was retrieved successfully
* \return #RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* \return #RCL_RET_NODE_INVALID if the given `node` is invalid, or
* \return #RCL_RET_NOT_INIT if node's type cache has not been initialized, or
* \return #RCL_RET_ERROR if an unspecified error occurs.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t rcl_node_type_cache_get_type_info(
const rcl_node_t * node,
const rosidl_type_hash_t * type_hash,
rcl_type_info_t * type_info);

#ifdef __cplusplus
}
#endif

#endif // RCL__NODE_TYPE_CACHE_H_
Loading

0 comments on commit a4633b8

Please sign in to comment.