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