ROS 2 rclcpp + rcl - rolling  rolling-20536064
ROS 2 C++ Client Library with ROS Client Library
event.c
1 // Copyright 2019 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/event.h"
21 
22 #include "rcl/error_handling.h"
23 #include "rcutils/allocator.h"
24 #include "rcutils/logging_macros.h"
25 #include "rmw/error_handling.h"
26 #include "rmw/validate_full_topic_name.h"
27 #include "rmw/event.h"
28 
29 #include "./common.h"
30 #include "./event_impl.h"
31 #include "./publisher_impl.h"
32 #include "./subscription_impl.h"
33 
36 {
37  // All members are initialized to 0 or NULL by C99 6.7.8/10.
38  static rcl_event_t null_event;
39  return null_event;
40 }
41 
44  rcl_event_t * event,
45  const rcl_publisher_t * publisher,
46  const rcl_publisher_event_type_t event_type)
47 {
48  RCL_CHECK_ARGUMENT_FOR_NULL(event, RCL_RET_EVENT_INVALID);
49  // Check publisher and allocator first, so allocator can be used with errors.
50  RCL_CHECK_ARGUMENT_FOR_NULL(publisher, RCL_RET_INVALID_ARGUMENT);
51  rcl_allocator_t * allocator = &publisher->impl->options.allocator;
52  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
53  rmw_event_type_t rmw_event_type = RMW_EVENT_INVALID;
54  switch (event_type) {
55  case RCL_PUBLISHER_OFFERED_DEADLINE_MISSED:
56  rmw_event_type = RMW_EVENT_OFFERED_DEADLINE_MISSED;
57  break;
58  case RCL_PUBLISHER_LIVELINESS_LOST:
59  rmw_event_type = RMW_EVENT_LIVELINESS_LOST;
60  break;
61  case RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS:
62  rmw_event_type = RMW_EVENT_OFFERED_QOS_INCOMPATIBLE;
63  break;
64  case RCL_PUBLISHER_INCOMPATIBLE_TYPE:
65  rmw_event_type = RMW_EVENT_PUBLISHER_INCOMPATIBLE_TYPE;
66  break;
67  case RCL_PUBLISHER_MATCHED:
68  rmw_event_type = RMW_EVENT_PUBLICATION_MATCHED;
69  break;
70  }
71  if (rmw_event_type == RMW_EVENT_INVALID) {
72  RCL_SET_ERROR_MSG("Event type for publisher not supported");
74  }
75 
76  // Allocate space for the implementation struct.
77  event->impl = (rcl_event_impl_t *) allocator->allocate(
78  sizeof(rcl_event_impl_t), allocator->state);
79  RCL_CHECK_FOR_NULL_WITH_MSG(
80  event->impl, "allocating memory failed", return RCL_RET_BAD_ALLOC);
81 
82  event->impl->rmw_handle = rmw_get_zero_initialized_event();
83  event->impl->allocator = *allocator;
84 
85  rmw_ret_t ret = rmw_publisher_event_init(
86  &event->impl->rmw_handle,
87  publisher->impl->rmw_handle,
88  rmw_event_type);
89  if (ret != RMW_RET_OK) {
90  goto fail;
91  }
92 
93  return RCL_RET_OK;
94 fail:
95  allocator->deallocate(event->impl, allocator->state);
96  event->impl = NULL;
97  return rcl_convert_rmw_ret_to_rcl_ret(ret);
98 }
99 
100 rcl_ret_t
102  rcl_event_t * event,
103  const rcl_subscription_t * subscription,
104  const rcl_subscription_event_type_t event_type)
105 {
106  RCL_CHECK_ARGUMENT_FOR_NULL(event, RCL_RET_EVENT_INVALID);
107  // Check subscription and allocator first, so allocator can be used with errors.
108  RCL_CHECK_ARGUMENT_FOR_NULL(subscription, RCL_RET_INVALID_ARGUMENT);
109  rcl_allocator_t * allocator = &subscription->impl->options.allocator;
110  RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
111  rmw_event_type_t rmw_event_type = RMW_EVENT_INVALID;
112  switch (event_type) {
113  case RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED:
114  rmw_event_type = RMW_EVENT_REQUESTED_DEADLINE_MISSED;
115  break;
116  case RCL_SUBSCRIPTION_LIVELINESS_CHANGED:
117  rmw_event_type = RMW_EVENT_LIVELINESS_CHANGED;
118  break;
119  case RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS:
120  rmw_event_type = RMW_EVENT_REQUESTED_QOS_INCOMPATIBLE;
121  break;
122  case RCL_SUBSCRIPTION_MESSAGE_LOST:
123  rmw_event_type = RMW_EVENT_MESSAGE_LOST;
124  break;
125  case RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE:
126  rmw_event_type = RMW_EVENT_SUBSCRIPTION_INCOMPATIBLE_TYPE;
127  break;
128  case RCL_SUBSCRIPTION_MATCHED:
129  rmw_event_type = RMW_EVENT_SUBSCRIPTION_MATCHED;
130  break;
131  }
132  if (rmw_event_type == RMW_EVENT_INVALID) {
133  RCL_SET_ERROR_MSG("Event type for subscription not supported");
135  }
136 
137  // Allocate space for the implementation struct.
138  event->impl = (rcl_event_impl_t *) allocator->allocate(
139  sizeof(rcl_event_impl_t), allocator->state);
140  RCL_CHECK_FOR_NULL_WITH_MSG(
141  event->impl, "allocating memory failed", return RCL_RET_BAD_ALLOC);
142 
143  event->impl->rmw_handle = rmw_get_zero_initialized_event();
144  event->impl->allocator = *allocator;
145 
146  rmw_ret_t ret = rmw_subscription_event_init(
147  &event->impl->rmw_handle,
148  subscription->impl->rmw_handle,
149  rmw_event_type);
150  if (ret != RMW_RET_OK) {
151  goto fail;
152  }
153 
154  return RCL_RET_OK;
155 fail:
156  allocator->deallocate(event->impl, allocator->state);
157  event->impl = NULL;
158  return rcl_convert_rmw_ret_to_rcl_ret(ret);
159 }
160 
161 rcl_ret_t
163  const rcl_event_t * event,
164  void * event_info)
165 {
166  bool taken = false;
167  if (!rcl_event_is_valid(event)) {
168  return RCL_RET_EVENT_INVALID;
169  }
170  RCL_CHECK_ARGUMENT_FOR_NULL(event_info, RCL_RET_INVALID_ARGUMENT);
171  rmw_ret_t ret = rmw_take_event(&event->impl->rmw_handle, event_info, &taken);
172  if (RMW_RET_OK != ret) {
173  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
174  return rcl_convert_rmw_ret_to_rcl_ret(ret);
175  }
176  if (!taken) {
177  RCUTILS_LOG_DEBUG_NAMED(
178  ROS_PACKAGE_NAME, "take_event request complete, unable to take event");
180  }
181  RCUTILS_LOG_DEBUG_NAMED(
182  ROS_PACKAGE_NAME, "take_event request success");
183  return rcl_convert_rmw_ret_to_rcl_ret(ret);
184 }
185 
186 rcl_ret_t
188 {
189  rcl_ret_t result = RCL_RET_OK;
190  RCL_CHECK_ARGUMENT_FOR_NULL(event, RCL_RET_EVENT_INVALID);
191 
192  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Finalizing event");
193  if (NULL != event->impl) {
194  rcl_allocator_t allocator = event->impl->allocator;
195  rmw_ret_t ret = rmw_event_fini(&event->impl->rmw_handle);
196  if (ret != RMW_RET_OK) {
197  RCL_SET_ERROR_MSG(rmw_get_error_string().str);
198  result = rcl_convert_rmw_ret_to_rcl_ret(ret);
199  }
200  allocator.deallocate(event->impl, allocator.state);
201  event->impl = NULL;
202  }
203  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Event finalized");
204 
205  return result;
206 }
207 
208 rmw_event_t *
210 {
211  if (!rcl_event_is_valid(event)) {
212  return NULL; // error already set
213  } else {
214  return &event->impl->rmw_handle;
215  }
216 }
217 
218 bool
220 {
221  RCL_CHECK_FOR_NULL_WITH_MSG(event, "event pointer is invalid", return false);
222  RCL_CHECK_FOR_NULL_WITH_MSG(event->impl, "event's implementation is invalid", return false);
223  if (event->impl->rmw_handle.event_type == RMW_EVENT_INVALID) {
224  RCUTILS_SET_ERROR_MSG("event's implementation not init");
225  return false;
226  }
227  RCUTILS_CHECK_ALLOCATOR_WITH_MSG(
228  &event->impl->allocator, "not valid allocator", return false);
229  return true;
230 }
231 
232 bool
234  const rcl_publisher_event_type_t event_type)
235 {
236  rmw_event_type_t rmw_event_type = RMW_EVENT_INVALID;
237  switch (event_type) {
238  case RCL_PUBLISHER_OFFERED_DEADLINE_MISSED:
239  rmw_event_type = RMW_EVENT_OFFERED_DEADLINE_MISSED;
240  break;
241  case RCL_PUBLISHER_LIVELINESS_LOST:
242  rmw_event_type = RMW_EVENT_LIVELINESS_LOST;
243  break;
244  case RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS:
245  rmw_event_type = RMW_EVENT_OFFERED_QOS_INCOMPATIBLE;
246  break;
247  case RCL_PUBLISHER_INCOMPATIBLE_TYPE:
248  rmw_event_type = RMW_EVENT_PUBLISHER_INCOMPATIBLE_TYPE;
249  break;
250  case RCL_PUBLISHER_MATCHED:
251  rmw_event_type = RMW_EVENT_PUBLICATION_MATCHED;
252  break;
253  }
254  if (rmw_event_type == RMW_EVENT_INVALID) {
255  return false;
256  }
257  return rmw_event_type_is_supported(rmw_event_type);
258 }
259 
260 bool
262  const rcl_subscription_event_type_t event_type)
263 {
264  rmw_event_type_t rmw_event_type = RMW_EVENT_INVALID;
265  switch (event_type) {
266  case RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED:
267  rmw_event_type = RMW_EVENT_REQUESTED_DEADLINE_MISSED;
268  break;
269  case RCL_SUBSCRIPTION_LIVELINESS_CHANGED:
270  rmw_event_type = RMW_EVENT_LIVELINESS_CHANGED;
271  break;
272  case RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS:
273  rmw_event_type = RMW_EVENT_REQUESTED_QOS_INCOMPATIBLE;
274  break;
275  case RCL_SUBSCRIPTION_MESSAGE_LOST:
276  rmw_event_type = RMW_EVENT_MESSAGE_LOST;
277  break;
278  case RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE:
279  rmw_event_type = RMW_EVENT_SUBSCRIPTION_INCOMPATIBLE_TYPE;
280  break;
281  case RCL_SUBSCRIPTION_MATCHED:
282  rmw_event_type = RMW_EVENT_SUBSCRIPTION_MATCHED;
283  break;
284  }
285  if (rmw_event_type == RMW_EVENT_INVALID) {
286  return false;
287  }
288  return rmw_event_type_is_supported(rmw_event_type);
289 }
290 
291 rcl_ret_t
293  const rcl_event_t * event,
294  rcl_event_callback_t callback,
295  const void * user_data)
296 {
297  if (!rcl_event_is_valid(event)) {
298  // error state already set
300  }
301 
302  return rmw_event_set_callback(
303  &event->impl->rmw_handle,
304  callback,
305  user_data);
306 }
307 
308 #ifdef __cplusplus
309 }
310 #endif
#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_event(const rcl_event_t *event, void *event_info)
Definition: event.c:162
enum rcl_publisher_event_type_e rcl_publisher_event_type_t
Enumeration of all of the publisher events that may fire.
RCL_PUBLIC RCL_WARN_UNUSED rcl_event_t rcl_get_zero_initialized_event(void)
Return a rcl_event_t struct with members set to NULL.
Definition: event.c:35
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_event_set_callback(const rcl_event_t *event, rcl_event_callback_t callback, const void *user_data)
Set the callback function for the event.
Definition: event.c:292
enum rcl_subscription_event_type_e rcl_subscription_event_type_t
Enumeration of all of the subscription events that may fire.
RCL_PUBLIC RCL_WARN_UNUSED rmw_event_t * rcl_event_get_rmw_handle(const rcl_event_t *event)
Return the rmw event handle.
Definition: event.c:209
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_event_init(rcl_event_t *event, const rcl_subscription_t *subscription, const rcl_subscription_event_type_t event_type)
Initialize an rcl_event_t with a subscription.
Definition: event.c:101
RCL_PUBLIC RCL_WARN_UNUSED bool rcl_subscription_event_type_is_supported(const rcl_subscription_event_type_t event_type)
Check if a subscription event type is supported by the active RMW implementation.
Definition: event.c:261
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_event_fini(rcl_event_t *event)
Definition: event.c:187
RCL_PUBLIC bool rcl_event_is_valid(const rcl_event_t *event)
Check that the event is valid.
Definition: event.c:219
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_publisher_event_init(rcl_event_t *event, const rcl_publisher_t *publisher, const rcl_publisher_event_type_t event_type)
Initialize an rcl_event_t with a publisher.
Definition: event.c:43
RCL_PUBLIC RCL_WARN_UNUSED bool rcl_publisher_event_type_is_supported(const rcl_publisher_event_type_t event_type)
Check if a publisher event type is supported by the active RMW implementation.
Definition: event.c:233
Structure which encapsulates a ROS QoS event handle.
Definition: event.h:61
rcl_event_impl_t * impl
Pointer to the event implementation.
Definition: event.h:63
rcl_allocator_t allocator
Custom allocator for the publisher, used for incidental allocations.
Definition: publisher.h:49
Structure which encapsulates a ROS Publisher.
Definition: publisher.h:37
rcl_publisher_impl_t * impl
Pointer to the publisher implementation.
Definition: publisher.h:39
rcl_allocator_t allocator
Custom allocator for the subscription, used for incidental allocations.
Definition: subscription.h:52
Structure which encapsulates a ROS Subscription.
Definition: subscription.h:40
rcl_subscription_impl_t * impl
Pointer to the subscription implementation.
Definition: subscription.h:42
#define RCL_RET_EVENT_TAKE_FAILED
Failed to take an event from the event handle.
Definition: types.h:121
#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_EVENT_INVALID
Invalid rcl_event_t given return code.
Definition: types.h:119
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24