Skip to content

Commit 01a6bef

Browse files
jaisontjmm318
andauthored
Support for ON_REQUESTED_INCOMPATIBLE_QOS and ON_OFFERED_INCOMPATIBLE_QOS events (#924)
Signed-off-by: Jaison Titus <[email protected]> Signed-off-by: Miaofei <[email protected]> Co-authored-by: Miaofei <[email protected]>
1 parent efa4754 commit 01a6bef

File tree

6 files changed

+216
-3
lines changed

6 files changed

+216
-3
lines changed

rclcpp/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,16 @@ if(BUILD_TESTING)
359359
${PROJECT_NAME}
360360
)
361361
endif()
362+
ament_add_gtest(test_qos_event test/test_qos_event.cpp)
363+
if(TARGET test_qos_event)
364+
ament_target_dependencies(test_qos_event
365+
"rmw"
366+
"test_msgs"
367+
)
368+
target_link_libraries(test_qos_event
369+
${PROJECT_NAME}
370+
)
371+
endif()
362372
ament_add_gtest(test_rate test/test_rate.cpp)
363373
if(TARGET test_rate)
364374
ament_target_dependencies(test_rate

rclcpp/include/rclcpp/publisher.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,11 @@ class Publisher : public PublisherBase
8484
options_.event_callbacks.liveliness_callback,
8585
RCL_PUBLISHER_LIVELINESS_LOST);
8686
}
87-
87+
if (options_.event_callbacks.incompatible_qos_callback) {
88+
this->add_event_handler(
89+
options_.event_callbacks.incompatible_qos_callback,
90+
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
91+
}
8892
// Setup continues in the post construction method, post_init_setup().
8993
}
9094

rclcpp/include/rclcpp/qos_event.hpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
#define RCLCPP__QOS_EVENT_HPP_
1717

1818
#include <functional>
19+
#include <string>
1920

2021
#include "rcl/error_handling.h"
22+
#include "rmw/incompatible_qos_events_statuses.h"
2123

2224
#include "rcutils/logging_macros.h"
2325

@@ -32,24 +34,46 @@ using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
3234
using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
3335
using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
3436
using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
37+
using QOSOfferedIncompatibleQoSInfo = rmw_offered_qos_incompatible_event_status_t;
38+
using QOSRequestedIncompatibleQoSInfo = rmw_requested_qos_incompatible_event_status_t;
3539

3640
using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequestedInfo &)>;
3741
using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
3842
using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
3943
using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
44+
using QOSOfferedIncompatibleQoSCallbackType = std::function<void (QOSOfferedIncompatibleQoSInfo &)>;
45+
using QOSRequestedIncompatibleQoSCallbackType =
46+
std::function<void (QOSRequestedIncompatibleQoSInfo &)>;
4047

4148
/// Contains callbacks for various types of events a Publisher can receive from the middleware.
4249
struct PublisherEventCallbacks
4350
{
4451
QOSDeadlineOfferedCallbackType deadline_callback;
4552
QOSLivelinessLostCallbackType liveliness_callback;
53+
QOSOfferedIncompatibleQoSCallbackType incompatible_qos_callback;
4654
};
4755

4856
/// Contains callbacks for non-message events that a Subscription can receive from the middleware.
4957
struct SubscriptionEventCallbacks
5058
{
5159
QOSDeadlineRequestedCallbackType deadline_callback;
5260
QOSLivelinessChangedCallbackType liveliness_callback;
61+
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_callback;
62+
};
63+
64+
class UnsupportedEventTypeException : public exceptions::RCLErrorBase, public std::runtime_error
65+
{
66+
public:
67+
RCLCPP_PUBLIC
68+
UnsupportedEventTypeException(
69+
rcl_ret_t ret,
70+
const rcl_error_state_t * error_state,
71+
const std::string & prefix);
72+
73+
RCLCPP_PUBLIC
74+
UnsupportedEventTypeException(
75+
const exceptions::RCLErrorBase & base_exc,
76+
const std::string & prefix);
5377
};
5478

