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 
34 namespace lely {
35 
36 namespace canopen {
37 
38 namespace {
39 
40 ::std::error_code
41 ErrorCode(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 
52 using namespace aio;
53 
55 struct 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 
82 template <class T>
83 void
85  impl->OnRequest<T>(this->idx, this->subidx, this->value);
86 }
87 
88 template <class T>
89 void
90 Sdo::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 
97 template <class T>
98 void
99 Sdo::UploadRequest<T>::OnRequest(Impl_* impl) noexcept {
100  impl->OnRequest<T>(this->idx, this->subidx);
101 }
102 
103 template <class T>
104 void
105 Sdo::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 
113 template <class T>
114 void
115 Sdo::DownloadRequestWrapper<T>::OnRequest(Impl_* impl) noexcept {
116  impl->OnRequest<T>(this->idx, this->subidx, this->value);
117 }
118 
119 template <class T>
120 void
121 Sdo::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 
133 template <class T>
134 void
135 Sdo::UploadRequestWrapper<T>::OnRequest(Impl_* impl) noexcept {
136  impl->OnRequest<T>(this->idx, this->subidx);
137 }
138 
139 template <class T>
140 void
141 Sdo::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 
154 template <class T>
155 void
156 Sdo::AsyncDownloadRequest<T>::OnRequest(Impl_* impl) noexcept {
157  impl->OnRequest<T>(this->idx, this->subidx, this->value);
158 }
159 
160 template <class T>
161 void
162 Sdo::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 
172 template <class T>
173 void
174 Sdo::AsyncUploadRequest<T>::OnRequest(Impl_* impl) noexcept {
175  impl->OnRequest<T>(this->idx, this->subidx);
176 }
177 
178 template <class T>
179 void
180 Sdo::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
195 template class Sdo::DownloadRequest<bool>;
196 template class Sdo::UploadRequest<bool>;
197 template class Sdo::DownloadRequestWrapper<bool>;
198 template class Sdo::UploadRequestWrapper<bool>;
199 template class Sdo::AsyncDownloadRequest<bool>;
200 template class Sdo::AsyncUploadRequest<bool>;
201 
202 // INTEGER8
203 template class Sdo::DownloadRequest<int8_t>;
204 template class Sdo::UploadRequest<int8_t>;
205 template class Sdo::DownloadRequestWrapper<int8_t>;
206 template class Sdo::UploadRequestWrapper<int8_t>;
207 template class Sdo::AsyncDownloadRequest<int8_t>;
208 template class Sdo::AsyncUploadRequest<int8_t>;
209 
210 // INTEGER16
211 template class Sdo::DownloadRequest<int16_t>;
212 template class Sdo::UploadRequest<int16_t>;
213 template class Sdo::DownloadRequestWrapper<int16_t>;
214 template class Sdo::UploadRequestWrapper<int16_t>;
215 template class Sdo::AsyncDownloadRequest<int16_t>;
216 template class Sdo::AsyncUploadRequest<int16_t>;
217 
218 // INTEGER32
219 template class Sdo::DownloadRequest<int32_t>;
220 template class Sdo::UploadRequest<int32_t>;
221 template class Sdo::DownloadRequestWrapper<int32_t>;
222 template class Sdo::UploadRequestWrapper<int32_t>;
223 template class Sdo::AsyncDownloadRequest<int32_t>;
224 template class Sdo::AsyncUploadRequest<int32_t>;
225 
226 // UNSIGNED8
227 template class Sdo::DownloadRequest<uint8_t>;
228 template class Sdo::UploadRequest<uint8_t>;
229 template class Sdo::DownloadRequestWrapper<uint8_t>;
230 template class Sdo::UploadRequestWrapper<uint8_t>;
231 template class Sdo::AsyncDownloadRequest<uint8_t>;
232 template class Sdo::AsyncUploadRequest<uint8_t>;
233 
234 // UNSIGNED16
235 template class Sdo::DownloadRequest<uint16_t>;
236 template class Sdo::UploadRequest<uint16_t>;
237 template class Sdo::DownloadRequestWrapper<uint16_t>;
238 template class Sdo::UploadRequestWrapper<uint16_t>;
239 template class Sdo::AsyncDownloadRequest<uint16_t>;
240 template class Sdo::AsyncUploadRequest<uint16_t>;
241 
242 // UNSIGNED32
243 template class Sdo::DownloadRequest<uint32_t>;
244 template class Sdo::UploadRequest<uint32_t>;
245 template class Sdo::DownloadRequestWrapper<uint32_t>;
246 template class Sdo::UploadRequestWrapper<uint32_t>;
247 template class Sdo::AsyncDownloadRequest<uint32_t>;
248 template class Sdo::AsyncUploadRequest<uint32_t>;
249 
250 // REAL32
251 template class Sdo::DownloadRequest<float>;
252 template class Sdo::UploadRequest<float>;
253 template class Sdo::DownloadRequestWrapper<float>;
254 template class Sdo::UploadRequestWrapper<float>;
255 template class Sdo::AsyncDownloadRequest<float>;
256 template class Sdo::AsyncUploadRequest<float>;
257 
258 // VISIBLE_STRING
259 template class Sdo::DownloadRequest<::std::string>;
260 template class Sdo::UploadRequest<::std::string>;
261 template class Sdo::DownloadRequestWrapper<::std::string>;
262 template class Sdo::UploadRequestWrapper<::std::string>;
263 template class Sdo::AsyncDownloadRequest<::std::string>;
264 template class Sdo::AsyncUploadRequest<::std::string>;
265 
266 // OCTET_STRING
267 template class Sdo::DownloadRequest<::std::vector<uint8_t>>;
268 template class Sdo::UploadRequest<::std::vector<uint8_t>>;
269 template class Sdo::DownloadRequestWrapper<::std::vector<uint8_t>>;
270 template class Sdo::UploadRequestWrapper<::std::vector<uint8_t>>;
271 template class Sdo::AsyncDownloadRequest<::std::vector<uint8_t>>;
272 template class Sdo::AsyncUploadRequest<::std::vector<uint8_t>>;
273 
274 // UNICODE_STRING
275 template class Sdo::DownloadRequest<::std::basic_string<char16_t>>;
276 template class Sdo::UploadRequest<::std::basic_string<char16_t>>;
277 template class Sdo::DownloadRequestWrapper<::std::basic_string<char16_t>>;
278 template class Sdo::UploadRequestWrapper<::std::basic_string<char16_t>>;
279 template class Sdo::AsyncDownloadRequest<::std::basic_string<char16_t>>;
280 template class Sdo::AsyncUploadRequest<::std::basic_string<char16_t>>;
281 
282 // TIME_OF_DAY
283 // TIME_DIFFERENCE
284 // DOMAIN
285 // INTEGER24
286 
287 // REAL64
288 template class Sdo::DownloadRequest<double>;
289 template class Sdo::UploadRequest<double>;
290 template class Sdo::DownloadRequestWrapper<double>;
291 template class Sdo::UploadRequestWrapper<double>;
292 template class Sdo::AsyncDownloadRequest<double>;
293 template class Sdo::AsyncUploadRequest<double>;
294 
295 // INTEGER40
296 // INTEGER48
297 // INTEGER56
298 
299 // INTEGER64
300 template class Sdo::DownloadRequest<int64_t>;
301 template class Sdo::UploadRequest<int64_t>;
302 template class Sdo::DownloadRequestWrapper<int64_t>;
303 template class Sdo::UploadRequestWrapper<int64_t>;
304 template class Sdo::AsyncDownloadRequest<int64_t>;
305 template class Sdo::AsyncUploadRequest<int64_t>;
306 
307 // UNSIGNED24
308 // UNSIGNED40
309 // UNSIGNED48
310 // UNSIGNED56
311 
312 // UNSIGNED64
313 template class Sdo::DownloadRequest<uint64_t>;
314 template class Sdo::UploadRequest<uint64_t>;
315 template class Sdo::DownloadRequestWrapper<uint64_t>;
316 template class Sdo::UploadRequestWrapper<uint64_t>;
317 template class Sdo::AsyncDownloadRequest<uint64_t>;
318 template class Sdo::AsyncUploadRequest<uint64_t>;
319 
320 #endif // !DOXYGEN_SHOULD_SKIP_THIS
321 
322 Sdo::Sdo() = default;
323 
324 Sdo::Sdo(CANNet* net, uint8_t id) : Sdo(net, nullptr, id) {}
325 
326 Sdo::Sdo(CANNet* net, CODev* dev, uint8_t num)
327  : impl_(new Impl_(net, dev, num)) {}
328 
329 Sdo::Sdo(COCSDO* sdo) : impl_(new Impl_(sdo, sdo->getTimeout())) {}
330 
331 Sdo& Sdo::operator=(Sdo&&) = default;
332 
333 Sdo::~Sdo() = default;
334 
335 void
336 Sdo::Submit(RequestBase_& op) {
337  impl_->Submit(op);
338 }
339 
340 ::std::size_t
341 Sdo::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 
350 Sdo::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 
355 Sdo::Impl_::Impl_(COCSDO* sdo_, int timeout)
356  : sdo(sdo_, [=](COCSDO* sdo) { sdo->setTimeout(timeout); }) {
357  aio_queue_init(&queue);
358 }
359 
360 Sdo::Impl_::~Impl_() { Cancel(nullptr, SdoErrc::NO_SDO); }
361 
362 void
363 Sdo::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
380 Sdo::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 
401 template <class T, class U>
402 void
403 Sdo::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 
418 template <class T>
419 void
420 Sdo::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 
432 void
433 Sdo::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 
447 template <class T>
448 void
449 Sdo::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 
464 void
465 Sdo::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
The internal implementation of the Client-SDO queue.
Definition: sdo.cpp:55
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
Definition: errnum.c:825
Sdo()
Default-constructs an invalid Client-SDO queue.
An opaque CANopen Client-SDO service type.
Definition: csdo.hpp:156
An SDO download request.
Definition: sdo.hpp:132
An opaque CANopen device type.
Definition: dev.hpp:76
Resource not available: SDO connection.
Operation canceled.
Definition: errnum.h:96
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
Operation in progress.
Definition: errnum.h:125
SdoErrc
The SDO abort codes.
Definition: sdo_error.hpp:37
~Sdo()
Destructs the Client-SDO queue.
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function...
Definition: errnum.c:947
This header file is part of the C++ CANopen application library; it contains the timeout conversion f...
int ToTimeout(const ::std::chrono::duration< Rep, Period > &d)
Converts a duration to an SDO timeout.
Definition: chrono.hpp:46
This is the internal header file of the C++ CANopen application library.
::std::size_t Cancel(SdoErrc ac)
Aborts the ongoing and all pending SDO requests.
Definition: sdo.cpp:346
This header file is part of the CANopen library; it contains the C++ interface of the Client-SDO decl...
The Client-SDO queue.
Definition: sdo.hpp:48
Global namespace for the Lely Industries N.V. libraries.
Definition: buf.hpp:32
An opaque CAN network interface type.
Definition: net.hpp:83
This header file is part of the C++ CANopen master library; it contains the Client-SDO queue declarat...