diff --git a/rcl/include/rcl/client.h b/rcl/include/rcl/client.h index 94290982a..224f74b8c 100644 --- a/rcl/include/rcl/client.h +++ b/rcl/include/rcl/client.h @@ -24,6 +24,7 @@ extern "C" #include "rosidl_runtime_c/service_type_support_struct.h" +#include "rcl/event_callback.h" #include "rcl/macros.h" #include "rcl/node.h" #include "rcl/visibility_control.h" @@ -461,6 +462,37 @@ RCL_WARN_UNUSED const rmw_qos_profile_t * rcl_client_response_subscription_get_actual_qos(const rcl_client_t * client); +/// Set the on new response callback function for the client. +/** + * This API sets the callback function to be called whenever the + * client is notified about a new response. + * + * \sa rmw_client_set_on_new_response_callback for details about this function. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] rmw implementation defined + * + * \param[in] client The client on which to set the callback + * \param[in] callback The callback to be called when new responses arrive, may be NULL + * \param[in] user_data Given to the callback when called later, may be NULL + * \return `RCL_RET_OK` if callback was set to the listener, or + * \return `RCL_RET_INVALID_ARGUMENT` if `client` is NULL, or + * \return `RCL_RET_UNSUPPORTED` if the API is not implemented in the dds implementation + */ +RCL_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_client_set_on_new_response_callback( + const rcl_client_t * client, + rcl_event_callback_t callback, + const void * user_data); + #ifdef __cplusplus } #endif diff --git a/rcl/include/rcl/event.h b/rcl/include/rcl/event.h index abf4e6386..fea87d782 100644 --- a/rcl/include/rcl/event.h +++ b/rcl/include/rcl/event.h @@ -25,6 +25,7 @@ extern "C" #include #include "rcl/client.h" +#include "rcl/event_callback.h" #include "rcl/macros.h" #include "rcl/publisher.h" #include "rcl/service.h" @@ -198,6 +199,37 @@ RCL_PUBLIC bool rcl_event_is_valid(const rcl_event_t * event); +/// Set the callback function for the event. +/** + * This API sets the callback function to be called whenever the + * event is notified about a new instance of the event. + * + * \sa rmw_event_set_callback for more details about this function. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] rmw implementation defined + * + * \param[in] event The event on which to set the callback + * \param[in] callback The callback to be called when new events occur, may be NULL + * \param[in] user_data Given to the callback when called later, may be NULL + * \return `RCL_RET_OK` if callback was set to the listener, or + * \return `RCL_RET_INVALID_ARGUMENT` if `event` is NULL, or + * \return `RCL_RET_UNSUPPORTED` if the API is not implemented in the dds implementation + */ +RCL_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_event_set_callback( + const rcl_event_t * event, + rcl_event_callback_t callback, + const void * user_data); + #ifdef __cplusplus } #endif diff --git a/rcl/include/rcl/event_callback.h b/rcl/include/rcl/event_callback.h new file mode 100644 index 000000000..9124907ab --- /dev/null +++ b/rcl/include/rcl/event_callback.h @@ -0,0 +1,31 @@ +// Copyright 2021 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__EVENT_CALLBACK_H_ +#define RCL__EVENT_CALLBACK_H_ + +#include "rmw/event_callback_type.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef rmw_event_callback_t rcl_event_callback_t; + +#ifdef __cplusplus +} +#endif + +#endif // RCL__EVENT_CALLBACK_H_ diff --git a/rcl/include/rcl/service.h b/rcl/include/rcl/service.h index b102d14c9..2461bd551 100644 --- a/rcl/include/rcl/service.h +++ b/rcl/include/rcl/service.h @@ -24,6 +24,7 @@ extern "C" #include "rosidl_runtime_c/service_type_support_struct.h" +#include "rcl/event_callback.h" #include "rcl/macros.h" #include "rcl/node.h" #include "rcl/visibility_control.h" @@ -492,6 +493,37 @@ RCL_WARN_UNUSED const rmw_qos_profile_t * rcl_service_response_publisher_get_actual_qos(const rcl_service_t * service); +/// Set the on new request callback function for the service. +/** + * This API sets the callback function to be called whenever the + * service is notified about a new request. + * + * \sa rmw_service_set_on_new_request_callback for details about this function. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] rmw implementation defined + * + * \param[in] service The service on which to set the callback + * \param[in] callback The callback to be called when new requests arrive, may be NULL + * \param[in] user_data Given to the callback when called later, may be NULL + * \return `RCL_RET_OK` if callback was set to the listener, or + * \return `RCL_RET_INVALID_ARGUMENT` if `service` is NULL, or + * \return `RCL_RET_UNSUPPORTED` if the API is not implemented in the dds implementation + */ +RCL_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_service_set_on_new_request_callback( + const rcl_service_t * service, + rcl_event_callback_t callback, + const void * user_data); + #ifdef __cplusplus } #endif diff --git a/rcl/include/rcl/subscription.h b/rcl/include/rcl/subscription.h index 09d6e6bc4..121949999 100644 --- a/rcl/include/rcl/subscription.h +++ b/rcl/include/rcl/subscription.h @@ -24,6 +24,7 @@ extern "C" #include "rosidl_runtime_c/message_type_support_struct.h" +#include "rcl/event_callback.h" #include "rcl/macros.h" #include "rcl/node.h" #include "rcl/visibility_control.h" @@ -611,6 +612,38 @@ RCL_PUBLIC bool rcl_subscription_can_loan_messages(const rcl_subscription_t * subscription); +/// Set the on new message callback function for the subscription. +/** + * This API sets the callback function to be called whenever the + * subscription is notified about a new message. + * + * \sa rmw_subscription_set_on_new_message_callback for details about this + * function. + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | Maybe [1] + * Lock-Free | Maybe [1] + * [1] rmw implementation defined + * + * \param[in] subscription The subscription on which to set the callback + * \param[in] callback The callback to be called when new messages arrive, may be NULL + * \param[in] user_data Given to the callback when called later, may be NULL + * \return `RCL_RET_OK` if successful, or + * \return `RCL_RET_INVALID_ARGUMENT` if `subscription` is NULL, or + * \return `RCL_RET_UNSUPPORTED` if the API is not implemented in the dds implementation + */ +RCL_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_subscription_set_on_new_message_callback( + const rcl_subscription_t * subscription, + rcl_event_callback_t callback, + const void * user_data); + #ifdef __cplusplus } #endif diff --git a/rcl/src/rcl/client.c b/rcl/src/rcl/client.c index bd38efa7a..432948d59 100644 --- a/rcl/src/rcl/client.c +++ b/rcl/src/rcl/client.c @@ -327,6 +327,24 @@ rcl_client_response_subscription_get_actual_qos(const rcl_client_t * client) } return &client->impl->actual_response_subscription_qos; } + +rcl_ret_t +rcl_client_set_on_new_response_callback( + const rcl_client_t * client, + rcl_event_callback_t callback, + const void * user_data) +{ + if (!rcl_client_is_valid(client)) { + // error state already set + return RCL_RET_INVALID_ARGUMENT; + } + + return rmw_client_set_on_new_response_callback( + client->impl->rmw_handle, + callback, + user_data); +} + #ifdef __cplusplus } #endif diff --git a/rcl/src/rcl/event.c b/rcl/src/rcl/event.c index c79c60ce6..6196442d1 100644 --- a/rcl/src/rcl/event.c +++ b/rcl/src/rcl/event.c @@ -218,6 +218,23 @@ rcl_event_is_valid(const rcl_event_t * event) return true; } +rcl_ret_t +rcl_event_set_callback( + const rcl_event_t * event, + rcl_event_callback_t callback, + const void * user_data) +{ + if (!rcl_event_is_valid(event)) { + // error state already set + return RCL_RET_INVALID_ARGUMENT; + } + + return rmw_event_set_callback( + &event->impl->rmw_handle, + callback, + user_data); +} + #ifdef __cplusplus } #endif diff --git a/rcl/src/rcl/service.c b/rcl/src/rcl/service.c index 42222b996..e1bdb0174 100644 --- a/rcl/src/rcl/service.c +++ b/rcl/src/rcl/service.c @@ -346,6 +346,23 @@ rcl_service_response_publisher_get_actual_qos(const rcl_service_t * service) return &service->impl->actual_response_publisher_qos; } +rcl_ret_t +rcl_service_set_on_new_request_callback( + const rcl_service_t * service, + rcl_event_callback_t callback, + const void * user_data) +{ + if (!rcl_service_is_valid(service)) { + // error state already set + return RCL_RET_INVALID_ARGUMENT; + } + + return rmw_service_set_on_new_request_callback( + service->impl->rmw_handle, + callback, + user_data); +} + #ifdef __cplusplus } #endif diff --git a/rcl/src/rcl/subscription.c b/rcl/src/rcl/subscription.c index d92fe21a4..32c3ca767 100644 --- a/rcl/src/rcl/subscription.c +++ b/rcl/src/rcl/subscription.c @@ -445,6 +445,23 @@ rcl_subscription_can_loan_messages(const rcl_subscription_t * subscription) return subscription->impl->rmw_handle->can_loan_messages; } +rcl_ret_t +rcl_subscription_set_on_new_message_callback( + const rcl_subscription_t * subscription, + rcl_event_callback_t callback, + const void * user_data) +{ + if (!rcl_subscription_is_valid(subscription)) { + // error state already set + return RCL_RET_INVALID_ARGUMENT; + } + + return rmw_subscription_set_on_new_message_callback( + subscription->impl->rmw_handle, + callback, + user_data); +} + #ifdef __cplusplus } #endif diff --git a/rcl_action/include/rcl_action/action_client.h b/rcl_action/include/rcl_action/action_client.h index 7fdf6df78..b686b65f1 100644 --- a/rcl_action/include/rcl_action/action_client.h +++ b/rcl_action/include/rcl_action/action_client.h @@ -22,6 +22,7 @@ extern "C" #include "rcl_action/types.h" #include "rcl_action/visibility_control.h" +#include "rcl/event_callback.h" #include "rcl/macros.h" #include "rcl/node.h" @@ -741,6 +742,46 @@ bool rcl_action_client_is_valid( const rcl_action_client_t * action_client); +RCL_ACTION_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_action_client_set_goal_client_callback( + const rcl_action_client_t * action_client, + rcl_event_callback_t callback, + const void * user_data); + +RCL_ACTION_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_action_client_set_cancel_client_callback( + const rcl_action_client_t * action_client, + rcl_event_callback_t callback, + const void * user_data); + +RCL_ACTION_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_action_client_set_result_client_callback( + const rcl_action_client_t * action_client, + rcl_event_callback_t callback, + const void * user_data); + +RCL_ACTION_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_action_client_set_feedback_subscription_callback( + const rcl_action_client_t * action_client, + rcl_event_callback_t callback, + const void * user_data); + +RCL_ACTION_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_action_client_set_status_subscription_callback( + const rcl_action_client_t * action_client, + rcl_event_callback_t callback, + const void * user_data); + #ifdef __cplusplus } #endif diff --git a/rcl_action/include/rcl_action/action_server.h b/rcl_action/include/rcl_action/action_server.h index d0d9a8e3a..eb4f95ce9 100644 --- a/rcl_action/include/rcl_action/action_server.h +++ b/rcl_action/include/rcl_action/action_server.h @@ -23,6 +23,7 @@ extern "C" #include "rcl_action/goal_handle.h" #include "rcl_action/types.h" #include "rcl_action/visibility_control.h" +#include "rcl/event_callback.h" #include "rcl/macros.h" #include "rcl/node.h" #include "rcl/time.h" @@ -930,6 +931,30 @@ RCL_WARN_UNUSED bool rcl_action_server_is_valid_except_context(const rcl_action_server_t * action_server); +RCL_ACTION_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_action_server_set_goal_service_callback( + const rcl_action_server_t * action_server, + rcl_event_callback_t callback, + const void * user_data); + +RCL_ACTION_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_action_server_set_cancel_service_callback( + const rcl_action_server_t * action_server, + rcl_event_callback_t callback, + const void * user_data); + +RCL_ACTION_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_action_server_set_result_service_callback( + const rcl_action_server_t * action_server, + rcl_event_callback_t callback, + const void * user_data); + #ifdef __cplusplus } #endif diff --git a/rcl_action/src/rcl_action/action_client.c b/rcl_action/src/rcl_action/action_client.c index a03a61ec3..d999f1e01 100644 --- a/rcl_action/src/rcl_action/action_client.c +++ b/rcl_action/src/rcl_action/action_client.c @@ -649,6 +649,86 @@ rcl_action_client_wait_set_get_entities_ready( return RCL_RET_OK; } +rcl_ret_t +rcl_action_client_set_goal_client_callback( + const rcl_action_client_t * action_client, + rcl_event_callback_t callback, + const void * user_data) +{ + if (!rcl_action_client_is_valid(action_client)) { + return RCL_RET_ACTION_CLIENT_INVALID; + } + + return rcl_client_set_on_new_response_callback( + &action_client->impl->goal_client, + callback, + user_data); +} + +rcl_ret_t +rcl_action_client_set_cancel_client_callback( + const rcl_action_client_t * action_client, + rcl_event_callback_t callback, + const void * user_data) +{ + if (!rcl_action_client_is_valid(action_client)) { + return RCL_RET_ACTION_CLIENT_INVALID; + } + + return rcl_client_set_on_new_response_callback( + &action_client->impl->cancel_client, + callback, + user_data); +} + +rcl_ret_t +rcl_action_client_set_result_client_callback( + const rcl_action_client_t * action_client, + rcl_event_callback_t callback, + const void * user_data) +{ + if (!rcl_action_client_is_valid(action_client)) { + return RCL_RET_ACTION_CLIENT_INVALID; + } + + return rcl_client_set_on_new_response_callback( + &action_client->impl->result_client, + callback, + user_data); +} + +rcl_ret_t +rcl_action_client_set_feedback_subscription_callback( + const rcl_action_client_t * action_client, + rcl_event_callback_t callback, + const void * user_data) +{ + if (!rcl_action_client_is_valid(action_client)) { + return RCL_RET_ACTION_CLIENT_INVALID; + } + + return rcl_subscription_set_on_new_message_callback( + &action_client->impl->feedback_subscription, + callback, + user_data); +} + +rcl_ret_t +rcl_action_client_set_status_subscription_callback( + const rcl_action_client_t * action_client, + rcl_event_callback_t callback, + const void * user_data) +{ + if (!rcl_action_client_is_valid(action_client)) { + return RCL_RET_ACTION_CLIENT_INVALID; + } + + return rcl_subscription_set_on_new_message_callback( + &action_client->impl->status_subscription, + callback, + user_data); +} + #ifdef __cplusplus } #endif diff --git a/rcl_action/src/rcl_action/action_server.c b/rcl_action/src/rcl_action/action_server.c index a5b6dbde4..63580c40f 100644 --- a/rcl_action/src/rcl_action/action_server.c +++ b/rcl_action/src/rcl_action/action_server.c @@ -1054,6 +1054,60 @@ rcl_action_server_wait_set_get_entities_ready( return RCL_RET_OK; } +RCL_ACTION_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_action_server_set_goal_service_callback( + const rcl_action_server_t * action_server, + rcl_event_callback_t callback, + const void * user_data) +{ + if (!rcl_action_server_is_valid_except_context(action_server)) { + return RCL_RET_ACTION_SERVER_INVALID; + } + + return rcl_service_set_on_new_request_callback( + &action_server->impl->goal_service, + callback, + user_data); +} + +RCL_ACTION_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_action_server_set_result_service_callback( + const rcl_action_server_t * action_server, + rcl_event_callback_t callback, + const void * user_data) +{ + if (!rcl_action_server_is_valid_except_context(action_server)) { + return RCL_RET_ACTION_SERVER_INVALID; + } + + return rcl_service_set_on_new_request_callback( + &action_server->impl->result_service, + callback, + user_data); +} + +RCL_ACTION_PUBLIC +RCL_WARN_UNUSED +rcl_ret_t +rcl_action_server_set_cancel_service_callback( + const rcl_action_server_t * action_server, + rcl_event_callback_t callback, + const void * user_data) +{ + if (!rcl_action_server_is_valid_except_context(action_server)) { + return RCL_RET_ACTION_SERVER_INVALID; + } + + return rcl_service_set_on_new_request_callback( + &action_server->impl->cancel_service, + callback, + user_data); +} + #ifdef __cplusplus } #endif