5579
class QOSEventHandlerBase : public Waitable
@@ -94,9 +118,11 @@ class QOSEventHandler : public QOSEventHandlerBase
94118
rcl_ret_t ret = init_func(&event_handle_, parent_handle, event_type);
95119
if (ret != RCL_RET_OK) {
96120
if (ret == RCL_RET_UNSUPPORTED) {
97-
rclcpp::exceptions::throw_from_rcl_error(ret, "event type is not supported");
121+
UnsupportedEventTypeException exc(ret, rcl_get_error_state(), "Failed to initialize event");
122+
rcl_reset_error();
123+
throw exc;
98124
} else {
99-
rclcpp::exceptions::throw_from_rcl_error(ret, "could not create event");
125+
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to initialize event");
100126
}
101127
}
102128
}

rclcpp/include/rclcpp/subscription.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ class Subscription : public SubscriptionBase
118118
options.event_callbacks.liveliness_callback,
119119
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
120120
}
121+
if (options.event_callbacks.incompatible_qos_callback) {
122+
this->add_event_handler(
123+
options.event_callbacks.incompatible_qos_callback,
124+
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
125+
}
121126

122127
// Setup intra process publishing if requested.
123128
if (rclcpp::detail::resolve_use_intra_process(options, *node_base)) {

rclcpp/src/rclcpp/qos_event.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,27 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
#include <string>
16+
1517
#include "rclcpp/qos_event.hpp"
1618

1719
namespace rclcpp
1820
{
1921

22+
UnsupportedEventTypeException::UnsupportedEventTypeException(
23+
rcl_ret_t ret,
24+
const rcl_error_state_t * error_state,
25+
const std::string & prefix)
26+
: UnsupportedEventTypeException(exceptions::RCLErrorBase(ret, error_state), prefix)
27+
{}
28+
29+
UnsupportedEventTypeException::UnsupportedEventTypeException(
30+
const exceptions::RCLErrorBase & base_exc,
31+
const std::string & prefix)
32+
: exceptions::RCLErrorBase(base_exc),
33+
std::runtime_error(prefix + (prefix.empty() ? "" : ": ") + base_exc.formatted_message)
34+
{}
35+
2036
QOSEventHandlerBase::~QOSEventHandlerBase()
2137
{
2238
if (rcl_event_fini(&event_handle_) != RCL_RET_OK) {

rclcpp/test/test_qos_event.cpp

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
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+
#include <gtest/gtest.h>
16+
17+
#include <memory>
18+
#include <string>
19+
20+
#include "rclcpp/rclcpp.hpp"
21+
#include "rmw/rmw.h"
22+
#include "test_msgs/msg/empty.hpp"
23+
24+
class TestQosEvent : public ::testing::Test
25+
{
26+
protected:
27+
static void SetUpTestCase()
28+
{
29+
rclcpp::init(0, nullptr);
30+
}
31+
32+
void SetUp()
33+
{
34+
node = std::make_shared<rclcpp::Node>("test_qos_event", "/ns");
35+
is_fastrtps =
36+
std::string(rmw_get_implementation_identifier()).find("rmw_fastrtps") != std::string::npos;
37+
}
38+
39+
void TearDown()
40+
{
41+
node.reset();
42+
}
43+
44+
static constexpr char topic_name[] = "test_topic";
45+
rclcpp::Node::SharedPtr node;
46+
bool is_fastrtps;
47+
};
48+
49+
constexpr char TestQosEvent::topic_name[];
50+
51+
/*
52+
Testing construction of a publishers with QoS event callback functions.
53+
*/
54+
TEST_F(TestQosEvent, test_publisher_constructor)
55+
{
56+
rclcpp::PublisherOptions options;
57+
58+
// options arg with no callbacks
59+
auto publisher = node->create_publisher<test_msgs::msg::Empty>(
60+
topic_name, 10, options);
61+
62+
// options arg with one of the callbacks
63+
options.event_callbacks.deadline_callback =
64+
[node = node.get()](rclcpp::QOSDeadlineOfferedInfo & event) {
65+
RCLCPP_INFO(
66+
node->get_logger(),
67+
"Offered deadline missed - total %d (delta %d)",
68+
event.total_count, event.total_count_change);
69+
};
70+
publisher = node->create_publisher<test_msgs::msg::Empty>(
71+
topic_name, 10, options);
72+
73+
// options arg with two of the callbacks
74+
options.event_callbacks.liveliness_callback =
75+
[node = node.get()](rclcpp::QOSLivelinessLostInfo & event) {
76+
RCLCPP_INFO(
77+
node->get_logger(),
78+
"Liveliness lost - total %d (delta %d)",
79+
event.total_count, event.total_count_change);
80+
};
81+
publisher = node->create_publisher<test_msgs::msg::Empty>(
82+
topic_name, 10, options);
83+
84+
// options arg with three of the callbacks
85+
options.event_callbacks.incompatible_qos_callback =
86+
[node = node.get()](rclcpp::QOSOfferedIncompatibleQoSInfo & event) {
87+
RCLCPP_INFO(
88+
node->get_logger(),
89+
"Offered incompatible qos - total %d (delta %d), last_policy_kind: %d",
90+
event.total_count, event.total_count_change, event.last_policy_kind);
91+
};
92+
try {
93+
publisher = node->create_publisher<test_msgs::msg::Empty>(
94+
topic_name, 10, options);
95+
} catch (const rclcpp::UnsupportedEventTypeException & /*exc*/) {
96+
EXPECT_TRUE(is_fastrtps);
97+
}
98+
}
99+
100+
/*
101+
Testing construction of a subscriptions with QoS event callback functions.
102+
*/
103+
TEST_F(TestQosEvent, test_subscription_constructor)
104+
{
105+
rclcpp::SubscriptionOptions options;
106+
107+
auto message_callback = [node = node.get()](const test_msgs::msg::Empty::SharedPtr /*msg*/) {
108+
RCLCPP_INFO(node->get_logger(), "Message received");
109+
};
110+
111+
// options arg with no callbacks
112+
auto subscription = node->create_subscription<test_msgs::msg::Empty>(
113+
topic_name, 10, message_callback, options);
114+
115+
// options arg with one of the callbacks
116+
options.event_callbacks.deadline_callback =
117+
[node = node.get()](rclcpp::QOSDeadlineRequestedInfo & event) {
118+
RCLCPP_INFO(
119+
node->get_logger(),
120+
"Requested deadline missed - total %d (delta %d)",
121+
event.total_count, event.total_count_change);
122+
};
123+
subscription = node->create_subscription<test_msgs::msg::Empty>(
124+
topic_name, 10, message_callback, options);
125+
126+
// options arg with two of the callbacks
127+
options.event_callbacks.liveliness_callback =
128+
[node = node.get()](rclcpp::QOSLivelinessChangedInfo & event) {
129+
RCLCPP_INFO(
130+
node->get_logger(),
131+
"Liveliness changed - alive %d (delta %d), not alive %d (delta %d)",
132+
event.alive_count, event.alive_count_change,
133+
event.not_alive_count, event.not_alive_count_change);
134+
};
135+
subscription = node->create_subscription<test_msgs::msg::Empty>(
136+
topic_name, 10, message_callback, options);
137+
138+
// options arg with three of the callbacks
139+
options.event_callbacks.incompatible_qos_callback =
140+
[node = node.get()](rclcpp::QOSRequestedIncompatibleQoSInfo & event) {
141+
RCLCPP_INFO(
142+
node->get_logger(),
143+
"Requested incompatible qos - total %d (delta %d), last_policy_kind: %d",
144+
event.total_count, event.total_count_change, event.last_policy_kind);
145+
};
146+
try {
147+
subscription = node->create_subscription<test_msgs::msg::Empty>(
148+
topic_name, 10, message_callback, options);
149+
} catch (const rclcpp::UnsupportedEventTypeException & /*exc*/) {
150+
EXPECT_TRUE(is_fastrtps);
151+
}
152+
}

0 commit comments

Comments
 (0)