ROS 2 rclcpp + rcl - lyrical  lyrical
ROS 2 C++ Client Library with ROS Client Library
subscription.c
1 // Copyright 2015 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/subscription.h"
21 
22 #include <stdio.h>
23 
24 #include "rcl/error_handling.h"
25 #include "rcl/node.h"
26 #include "rcl/node_type_cache.h"
27 #include "rcutils/env.h"
28 #include "rcutils/logging_macros.h"
29 #include "rcutils/strdup.h"
30 #include "rcutils/types/string_array.h"
31 #include "rmw/error_handling.h"
32 #include "rmw/dynamic_message_type_support.h"
33 #include "rmw/subscription_content_filter_options.h"
34 #include "rmw/validate_full_topic_name.h"
35 #include "rosidl_dynamic_typesupport/identifier.h"
36 #include "tracetools/tracetools.h"
37 
38 #include "./common.h"
39 #include "./subscription_impl.h"
40 
41 
44 {
45  // All members are initialized to 0 or NULL by C99 6.7.8/10.
46  static rcl_subscription_t null_subscription;
47  return null_subscription;
48 }
49 
52  rcl_subscription_t * subscription,
53  const rcl_node_t * node,
54  const rosidl_message_type_support_t * type_support,
55  const char * topic_name,
56  const rcl_subscription_options_t * options
57 )
58 {
59  rcl_ret_t fail_ret = RCL_RET_ERROR;
60 
61  // Check options and allocator first, so the allocator can be used in errors.
62  RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT);
63  rcl_allocator_t * allocator = (rcl_allocator_t *)&options->allocator;
64  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
65  RCL_CHECK_ARGUMENT_FOR_NULL(subscription, RCL_RET_INVALID_ARGUMENT);
66  if (!rcl_node_is_valid(node)) {
67  return RCL_RET_NODE_INVALID; // error already set
68  }
69  RCL_CHECK_ARGUMENT_FOR_NULL(type_support, RCL_RET_INVALID_ARGUMENT);
70  RCL_CHECK_ARGUMENT_FOR_NULL(topic_name, RCL_RET_INVALID_ARGUMENT);
71  RCUTILS_LOG_DEBUG_NAMED(
72  ROS_PACKAGE_NAME, "Initializing subscription for topic name '%s'", topic_name);
73  if (subscription->impl) {
74  RCL_SET_ERROR_MSG("subscription already initialized, or memory was uninitialized");
75  return RCL_RET_ALREADY_INIT;
76  }
77 
78  // Expand and remap the given topic name.
79  char * remapped_topic_name = NULL;
81  node,
82  topic_name,
83  *allocator,
84  false,
85  false,
86  &remapped_topic_name);
87  if (ret != RCL_RET_OK) {
90  } else if (ret != RCL_RET_BAD_ALLOC) {
91  ret = RCL_RET_ERROR;
92  }
93  goto cleanup;
94  }
95  RCUTILS_LOG_DEBUG_NAMED(
96  ROS_PACKAGE_NAME, "Expanded and remapped topic name '%s'", remapped_topic_name);
97 
98  // Allocate memory for the implementation struct.
99  subscription->impl = (rcl_subscription_impl_t *)allocator->zero_allocate(
100  1, sizeof(rcl_subscription_impl_t), allocator->state);
101  RCL_CHECK_FOR_NULL_WITH_MSG(
102  subscription->impl, "allocating memory failed", ret = RCL_RET_BAD_ALLOC; goto cleanup);
103 
104  // options
105  subscription->impl->options = *options;
106  subscription->impl->in_use_by_waitset = false;
107 
108  // Fill out the implemenation struct.
109  // TODO(wjwwood): pass allocator once supported in rmw api.
110  subscription->impl->rmw_handle = rmw_create_subscription(
112  type_support,
113  remapped_topic_name,
114  &(options->qos),
115  &(options->rmw_subscription_options));
116  if (!subscription->impl->rmw_handle) {
117  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
118  goto fail;
119  }
120  // get actual qos, and store it
121  rmw_ret_t rmw_ret = rmw_subscription_get_actual_qos(
122  subscription->impl->rmw_handle,
123  &subscription->impl->actual_qos);
124  if (RMW_RET_OK != rmw_ret) {
125  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
126  goto fail;
127  }
128  subscription->impl->actual_qos.avoid_ros_namespace_conventions =
129  options->qos.avoid_ros_namespace_conventions;
130 
131  if (RCL_RET_OK != rcl_node_type_cache_register_type(
132  node, type_support->get_type_hash_func(type_support),
133  type_support->get_type_description_func(type_support),
134  type_support->get_type_description_sources_func(type_support)))
135  {
136  rcutils_reset_error();
137  RCL_SET_ERROR_MSG("Failed to register type for subscription");
138  goto fail;
139  }
140  subscription->impl->type_hash = *type_support->get_type_hash_func(type_support);
141 
142  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Subscription initialized");
143  ret = RCL_RET_OK;
144  TRACETOOLS_TRACEPOINT(
146  (const void *)subscription,
147  (const void *)node,
148  (const void *)subscription->impl->rmw_handle,
149  remapped_topic_name,
150  options->qos.depth);
151 
152  goto cleanup;
153 fail:
154  if (subscription->impl) {
155  if (subscription->impl->rmw_handle) {
156  rmw_ret_t rmw_fail_ret = rmw_destroy_subscription(
157  rcl_node_get_rmw_handle(node), subscription->impl->rmw_handle);
158  if (RMW_RET_OK != rmw_fail_ret) {
159  RCUTILS_SAFE_FWRITE_TO_STDERR(rmw_get_error_string().str);
160  RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
161  }
162  }
163 
164  ret = rcl_subscription_options_fini(&subscription->impl->options);
165  if (RCL_RET_OK != ret) {
166  RCUTILS_SAFE_FWRITE_TO_STDERR(rmw_get_error_string().str);
167  RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
168  }
169 
170  allocator->deallocate(subscription->impl, allocator->state);
171  subscription->impl = NULL;
172  }
173  ret = fail_ret;
174  // Fall through to cleanup
175 cleanup:
176  allocator->deallocate(remapped_topic_name, allocator->state);
177  return ret;
178 }
179 
180 rcl_ret_t
182 {
183  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_SUBSCRIPTION_INVALID);
184  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_NODE_INVALID);
185  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
186  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_ERROR);
187 
188  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Finalizing subscription");
189  rcl_ret_t result = RCL_RET_OK;
190  RCL_CHECK_ARGUMENT_FOR_NULL(subscription, RCL_RET_SUBSCRIPTION_INVALID);
192  return RCL_RET_NODE_INVALID; // error already set
193  }
194  if (subscription->impl) {
195  rcl_allocator_t allocator = subscription->impl->options.allocator;
196  rmw_node_t * rmw_node = rcl_node_get_rmw_handle(node);
197  if (!rmw_node) {
199  }
200  rmw_ret_t ret =
201  rmw_destroy_subscription(rmw_node, subscription->impl->rmw_handle);
202  if (ret != RMW_RET_OK) {
203  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
204  result = RCL_RET_ERROR;
205  }
206  rcl_ret_t rcl_ret = rcl_subscription_options_fini(&subscription->impl->options);
207  if (RCL_RET_OK != rcl_ret) {
208  RCUTILS_SAFE_FWRITE_TO_STDERR(rcl_get_error_string().str);
209  RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
210  result = RCL_RET_ERROR;
211  }
212 
213  if (
214  ROSIDL_TYPE_HASH_VERSION_UNSET != subscription->impl->type_hash.version &&
215  RCL_RET_OK != rcl_node_type_cache_unregister_type(node, &subscription->impl->type_hash))
216  {
217  RCUTILS_SAFE_FWRITE_TO_STDERR(rcl_get_error_string().str);
218  RCUTILS_SAFE_FWRITE_TO_STDERR("\n");
219  result = RCL_RET_ERROR;
220  }
221 
222  allocator.deallocate(subscription->impl, allocator.state);
223  subscription->impl = NULL;
224  }
225  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Subscription finalized");
226  return result;
227 }
228 
231 {
232  // !!! MAKE SURE THAT CHANGES TO THESE DEFAULTS ARE REFLECTED IN THE HEADER DOC STRING
233  rcl_subscription_options_t default_options;
234  // Must set these after declaration because they are not a compile time constants.
235  default_options.qos = rmw_qos_profile_default;
236  default_options.allocator = rcl_get_default_allocator();
237  default_options.rmw_subscription_options = rmw_get_default_subscription_options();
238 
239  // Load disable flag to LoanedMessage via environmental variable.
240  // TODO(clalancette): This is kind of a copy of rcl_get_disable_loaned_message(), but we need
241  // more information than that function provides.
242  default_options.disable_loaned_message = true;
243 
244  const char * env_val = NULL;
245  const char * env_error_str = rcutils_get_env(RCL_DISABLE_LOANED_MESSAGES_ENV_VAR, &env_val);
246  if (NULL != env_error_str) {
247  RCUTILS_SAFE_FWRITE_TO_STDERR("Failed to get disable_loaned_message: ");
248  RCUTILS_SAFE_FWRITE_TO_STDERR_WITH_FORMAT_STRING(
249  "Error getting env var: '" RCUTILS_STRINGIFY(RCL_DISABLE_LOANED_MESSAGES_ENV_VAR) "': %s\n",
250  env_error_str);
251  } else {
252  default_options.disable_loaned_message = !(strcmp(env_val, "0") == 0);
253  }
254 
255  return default_options;
256 }
257 
258 rcl_ret_t
260 {
261  RCL_CHECK_ARGUMENT_FOR_NULL(option, RCL_RET_INVALID_ARGUMENT);
262  // fini rmw_subscription_options_t
263  const rcl_allocator_t * allocator = &option->allocator;
264  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
265 
266  if (option->rmw_subscription_options.content_filter_options) {
267  rmw_ret_t ret = rmw_subscription_content_filter_options_fini(
268  option->rmw_subscription_options.content_filter_options, allocator);
269  if (RCUTILS_RET_OK != ret) {
270  RCUTILS_SAFE_FWRITE_TO_STDERR("Failed to fini content filter options.\n");
271  return rcl_convert_rmw_ret_to_rcl_ret(ret);
272  }
273  allocator->deallocate(
274  option->rmw_subscription_options.content_filter_options, allocator->state);
275  option->rmw_subscription_options.content_filter_options = NULL;
276  }
277 
278  if (option->rmw_subscription_options.acceptable_buffer_backends) {
279  allocator->deallocate(
280  (char *)option->rmw_subscription_options.acceptable_buffer_backends, allocator->state);
281  option->rmw_subscription_options.acceptable_buffer_backends = NULL;
282  }
283 
284  return RCL_RET_OK;
285 }
286 
287 rcl_ret_t
289  const char * acceptable_buffer_backends,
290  rcl_subscription_options_t * options)
291 {
292  RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT);
293  const rcl_allocator_t * allocator = &options->allocator;
294  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
295 
296  // Free any previously allocated value
297  if (options->rmw_subscription_options.acceptable_buffer_backends) {
298  allocator->deallocate(
299  (char *)options->rmw_subscription_options.acceptable_buffer_backends, allocator->state);
300  options->rmw_subscription_options.acceptable_buffer_backends = NULL;
301  }
302 
303  if (NULL == acceptable_buffer_backends || '\0' == acceptable_buffer_backends[0]) {
304  return RCL_RET_OK;
305  }
306 
307  char * dup = rcutils_strdup(acceptable_buffer_backends, *allocator);
308  if (NULL == dup) {
309  RCL_SET_ERROR_MSG("failed to allocate acceptable_buffer_backends string");
310  return RCL_RET_BAD_ALLOC;
311  }
312  options->rmw_subscription_options.acceptable_buffer_backends = dup;
313 
314  return RCL_RET_OK;
315 }
316 
317 rcl_ret_t
319  const char * filter_expression,
320  size_t expression_parameters_argc,
321  const char * expression_parameter_argv[],
322  rcl_subscription_options_t * options)
323 {
324  RCL_CHECK_ARGUMENT_FOR_NULL(filter_expression, RCL_RET_INVALID_ARGUMENT);
325  if (expression_parameters_argc > 100) {
326  RCL_SET_ERROR_MSG("The maximum of expression parameters argument number is 100");
328  }
329  RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT);
330  const rcl_allocator_t * allocator = &options->allocator;
331  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
332 
333  rcl_ret_t ret;
334  rmw_ret_t rmw_ret;
335  rmw_subscription_content_filter_options_t * original_content_filter_options =
336  options->rmw_subscription_options.content_filter_options;
337  rmw_subscription_content_filter_options_t content_filter_options_backup =
338  rmw_get_zero_initialized_content_filter_options();
339 
340  if (original_content_filter_options) {
341  // make a backup, restore the data if failure happened
342  rmw_ret = rmw_subscription_content_filter_options_copy(
343  original_content_filter_options,
344  allocator,
345  &content_filter_options_backup
346  );
347  if (rmw_ret != RMW_RET_OK) {
348  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
349  }
350  } else {
351  options->rmw_subscription_options.content_filter_options =
352  allocator->allocate(
353  sizeof(rmw_subscription_content_filter_options_t), allocator->state);
354  if (!options->rmw_subscription_options.content_filter_options) {
355  RCL_SET_ERROR_MSG("failed to allocate memory");
356  return RCL_RET_BAD_ALLOC;
357  }
358  *options->rmw_subscription_options.content_filter_options =
359  rmw_get_zero_initialized_content_filter_options();
360  }
361 
362  rmw_ret = rmw_subscription_content_filter_options_set(
363  filter_expression,
364  expression_parameters_argc,
365  expression_parameter_argv,
366  allocator,
367  options->rmw_subscription_options.content_filter_options
368  );
369 
370  if (rmw_ret != RMW_RET_OK) {
371  ret = rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
372  goto failed;
373  }
374 
375  rmw_ret = rmw_subscription_content_filter_options_fini(
376  &content_filter_options_backup,
377  allocator
378  );
379  if (rmw_ret != RMW_RET_OK) {
380  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
381  }
382 
383  return RMW_RET_OK;
384 
385 failed:
386 
387  if (original_content_filter_options == NULL) {
388  if (options->rmw_subscription_options.content_filter_options) {
389  rmw_ret = rmw_subscription_content_filter_options_fini(
390  options->rmw_subscription_options.content_filter_options,
391  allocator
392  );
393 
394  if (rmw_ret != RMW_RET_OK) {
395  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
396  }
397 
398  allocator->deallocate(
399  options->rmw_subscription_options.content_filter_options, allocator->state);
400  options->rmw_subscription_options.content_filter_options = NULL;
401  }
402  } else {
403  rmw_ret = rmw_subscription_content_filter_options_copy(
404  &content_filter_options_backup,
405  allocator,
406  options->rmw_subscription_options.content_filter_options
407  );
408  if (rmw_ret != RMW_RET_OK) {
409  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
410  }
411 
412  rmw_ret = rmw_subscription_content_filter_options_fini(
413  &content_filter_options_backup,
414  allocator
415  );
416  if (rmw_ret != RMW_RET_OK) {
417  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
418  }
419  }
420 
421  return ret;
422 }
423 
426 {
428  .rmw_subscription_content_filter_options =
429  rmw_get_zero_initialized_content_filter_options()
430  }; // NOLINT(readability/braces): false positive
431 }
432 
433 rcl_ret_t
435  const rcl_subscription_t * subscription,
436  const char * filter_expression,
437  size_t expression_parameters_argc,
438  const char * expression_parameter_argv[],
440 {
441  if (!rcl_subscription_is_valid(subscription)) {
443  }
444  RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT);
445  const rcl_allocator_t * allocator = &subscription->impl->options.allocator;
446  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
447  if (expression_parameters_argc > 100) {
448  RCL_SET_ERROR_MSG("The maximum of expression parameters argument number is 100");
450  }
451 
452  rmw_ret_t rmw_ret = rmw_subscription_content_filter_options_init(
453  filter_expression,
454  expression_parameters_argc,
455  expression_parameter_argv,
456  allocator,
457  &options->rmw_subscription_content_filter_options
458  );
459 
460  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
461 }
462 
463 rcl_ret_t
465  const rcl_subscription_t * subscription,
466  const char * filter_expression,
467  size_t expression_parameters_argc,
468  const char * expression_parameter_argv[],
470 {
471  if (!rcl_subscription_is_valid(subscription)) {
473  }
474  if (expression_parameters_argc > 100) {
475  RCL_SET_ERROR_MSG("The maximum of expression parameters argument number is 100");
477  }
478  RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT);
479  const rcl_allocator_t * allocator = &subscription->impl->options.allocator;
480  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
481 
482  rmw_ret_t ret = rmw_subscription_content_filter_options_set(
483  filter_expression,
484  expression_parameters_argc,
485  expression_parameter_argv,
486  allocator,
487  &options->rmw_subscription_content_filter_options
488  );
489  return rcl_convert_rmw_ret_to_rcl_ret(ret);
490 }
491 
492 rcl_ret_t
494  const rcl_subscription_t * subscription,
496 {
497  if (!rcl_subscription_is_valid(subscription)) {
499  }
500  RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT);
501  const rcl_allocator_t * allocator = &subscription->impl->options.allocator;
502  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
503 
504  rmw_ret_t ret = rmw_subscription_content_filter_options_fini(
505  &options->rmw_subscription_content_filter_options,
506  allocator
507  );
508 
509  return rcl_convert_rmw_ret_to_rcl_ret(ret);
510 }
511 
512 bool
514 {
515  if (!rcl_subscription_is_valid(subscription)) {
516  return false;
517  }
518  return subscription->impl->rmw_handle->is_cft_enabled;
519 }
520 
521 rcl_ret_t
523  const rcl_subscription_t * subscription,
525 )
526 {
527  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_SUBSCRIPTION_INVALID);
528  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
529 
530  if (!rcl_subscription_is_valid(subscription)) {
532  }
533 
534  RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT);
535  rmw_ret_t ret = rmw_subscription_set_content_filter(
536  subscription->impl->rmw_handle,
537  &options->rmw_subscription_content_filter_options);
538 
539  if (ret != RMW_RET_OK) {
540  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
541  return rcl_convert_rmw_ret_to_rcl_ret(ret);
542  }
543 
544  // copy options into subscription_options
545  const rmw_subscription_content_filter_options_t * content_filter_options =
546  &options->rmw_subscription_content_filter_options;
548  content_filter_options->filter_expression,
549  content_filter_options->expression_parameters.size,
550  (const char **)content_filter_options->expression_parameters.data,
551  &subscription->impl->options
552  );
553 }
554 
555 rcl_ret_t
557  const rcl_subscription_t * subscription,
559 )
560 {
561  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_SUBSCRIPTION_INVALID);
562  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
563 
564  if (!rcl_subscription_is_valid(subscription)) {
566  }
567  RCL_CHECK_ARGUMENT_FOR_NULL(options, RCL_RET_INVALID_ARGUMENT);
568  rcl_allocator_t * allocator = &subscription->impl->options.allocator;
569  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
570 
571  rmw_ret_t rmw_ret = rmw_subscription_get_content_filter(
572  subscription->impl->rmw_handle,
573  allocator,
574  &options->rmw_subscription_content_filter_options);
575 
576  return rcl_convert_rmw_ret_to_rcl_ret(rmw_ret);
577 }
578 
579 rcl_ret_t
581  const rcl_subscription_t * subscription,
582  void * ros_message,
583  rmw_message_info_t * message_info,
584  rmw_subscription_allocation_t * allocation
585 )
586 {
587  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Subscription taking message");
588  if (!rcl_subscription_is_valid(subscription)) {
589  return RCL_RET_SUBSCRIPTION_INVALID; // error message already set
590  }
591  RCL_CHECK_ARGUMENT_FOR_NULL(ros_message, RCL_RET_INVALID_ARGUMENT);
592 
593  // If message_info is NULL, use a place holder which can be discarded.
594  rmw_message_info_t dummy_message_info;
595  rmw_message_info_t * message_info_local = message_info ? message_info : &dummy_message_info;
596  *message_info_local = rmw_get_zero_initialized_message_info();
597  // Call rmw_take_with_info.
598  bool taken = false;
599  rmw_ret_t ret = rmw_take_with_info(
600  subscription->impl->rmw_handle, ros_message, &taken, message_info_local, allocation);
601  if (ret != RMW_RET_OK) {
602  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
603  return rcl_convert_rmw_ret_to_rcl_ret(ret);
604  }
605  RCUTILS_LOG_DEBUG_NAMED(
606  ROS_PACKAGE_NAME, "Subscription take succeeded: %s", taken ? "true" : "false");
607  TRACETOOLS_TRACEPOINT(rcl_take, (const void *)ros_message);
608  if (!taken) {
610  }
611  return RCL_RET_OK;
612 }
613 
614 rcl_ret_t
616  const rcl_subscription_t * subscription,
617  size_t count,
618  rmw_message_sequence_t * message_sequence,
619  rmw_message_info_sequence_t * message_info_sequence,
620  rmw_subscription_allocation_t * allocation
621 )
622 {
623  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Subscription taking %zu messages", count);
624  if (!rcl_subscription_is_valid(subscription)) {
625  return RCL_RET_SUBSCRIPTION_INVALID; // error message already set
626  }
627  RCL_CHECK_ARGUMENT_FOR_NULL(message_sequence, RCL_RET_INVALID_ARGUMENT);
628  RCL_CHECK_ARGUMENT_FOR_NULL(message_info_sequence, RCL_RET_INVALID_ARGUMENT);
629 
630  if (message_sequence->capacity < count) {
631  RCL_SET_ERROR_MSG("Insufficient message sequence capacity for requested count");
633  }
634 
635  if (message_info_sequence->capacity < count) {
636  RCL_SET_ERROR_MSG("Insufficient message info sequence capacity for requested count");
638  }
639 
640  // Set the sizes to zero to indicate that there are no valid messages
641  message_sequence->size = 0u;
642  message_info_sequence->size = 0u;
643 
644  size_t taken = 0u;
645  rmw_ret_t ret = rmw_take_sequence(
646  subscription->impl->rmw_handle, count, message_sequence, message_info_sequence, &taken,
647  allocation);
648  if (ret != RMW_RET_OK) {
649  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
650  return rcl_convert_rmw_ret_to_rcl_ret(ret);
651  }
652  RCUTILS_LOG_DEBUG_NAMED(
653  ROS_PACKAGE_NAME, "Subscription took %zu messages", taken);
654  if (0u == taken) {
656  }
657  return RCL_RET_OK;
658 }
659 
660 rcl_ret_t
662  const rcl_subscription_t * subscription,
663  rcl_serialized_message_t * serialized_message,
664  rmw_message_info_t * message_info,
665  rmw_subscription_allocation_t * allocation
666 )
667 {
668  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Subscription taking serialized message");
669  if (!rcl_subscription_is_valid(subscription)) {
670  return RCL_RET_SUBSCRIPTION_INVALID; // error already set
671  }
672  RCL_CHECK_ARGUMENT_FOR_NULL(serialized_message, RCL_RET_INVALID_ARGUMENT);
673  // If message_info is NULL, use a place holder which can be discarded.
674  rmw_message_info_t dummy_message_info;
675  rmw_message_info_t * message_info_local = message_info ? message_info : &dummy_message_info;
676  *message_info_local = rmw_get_zero_initialized_message_info();
677  // Call rmw_take_with_info.
678  bool taken = false;
679  rmw_ret_t ret = rmw_take_serialized_message_with_info(
680  subscription->impl->rmw_handle, serialized_message, &taken, message_info_local, allocation);
681  if (ret != RMW_RET_OK) {
682  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
683  return rcl_convert_rmw_ret_to_rcl_ret(ret);
684  }
685  RCUTILS_LOG_DEBUG_NAMED(
686  ROS_PACKAGE_NAME, "Subscription serialized take succeeded: %s", taken ? "true" : "false");
687  TRACETOOLS_TRACEPOINT(rcl_take, (const void *)serialized_message);
688  if (!taken) {
690  }
691  return RCL_RET_OK;
692 }
693 
694 rcl_ret_t
696  const rcl_subscription_t * subscription,
697  rosidl_dynamic_typesupport_dynamic_data_t * dynamic_message,
698  rmw_message_info_t * message_info,
699  rmw_subscription_allocation_t * allocation)
700 {
701  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Subscription taking dynamic message");
702  if (!rcl_subscription_is_valid(subscription)) {
703  return RCL_RET_SUBSCRIPTION_INVALID; // error already set
704  }
705  RCL_CHECK_ARGUMENT_FOR_NULL(dynamic_message, RCL_RET_INVALID_ARGUMENT);
706  // If message_info is NULL, use a place holder which can be discarded.
707  rmw_message_info_t dummy_message_info;
708  rmw_message_info_t * message_info_local = message_info ? message_info : &dummy_message_info;
709  *message_info_local = rmw_get_zero_initialized_message_info();
710  // Call take with info
711  bool taken = false;
712  rmw_ret_t ret = rmw_take_dynamic_message_with_info(
713  subscription->impl->rmw_handle, dynamic_message, &taken, message_info_local, allocation);
714  if (ret != RMW_RET_OK) {
715  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
716  return rcl_convert_rmw_ret_to_rcl_ret(ret);
717  }
718  RCUTILS_LOG_DEBUG_NAMED(
719  ROS_PACKAGE_NAME, "Subscription dynamic take succeeded: %s", taken ? "true" : "false");
720  if (!taken) {
722  }
723  return RCL_RET_OK;
724 }
725 
726 rcl_ret_t
728  const rcl_subscription_t * subscription,
729  void ** loaned_message,
730  rmw_message_info_t * message_info,
731  rmw_subscription_allocation_t * allocation)
732 {
733  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Subscription taking loaned message");
734  if (!rcl_subscription_is_valid(subscription)) {
735  return RCL_RET_SUBSCRIPTION_INVALID; // error already set
736  }
737  RCL_CHECK_ARGUMENT_FOR_NULL(loaned_message, RCL_RET_INVALID_ARGUMENT);
738  if (*loaned_message) {
739  RCL_SET_ERROR_MSG("loaned message is already initialized");
741  }
742  // If message_info is NULL, use a place holder which can be discarded.
743  rmw_message_info_t dummy_message_info;
744  rmw_message_info_t * message_info_local = message_info ? message_info : &dummy_message_info;
745  *message_info_local = rmw_get_zero_initialized_message_info();
746  // Call rmw_take_with_info.
747  bool taken = false;
748  rmw_ret_t ret = rmw_take_loaned_message_with_info(
749  subscription->impl->rmw_handle, loaned_message, &taken, message_info_local, allocation);
750  if (ret != RMW_RET_OK) {
751  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
752  return rcl_convert_rmw_ret_to_rcl_ret(ret);
753  }
754  RCUTILS_LOG_DEBUG_NAMED(
755  ROS_PACKAGE_NAME, "Subscription loaned take succeeded: %s", taken ? "true" : "false");
756  TRACETOOLS_TRACEPOINT(rcl_take, (const void *)(*loaned_message));
757  if (!taken) {
759  }
760  return RCL_RET_OK;
761 }
762 
763 rcl_ret_t
765  const rcl_subscription_t * subscription,
766  void * loaned_message)
767 {
768  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Subscription releasing loaned message");
769  if (!rcl_subscription_is_valid(subscription)) {
770  return RCL_RET_SUBSCRIPTION_INVALID; // error already set
771  }
772  RCL_CHECK_ARGUMENT_FOR_NULL(loaned_message, RCL_RET_INVALID_ARGUMENT);
773  return rcl_convert_rmw_ret_to_rcl_ret(
774  rmw_return_loaned_message_from_subscription(
775  subscription->impl->rmw_handle, loaned_message));
776 }
777 
778 const char *
780 {
781  if (!rcl_subscription_is_valid(subscription)) {
782  return NULL; // error already set
783  }
784  return subscription->impl->rmw_handle->topic_name;
785 }
786 
789 {
790  if (!rcl_subscription_is_valid(subscription)) {
791  return NULL; // error already set
792  }
793  return &subscription->impl->options;
794 }
795 
796 rmw_subscription_t *
798 {
799  if (!rcl_subscription_is_valid(subscription)) {
800  return NULL; // error already set
801  }
802  return subscription->impl->rmw_handle;
803 }
804 
805 bool
807 {
808  RCL_CHECK_FOR_NULL_WITH_MSG(subscription, "subscription pointer is invalid", return false);
809  RCL_CHECK_FOR_NULL_WITH_MSG(
810  subscription->impl, "subscription's implementation is invalid", return false);
811  RCL_CHECK_FOR_NULL_WITH_MSG(
812  subscription->impl->rmw_handle, "subscription's rmw handle is invalid", return false);
813  return true;
814 }
815 
816 rmw_ret_t
818  const rcl_subscription_t * subscription,
819  size_t * publisher_count)
820 {
821  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_SUBSCRIPTION_INVALID);
822  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
823 
824  if (!rcl_subscription_is_valid(subscription)) {
826  }
827  RCL_CHECK_ARGUMENT_FOR_NULL(publisher_count, RCL_RET_INVALID_ARGUMENT);
828  rmw_ret_t ret = rmw_subscription_count_matched_publishers(
829  subscription->impl->rmw_handle, publisher_count);
830 
831  if (ret != RMW_RET_OK) {
832  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
833  return rcl_convert_rmw_ret_to_rcl_ret(ret);
834  }
835  return RCL_RET_OK;
836 }
837 
838 const rmw_qos_profile_t *
840 {
841  if (!rcl_subscription_is_valid(subscription)) {
842  return NULL;
843  }
844  return &subscription->impl->actual_qos;
845 }
846 
847 bool
849 {
850  if (!rcl_subscription_is_valid(subscription)) {
851  return false; // error message already set
852  }
853 
854  if (subscription->impl->options.disable_loaned_message) {
855  return false;
856  }
857 
858  return subscription->impl->rmw_handle->can_loan_messages;
859 }
860 
861 rcl_ret_t
863  const rcl_subscription_t * subscription,
864  rcl_event_callback_t callback,
865  const void * user_data)
866 {
867  if (!rcl_subscription_is_valid(subscription)) {
868  // error state already set
870  }
871 
872  return rmw_subscription_set_on_new_message_callback(
873  subscription->impl->rmw_handle,
874  callback,
875  user_data);
876 }
877 
878 bool
880 {
881  if (!rcl_subscription_is_valid(subscription)) {
882  return false; // error message already set
883  }
884  return subscription->impl->rmw_handle->is_cft_supported;
885 }
886 
887 #ifdef __cplusplus
888 }
889 #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 bool rcl_node_is_valid(const rcl_node_t *node)
Return true if the node is valid, else false.
Definition: node.c:402
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:466
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:392
Structure which encapsulates a ROS Node.
Definition: node.h:45
Options available for a rcl subscription.
Definition: subscription.h:47
rcl_allocator_t allocator
Custom allocator for the subscription, used for incidental allocations.
Definition: subscription.h:52
rmw_qos_profile_t qos
Middleware quality of service settings for the subscription.
Definition: subscription.h:49
rmw_subscription_options_t rmw_subscription_options
rmw specific subscription options, e.g. the rmw implementation specific payload.
Definition: subscription.h:54
bool disable_loaned_message
Disable flag to LoanedMessage, initialized via environmental variable.
Definition: subscription.h:56
Structure which encapsulates a ROS Subscription.
Definition: subscription.h:40
rcl_subscription_impl_t * impl
Pointer to the subscription implementation.
Definition: subscription.h:42
RCL_PUBLIC RCL_WARN_UNUSED rcl_subscription_options_t rcl_subscription_get_default_options(void)
Return the default subscription options in a rcl_subscription_options_t.
Definition: subscription.c:230
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_content_filter_options_fini(const rcl_subscription_t *subscription, rcl_subscription_content_filter_options_t *options)
Reclaim rcl_subscription_content_filter_options_t structure.
Definition: subscription.c:493
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_options_fini(rcl_subscription_options_t *option)
Reclaim resources held inside rcl_subscription_options_t structure.
Definition: subscription.c:259
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_init(rcl_subscription_t *subscription, const rcl_node_t *node, const rosidl_message_type_support_t *type_support, const char *topic_name, const rcl_subscription_options_t *options)
Initialize a ROS subscription.
Definition: subscription.c:51
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take_sequence(const rcl_subscription_t *subscription, size_t count, rmw_message_sequence_t *message_sequence, rmw_message_info_sequence_t *message_info_sequence, rmw_subscription_allocation_t *allocation)
Take a sequence of messages from a topic using a rcl subscription.
Definition: subscription.c:615
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_subscription_get_topic_name(const rcl_subscription_t *subscription)
Get the topic name for the subscription.
Definition: subscription.c:779
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)
Set the on new message callback function for the subscription.
Definition: subscription.c:862
RCL_PUBLIC bool rcl_subscription_can_loan_messages(const rcl_subscription_t *subscription)
Check if subscription instance can loan messages.
Definition: subscription.c:848
RCL_PUBLIC RCL_WARN_UNUSED rmw_subscription_t * rcl_subscription_get_rmw_handle(const rcl_subscription_t *subscription)
Return the rmw subscription handle.
Definition: subscription.c:797
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_fini(rcl_subscription_t *subscription, rcl_node_t *node)
Finalize a rcl_subscription_t.
Definition: subscription.c:181
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take(const rcl_subscription_t *subscription, void *ros_message, rmw_message_info_t *message_info, rmw_subscription_allocation_t *allocation)
Take a ROS message from a topic using a rcl subscription.
Definition: subscription.c:580
RCL_PUBLIC RCL_WARN_UNUSED rmw_ret_t rcl_subscription_get_publisher_count(const rcl_subscription_t *subscription, size_t *publisher_count)
Get the number of publishers matched to a subscription.
Definition: subscription.c:817
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_options_set_content_filter_options(const char *filter_expression, size_t expression_parameters_argc, const char *expression_parameter_argv[], rcl_subscription_options_t *options)
Set the content filter options for the given subscription options.
Definition: subscription.c:318
RCL_PUBLIC bool rcl_subscription_is_valid(const rcl_subscription_t *subscription)
Check that the subscription is valid.
Definition: subscription.c:806
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take_serialized_message(const rcl_subscription_t *subscription, rcl_serialized_message_t *serialized_message, rmw_message_info_t *message_info, rmw_subscription_allocation_t *allocation)
Take a serialized raw message from a topic using a rcl subscription.
Definition: subscription.c:661
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_options_set_acceptable_buffer_backends(const char *acceptable_buffer_backends, rcl_subscription_options_t *options)
Set the acceptable buffer backends for the given subscription options.
Definition: subscription.c:288
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take_loaned_message(const rcl_subscription_t *subscription, void **loaned_message, rmw_message_info_t *message_info, rmw_subscription_allocation_t *allocation)
Take a loaned message from a topic using a rcl subscription.
Definition: subscription.c:727
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_content_filter_options_set(const rcl_subscription_t *subscription, const char *filter_expression, size_t expression_parameters_argc, const char *expression_parameter_argv[], rcl_subscription_content_filter_options_t *options)
Set the content filter options for the given subscription options.
Definition: subscription.c:464
RCL_PUBLIC RCL_WARN_UNUSED rcl_subscription_content_filter_options_t rcl_get_zero_initialized_subscription_content_filter_options(void)
Return the zero initialized subscription content filter options.
Definition: subscription.c:425
RCL_PUBLIC RCL_WARN_UNUSED bool rcl_subscription_is_cft_enabled(const rcl_subscription_t *subscription)
Check if the content filtered topic feature is enabled in the subscription.
Definition: subscription.c:513
RCL_PUBLIC RCL_WARN_UNUSED const rmw_qos_profile_t * rcl_subscription_get_actual_qos(const rcl_subscription_t *subscription)
Get the actual qos settings of the subscription.
Definition: subscription.c:839
RCL_PUBLIC RCL_WARN_UNUSED rcl_subscription_t rcl_get_zero_initialized_subscription(void)
Return a rcl_subscription_t struct with members set to NULL.
Definition: subscription.c:43
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_get_content_filter(const rcl_subscription_t *subscription, rcl_subscription_content_filter_options_t *options)
Retrieve the filter expression of the subscription.
Definition: subscription.c:556
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_set_content_filter(const rcl_subscription_t *subscription, const rcl_subscription_content_filter_options_t *options)
Set the filter expression and expression parameters for the subscription.
Definition: subscription.c:522
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_content_filter_options_init(const rcl_subscription_t *subscription, const char *filter_expression, size_t expression_parameters_argc, const char *expression_parameter_argv[], rcl_subscription_content_filter_options_t *options)
Initialize the content filter options for the given subscription options.
Definition: subscription.c:434
RCL_PUBLIC bool rcl_subscription_is_cft_supported(const rcl_subscription_t *subscription)
Check if subscription instance supports content filtering.
Definition: subscription.c:879
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_return_loaned_message_from_subscription(const rcl_subscription_t *subscription, void *loaned_message)
Return a loaned message from a topic using a rcl subscription.
Definition: subscription.c:764
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take_dynamic_message(const rcl_subscription_t *subscription, rosidl_dynamic_typesupport_dynamic_data_t *dynamic_message, rmw_message_info_t *message_info, rmw_subscription_allocation_t *allocation)
Take a dynamic type message from a topic using a rcl subscription.
Definition: subscription.c:695
RCL_PUBLIC RCL_WARN_UNUSED const rcl_subscription_options_t * rcl_subscription_get_options(const rcl_subscription_t *subscription)
Return the rcl subscription options.
Definition: subscription.c:788
#define RCL_RET_UNKNOWN_SUBSTITUTION
Topic name substitution is unknown.
Definition: types.h:51
#define RCL_RET_ALREADY_INIT
rcl_init() already called return code.
Definition: types.h:41
#define RCL_RET_SUBSCRIPTION_TAKE_FAILED
Failed to take a message from the subscription return code.
Definition: types.h:75
#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
rmw_serialized_message_t rcl_serialized_message_t
typedef for rmw_serialized_message_t;
Definition: types.h:152
#define RCL_RET_NODE_INVALID
Invalid rcl_node_t given return code.
Definition: types.h:59
#define RCL_RET_TOPIC_NAME_INVALID
Topic name does not pass validation.
Definition: types.h:47
#define RCL_RET_SUBSCRIPTION_INVALID
Invalid rcl_subscription_t given return code.
Definition: types.h:73
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24