ROS 2 rclcpp + rcl - kilted  kilted
ROS 2 C++ Client Library with ROS Client Library
parameter_event_handler.cpp
1 // Copyright 2019 Intel Corporation
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 <functional>
16 #include <memory>
17 #include <string>
18 #include <unordered_map>
19 #include <utility>
20 #include <vector>
21 
22 #include "rclcpp/parameter_event_handler.hpp"
23 #include "rcpputils/join.hpp"
24 
25 namespace rclcpp
26 {
27 
28 ParameterEventCallbackHandle::SharedPtr
30  ParameterEventCallbackType callback)
31 {
32  std::lock_guard<std::recursive_mutex> lock(callbacks_->mutex_);
33  auto handle = std::make_shared<ParameterEventCallbackHandle>();
34  handle->callback = callback;
35  callbacks_->event_callbacks_.emplace_front(handle);
36 
37  return handle;
38 }
39 
40 void
42  ParameterEventCallbackHandle::SharedPtr callback_handle)
43 {
44  std::lock_guard<std::recursive_mutex> lock(callbacks_->mutex_);
45  auto it = std::find_if(
46  callbacks_->event_callbacks_.begin(),
47  callbacks_->event_callbacks_.end(),
48  [callback_handle](const auto & weak_handle) {
49  return callback_handle.get() == weak_handle.lock().get();
50  });
51  if (it != callbacks_->event_callbacks_.end()) {
52  callbacks_->event_callbacks_.erase(it);
53  } else {
54  throw std::runtime_error("Callback doesn't exist");
55  }
56 }
57 
58 ParameterCallbackHandle::SharedPtr
60  const std::string & parameter_name,
61  ParameterCallbackType callback,
62  const std::string & node_name)
63 {
64  std::lock_guard<std::recursive_mutex> lock(callbacks_->mutex_);
65  auto full_node_name = resolve_path(node_name);
66 
67  auto handle = std::make_shared<ParameterCallbackHandle>();
68  handle->callback = callback;
69  handle->parameter_name = parameter_name;
70  handle->node_name = full_node_name;
71  // the last callback registered is executed first.
72  callbacks_->parameter_callbacks_[{parameter_name, full_node_name}].emplace_front(handle);
73 
74  return handle;
75 }
76 
77 void
79  ParameterCallbackHandle::SharedPtr callback_handle)
80 {
81  std::lock_guard<std::recursive_mutex> lock(callbacks_->mutex_);
82  auto handle = callback_handle.get();
83  auto & container = callbacks_->parameter_callbacks_[{handle->parameter_name, handle->node_name}];
84  auto it = std::find_if(
85  container.begin(),
86  container.end(),
87  [handle](const auto & weak_handle) {
88  return handle == weak_handle.lock().get();
89  });
90  if (it != container.end()) {
91  container.erase(it);
92  if (container.empty()) {
93  callbacks_->parameter_callbacks_.erase({handle->parameter_name, handle->node_name});
94  }
95  } else {
96  throw std::runtime_error("Callback doesn't exist");
97  }
98 }
99 
100 bool
102  const rcl_interfaces::msg::ParameterEvent & event,
103  rclcpp::Parameter & parameter,
104  const std::string & parameter_name,
105  const std::string & node_name)
106 {
107  if (event.node != node_name) {
108  return false;
109  }
110 
111  for (auto & new_parameter : event.new_parameters) {
112  if (new_parameter.name == parameter_name) {
113  parameter = rclcpp::Parameter::from_parameter_msg(new_parameter);
114  return true;
115  }
116  }
117 
118  for (auto & changed_parameter : event.changed_parameters) {
119  if (changed_parameter.name == parameter_name) {
120  parameter = rclcpp::Parameter::from_parameter_msg(changed_parameter);
121  return true;
122  }
123  }
124 
125  return false;
126 }
127 
130  const rcl_interfaces::msg::ParameterEvent & event,
131  const std::string & parameter_name,
132  const std::string & node_name)
133 {
135  if (!get_parameter_from_event(event, p, parameter_name, node_name)) {
136  if (event.node == node_name) {
137  return rclcpp::Parameter(parameter_name, rclcpp::PARAMETER_NOT_SET);
138  } else {
139  throw std::runtime_error(
140  "The node name '" + node_name + "' of parameter '" + parameter_name +
141  +"' doesn't match the node name '" + event.node + "' in parameter event");
142  }
143  }
144  return p;
145 }
146 
147 std::vector<rclcpp::Parameter>
149  const rcl_interfaces::msg::ParameterEvent & event)
150 {
151  std::vector<rclcpp::Parameter> params;
152 
153  for (auto & new_parameter : event.new_parameters) {
154  params.push_back(rclcpp::Parameter::from_parameter_msg(new_parameter));
155  }
156 
157  for (auto & changed_parameter : event.changed_parameters) {
158  params.push_back(rclcpp::Parameter::from_parameter_msg(changed_parameter));
159  }
160 
161  return params;
162 }
163 
164 void
165 ParameterEventHandler::Callbacks::event_callback(const rcl_interfaces::msg::ParameterEvent & event)
166 {
167  std::lock_guard<std::recursive_mutex> lock(mutex_);
168 
169  for (auto it = parameter_callbacks_.begin(); it != parameter_callbacks_.end(); ++it) {
171  if (get_parameter_from_event(event, p, it->first.first, it->first.second)) {
172  for (auto cb = it->second.begin(); cb != it->second.end(); ++cb) {
173  auto shared_handle = cb->lock();
174  if (nullptr != shared_handle) {
175  shared_handle->callback(p);
176  } else {
177  cb = it->second.erase(cb);
178  }
179  }
180  }
181  }
182 
183  for (auto event_cb = event_callbacks_.begin(); event_cb != event_callbacks_.end(); ++event_cb) {
184  auto shared_event_handle = event_cb->lock();
185  if (nullptr != shared_event_handle) {
186  shared_event_handle->callback(event);
187  } else {
188  event_cb = event_callbacks_.erase(event_cb);
189  }
190  }
191 }
192 
193 std::string
194 ParameterEventHandler::resolve_path(const std::string & path)
195 {
196  std::string full_path;
197 
198  if (path == "") {
199  full_path = node_base_->get_fully_qualified_name();
200  } else {
201  full_path = path;
202  if (*path.begin() != '/') {
203  auto ns = node_base_->get_namespace();
204  const std::vector<std::string> paths{ns, path};
205  full_path = (ns == std::string("/")) ? ns + path : rcpputils::join(paths, "/");
206  }
207  }
208 
209  return full_path;
210 }
211 
212 } // namespace rclcpp
RCLCPP_PUBLIC void remove_parameter_callback(ParameterCallbackHandle::SharedPtr callback_handle)
Remove a parameter callback registered with add_parameter_callback.
static RCLCPP_PUBLIC bool get_parameter_from_event(const rcl_interfaces::msg::ParameterEvent &event, rclcpp::Parameter &parameter, const std::string &parameter_name, const std::string &node_name="")
Get an rclcpp::Parameter from a parameter event.
static RCLCPP_PUBLIC std::vector< rclcpp::Parameter > get_parameters_from_event(const rcl_interfaces::msg::ParameterEvent &event)
Get all rclcpp::Parameter values from a parameter event.
RCLCPP_PUBLIC void remove_parameter_event_callback(ParameterEventCallbackHandle::SharedPtr callback_handle)
Remove parameter event callback registered with add_parameter_event_callback.
RCLCPP_PUBLIC RCUTILS_WARN_UNUSED ParameterEventCallbackHandle::SharedPtr add_parameter_event_callback(ParameterEventCallbackType callback)
Set a callback for all parameter events.
RCLCPP_PUBLIC RCUTILS_WARN_UNUSED ParameterCallbackHandle::SharedPtr add_parameter_callback(const std::string &parameter_name, ParameterCallbackType callback, const std::string &node_name="")
Add a callback for a specified parameter.
Structure to store an arbitrary parameter with templated get/set methods.
Definition: parameter.hpp:53
static RCLCPP_PUBLIC Parameter from_parameter_msg(const rcl_interfaces::msg::Parameter &parameter)
Convert a parameter message in a Parameter class object.
Definition: parameter.cpp:145
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC void event_callback(const rcl_interfaces::msg::ParameterEvent &event)
Callback for parameter events subscriptions.