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