ros2_canopen  master
C++ ROS CANopen Library
node_canopen_master.hpp
Go to the documentation of this file.
1 #ifndef NODE_CANOPEN_MASTER_HPP_
2 #define NODE_CANOPEN_MASTER_HPP_
3 
4 #include <yaml-cpp/yaml.h>
5 #include <atomic>
6 #include <lely/coapp/master.hpp>
7 #include <lely/coapp/slave.hpp>
8 #include <lely/ev/exec.hpp>
9 #include <lely/ev/loop.hpp>
10 #include <lely/io2/linux/can.hpp>
11 #include <lely/io2/posix/poll.hpp>
12 #include <lely/io2/sys/io.hpp>
13 #include <lely/io2/sys/sigset.hpp>
14 #include <lely/io2/sys/timer.hpp>
15 #include <rclcpp/rclcpp.hpp>
16 #include <rclcpp_lifecycle/lifecycle_node.hpp>
17 #include <thread>
20 
21 namespace ros2_canopen
22 {
23 namespace node_interfaces
24 {
36 template <class NODETYPE>
38 {
39  static_assert(
40  std::is_base_of<rclcpp::Node, NODETYPE>::value ||
41  std::is_base_of<rclcpp_lifecycle::LifecycleNode, NODETYPE>::value,
42  "NODETYPE must derive from rclcpp::Node or rclcpp_lifecycle::LifecycleNode");
43 
44 protected:
45  NODETYPE * node_;
46 
47  std::atomic<bool> initialised_;
48  std::atomic<bool> configured_;
49  std::atomic<bool> activated_;
50  std::atomic<bool> master_set_;
51 
52  std::shared_ptr<lely::canopen::AsyncMaster> master_;
53  std::shared_ptr<lely::ev::Executor> exec_;
54 
55  std::unique_ptr<lely::io::IoGuard> io_guard_;
56  std::unique_ptr<lely::io::Context> ctx_;
57  std::unique_ptr<lely::io::Poll> poll_;
58  std::unique_ptr<lely::ev::Loop> loop_;
59  std::unique_ptr<lely::io::Timer> timer_;
60  std::unique_ptr<lely::io::CanController> ctrl_;
61  std::unique_ptr<lely::io::CanChannel> chan_;
62  std::unique_ptr<lely::io::SignalSet> sigset_;
63 
64  rclcpp::CallbackGroup::SharedPtr client_cbg_;
65  rclcpp::CallbackGroup::SharedPtr timer_cbg_;
66 
67  YAML::Node config_;
68  uint8_t node_id_;
69  std::chrono::milliseconds non_transmit_timeout_;
70  std::string container_name_;
71  std::string master_dcf_;
72  std::string master_bin_;
73  std::string can_interface_name_;
74 
75  std::thread spinner_;
76 
77 public:
78  NodeCanopenMaster(NODETYPE * node)
79  : initialised_(false), configured_(false), activated_(false), master_set_(false)
80  {
81  node_ = node;
82  }
83 
88  void init() override
89  {
90  RCLCPP_DEBUG(node_->get_logger(), "init_start");
91  if (configured_.load())
92  {
93  throw MasterException("Init: Master is already configured.");
94  }
95  if (activated_.load())
96  {
97  throw MasterException("Init: Master is already activated.");
98  }
99  client_cbg_ = node_->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
100  timer_cbg_ = node_->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
101 
102  node_->declare_parameter("container_name", "");
103  node_->declare_parameter("master_dcf", "");
104  node_->declare_parameter("master_bin", "");
105  node_->declare_parameter("can_interface_name", "vcan0");
106  node_->declare_parameter("node_id", 0);
107  node_->declare_parameter("non_transmit_timeout", 100);
108  node_->declare_parameter("config", "");
109  this->init(true);
110  this->initialised_.store(true);
111  RCLCPP_DEBUG(node_->get_logger(), "init_end");
112  }
113  virtual void init(bool called_from_base) {}
114 
122  void configure() override
123  {
124  if (!initialised_.load())
125  {
126  throw MasterException("Configure: Master is not initialised.");
127  }
128  if (configured_.load())
129  {
130  throw MasterException("Configure: Master is already configured.");
131  }
132  if (activated_.load())
133  {
134  throw MasterException("Configure: Master is already activated.");
135  }
136 
137  int non_transmit_timeout;
138  std::string config;
139 
140  node_->get_parameter("container_name", container_name_);
141  node_->get_parameter("master_dcf", master_dcf_);
142  node_->get_parameter("master_bin", master_bin_);
143  node_->get_parameter("can_interface_name", can_interface_name_);
144  node_->get_parameter("node_id", node_id_);
145  node_->get_parameter("non_transmit_timeout", non_transmit_timeout);
146  node_->get_parameter("config", config);
147 
148  this->config_ = YAML::Load(config);
149  this->non_transmit_timeout_ = std::chrono::milliseconds(non_transmit_timeout);
150 
151  this->configure(true);
152  this->configured_.store(true);
153  }
154 
155  virtual void configure(bool called_from_base) {}
156 
164  void activate() override
165  {
166  RCLCPP_DEBUG(this->node_->get_logger(), "NodeCanopenMaster activate start");
167  if (!initialised_.load())
168  {
169  throw MasterException("Activate: master is not initialised");
170  }
171  if (!configured_.load())
172  {
173  throw MasterException("Activate: master is not configured");
174  }
175  if (activated_.load())
176  {
177  throw MasterException("Activate: master is already activated");
178  }
179 
180  io_guard_ = std::make_unique<lely::io::IoGuard>();
181  ctx_ = std::make_unique<lely::io::Context>();
182  poll_ = std::make_unique<lely::io::Poll>(*ctx_);
183  loop_ = std::make_unique<lely::ev::Loop>(poll_->get_poll());
184 
185  exec_ = std::make_shared<lely::ev::Executor>(loop_->get_executor());
186  timer_ = std::make_unique<lely::io::Timer>(*poll_, *exec_, CLOCK_MONOTONIC);
187  ctrl_ = std::make_unique<lely::io::CanController>(can_interface_name_.c_str());
188  chan_ = std::make_unique<lely::io::CanChannel>(*poll_, *exec_);
189  chan_->open(*ctrl_);
190 
191  this->activate(true);
192  if (!master_)
193  {
194  throw MasterException("Activate: master not set");
195  }
196  this->master_set_.store(true);
197  this->master_->Reset();
198  this->spinner_ = std::thread(
199  [this]()
200  {
201  try
202  {
203  loop_->run();
204  }
205  catch (const std::exception & e)
206  {
207  RCLCPP_INFO(this->node_->get_logger(), e.what());
208  }
209  RCLCPP_INFO(this->node_->get_logger(), "Canopen master loop stopped");
210  });
211  this->activated_.store(true);
212  RCLCPP_DEBUG(this->node_->get_logger(), "NodeCanopenMaster activate end");
213  }
223  virtual void activate(bool called_from_base) {}
224 
232  void deactivate() override
233  {
234  if (!initialised_.load())
235  {
236  throw MasterException("Deactivate: master is not initialised");
237  }
238  if (!configured_.load())
239  {
240  throw MasterException("Deactivate: master is not configured");
241  }
242  if (!activated_.load())
243  {
244  throw MasterException("Deactivate: master is not activated");
245  }
246  exec_->post(
247  [this]()
248  {
249  RCLCPP_INFO(node_->get_logger(), "Lely Core Context Shutdown");
250  ctx_->shutdown();
251  });
252  this->spinner_.join();
253 
254  this->deactivate(true);
255  this->activated_.store(false);
256  }
257 
266  virtual void deactivate(bool called_from_base) {}
267 
275  void cleanup() override
276  {
277  if (!initialised_.load())
278  {
279  throw MasterException("Cleanup: master is not initialised.");
280  }
281  if (!configured_.load())
282  {
283  throw MasterException("Cleanup: master is not configured");
284  }
285  if (activated_.load())
286  {
287  throw MasterException("Cleanup: master is still active");
288  }
289  this->cleanup(true);
290  this->configured_.store(false);
291  }
292  virtual void cleanup(bool called_from_base) {}
293 
300  void shutdown() override
301  {
302  RCLCPP_DEBUG(this->node_->get_logger(), "Shutting down.");
303  if (this->activated_)
304  {
305  this->deactivate();
306  }
307 
308  if (this->configured_)
309  {
310  this->cleanup();
311  }
312  shutdown(true);
313 
314  this->master_set_.store(false);
315  this->initialised_.store(false);
316  this->configured_.store(false);
317  this->activated_.store(false);
318  }
319  virtual void shutdown(bool called_from_base) {}
320 
326  virtual std::shared_ptr<lely::canopen::AsyncMaster> get_master()
327  {
328  if (!master_set_.load())
329  {
330  throw MasterException("Get Master: Master is not set.");
331  }
332  return master_;
333  }
339  virtual std::shared_ptr<lely::ev::Executor> get_executor()
340  {
341  if (!master_set_.load())
342  {
343  throw MasterException("Get Executor: master is not set");
344  }
345  return exec_;
346  }
347 };
348 } // namespace node_interfaces
349 } // namespace ros2_canopen
350 
351 #endif
Master Exception.
Definition: master_error.hpp:16
Node Canopen Master Interface.
Definition: node_canopen_master_interface.hpp:20
Node Canopen Master.
Definition: node_canopen_master.hpp:38
YAML::Node config_
Definition: node_canopen_master.hpp:67
void shutdown() override
Shutdown the driver.
Definition: node_canopen_master.hpp:300
std::unique_ptr< lely::ev::Loop > loop_
Definition: node_canopen_master.hpp:58
rclcpp::CallbackGroup::SharedPtr client_cbg_
Definition: node_canopen_master.hpp:64
virtual void deactivate(bool called_from_base)
Deactivate hook for derived classes.
Definition: node_canopen_master.hpp:266
void configure() override
Configure the driver.
Definition: node_canopen_master.hpp:122
virtual void init(bool called_from_base)
Definition: node_canopen_master.hpp:113
virtual void shutdown(bool called_from_base)
Definition: node_canopen_master.hpp:319
std::string can_interface_name_
Definition: node_canopen_master.hpp:73
std::string master_bin_
Definition: node_canopen_master.hpp:72
std::shared_ptr< lely::ev::Executor > exec_
Definition: node_canopen_master.hpp:53
std::unique_ptr< lely::io::CanChannel > chan_
Definition: node_canopen_master.hpp:61
void init() override
Initialise Master.
Definition: node_canopen_master.hpp:88
virtual std::shared_ptr< lely::canopen::AsyncMaster > get_master()
Get the master object.
Definition: node_canopen_master.hpp:326
virtual void activate(bool called_from_base)
Activate hook for derived classes.
Definition: node_canopen_master.hpp:223
std::atomic< bool > master_set_
Definition: node_canopen_master.hpp:50
std::unique_ptr< lely::io::Context > ctx_
Definition: node_canopen_master.hpp:56
std::unique_ptr< lely::io::IoGuard > io_guard_
Definition: node_canopen_master.hpp:55
std::unique_ptr< lely::io::Poll > poll_
Definition: node_canopen_master.hpp:57
std::string container_name_
Definition: node_canopen_master.hpp:70
virtual std::shared_ptr< lely::ev::Executor > get_executor()
Get the executor object.
Definition: node_canopen_master.hpp:339
std::chrono::milliseconds non_transmit_timeout_
Definition: node_canopen_master.hpp:69
NODETYPE * node_
Definition: node_canopen_master.hpp:42
virtual void configure(bool called_from_base)
Definition: node_canopen_master.hpp:155
std::unique_ptr< lely::io::CanController > ctrl_
Definition: node_canopen_master.hpp:60
std::shared_ptr< lely::canopen::AsyncMaster > master_
Definition: node_canopen_master.hpp:52
void deactivate() override
Deactivate the driver.
Definition: node_canopen_master.hpp:232
void cleanup() override
Cleanup the driver.
Definition: node_canopen_master.hpp:275
rclcpp::CallbackGroup::SharedPtr timer_cbg_
Definition: node_canopen_master.hpp:65
std::unique_ptr< lely::io::Timer > timer_
Definition: node_canopen_master.hpp:59
std::atomic< bool > activated_
Definition: node_canopen_master.hpp:49
virtual void cleanup(bool called_from_base)
Definition: node_canopen_master.hpp:292
void activate() override
Activate the driver.
Definition: node_canopen_master.hpp:164
std::atomic< bool > initialised_
Definition: node_canopen_master.hpp:47
std::thread spinner_
Definition: node_canopen_master.hpp:75
std::unique_ptr< lely::io::SignalSet > sigset_
Definition: node_canopen_master.hpp:62
NodeCanopenMaster(NODETYPE *node)
Definition: node_canopen_master.hpp:78
std::string master_dcf_
Definition: node_canopen_master.hpp:71
uint8_t node_id_
Definition: node_canopen_master.hpp:68
std::atomic< bool > configured_
Definition: node_canopen_master.hpp:48
Definition: configuration_manager.hpp:28