Lely core libraries 2.3.4
sdo.hpp
Go to the documentation of this file.
1
22#ifndef LELY_COAPP_SDO_HPP_
23#define LELY_COAPP_SDO_HPP_
24
27#include <lely/ev/future.hpp>
28
29#include <chrono>
30#include <limits>
31#include <memory>
32#include <string>
33#include <utility>
34
35// The CAN network interface from <lely/can/net.h>.
36struct __can_net;
37
38// The CANopen device from <lely/co/dev.h>.
39struct __co_dev;
40
41// The CANopen Client-SDO service from <lely/co/csdo.h>.
42struct __co_csdo;
43
44namespace lely {
45
46namespace canopen {
47
54template <class T>
56
63template <class T>
65
72inline SdoFuture<void>
74 return ev::make_empty_future<::std::exception_ptr>();
75}
76
84inline SdoFuture<V>
86 return ev::make_ready_future<::std::exception_ptr, V>(
87 ::std::forward<T>(value));
88}
89
97template <class T>
98inline SdoFuture<T>
100 ::std::error_code ec) {
101 return ev::make_error_future<T>(make_sdo_exception_ptr(id, idx, subidx, ec));
102}
103
111template <class T>
112inline SdoFuture<T>
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
126template <class T>
127inline SdoFuture<T>
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
134class Sdo;
135
136namespace detail {
137
139inline ::std::chrono::milliseconds
140from_sdo_timeout(int timeout) {
141 using ::std::chrono::milliseconds;
142 return timeout <= 0 ? milliseconds::max() : milliseconds(timeout);
143}
144
146template <class Rep, class Period>
147inline int
148to_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
162class 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 bool block_ = false,
168 const ::std::chrono::milliseconds& timeout_ = {})
170 [](ev_task* task) noexcept {
171 (*static_cast<SdoRequestBase*>(task))();
172 }),
173 idx(idx_),
174 subidx(subidx_),
175 block(block_),
176 timeout(timeout_) {}
177
178 SdoRequestBase(const SdoRequestBase&) = delete;
179
180 SdoRequestBase& operator=(const SdoRequestBase&) = delete;
181
182 virtual ~SdoRequestBase() = default;
183
189
191 uint8_t id{0};
200 bool block{false};
206 ::std::chrono::milliseconds timeout;
208 ::std::error_code ec;
209
210 private:
211 virtual void operator()() noexcept = 0;
212
213 virtual void OnRequest(void* data) noexcept = 0;
214};
215
216template <class T>
218 public:
219 using SdoRequestBase::SdoRequestBase;
220
221 template <class U>
223 U&& value_, bool block = false,
224 const ::std::chrono::milliseconds& timeout = {})
226 value(::std::forward<U>(value_)) {}
227
229 T value{};
230};
231
233 public:
234 using SdoRequestBase::SdoRequestBase;
235
237 const uint8_t* end_,
238 const ::std::chrono::milliseconds& timeout = {})
239 : SdoRequestBase(exec, 0, 0, false, timeout), begin(begin_), end(end_) {}
240
241 SdoDownloadDcfRequestBase(ev_exec_t* exec, const char* path,
242 const ::std::chrono::milliseconds& timeout = {})
243 : SdoRequestBase(exec, 0, 0, false, timeout) {
244 Read(path);
245 }
246
248
250 void Read(const char* path);
251
256 const uint8_t* begin{nullptr};
257
262 const uint8_t* end{nullptr};
263
264 private:
265 void* dom_{nullptr};
266};
267
268template <class T>
270 public:
271 using SdoRequestBase::SdoRequestBase;
272
274 T value{};
275};
276
277} // namespace detail
278
280template <class T>
282 public:
294 using Signature = void(uint8_t id, uint16_t idx, uint8_t subidx,
295 ::std::error_code ec);
296
302 template <class F>
304 : detail::SdoDownloadRequestBase<T>(exec), con_(::std::forward<F>(con)) {}
305
306 private:
307 void operator()() noexcept final;
308
309 void OnRequest(void* data) noexcept final;
310
311 ::std::function<Signature> con_;
312};
313
318class SdoDownloadDcfRequest : public detail::SdoDownloadDcfRequestBase {
319 public:
337 using Signature = void(uint8_t id, uint16_t idx, uint8_t subidx,
338 ::std::error_code ec);
339
347 template <class F>
349 : detail::SdoDownloadDcfRequestBase(exec), con_(::std::forward<F>(con)) {}
350
351 private:
352 void operator()() noexcept final;
353
354 void OnRequest(void* data) noexcept final;
355
356 ::std::function<Signature> con_;
357};
358
360template <class T>
361class SdoUploadRequest : public detail::SdoUploadRequestBase<T> {
362 public:
375 using Signature = void(uint8_t id, uint16_t idx, uint8_t subidx,
376 ::std::error_code ec, T value);
377
383 template <class F>
385 : detail::SdoUploadRequestBase<T>(exec), con_(::std::forward<F>(con)) {}
386
387 private:
388 void operator()() noexcept final;
389
390 void OnRequest(void* data) noexcept final;
391
392 ::std::function<Signature> con_;
393};
394
395namespace detail {
396
397template <class T>
398class SdoDownloadRequestWrapper : public SdoDownloadRequestBase<T> {
399 public:
400 using Signature = void(uint8_t id, uint16_t idx, uint8_t subidx,
401 ::std::error_code ec);
402
403 template <class U, class F>
404 SdoDownloadRequestWrapper(ev_exec_t* exec, uint16_t idx, uint8_t subidx,
405 U&& value, F&& con, bool block,
406 const ::std::chrono::milliseconds& timeout)
407 : SdoDownloadRequestBase<T>(exec, idx, subidx, ::std::forward<U>(value),
408 block, timeout),
409 con_(::std::forward<F>(con)) {}
410
411 private:
412 void operator()() noexcept final;
413
414 void OnRequest(void* data) noexcept final;
415
416 ::std::function<Signature> con_;
417};
418
419class SdoDownloadDcfRequestWrapper : public SdoDownloadDcfRequestBase {
420 public:
421 using Signature = void(uint8_t id, uint16_t idx, uint8_t subidx,
422 ::std::error_code ec);
423
424 template <class F>
425 SdoDownloadDcfRequestWrapper(ev_exec_t* exec, const uint8_t* begin,
426 const uint8_t* end, F&& con,
427 const ::std::chrono::milliseconds& timeout)
428 : SdoDownloadDcfRequestBase(exec, begin, end, timeout),
429 con_(::std::forward<F>(con)) {}
430
431 template <class F>
432 SdoDownloadDcfRequestWrapper(ev_exec_t* exec, const char* path, F&& con,
433 const ::std::chrono::milliseconds& timeout)
434 : SdoDownloadDcfRequestBase(exec, path, timeout),
435 con_(::std::forward<F>(con)) {}
436
437 template <class F>
438 SdoDownloadDcfRequestWrapper(ev_exec_t* exec, const ::std::string& path,
439 F&& con,
440 const ::std::chrono::milliseconds& timeout)
441 : SdoDownloadDcfRequestBase(exec, path.c_str(), timeout),
442 con_(::std::forward<F>(con)) {}
443
444 private:
445 void operator()() noexcept final;
446
447 void OnRequest(void* data) noexcept final;
448
449 ::std::function<Signature> con_;
450};
451
452template <class T>
453class SdoUploadRequestWrapper : public SdoUploadRequestBase<T> {
454 public:
455 using Signature = void(uint8_t id, uint16_t idx, uint8_t subidx,
456 ::std::error_code ec, T value);
457
458 template <class F>
459 SdoUploadRequestWrapper(ev_exec_t* exec, uint16_t idx, uint8_t subidx,
460 F&& con, bool block,
461 const ::std::chrono::milliseconds& timeout)
462 : SdoUploadRequestBase<T>(exec, idx, subidx, block, timeout),
463 con_(::std::forward<F>(con)) {}
464
465 private:
466 void operator()() noexcept final;
467
468 void OnRequest(void* data) noexcept final;
469
470 ::std::function<Signature> con_;
471};
472
473} // namespace detail
474
495template <class T, class U, class F>
496inline detail::SdoDownloadRequestWrapper<T>*
497make_sdo_download_request(ev_exec_t* exec, uint16_t idx, uint8_t subidx,
498 U&& value, F&& con, bool block = false,
499 const ::std::chrono::milliseconds& timeout = {}) {
500 return new detail::SdoDownloadRequestWrapper<T>(
501 exec, idx, subidx, ::std::forward<U>(value), ::std::forward<F>(con),
502 block, timeout);
503}
504
525template <class F>
526inline detail::SdoDownloadDcfRequestWrapper*
528 const uint8_t* end, F&& con,
529 const ::std::chrono::milliseconds& timeout = {}) {
530 return new detail::SdoDownloadDcfRequestWrapper(
531 exec, begin, end, ::std::forward<F>(con), timeout);
532}
533
551template <class F>
552inline detail::SdoDownloadDcfRequestWrapper*
554 const ::std::chrono::milliseconds& timeout = {}) {
555 return new detail::SdoDownloadDcfRequestWrapper(
556 exec, path, ::std::forward<F>(con), timeout);
557}
558
578template <class T, class F>
579inline detail::SdoUploadRequestWrapper<T>*
581 bool block = false,
582 const ::std::chrono::milliseconds& timeout = {}) {
583 return new detail::SdoUploadRequestWrapper<T>(
584 exec, idx, subidx, ::std::forward<F>(con), block, timeout);
585}
586
588class Sdo {
589 template <class>
590 friend class SdoDownloadRequest;
591
592 friend class SdoDownloadDcfRequest;
593
594 template <class>
595 friend class SdoUploadRequest;
596
597 template <class>
598 friend class detail::SdoDownloadRequestWrapper;
599
600 friend class detail::SdoDownloadDcfRequestWrapper;
601
602 template <class>
603 friend class detail::SdoUploadRequestWrapper;
604
605 public:
608
617 Sdo(__can_net* net, uint8_t id);
618
628 Sdo(__can_net* net, __co_dev* dev, uint8_t num);
629
638 Sdo(__co_csdo* sdo);
639
640 Sdo(const Sdo&) = delete;
641 Sdo(Sdo&&) = default;
642
643 Sdo& operator=(const Sdo&) = delete;
644 Sdo& operator=(Sdo&&);
645
651
653 explicit operator bool() const noexcept { return !!impl_; }
654
656 template <class T>
657 typename ::std::enable_if<is_canopen<T>::value>::type
659 Submit(req);
660 }
661
680 typename ::std::enable_if<is_canopen<U>::value>::type
681 SubmitDownload(ev_exec_t* exec, uint16_t idx, uint8_t subidx, T&& value,
682 F&& con, bool block = false,
683 const ::std::chrono::milliseconds& timeout = {}) {
685 exec, idx, subidx, ::std::forward<T>(value), ::std::forward<F>(con),
686 block, timeout));
687 }
688
690 template <class T>
691 typename ::std::enable_if<is_canopen<T>::value, bool>::type
693 return Cancel(req, ac);
694 }
695
697 template <class T>
698 typename ::std::enable_if<is_canopen<T>::value, bool>::type
700 return Abort(req);
701 }
702
704 void
706 Submit(req);
707 }
708
726 template <class F>
727 void
728 SubmitDownloadDcf(ev_exec_t* exec, const uint8_t* begin, const uint8_t* end,
729 F&& con, const ::std::chrono::milliseconds& timeout = {}) {
730 Submit(*make_sdo_download_dcf_request(exec, begin, end,
731 ::std::forward<F>(con), timeout));
732 }
733
748 template <class F>
749 void
750 SubmitDownloadDcf(ev_exec_t* exec, const char* path, F&& con,
751 const ::std::chrono::milliseconds& timeout = {}) {
752 Submit(*make_sdo_download_dcf_request(exec, path, ::std::forward<F>(con),
753 timeout));
754 }
755
757 bool
759 return Cancel(req, ac);
760 }
761
763 bool
765 return Abort(req);
766 }
767
769 template <class T>
770 typename ::std::enable_if<is_canopen<T>::value>::type
772 Submit(req);
773 }
774
791 template <class T, class F>
792 typename ::std::enable_if<is_canopen<T>::value>::type
793 SubmitUpload(ev_exec_t* exec, uint16_t idx, uint8_t subidx, F&& con,
794 bool block = false,
795 const ::std::chrono::milliseconds& timeout = {}) {
796 Submit(*make_sdo_upload_request<T>(exec, idx, subidx,
797 ::std::forward<F>(con), block, timeout));
798 }
799
801 template <class T>
802 typename ::std::enable_if<is_canopen<T>::value, bool>::type
804 return Cancel(req, ac);
805 }
806
808 template <class T>
809 typename ::std::enable_if<is_canopen<T>::value, bool>::type
811 return Abort(req);
812 }
813
832 typename ::std::enable_if<is_canopen<U>::value, SdoFuture<void>>::type
833 AsyncDownload(ev_exec_t* exec, uint16_t idx, uint8_t subidx, T&& value,
834 bool block = false,
835 const ::std::chrono::milliseconds& timeout = {}) {
837 SubmitDownload(
838 exec, idx, subidx, ::std::forward<T>(value),
839 [p](uint8_t id, uint16_t idx, uint8_t subidx,
840 ::std::error_code ec) mutable {
841 if (ec)
842 p.set(util::failure(
843 make_sdo_exception_ptr(id, idx, subidx, ec, "AsyncDownload")));
844 else
845 p.set(util::success());
846 },
847 block, timeout);
848 return p.get_future();
849 }
850
868 SdoFuture<void> AsyncDownloadDcf(
869 ev_exec_t* exec, const uint8_t* begin, const uint8_t* end,
870 const ::std::chrono::milliseconds& timeout = {});
871
886 SdoFuture<void> AsyncDownloadDcf(
887 ev_exec_t* exec, const char* path,
888 const ::std::chrono::milliseconds& timeout = {});
889
907 template <class T>
908 typename ::std::enable_if<is_canopen<T>::value, SdoFuture<T>>::type
909 AsyncUpload(ev_exec_t* exec, uint16_t idx, uint8_t subidx, bool block = false,
910 const ::std::chrono::milliseconds& timeout = {}) {
913 exec, idx, subidx,
914 [p](uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec,
915 T value) mutable {
916 if (ec)
917 p.set(util::failure(
918 make_sdo_exception_ptr(id, idx, subidx, ec, "AsyncUpload")));
919 else
920 p.set(util::success(::std::move(value)));
921 },
922 block, timeout);
923 return p.get_future();
924 }
925
927 void Submit(detail::SdoRequestBase& req);
928
938 bool Cancel(detail::SdoRequestBase& req, SdoErrc ac);
939
947 ::std::size_t CancelAll(SdoErrc ac);
948
956 bool Abort(detail::SdoRequestBase& req);
957
964 ::std::size_t AbortAll();
965
966 private:
967 struct Impl_;
968 ::std::unique_ptr<Impl_> impl_;
969};
970
971} // namespace canopen
972
973} // namespace lely
974
975#endif // LELY_COAPP_SDO_HPP_
A CANopen value.
Definition val.hpp:42
A series of SDO download (i.e., write) requests corresponding to the entries in a concise DCF.
Definition sdo.hpp:318
void(uint8_t id, uint16_t idx, uint8_t subidx, ::std::error_code ec) Signature
The signature of the callback function invoked when all SDO download requests are successfully comple...
Definition sdo.hpp:338
SdoDownloadDcfRequest(ev_exec_t *exec, F &&con)
Constructs an empty SDO download DCF request.
Definition sdo.hpp:348
An SDO download (i.e., write) request.
Definition sdo.hpp:281
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:295
SdoDownloadRequest(ev_exec_t *exec, F &&con)
Constructs an empty SDO download request.
Definition sdo.hpp:303
An SDO upload (i.e., read) request.
Definition sdo.hpp:361
SdoUploadRequest(ev_exec_t *exec, F &&con)
Constructs an empty SDO upload request.
Definition sdo.hpp:384
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:376
A Client-SDO queue.
Definition sdo.hpp:588
typename::std::enable_if< is_canopen< T >::value, bool >::type AbortUpload(SdoUploadRequest< T > &req)
Aborts an SDO upload request.
Definition sdo.hpp:810
typename::std::enable_if< is_canopen< T >::value >::type SubmitDownload(SdoDownloadRequest< T > &req)
Queues an SDO download request.
Definition sdo.hpp:658
typename::std::enable_if< is_canopen< T >::value >::type SubmitUpload(ev_exec_t *exec, uint16_t idx, uint8_t subidx, F &&con, bool block=false, const ::std::chrono::milliseconds &timeout={})
Queues an SDO upload request.
Definition sdo.hpp:793
Sdo()
Default-constructs an invalid Client-SDO queue.
typename::std::enable_if< is_canopen< T >::value, bool >::type CancelDownload(SdoDownloadRequest< T > &req, SdoErrc ac)
Cancels an SDO download request.
Definition sdo.hpp:692
typename::std::enable_if< is_canopen< T >::value, bool >::type CancelUpload(SdoUploadRequest< T > &req, SdoErrc ac)
Cancels an SDO upload request.
Definition sdo.hpp:803
bool AbortDownloadDcf(SdoDownloadDcfRequest &req)
Aborts an SDO download DCF request.
Definition sdo.hpp:764
typename::std::enable_if< is_canopen< U >::value, SdoFuture< void > >::type AsyncDownload(ev_exec_t *exec, uint16_t idx, uint8_t subidx, T &&value, bool block=false, const ::std::chrono::milliseconds &timeout={})
Queues an asynchronous SDO download request and creates a future which becomes ready once the request...
Definition sdo.hpp:833
typename::std::enable_if< is_canopen< T >::value, SdoFuture< T > >::type AsyncUpload(ev_exec_t *exec, uint16_t idx, uint8_t subidx, bool block=false, 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:909
void SubmitDownloadDcf(ev_exec_t *exec, const uint8_t *begin, const uint8_t *end, F &&con, const ::std::chrono::milliseconds &timeout={})
Queues an SDO download DCF request.
Definition sdo.hpp:728
typename::std::enable_if< is_canopen< T >::value >::type SubmitUpload(SdoUploadRequest< T > &req)
Queues an SDO upload request.
Definition sdo.hpp:771
void SubmitDownloadDcf(SdoDownloadDcfRequest &req)
Queues an SDO download DCF request.
Definition sdo.hpp:705
~Sdo()
Destructs the Client-SDO queue.
void SubmitDownloadDcf(ev_exec_t *exec, const char *path, F &&con, const ::std::chrono::milliseconds &timeout={})
Queues an SDO download DCF request.
Definition sdo.hpp:750
typename::std::enable_if< is_canopen< T >::value, bool >::type AbortDownload(SdoDownloadRequest< T > &req)
Aborts an SDO download request.
Definition sdo.hpp:699
typename::std::enable_if< is_canopen< U >::value >::type SubmitDownload(ev_exec_t *exec, uint16_t idx, uint8_t subidx, T &&value, F &&con, bool block=false, const ::std::chrono::milliseconds &timeout={})
Queues an SDO download request.
Definition sdo.hpp:681
bool CancelDownloadDcf(SdoDownloadDcfRequest &req, SdoErrc ac)
Cancels an SDO download request.
Definition sdo.hpp:758
uint16_t idx
The object index.
Definition sdo.hpp:193
::std::chrono::milliseconds timeout
The SDO timeout.
Definition sdo.hpp:206
ev::Executor GetExecutor() const noexcept
Returns the executor to which the completion task is (to be) submitted.
Definition sdo.hpp:186
bool block
A flag specifying whether the request should use a block SDO instead of a segmented (or expedited) SD...
Definition sdo.hpp:200
uint8_t subidx
The object sub-index.
Definition sdo.hpp:195
::std::error_code ec
The SDO abort code (0 on success).
Definition sdo.hpp:208
An abstract task executor. This class is a wrapper around #ev_exec_t*.
Definition exec.hpp:38
A future.
Definition future.hpp:384
A promise.
Definition future.hpp:60
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...
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
Definition ev.h:29
inline ::std::chrono::milliseconds from_sdo_timeout(int timeout)
Converts an SDO timeout to a duration.
Definition sdo.hpp:140
int to_sdo_timeout(const ::std::chrono::duration< Rep, Period > &d)
Converts a duration to an SDO timeout.
Definition sdo.hpp:148
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
detail::SdoUploadRequestWrapper< T > * make_sdo_upload_request(ev_exec_t *exec, uint16_t idx, uint8_t subidx, F &&con, bool block=false, const ::std::chrono::milliseconds &timeout={})
Creates an SDO upload request with a completion task.
Definition sdo.hpp:580
SdoErrc
The SDO abort codes.
Definition sdo_error.hpp:42
detail::SdoDownloadDcfRequestWrapper * make_sdo_download_dcf_request(ev_exec_t *exec, const uint8_t *begin, const uint8_t *end, F &&con, const ::std::chrono::milliseconds &timeout={})
Creates a series of SDO download requests, corresponding to the entries in a concise DCF,...
Definition sdo.hpp:527
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
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
::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 ...
STL namespace.
This header file is part of the C++ CANopen application library; it contains the SDO error declaratio...
A CAN network interface.
Definition net.c:37
A CANopen Client-SDO.
Definition csdo.c:71
A CANopen device.
Definition dev.h:30
An executable task.
Definition task.h:41
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
Definition task.h:43
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
Definition task.h:53