rclcpp  master
C++ ROS Client Library API
service.hpp
Go to the documentation of this file.
1 // Copyright 2014 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef RCLCPP__SERVICE_HPP_
16 #define RCLCPP__SERVICE_HPP_
17 
18 #include <atomic>
19 #include <functional>
20 #include <iostream>
21 #include <memory>
22 #include <sstream>
23 #include <string>
24 
25 #include "rcl/error_handling.h"
26 #include "rcl/service.h"
27 
29 #include "rclcpp/exceptions.hpp"
30 #include "rclcpp/macros.hpp"
34 #include "rclcpp/logging.hpp"
35 #include "rmw/error_handling.h"
36 #include "rmw/rmw.h"
37 #include "tracetools/tracetools.h"
38 
39 namespace rclcpp
40 {
41 
43 {
44 public:
46 
48  explicit ServiceBase(std::shared_ptr<rcl_node_t> node_handle);
49 
51  virtual ~ServiceBase();
52 
54 
56  const char *
58 
60 
67 
69 
75  get_service_handle() const;
76 
78 
93  bool
94  take_type_erased_request(void * request_out, rmw_request_id_t & request_id_out);
95 
96  virtual
98  create_request() = 0;
99 
100  virtual
102  create_request_header() = 0;
103 
104  virtual
105  void
107  std::shared_ptr<rmw_request_id_t> request_header,
108  std::shared_ptr<void> request) = 0;
109 
111 
121  bool
122  exchange_in_use_by_wait_set_state(bool in_use_state);
123 
124 protected:
126 
128  rcl_node_t *
130 
132  const rcl_node_t *
133  get_rcl_node_handle() const;
134 
136 
138  bool owns_rcl_handle_ = true;
139 
141 };
142 
143 template<typename ServiceT>
144 class Service : public ServiceBase
145 {
146 public:
147  using CallbackType = std::function<
148  void (
151 
153  void (
158 
159 
160 
171  std::shared_ptr<rcl_node_t> node_handle,
172  const std::string & service_name,
173  AnyServiceCallback<ServiceT> any_callback,
174  rcl_service_options_t & service_options)
175  : ServiceBase(node_handle), any_callback_(any_callback)
176  {
177  using rosidl_typesupport_cpp::get_service_type_support_handle;
178  auto service_type_support_handle = get_service_type_support_handle<ServiceT>();
179 
180  // rcl does the static memory allocation here
182  new rcl_service_t, [handle = node_handle_, service_name](rcl_service_t * service)
183  {
184  if (rcl_service_fini(service, handle.get()) != RCL_RET_OK) {
185  RCLCPP_ERROR(
186  rclcpp::get_node_logger(handle.get()).get_child("rclcpp"),
187  "Error in destruction of rcl service handle: %s",
188  rcl_get_error_string().str);
189  rcl_reset_error();
190  }
191  delete service;
192  });
194 
197  node_handle.get(),
198  service_type_support_handle,
199  service_name.c_str(),
200  &service_options);
201  if (ret != RCL_RET_OK) {
202  if (ret == RCL_RET_SERVICE_NAME_INVALID) {
203  auto rcl_node_handle = get_rcl_node_handle();
204  // this will throw on any validation problem
205  rcl_reset_error();
207  service_name,
208  rcl_node_get_name(rcl_node_handle),
209  rcl_node_get_namespace(rcl_node_handle),
210  true);
211  }
212 
213  rclcpp::exceptions::throw_from_rcl_error(ret, "could not create service");
214  }
215  TRACEPOINT(
216  rclcpp_service_callback_added,
217  static_cast<const void *>(get_service_handle().get()),
218  static_cast<const void *>(&any_callback_));
219 #ifndef TRACETOOLS_DISABLED
220  any_callback_.register_callback_for_tracing();
221 #endif
222  }
223 
225 
235  std::shared_ptr<rcl_node_t> node_handle,
236  std::shared_ptr<rcl_service_t> service_handle,
237  AnyServiceCallback<ServiceT> any_callback)
238  : ServiceBase(node_handle),
239  any_callback_(any_callback)
240  {
241  // check if service handle was initialized
242  if (!rcl_service_is_valid(service_handle.get())) {
243  // *INDENT-OFF* (prevent uncrustify from making unnecessary indents here)
244  throw std::runtime_error(
245  std::string("rcl_service_t in constructor argument must be initialized beforehand."));
246  // *INDENT-ON*
247  }
248 
249  service_handle_ = service_handle;
250  TRACEPOINT(
251  rclcpp_service_callback_added,
252  static_cast<const void *>(get_service_handle().get()),
253  static_cast<const void *>(&any_callback_));
254 #ifndef TRACETOOLS_DISABLED
255  any_callback_.register_callback_for_tracing();
256 #endif
257  }
258 
260 
270  std::shared_ptr<rcl_node_t> node_handle,
271  rcl_service_t * service_handle,
272  AnyServiceCallback<ServiceT> any_callback)
273  : ServiceBase(node_handle),
274  any_callback_(any_callback)
275  {
276  // check if service handle was initialized
277  if (!rcl_service_is_valid(service_handle)) {
278  // *INDENT-OFF* (prevent uncrustify from making unnecessary indents here)
279  throw std::runtime_error(
280  std::string("rcl_service_t in constructor argument must be initialized beforehand."));
281  // *INDENT-ON*
282  }
283 
284  // In this case, rcl owns the service handle memory
286  service_handle_->impl = service_handle->impl;
287  TRACEPOINT(
288  rclcpp_service_callback_added,
289  static_cast<const void *>(get_service_handle().get()),
290  static_cast<const void *>(&any_callback_));
291 #ifndef TRACETOOLS_DISABLED
292  any_callback_.register_callback_for_tracing();
293 #endif
294  }
295 
296  Service() = delete;
297 
298  virtual ~Service()
299  {
300  }
301 
303 
314  bool
315  take_request(typename ServiceT::Request & request_out, rmw_request_id_t & request_id_out)
316  {
317  return this->take_type_erased_request(&request_out, request_id_out);
318  }
319 
321  create_request() override
322  {
323  return std::make_shared<typename ServiceT::Request>();
324  }
325 
328  {
329  return std::make_shared<rmw_request_id_t>();
330  }
331 
332  void
334  std::shared_ptr<rmw_request_id_t> request_header,
335  std::shared_ptr<void> request) override
336  {
337  auto typed_request = std::static_pointer_cast<typename ServiceT::Request>(request);
338  auto response = std::make_shared<typename ServiceT::Response>();
339  any_callback_.dispatch(request_header, typed_request, response);
340  send_response(*request_header, *response);
341  }
342 
343  void
344  send_response(rmw_request_id_t & req_id, typename ServiceT::Response & response)
345  {
346  rcl_ret_t ret = rcl_send_response(get_service_handle().get(), &req_id, &response);
347 
348  if (ret != RCL_RET_OK) {
349  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send response");
350  }
351  }
352 
353 private:
355 
356  AnyServiceCallback<ServiceT> any_callback_;
357 };
358 
359 } // namespace rclcpp
360 
361 #endif // RCLCPP__SERVICE_HPP_
rclcpp::ServiceBase::handle_request
virtual void handle_request(std::shared_ptr< rmw_request_id_t > request_header, std::shared_ptr< void > request)=0
rcl_node_t
rcl_node_get_name
const char * rcl_node_get_name(const rcl_node_t *node)
RCL_RET_SERVICE_NAME_INVALID
#define RCL_RET_SERVICE_NAME_INVALID
exceptions.hpp
rclcpp::AnyServiceCallback
Definition: any_service_callback.hpp:33
rcl_service_t::impl
struct rcl_service_impl_t * impl
std::string
std::shared_ptr< rcl_node_t >
rcl_node_get_namespace
const char * rcl_node_get_namespace(const rcl_node_t *node)
RCLCPP_DISABLE_COPY
#define RCLCPP_DISABLE_COPY(...)
Definition: macros.hpp:26
rclcpp::ServiceBase::~ServiceBase
virtual ~ServiceBase()
rmw.h
rcl_ret_t
rmw_ret_t rcl_ret_t
rclcpp::ServiceBase::owns_rcl_handle_
bool owns_rcl_handle_
Definition: service.hpp:138
rcl_service_options_t
error_handling.h
rcl_service_init
rcl_ret_t rcl_service_init(rcl_service_t *service, const rcl_node_t *node, const rosidl_service_type_support_t *type_support, const char *service_name, const rcl_service_options_t *options)
rclcpp::Service
Definition: service.hpp:144
service.h
std::shared_ptr::get
T get(T... args)
std::function< void(const std::shared_ptr< typename ServiceT::Request >, std::shared_ptr< typename ServiceT::Response >)>
rclcpp::Service::Service
Service()=delete
rclcpp::Service::send_response
void send_response(rmw_request_id_t &req_id, typename ServiceT::Response &response)
Definition: service.hpp:344
rclcpp::Service::Service
Service(std::shared_ptr< rcl_node_t > node_handle, std::shared_ptr< rcl_service_t > service_handle, AnyServiceCallback< ServiceT > any_callback)
Default constructor.
Definition: service.hpp:234
rclcpp
This header provides the get_node_base_interface() template function.
Definition: allocator_common.hpp:24
rclcpp::ServiceBase::service_handle_
std::shared_ptr< rcl_service_t > service_handle_
Definition: service.hpp:137
RCLCPP_PUBLIC
#define RCLCPP_PUBLIC
Definition: visibility_control.hpp:50
rclcpp::Service::create_request
std::shared_ptr< void > create_request() override
Definition: service.hpp:321
rclcpp::ServiceBase::create_request_header
virtual std::shared_ptr< rmw_request_id_t > create_request_header()=0
rclcpp::Service::~Service
virtual ~Service()
Definition: service.hpp:298
RCLCPP_SMART_PTR_DEFINITIONS
#define RCLCPP_SMART_PTR_DEFINITIONS(...)
Definition: macros.hpp:36
macros.hpp
rclcpp::ServiceBase::get_service_name
const char * get_service_name()
Return the name of the service.
rclcpp::expand_topic_or_service_name
std::string expand_topic_or_service_name(const std::string &name, const std::string &node_name, const std::string &namespace_, bool is_service=false)
Expand a topic or service name and throw if it is not valid.
logging.hpp
rcl_send_response
rcl_ret_t rcl_send_response(const rcl_service_t *service, rmw_request_id_t *response_header, void *ros_response)
any_service_callback.hpp
expand_topic_or_service_name.hpp
rmw_request_id_t
std::runtime_error
std::atomic< bool >
rclcpp::ServiceBase::ServiceBase
ServiceBase(std::shared_ptr< rcl_node_t > node_handle)
rclcpp::ServiceBase::exchange_in_use_by_wait_set_state
bool exchange_in_use_by_wait_set_state(bool in_use_state)
Exchange the "in use by wait set" state for this service.
rcl_service_fini
rcl_ret_t rcl_service_fini(rcl_service_t *service, rcl_node_t *node)
rclcpp::Service::Service
Service(std::shared_ptr< rcl_node_t > node_handle, rcl_service_t *service_handle, AnyServiceCallback< ServiceT > any_callback)
Default constructor.
Definition: service.hpp:269
rclcpp::ServiceBase::get_service_handle
std::shared_ptr< rcl_service_t > get_service_handle()
Return the rcl_service_t service handle in a std::shared_ptr.
type_support_decl.hpp
rclcpp::Service::handle_request
void handle_request(std::shared_ptr< rmw_request_id_t > request_header, std::shared_ptr< void > request) override
Definition: service.hpp:333
visibility_control.hpp
std
rclcpp::ServiceBase::create_request
virtual std::shared_ptr< void > create_request()=0
rclcpp::ServiceBase::in_use_by_wait_set_
std::atomic< bool > in_use_by_wait_set_
Definition: service.hpp:140
rclcpp::ServiceBase::node_handle_
std::shared_ptr< rcl_node_t > node_handle_
Definition: service.hpp:135
rclcpp::ServiceBase::get_rcl_node_handle
rcl_node_t * get_rcl_node_handle()
rclcpp::Service::create_request_header
std::shared_ptr< rmw_request_id_t > create_request_header() override
Definition: service.hpp:327
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE
#define RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(...)
Definition: macros.hpp:51
rclcpp::exceptions::throw_from_rcl_error
void throw_from_rcl_error(rcl_ret_t ret, const std::string &prefix="", const rcl_error_state_t *error_state=nullptr, void(*reset_error)()=rcl_reset_error)
Throw a C++ std::exception which was created based on an rcl error.
rcl_service_t
rcl_get_zero_initialized_service
rcl_service_t rcl_get_zero_initialized_service(void)
RCL_RET_OK
#define RCL_RET_OK
rclcpp::ServiceBase
Definition: service.hpp:42
rclcpp::ServiceBase::take_type_erased_request
bool take_type_erased_request(void *request_out, rmw_request_id_t &request_id_out)
Take the next request from the service as a type erased pointer.
rcl_service_is_valid
bool rcl_service_is_valid(const rcl_service_t *service)
rclcpp::Service::take_request
bool take_request(typename ServiceT::Request &request_out, rmw_request_id_t &request_id_out)
Take the next request from the service.
Definition: service.hpp:315