Lely core libraries  1.9.2
driver.hpp
Go to the documentation of this file.
1 
22 #ifndef LELY_COCPP_DRIVER_HPP_
23 #define LELY_COCPP_DRIVER_HPP_
24 
25 #include <lely/aio/loop.hpp>
26 #include <lely/coapp/master.hpp>
27 
28 namespace lely {
29 
30 namespace canopen {
31 
33 class DriverBase {
34  public:
35  using CanState = BasicMaster::CanState;
36  using CanError = BasicMaster::CanError;
37 
38  using time_point = BasicMaster::time_point;
39 
40  DriverBase() = default;
41 
42  DriverBase(const DriverBase&) = delete;
43 
44  DriverBase& operator=(const DriverBase&) = delete;
45 
46  virtual ~DriverBase() = default;
47 
52  virtual aio::ExecutorBase GetExecutor() const noexcept = 0;
53 
55  virtual uint8_t netid() const noexcept = 0;
56 
58  virtual uint8_t id() const noexcept = 0;
59 
65  virtual void OnCanState(CanState new_state, CanState old_state) noexcept = 0;
66 
72  virtual void OnCanError(CanError error) noexcept = 0;
73 
81  virtual void OnCommand(NmtCommand cs) noexcept = 0;
82 
96  virtual void OnNodeGuarding(bool occurred) noexcept = 0;
97 
111  virtual void OnHeartbeat(bool occurred) noexcept = 0;
112 
123  virtual void OnState(NmtState st) noexcept = 0;
124 
165  virtual void OnBoot(NmtState st, char es,
166  const ::std::string& what) noexcept = 0;
167 
183  virtual void OnConfig(
184  ::std::function<void(::std::error_code ec)> res) noexcept = 0;
185 
209  virtual void OnRpdo(int num, ::std::error_code ec, const void* p,
210  ::std::size_t n) noexcept = 0;
211 
225  virtual void OnRpdoError(int num, uint16_t eec, uint8_t er) noexcept = 0;
226 
249  virtual void OnTpdo(int num, ::std::error_code ec, const void* p,
250  ::std::size_t n) noexcept = 0;
251 
262  virtual void OnSync(uint8_t cnt, const Node::time_point& t) noexcept = 0;
263 
273  virtual void OnSyncError(uint16_t eec, uint8_t er) noexcept = 0;
274 
282  virtual void OnTime(
283  const ::std::chrono::system_clock::time_point& abs_time) noexcept = 0;
284 
294  virtual void OnEmcy(uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept = 0;
295 };
296 
298 class BasicDriver : private DriverBase {
299  friend class BasicMaster;
300 
301  public:
302  using DriverBase::time_point;
303 
317  BasicDriver(aio::LoopBase& loop, aio::ExecutorBase& exec, BasicMaster& master,
318  uint8_t id);
319 
320  virtual ~BasicDriver();
321 
323  aio::LoopBase
324  GetLoop() const noexcept {
325  return loop_;
326  }
327 
328  aio::ExecutorBase
329  GetExecutor() const noexcept final override {
330  return exec_;
331  }
332 
333  uint8_t netid() const noexcept final override;
334 
335  uint8_t
336  id() const noexcept final override {
337  return id_;
338  }
339 
346  void
347  Error() {
348  master.Error(id());
349  }
350 
356  template <class T, class F>
357  void
358  SubmitRead(uint16_t idx, uint8_t subidx, F&& con) {
359  auto exec = GetExecutor();
360  master.SubmitRead<T>(id(), idx, subidx, exec, ::std::forward<F>(con));
361  }
362 
369  template <class T, class F>
370  void
371  SubmitRead(uint16_t idx, uint8_t subidx, F&& con, ::std::error_code& ec) {
372  auto exec = GetExecutor();
373  master.SubmitRead<T>(id(), idx, subidx, exec, ::std::forward<F>(con), ec);
374  }
375 
382  template <class T, class F>
383  void
384  SubmitRead(uint16_t idx, uint8_t subidx, F&& con,
385  const Sdo::duration& timeout) {
386  auto exec = GetExecutor();
387  master.SubmitRead<T>(id(), idx, subidx, exec, ::std::forward<F>(con),
388  timeout);
389  }
390 
406  template <class T, class F>
407  void
408  SubmitRead(uint16_t idx, uint8_t subidx, F&& con,
409  const Sdo::duration& timeout, ::std::error_code& ec) {
410  auto exec = GetExecutor();
411  master.SubmitRead<T>(id(), idx, subidx, exec, ::std::forward<F>(con),
412  timeout, ec);
413  }
414 
421  template <class T, class F>
422  void
423  SubmitWrite(uint16_t idx, uint8_t subidx, T&& value, F&& con) {
424  auto exec = GetExecutor();
425  master.SubmitWrite<T>(id(), idx, subidx, ::std::forward<T>(value), exec,
426  ::std::forward<F>(con));
427  }
428 
435  template <class T, class F>
436  void
437  SubmitWrite(uint16_t idx, uint8_t subidx, T&& value, F&& con,
438  ::std::error_code& ec) {
439  auto exec = GetExecutor();
440  master.SubmitWrite<T>(id(), idx, subidx, ::std::forward<T>(value), exec,
441  ::std::forward<F>(con), ec);
442  }
443 
450  template <class T, class F>
451  void
452  SubmitWrite(uint16_t idx, uint8_t subidx, T&& value, F&& con,
453  const Sdo::duration& timeout) {
454  auto exec = GetExecutor();
455  master.SubmitWrite<T>(id(), idx, subidx, ::std::forward<T>(value), exec,
456  ::std::forward<F>(con), timeout);
457  }
458 
475  template <class T, class F>
476  void
477  SubmitWrite(uint16_t idx, uint8_t subidx, T&& value, F&& con,
478  const Sdo::duration& timeout, ::std::error_code& ec) {
479  auto exec = GetExecutor();
480  master.SubmitWrite<T>(id(), idx, subidx, ::std::forward<T>(value), exec,
481  ::std::forward<F>(con), timeout, ec);
482  }
483 
490  template <class T>
491  aio::Future<::std::tuple<::std::error_code, T>>
492  AsyncRead(uint16_t idx, uint8_t subidx) {
493  auto loop = GetLoop();
494  auto exec = GetExecutor();
495  return master.AsyncRead<T>(loop, exec, id(), idx, subidx);
496  }
497 
512  template <class T>
513  aio::Future<::std::tuple<::std::error_code, T>>
514  AsyncRead(uint16_t idx, uint8_t subidx, const Sdo::duration& timeout) {
515  auto loop = GetLoop();
516  auto exec = GetExecutor();
517  return master.AsyncRead<T>(loop, exec, id(), idx, subidx, timeout);
518  }
519 
526  template <class T>
527  aio::Future<::std::error_code>
528  AsyncWrite(uint16_t idx, uint8_t subidx, T&& value) {
529  auto loop = GetLoop();
530  auto exec = GetExecutor();
531  return master.AsyncWrite(loop, exec, id(), idx, subidx,
532  ::std::forward<T>(value));
533  }
534 
549  template <class T>
550  aio::Future<::std::error_code>
551  AsyncWrite(uint16_t idx, uint8_t subidx, T&& value,
552  const Sdo::duration& timeout) {
553  auto loop = GetLoop();
554  auto exec = GetExecutor();
555  return master.AsyncWrite(loop, exec, id(), idx, subidx,
556  ::std::forward<T>(value), timeout);
557  }
558 
564  template <class T>
565  T
566  RunRead(uint16_t idx, uint8_t subidx) {
567  ::std::error_code ec;
568  auto r = RunRead<T>(idx, subidx, ec);
569  if (ec) throw SdoError(netid(), id(), idx, subidx, ec, "RunRead");
570  return r;
571  }
572 
579  template <class T>
580  T
581  RunRead(uint16_t idx, uint8_t subidx, ::std::error_code& ec) {
582  T value{};
583  auto future = AsyncRead<T>(idx, subidx);
584  if (future) {
585  auto t = future.Get();
586  ec = ::std::get<0>(t);
587  value = ::std::move(::std::get<1>(t));
588  } else {
589  ec = SdoErrc::NO_SDO;
590  }
591  return value;
592  }
593 
600  template <class T>
601  T
602  RunRead(uint16_t idx, uint8_t subidx, const Sdo::duration& timeout) {
603  ::std::error_code ec;
604  auto r = RunRead<T>(idx, subidx, timeout, ec);
605  if (ec) throw SdoError(netid(), id(), idx, subidx, ec, "RunRead");
606  return r;
607  }
608 
624  template <class T>
625  T
626  RunRead(uint16_t idx, uint8_t subidx, const Sdo::duration& timeout,
627  ::std::error_code& ec) {
628  T value{};
629  auto future = AsyncRead<T>(idx, subidx, timeout);
630  if (future) {
631  auto t = future.Get();
632  ec = ::std::get<0>(t);
633  value = ::std::move(::std::get<1>(t));
634  } else {
635  ec = SdoErrc::NO_SDO;
636  }
637  return value;
638  }
639 
645  template <class T>
646  void
647  RunWrite(uint16_t idx, uint8_t subidx, T&& value) {
648  ::std::error_code ec;
649  RunWrite(idx, subidx, ::std::forward<T>(value), ec);
650  if (ec) throw SdoError(netid(), id(), idx, subidx, ec, "RunWrite");
651  }
652 
659  template <class T>
660  void
661  RunWrite(uint16_t idx, uint8_t subidx, T&& value, ::std::error_code& ec) {
662  auto future = AsyncWrite(idx, subidx, ::std::forward<T>(value));
663  ec = future ? future.Get() : SdoErrc::NO_SDO;
664  }
665 
672  template <class T>
673  void
674  RunWrite(uint16_t idx, uint8_t subidx, T&& value,
675  const Sdo::duration& timeout) {
676  ::std::error_code ec;
677  RunWrite(idx, subidx, ::std::forward<T>(value), timeout, ec);
678  if (ec) throw SdoError(netid(), id(), idx, subidx, ec, "RunWrite");
679  }
680 
695  template <class T>
696  void
697  RunWrite(uint16_t idx, uint8_t subidx, T&& value,
698  const Sdo::duration& timeout, ::std::error_code& ec) {
699  auto future = AsyncWrite(idx, subidx, ::std::forward<T>(value), timeout);
700  ec = future ? future.Get() : SdoErrc::NO_SDO;
701  }
702 
705 
712  template <class F>
713  void
714  Post(F&& f) {
715  auto* op = new aio::TaskWrapper([=](::std::error_code ec) {
716  if (!ec) f();
717  });
718  GetExecutor().Post(*op);
719  }
720 
721  private:
722  void
723  OnCanState(CanState /*new_state*/, CanState /*old_state*/) noexcept override {
724  }
725 
726  void
727  OnCanError(CanError /*error*/) noexcept override {}
728 
729  void
730  OnCommand(NmtCommand /*cs*/) noexcept override {}
731 
732  void
733  OnNodeGuarding(bool /*occurred*/) noexcept override {}
734 
735  void
736  OnHeartbeat(bool /*occurred*/) noexcept override {}
737 
738  void
739  OnState(NmtState /*st*/) noexcept override {}
740 
741  void
742  OnBoot(NmtState /*st*/, char /*es*/,
743  const ::std::string& /*what*/) noexcept override {}
744 
745  void
746  OnConfig(::std::function<void(::std::error_code ec)> res) noexcept override {
747  res(::std::error_code());
748  }
749 
750  void
751  OnRpdo(int /*num*/, ::std::error_code /*ec*/, const void* /*p*/,
752  ::std::size_t /*n*/) noexcept override {}
753 
754  void
755  OnRpdoError(int /*num*/, uint16_t /*eec*/, uint8_t /*er*/) noexcept override {
756  }
757 
758  void
759  OnTpdo(int /*num*/, ::std::error_code /*ec*/, const void* /*p*/,
760  ::std::size_t /*n*/) noexcept override {}
761 
762  void
763  OnSync(uint8_t /*cnt*/, const time_point& /*t*/) noexcept override {}
764 
765  void
766  OnSyncError(uint16_t /*eec*/, uint8_t /*er*/) noexcept override {}
767 
768  void
769  OnTime(const ::std::chrono::system_clock::
770  time_point& /*abs_time*/) noexcept override {}
771 
772  void
773  OnEmcy(uint16_t /*eec*/, uint8_t /*er*/,
774  uint8_t /*msef*/[5]) noexcept override {}
775 
776  aio_loop_t* loop_{nullptr};
777  aio_exec_t* exec_{nullptr};
778  uint8_t id_{0xff};
779 };
780 
781 namespace detail {
782 
788  protected:
789  aio::Loop loop{};
790  aio::Executor exec{loop};
791 };
792 
793 } // namespace detail
794 
797  public:
798  LoopDriver(BasicMaster& master, uint8_t id);
799  ~LoopDriver();
800 
801  private:
802  struct Impl_;
803  ::std::unique_ptr<Impl_> impl_;
804 };
805 
806 } // namespace canopen
807 
808 } // namespace lely
809 
810 #endif // LELY_COCPP_DRIVER_HPP_
virtual void OnTime(const ::std::chrono::system_clock::time_point &abs_time) noexcept=0
The function invoked when a TIME message is received by the master.
void RunWrite(uint16_t idx, uint8_t subidx, T &&value, ::std::error_code &ec)
Equivalent to RunWrite(uint16_t idx, uint8_t subidx, T&& value, const Sdo::duration& timeout...
Definition: driver.hpp:661
void SubmitRead(uint8_t id, Sdo::UploadRequest< T > &req)
Equivalent to SubmitRead(uint8_t id, Sdo::UploadRequest<T>& req, ::std::error_code& ec)...
Definition: master.hpp:481
The CANopen master.
Definition: master.hpp:46
void RunWrite(uint16_t idx, uint8_t subidx, T &&value)
Equivalent to RunWrite(uint16_t idx, uint8_t subidx, T&& value, ::std::error_code& ec)...
Definition: driver.hpp:647
virtual void OnEmcy(uint16_t eec, uint8_t er, uint8_t msef[5]) noexcept=0
The function invoked when an EMCY message is received from the remote node.
The base class for drivers for remote CANopen nodes.
Definition: driver.hpp:298
T RunRead(uint16_t idx, uint8_t subidx, const Sdo::duration &timeout, ::std::error_code &ec)
Queues an asynchronous read (SDO upload) operation and runs the event loop until the operation is com...
Definition: driver.hpp:626
aio::Future<::std::tuple<::std::error_code, T > > AsyncRead(uint16_t idx, uint8_t subidx)
Equivalent to AsyncRead(uint16_t idx, uint8_t subidx, const Sdo::duration& timeout), except that it uses the SDO timeout given by lely::canopen::BasicMaster::GetTimeout().
Definition: driver.hpp:492
NmtCommand
The NMT command specifiers.
Definition: node.hpp:36
T RunRead(uint16_t idx, uint8_t subidx, const Sdo::duration &timeout)
Equivalent to RunRead(uint16_t idx, uint8_t subidx, const Sdo::duration& timeout, ::std::error_code& ...
Definition: driver.hpp:602
virtual void OnNodeGuarding(bool occurred) noexcept=0
The function invoked when a node guarding timeout event occurs or is resolved for the remote node...
virtual uint8_t netid() const noexcept=0
Returns the network-ID.
void RunWrite(uint16_t idx, uint8_t subidx, T &&value, const Sdo::duration &timeout)
Equivalent to RunWrite(uint16_t idx, uint8_t subidx, T&& value, const Sdo::duration& timeout...
Definition: driver.hpp:674
void Post(F &&f)
Schedules the specified Callable object for execution by the executor for this driver.
Definition: driver.hpp:714
aio::Future<::std::tuple<::std::error_code, T > > AsyncRead(aio::LoopBase &loop, aio::ExecutorBase &exec, uint8_t id, uint16_t idx, uint8_t subidx)
Equivalent to AsyncRead(aio::LoopBase& loop, aio::ExecutorBase& exec, uint8_t id, uint16_t idx...
Definition: master.hpp:729
virtual uint8_t id() const noexcept=0
Returns the node-ID.
The abstract driver interface for a remote CANopen node.
Definition: driver.hpp:33
This header file is part of the C++ CANopen application library; it contains the CANopen master decla...
T RunRead(uint16_t idx, uint8_t subidx, ::std::error_code &ec)
Equivalent to RunRead(uint16_t idx, uint8_t subidx, const Sdo::duration& timeout, ::std::error_code& ...
Definition: driver.hpp:581
virtual void OnConfig(::std::function< void(::std::error_code ec)> res) noexcept=0
The function invoked when the &#39;update configuration&#39; step is reached during the NMT &#39;boot slave&#39; proc...
Resource not available: SDO connection.
aio::Future<::std::error_code > AsyncWrite(uint16_t idx, uint8_t subidx, T &&value)
Equivalent to AsyncWrite(uint16_t idx, uint8_t subidx, T&& value, const Sdo::duration& timeout)...
Definition: driver.hpp:528
virtual void OnSyncError(uint16_t eec, uint8_t er) noexcept=0
The function invoked when the data length of a received SYNC message does not match.
void Error(uint8_t id)
Indicates the occurrence of an error event on a remote node and triggers the error handling process (...
Definition: master.cpp:64
virtual void OnCommand(NmtCommand cs) noexcept=0
The function invoked when an NMT state change occurs on the master.
virtual void OnRpdo(int num, ::std::error_code ec, const void *p, ::std::size_t n) noexcept=0
The function invoked when a Receive-PDO is processed by the master.
virtual void OnCanState(CanState new_state, CanState old_state) noexcept=0
The function invoked when a CAN bus state change is detected.
virtual void OnTpdo(int num, ::std::error_code ec, const void *p, ::std::size_t n) noexcept=0
The function invoked after a Transmit-PDO is sent by the master or an error occurs.
void SubmitRead(uint16_t idx, uint8_t subidx, F &&con, ::std::error_code &ec)
Equivalent to SubmitRead(uint16_t idx, uint8_t subidx, F&& con, const Sdo::duration& timeout...
Definition: driver.hpp:371
The internal implementation of lely::canopen::LoopDriver.
Definition: driver.cpp:40
T RunRead(uint16_t idx, uint8_t subidx)
Equivalent to RunRead(uint16_t idx, uint8_t subidx, ::std::error_code& ec), except that it throws lel...
Definition: driver.hpp:566
void SubmitRead(uint16_t idx, uint8_t subidx, F &&con)
Equivalent to SubmitRead(uint16_t idx, uint8_t subidx, F&& con, ::std::error_code& ec)...
Definition: driver.hpp:358
A CANopen driver running its own dedicated event loop in a separate thread.
Definition: driver.hpp:796
::std::chrono::milliseconds duration
The type used to represent an SDO timeout duration.
Definition: sdo.hpp:51
aio::Future<::std::tuple<::std::error_code, T > > AsyncRead(uint16_t idx, uint8_t subidx, const Sdo::duration &timeout)
Queues an asynchronous read (SDO upload) operation and returns a future.
Definition: driver.hpp:514
A base class for lely::canopen::LoopDriver, containing an event loop and the associated executor...
Definition: driver.hpp:787
aio::ExecutorBase GetExecutor() const noexcept final override
Returns the executor used to execute event handlers for this driver, including SDO confirmation funct...
Definition: driver.hpp:329
virtual void OnState(NmtState st) noexcept=0
The function invoked when an NMT state change or boot-up event is detected for the remote node by the...
The type of objects thrown as exceptions to report a system error with an associated error code...
Definition: exception.hpp:54
virtual void OnBoot(NmtState st, char es, const ::std::string &what) noexcept=0
The function invoked when the NMT &#39;boot slave&#39; process completes for the remote node.
virtual void OnRpdoError(int num, uint16_t eec, uint8_t er) noexcept=0
The function invoked when a Receive-PDO length mismatch or timeout error occurs on the master...
uint8_t netid() const noexcept final override
Returns the network-ID.
Definition: driver.cpp:60
void SubmitWrite(uint16_t idx, uint8_t subidx, T &&value, F &&con, const Sdo::duration &timeout, ::std::error_code &ec)
Queues an asynchronous write (SDO download) operation.
Definition: driver.hpp:477
virtual void OnCanError(CanError error) noexcept=0
The function invoked when an error is detected on the CAN bus.
virtual void OnHeartbeat(bool occurred) noexcept=0
The function invoked when a heartbeat timeout event occurs or is resolved for the remote node...
void RunWrite(uint16_t idx, uint8_t subidx, T &&value, const Sdo::duration &timeout, ::std::error_code &ec)
Queues an asynchronous write (SDO download) operation and runs the event loop until the operation is ...
Definition: driver.hpp:697
virtual aio::ExecutorBase GetExecutor() const noexcept=0
Returns the executor used to execute event handlers for this driver, including SDO confirmation funct...
BasicMaster & master
A reference to the master with which this driver is registered.
Definition: driver.hpp:704
virtual void OnSync(uint8_t cnt, const Node::time_point &t) noexcept=0
The function invoked when a SYNC message is sent/received by the master.
uint8_t id() const noexcept final override
Returns the node-ID.
Definition: driver.hpp:336
void Error()
Indicates the occurrence of an error event on the remote node and triggers the error handling process...
Definition: driver.hpp:347
NmtState
The NMT states.
Definition: node.hpp:50
void SubmitWrite(uint16_t idx, uint8_t subidx, T &&value, F &&con, ::std::error_code &ec)
Equivalent to SubmitWrite(uint16_t idx, uint8_t subidx, T&& value, F&& con, const Sdo::duration& time...
Definition: driver.hpp:437
void SubmitWrite(uint16_t idx, uint8_t subidx, T &&value, F &&con, const Sdo::duration &timeout)
Equivalent to SubmitWrite(uint16_t idx, uint8_t subidx, T&& value, F&& con, const Sdo::duration& time...
Definition: driver.hpp:452
Global namespace for the Lely Industries N.V. libraries.
Definition: buf.hpp:32
void SubmitWrite(uint8_t id, Sdo::DownloadRequest< T > &req)
Equivalent to SubmitWrite(uint8_t id, Sdo::DownloadRequest<T>& req, ::std::error_code& ec)...
Definition: master.hpp:601
BasicDriver(aio::LoopBase &loop, aio::ExecutorBase &exec, BasicMaster &master, uint8_t id)
Creates a new driver for a remote CANopen node and registers it with the master.
Definition: driver.cpp:51
aio::LoopBase GetLoop() const noexcept
Returns the event loop used to create promises and futures.
Definition: driver.hpp:324
aio::Future<::std::error_code > AsyncWrite(uint16_t idx, uint8_t subidx, T &&value, const Sdo::duration &timeout)
Queues an asynchronous write (SDO download) operation and returns a future.
Definition: driver.hpp:551
void SubmitRead(uint16_t idx, uint8_t subidx, F &&con, const Sdo::duration &timeout, ::std::error_code &ec)
Queues an asynchronous read (SDO upload) operation.
Definition: driver.hpp:408
aio::Future<::std::error_code > AsyncWrite(aio::LoopBase &loop, aio::ExecutorBase &exec, uint8_t id, uint16_t idx, uint8_t subidx, T &&value)
Equivalent to AsyncWrite(aio::LoopBase& loop, aio::ExecutorBase& exec, uint8_t id, uint16_t idx, uint8_t subidx, T&& value, const Sdo::duration& timeout), except that it uses the SDO timeout given by GetTimeout().
Definition: master.hpp:775
The type of exception thrown when an SDO abort code is received.
Definition: sdo_error.hpp:116
void SubmitRead(uint16_t idx, uint8_t subidx, F &&con, const Sdo::duration &timeout)
Equivalent to SubmitRead(uint16_t idx, uint8_t subidx, F&& con, const Sdo::duration& timeout...
Definition: driver.hpp:384
void SubmitWrite(uint16_t idx, uint8_t subidx, T &&value, F &&con)
Equivalent to SubmitWrite(uint16_t idx, uint8_t subidx, T&& value, F&& con, ::std::error_code& ec)...
Definition: driver.hpp:423