ROS 2 rclcpp + rcl - rolling  rolling-29de98cf
ROS 2 C++ Client Library with ROS Client Library
qos_parameters.hpp
1 // Copyright 2020 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 #ifndef RCLCPP__DETAIL__QOS_PARAMETERS_HPP_
16 #define RCLCPP__DETAIL__QOS_PARAMETERS_HPP_
17 
18 #include <algorithm>
19 #include <array>
20 #include <functional>
21 #include <initializer_list>
22 #include <map>
23 #include <sstream>
24 #include <string>
25 #include <type_traits>
26 #include <vector>
27 
28 #include "rcl_interfaces/msg/parameter_descriptor.hpp"
29 #include "rcpputils/pointer_traits.hpp"
30 #include "rmw/qos_string_conversions.h"
31 
32 #include "rclcpp/duration.hpp"
33 #include "rclcpp/node_interfaces/get_node_parameters_interface.hpp"
34 #include "rclcpp/node_interfaces/node_parameters_interface.hpp"
35 #include "rclcpp/qos_overriding_options.hpp"
36 
37 namespace rclcpp
38 {
39 namespace detail
40 {
41 
44 {
45  static constexpr const char * entity_type() {return "publisher";}
46  static constexpr auto allowed_policies()
47  {
48  return std::array<::rclcpp::QosPolicyKind, 9> {
49  QosPolicyKind::AvoidRosNamespaceConventions,
50  QosPolicyKind::Deadline,
51  QosPolicyKind::Durability,
52  QosPolicyKind::History,
53  QosPolicyKind::Depth,
54  QosPolicyKind::Lifespan,
55  QosPolicyKind::Liveliness,
56  QosPolicyKind::LivelinessLeaseDuration,
57  QosPolicyKind::Reliability,
58  };
59  }
60 };
61 
64 {
65  static constexpr const char * entity_type() {return "subscription";}
66  static constexpr auto allowed_policies()
67  {
68  return std::array<::rclcpp::QosPolicyKind, 8> {
69  QosPolicyKind::AvoidRosNamespaceConventions,
70  QosPolicyKind::Deadline,
71  QosPolicyKind::Durability,
72  QosPolicyKind::History,
73  QosPolicyKind::Depth,
74  QosPolicyKind::Liveliness,
75  QosPolicyKind::LivelinessLeaseDuration,
76  QosPolicyKind::Reliability,
77  };
78  }
79 };
80 
82 inline
83 ::rclcpp::ParameterValue
84 get_default_qos_param_value(rclcpp::QosPolicyKind policy, const rclcpp::QoS & qos);
85 
87 inline
88 void
89 apply_qos_override(
90  rclcpp::QosPolicyKind policy, rclcpp::ParameterValue value, rclcpp::QoS & qos);
91 
92 inline
94 declare_parameter_or_get(
96  const std::string & param_name,
97  rclcpp::ParameterValue param_value,
98  rcl_interfaces::msg::ParameterDescriptor descriptor)
99 {
100  try {
101  // enable parameter modification to make it possible
102  // to declare QoS override parameters during parameter callbacks.
103  parameters_interface.enable_parameter_modification();
104  return parameters_interface.declare_parameter(
105  param_name, param_value, descriptor);
107  return parameters_interface.get_parameter(param_name).get_parameter_value();
108  }
109 }
110 
111 #ifdef DOXYGEN_ONLY
113 
124 template<typename NodeT, typename EntityQosParametersTraits>
126  declare_qos_parameters(
127  const ::rclcpp::QosOverridingOptions & options,
128  NodeT & node,
129  const std::string & topic_name,
130  const ::rclcpp::QoS & default_qos,
131  EntityQosParametersTraits);
132 
133 #else
134 
135 template<typename NodeT, typename EntityQosParametersTraits>
136 std::enable_if_t<
137  (rclcpp::node_interfaces::has_node_parameters_interface<
138  decltype(std::declval<typename rcpputils::remove_pointer<NodeT>::type>())>::value ||
139  std::is_same<typename std::decay_t<NodeT>,
140  rclcpp::node_interfaces::NodeParametersInterface::SharedPtr>::value),
141  rclcpp::QoS>
142 declare_qos_parameters(
143  const ::rclcpp::QosOverridingOptions & options,
144  NodeT & node,
145  const std::string & topic_name,
146  const ::rclcpp::QoS & default_qos,
147  EntityQosParametersTraits)
148 {
149  auto & parameters_interface = *rclcpp::node_interfaces::get_node_parameters_interface(node);
150  std::string param_prefix;
151  const auto & id = options.get_id();
152  {
153  std::ostringstream oss{"qos_overrides.", std::ios::ate};
154  oss << topic_name << "." << EntityQosParametersTraits::entity_type();
155  if (!id.empty()) {
156  oss << "_" << id;
157  }
158  oss << ".";
159  param_prefix = oss.str();
160  }
161  std::string param_description_suffix;
162  {
163  std::ostringstream oss{"} for ", std::ios::ate};
164  oss << EntityQosParametersTraits::entity_type() << " {" << topic_name << "}";
165  if (!id.empty()) {
166  oss << " with id {" << id << "}";
167  }
168  param_description_suffix = oss.str();
169  }
170  rclcpp::QoS qos = default_qos;
171  for (auto policy : EntityQosParametersTraits::allowed_policies()) {
172  if (
173  std::count(options.get_policy_kinds().begin(), options.get_policy_kinds().end(), policy))
174  {
175  std::ostringstream param_name{param_prefix, std::ios::ate};
176  param_name << qos_policy_kind_to_cstr(policy);
177  std::ostringstream param_desciption{"qos policy {", std::ios::ate};
178  param_desciption << qos_policy_kind_to_cstr(policy) << param_description_suffix;
179  rcl_interfaces::msg::ParameterDescriptor descriptor{};
180  descriptor.description = param_desciption.str();
181  descriptor.read_only = true;
182  auto value = declare_parameter_or_get(
183  parameters_interface, param_name.str(),
184  get_default_qos_param_value(policy, qos), descriptor);
185  ::rclcpp::detail::apply_qos_override(policy, value, qos);
186  }
187  }
188  const auto & validation_callback = options.get_validation_callback();
189  if (validation_callback) {
190  auto result = validation_callback(qos);
191  if (!result.successful) {
193  "validation callback failed: " + result.reason};
194  }
195  }
196  return qos;
197 }
198 
199 // TODO(ivanpauno): This overload cannot declare the QoS parameters, as a node parameters interface
200 // was not provided.
201 template<typename NodeT, typename EntityQosParametersTraits>
202 std::enable_if_t<
203  !(rclcpp::node_interfaces::has_node_parameters_interface<
204  decltype(std::declval<typename rcpputils::remove_pointer<NodeT>::type>())>::value ||
205  std::is_same<typename std::decay_t<NodeT>,
206  rclcpp::node_interfaces::NodeParametersInterface::SharedPtr>::value),
207  rclcpp::QoS>
208 declare_qos_parameters(
209  const ::rclcpp::QosOverridingOptions & options,
210  NodeT &,
211  const std::string &,
212  const ::rclcpp::QoS & default_qos,
213  EntityQosParametersTraits)
214 {
215  if (options.get_policy_kinds().size()) {
216  std::runtime_error exc{
217  "passed non-default qos overriding options without providing a parameters interface"};
218  throw exc;
219  }
220  return default_qos;
221 }
222 
223 #endif
224 
226 #define RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING( \
227  kind_lower, kind_upper, parameter_value, rclcpp_qos) \
228  do { \
229  auto policy_string = (parameter_value).get<std::string>(); \
230  auto policy_value = rmw_qos_ ## kind_lower ## _policy_from_str(policy_string.c_str()); \
231  if (RMW_QOS_POLICY_ ## kind_upper ## _UNKNOWN == policy_value) { \
232  throw std::invalid_argument{"unknown QoS policy " #kind_lower " value: " + policy_string}; \
233  } \
234  ((rclcpp_qos).kind_lower)(policy_value); \
235  } while (0)
236 
237 inline
238 void
239 apply_qos_override(
240  rclcpp::QosPolicyKind policy, rclcpp::ParameterValue value, rclcpp::QoS & qos)
241 {
242  switch (policy) {
243  case QosPolicyKind::AvoidRosNamespaceConventions:
244  qos.avoid_ros_namespace_conventions(value.get<bool>());
245  break;
246  case QosPolicyKind::Deadline:
247  qos.deadline(::rclcpp::Duration::from_nanoseconds(value.get<int64_t>()));
248  break;
249  case QosPolicyKind::Durability:
250  RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
251  durability, DURABILITY, value, qos);
252  break;
253  case QosPolicyKind::History:
254  RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
255  history, HISTORY, value, qos);
256  break;
257  case QosPolicyKind::Depth:
258  qos.get_rmw_qos_profile().depth = static_cast<size_t>(value.get<int64_t>());
259  break;
260  case QosPolicyKind::Lifespan:
261  qos.lifespan(::rclcpp::Duration::from_nanoseconds(value.get<int64_t>()));
262  break;
263  case QosPolicyKind::Liveliness:
264  RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
265  liveliness, LIVELINESS, value, qos);
266  break;
267  case QosPolicyKind::LivelinessLeaseDuration:
269  break;
270  case QosPolicyKind::Reliability:
271  RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
272  reliability, RELIABILITY, value, qos);
273  break;
274  case QosPolicyKind::Invalid:
275  throw std::invalid_argument{"invalid QosPolicyKind"};
276  }
277 }
278 
280 inline
281 int64_t
282 rmw_duration_to_int64_t(rmw_time_t rmw_duration)
283 {
284  return ::rclcpp::Duration(
285  static_cast<int32_t>(rmw_duration.sec),
286  static_cast<uint32_t>(rmw_duration.nsec)
287  ).nanoseconds();
288 }
289 
291 inline
292 const char *
293 check_if_stringified_policy_is_null(const char * policy_value_stringified, QosPolicyKind kind)
294 {
295  if (!policy_value_stringified) {
296  std::ostringstream oss{"unknown value for policy kind {", std::ios::ate};
297  oss << kind << "}";
298  throw std::invalid_argument{oss.str()};
299  }
300  return policy_value_stringified;
301 }
302 
303 inline
304 ::rclcpp::ParameterValue
305 get_default_qos_param_value(rclcpp::QosPolicyKind kind, const rclcpp::QoS & qos)
306 {
307  using ParameterValue = ::rclcpp::ParameterValue;
308  const auto & rmw_qos = qos.get_rmw_qos_profile();
309  switch (kind) {
310  case QosPolicyKind::AvoidRosNamespaceConventions:
311  return ParameterValue(rmw_qos.avoid_ros_namespace_conventions);
312  case QosPolicyKind::Deadline:
313  return ParameterValue(rmw_duration_to_int64_t(rmw_qos.deadline));
314  case QosPolicyKind::Durability:
315  return ParameterValue(
316  check_if_stringified_policy_is_null(
317  rmw_qos_durability_policy_to_str(rmw_qos.durability), kind));
318  case QosPolicyKind::History:
319  return ParameterValue(
320  check_if_stringified_policy_is_null(
321  rmw_qos_history_policy_to_str(rmw_qos.history), kind));
322  case QosPolicyKind::Depth:
323  return ParameterValue(static_cast<int64_t>(rmw_qos.depth));
324  case QosPolicyKind::Lifespan:
325  return ParameterValue(rmw_duration_to_int64_t(rmw_qos.lifespan));
326  case QosPolicyKind::Liveliness:
327  return ParameterValue(
328  check_if_stringified_policy_is_null(
329  rmw_qos_liveliness_policy_to_str(rmw_qos.liveliness), kind));
330  case QosPolicyKind::LivelinessLeaseDuration:
331  return ParameterValue(rmw_duration_to_int64_t(rmw_qos.liveliness_lease_duration));
332  case QosPolicyKind::Reliability:
333  return ParameterValue(
334  check_if_stringified_policy_is_null(
335  rmw_qos_reliability_policy_to_str(rmw_qos.reliability), kind));
336  case QosPolicyKind::Invalid:
337  throw std::invalid_argument{"invalid QoS policy kind"};
338  }
339 
340  return ParameterValue();
341 }
342 
343 } // namespace detail
344 } // namespace rclcpp
345 
346 #endif // RCLCPP__DETAIL__QOS_PARAMETERS_HPP_
static Duration from_nanoseconds(rcl_duration_value_t nanoseconds)
Create a duration object from an integer number representing nanoseconds.
Definition: duration.cpp:313
Store the type and value of a parameter.
RCLCPP_PUBLIC const rclcpp::ParameterValue & get_parameter_value() const
Get the internal storage for the parameter value.
Definition: parameter.cpp:85
Encapsulation of Quality of Service settings.
Definition: qos.hpp:114
QoS & lifespan(rmw_time_t lifespan)
Set the lifespan setting.
Definition: qos.cpp:236
QoS & deadline(rmw_time_t deadline)
Set the deadline setting.
Definition: qos.cpp:223
QoS & liveliness_lease_duration(rmw_time_t liveliness_lease_duration)
Set the liveliness_lease_duration setting.
Definition: qos.cpp:264
rmw_qos_profile_t & get_rmw_qos_profile()
Return the rmw qos profile.
Definition: qos.cpp:109
QoS & avoid_ros_namespace_conventions(bool avoid_ros_namespace_conventions)
Set the avoid_ros_namespace_conventions setting.
Definition: qos.cpp:277
Thrown if the QoS overrides provided aren't valid.
Definition: exceptions.hpp:344
Thrown if parameter is already declared.
Definition: exceptions.hpp:303
Pure virtual interface class for the NodeParameters part of the Node API.
virtual RCLCPP_PUBLIC const rclcpp::ParameterValue & declare_parameter(const std::string &name, const rclcpp::ParameterValue &default_value, const rcl_interfaces::msg::ParameterDescriptor &parameter_descriptor=rcl_interfaces::msg::ParameterDescriptor(), bool ignore_override=false)=0
Declare and initialize a parameter.
virtual RCLCPP_PUBLIC rclcpp::Parameter get_parameter(const std::string &name) const =0
Get the description of one parameter given a name.
virtual RCLCPP_PUBLIC void enable_parameter_modification()=0
Enable parameter modification recursively during parameter callbacks.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.