Lely core libraries 1.9.2
sdo.cpp
Go to the documentation of this file.
1
24#include "coapp.hpp"
25
27#include <lely/coapp/sdo.hpp>
28
29#include <cassert>
30
31#include <lely/aio/queue.h>
32#include <lely/co/csdo.hpp>
33
34namespace lely {
35
36namespace canopen {
37
38namespace {
39
40::std::error_code
41ErrorCode(int errc, uint32_t ac) {
42 if (errc)
43 return ::std::error_code(errc, ::std::system_category());
44 else if (ac)
45 return static_cast<SdoErrc>(ac);
46 else
47 return {};
48}
49
50} // namespace
51
52using namespace aio;
53
55struct Sdo::Impl_ {
56 Impl_(CANNet* net, CODev* dev, uint8_t num);
57 Impl_(COCSDO* sdo, int timeout);
58 ~Impl_();
59
60 void Submit(RequestBase_& req);
61
62 ::std::size_t Cancel(RequestBase_* req, SdoErrc ac);
63
64 template <class T, class U>
65 void OnRequest(uint16_t idx, uint8_t subidx, U&& value);
66
67 template <class T>
68 void OnRequest(uint16_t idx, uint8_t subidx);
69
70 void OnDnCon(COCSDO*, uint16_t idx, uint8_t subidx, uint32_t ac) noexcept;
71
72 template <class T>
73 void OnUpCon(COCSDO*, uint16_t idx, uint8_t subidx, uint32_t ac,
74 T value) noexcept;
75
76 void OnTaskFinished(RequestBase_& op) noexcept;
77
78 aio_queue queue;
79 ::std::shared_ptr<COCSDO> sdo;
80};
81
82template <class T>
83void
85 impl->OnRequest<T>(this->idx, this->subidx, this->value);
86}
87
88template <class T>
89void
90Sdo::DownloadRequest<T>::Func_(aio_task* task) noexcept {
91 auto self = static_cast<Sdo::DownloadRequest<T>*>(task);
92
93 if (self->con_)
94 self->con_(self->idx, self->subidx, ErrorCode(self->errc, self->ac));
95}
96
97template <class T>
98void
99Sdo::UploadRequest<T>::OnRequest(Impl_* impl) noexcept {
100 impl->OnRequest<T>(this->idx, this->subidx);
101}
102
103template <class T>
104void
105Sdo::UploadRequest<T>::Func_(aio_task* task) noexcept {
106 auto self = static_cast<Sdo::UploadRequest<T>*>(task);
107
108 if (self->con_)
109 self->con_(self->idx, self->subidx, ErrorCode(self->errc, self->ac),
110 ::std::move(self->value));
111}
112
113template <class T>
114void
115Sdo::DownloadRequestWrapper<T>::OnRequest(Impl_* impl) noexcept {
116 impl->OnRequest<T>(this->idx, this->subidx, this->value);
117}
118
119template <class T>
120void
121Sdo::DownloadRequestWrapper<T>::Func_(aio_task* task) noexcept {
122 auto self = static_cast<Sdo::DownloadRequestWrapper<T>*>(task);
123
124 ::std::function<DownloadSignature> con = ::std::move(self->con_);
125 auto idx = self->idx;
126 auto subidx = self->subidx;
127 auto ec = ErrorCode(self->errc, self->ac);
128 delete self;
129
130 if (con) con(idx, subidx, ec);
131}
132
133template <class T>
134void
135Sdo::UploadRequestWrapper<T>::OnRequest(Impl_* impl) noexcept {
136 impl->OnRequest<T>(this->idx, this->subidx);
137}
138
139template <class T>
140void
141Sdo::UploadRequestWrapper<T>::Func_(aio_task* task) noexcept {
142 auto self = static_cast<Sdo::UploadRequestWrapper<T>*>(task);
143
144 ::std::function<UploadSignature<T>> con = ::std::move(self->con_);
145 auto idx = self->idx;
146 auto subidx = self->subidx;
147 auto ec = ErrorCode(self->errc, self->ac);
148 T value = ::std::move(self->value);
149 delete self;
150
151 if (con) con(idx, subidx, ec, ::std::move(value));
152}
153
154template <class T>
155void
156Sdo::AsyncDownloadRequest<T>::OnRequest(Impl_* impl) noexcept {
157 impl->OnRequest<T>(this->idx, this->subidx, this->value);
158}
159
160template <class T>
161void
162Sdo::AsyncDownloadRequest<T>::Func_(aio_task* task) noexcept {
163 auto self = static_cast<Sdo::AsyncDownloadRequest<T>*>(task);
164
165 aio::Promise<::std::error_code> promise = ::std::move(self->promise_);
166 auto ec = ErrorCode(self->errc, self->ac);
167 delete self;
168
169 promise.SetValue(ec);
170}
171
172template <class T>
173void
174Sdo::AsyncUploadRequest<T>::OnRequest(Impl_* impl) noexcept {
175 impl->OnRequest<T>(this->idx, this->subidx);
176}
177
178template <class T>
179void
180Sdo::AsyncUploadRequest<T>::Func_(aio_task* task) noexcept {
181 auto self = static_cast<Sdo::AsyncUploadRequest<T>*>(task);
182
183 aio::Promise<::std::tuple<::std::error_code, T>> promise =
184 ::std::move(self->promise_);
185 auto value = ::std::make_tuple(ErrorCode(self->errc, self->ac),
186 ::std::move(self->value));
187 delete self;
188
189 promise.SetValue(value);
190}
191
192#ifndef DOXYGEN_SHOULD_SKIP_THIS
193
194// BOOLEAN
195template class Sdo::DownloadRequest<bool>;
196template class Sdo::UploadRequest<bool>;
197template class Sdo::DownloadRequestWrapper<bool>;
198template class Sdo::UploadRequestWrapper<bool>;
199template class Sdo::AsyncDownloadRequest<bool>;
200template class Sdo::AsyncUploadRequest<bool>;
201
202// INTEGER8
203template class Sdo::DownloadRequest<int8_t>;
204template class Sdo::UploadRequest<int8_t>;
205template class Sdo::DownloadRequestWrapper<int8_t>;
206template class Sdo::UploadRequestWrapper<int8_t>;
207template class Sdo::AsyncDownloadRequest<int8_t>;
208template class Sdo::AsyncUploadRequest<int8_t>;
209
210// INTEGER16
211template class Sdo::DownloadRequest<int16_t>;
212template class Sdo::UploadRequest<int16_t>;
213template class Sdo::DownloadRequestWrapper<int16_t>;
214template class Sdo::UploadRequestWrapper<int16_t>;
215template class Sdo::AsyncDownloadRequest<int16_t>;
216template class Sdo::AsyncUploadRequest<int16_t>;
217
218// INTEGER32
219template class Sdo::DownloadRequest<int32_t>;
220template class Sdo::UploadRequest<int32_t>;
221template class Sdo::DownloadRequestWrapper<int32_t>;
222template class Sdo::UploadRequestWrapper<int32_t>;
223template class Sdo::AsyncDownloadRequest<int32_t>;
224template class Sdo::AsyncUploadRequest<int32_t>;
225
226// UNSIGNED8
227template class Sdo::DownloadRequest<uint8_t>;
228template class Sdo::UploadRequest<uint8_t>;
229template class Sdo::DownloadRequestWrapper<uint8_t>;
230template class Sdo::UploadRequestWrapper<uint8_t>;
231template class Sdo::AsyncDownloadRequest<uint8_t>;
232template class Sdo::AsyncUploadRequest<uint8_t>;
233
234// UNSIGNED16
235template class Sdo::DownloadRequest<uint16_t>;
236template class Sdo::UploadRequest<uint16_t>;
237template class Sdo::DownloadRequestWrapper<uint16_t>;
238template class Sdo::UploadRequestWrapper<uint16_t>;
239template class Sdo::AsyncDownloadRequest<uint16_t>;
240template class Sdo::AsyncUploadRequest<uint16_t>;
241
242// UNSIGNED32
243template class Sdo::DownloadRequest<uint32_t>;
244template class Sdo::UploadRequest<uint32_t>;
245template class Sdo::DownloadRequestWrapper<uint32_t>;
246template class Sdo::UploadRequestWrapper<uint32_t>;
247template class Sdo::AsyncDownloadRequest<uint32_t>;
248template class Sdo::AsyncUploadRequest<uint32_t>;
249
250// REAL32
251template class Sdo::DownloadRequest<float>;
252template class Sdo::UploadRequest<float>;
253template class Sdo::DownloadRequestWrapper<float>;
254template class Sdo::UploadRequestWrapper<float>;
255template class Sdo::AsyncDownloadRequest<float>;
256template class Sdo::AsyncUploadRequest<float>;
257
258// VISIBLE_STRING
259template class Sdo::DownloadRequest<::std::string>;
260template class Sdo::UploadRequest<::std::string>;
261template class Sdo::DownloadRequestWrapper<::std::string>;
262template class Sdo::UploadRequestWrapper<::std::string>;
263template class Sdo::AsyncDownloadRequest<::std::string>;
264template class Sdo::AsyncUploadRequest<::std::string>;
265
266// OCTET_STRING
267template class Sdo::DownloadRequest<::std::vector<uint8_t>>;
268template class Sdo::UploadRequest<::std::vector<uint8_t>>;
269template class Sdo::DownloadRequestWrapper<::std::vector<uint8_t>>;
270template class Sdo::UploadRequestWrapper<::std::vector<uint8_t>>;
271template class Sdo::AsyncDownloadRequest<::std::vector<uint8_t>>;
272template class Sdo::AsyncUploadRequest<::std::vector<uint8_t>>;
273
274// UNICODE_STRING
275template class Sdo::DownloadRequest<::std::basic_string<char16_t>>;
276template class Sdo::UploadRequest<::std::basic_string<char16_t>>;
277template class Sdo::DownloadRequestWrapper<::std::basic_string<char16_t>>;
278template class Sdo::UploadRequestWrapper<::std::basic_string<char16_t>>;
279template class Sdo::AsyncDownloadRequest<::std::basic_string<char16_t>>;
280template class Sdo::AsyncUploadRequest<::std::basic_string<char16_t>>;
281
282// TIME_OF_DAY
283// TIME_DIFFERENCE
284// DOMAIN
285// INTEGER24
286
287// REAL64
288template class Sdo::DownloadRequest<double>;
289template class Sdo::UploadRequest<double>;
290template class Sdo::DownloadRequestWrapper<double>;
291template class Sdo::UploadRequestWrapper<double>;
292template class Sdo::AsyncDownloadRequest<double>;
293template class Sdo::AsyncUploadRequest<double>;
294
295// INTEGER40
296// INTEGER48
297// INTEGER56
298
299// INTEGER64
300template class Sdo::DownloadRequest<int64_t>;
301template class Sdo::UploadRequest<int64_t>;
302template class Sdo::DownloadRequestWrapper<int64_t>;
303template class Sdo::UploadRequestWrapper<int64_t>;
304template class Sdo::AsyncDownloadRequest<int64_t>;
305template class Sdo::AsyncUploadRequest<int64_t>;
306
307// UNSIGNED24
308// UNSIGNED40
309// UNSIGNED48
310// UNSIGNED56
311
312// UNSIGNED64
313template class Sdo::DownloadRequest<uint64_t>;
314template class Sdo::UploadRequest<uint64_t>;
315template class Sdo::DownloadRequestWrapper<uint64_t>;
316template class Sdo::UploadRequestWrapper<uint64_t>;
317template class Sdo::AsyncDownloadRequest<uint64_t>;
318template class Sdo::AsyncUploadRequest<uint64_t>;
319
320#endif // !DOXYGEN_SHOULD_SKIP_THIS
321
322Sdo::Sdo() = default;
323
324Sdo::Sdo(CANNet* net, uint8_t id) : Sdo(net, nullptr, id) {}
325
326Sdo::Sdo(CANNet* net, CODev* dev, uint8_t num)
327 : impl_(new Impl_(net, dev, num)) {}
328
329Sdo::Sdo(COCSDO* sdo) : impl_(new Impl_(sdo, sdo->getTimeout())) {}
330
331Sdo& Sdo::operator=(Sdo&&) = default;
332
333Sdo::~Sdo() = default;
334
335void
336Sdo::Submit(RequestBase_& op) {
337 impl_->Submit(op);
338}
339
340::std::size_t
341Sdo::Cancel(RequestBase_& op, SdoErrc ac) {
342 return impl_->Cancel(&op, ac);
343}
344
345::std::size_t
347 return impl_->Cancel(nullptr, ac);
348}
349
350Sdo::Impl_::Impl_(CANNet* net, CODev* dev, uint8_t num)
351 : sdo(make_shared_c<COCSDO>(net, dev, num)) {
352 aio_queue_init(&queue);
353}
354
355Sdo::Impl_::Impl_(COCSDO* sdo_, int timeout)
356 : sdo(sdo_, [=](COCSDO* sdo) { sdo->setTimeout(timeout); }) {
357 aio_queue_init(&queue);
358}
359
360Sdo::Impl_::~Impl_() { Cancel(nullptr, SdoErrc::NO_SDO); }
361
362void
363Sdo::Impl_::Submit(RequestBase_& req) {
364 assert(req.exec);
365 req.GetExecutor().OnTaskStarted();
366 req.errc = errnum2c(ERRNUM_INPROGRESS);
367
368 if (!sdo) {
369 req.errc = 0;
370 req.ac = static_cast<uint32_t>(SdoErrc::NO_SDO);
371 OnTaskFinished(req);
372 } else {
373 bool first = aio_queue_empty(&queue);
374 aio_queue_push(&queue, &req);
375 if (first) req.OnRequest(this);
376 }
377}
378
379::std::size_t
380Sdo::Impl_::Cancel(RequestBase_* req, SdoErrc ac) {
381 aio_queue queue_;
382 aio_queue_init(&queue_);
383
384 if (!req || req != aio_queue_front(&queue)) {
385 auto task = aio_queue_pop(&queue);
386 aio_queue_move(&queue_, &queue, req);
387 if (task) aio_queue_push(&queue, task);
388 req = task && !req ? static_cast<RequestBase_*>(task) : nullptr;
389 }
390
391 if (req) {
392 assert(req == aio_queue_front(&queue));
393 sdo->abortReq(static_cast<uint32_t>(ac));
394 }
395
396 auto n = aio_queue_cancel(&queue_, errnum2c(ERRNUM_CANCELED));
397 if (req) n += n < ::std::numeric_limits<decltype(n)>::max();
398 return n;
399}
400
401template <class T, class U>
402void
403Sdo::Impl_::OnRequest(uint16_t idx, uint8_t subidx, U&& value) {
404 constexpr auto N = co_type_traits_T<T>::index;
405
406 auto task = aio_queue_front(&queue);
407 assert(task);
408 auto& req = *static_cast<Sdo::RequestBase_*>(task);
409
410 sdo->setTimeout(detail::ToTimeout(req.timeout));
411 if (sdo->dnReq<N, Impl_, &Impl_::OnDnCon>(
412 idx, subidx, ::std::forward<U>(value), this) == -1) {
413 req.errc = get_errc();
414 OnTaskFinished(req);
415 }
416}
417
418template <class T>
419void
420Sdo::Impl_::OnRequest(uint16_t idx, uint8_t subidx) {
421 auto task = aio_queue_front(&queue);
422 assert(task);
423 auto& req = *static_cast<Sdo::RequestBase_*>(task);
424
425 sdo->setTimeout(detail::ToTimeout(req.timeout));
426 if (sdo->upReq<T, Impl_, &Impl_::OnUpCon<T>>(idx, subidx, this) == -1) {
427 req.errc = get_errc();
428 OnTaskFinished(req);
429 }
430}
431
432void
433Sdo::Impl_::OnDnCon(COCSDO*, uint16_t idx, uint8_t subidx,
434 uint32_t ac) noexcept {
435 auto task = aio_queue_pop(&queue);
436 assert(task);
437 auto& req = *static_cast<Sdo::RequestBase_*>(task);
438
439 req.errc = 0;
440 req.idx = idx;
441 req.subidx = subidx;
442 req.ac = ac;
443
444 OnTaskFinished(req);
445}
446
447template <class T>
448void
449Sdo::Impl_::OnUpCon(COCSDO*, uint16_t idx, uint8_t subidx, uint32_t ac,
450 T value) noexcept {
451 auto task = aio_queue_pop(&queue);
452 assert(task);
453 auto& req = *static_cast<Sdo::UploadRequestBase_<T>*>(task);
454
455 req.errc = 0;
456 req.idx = idx;
457 req.subidx = subidx;
458 req.ac = ac;
459 req.value = ::std::move(value);
460
461 OnTaskFinished(req);
462}
463
464void
465Sdo::Impl_::OnTaskFinished(RequestBase_& req) noexcept {
466 auto exec = req.GetExecutor();
467 exec.Post(req);
468 exec.OnTaskFinished();
469
470 auto task = aio_queue_front(&queue);
471 if (task) static_cast<Sdo::RequestBase_*>(task)->OnRequest(this);
472}
473
474} // namespace canopen
475
476} // namespace lely
This header file is part of the C++ CANopen application library; it contains the timeout conversion f...
An opaque CAN network interface type.
Definition: net.hpp:83
An opaque CANopen Client-SDO service type.
Definition: csdo.hpp:156
An opaque CANopen device type.
Definition: dev.hpp:76
An SDO download request.
Definition: sdo.hpp:132
The Client-SDO queue.
Definition: sdo.hpp:48
Sdo()
Default-constructs an invalid Client-SDO queue.
::std::size_t Cancel(SdoErrc ac)
Aborts the ongoing and all pending SDO requests.
Definition: sdo.cpp:346
~Sdo()
Destructs the Client-SDO queue.
This header file is part of the CANopen library; it contains the C++ interface of the Client-SDO decl...
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition: errnum.c:825
@ ERRNUM_INPROGRESS
Operation in progress.
Definition: errnum.h:125
@ ERRNUM_CANCELED
Operation canceled.
Definition: errnum.h:96
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
Definition: errnum.c:947
int ToTimeout(const ::std::chrono::duration< Rep, Period > &d)
Converts a duration to an SDO timeout.
Definition: chrono.hpp:46
SdoErrc
The SDO abort codes.
Definition: sdo_error.hpp:37
@ NO_SDO
Resource not available: SDO connection.
Global namespace for the Lely Industries N.V. libraries.
Definition: buf.hpp:32
inline ::std::shared_ptr< T > make_shared_c(Args &&... args)
Creates an instance of a trivial, standard layout or incomplete C type and wraps it in a std::shared_...
Definition: c_type.hpp:93
This header file is part of the C++ CANopen master library; it contains the Client-SDO queue declarat...
This is the internal header file of the C++ CANopen application library.
The internal implementation of the Client-SDO queue.
Definition: sdo.cpp:55