Lely core libraries  2.2.5
sdo.hpp
Go to the documentation of this file.
1 
22 #ifndef LELY_COAPP_SDO_HPP_
23 #define LELY_COAPP_SDO_HPP_
24 
26 #include <lely/coapp/sdo_error.hpp>
27 #include <lely/ev/future.hpp>
28 
29 #include <chrono>
30 #include <limits>
31 #include <memory>
32 #include <string>
33 #include <utility>
34 
35 namespace lely {
36 
37 // The CAN network interface from <lely/can/net.hpp>.
38 class CANNet;
39 
40 // The CANopen device from <lely/co/dev.hpp>.
41 class CODev;
42 
43 // The CANopen Client-SDO service from <lely/co/csdo.hpp>.
44 class COCSDO;
45 
46 namespace canopen {
47 
54 template <class T>
56 
63 template <class T>
65 
72 inline SdoFuture<void>
74  return ev::make_empty_future<::std::exception_ptr>();
75 }
76 
83 template <class T, class V = typename ::std::decay<T>::type>
84 inline SdoFuture<V>
86  return ev::make_ready_future<::std::exception_ptr, V>(
87  ::std::forward<T>(value));
88 }
89 
97 template <class T>
98 inline SdoFuture<T>
99 make_error_sdo_future(uint8_t id, uint16_t idx, uint8_t subidx,
100  ::std::error_code ec) {
101  return ev::make_error_future<T>(make_sdo_exception_ptr(id, idx, subidx, ec));
102 }
103 
111 template <class T>
112 inline SdoFuture<T>
113 make_error_sdo_future(uint8_t id, uint16_t idx, uint8_t subidx,
114  ::std::error_code ec, const ::std::string& what_arg) {
115  return ev::make_error_future<T>(
116  make_sdo_exception_ptr(id, idx, subidx, ec, what_arg));
117 }
118 
126 template <class T>
127 inline SdoFuture<T>
128 make_error_sdo_future(uint8_t id, uint16_t idx, uint8_t subidx,
129  ::std::error_code ec, const char* what_arg) {
130  return ev::make_error_future<T>(
131  make_sdo_exception_ptr(id, idx, subidx, ec, what_arg));
132 }
133 
134 class Sdo;
135 
136 namespace detail {
137 
139 inline ::std::chrono::milliseconds
140 from_sdo_timeout(int timeout) {
141  using ::std::chrono::milliseconds;
142  return timeout <= 0 ? milliseconds::max() : milliseconds(timeout);
143 }
144 
146 template <class Rep, class Period>
147 inline int
148 to_sdo_timeout(const ::std::chrono::duration<Rep, Period>& d) {
149  using ::std::chrono::duration;
150  using ::std::chrono::duration_cast;
151  using ::std::chrono::milliseconds;
152  // The maximum duration is interpreted as an infinite timeout.
153  if (d == duration<Rep, Period>::max()) return 0;
154  auto timeout = duration_cast<milliseconds>(d).count();
155  // A timeout less than 1 ms is rounded up to keep it finite.
156  if (timeout < 1) return 1;
157  if (timeout > ::std::numeric_limits<int>::max())
158  return ::std::numeric_limits<int>::max();
159  return timeout;
160 }
161 
162 class SdoRequestBase : public ev_task {
163  friend class canopen::Sdo;
164 
165  public:
166  SdoRequestBase(ev_exec_t* exec, uint16_t idx_ = 0, uint8_t subidx_ = 0,
167  const ::std::chrono::milliseconds& timeout_ = {})
168  : ev_task EV_TASK_INIT(exec,
169  [](ev_task* task) noexcept {
170  (*static_cast<SdoRequestBase*>(task))();
171  }),
172  idx(idx_),
173  subidx(subidx_),
174  timeout(timeout_) {}
175 
176  SdoRequestBase(const SdoRequestBase&) = delete;
177 
178  SdoRequestBase& operator=(const SdoRequestBase&) = delete;
179 
180  virtual ~SdoRequestBase() = default;
181 
184  GetExecutor() const noexcept {
185  return ev::Executor(ev_task::exec);
186  }
187 
189  uint8_t id{0};
191  uint16_t idx{0};
193  uint8_t subidx{0};
199  ::std::chrono::milliseconds timeout;
201  ::std::error_code ec;
202 
203  private:
204  virtual void operator()() noexcept = 0;
205 
206  virtual void OnRequest(void* data) noexcept = 0;
207 };
208 
209 template <class T>
211  public:
212  using SdoRequestBase::SdoRequestBase;
213 
214  template <class U>
215  SdoDownloadRequestBase(ev_exec_t* exec, uint16_t idx, uint8_t subidx,
216  U&& value_,
217  const ::std::chrono::milliseconds& timeout = {})
218  : SdoRequestBase(exec, idx, subidx, timeout),
219  value(::std::forward<U>(value_)) {}
220 
222  T value{};
223 };
224 
225 template <class T>
227  public:
228  using SdoRequestBase::SdoRequestBase;
229 
231  T value{};
232 };
233 
234 } // namespace detail
235 
237 template <class T>
239  public:
251  using Signature = void(uint8_t id, uint16_t idx, uint8_t subidx,
252  ::std::error_code ec);
253 
259  template <class F>
261  : detail::SdoDownloadRequestBase<T>(exec), con_(::std::forward<F>(con)) {}
262 
263  private:
264  void operator()() noexcept final;
265 
266  void OnRequest(void* data) noexcept final;
267 
268  ::std::function<Signature> con_;
269 };
270 
272 template <class T>
274  public:
287  using Signature = void(uint8_t id, uint16_t idx, uint8_t subidx,
288  ::std::error_code ec, T value);
289 
295  template <class F>
297  : detail::SdoUploadRequestBase<T>(exec), con_(::std::forward<F>(con)) {}
298 
299  private:
300  void operator()() noexcept final;
301 
302  void OnRequest(void* data) noexcept final;
303 
304  ::std::function<Signature> con_;
305 };
306 
307 namespace detail {
308 
309 template <class T>
311  public:
312  using Signature = void(uint8_t id, uint16_t idx, uint8_t subidx,
313  ::std::error_code ec);
314 
315  template <class U, class F>
316  SdoDownloadRequestWrapper(ev_exec_t* exec, uint16_t idx, uint8_t subidx,
317  U&& value, F&& con,
318  const ::std::chrono::milliseconds& timeout)
319  : SdoDownloadRequestBase<T>(exec, idx, subidx, ::std::forward<U>(value),
320  timeout),
321  con_(::std::forward<F>(con)) {}
322 
323  private:
324  void operator()() noexcept final;
325 
326  void OnRequest(void* data) noexcept final;
327 
328  ::std::function<Signature> con_;
329 };
330 
331 template <class T>
333  public:
334  using Signature = void(uint8_t id, uint16_t idx, uint8_t subidx,
335  ::std::error_code ec, T value);
336 
337  template <class F>
338  SdoUploadRequestWrapper(ev_exec_t* exec, uint16_t idx, uint8_t subidx,
339  F&& con, const ::std::chrono::milliseconds& timeout)
341  con_(::std::forward<F>(con)) {}
342 
343  private:
344  void operator()() noexcept final;
345 
346  void OnRequest(void* data) noexcept final;
347 
348  ::std::function<Signature> con_;
349 };
350 
351 } // namespace detail
352 
371 template <class T, class U, class F>
374  U&& value, F&& con,
375  const ::std::chrono::milliseconds& timeout = {}) {
377  exec, idx, subidx, ::std::forward<U>(value), ::std::forward<F>(con),
378  timeout);
379 }
380 
398 template <class T, class F>
400 make_sdo_upload_request(ev_exec_t* exec, uint16_t idx, uint8_t subidx, F&& con,
401  const ::std::chrono::milliseconds& timeout = {}) {
403  exec, idx, subidx, ::std::forward<F>(con), timeout);
404 }
405 
407 class Sdo {
408  template <class>
409  friend class SdoDownloadRequest;
410 
411  template <class>
412  friend class SdoUploadRequest;
413 
414  template <class>
416 
417  template <class>
418  friend class detail::SdoUploadRequestWrapper;
419 
420  public:
422  Sdo();
423 
432  Sdo(CANNet* net, uint8_t id);
433 
443  Sdo(CANNet* net, CODev* dev, uint8_t num);
444 
453  Sdo(COCSDO* sdo);
454 
455  Sdo(const Sdo&) = delete;
456  Sdo(Sdo&&) = default;
457 
458  Sdo& operator=(const Sdo&) = delete;
459  Sdo& operator=(Sdo&&);
460 
465  ~Sdo();
466 
468  explicit operator bool() const noexcept { return !!impl_; }
469 
471  template <class T>
472  typename ::std::enable_if<detail::is_canopen_type<T>::value>::type
474  Submit(req);
475  }
476 
492  template <class T, class F, class U = typename ::std::decay<T>::type>
493  typename ::std::enable_if<detail::is_canopen_type<U>::value>::type
494  SubmitDownload(ev_exec_t* exec, uint16_t idx, uint8_t subidx, T&& value,
495  F&& con, const ::std::chrono::milliseconds& timeout = {}) {
496  Submit(*make_sdo_download_request<U>(exec, idx, subidx,
497  ::std::forward<T>(value),
498  ::std::forward<F>(con), timeout));
499  }
500 
502  template <class T>
503  typename ::std::enable_if<detail::is_canopen_type<T>::value, bool>::type
505  return Cancel(req, ac);
506  }
507 
509  template <class T>
510  typename ::std::enable_if<detail::is_canopen_type<T>::value, bool>::type
512  return Abort(req);
513  }
514 
516  template <class T>
517  typename ::std::enable_if<detail::is_canopen_type<T>::value>::type
519  Submit(req);
520  }
521 
536  template <class T, class F>
537  typename ::std::enable_if<detail::is_canopen_type<T>::value>::type
538  SubmitUpload(ev_exec_t* exec, uint16_t idx, uint8_t subidx, F&& con,
539  const ::std::chrono::milliseconds& timeout = {}) {
540  Submit(*make_sdo_upload_request<T>(exec, idx, subidx,
541  ::std::forward<F>(con), timeout));
542  }
543 
545  template <class T>
546  typename ::std::enable_if<detail::is_canopen_type<T>::value, bool>::type
548  return Cancel(req, ac);
549  }
550 
552  template <class T>
553  typename ::std::enable_if<detail::is_canopen_type<T>::value, bool>::type
555  return Abort(req);
556  }
557 
573  template <class T, class U = typename ::std::decay<T>::type>
574  typename ::std::enable_if<detail::is_canopen_type<U>::value,
575  SdoFuture<void>>::type
576  AsyncDownload(ev_exec_t* exec, uint16_t idx, uint8_t subidx, T&& value,
577  const ::std::chrono::milliseconds& timeout = {}) {
579  SubmitDownload(
580  exec, idx, subidx, ::std::forward<T>(value),
581  [p](uint8_t id, uint16_t idx, uint8_t subidx,
582  ::std::error_code ec) mutable {
583  if (ec)
584  p.set(util::failure(
585  make_sdo_exception_ptr(id, idx, subidx, ec, "AsyncDownload")));
586  else
587  p.set(util::success());
588  },
589  timeout);
590  return p.get_future();
591  }
592 
608  template <class T>
609  typename ::std::enable_if<detail::is_canopen_type<T>::value,
610  SdoFuture<T>>::type
611  AsyncUpload(ev_exec_t* exec, uint16_t idx, uint8_t subidx,
612  const ::std::chrono::milliseconds& timeout = {}) {
613  SdoPromise<T> p;
614  SubmitUpload<T>(
615  exec, idx, subidx,
616  [p](uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec,
617  T value) mutable {
618  if (ec)
619  p.set(util::failure(
620  make_sdo_exception_ptr(id, idx, subidx, ec, "AsyncUpload")));
621  else
622  p.set(util::success(::std::move(value)));
623  },
624  timeout);
625  return p.get_future();
626  }
627 
629  void Submit(detail::SdoRequestBase& req);
630 
640  bool Cancel(detail::SdoRequestBase& req, SdoErrc ac);
641 
649  ::std::size_t CancelAll(SdoErrc ac);
650 
658  bool Abort(detail::SdoRequestBase& req);
659 
666  ::std::size_t AbortAll();
667 
668  private:
669  struct Impl_;
670  ::std::unique_ptr<Impl_> impl_;
671 };
672 
673 } // namespace canopen
674 
675 } // namespace lely
676 
677 #endif // LELY_COAPP_SDO_HPP_
typename ::std::enable_if< detail::is_canopen_type< T >::value >::type SubmitUpload(SdoUploadRequest< T > &req)
Queues an SDO upload request.
Definition: sdo.hpp:518
SdoUploadRequest(ev_exec_t *exec, F &&con)
Constructs an empty SDO upload request.
Definition: sdo.hpp:296
The internal implementation of the Client-SDO queue.
Definition: sdo.cpp:42
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition: ev.h:29
typename ::std::enable_if< detail::is_canopen_type< T >::value, bool >::type AbortUpload(SdoUploadRequest< T > &req)
Aborts an SDO upload request.
Definition: sdo.hpp:554
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
Definition: task.h:53
uint8_t id
The node-ID.
Definition: sdo.hpp:189
This header file is part of the C++ CANopen application library; it contains the SDO error declaratio...
detail::SdoUploadRequestWrapper< T > * make_sdo_upload_request(ev_exec_t *exec, uint16_t idx, uint8_t subidx, F &&con, const ::std::chrono::milliseconds &timeout={})
Creates an SDO upload request with a completion task.
Definition: sdo.hpp:400
STL namespace.
An opaque CANopen Client-SDO service type.
Definition: csdo.hpp:156
An opaque CANopen device type.
Definition: dev.hpp:77
typename ::std::enable_if< detail::is_canopen_type< T >::value, bool >::type AbortDownload(SdoDownloadRequest< T > &req)
Aborts an SDO download request.
Definition: sdo.hpp:511
SdoFuture< V > make_ready_sdo_future(T &&value)
Returns an SDO future with a shared state that is immediately ready, containing a successful result c...
Definition: sdo.hpp:85
void(uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec, T value) Signature
The signature of the callback function invoked on completion of an SDO upload request.
Definition: sdo.hpp:288
uint8_t subidx
The object sub-index.
Definition: sdo.hpp:193
A promise.
Definition: future.hpp:60
typename ::std::enable_if< detail::is_canopen_type< T >::value, bool >::type CancelDownload(SdoDownloadRequest< T > &req, SdoErrc ac)
Cancels an SDO download request.
Definition: sdo.hpp:504
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
Definition: task.h:43
uint16_t idx
The object index.
Definition: sdo.hpp:191
Future< T, E > get_future() const noexcept
Returns a lely::ev::Future with (a reference to) the same shared state as *this.
Definition: future.hpp:188
typename ::std::enable_if< detail::is_canopen_type< T >::value, bool >::type CancelUpload(SdoUploadRequest< T > &req, SdoErrc ac)
Cancels an SDO upload request.
Definition: sdo.hpp:547
::std::error_code ec
The SDO abort code (0 on success).
Definition: sdo.hpp:201
ev::Executor GetExecutor() const noexcept
Returns the executor to which the completion task is (to be) submitted.
Definition: sdo.hpp:184
SdoErrc
The SDO abort codes.
Definition: sdo_error.hpp:42
SdoFuture< T > make_error_sdo_future(uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec)
Returns an SDO future with a shared state that is immediately ready, containing a failure result cons...
Definition: sdo.hpp:99
inline ::std::chrono::milliseconds from_sdo_timeout(int timeout)
Converts an SDO timeout to a duration.
Definition: sdo.hpp:140
typename ::std::enable_if< detail::is_canopen_type< T >::value >::type SubmitUpload(ev_exec_t *exec, uint16_t idx, uint8_t subidx, F &&con, const ::std::chrono::milliseconds &timeout={})
Queues an SDO upload request.
Definition: sdo.hpp:538
An SDO download (i.e., write) request.
Definition: sdo.hpp:238
SdoDownloadRequest(ev_exec_t *exec, F &&con)
Constructs an empty SDO download request.
Definition: sdo.hpp:260
This header file is part of the C++ CANopen application library; it contains the CANopen type traits...
This header file is part of the event library; it contains the C++ interface for the futures and prom...
void(uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec) Signature
The signature of the callback function invoked on completion of an SDO download request.
Definition: sdo.hpp:252
::std::exception_ptr make_sdo_exception_ptr(uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec) noexcept
Creates an std::exception_ptr that holds a reference to a lely::canopen::SdoError with the specified ...
Definition: sdo_error.cpp:209
typename ::std::enable_if< detail::is_canopen_type< T >::value >::type SubmitDownload(SdoDownloadRequest< T > &req)
Queues an SDO download request.
Definition: sdo.hpp:473
::std::chrono::milliseconds timeout
The SDO timeout.
Definition: sdo.hpp:199
An executable task.
Definition: task.h:41
An abstract task executor. This class is a wrapper around ev_exec_t*.
Definition: exec.hpp:38
An SDO upload (i.e., read) request.
Definition: sdo.hpp:273
typename ::std::enable_if< detail::is_canopen_type< U >::value, SdoFuture< void > >::type AsyncDownload(ev_exec_t *exec, uint16_t idx, uint8_t subidx, T &&value, const ::std::chrono::milliseconds &timeout={})
Queues an asynchronous SDO download request and creates a future which becomes ready once the request...
Definition: sdo.hpp:576
detail::SdoDownloadRequestWrapper< T > * make_sdo_download_request(ev_exec_t *exec, uint16_t idx, uint8_t subidx, U &&value, F &&con, const ::std::chrono::milliseconds &timeout={})
Creates an SDO download request with a completion task.
Definition: sdo.hpp:373
A Client-SDO queue.
Definition: sdo.hpp:407
Definition: buf.hpp:32
typename ::std::enable_if< detail::is_canopen_type< T >::value, SdoFuture< T > >::type AsyncUpload(ev_exec_t *exec, uint16_t idx, uint8_t subidx, const ::std::chrono::milliseconds &timeout={})
Queues an asynchronous SDO upload request and creates a future which becomes ready once the request c...
Definition: sdo.hpp:611
An opaque CAN network interface type.
Definition: net.hpp:85
typename ::std::enable_if< detail::is_canopen_type< U >::value >::type SubmitDownload(ev_exec_t *exec, uint16_t idx, uint8_t subidx, T &&value, F &&con, const ::std::chrono::milliseconds &timeout={})
Queues an SDO download request.
Definition: sdo.hpp:494
SdoFuture< void > make_empty_sdo_future()
Returns an SDO future with a shared state that is immediately ready, containing a successful result o...
Definition: sdo.hpp:73
bool set(U &&u)
Satisfies a promise, if it was not aready satisfied, and stores the specified value as the result in ...
Definition: future.hpp:166
int to_sdo_timeout(const ::std::chrono::duration< Rep, Period > &d)
Converts a duration to an SDO timeout.
Definition: sdo.hpp:148
A future.
Definition: future.hpp:50