ROS 2 rclcpp + rcl - jazzy  jazzy
ROS 2 C++ Client Library with ROS Client Library
client.c
1 // Copyright 2016 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 #ifdef __cplusplus
16 extern "C"
17 {
18 #endif
19 
20 #include "rcl/client.h"
21 
22 #include <stdio.h>
23 #include <string.h>
24 
25 #include "rcl/error_handling.h"
26 #include "rcl/node.h"
27 #include "rcl/node_type_cache.h"
28 #include "rcl/publisher.h"
29 #include "rcl/time.h"
30 #include "rcutils/logging_macros.h"
31 #include "rcutils/macros.h"
32 #include "rcutils/stdatomic_helper.h"
33 #include "rmw/error_handling.h"
34 #include "rmw/rmw.h"
35 #include "service_msgs/msg/service_event_info.h"
36 #include "tracetools/tracetools.h"
37 
38 #include "rosidl_runtime_c/service_type_support_struct.h"
39 
40 #include "./common.h"
41 #include "./service_event_publisher.h"
42 
44 {
45  rcl_client_options_t options;
46  rmw_qos_profile_t actual_request_publisher_qos;
47  rmw_qos_profile_t actual_response_subscription_qos;
48  rmw_client_t * rmw_handle;
49  atomic_int_least64_t sequence_number;
50  rcl_service_event_publisher_t * service_event_publisher;
51  char * remapped_service_name;
52  rosidl_type_hash_t type_hash;
53 };
54 
57 {
58  static rcl_client_t null_client = {0};
59  return null_client;
60 }
61 
62 static
64 unconfigure_service_introspection(
65  rcl_node_t * node,
66  struct rcl_client_impl_s * client_impl,
67  rcl_allocator_t * allocator)
68 {
69  if (client_impl == NULL) {
70  return RCL_RET_ERROR;
71  }
72 
73  if (client_impl->service_event_publisher == NULL) {
74  return RCL_RET_OK;
75  }
76 
77  rcl_ret_t ret = rcl_service_event_publisher_fini(client_impl->service_event_publisher, node);
78 
79  allocator->deallocate(client_impl->service_event_publisher, allocator->state);
80  client_impl->service_event_publisher = NULL;
81 
82  return ret;
83 }
84 
87  rcl_client_t * client,
88  const rcl_node_t * node,
89  const rosidl_service_type_support_t * type_support,
90  const char * service_name,
91  const rcl_client_options_t * options)
92 {
93  // check the options and allocator first, so the allocator can be passed to errors
94  RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT);
95  rcl_allocator_t * allocator = (rcl_allocator_t *)&options->allocator;
96  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
97  RCL_CHECK_ARGUMENT_FOR_NULL(client, RCL_RET_INVALID_ARGUMENT);
98  if (!rcl_node_is_valid(node)) {
99  return RCL_RET_NODE_INVALID; // error already set
100  }
101  RCL_CHECK_ARGUMENT_FOR_NULL(type_support, RCL_RET_INVALID_ARGUMENT);
102  RCL_CHECK_ARGUMENT_FOR_NULL(service_name, RCL_RET_INVALID_ARGUMENT);
103  RCUTILS_LOG_DEBUG_NAMED(
104  ROS_PACKAGE_NAME, "Initializing client for service name '%s'", service_name);
105  if (client->impl) {
106  RCL_SET_ERROR_MSG("client already initialized, or memory was unintialized");
107  return RCL_RET_ALREADY_INIT;
108  }
109 
110  // Allocate space for the implementation struct.
111  client->impl = (rcl_client_impl_t *)allocator->zero_allocate(
112  1, sizeof(rcl_client_impl_t), allocator->state);
113  RCL_CHECK_FOR_NULL_WITH_MSG(
114  client->impl, "allocating memory failed",
115  return RCL_RET_BAD_ALLOC;);
116 
117  // Expand the given service name.
119  node,
120  service_name,
121  *allocator,
122  true,
123  false,
124  &client->impl->remapped_service_name);
125  if (ret != RCL_RET_OK) {
128  } else if (RCL_RET_BAD_ALLOC != ret) {
129  ret = RCL_RET_ERROR;
130  }
131  goto free_client_impl;
132  }
133  RCUTILS_LOG_DEBUG_NAMED(
134  ROS_PACKAGE_NAME, "Expanded and remapped service name '%s'",
135  client->impl->remapped_service_name);
136 
137  // Fill out implementation struct.
138  // rmw handle (create rmw client)
139  // TODO(wjwwood): pass along the allocator to rmw when it supports it
140  client->impl->rmw_handle = rmw_create_client(
142  type_support,
143  client->impl->remapped_service_name,
144  &options->qos);
145  if (!client->impl->rmw_handle) {
146  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
147  ret = RCL_RET_ERROR;
148  goto free_remapped_service_name;
149  }
150 
151  // get actual qos, and store it
152  rmw_ret_t rmw_ret = rmw_client_request_publisher_get_actual_qos(
153  client->impl->rmw_handle,
154  &client->impl->actual_request_publisher_qos);
155  if (RMW_RET_OK != rmw_ret) {
156  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
157  ret = rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
158  goto destroy_client;
159  }
160 
161  rmw_ret = rmw_client_response_subscription_get_actual_qos(
162  client->impl->rmw_handle,
163  &client->impl->actual_response_subscription_qos);
164  if (RMW_RET_OK != rmw_ret) {
165  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
166  ret = rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
167  goto destroy_client;
168  }
169 
170  // ROS specific namespacing conventions avoidance
171  // is not retrieved by get_actual_qos
172  client->impl->actual_request_publisher_qos.avoid_ros_namespace_conventions =
173  options->qos.avoid_ros_namespace_conventions;
174  client->impl->actual_response_subscription_qos.avoid_ros_namespace_conventions =
175  options->qos.avoid_ros_namespace_conventions;
176 
177  // options
178  client->impl->options = *options;
179  atomic_init(&client->impl->sequence_number, 0);
180 
181  const rosidl_type_hash_t * hash = type_support->get_type_hash_func(type_support);
182  if (hash == NULL) {
183  RCL_SET_ERROR_MSG("Failed to get the type hash");
185  goto destroy_client;
186  }
187 
188  if (RCL_RET_OK != rcl_node_type_cache_register_type(
189  node, hash, type_support->get_type_description_func(type_support),
190  type_support->get_type_description_sources_func(type_support)))
191  {
192  rcutils_reset_error();
193  RCL_SET_ERROR_MSG("Failed to register type for client");
194  ret = RCL_RET_ERROR;
195  goto destroy_client;
196  }
197  client->impl->type_hash = *hash;
198 
199  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Client initialized");
200  TRACETOOLS_TRACEPOINT(
202  (const void *)client,
203  (const void *)node,
204  (const void *)client->impl->rmw_handle,
205  client->impl->remapped_service_name);
206 
207  return RCL_RET_OK;
208 
209 destroy_client:
210  rmw_ret = rmw_destroy_client(rcl_node_get_rmw_handle(node), client->impl->rmw_handle);
211  if (RMW_RET_OK != rmw_ret) {
212  RCUTILS_SAFE_FWRITE_TO_STDERR(rmw_get_error_string().str);
213  RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
214  }
215 
216 free_remapped_service_name:
217  allocator->deallocate(client->impl->remapped_service_name, allocator->state);
218  client->impl->remapped_service_name = NULL;
219 
220 free_client_impl:
221  allocator->deallocate(client->impl, allocator->state);
222  client->impl = NULL;
223 
224  return ret;
225 }
226 
227 rcl_ret_t
229 {
230  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
231  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_NODE_INVALID);
232  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
233 
234  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Finalizing client");
235  rcl_ret_t result = RCL_RET_OK;
236  RCL_CHECK_ARGUMENT_FOR_NULL(client, RCL_RET_INVALID_ARGUMENT);
238  return RCL_RET_NODE_INVALID; // error already set
239  }
240 
241  if (client->impl) {
242  rcl_allocator_t allocator = client->impl->options.allocator;
243  rmw_node_t * rmw_node = rcl_node_get_rmw_handle(node);
244  if (!rmw_node) {
246  }
247 
248  rcl_ret_t rcl_ret = unconfigure_service_introspection(node, client->impl, &allocator);
249  if (RCL_RET_OK != rcl_ret) {
250  RCL_SET_ERROR_MSG(rcl_get_error_string().str);
251  result = rcl_ret;
252  }
253 
254  rmw_ret_t ret = rmw_destroy_client(rmw_node, client->impl->rmw_handle);
255  if (ret != RMW_RET_OK) {
256  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
257  result = RCL_RET_ERROR;
258  }
259 
260  if (
261  ROSIDL_TYPE_HASH_VERSION_UNSET != client->impl->type_hash.version &&
262  RCL_RET_OK != rcl_node_type_cache_unregister_type(node, &client->impl->type_hash))
263  {
264  RCUTILS_SAFE_FWRITE_TO_STDERR(rcl_get_error_string().str);
265  result = RCL_RET_ERROR;
266  }
267 
268  allocator.deallocate(client->impl->remapped_service_name, allocator.state);
269  client->impl->remapped_service_name = NULL;
270 
271  allocator.deallocate(client->impl, allocator.state);
272  client->impl = NULL;
273  }
274  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Client finalized");
275  return result;
276 }
277 
280 {
281  // !!! MAKE SURE THAT CHANGES TO THESE DEFAULTS ARE REFLECTED IN THE HEADER DOC STRING
282  static rcl_client_options_t default_options;
283  // Must set the allocator and qos after because they are not a compile time constant.
284  default_options.qos = rmw_qos_profile_services_default;
285  default_options.allocator = rcl_get_default_allocator();
286  return default_options;
287 }
288 
289 const char *
291 {
292  if (!rcl_client_is_valid(client)) {
293  return NULL; // error already set
294  }
295  return client->impl->rmw_handle->service_name;
296 }
297 
298 const rcl_client_options_t *
300 {
301  if (!rcl_client_is_valid(client)) {
302  return NULL; // error already set
303  }
304  return &client->impl->options;
305 }
306 
307 rmw_client_t *
309 {
310  if (!rcl_client_is_valid(client)) {
311  return NULL; // error already set
312  }
313  return client->impl->rmw_handle;
314 }
315 
316 rcl_ret_t
317 rcl_send_request(const rcl_client_t * client, const void * ros_request, int64_t * sequence_number)
318 {
319  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Client sending service request");
320  if (!rcl_client_is_valid(client)) {
321  return RCL_RET_CLIENT_INVALID; // error already set
322  }
323  RCL_CHECK_ARGUMENT_FOR_NULL(ros_request, RCL_RET_INVALID_ARGUMENT);
324  RCL_CHECK_ARGUMENT_FOR_NULL(sequence_number, RCL_RET_INVALID_ARGUMENT);
325  *sequence_number = rcutils_atomic_load_int64_t(&client->impl->sequence_number);
326  if (rmw_send_request(
327  client->impl->rmw_handle, ros_request, sequence_number) != RMW_RET_OK)
328  {
329  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
330  return RCL_RET_ERROR;
331  }
332  rcutils_atomic_exchange_int64_t(&client->impl->sequence_number, *sequence_number);
333 
334  if (client->impl->service_event_publisher != NULL) {
335  rmw_gid_t gid;
336  rmw_ret_t rmw_ret = rmw_get_gid_for_client(client->impl->rmw_handle, &gid);
337  if (rmw_ret != RMW_RET_OK) {
338  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
339  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
340  }
341  rcl_ret_t ret = rcl_send_service_event_message(
342  client->impl->service_event_publisher,
343  service_msgs__msg__ServiceEventInfo__REQUEST_SENT,
344  ros_request,
345  *sequence_number,
346  gid.data);
347  if (RCL_RET_OK != ret) {
348  RCL_SET_ERROR_MSG(rcl_get_error_string().str);
349  return ret;
350  }
351  }
352  return RCL_RET_OK;
353 }
354 
355 rcl_ret_t
357  const rcl_client_t * client,
358  rmw_service_info_t * request_header,
359  void * ros_response)
360 {
361  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Client taking service response");
362  if (!rcl_client_is_valid(client)) {
363  return RCL_RET_CLIENT_INVALID; // error already set
364  }
365 
366  RCL_CHECK_ARGUMENT_FOR_NULL(request_header, RCL_RET_INVALID_ARGUMENT);
367  RCL_CHECK_ARGUMENT_FOR_NULL(ros_response, RCL_RET_INVALID_ARGUMENT);
368 
369  bool taken = false;
370  request_header->source_timestamp = 0;
371  request_header->received_timestamp = 0;
372  if (rmw_take_response(
373  client->impl->rmw_handle, request_header, ros_response, &taken) != RMW_RET_OK)
374  {
375  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
376  return RCL_RET_ERROR;
377  }
378  RCUTILS_LOG_DEBUG_NAMED(
379  ROS_PACKAGE_NAME, "Client take response succeeded: %s", taken ? "true" : "false");
380  if (!taken) {
382  }
383 
384  if (client->impl->service_event_publisher != NULL) {
385  rmw_gid_t gid;
386  rmw_ret_t rmw_ret = rmw_get_gid_for_client(client->impl->rmw_handle, &gid);
387  if (rmw_ret != RMW_RET_OK) {
388  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
389  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
390  }
391  rcl_ret_t ret = rcl_send_service_event_message(
392  client->impl->service_event_publisher,
393  service_msgs__msg__ServiceEventInfo__RESPONSE_RECEIVED,
394  ros_response,
395  request_header->request_id.sequence_number,
396  gid.data);
397  if (RCL_RET_OK != ret) {
398  RCL_SET_ERROR_MSG(rcl_get_error_string().str);
399  return ret;
400  }
401  }
402  return RCL_RET_OK;
403 }
404 
405 rcl_ret_t
407  const rcl_client_t * client,
408  rmw_request_id_t * request_header,
409  void * ros_response)
410 {
411  rmw_service_info_t header;
412  header.request_id = *request_header;
413  rcl_ret_t ret = rcl_take_response_with_info(client, &header, ros_response);
414  *request_header = header.request_id;
415  return ret;
416 }
417 
418 bool
420 {
421  RCL_CHECK_FOR_NULL_WITH_MSG(client, "client pointer is invalid", return false);
422  RCL_CHECK_FOR_NULL_WITH_MSG(
423  client->impl, "client's rmw implementation is invalid", return false);
424  RCL_CHECK_FOR_NULL_WITH_MSG(
425  client->impl->rmw_handle, "client's rmw handle is invalid", return false);
426  return true;
427 }
428 
429 const rmw_qos_profile_t *
431 {
432  if (!rcl_client_is_valid(client)) {
433  return NULL;
434  }
435  return &client->impl->actual_request_publisher_qos;
436 }
437 
438 const rmw_qos_profile_t *
440 {
441  if (!rcl_client_is_valid(client)) {
442  return NULL;
443  }
444  return &client->impl->actual_response_subscription_qos;
445 }
446 
447 rcl_ret_t
449  const rcl_client_t * client,
450  rcl_event_callback_t callback,
451  const void * user_data)
452 {
453  if (!rcl_client_is_valid(client)) {
454  // error state already set
456  }
457 
458  return rmw_client_set_on_new_response_callback(
459  client->impl->rmw_handle,
460  callback,
461  user_data);
462 }
463 
464 rcl_ret_t
466  rcl_client_t * client,
467  rcl_node_t * node,
468  rcl_clock_t * clock,
469  const rosidl_service_type_support_t * type_support,
470  const rcl_publisher_options_t publisher_options,
471  rcl_service_introspection_state_t introspection_state)
472 {
473  if (!rcl_client_is_valid(client)) {
474  return RCL_RET_CLIENT_INVALID; // error already set
475  }
476  RCL_CHECK_ARGUMENT_FOR_NULL(node, RCL_RET_INVALID_ARGUMENT);
477  RCL_CHECK_ARGUMENT_FOR_NULL(clock, RCL_RET_INVALID_ARGUMENT);
478  RCL_CHECK_ARGUMENT_FOR_NULL(type_support, RCL_RET_INVALID_ARGUMENT);
479 
480  rcl_allocator_t allocator = client->impl->options.allocator;
481 
482  if (introspection_state == RCL_SERVICE_INTROSPECTION_OFF) {
483  return unconfigure_service_introspection(node, client->impl, &allocator);
484  }
485 
486  if (client->impl->service_event_publisher == NULL) {
487  // We haven't been introspecting, so we need to allocate the service event publisher
488 
489  client->impl->service_event_publisher = allocator.allocate(
490  sizeof(rcl_service_event_publisher_t), allocator.state);
491  RCL_CHECK_FOR_NULL_WITH_MSG(
492  client->impl->service_event_publisher, "allocating memory failed", return RCL_RET_BAD_ALLOC;);
493 
494  *client->impl->service_event_publisher = rcl_get_zero_initialized_service_event_publisher();
495  rcl_ret_t ret = rcl_service_event_publisher_init(
496  client->impl->service_event_publisher, node, clock, publisher_options,
497  client->impl->remapped_service_name, type_support);
498  if (RCL_RET_OK != ret) {
499  allocator.deallocate(client->impl->service_event_publisher, allocator.state);
500  client->impl->service_event_publisher = NULL;
501  return ret;
502  }
503  }
504 
505  return rcl_service_event_publisher_change_state(
506  client->impl->service_event_publisher, introspection_state);
507 }
508 
509 #ifdef __cplusplus
510 }
511 #endif
#define rcl_get_default_allocator
Return a properly initialized rcl_allocator_t with default values.
Definition: allocator.h:37
#define RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, msg, fail_statement)
Check that the given allocator is initialized, or fail with a message.
Definition: allocator.h:56
rcutils_allocator_t rcl_allocator_t
Encapsulation of an allocator.
Definition: allocator.h:31
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take_response_with_info(const rcl_client_t *client, rmw_service_info_t *request_header, void *ros_response)
Take a ROS response using a client.
Definition: client.c:356
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_client_configure_service_introspection(rcl_client_t *client, rcl_node_t *node, rcl_clock_t *clock, const rosidl_service_type_support_t *type_support, const rcl_publisher_options_t publisher_options, rcl_service_introspection_state_t introspection_state)
Configures service introspection features for the client.
Definition: client.c:465
RCL_PUBLIC RCL_WARN_UNUSED const rmw_qos_profile_t * rcl_client_request_publisher_get_actual_qos(const rcl_client_t *client)
Get the actual qos settings of the client's request publisher.
Definition: client.c:430
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_client_get_service_name(const rcl_client_t *client)
Get the name of the service that this client will request a response from.
Definition: client.c:290
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_client_fini(rcl_client_t *client, rcl_node_t *node)
Finalize a rcl_client_t.
Definition: client.c:228
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_client_init(rcl_client_t *client, const rcl_node_t *node, const rosidl_service_type_support_t *type_support, const char *service_name, const rcl_client_options_t *options)
Initialize a rcl client.
Definition: client.c:86
RCL_PUBLIC RCL_WARN_UNUSED rcl_client_options_t rcl_client_get_default_options(void)
Return the default client options in a rcl_client_options_t.
Definition: client.c:279
RCL_PUBLIC RCL_WARN_UNUSED rmw_client_t * rcl_client_get_rmw_handle(const rcl_client_t *client)
Return the rmw client handle.
Definition: client.c:308
RCL_PUBLIC RCL_WARN_UNUSED rcl_client_t rcl_get_zero_initialized_client(void)
Return a rcl_client_t struct with members set to NULL.
Definition: client.c:56
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take_response(const rcl_client_t *client, rmw_request_id_t *request_header, void *ros_response)
backwards compatibility function that takes a rmw_request_id_t only
Definition: client.c:406
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)
Set the on new response callback function for the client.
Definition: client.c:448
RCL_PUBLIC bool rcl_client_is_valid(const rcl_client_t *client)
Check that the client is valid.
Definition: client.c:419
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_send_request(const rcl_client_t *client, const void *ros_request, int64_t *sequence_number)
Send a ROS request using a client.
Definition: client.c:317
RCL_PUBLIC RCL_WARN_UNUSED const rmw_qos_profile_t * rcl_client_response_subscription_get_actual_qos(const rcl_client_t *client)
Get the actual qos settings of the client's response subscription.
Definition: client.c:439
RCL_PUBLIC RCL_WARN_UNUSED const rcl_client_options_t * rcl_client_get_options(const rcl_client_t *client)
Return the rcl client options.
Definition: client.c:299
RCL_PUBLIC bool rcl_node_is_valid(const rcl_node_t *node)
Return true if the node is valid, else false.
Definition: node.c:397
RCL_PUBLIC RCL_WARN_UNUSED rmw_node_t * rcl_node_get_rmw_handle(const rcl_node_t *node)
Return the rmw node handle.
Definition: node.c:461
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_node_resolve_name(const rcl_node_t *node, const char *input_name, rcl_allocator_t allocator, bool is_service, bool only_expand, char **output_name)
Expand a given name into a fully-qualified topic name and apply remapping rules.
RCL_PUBLIC bool rcl_node_is_valid_except_context(const rcl_node_t *node)
Return true if node is valid, except for the context being valid.
Definition: node.c:387
Options available for a rcl_client_t.
Definition: client.h:50
rcl_allocator_t allocator
Custom allocator for the client, used for incidental allocations.
Definition: client.h:55
rmw_qos_profile_t qos
Middleware quality of service settings for the client.
Definition: client.h:52
Structure which encapsulates a ROS Client.
Definition: client.h:43
rcl_client_impl_t * impl
Pointer to the client implementation.
Definition: client.h:45
Encapsulation of a time source.
Definition: time.h:138
Structure which encapsulates a ROS Node.
Definition: node.h:45
Options available for a rcl publisher.
Definition: publisher.h:44
#define RCL_RET_CLIENT_INVALID
Invalid rcl_client_t given return code.
Definition: types.h:79
#define RCL_RET_CLIENT_TAKE_FAILED
Failed to take a response from the client return code.
Definition: types.h:81
#define RCL_RET_UNKNOWN_SUBSTITUTION
Topic name substitution is unknown.
Definition: types.h:51
#define RCL_RET_SERVICE_NAME_INVALID
Service name (same as topic name) does not pass validation.
Definition: types.h:49
#define RCL_RET_ALREADY_INIT
rcl_init() already called return code.
Definition: types.h:41
#define RCL_RET_OK
Success return code.
Definition: types.h:27
#define RCL_RET_BAD_ALLOC
Failed to allocate memory return code.
Definition: types.h:33
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
Definition: types.h:35
#define RCL_RET_ERROR
Unspecified error return code.
Definition: types.h:29
#define RCL_RET_NODE_INVALID
Invalid rcl_node_t given return code.
Definition: types.h:59
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24