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