Lely core libraries  2.3.4
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 // The CANopen NMT master/slave service from <lely/co/nmt.h>.
35 struct __co_nmt;
36 
37 namespace lely {
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
74 operator&(NmtState lhs, NmtState rhs) {
75  return static_cast<NmtState>(static_cast<int>(lhs) & static_cast<int>(rhs));
76 }
77 
78 constexpr NmtState
79 operator|(NmtState lhs, NmtState rhs) {
80  return static_cast<NmtState>(static_cast<int>(lhs) | static_cast<int>(rhs));
81 }
82 
83 constexpr NmtState
84 operator^(NmtState lhs, NmtState rhs) {
85  return static_cast<NmtState>(static_cast<int>(lhs) ^ static_cast<int>(rhs));
86 }
87 
88 constexpr NmtState
89 operator~(NmtState lhs) {
90  return static_cast<NmtState>(~static_cast<int>(lhs));
91 }
92 
93 inline NmtState&
94 operator&=(NmtState& lhs, NmtState rhs) noexcept {
95  return lhs = lhs & rhs;
96 }
97 
98 inline NmtState&
99 operator|=(NmtState& lhs, NmtState rhs) noexcept {
100  return lhs = lhs | rhs;
101 }
102 
103 inline NmtState&
104 operator^=(NmtState& lhs, NmtState rhs) noexcept {
105  return lhs = lhs ^ rhs;
106 }
107 
116 class Node : public io::CanNet, public Device {
117  friend class LssMaster;
118 
119  public:
120  using duration = io::TimerBase::duration;
121  using time_point = io::TimerBase::time_point;
122 
143  explicit Node(ev_exec_t* exec, io::TimerBase& timer, io::CanChannelBase& chan,
144  const ::std::string& dcf_txt, const ::std::string& dcf_bin = "",
145  uint8_t id = 0xff);
146 
148  explicit Node(io::TimerBase& timer, io::CanChannelBase& chan,
149  const ::std::string& dcf_txt, const ::std::string& dcf_bin = "",
150  uint8_t id = 0xff)
151  : Node(nullptr, timer, chan, dcf_txt, dcf_bin, id) {}
152 
153  Node(const Node&) = delete;
154  Node& operator=(const Node&) = delete;
155 
156  virtual ~Node();
157 
159  ev::Executor GetExecutor() const noexcept;
160 
162  io::ContextBase GetContext() const noexcept;
163 
165  io::Clock GetClock() const noexcept;
166 
171  void SubmitWait(const time_point& t, io_tqueue_wait& wait);
172 
177  void SubmitWait(const duration& d, io_tqueue_wait& wait);
178 
187  template <class F>
188  void
189  SubmitWait(const time_point& t, ev_exec_t* exec, F&& f) {
190  SubmitWait(t,
191  *io::make_timer_queue_wait_wrapper(exec, ::std::forward<F>(f)));
192  }
193 
202  template <class F>
203  void
204  SubmitWait(const duration& d, ev_exec_t* exec, F&& f) {
205  SubmitWait(d,
206  *io::make_timer_queue_wait_wrapper(exec, ::std::forward<F>(f)));
207  }
208 
210  template <class F>
211  typename ::std::enable_if<!::std::is_base_of<
212  io_tqueue_wait, typename ::std::decay<F>::type>::value>::type
213  SubmitWait(const time_point& t, F&& f) {
214  SubmitWait(t, nullptr, ::std::forward<F>(f));
215  }
216 
218  template <class F>
219  typename ::std::enable_if<!::std::is_base_of<
220  io_tqueue_wait, typename ::std::decay<F>::type>::value>::type
221  SubmitWait(const duration& d, F&& f) {
222  SubmitWait(d, nullptr, ::std::forward<F>(f));
223  }
224 
238  ev_exec_t* exec, const time_point& t, io_tqueue_wait** pwait = nullptr);
239 
253  ev_exec_t* exec, const duration& d, io_tqueue_wait** pwait = nullptr);
254 
257  AsyncWait(const time_point& t, io_tqueue_wait** pwait = nullptr) {
258  return AsyncWait(nullptr, t, pwait);
259  }
260 
263  AsyncWait(const duration& d, io_tqueue_wait** pwait = nullptr) {
264  return AsyncWait(nullptr, d, pwait);
265  }
266 
275  bool CancelWait(io_tqueue_wait& wait) noexcept;
276 
284  bool AbortWait(io_tqueue_wait& wait) noexcept;
285 
304  io::CanControllerBase& ctrl, int bitrate,
305  ::std::chrono::milliseconds delay);
306 
313  void OnCanState(
314  ::std::function<void(io::CanState, io::CanState)> on_can_state);
315 
322  void OnCanError(::std::function<void(io::CanError)> on_can_error);
323 
330  void Reset();
331 
341  void ConfigHeartbeat(uint8_t id, const ::std::chrono::milliseconds& ms,
342  ::std::error_code& ec);
343 
354  void ConfigHeartbeat(uint8_t id, const ::std::chrono::milliseconds& ms);
355 
362  void OnCommand(::std::function<void(NmtCommand)> on_command);
363 
370  void OnHeartbeat(::std::function<void(uint8_t, bool)> on_heartbeat);
371 
379  void OnState(::std::function<void(uint8_t, NmtState)> on_state);
380 
388  void OnRpdo(
389  ::std::function<void(int, ::std::error_code, const void*, ::std::size_t)>
390  on_rpdo);
391 
399  void OnRpdoError(::std::function<void(int, uint16_t, uint8_t)> on_rpdo_error);
400 
408  void OnTpdo(
409  ::std::function<void(int, ::std::error_code, const void*, ::std::size_t)>
410  on_tpdo);
411 
418  void OnSync(::std::function<void(uint8_t, const time_point&)> on_sync);
419 
427  void OnSyncError(::std::function<void(uint16_t, uint8_t)> on_sync_error);
428 
435  void OnTime(
436  ::std::function<void(const ::std::chrono::system_clock::time_point&)>
437  on_time);
438 
445  void OnEmcy(
446  ::std::function<void(uint8_t, uint16_t, uint8_t, uint8_t[5])> on_emcy);
447 
455  void OnSwitchBitrate(::std::function<void(int, ::std::chrono::milliseconds)>
456  on_switch_bitrate);
457 
458  protected:
464  friend class Node;
465 
466  public:
467  void lock() override;
468  void unlock() override;
469 
470  protected:
471  TpdoEventMutex(Node& node_) noexcept : node(&node_) {}
472 
473  Node* node;
474  };
475 
480  __can_net* net() const noexcept;
481 
483  void SetTime();
484 
497  virtual void OnCanState(io::CanState new_state,
498  io::CanState old_state) noexcept;
499 
507  virtual void
508  OnCanError(io::CanError error) noexcept {
509  (void)error;
510  }
511 
516  __co_nmt* nmt() const noexcept;
517 
518  /*
519  * Generates an EMCY error and triggers the error handling behavior according
520  * to object 1029:01 (Error behavior object) in case of a communication error
521  * (emergency error code 0x81xx).
522  *
523  * @param eec the emergency error code.
524  * @param er the error register.
525  * @param msef the manufacturer-specific error code.
526  */
527  void Error(uint16_t eec, uint8_t er,
528  const uint8_t msef[5] = nullptr) noexcept;
529 
537  void RpdoRtr(int num = 0) noexcept;
538 
547  void TpdoEvent(int num = 0) noexcept;
548 
559  template <class T>
560  typename ::std::enable_if<is_canopen_basic<T>::value && sizeof(T) <= 4,
561  void>::type
562  DamMpdoEvent(int num, uint8_t id, uint16_t idx, uint8_t subidx, T value);
563 
568  TpdoEventMutex tpdo_event_mutex;
569 
570  private:
571  void on_can_state(io::CanState new_state,
572  io::CanState old_state) noexcept final;
573  void on_can_error(io::CanError error) noexcept final;
574 
582  virtual void
583  OnCommand(NmtCommand cs) noexcept {
584  (void)cs;
585  }
586 
598  virtual void
599  OnHeartbeat(uint8_t id, bool occurred) noexcept {
600  (void)id;
601  (void)occurred;
602  }
603 
613  virtual void
614  OnState(uint8_t id, NmtState st) noexcept {
615  (void)id;
616  (void)st;
617  }
618 
639  virtual void
640  OnRpdo(int num, ::std::error_code ec, const void* p,
641  ::std::size_t n) noexcept {
642  (void)num;
643  (void)ec;
644  (void)p;
645  (void)n;
646  }
647 
661  virtual void
662  OnRpdoError(int num, uint16_t eec, uint8_t er) noexcept {
663  (void)num;
664  Error(eec, er);
665  }
666 
686  virtual void
687  OnTpdo(int num, ::std::error_code ec, const void* p,
688  ::std::size_t n) noexcept {
689  (void)num;
690  (void)ec;
691  (void)p;
692  (void)n;
693  }
694 
703  virtual void
704  OnSync(uint8_t cnt, const time_point& t) noexcept {
705  (void)cnt;
706  (void)t;
707  }
708 
718  virtual void
719  OnSyncError(uint16_t eec, uint8_t er) noexcept {
720  Error(eec, er);
721  }
722 
728  virtual void
729  OnTime(const ::std::chrono::system_clock::time_point& abs_time) noexcept {
730  (void)abs_time;
731  }
732 
741  virtual void
742  OnEmcy(uint8_t id, uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept {
743  (void)id;
744  (void)eec;
745  (void)er;
746  (void)msef;
747  }
748 
757  virtual void
758  OnSwitchBitrate(int bitrate, ::std::chrono::milliseconds delay) noexcept {
759  (void)bitrate;
760  (void)delay;
761  }
762 
774  virtual void OnStore(uint8_t id, int bitrate);
775 
776  struct Impl_;
777  ::std::unique_ptr<Impl_> impl_;
778 };
779 
780 } // namespace canopen
781 
782 } // namespace lely
783 
784 #endif // LELY_COAPP_NODE_HPP_
This header file is part of the I/O library; it contains the C++ interface for the timer queue.
The CANopen device description.
Definition: device.hpp:45
uint8_t id() const noexcept
Returns the node-ID.
Definition: device.cpp:193
The base class for CANopen LSS masters.
A recursive mutex-like object that can be used to postpone the transmission of acyclic and event-driv...
Definition: node.hpp:463
void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process,...
Definition: node.cpp:396
void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
Definition: node.cpp:403
The base class for CANopen nodes.
Definition: node.hpp:116
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:185
ev::Future< void, ::std::exception_ptr > AsyncWait(const duration &d, io_tqueue_wait **pwait=nullptr)
Equivalent to AsyncWait(nullptr, d, pwait).
Definition: node.hpp:263
void Reset()
(Re)starts the node.
Definition: node.cpp:258
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:352
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:221
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:342
void OnState(::std::function< void(uint8_t, NmtState)> on_state)
Registers the function to be invoked when an NMT state change or boot-up event is detected for a remo...
Definition: node.cpp:302
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:270
void SetTime()
Updates the CAN network time.
Definition: node.cpp:415
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:252
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:290
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:385
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:145
__co_nmt * nmt() const noexcept
Returns a pointer to the internal CANopen NMT master/slave service from <lely/co/nmt....
Definition: node.cpp:434
io::ContextBase GetContext() const noexcept
Returns the underlying I/O context with which this context is registered.
Definition: node.cpp:164
void TpdoEvent(int num=0) noexcept
Triggers the transmission of an acyclic or event-driven PDO.
Definition: node.cpp:457
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:296
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:213
__can_net * net() const noexcept
Returns a pointer to the internal CAN network interface from <lely/can/net.h>.
Definition: node.cpp:410
ev::Executor GetExecutor() const noexcept
Returns the executor used to process I/O and CANopen events.
Definition: node.cpp:159
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:362
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:308
void SubmitWait(const duration &d, ev_exec_t *exec, F &&f)
Submits a wait operation.
Definition: node.hpp:204
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:320
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:330
io::Clock GetClock() const noexcept
Returns the clock used by the timer.
Definition: node.cpp:169
bool AbortWait(io_tqueue_wait &wait) noexcept
Aborts the specified wait operation if it is pending.
Definition: node.cpp:208
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:257
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:213
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:148
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:374
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:245
void SubmitWait(const time_point &t, io_tqueue_wait &wait)
Submits a wait operation.
Definition: node.cpp:174
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:444
bool CancelWait(io_tqueue_wait &wait) noexcept
Cancels the specified wait operation if it is pending.
Definition: node.cpp:203
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:430
A reference to an abstract CAN controller.
Definition: can.hpp:286
A CAN network interface. This class is a wrapper around io_can_net_t*.
Definition: can_net.hpp:38
virtual void on_can_error(CanError error) noexcept
The function invoked when an error is detected on the CAN bus.
Definition: can_net.hpp:208
virtual void on_can_state(CanState new_state, CanState old_state) noexcept
The function invoked when a CAN bus state change is detected.
Definition: can_net.hpp:191
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 CAN network interface.
Definition: net.c:37
A CANopen NMT master/slave service.
Definition: nmt.c:148
A wait operation suitable for use with a timer queue.
Definition: tqueue.h:36
If T is one of the CANopen basic types, provides the member constant value equal to true.
This header file is part of the I/O library; it contains the C++ interface for the timer queue.