Lely core libraries  2.2.5
node.hpp
Go to the documentation of this file.
1 
22 #ifndef LELY_COAPP_NODE_HPP_
23 #define LELY_COAPP_NODE_HPP_
24 
25 #include <lely/coapp/device.hpp>
26 #include <lely/io2/can_net.hpp>
27 #include <lely/io2/tqueue.hpp>
28 
29 #include <functional>
30 #include <memory>
31 #include <string>
32 #include <utility>
33 
34 namespace lely {
35 
36 // The CANopen NMT node service from <lely/co/nmt.hpp>.
37 class CONMT;
38 
39 namespace canopen {
40 
42 enum class NmtCommand {
44  START = 0x01,
46  STOP = 0x02,
48  ENTER_PREOP = 0x80,
50  RESET_NODE = 0x81,
52  RESET_COMM = 0x82
53 };
54 
56 enum class NmtState {
58  BOOTUP = 0x00,
60  STOP = 0x04,
62  START = 0x05,
64  RESET_NODE = 0x06,
66  RESET_COMM = 0x07,
68  PREOP = 0x7f,
70  TOGGLE = 0x80
71 };
72 
73 constexpr NmtState operator&(NmtState lhs, NmtState rhs) {
74  return static_cast<NmtState>(static_cast<int>(lhs) & static_cast<int>(rhs));
75 }
76 
77 constexpr NmtState
78 operator|(NmtState lhs, NmtState rhs) {
79  return static_cast<NmtState>(static_cast<int>(lhs) | static_cast<int>(rhs));
80 }
81 
82 constexpr NmtState
83 operator^(NmtState lhs, NmtState rhs) {
84  return static_cast<NmtState>(static_cast<int>(lhs) ^ static_cast<int>(rhs));
85 }
86 
87 constexpr NmtState
88 operator~(NmtState lhs) {
89  return static_cast<NmtState>(~static_cast<int>(lhs));
90 }
91 
92 inline NmtState&
93 operator&=(NmtState& lhs, NmtState rhs) noexcept {
94  return lhs = lhs & rhs;
95 }
96 
97 inline NmtState&
98 operator|=(NmtState& lhs, NmtState rhs) noexcept {
99  return lhs = lhs | rhs;
100 }
101 
102 inline NmtState&
103 operator^=(NmtState& lhs, NmtState rhs) noexcept {
104  return lhs = lhs ^ rhs;
105 }
106 
115 class Node : public io::CanNet, public Device {
116  friend class LssMaster;
117 
118  public:
119  using duration = io::TimerBase::duration;
120  using time_point = io::TimerBase::time_point;
121 
142  explicit Node(ev_exec_t* exec, io::TimerBase& timer, io::CanChannelBase& chan,
143  const ::std::string& dcf_txt, const ::std::string& dcf_bin = "",
144  uint8_t id = 0xff);
145 
147  explicit Node(io::TimerBase& timer, io::CanChannelBase& chan,
148  const ::std::string& dcf_txt, const ::std::string& dcf_bin = "",
149  uint8_t id = 0xff)
150  : Node(nullptr, timer, chan, dcf_txt, dcf_bin, id) {}
151 
152  Node(const Node&) = delete;
153  Node& operator=(const Node&) = delete;
154 
155  virtual ~Node();
156 
158  ev::Executor GetExecutor() const noexcept;
159 
161  io::ContextBase GetContext() const noexcept;
162 
164  io::Clock GetClock() const noexcept;
165 
170  void SubmitWait(const time_point& t, io_tqueue_wait& wait);
171 
176  void SubmitWait(const duration& d, io_tqueue_wait& wait);
177 
186  template <class F>
187  void
188  SubmitWait(const time_point& t, ev_exec_t* exec, F&& f) {
189  SubmitWait(t,
190  *io::make_timer_queue_wait_wrapper(exec, ::std::forward<F>(f)));
191  }
192 
201  template <class F>
202  void
203  SubmitWait(const duration& d, ev_exec_t* exec, F&& f) {
204  SubmitWait(d,
205  *io::make_timer_queue_wait_wrapper(exec, ::std::forward<F>(f)));
206  }
207 
209  template <class F>
210  typename ::std::enable_if<!::std::is_base_of<
211  io_tqueue_wait, typename ::std::decay<F>::type>::value>::type
212  SubmitWait(const time_point& t, F&& f) {
213  SubmitWait(t, nullptr, ::std::forward<F>(f));
214  }
215 
217  template <class F>
218  typename ::std::enable_if<!::std::is_base_of<
219  io_tqueue_wait, typename ::std::decay<F>::type>::value>::type
220  SubmitWait(const duration& d, F&& f) {
221  SubmitWait(d, nullptr, ::std::forward<F>(f));
222  }
223 
237  ev_exec_t* exec, const time_point& t, io_tqueue_wait** pwait = nullptr);
238 
252  ev_exec_t* exec, const duration& d, io_tqueue_wait** pwait = nullptr);
253 
256  AsyncWait(const time_point& t, io_tqueue_wait** pwait = nullptr) {
257  return AsyncWait(nullptr, t, pwait);
258  }
259 
262  AsyncWait(const duration& d, io_tqueue_wait** pwait = nullptr) {
263  return AsyncWait(nullptr, d, pwait);
264  }
265 
274  bool CancelWait(io_tqueue_wait& wait) noexcept;
275 
283  bool AbortWait(io_tqueue_wait& wait) noexcept;
284 
303  io::CanControllerBase& ctrl, int bitrate,
304  ::std::chrono::milliseconds delay);
305 
312  void OnCanState(
313  ::std::function<void(io::CanState, io::CanState)> on_can_state);
314 
321  void OnCanError(::std::function<void(io::CanError)> on_can_error);
322 
329  void Reset();
330 
340  void ConfigHeartbeat(uint8_t id, const ::std::chrono::milliseconds& ms,
341  ::std::error_code& ec);
342 
353  void ConfigHeartbeat(uint8_t id, const ::std::chrono::milliseconds& ms);
354 
361  void OnCommand(::std::function<void(NmtCommand)> on_command);
362 
369  void OnHeartbeat(::std::function<void(uint8_t, bool)> on_heartbeat);
370 
378  void OnState(::std::function<void(uint8_t, NmtState)> on_state);
379 
387  void OnRpdo(
388  ::std::function<void(int, ::std::error_code, const void*, ::std::size_t)>
389  on_rpdo);
390 
398  void OnRpdoError(::std::function<void(int, uint16_t, uint8_t)> on_rpdo_error);
399 
407  void OnTpdo(
408  ::std::function<void(int, ::std::error_code, const void*, ::std::size_t)>
409  on_tpdo);
410 
417  void OnSync(::std::function<void(uint8_t, const time_point&)> on_sync);
418 
426  void OnSyncError(::std::function<void(uint16_t, uint8_t)> on_sync_error);
427 
434  void OnTime(
435  ::std::function<void(const ::std::chrono::system_clock::time_point&)>
436  on_time);
437 
444  void OnEmcy(
445  ::std::function<void(uint8_t, uint16_t, uint8_t, uint8_t[5])> on_emcy);
446 
454  void OnSwitchBitrate(::std::function<void(int, ::std::chrono::milliseconds)>
455  on_switch_bitrate);
456 
457  protected:
463  friend class Node;
464 
465  public:
466  void lock() override;
467  void unlock() override;
468 
469  protected:
470  TpdoEventMutex(Node& node_) noexcept : node(&node_) {}
471 
472  Node* node;
473  };
474 
479  CANNet* net() const noexcept;
480 
482  void SetTime();
483 
496  virtual void OnCanState(io::CanState new_state,
497  io::CanState old_state) noexcept;
498 
506  virtual void
507  OnCanError(io::CanError error) noexcept {
508  (void)error;
509  }
510 
515  CONMT* nmt() const noexcept;
516 
517  /*
518  * Generates an EMCY error and triggers the error handling behavior according
519  * to object 1029:01 (Error behavior object) in case of a communication error
520  * (emergency error code 0x81xx).
521  *
522  * @param eec the emergency error code.
523  * @param er the error register.
524  * @param msef the manufacturer-specific error code.
525  */
526  void Error(uint16_t eec, uint8_t er,
527  const uint8_t msef[5] = nullptr) noexcept;
528 
536  void RpdoRtr(int num = 0) noexcept;
537 
546  void TpdoEvent(int num = 0) noexcept;
547 
553 #ifndef DOXYGEN_SHOULD_SKIP_THIS
554 
555  private:
556 #endif
557  void on_can_state(io::CanState new_state,
558  io::CanState old_state) noexcept final;
559  void on_can_error(io::CanError error) noexcept final;
560 
568  virtual void
569  OnCommand(NmtCommand cs) noexcept {
570  (void)cs;
571  }
572 
584  virtual void
585  OnHeartbeat(uint8_t id, bool occurred) noexcept {
586  (void)id;
587  (void)occurred;
588  }
589 
599  virtual void
600  OnState(uint8_t id, NmtState st) noexcept {
601  (void)id;
602  (void)st;
603  }
604 
625  virtual void
626  OnRpdo(int num, ::std::error_code ec, const void* p,
627  ::std::size_t n) noexcept {
628  (void)num;
629  (void)ec;
630  (void)p;
631  (void)n;
632  }
633 
647  virtual void
648  OnRpdoError(int num, uint16_t eec, uint8_t er) noexcept {
649  (void)num;
650  Error(eec, er);
651  }
652 
672  virtual void
673  OnTpdo(int num, ::std::error_code ec, const void* p,
674  ::std::size_t n) noexcept {
675  (void)num;
676  (void)ec;
677  (void)p;
678  (void)n;
679  }
680 
689  virtual void
690  OnSync(uint8_t cnt, const time_point& t) noexcept {
691  (void)cnt;
692  (void)t;
693  }
694 
704  virtual void
705  OnSyncError(uint16_t eec, uint8_t er) noexcept {
706  Error(eec, er);
707  }
708 
714  virtual void
715  OnTime(const ::std::chrono::system_clock::time_point& abs_time) noexcept {
716  (void)abs_time;
717  }
718 
727  virtual void
728  OnEmcy(uint8_t id, uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept {
729  (void)id;
730  (void)eec;
731  (void)er;
732  (void)msef;
733  }
734 
743  virtual void
744  OnSwitchBitrate(int bitrate, ::std::chrono::milliseconds delay) noexcept {
745  (void)bitrate;
746  (void)delay;
747  }
748 
760  virtual void OnStore(uint8_t id, int bitrate);
761 
762 #ifdef DOXYGEN_SHOULD_SKIP_THIS
763 
764  private:
765 #endif
766  struct Impl_;
767  ::std::unique_ptr<Impl_> impl_;
768 };
769 
770 } // namespace canopen
771 
772 } // namespace lely
773 
774 #endif // LELY_COAPP_NODE_HPP_
This header file is part of the I/O library; it contains the C++ interface for the timer queue.
An opaque CAN network interface type.
Definition: net.hpp:85
An opaque CANopen NMT master/slave service type.
Definition: nmt.hpp:71
The CANopen device description.
Definition: device.hpp:45
uint8_t id() const noexcept
Returns the node-ID.
Definition: device.cpp:161
The base class for CANopen LSS masters.
A mutex-like object that can be used to postpone the transmission of acyclic and event-driven Transmi...
Definition: node.hpp:462
void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process,...
Definition: node.cpp:311
void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
Definition: node.cpp:316
The base class for CANopen nodes.
Definition: node.hpp:115
ev::Future< void, ::std::exception_ptr > AsyncWait(ev_exec_t *exec, const time_point &t, io_tqueue_wait **pwait=nullptr)
Submits an asynchronous wait operation and creates a future which becomes ready once the wait operati...
Definition: node.cpp:132
ev::Future< void, ::std::exception_ptr > AsyncWait(const duration &d, io_tqueue_wait **pwait=nullptr)
Equivalent to AsyncWait(nullptr, d, pwait).
Definition: node.hpp:262
void Reset()
(Re)starts the node.
Definition: node.cpp:206
void OnSyncError(::std::function< void(uint16_t, uint8_t)> on_sync_error)
Registers the function to be invoked when the data length of a received SYNC message does not match.
Definition: node.cpp:283
typename ::std::enable_if<!::std::is_base_of< io_tqueue_wait, typename ::std::decay< F >::type >::value >::type SubmitWait(const duration &d, F &&f)
Equivalent to SubmitWait(d, nullptr, f).
Definition: node.hpp:220
void OnSync(::std::function< void(uint8_t, const time_point &)> on_sync)
Registers the function to be invoked when a SYNC message is sent/received.
Definition: node.cpp:277
void OnState(::std::function< void(uint8_t, NmtState)> on_state)
Registers the function to be invoked whenan NMT state change or boot-up event is detected for a remot...
Definition: node.cpp:249
void ConfigHeartbeat(uint8_t id, const ::std::chrono::milliseconds &ms, ::std::error_code &ec)
Configures heartbeat consumption for the specified node by updating CANopen object 1016 (Consumer hea...
Definition: node.cpp:217
void SetTime()
Updates the CAN network time.
Definition: node.cpp:326
CANNet * net() const noexcept
Returns a pointer to the internal CAN network interface from <lely/can/net.hpp>.
Definition: node.cpp:321
void OnCanError(::std::function< void(io::CanError)> on_can_error)
Registers the function to be invoked when an error is detected on the CAN bus.
Definition: node.cpp:200
void OnCommand(::std::function< void(NmtCommand)> on_command)
Registers the function to be invoked when an NMT command is received from the master.
Definition: node.cpp:237
virtual void OnTime(const ::std::chrono::system_clock::time_point &abs_time) noexcept
The function invoked when a TIME message is received.
Definition: node.hpp:715
void OnSwitchBitrate(::std::function< void(int, ::std::chrono::milliseconds)> on_switch_bitrate)
Registers the function to be invoked when the LSS master activates the bit rate of all CANopen device...
Definition: node.cpp:304
virtual void OnRpdo(int num, ::std::error_code ec, const void *p, ::std::size_t n) noexcept
The function invoked when a Receive-PDO is processed.
Definition: node.hpp:626
void on_can_state(io::CanState new_state, io::CanState old_state) noexcept final
The function invoked when a CAN bus state change is detected.
Definition: node.cpp:369
Node(ev_exec_t *exec, io::TimerBase &timer, io::CanChannelBase &chan, const ::std::string &dcf_txt, const ::std::string &dcf_bin="", uint8_t id=0xff)
Creates a new CANopen node.
Definition: node.cpp:92
virtual void OnCommand(NmtCommand cs) noexcept
The function invoked when an NMT command is received from the master.
Definition: node.hpp:569
virtual void OnRpdoError(int num, uint16_t eec, uint8_t er) noexcept
The function invoked when a Receive-PDO length mismatch or timeout error occurs.
Definition: node.hpp:648
virtual void OnTpdo(int num, ::std::error_code ec, const void *p, ::std::size_t n) noexcept
The function invoked after a Transmit-PDO is sent or an error occurs.
Definition: node.hpp:673
CONMT * nmt() const noexcept
Returns a pointer to the internal CANopen NMT master/slave service from <lely/co/nmt....
Definition: node.cpp:345
virtual void OnSwitchBitrate(int bitrate, ::std::chrono::milliseconds delay) noexcept
The function invoked when the LSS master activates the bit rate of all CANopen devices in the network...
Definition: node.hpp:744
io::ContextBase GetContext() const noexcept
Returns the underlying I/O context with which this context is registered.
Definition: node.cpp:111
void TpdoEvent(int num=0) noexcept
Triggers the transmission of an acyclic or event-driven PDO.
Definition: node.cpp:364
void OnHeartbeat(::std::function< void(uint8_t, bool)> on_heartbeat)
Registers the function to be invoked when a heartbeat timeout event occurs or is resolved.
Definition: node.cpp:243
ev::Future< void, ::std::exception_ptr > AsyncSwitchBitrate(io::CanControllerBase &ctrl, int bitrate, ::std::chrono::milliseconds delay)
Stops the specified CAN controller and submits asynchronous operations to wait for the delay period,...
Definition: node.cpp:160
virtual void OnSyncError(uint16_t eec, uint8_t er) noexcept
The function invoked when the data length of a received SYNC message does not match.
Definition: node.hpp:705
virtual void OnSync(uint8_t cnt, const time_point &t) noexcept
The function invoked when a SYNC message is sent/received.
Definition: node.hpp:690
TpdoEventMutex tpdo_event_mutex
The mutex used to postpone the transmission of acyclic and event-driven PDOs.
Definition: node.hpp:552
ev::Executor GetExecutor() const noexcept
Returns the executor used to process I/O and CANopen events.
Definition: node.cpp:106
void on_can_error(io::CanError error) noexcept final
The function invoked when an error is detected on the CAN bus.
Definition: node.cpp:379
void OnTime(::std::function< void(const ::std::chrono::system_clock::time_point &)> on_time)
Registers the function to be invoked when a TIME message is received.
Definition: node.cpp:289
void OnRpdo(::std::function< void(int, ::std::error_code, const void *, ::std::size_t)> on_rpdo)
Registers the function to be invoked when a Receive-PDO is processed.
Definition: node.cpp:255
void SubmitWait(const duration &d, ev_exec_t *exec, F &&f)
Submits a wait operation.
Definition: node.hpp:203
virtual void OnEmcy(uint8_t id, uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept
The function invoked when an EMCY message is received.
Definition: node.hpp:728
void OnRpdoError(::std::function< void(int, uint16_t, uint8_t)> on_rpdo_error)
Registers the function to be invoked when a Receive-PDO length mismatch or timeout error occurs.
Definition: node.cpp:263
void OnTpdo(::std::function< void(int, ::std::error_code, const void *, ::std::size_t)> on_tpdo)
Registers the function to be invoked after a Transmit-PDO is sent or an error occurs.
Definition: node.cpp:269
io::Clock GetClock() const noexcept
Returns the clock used by the timer.
Definition: node.cpp:116
bool AbortWait(io_tqueue_wait &wait) noexcept
Aborts the specified wait operation if it is pending.
Definition: node.cpp:155
virtual void OnHeartbeat(uint8_t id, bool occurred) noexcept
The function invoked when a heartbeat timeout event occurs or is resolved.
Definition: node.hpp:585
ev::Future< void, ::std::exception_ptr > AsyncWait(const time_point &t, io_tqueue_wait **pwait=nullptr)
Equivalent to AsyncWait(nullptr, t, pwait).
Definition: node.hpp:256
typename ::std::enable_if<!::std::is_base_of< io_tqueue_wait, typename ::std::decay< F >::type >::value >::type SubmitWait(const time_point &t, F &&f)
Equivalent to SubmitWait(t, nullptr, f).
Definition: node.hpp:212
Node(io::TimerBase &timer, io::CanChannelBase &chan, const ::std::string &dcf_txt, const ::std::string &dcf_bin="", uint8_t id=0xff)
Creates a new CANopen node.
Definition: node.hpp:147
void OnEmcy(::std::function< void(uint8_t, uint16_t, uint8_t, uint8_t[5])> on_emcy)
Registers the function to be invoked when an EMCY message is received.
Definition: node.cpp:297
void OnCanState(::std::function< void(io::CanState, io::CanState)> on_can_state)
Registers the function to be invoked when a CAN bus state change is detected.
Definition: node.cpp:193
void SubmitWait(const time_point &t, io_tqueue_wait &wait)
Submits a wait operation.
Definition: node.cpp:121
virtual void OnState(uint8_t id, NmtState st) noexcept
The function invoked when an NMT state change or boot-up event is detected for a remote node by the h...
Definition: node.hpp:600
void RpdoRtr(int num=0) noexcept
Requests the transmission of a PDO by sending a CAN frame with the RTR (Remote Transmission Request) ...
Definition: node.cpp:355
virtual void OnStore(uint8_t id, int bitrate)
The function invoked then a request is received from the LSS master to store the pending node-ID and ...
Definition: node.cpp:389
bool CancelWait(io_tqueue_wait &wait) noexcept
Cancels the specified wait operation if it is pending.
Definition: node.cpp:150
The type of objects thrown as exceptions to report a system error with an associated error code.
Definition: exception.hpp:54
An abstract task executor. This class is a wrapper around #ev_exec_t*.
Definition: exec.hpp:38
A future.
Definition: future.hpp:384
A reference to an abstract CAN channel.
Definition: can.hpp:429
A reference to an abstract CAN controller.
Definition: can.hpp:285
A CAN network interface. This class is a wrapper around io_can_net_t*.
Definition: can_net.hpp:38
A reference to an abstract timer.
Definition: timer.hpp:130
An abstract interface conforming to the BasicLockable concept.
Definition: mutex.hpp:34
This header file is part of the C++ CANopen application library; it contains the CANopen device descr...
CanError
The error flags of a CAN bus, which are not mutually exclusive.
Definition: err.hpp:47
CanState
The states of a CAN node, depending on the TX/RX error count.
Definition: err.hpp:33
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
NmtState
The NMT states.
Definition: node.hpp:56
@ TOGGLE
The mask to get/set the toggle bit from an NMT state.
@ PREOP
Pre-operational.
@ RESET_COMM
Reset communication (a local NMT sub-state).
@ RESET_NODE
Reset application (a local NMT sub-state).
NmtCommand
The NMT command specifiers.
Definition: node.hpp:42
@ ENTER_PREOP
Enter pre-operational.
@ RESET_COMM
Reset communication.
A wait operation suitable for use with a timer queue.
Definition: tqueue.h:36
This header file is part of the I/O library; it contains the C++ interface for the timer queue.